static string ParsedTypePath(string baseUrl, ParsedType type) { string name = type.FullName; if (!baseUrl.StartsWith("/")) { baseUrl = "/" + baseUrl; } if (!baseUrl.EndsWith("/")) { baseUrl += "/"; } name = baseUrl + name.Replace(".", "/") + "/"; return(name.ToLower()); }
public void Merge(ParsedType other) { if (!FullName.Equals(other.FullName) && !other.Name.Equals("NamespaceDoc")) { throw new Exception("Invalid Merge"); } if (other.Documentation != null) { // TODO: deal with merging documentation //if (this.Documentation != null) // throw new Exception("two Documentation sections on merge"); Documentation = other.Documentation; } if (!IsPublic && other.IsPublic) { // partial classes can appear as non-public. If one of the declarations // is public, then the whole thing is public _declarationType = other._declarationType; } }
public string Signature(bool forSorting) { string prefix = forSorting ? ClassPath + "." : ""; if (!forSorting && IsStatic) { prefix = "static "; } { MethodDeclarationSyntax method = Member as MethodDeclarationSyntax; if (method != null) { var signature = new System.Text.StringBuilder(); if (forSorting) { signature.Append($"{ClassPath}.{method.Identifier}("); } else { signature.Append($"{prefix}{method.ReturnType} {method.Identifier}("); } int parameterCount = method.ParameterList.Parameters.Count; for (int i = 0; i < parameterCount; i++) { if (i > 0) { signature.Append(", "); } var parameter = method.ParameterList.Parameters[i]; for (int j = 0; j < parameter.Modifiers.Count; j++) { signature.Append(parameter.Modifiers[j].Text); signature.Append(" "); } string paramType = parameter.Type.ToString(); int angleIndex = paramType.IndexOf('<'); if (angleIndex > 0) { string prefixType = paramType.Substring(0, angleIndex); int prefixIndex = prefixType.LastIndexOf('.'); if (prefixIndex > 0) { prefixType = prefixType.Substring(prefixIndex + 1); } string genericType = paramType.Substring(angleIndex + 1); int genericIndex = genericType.LastIndexOf('.'); if (genericIndex > 0) { genericType = genericType.Substring(genericIndex + 1); } paramType = prefixType + "<" + genericType; } else { int index = paramType.LastIndexOf('.'); if (index > 0) { paramType = paramType.Substring(index + 1); } } signature.Append(paramType); if (!forSorting) { signature.Append($" {parameter.Identifier}"); } } signature.Append(")"); return(signature.ToString()); } } { PropertyDeclarationSyntax property = Member as PropertyDeclarationSyntax; if (property != null) { var signature = new System.Text.StringBuilder(); if (forSorting) { signature.Append($"{ClassPath}.{property.Identifier}"); } else { string proptype = $"{property.Type}"; int index = proptype.LastIndexOf('.'); if (index > 0) { proptype = proptype.Substring(index + 1); } signature.Append($"{prefix}{proptype} {property.Identifier}"); } return(signature.ToString()); } } { EventDeclarationSyntax evt = Member as EventDeclarationSyntax; if (evt != null) { var signature = new System.Text.StringBuilder(); signature.Append($"{prefix}{evt.Identifier}"); return(signature.ToString()); } } { OperatorDeclarationSyntax op = Member as OperatorDeclarationSyntax; if (op != null) { var signature = new System.Text.StringBuilder(); signature.Append($"{prefix}{op.OperatorToken}"); return(signature.ToString()); } } { EventFieldDeclarationSyntax eventField = Member as EventFieldDeclarationSyntax; if (eventField != null) { var signature = new System.Text.StringBuilder(); string declaration = eventField.ToString(); int index = declaration.LastIndexOf(' '); declaration = declaration.Substring(index + 1, declaration.Length - 1 - (index + 1)); signature.Append($"{prefix}{declaration}"); return(signature.ToString()); } } { ConstructorDeclarationSyntax constructor = Member as ConstructorDeclarationSyntax; if (constructor != null) { var signature = new System.Text.StringBuilder(); if (forSorting) { signature.Append($"{ClassPath}("); } else { if (IsStatic) { signature.Append("static "); } var parent = new ParsedType(Member.Parent as BaseTypeDeclarationSyntax, null); signature.Append($"{parent.Name}("); } int parameterCount = constructor.ParameterList.Parameters.Count; for (int i = 0; i < parameterCount; i++) { if (i > 0) { signature.Append(", "); } var parameter = constructor.ParameterList.Parameters[i]; string paramType = parameter.Type.ToString(); int angleIndex = paramType.IndexOf('<'); if (angleIndex > 0) { string prefixType = paramType.Substring(0, angleIndex); int prefixIndex = prefixType.LastIndexOf('.'); if (prefixIndex > 0) { prefixType = prefixType.Substring(prefixIndex + 1); } string genericType = paramType.Substring(angleIndex + 1); int genericIndex = genericType.LastIndexOf('.'); if (genericIndex > 0) { genericType = genericType.Substring(genericIndex + 1); } paramType = prefixType + "<" + genericType; } else { int index = paramType.LastIndexOf('.'); if (index > 0) { paramType = paramType.Substring(index + 1); } } signature.Append(paramType); if (!forSorting) { signature.Append($" {parameter.Identifier}"); } } signature.Append(")"); return(signature.ToString()); } } { EnumMemberDeclarationSyntax enumMember = Member as EnumMemberDeclarationSyntax; if (enumMember != null) { var signature = enumMember.ToString(); var items = signature.Split(new char[] { '\n' }); signature = items[items.Length - 1]; return(signature); } } throw new NotImplementedException(); }
static string MembersAsJsonArray(ParsedType type, ParsedMemberType filter, bool asJavascript = true) { if (type.Members == null) { return(null); } StringBuilder sb = new StringBuilder(); sb.AppendLine("["); bool memberAdded = false; foreach (var member in type.Members) { if (filter != member.MemberType) { continue; } if (memberAdded) { sb.AppendLine(","); } sb.AppendLine(" {"); sb.Append(KeyValString(8, "signature", member.Signature(false), asJavascript)); //sb.Append($" signature: '{member.Signature(false)}'"); string summary = member.Summary(); if (!string.IsNullOrWhiteSpace(summary)) { sb.AppendLine(","); sb.Append(KeyValString(8, "summary", summary, asJavascript)); //sb.Append($" summary: {JsonQuote(summary)}"); } string since = member.Since; if (!string.IsNullOrWhiteSpace(since) && double.TryParse(since, out double sinceValue)) { sb.AppendLine(","); sb.Append(KeyValString(8, "since", since, asJavascript)); //sb.Append($" since: '{since}'"); } string deprecated = member.Deprecated; if (!string.IsNullOrWhiteSpace(deprecated) && double.TryParse(deprecated, out double deprecatedValue)) { sb.AppendLine(","); sb.Append(KeyValString(8, "deprecated", deprecated, asJavascript)); //sb.Append($" deprecated: '{deprecated}'"); } var parameters = member.GetParameters(); if (parameters != null) { // for now, just skip items that have ALL undocumented parameters bool writeParameters = false; for (int i = 0; i < parameters.Length; i++) { if (!string.IsNullOrWhiteSpace(parameters[i].DocString)) { writeParameters = true; break; } } if (writeParameters) { sb.AppendLine(","); if (asJavascript) { sb.AppendLine($" parameters: ["); } else { sb.AppendLine($" \"parameters\": ["); } for (int i = 0; i < parameters.Length; i++) { if (i > 0) { sb.AppendLine(","); } sb.AppendLine(" {"); sb.AppendLine(KeyValString(12, "name", parameters[i].Name, asJavascript) + ","); //sb.AppendLine($" name: {JsonQuote(parameters[i].Name)},"); // Not sure if we really need type as it is easy to resolve in javascript // sb.AppendLine($" type: {JsonQuote(parameters[i].Type)},"); sb.AppendLine(KeyValString(12, "summary", parameters[i].DocString, asJavascript)); //sb.AppendLine($" summary: {JsonQuote(parameters[i].DocString)}"); sb.Append(" }"); } sb.AppendLine(); sb.Append(" ]"); } } if (member.MemberType == ParsedMemberType.Method) { string returns = member.ReturnDocString(); if (!string.IsNullOrWhiteSpace(returns)) { sb.AppendLine(","); sb.Append(KeyValString(8, "returns", returns, asJavascript)); } } if (member.MemberType == ParsedMemberType.Property) { bool get, set; if (member.PropertyType(out get, out set)) { sb.AppendLine(","); string s = get ? "['get'" : "["; if (set) { if (get) { s += ", "; } s += "'set'"; } s += "]"; if (!asJavascript) { s = s.Replace("'", "\""); } if (asJavascript) { sb.Append($" property: {s}"); } else { sb.Append($" \"property\": {s}"); } } } sb.AppendLine(); sb.Append(" }"); memberAdded = true; } sb.AppendLine(); sb.Append(" ]"); return(memberAdded ? sb.ToString() : null); }
static string WriteTypeAsObject(ParsedType type, Dictionary <string, ParsedType> allPublicTypesByShortName, bool asJavascript) { if (!type.IsPublic || (type.DataType != ParsedDataType.Namespace && string.IsNullOrWhiteSpace(type.Namespace))) { return(null); } StringBuilder sb = new StringBuilder(); sb.AppendLine(" {"); if (type.DataType == ParsedDataType.Namespace) { sb.AppendLine(KeyValString(4, "name", type.FullName, asJavascript) + ","); } else { sb.AppendLine(KeyValString(4, "namespace", type.Namespace, asJavascript) + ","); sb.AppendLine(KeyValString(4, "name", type.Name, asJavascript) + ","); } sb.Append(KeyValString(4, "dataType", type.DataType.ToString().ToLower(), asJavascript)); string summary = type.Summary(); if (!string.IsNullOrWhiteSpace(summary)) { sb.AppendLine(","); sb.Append(KeyValString(4, "summary", summary, asJavascript)); } string remarks = type.Remarks(); if (!string.IsNullOrWhiteSpace(remarks)) { sb.AppendLine(","); sb.Append(KeyValString(4, "remarks", remarks, asJavascript)); } if (type.DataType == ParsedDataType.Namespace) { sb.AppendLine(); } else { string[] baseList = type.IsClass ? type.GetBaseList(allPublicTypesByShortName) : null; if (baseList != null && baseList.Length > 0) { sb.AppendLine(","); int firstInterfaceIndex = -1; for (int i = 0; i < baseList.Length; i++) { // TODO: guessing based on .Net naming conventions. I'm sure // this can be improved if (baseList[i].StartsWith("I") && char.IsUpper(baseList[i][1])) { firstInterfaceIndex = i; break; } } if (firstInterfaceIndex != 0) { sb.Append(KeyValString(4, "baseclass", baseList[0], asJavascript)); } if (firstInterfaceIndex > -1) { if (firstInterfaceIndex > 0) { sb.AppendLine(","); } if (asJavascript) { sb.Append(" interfaces: ["); } else { sb.Append(" \"interfaces\": ["); } for (int i = firstInterfaceIndex; i < baseList.Length; i++) { if (i > firstInterfaceIndex) { sb.Append(", "); } sb.Append(JsonQuote(baseList[i], asJavascript, null)); } sb.Append("]"); } } if (type.HasSinceTag()) { sb.AppendLine(","); sb.Append(KeyValString(4, "since", type.Since, asJavascript)); } if (type.HasDeprecatedTag()) { sb.AppendLine(","); sb.Append(KeyValString(4, "deprecated", type.Deprecated, asJavascript)); } string values = MembersAsJsonArray(type, ParsedMemberType.EnumValue, asJavascript); string constructors = MembersAsJsonArray(type, ParsedMemberType.Constructor, asJavascript); string properties = MembersAsJsonArray(type, ParsedMemberType.Property, asJavascript); string methods = MembersAsJsonArray(type, ParsedMemberType.Method, asJavascript); string events = MembersAsJsonArray(type, ParsedMemberType.Event, asJavascript); if (values != null || constructors != null || properties != null || methods != null || events != null) { sb.AppendLine(","); } else { sb.AppendLine(); } if (!string.IsNullOrWhiteSpace(values)) { if (asJavascript) { sb.AppendLine($" values: {values}"); } else { sb.AppendLine($" \"values\": {values}"); } } if (!string.IsNullOrWhiteSpace(constructors)) { if (asJavascript) { sb.Append($" constructors: {constructors}"); } else { sb.Append($" \"constructors\": {constructors}"); } if (properties != null || methods != null || events != null) { sb.AppendLine(","); } else { sb.AppendLine(); } } if (!string.IsNullOrWhiteSpace(properties)) { if (asJavascript) { sb.Append($" properties: {properties}"); } else { sb.Append($" \"properties\": {properties}"); } if (methods != null || events != null) { sb.AppendLine(","); } else { sb.AppendLine(); } } if (!string.IsNullOrWhiteSpace(methods)) { if (asJavascript) { sb.Append($" methods: {methods}"); } else { sb.Append($" \"methods\": {methods}"); } if (events != null) { sb.AppendLine(","); } else { sb.AppendLine(); } } if (!string.IsNullOrWhiteSpace(events)) { if (asJavascript) { sb.AppendLine($" events: {events}"); } else { sb.AppendLine($" \"events\": {events}"); } } } sb.Append(" }"); return(sb.ToString()); }
public static void WriteTypes(Dictionary <string, ParsedType> types, string outputDirectory) { var di = new System.IO.DirectoryInfo(outputDirectory); string apibase = di.Name; var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = 100 }; Parallel.ForEach(types, parallelOptions, (keyValue) => { ParsedType basetype = keyValue.Value; if (!basetype.IsPublic) { return; } var content = new StringBuilder(); content.AppendLine("---"); content.AppendLine($"title: \"{basetype.Name}\""); content.AppendLine($"date: {DateTime.Now.ToString("u")}"); content.AppendLine("draft: false"); content.AppendLine("---"); content.AppendLine(); content.AppendLine($"*Namespace: [{basetype.Namespace}](../)*"); content.AppendLine(); string baseTypeSummary = basetype.Summary(); if (!string.IsNullOrEmpty(baseTypeSummary)) { content.AppendLine(baseTypeSummary); } if (basetype.IsClass) { content.AppendLine("```cs"); string[] attributes = basetype.GetAttributes(); for (int i = 0; i < attributes.Length; i++) { content.AppendLine(attributes[i]); } content.Append($"public class {basetype.Name}"); string[] baseList = basetype.GetBaseList(null); if (baseList != null) { for (int i = 0; i < baseList.Length; i++) { if (i == 0) { content.Append($": {baseList[i]}"); } else { content.Append($", {baseList[i]}"); } } } content.AppendLine(); content.AppendLine("```"); } if (basetype.Members == null) { return; // TODO: Figure out this case } ParsedMemberType state = ParsedMemberType.None; foreach (var item in basetype.Members) { if (item.IsEvent && state != ParsedMemberType.Event) { content.AppendLine("## Events"); state = ParsedMemberType.Event; } if (item.IsProperty && state != ParsedMemberType.Property) { content.AppendLine("## Properties"); state = ParsedMemberType.Property; } if (item.IsMethod && state != ParsedMemberType.Method) { content.AppendLine("## Methods"); state = ParsedMemberType.Method; } if (item.IsConstructor && state != ParsedMemberType.Constructor) { content.AppendLine("## Constructors"); state = ParsedMemberType.Constructor; } content.AppendLine(); string signature = item.Signature(false); var returntype = item.ReturnType(types.Values); if (returntype != null && returntype != item.ParentType) { string rn = returntype.Name; int index = signature.IndexOf(rn); string link = ParsedTypePath(apibase, returntype); string s = ""; if (index > 0) { s = signature.Substring(0, index); } s += $"[{signature.Substring(index, rn.Length)}]({link}){signature.Substring(index + rn.Length)}"; signature = s; } content.AppendLine(signature); content.AppendLine($": {item.Summary()}"); string returnString = item.ReturnDocString(); if (!string.IsNullOrWhiteSpace(returnString)) { content.AppendLine($": Returns - {returnString}"); } if (!item.Since.Equals("5.0")) // no need to add since tags initial items { content.AppendLine($": since {item.Since}"); } } string name = basetype.Name; string directory = OutputDirectoryFromNamespace(outputDirectory, basetype.Namespace); string path = System.IO.Path.Combine(directory, name.ToLower() + ".md"); if (WriteContent(content, path, true)) { Console.WriteLine($"(write) {name}"); } else { Console.WriteLine($"(no change) {name}"); } }); }