GithubHelp home page GithubHelp logo

andrei15193 / codemap Goto Github PK

View Code? Open in Web Editor NEW
5.0 2.0 0.0 2.92 MB

An extensible tool for generating documentation for your .NET libraries. Generate HTML, Markdown or in any other format, customise the documentation at your discretion.

Home Page: https://andrei15193.github.io/CodeMap/

License: GNU Lesser General Public License v3.0

C# 86.87% CSS 0.38% Handlebars 1.64% HTML 0.45% SCSS 10.66%
documentation-generator html documentation documentation-tool documentation-code generator site-generator

codemap's Introduction

Build and Deploy

Visual Studio enables developers to write comprehensive documentation inside their code using XML in three slashed comments, see XML Documentation Comments (C# Programming Guide) for more details about supported tags.

When we build a project that has been configured to generate XML documentation files (simply specify the output path where resulting files should be saved) Visual Studio will look for this file and display the respective documentation in IntelliSense.

This is great and all library owners should be writing documentation like this in their code, however there aren't that many tools out there that allow us to transform the XML generated documentation into something else, say JSON or custom HTML, to display the exact same documentation on the project's website.

Having a single source for documentation is the best way to ensure consistency, what you see in code is what you see on the project's website. There are no discrepancies. Writing all documentation in code may upset developers, but after all they know best what the code they are writing is all about.

CodeMap aims to bring a tool into the developers hands that allows them to generate any output format they wish from a given assembly and associated XML documentation.

This is done following the visitor design pattern, an assembly is being visited and all elements that make up an assembly get their turn. When you want to generate a specific output (say Markdown or Creole) you simply implement your own visitor.

There are some elements that do not have XML documentation correspondents, such as assemblies, modules and namespaces. You cannot write documentation for neither in code and have it generated in the resulting XML document.

This tool does not work directly on the XML file but rather on a representation of the file (XDocument), this allows for the document to be loaded, updated if necessary and only then processed. This enables the tool to support additions to the standard XML document format allowing for extra documentation to be manually added. If you want to add specific documentation to a namespace, you can, but you have to do it manually which means you follow the XML document structure as well.

This project exposes an XML Schema (.xsd) that is used for validating an XML document containing documentation to ensure that it is being correctly processed.

Exceptions

Some elements are ignored when processing the XML document because they either are complex to use or there is little support for them.

  • include is being ignored because its usage is rather complex and can be misleading. The documentation is being kept separate from the source code which can easily lead to discrepancies when changes to code occur.

  • permission is being ignored because its usage is more of an edge case and code permissions are not supported in .NET Core making this element obsolete in this case.

Interpretations

There are XML elements defined for various sections and limited markup support. The main sections for documentation are the following:

  • summary
  • typeparam (available only for types and methods)
  • param (available only for delegates, constructors, methods, properties with parameters)
  • returns (available only for delegates and methods with result)
  • exception (available only for delegates, constructors, methods and properties)
  • remarks
  • example
  • value (available only for properties)
  • seealso

All of the above sections can contain documentation made out of blocks, text and limited markup. seealso does not contain any content and are interpreted as references.

The content blocks are made using the following tags:

It is not mandatory to specify the para element because it is inferred. It is mandatory to do so only when you want to distinguish two paragraphs that are one after the other, but if there is plain text that has a code or a list element then the text before the respective tag is considered a paragraph and the text afterwards is considered a separate paragraph.

For instance, the following returns section contains three paragraphs, a code block and a list.

<remarks>
This is my first paragraph.
<code>
This is a code block
</code>
This is my second paragraph.
<list>
    <item>Item 1</item>
    <item>Item 2</item>
    <item>Item 3</item>
</list>
This is my third paragraph.
</remarks>

To distinguish two paragraphs one after the other you need to use the para tag.

<remarks>
<para>
    This is my first paragraph.
</para>
<para>
    This is my second paragraph.
</para>
</remarks>

Each content block can contain plain text and limited markup using the following tags:

Some XML elements lack a proper documentation and are not properly interpreted by Visual Studio.

List is one of these elements, regardless of how you define the list element, Visual Studio will display the contents as plain text. This is understandable, there should not be such complex markup in the summary of a method or parameter description.

One the other hand, the lack of documentation for this element and the lack of proper interpretation allows for more flexibility when it comes to parsing lists. This tool parses lists as follows:

Simple Lists

This corresponds to list type bullet and number that have no listheader element.

To define a list simply use the list element, specify a type (the default is bullet) and then define each item using an item element. Optionally include a description subelement (this is more for compliance with the documentation, having a description element or not makes no difference).

Examples

Bullet (unordered) list:

<list type="bullet">
    <item>this is an item</item>
    <item>
        <description>this is an item using description, it is the same as the first one</description>
    </item>
    <item>the description element is optional, use at your discretion</item>
</list>

Number (ordered) list:

<list type="number">
    <item>first item</item>
    <item>second item</item>
    <item>third item</item>
</list>

Definition Lists

This is where it can get a bit confusing. The definition list is inferred by the given list type (bullet or number) or lack of this attribute. Definition lists cannot be ordered or unordered, they define a list of terms. This makes the type attribute rather useless in this case, it can be safely omitted since the default is bullet and alligns with the interpretation.

To create a definition list it must either have a title or one of its items to contain the term element. The title is optional, however if the list element is empty it will not be inferred as a definition list!

Optionally, a definition list can have a title which is defined using the listheader element. The title can be written directly in the element or can be wrapped in a term element.

Examples

Simple definition list:

<list>
    <item>
        <term>Exception</term>
        <description>Describes an abnormal behaviour</description>
    </item>
    <item>
        <term>Logging</term>
        <description>Something we should be doing</description>
    </item>
    <item>
        <term>HTTP</term>
        <description>HyperText Transfer Protocol, today's standard for communication</description>
    </item>
</list>

Definition list with title:

<list>
    <listheader>Music Genres</listheader>
    <item>
        <term>Pop</term>
        <description>Very popular (hence the name) genre, mostly singing nonsence.</description>
    </item>
    <item>
        <term>Rock</term>
        <description>Experiences with depth that are very musical with some grotesque exceptions that seem more like yelling than singing.</description>
    </item>
    <item>
        <term>EDM</term>
        <description>Electronic Dance Music, less singing mostly used for background noise or to help get into a specific mood.</description>
    </item>
</list>

Same definition list, we can wrap the title in a term element to conform with the documentation:

<list>
    <listheader>
        <term>Music Genres</term>
    </listheader>
    <item>
        <term>Pop</term>
        <description>Very popular (hence the name) genre, mostly singing nonsence.</description>
    </item>
    <item>
        <term>Rock</term>
        <description>Experiences with depth that are very musical with some grotesque exceptions that seem more like yelling than singing.</description>
    </item>
    <item>
        <term>EDM</term>
        <description>Electronic Dance Music, less singing mostly used for background noise or to help get into a specific mood.</description>
    </item>
</list>

A definition list without a term for its second item:

<list>
    <item>
        <term>LOL</term>
        <description>Usually meaning laughing out loud, can be confused with League of Legends, a very popular video game.</description>
    </item>
    <item>
        <description>For some reason I forgot to mention the term I am currently describing, Infer this!</description>
    </item>
</list>

Tables

This is where things will get a bit interesting. Tables are useful in a lot of scenarios, however there is no explicit syntax for them.

To define a table specify the type of a list to table. To define the header rows (if any) use the listheader element, to define each column header specify multiple term elements.

To define each row use the item element and for each column use a description element.

The number of columns is determined by the maximum number of term or description elements found in an enclosing element (listheader or item). If there are missing values for a column header or row then they will be filled with blank.

Examples

Simple table:

<list type="table">
    <listheader>
        <term>Column 1</term>
        <term>Column 2</term>
    </listheader>
    <item>
        <description>Row 1, Column 1</description>
        <description>Row 1, Column 2</description>
    </item>
    <item>
        <description>Row 2, Column 1</description>
        <description>Row 2, Column 2</description>
    </item>
    <item>
        <description>Row 3, Column 1</description>
        <description>Row 3, Column 2</description>
    </item>
</list>

Table without heading:

<list type="table">
    <item>
        <description>Row 1, Column 1</description>
        <description>Row 1, Column 2</description>
    </item>
    <item>
        <description>Row 2, Column 1</description>
        <description>Row 2, Column 2</description>
    </item>
    <item>
        <description>Row 3, Column 1</description>
        <description>Row 3, Column 2</description>
    </item>
</list>

Table with missing values for last column:

<list type="table">
    <listheader>
        <term>Column 1</term>
    </listheader>
    <item>
        <description>Row 1, Column 1</description>
    </item>
    <item>
        <description>Row 2, Column 1</description>
        <description>Row 2, Column 2</description>
    </item>
    <item>
        <description>Row 3, Column 1</description>
    </item>
</list>

codemap's People

Contributors

andrei15193 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

codemap's Issues

Add Support for Anchor (a) Elements

Currently, the only way to create hyperlinks inside the documentation is by using the see and seealso elements. It would be great to be able to use <a href="...">...</a> elements to create custom hyperlinks. Sometimes we need to add links to different pages (NuGet packages, GitHub repositories, tutorials and so on) that cannot be referenced by a member reference.

Adding the a tag as an addition to the documentation elements would help with this.

XML Documentation File Processing

Processing an XML documentation file should be made before processing the assembly for which it was generated.

The processing should read all members and group them by canonical name. There is no use of the canonical name resolver while reading the XML documentation file! The result should be a collection-like object that can be queried to retrieve the entire documentation elements for a member, e.g.:

var memberInfo = typeof(string);
var canonicalNameResolver = new CanonicalNameResolver();
var canonicalName = canonicalNameResolver.GetCanonicalNameFor(typeof(memberInfo);
if (xmlDocumentationReadResult.TryGetDocumentation(canonicalName , out var memberDocumentation))
{
    // has documentation, do something
}
else
{
    // does not have documentation, trigger warning?
}

Same as with the canonical name resolver, the search is done in case insensitive where a perfect match (case sensitive match) is preferred. I.e.: if a case sensitive match is found then that one is returned even if it is the last element; otherwise the first case insensitive match is returned.

With regards to how XML elements are interpreted (see readme.md which will be moved in the wiki section as part of the documentation) each will have a corresponding C# element. In order to access the documentation elements a visitor should be made available.

Add Access Modifier Filter

Depending on how much we want to expose from a library, it would be better to be able to specify an access modifier filter when the assembly declaration node is being created for all contained members. There's no point in including members that we are not interested in in the tree representation as they would be filtered later on.

This can reduce the memory footprint as the documentation tree is smaller, but also removes filtering of members at multiple levels later on as documentation is being generated from the documentation tree.

Add Support for Multiple Themes

CodeMap.Handlebars can provide multiple themes out of the box, based on different libraries like Bootstrap, FabricUI etc., but, they can be adapted to generate Liquid pages (with front matter) from which Jekyll can pick them up and generate the website. This would make it easier to update references as there would only be one layout file containing the references and would be easy to combine with Jekyll and have a Blog along side the project site.

Migrate to .NET Standard

The project should be targeting .NET Standard to be generally available for all project types as each user of this library will generate their documentation from referencing the desired assembly from a project dedicated with generating the documentation. This ensures that all dependencies are available when this happens.

Add Deprecation Notice

Add a deprecation notice on top of the documentation page for members decorated with the ObsoleteAttribute. If the configuration to break compilation, then use an error banner; otherwise use a warning banner.

Create XML Writer Documentation Visitor

Create an XML writer documentation visitor that will export the entire documentation in an XML format that can later be loaded into 3rd party tools and generate web pages from it.

All documentation members should be included, update this ticket with the XML schema and include it in the remarks section of the visitor documentation as well.

Expand Default Member Reference Resolver

The default member reference resolver only accounts for one assembly as being the library, but does not cover the scenario where the project is made out of multiple referenced libraries (e.g.: CodeMap.Handlebars references CodeMap, but the links from the former to the latter are broken because a MS Doc hyperlink is created).

The member reference resolver should be available for multiple assemblies. An aggregate member reference resolver can be created which picks a specific resolver based on the assembly to which a MemberReference points to. More like a switch for assemblies.

Inconsistent Reference Model

The MemberInfoReferenceDocumentationElement used to reference MemberInfos from XML documentation should not expose a reference to the referred MemberInfo as this will force visitors to implement referencing logic for the MemberInfo (what if it's a type? what if it's a method? How should the link be displayed?).

There already is a TypeReferenceData defined, it should be extended such that any MemberInfo can be referenced and thus providing a single model for referencing members of an Assembly.

Move CodeMap.Handlebars to Own Repostiory

Currently, this repository contains both the CodeMap implementation as well as the Handlebars default implementation for generating a static website based on CodeMap. This is to provide a default implementation that generates documentation from source code to HTML out of the box with the option to customize this at every point, from customizing the Handlebars templates to being able to generate documentation in your own format (maybe you want a React app for that, you are completely able to do that with this library).

The Handlebars implementation should be moved to its own repository in order to be able to track changes particularly for that without interfering with the library code changes and vice-versa. Versions might go astray, but it is unlikely as any feature added to CodeMap should be covered by the Handlebars based implementation as these features expose additional information about a documented library that people may want to know about.

One problem that can arise from this is a form of circular referencing. In order to update this libraries documentation site, the Handlebars based implementation needs to also be updated to the latest CodeMap version which means that first, a CodeMap release has to be made (e.g.: an alpha release) which then is used by CodeMap.Handlebars which then is used by the documentation generating console app in this repository which requires another release in order to build the documentation site.

Define Update Visitor

Define an update visitor that allows to selectively update specific nodes from a documentation tree. Updates are made by creating a new node as the entire tree is read-only for the user.

This will allow elements to be updated with documentation (assemblies, namespaces, default constructors) and afterwards traversed with a writer visitor to generate JSON, XML, HTML or any other format instead of having this done in each writer visitor.

The documentation tree is not an actual tree as methods that are 'childs' of a type can reference other type nodes defined in the assembly and thus are part of the same 'tree' making the documentation tree more of a graph. This isn't necessarily bad as this can allow easy checking if the referred type is defined in the same assembly or not (e..g.: typeReference is TypeDocumentationElement or typeReference.Assembly == declaringType.Assembly).

The update visitor traverses the entire old documentation tree, even if a type is updated references to it will still go to the old instances when traversing. Once the update is complete a new tree is constructed with the updated instances. If null is returned for one of the documentation elements then that element is removed. Most likely only the AssemblyDocumentationElement to expose a method for the update visitor as an update at any other level itself may not make sense as the NamespaceDocumentationElement and type declaration documentation elements have references to the assembly, updating them alone would mean the reference to the old assembly documentation element is kept and a new one is not created meaning that the updated documentation elements will be left out when traversing from the assembly documentation element!

Due to circular references the entire tree will be recreated in order to remove all references to old elements.

Updates should be available only for the XML related documentation so that the summary or remarks of a documentation element may be updated.

Create JSON Writer Documentation Visitor

Create a JSON writer documentation visitor that will export the entire documentation in a JSON format that can later be loaded into 3rd party tools and generate web pages from it.

All documentation members should be included, update this ticket with a JSON schema or structure definition and include it in the remarks section of the visitor as well.

XML Canonical Name Resolution

The references in the XML documentation file follow a specific syntax from which one can find the member that is referenced. For instance, a <see cref="string"/> will generate <see cref="T:System.String"/> where T:System.String is the canonical name in the resulting XML documentation file. There is no need to specify in which assembly the type is found because all referenced assemblies must contain unique types (i.e.: the same name for a type cannot be used inside the same namespace even when they are part of different assemblies and they are both referenced, it is ambiguous which one should be used as neither in code do we specify the assembly when we import a namespace or declare a variable).

The generated XML documentation file contains references to various members of a .NET assembly (all references resolve to a MemberInfo), it is possible to reference members of assemblies that are not listed in the referenced assemblies (see Assembly.GetReferencedAssemblies, this method returns only referenced assemblies that are actually used in code, the csproj can reference 100 assemblies but the resulting one to reference only 3).

There are no stated rules to how the canonical name is determined, however generating an XML documentation file from test data that contains most, if not all, possible scenarios we can infer the rules.

The format of the canonical name is <member_type_character_identifier>:<full_name_with_parameters>. The member_type_character_identifier is one of the following:

The full_name_with_parameters contains the namespace of the type or declaring type along side the name of all declaring type in case of a nested type where each name part is separated with a period (.), this is different from what reflection returns for nested types.

In other words, the full_name_with_parameters for a type is the same as when referencing a type in C# without importing any namespaces. For type members (fields, properties, events and methods) the name of the member is appended at the end of the declaring type full name, if the property or method has parameters then the list of parameter types is concatenated after the name between parenthesis (( and )) and each parameter type is delimited by comma (,). The parameter list (including parenthesis) is included only if there are any parameters, if a method has no parameters then the canonical name will look the same as for a field.

A special case is made for constructors as they follow the same rules as methods only that the method name id #ctor for instance constructors and #cctor for static constructors.

Generic types can have the same name as non generic ones, in fact the difference between generic types and methods is made by it's number of generic parameters. This is similar to overloading methods only that just the number of parameters makes a difference, generic constraints do not count. To differentiate between a generic type and a non-generic type in the reference, if there are any generic parameters then their number is appended at the end of the type name after a backquote (`) and after two backquotes for generic methods (``).

When declaring methods that use generic parameters as their parameter types they are referred using one or two backquotes (`) followed by the index (starting from 0) of the respective generic parameter. One backquote is for generic parameters declared by the type and two backqoutes for the ones declared by the method.

Below is the inferred EBNF for the canonical name rules (EBNF Evaluator can be used to test the definition):

CanonicalName ::= MemberType ':' TypeFullName ('.' MemberName)?
MemberType    ::= ('T' | 'F' | 'E' | 'P' | 'M')
MemberName    ::= ( '#cctor' | '#ctor' | Identifier ('``' #'[0-9]+')? ) Parameters?
Parameters    ::= '(' ParameterType (',' ParameterType)* ')'
ParameterType ::= ( TypeFullName | #'`{1,2}[0-9]+' )
TypeFullName  ::= Identifier ('`' #'[0-9]'+)? ('.' TypeName)*
TypeName      ::= Identifier ('`' #'[0-9]'+)?
Identifier    ::= #'[a-zA-Z_][0-9a-zA-Z_]*'

Examples of canonical names:

  • <see cref="string"/> -> T:System.String
  • <see cref="IEnumerable{T}"/> -> T:System.Collections.Generic.IEnumerable`1
  • <see cref="IEnumerable{T}.GetEnumerator" -> M:System.Collections.Generic.IEnumerable`1.GetEnumerator
  • <see cref="Tuple.Create{T1}(T1)"/> -> M:System.Tuple.Create``1(``0)
  • <see cref="Action{T}.Invoke(T)"/> -> M:System.Action`1.Invoke(`0)

Improve Test Data

The current test data covers most, if not all, scenarios that may be encountered in an assembly definition. The test data should be improved to reduce the number of parameters on methods and index properties, to make it look like more of what would be expected in an actual library. The number of methods may explode due to this, but rather than having one method with all parameter possibilities it is better to have multiple methods with each scenario.

The test data project will also serve as a source documentation project when creating templates for generating documentation as it covers most, if not all, cases. This will help test the base documentation generators as that needs to cover all cases as well.

Improve Assembly Lookups

As a developer I want to use the library to scan .NET Assemblies regardless of the runtime they were build for (.NET Framework, UWP or .NET Core) so that I can use it to generate documentation for any kind of project I am building

Currently there are some issues when scanning an assembly depending on the runtime it was built for, some references cannot be loaded, this should be fixed and included in a test suite so that it works across all .NET Assemblies. After all, it's just one standard, it should work.

Create project site

It would be great, as with any library, to have a project site where the documentation is available. If only there was a library that reads assemblies and related XML documentation and allows documentation to be generated from them, oh wait, it's this one!

As a great dogfooding exercise, the repository can contain a clear example of how to use it by generating documentation for itself.

Drop Async Implementation

There is really no need for the async implementation. The synchronous one is enough as any operation that takes too long can be easily moved to a Task.Run(). It is most likely that the operation that takes too long and might block a UI thread requires to be fully completed before displaying any results.

All async methods can be dropped and only the synchronous ones can be kept, it would make using the library much more easier.

Update DocumentationElements to use ReferenceData

Currently, the Documentation Elements and Reference Data are separate, however this can have an impact on generating documentation as sometimes the user has to deal with Reference Data (coming from Declaration Nodes) and in other cases they have to deal with MemberInfos (coming from Documentation Elements).

The referencing should be streamlined across and any member reference that is made should be represented by a Reference Data. This will ensure consistency and ease of use since the entire type system is abstracted to a common representation.

Refactor Template Writer & IMemberReferenceResolver

Right now, the template writer does a great job for generating files. The downside of it is because of the IMemberReferenceResolver you need to create a new template writer each time you want to generate documentation for a specific Declaration Node graph. It would be great to be able to have just one template writer that can work for every Declaration Node graph.

Include CodeMap.Handlebars in Release

Currently, only the CodeMap description and release notes are included in the release that is created using GitHub Actions. The description and release notes of CodeMap.Handlebars should be included as well, along side the generated NuGet package as an attachment.

Add Test Data Site

As the latest changes on master are available under the /dev on the project site, the latest test data website should be generated under /test-data for testing purposes and preview. When there are multiple templates for generating project sites this can be renamed to /templates which has a landing page where all the templates can be browsed and previewed.

This issue is best done after #24.

Improve Reference Data

Currently, Reference Data has a slight split between MemberInfo representations and AssemblyName and there's no Reference Data representation for namespaces. The aim is to be able to provide a Reference Data object for each Declaration Node to ease generation of documentation. Both objects are generated from reflection and one should be convertible to the other, namely Documentation Node to Reference Data. This will simplify link generation because all links would be generated exclusively from Reference Data.

All Reference Data members should have the same base class.

In addition, a global Reference Data Factory should be encapsulated somewhere to ease creation of reference data, This would be useful when making documentation additions as a separate factory would no longer need to be created and Documentation Elements would be able to be created from MemberInfos directly.

All referred members are part of an assembly, there should be an easy way to get the declaring assembly of a referred member from the base type. This will help with member reference resolvers as one may be picked over the other depending on the declaring assembly.

Lastly, type references should contain a type reference for the declaring type in case of references towards nested types.

Promote Common Code

Over the development of some features there is some common code (validation for now) that should be promoted to factory-zero.

  • IThreadSafe in Covenant
  • CommonValidation in Covenant
  • CommonValidationTests in Covenant.Tests

Extend Reference Data Visitor

The Reference Data Visitor currently handles all types of references except assembly ones because assembly references do not have an Accept method.

Assembly references should also be visitable as they can be used in other parts of the documentation object model (assembly dependencies), this will help reduce code duplication and maintain consistency when writing assembly references.

Separate Documentation Object Model

Currently, all object models are, more or less, defined using a single object model. Reference Data, Documentation Data (from XML documentation) and Reflection Data (from the scanned Assembly). These object models should be split into three distinct parts:

  • Reference Data (see #14) - responsible to provide users with all the required data for creating references to different types and members (links to Microsoft Docs, other libraries, same library and so on).
  • Documentation Elements - responsible with mapping the XML documentation elements to a tree of elements that can be traversed (or visited) and thus accessing written documentation. May use Reference Data (check <see cref="..."/> XML tag).
  • Declaration Nodes - responsible with mapping the relevant declaration elements (assembly, types, methods and so on) so that they can be traversed and finally generate the documentation of an assembly. May use both Reference Data and Documentation as this is the entry point for creating a documentation, both what is declared and associated written documentation need to be available.

This will split the code into three main parts each having its own responsibility. This will make understanding, testing and maintaining the library easier.

Create Build Pipeline for Releases

Create build pipeline that updates the version according to branch naming and published NuGet packages. The pipeline needs to build, test and generate a NuGet package in the build artifacts and is configured only for when changes are pushed unto releases/* breanches, not for pull request validation.

Include Default Structure for Handlebars Templates and Assets

While the current implementation is great, it requires a class to be declared to provide new or override custom templates. This scenario should still be available since there may be some edge cases where the default loading of templates needs to be changed.

The current writer should be able to load resources from multiple assemblies given they have a specific structure (e.g.: at the project level, the .hbs embedded resources under templates and partials are loaded automatically). The order of the assemblies also provides the precedence thus if there are multiple templates with the same name the last one is the one that has precedence. This is similar to loading the resources in each assembly using an add or replace approach.

public IReadOnlyDictionary<string, string> LoadTemplates(IEnumerable<Assembly> additionalAssemblies)
{
    var templates = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
    foreach (var template in GetTemplatesFrom(Enumerable.Repeat(codeMapHandlebarsAssembly, 1).Concat(additionalAssemblies)))
        templates[GetTemplateName(template)] = LoadTemplate(template);
    return templates;
}

In addition to templates, it would be great to cover the Assets folder as well. Basically everything in the Assets folder (including the folder structure) can just be pasted into a DirectoryInfo. This includes CSS files, favicons, pictures and so on.

Assembly Processing

Having the related XML documentation processed and loaded into MemberDocumentation items should allow for completely processing a .NET assembly and related documentation. For each member in the assembly the related documentation is looked up constructing a new DocumentationElement that represents the respective member (type, method, property etc.).

A factory should be defined for creating documentation elements from specific reflection instances (Type, MethodInfo, ConstructorInfo and so on). This will simplify the creation of such elements and make testing much more easier.

Update Visitor Interface

Currently, the visitor allows to go through each reflection related documentation element (assembly, classes, namespaces etc.) but for XML documentation elements it has a 'begin' and 'end' methods pair which is somewhat alright. The issue is that the sequence in which methods are called is important to know in order to be 99% sure you are generating a correct document.

This is problematic because a method should ensure that the generated content (e.g.: JSON) is formed correctly. Generally, if a JSON object or array is started in a method it should also be closed in the same method. There might be exceptions from this rule, but it definitely should not be main pattern to follow.

Prepare beta1 Release

There's been a lot of work done and the library is in a good shape to have it's first release. This should include both CodeMap and CodeMap.Handlebars as the pair with these two provides a full implementation from source code to documentation page that should be covered in articles or blog posts to promote the application but also provide tutorials on how to use it and the intend behind it, how it started and why.

Create HTML Writer Documentation Visitor

Create an HTML writer documentation visitor that will generate a single HTML file containing the entire documentation for a .NET assembly and related XML documentation.

The resulting file should be a single page application styled using Bootstrap that allows users to view the entire documentation starting from the assembly level then going through each namespace, each type and finally each member.

Only public members are included in the resulting documentation.

Custom Attributes in XML Documentation

Process custom XML attributes to allow for more customization when traversing the documentation tree. Useful scenarios are for writing inline code and code blocks, it would be useful to hint towards the language that is used so that it can be highlighted when displaying the end result. E.g.:

/// <summary>
///     <code language="C#">
///     public class Test
///     {
///     }
///     </code>
/// </summary>

A second useful scenario is when describing multiple examples to be able to have a title for each so that it is clear what is being illustrated in each example. E.g.:

/// <example title="Example 1">
/// ...
/// </example >
/// <example title="Example 2">
/// ...
/// </example>

Last but not least, having a rather long sections can happen especially when you want to include a tutorial through the examples section. Being able to group paragraphs and other block elements into subsections can be beneficial to the reader and overall structure of the documentation. This is usually done by using heading, a paragraph, list, table or code block can be used to insert a heading by using a custom attribute. E.g.:

/// <example>
/// <para caption="Part 1">
/// ...
/// </para>
/// <list caption="Part 2">
/// ...
/// </para>
/// </example>

Improve Reference Data Object Model

Right now the reference data object model only supports references to Type and is intertwined with the Reflection Documentation Elements Object Model for generic parameter definitions. This is problematic as this forces to place the creation logic for reference data and reflection documentation elements in one place in order to properly cache the instances and reuse them and it is hard to reuse the creation logic outside this specific factory.

With #13 any MemberInfo should be able to be referenced using the reference data object model (including generic definitions and constructed generic types and methods).

The Reference Data Object Model should be a completely separate model from the Reflection Documentation Element Object Model and from the XML Documentation Element Object Model (naming for these last two may change before the 1st release). This object model should have its own visitor class to further separate the responsibility of the visitor class that is currently defined.

Transforming Reference Data is tied to transforming the entire documentation, however this is always treated separately and it always ends up checking what concrete instance a Reference Data object is in order to properly transform the reference. This is the exact same situation as with Documentation Elements which was addressed using the Visitor Pattern, the same should be done in this case. Breaking the visitor in two will make it easier to test and maintain as well.

Shadowed Constants Tests

There is no test case for shadowing constants and from the implementation it results that the flag will always be set to false. Constants can be shadowed, this applies to inheritance hierarchies where the constant can be referred just by name inside the subclass.

public BaseClass
{
    public const int Constant = 1;
}

public SubClass : BaseClass
{
    public const int Constant = 2; // The compiler issues a warning that the member implicitly hides an inherited member

    public SubClass()
    {
        var whoAmI = Constant; // the value is 2, this is because the newly defined constant shadows the base class member with the same name
    }
}

This case should be covered by tests to ensure the flag gets set properly.

Cache Dynamic Type Reference

The MemberReferenceFactory caches all instances of member references that are created. This is due to circular references and to reduce the memory print when referencing the same member multiple times.

The DynamicTypeReference is more of a special case because it does not map to any MemberInfo instance because it is not really an actual type. Behind the scenes it is represented by the object type and decorated with DynamicAttribute for parameters and return types. To create a DynamicTypeReference a separate method needs to be called.

When created, the DynamicTypeReference is not cached like other member references. This is not consistent with the factory and should be changed.

Sign Assembly for Every Build

Currently, the assembly will be signed only when it is being packaged. This is a bit problematic when it comes to testing as the PublicKeyToken is not being properly tested for CodeMap.Tests.Data. The build script should always sign the resulting assemblies and only provide versioning information when being packaged (to not override CodeMap.Tests.Data version as that is being tested as well).

Extend Project Site

Currently, both CodeMap and CodeMap.Handlebars are being hosted in the same repository. The documentation website should be extended to include documentation for both as well as a landing page describing the aim of the project and maybe a small example on how to use it.

See and SeeAlso Support Hyperlink References

The anchor custom element was added to address references to external resources through hyperlinks, this was either missed or added at a later time, but now we can do this using the href attribute on see and seealso elements.

This is great as it no longer requires a custom element and it can be safely removed in favor of the officially supported ones (not to mention IDE support).

References

Ensure Library is CLS Compliant

In order to ensure library compliance it should be marked as CLS Compliant. This will ensure that code that is non-CLS compliant is not made part of the library and will make sure that any language following the Common Language Specifications (CLS) will be able to use the library.

Add Support for Inheritdoc

This would be a great feature because in a number of cases, the exact same documentation from a base class or implemented interface is used by the library code. Even in the same library, there are types that specialise other types, but we would like to keep the same remarks section and maybe change the summary a bit.

The inheritdoc tag should copy all the available documentation for a MemberInfo, and allow overwriting parts of it. For instance, just writing inheritdoc will copy the documentation:

/// <inheritdoc/>
public override void Method(string param1, int param2)
{
    ...
}

But if I write a summary for the method I expect to have all other documentation copied (parameters, returns, exceptions and so on.) and only have the summary updated.

/// <inheritdoc/>
/// <summary>Updated summary</summary>
public override void Method(string param1, int param2)
{
    ...
}

This feature will extend the documentation lookup because the related XML documentation file needs to be loaded for all referenced assemblies. It is possible that not all referenced assemblies will have their documentation inherited, to reduce the memory print and load time it is okay to implement this extra lookup as a lazy loaded resource from the start.

Add Support for Operators

Currently there is no support for operators. They are not used a lot, however it would be great to have them covered in the documentation tree.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.