/// <summary> /// Parses a <see cref="DocAssembly"/> to return a <see cref="DocFile"/>. /// </summary> /// <param name="assembly">The <see cref="DocAssembly"/> to parse.</param> /// <returns>The transformed <see cref="DocFile"/>.</returns> public DocFile Parse(DocAssembly assembly) { var result = new DocFile(assembly.FileName); result.AddThenBlankLine(writer.WriteHeading1($"{assembly.Name} API Reference")); result.AddThenBlankLine(ParserUtils.ProcessBreadcrumb(this)); var list = new MarkdownList(); foreach (var customDoc in assembly.CustomDocs) { if (customDoc is DocSerialization ser) { list.AddItem(writer.WriteLink($"{ser.Name.NameOnly()} Reference", ser.FileName)); result.Files.Add(ProcessSerialization(ser, assembly)); } } foreach (var ns in assembly.Namespaces.OrderBy(ns => ns.Name)) { list.AddItem(writer.WriteLink(ns.Name, ns.FileName)); result.Files.Add(ProcessNamespace(ns)); } writer.AddRange(result.Markdown, list.CloseList()); return(result); }
private DocFile ProcessSerialization(DocSerialization ser, DocAssembly assembly) { var result = new DocFile(ser.FileName); result.AddThenBlankLine(writer.WriteHeading1($"{ser.Name} Reference")); result.AddThenBlankLine(ParserUtils.ProcessBreadcrumb(assembly)); var table = new MarkdownTable("ExpressionType", "Serializer"); foreach (ExpressionType expressionType in Enum.GetValues(typeof(ExpressionType))) { var name = expressionType.ToString(); if (ser.Serializers.ContainsKey(expressionType)) { var entry = ser.Serializers[expressionType]; table.AddRow(name, writer.WriteLink(entry.Name.NameOnly(), entry.FileName)); } else { table.AddRow(name, "_Not Supported_"); } } writer.AddRange(result.Markdown, table.CloseTable()); return(result); }
/// <summary> /// Builds the serializer cross-reference. /// </summary> /// <param name="doc">The <see cref="DocAssembly"/> for serializers.</param> private void IterateSerializers(DocAssembly doc) { if (doc.CustomDocs.OfType <DocSerialization>().Any()) { return; } var serializerDoc = new DocSerialization { Name = typeof(ExpressionSerializerAttribute).Namespace, }; var types = Assembly.GetTypes() .Where(t => t.Namespace == typeof(BaseSerializer <,>).Namespace && t.GetCustomAttributes(false) .Any(c => c is ExpressionSerializerAttribute)) .SelectMany(t => t.GetCustomAttributes(false).OfType <ExpressionSerializerAttribute>() .Select(c => new { serializer = t, type = c.Type })); foreach (var serializer in types) { var name = serializer.serializer.FullName; var typeDoc = ParserUtils.GetTypeQuery(doc).Where(d => d.Name == name).Single(); serializerDoc.Serializers.Add(serializer.type, typeDoc); } doc.CustomDocs.Add(serializerDoc); }
/// <summary> /// Parse the comments for an assembly. /// </summary> /// <param name="path">The path that contains the XML comments.</param> /// <param name="assembly">The <see cref="DocAssembly"/> to annotate.</param> public void ParseComments(string path, DocAssembly assembly) { var doc = fileHelper.LoadXmlDocs(path); if (doc != null) { ParseXml(doc, assembly); } }
/// <summary> /// Iterate the namespaces of the assembly. /// </summary> /// <param name="doc">The <see cref="DocAssembly"/> to iterate.</param> private void IterateNamespaces(DocAssembly doc) { Types = Assembly.GetExportedTypes(); var namespaces = Types.Select(t => t.Namespace).Distinct().OrderBy(n => n); foreach (var nsp in namespaces) { Console.WriteLine($"Parsing namespace \"{nsp}\"..."); var docNamespace = new DocNamespace(nsp) { Assembly = doc, }; IterateTypes(docNamespace); doc.Namespaces.Add(docNamespace); } }
/// <summary> /// Parses the assembly. /// </summary> /// <remarks> /// First pass creates the assembly and parses it. Second pass takes the /// assembly and processes for addition info that requires cross-referencing. /// </remarks> /// <param name="doc">The <see cref="DocAssembly"/> ref for pass 2.</param> /// <returns>The parsed <see cref="DocAssembly"/>.</returns> public DocAssembly Parse(DocAssembly doc = null) { if (doc == null) { doc = new DocAssembly(AssemblyName); IterateNamespaces(doc); } else { IterateNamespacesPass2(doc); } if (Assembly.GetTypes().Any(t => t == typeof(ExpressionSerializerAttribute))) { IterateSerializers(doc); } return(doc); }
/// <summary> /// Second pass to handle relationships. /// </summary> /// <param name="doc">The <see cref="DocAssembly"/> to iterate.</param> private void IterateNamespacesPass2(DocAssembly doc) { // now go back and handle relationships foreach (var nsp in doc.Namespaces) { foreach (var type in nsp.Types) { ProcessTypePass2(type); if (!type.IsInterface) { type.Inheritance = ProcessInheritance(type.Type); } ProcessConstructors(type); ProcessProperties(type); ProcessMethods(type); } } }
/// <summary> /// Gets a queryable to examine types. /// </summary> /// <param name="assembly">The host <see cref="DocAssembly"/>.</param> /// <returns>The <see cref="IQueryable"/>.</returns> public static IQueryable <DocExportedType> GetTypeQuery(this DocAssembly assembly) => assembly.Namespaces.SelectMany(ns => ns.Types).AsQueryable();
/// <summary> /// Parses the XML comments. /// </summary> /// <param name="doc">The <see cref="XmlDocument"/> for XML comments.</param> /// <param name="assembly">The <see cref="DocAssembly"/> to annotate.</param> private void ParseXml(XmlDocument doc, DocAssembly assembly) { var typeList = assembly.Namespaces.SelectMany(ns => ns.Types); foreach (var type in typeList) { var typeNode = doc.SelectSingleNode(type.XPath); if (typeNode == null) { NotFound(type.XPath); } if (typeNode is XmlElement node) { type.Description = GetTextBlock(node, ParserUtils.Summary); type.Remarks = GetTextBlock(node, ParserUtils.Remarks); type.Example = GetTextBlock(node, ParserUtils.Example); ProcessTypeParamDescriptions(node, type.TypeParameters); } if (type.Constructor != null && type.Constructor.Overloads.Any()) { foreach (var overload in type.Constructor.Overloads) { var docNode = doc.SelectSingleNode(overload.XPath); if (docNode == null) { NotFound(overload.XPath); } if (docNode is XmlElement ctorNode) { overload.Description = GetTextBlock(ctorNode, ParserUtils.Summary); overload.Remarks = GetTextBlock(ctorNode, ParserUtils.Remarks); overload.Example = GetTextBlock(ctorNode, ParserUtils.Example); overload.Exceptions = GetExceptions(ctorNode); ProcessParameters(overload.Parameters, ctorNode); ProcessTypeParamDescriptions(ctorNode, overload.TypeParameters); } if (string.IsNullOrWhiteSpace(overload.Description)) { var ctorType = overload.Constructor.ConstructorType.Type; overload.Description = $"Initializes a new instance of the [{MarkdownWriter.Normalize(TypeCache.Cache[ctorType].FriendlyName)}]({TypeCache.Cache[ctorType].Link}) class."; } } } if (type.Methods.Any()) { foreach (var method in type.Methods) { foreach (var overload in method.MethodOverloads) { var oNode = doc.SelectSingleNode(overload.XPath); if (oNode == null) { NotFound(overload.XPath); } if (oNode is XmlElement methodNode) { overload.Description = GetTextBlock(methodNode, ParserUtils.Summary); overload.Remarks = GetTextBlock(methodNode, ParserUtils.Remarks); overload.Example = GetTextBlock(methodNode, ParserUtils.Example); overload.Exceptions = GetExceptions(methodNode); overload.Returns = GetTextBlock(methodNode, ParserUtils.Returns); ProcessParameters(overload.Parameters, methodNode); ProcessTypeParamDescriptions(methodNode, overload.Method.MethodType.TypeParameters); } } } } if (type.Properties.Any()) { ProcessProperties(doc, type.Properties, type.TypeParameters); } } }