public override void BuildDocs(string outputPath) { outputPath = DocUtilities.ChangeExtension(outputPath, "md"); // Write markdown file using (var writer = new MarkdownWriter(outputPath)) { foreach (var type in Library.ExportedTypes.Where(t => !t.Name.StartsWith("_")).OrderBy(t => t.Name)) { // Pull XML docs for type var typeDocs = Docs[ID.GetIDString(type)]; // Header, e.g. "StringBuilder class (System)" writer.WriteHeader(2, DocUtilities.GetTypeTitle(type, true), true); // Summary and other info PrintObsoleteWarning(type, writer); writer.WriteParagraph($"**Namespace:** {type.Namespace}"); writer.WriteParagraph($"**Inheritance:** {DocUtilities.GetInheritanceString(type)}", true); Summary(typeDocs, writer); // Signature writer.WriteCodeBlock(Lang, DocUtilities.GetClassSignature(type)); // Members WriteConstructors(type, writer); WriteProperties(type, writer); WriteIndexers(type, writer); WriteFields(type, writer); WriteMethods(type, writer); } } }
private void WriteMethods(Type type, MarkdownWriter writer) { var methods = type.GetMethods(MemberSearchFlags) // Exclude compiler-generated and internal methods .Where(m => !m.IsSpecialName && !m.IsAssembly) // Exclude protected methods when class is sealed .Where(m => type.IsSealed ? m.IsPublic : !m.IsPrivate) // Sort alphabetically... .OrderBy(m => m.Name) // ... then by parameter count. .ThenBy(m => m.GetParameters().Length) .ToArray(); if (methods.Length > 0) { writer.WriteHeader(3, "Methods"); foreach (var method in methods) { var methodDocs = Docs[ID.GetIDString(method)]; // Heading writer.WriteHeader(4, DocUtilities.GetMethodSignature(method, false, false), true); PrintObsoleteWarning(method, writer); Summary(methodDocs, writer); writer.WriteCodeBlock(Lang, DocUtilities.GetMethodSignature(method, true, true)); // Parameters WriteParamList(4, method, writer, methodDocs); Returns(4, methodDocs, writer); Remarks(4, methodDocs, writer); } } }
private void WriteFields(Type type, MarkdownWriter writer) { var fields = type.GetFields() .Where(f => !f.IsSpecialName) .OrderBy(f => f.Name) .ToArray(); if (fields.Length == 0) { return; } writer.WriteHeader(3, "Fields"); for (int i = 0; i < fields.Length; i++) { var fieldDocs = Docs[ID.GetIDString(fields[i])]; writer.WriteHeader(4, DocUtilities.GetFieldSignature(fields[i], false)); PrintObsoleteWarning(fields[i], writer); Summary(fieldDocs, writer); writer.WriteCodeBlock(Lang, DocUtilities.GetFieldSignature(fields[i], true)); Remarks(5, fieldDocs, writer); } }
private void WriteConstructors(Type type, MarkdownWriter writer) { // Constructor list var ctors = type.GetConstructors(); if (ctors.Length > 0) { writer.WriteHeader(3, "Constructors"); for (int i = 0; i < ctors.Length; i++) { // Heading for constructor section var ctorDocs = Docs[ID.GetIDString(ctors[i])]; writer.WriteHeader(4, DocUtilities.GetMethodSignature(ctors[i], false, false)); PrintObsoleteWarning(ctors[i], writer); Summary(ctorDocs, writer); // Signature writer.WriteCodeBlock(Lang, DocUtilities.GetMethodSignature(ctors[i], true, true)); // Get constructor's parameters and associated docs WriteParamList(5, ctors[i], writer, ctorDocs); Remarks(5, ctorDocs, writer); } } }
private void WriteIndexers(Type type, MarkdownWriter writer) { var indexers = type.GetProperties() .Where(p => p.GetIndexParameters().Length > 0) .OrderBy(p => p.GetIndexParameters().Length) .ToArray(); if (indexers.Length == 0) { return; } writer.WriteHeader(3, "Indexers"); for (int i = 0; i < indexers.Length; i++) { var indexDocs = Docs[ID.GetIDString(indexers[i])]; writer.WriteHeader(4, DocUtilities.GetPropertySignature(indexers[i], false, true, false)); PrintObsoleteWarning(indexers[i], writer); Summary(indexDocs, writer); writer.WriteCodeBlock(Lang, DocUtilities.GetPropertySignature(indexers[i], true, true, true)); Remarks(5, indexDocs, writer); } }
private void WriteProperties(Type type, MarkdownWriter writer) { var props = type.GetProperties(MemberSearchFlags) // Show protected members if class is not sealed .Where(p => type.IsSealed ? (p.CanRead && p.GetMethod.IsPublic) || (p.CanWrite && p.SetMethod.IsPublic) : (p.CanRead && !p.GetMethod.IsPrivate) || (p.CanWrite && !p.SetMethod.IsPrivate)) // Indexers are technically properties, but we want to handle them separately .Where(p => p.GetIndexParameters().Length == 0) // Sort alphabetically .OrderBy(p => p.Name) .ToArray(); if (props.Length == 0) { return; } writer.WriteHeader(3, "Properties"); for (int i = 0; i < props.Length; i++) { var propDocs = Docs[ID.GetIDString(props[i])]; writer.WriteHeader(4, DocUtilities.GetPropertySignature(props[i], false, false, false)); PrintObsoleteWarning(props[i], writer); Summary(propDocs, writer); writer.WriteCodeBlock(Lang, DocUtilities.GetPropertySignature(props[i], true, true, true)); Remarks(5, propDocs, writer); } }
private void WriteParamList(int rank, MethodBase method, MarkdownWriter writer, MemberXmlDocs docs) { var plist = method.GetParameters(); if (method.ContainsGenericParameters) { if (method.IsGenericMethod) { var tplist = method.GetGenericArguments(); writer.WriteParagraph("**Type Parameters**"); for (int i = 0; i < tplist.Length; i++) { writer.WriteLine($"- `{tplist[i].Name}`: {TypeParam(docs, tplist[i].Name)}"); } } } if (plist.Length > 0) { writer.WriteParagraph("**Parameters**"); for (int i = 0; i < plist.Length; i++) { writer.WriteLine($"- `{plist[i].Name}`: {Param(docs, plist[i])}"); } } }
private static void Returns(int rank, MemberXmlDocs docs, MarkdownWriter writer) { var returns = docs?.Returns; if (!String.IsNullOrWhiteSpace(returns)) { writer.WriteHeader(rank, "Returns"); writer.WriteParagraph(returns); } }
private void PrintObsoleteWarning(MemberInfo member, MarkdownWriter writer) { var obsAttr = member.GetCustomAttribute <ObsoleteAttribute>(); if (obsAttr == null) { return; } writer.WriteInfoBox($"**This item is deprecated.**\n{obsAttr.Message}", "warning"); }
private static void Summary(MemberXmlDocs docs, MarkdownWriter writer) => writer.WriteParagraph(docs?.Summary ?? "_No Summary_");
public override void BuildDocs(string outputPath) { var pages = new PageTree("docs"); var PageTrees = new List <PageTree>(); foreach (var type in Library.GetExportedTypes()) { var typePath = $"{type.Namespace.Replace('.', '/')}/{DocUtilities.GetURLTitle(type)}"; var typeData = Docs[ID.GetIDString(type)]; pages[typePath] = new TypePage(type, typeData, Docs); PageTrees.Add(pages.GetNode(typePath)); // Constructors var ctors = type.GetConstructors(); if (ctors.Length > 0) { // Path to ctors group var ctorsGroupPath = $"{typePath}/ctors"; var ctorsData = new Dictionary <ConstructorInfo, MemberXmlDocs>(); foreach (var ctor in ctors) { var ctorData = Docs[ID.GetIDString(ctor)]; ctorsData.Add(ctor, ctorData); } pages[ctorsGroupPath] = new ConstructorsPage(type, ctors, ctorsData); PageTrees.Add(pages.GetNode(ctorsGroupPath)); } // Method groups foreach (var methodGroup in type.GetMethods() .Where(m => !m.Name.StartsWith("get_") && !m.Name.StartsWith("set_")) .GroupBy(m => m.Name)) { // Path to method group var methodGroupPath = $"{typePath}/{methodGroup.Key}"; // Map of reflected methods and documentation var methods = new Dictionary <MethodInfo, MemberXmlDocs>(); foreach (var method in methodGroup) { var methodData = Docs[ID.GetIDString(method)]; methods[method] = methodData; } pages[methodGroupPath] = new MethodGroupPage(type, methodGroup.Key, methods); PageTrees.Add(pages.GetNode(methodGroupPath)); } // Fields foreach (var field in type.GetFields().Where(f => (f.IsPublic || !f.IsPrivate) && (!f.DeclaringType.IsEnum || !f.IsSpecialName))) { var fieldPath = Path.Combine(typePath, field.Name).Replace('\\', '/'); var fieldData = Docs[ID.GetIDString(field)]; pages[fieldPath] = new FieldPage(field, fieldData); PageTrees.Add(pages.GetNode(fieldPath)); } // Properties and Indexers int numIndexers = 0; foreach (var property in type.GetProperties()) { var propData = Docs[ID.GetIDString(property)]; string propPath; if (property.GetIndexParameters().Length > 0) { propPath = $"{typePath}/this/{++numIndexers}"; } else { propPath = $"{typePath}/{property.Name}"; } pages[propPath] = new PropertyPage(property, propData); PageTrees.Add(pages.GetNode(propPath)); } } // Create a task for each document that needs to be exported, run them all at once var exportTasks = new Task[PageTrees.Count]; for (int i = 0; i < PageTrees.Count; i++) { var node = PageTrees[i]; exportTasks[i] = Task.Run(() => { var documentDir = Directory.GetParent($"{outputPath}/{node.Path}").FullName; var documentPath = $"{outputPath}/{node.Path}.md"; Directory.CreateDirectory(documentDir); using (var writer = new MarkdownWriter(documentPath)) { node.Page.Render(node, writer); } }); } // Wait for all export tasks to finish Task.WaitAll(exportTasks); }