Skip to content

Commit

Permalink
Generate documentation that can be published with Docusaurus (#918)
Browse files Browse the repository at this point in the history
  • Loading branch information
josefpihrt authored Jul 17, 2022
1 parent 832a70b commit dbfc734
Show file tree
Hide file tree
Showing 41 changed files with 1,105 additions and 504 deletions.
2 changes: 2 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Convert more syntax to implicit object creation (RCS1250) ([#910](https://github.com/josefpihrt/roslynator/pull/910)).
- Add code fix for CS0037 ([#929](https://github.com/josefpihrt/roslynator/pull/929)).
- [CLI] Generate reference documentation that can be published with Docusaurus ([#918](https://github.com/josefpihrt/roslynator/pull/918)).
- `roslynator generate-doc --host docusaurus`

### Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="DotMarkdown" Version="0.1.1" />
<PackageReference Include="DotMarkdown" Version="0.2.0" />
<PackageReference Include="CommandLineParser" Version="2.8.0" />
</ItemGroup>

Expand Down
3 changes: 2 additions & 1 deletion src/CommandLine/CommandLine.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<PropertyGroup Condition="'$(RoslynatorDotNetCli)' == true AND '$(Configuration)' == 'Release'">
<PropertyGroup Condition="'$(RoslynatorDotNetCli)' == true">
<TargetFrameworks>net5.0;net6.0</TargetFrameworks>
</PropertyGroup>

Expand Down Expand Up @@ -51,6 +51,7 @@
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="4.2.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="DotMarkdown" Version="0.2.0" />
</ItemGroup>

<ItemGroup>
Expand Down
102 changes: 94 additions & 8 deletions src/CommandLine/Commands/GenerateDocCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using DotMarkdown;
using Microsoft.CodeAnalysis;
using Roslynator.Documentation;
using Roslynator.Documentation.Markdown;
Expand All @@ -26,9 +27,14 @@ public GenerateDocCommand(
NamespaceDocumentationParts ignoredNamespaceParts,
TypeDocumentationParts ignoredTypeParts,
MemberDocumentationParts ignoredMemberParts,
CommonDocumentationParts ignoredCommonParts,
OmitMemberParts omitMemberParts,
IncludeContainingNamespaceFilter includeContainingNamespaceFilter,
Visibility visibility,
DocumentationHost documentationHost,
FilesLayout filesLayout,
bool groupByCommonNamespace,
InheritanceStyle inheritanceStyle,
in ProjectFilter projectFilter) : base(projectFilter)
{
Options = options;
Expand All @@ -37,9 +43,14 @@ public GenerateDocCommand(
IgnoredNamespaceParts = ignoredNamespaceParts;
IgnoredTypeParts = ignoredTypeParts;
IgnoredMemberParts = ignoredMemberParts;
IgnoredCommonParts = ignoredCommonParts;
OmitMemberParts = omitMemberParts;
IncludeContainingNamespaceFilter = includeContainingNamespaceFilter;
Visibility = visibility;
DocumentationHost = documentationHost;
FilesLayout = filesLayout;
GroupByCommonNamespace = groupByCommonNamespace;
InheritanceStyle = inheritanceStyle;
}

public GenerateDocCommandLineOptions Options { get; }
Expand All @@ -54,17 +65,28 @@ public GenerateDocCommand(

public MemberDocumentationParts IgnoredMemberParts { get; }

public CommonDocumentationParts IgnoredCommonParts { get; }

public OmitMemberParts OmitMemberParts { get; }

public IncludeContainingNamespaceFilter IncludeContainingNamespaceFilter { get; }

public Visibility Visibility { get; }

public DocumentationHost DocumentationHost { get; }

public FilesLayout FilesLayout { get; }

public bool GroupByCommonNamespace { get; }

public InheritanceStyle InheritanceStyle { get; }

public override async Task<CommandResult> ExecuteAsync(ProjectOrSolution projectOrSolution, CancellationToken cancellationToken = default)
{
AssemblyResolver.Register();

var documentationOptions = new DocumentationOptions(
rootFileHeading: Options.Heading,
ignoredNames: Options.IgnoredNames,
preferredCultureName: Options.PreferredCulture,
maxDerivedTypes: Options.MaxDerivedTypes,
Expand All @@ -82,26 +104,90 @@ public override async Task<CommandResult> ExecuteAsync(ProjectOrSolution project
includeInheritedAttributes: !Options.OmitInheritedAttributes,
omitIEnumerable: !Options.IncludeIEnumerable,
depth: Depth,
inheritanceStyle: Options.InheritanceStyle,
inheritanceStyle: InheritanceStyle,
ignoredRootParts: IgnoredRootParts,
ignoredNamespaceParts: IgnoredNamespaceParts,
ignoredTypeParts: IgnoredTypeParts,
ignoredMemberParts: IgnoredMemberParts,
ignoredCommonParts: IgnoredCommonParts,
includeContainingNamespaceFilter: IncludeContainingNamespaceFilter,
filesLayout: FilesLayout,
scrollToContent: Options.ScrollToContent);

ImmutableArray<Compilation> compilations = await GetCompilationsAsync(projectOrSolution, cancellationToken);

var documentationModel = new DocumentationModel(compilations, DocumentationFilterOptions.Instance, Options.AdditionalXmlDocumentation);
#if DEBUG
SourceReferenceProvider sourceReferenceProvider = (Options.SourceReferences.Any())
? SourceReferenceProvider.Load(Options.SourceReferences)
: null;

var generator = new MarkdownDocumentationGenerator(documentationModel, WellKnownUrlProviders.GitHub, documentationOptions, sourceReferenceProvider);
#else
var generator = new MarkdownDocumentationGenerator(documentationModel, WellKnownUrlProviders.GitHub, documentationOptions);
List<INamespaceSymbol> commonNamespaces = null;

if (GroupByCommonNamespace)
{
commonNamespaces = DocumentationUtility.FindCommonNamespaces(
documentationModel.Types.Concat(documentationModel.GetExtendedExternalTypes()));
}

UrlSegmentProvider urlSegmentProvider = new DefaultUrlSegmentProvider(FilesLayout, commonNamespaces);

var externalProviders = new MicrosoftDocsUrlProvider[] { MicrosoftDocsUrlProvider.Instance };

DocumentationUrlProvider GetUrlProvider()
{
switch (DocumentationHost)
{
case DocumentationHost.GitHub:
return new GitHubDocumentationUrlProvider(urlSegmentProvider, externalProviders);
case DocumentationHost.Docusaurus:
return new DocusaurusDocumentationUrlProvider(urlSegmentProvider, externalProviders);
default:
throw new InvalidOperationException($"Unknown value '{DocumentationHost}'.");
}
}

MarkdownWriterSettings GetMarkdownWriterSettings()
{
switch (DocumentationHost)
{
case DocumentationHost.GitHub:
return MarkdownWriterSettings.Default;
case DocumentationHost.Docusaurus:
return new MarkdownWriterSettings(new MarkdownFormat(angleBracketEscapeStyle: AngleBracketEscapeStyle.EntityRef));
default:
throw new InvalidOperationException($"Unknown value '{DocumentationHost}'.");
}
}

MarkdownWriterSettings markdownWriterSettings = GetMarkdownWriterSettings();

DocumentationWriter CreateDocumentationWriter(DocumentationContext context)
{
MarkdownWriter writer = MarkdownWriter.Create(new StringBuilder(), markdownWriterSettings);

switch (DocumentationHost)
{
case DocumentationHost.GitHub:
return new MarkdownDocumentationWriter(context, writer);
case DocumentationHost.Docusaurus:
return new DocusaurusDocumentationWriter(context, writer);
default:
throw new InvalidOperationException($"Unknown value '{DocumentationHost}'.");
}
}

SourceReferenceProvider sourceReferenceProvider = null;
#if DEBUG
if (Options.SourceReferences.Any())
sourceReferenceProvider = SourceReferenceProvider.Load(Options.SourceReferences);
#endif
var context = new DocumentationContext(
documentationModel,
GetUrlProvider(),
documentationOptions,
c => CreateDocumentationWriter(c),
sourceReferenceProvider: sourceReferenceProvider,
commonNamespaces: commonNamespaces);

var generator = new DocumentationGenerator(context);

string directoryPath = Options.Output;

if (!Options.NoDelete
Expand Down
61 changes: 60 additions & 1 deletion src/CommandLine/Commands/GenerateDocRootCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using DotMarkdown;
using Microsoft.CodeAnalysis;
using Roslynator.Documentation;
using Roslynator.Documentation.Markdown;
Expand All @@ -24,13 +25,15 @@ public GenerateDocRootCommand(
RootDocumentationParts ignoredParts,
IncludeContainingNamespaceFilter includeContainingNamespaceFilter,
Visibility visibility,
DocumentationHost documentationHost,
in ProjectFilter projectFilter) : base(projectFilter)
{
Options = options;
Depth = depth;
IgnoredParts = ignoredParts;
IncludeContainingNamespaceFilter = includeContainingNamespaceFilter;
Visibility = visibility;
DocumentationHost = documentationHost;
}

public GenerateDocRootCommandLineOptions Options { get; }
Expand All @@ -43,11 +46,14 @@ public GenerateDocRootCommand(

public Visibility Visibility { get; }

public DocumentationHost DocumentationHost { get; }

public override async Task<CommandResult> ExecuteAsync(ProjectOrSolution projectOrSolution, CancellationToken cancellationToken = default)
{
AssemblyResolver.Register();

var documentationOptions = new DocumentationOptions(
rootFileHeading: Options.Heading,
ignoredNames: Options.IgnoredNames,
rootDirectoryUrl: Options.RootDirectoryUrl,
placeSystemNamespaceFirst: !Options.NoPrecedenceForSystem,
Expand All @@ -62,7 +68,60 @@ public override async Task<CommandResult> ExecuteAsync(ProjectOrSolution project

var documentationModel = new DocumentationModel(compilations, DocumentationFilterOptions.Instance);

var generator = new MarkdownDocumentationGenerator(documentationModel, WellKnownUrlProviders.GitHub, documentationOptions);
UrlSegmentProvider urlSegmentProvider = DefaultUrlSegmentProvider.Hierarchical;

var externalProviders = new MicrosoftDocsUrlProvider[] { MicrosoftDocsUrlProvider.Instance };

DocumentationUrlProvider GetUrlProvider()
{
switch (DocumentationHost)
{
case DocumentationHost.GitHub:
return new GitHubDocumentationUrlProvider(urlSegmentProvider, externalProviders);
case DocumentationHost.Docusaurus:
return new DocusaurusDocumentationUrlProvider(urlSegmentProvider, externalProviders);
default:
throw new InvalidOperationException($"Unknown value '{DocumentationHost}'.");
}
}

MarkdownWriterSettings GetMarkdownWriterSettings()
{
switch (DocumentationHost)
{
case DocumentationHost.GitHub:
return MarkdownWriterSettings.Default;
case DocumentationHost.Docusaurus:
return new MarkdownWriterSettings(new MarkdownFormat(angleBracketEscapeStyle: AngleBracketEscapeStyle.EntityRef));
default:
throw new InvalidOperationException($"Unknown value '{DocumentationHost}'.");
}
}

MarkdownWriterSettings markdownWriterSettings = GetMarkdownWriterSettings();

DocumentationWriter CreateDocumentationWriter(DocumentationContext context)
{
MarkdownWriter writer = MarkdownWriter.Create(new StringBuilder(), markdownWriterSettings);

switch (DocumentationHost)
{
case DocumentationHost.GitHub:
return new MarkdownDocumentationWriter(context, writer);
case DocumentationHost.Docusaurus:
return new DocusaurusDocumentationWriter(context, writer);
default:
throw new InvalidOperationException($"Unknown value '{DocumentationHost}'.");
}
}

var context = new DocumentationContext(
documentationModel,
GetUrlProvider(),
documentationOptions,
c => CreateDocumentationWriter(c));

var generator = new DocumentationGenerator(context);

string path = Options.Output;

Expand Down
15 changes: 13 additions & 2 deletions src/CommandLine/Commands/ListSymbolsCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,12 @@ public override async Task<CommandResult> ExecuteAsync(ProjectOrSolution project
using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
using (var streamWriter = new StreamWriter(fileStream, Encodings.UTF8NoBom))
using (MarkdownWriter markdownWriter = MarkdownWriter.Create(streamWriter, markdownWriterSettings))
using (SymbolDefinitionWriter writer = new SymbolDefinitionMarkdownWriter(markdownWriter, SymbolFilterOptions, format, hierarchyRoot: hierarchyRoot, urlProvider: WellKnownUrlProviders.GitHub))
using (SymbolDefinitionWriter writer = new SymbolDefinitionMarkdownWriter(
markdownWriter,
SymbolFilterOptions,
format,
hierarchyRoot: hierarchyRoot,
urlProvider: new GitHubDocumentationUrlProvider(DefaultUrlSegmentProvider.Hierarchical, new MicrosoftDocsUrlProvider[] { MicrosoftDocsUrlProvider.Instance })))
{
writer.WriteDocument(assemblies, cancellationToken);
}
Expand Down Expand Up @@ -351,7 +356,13 @@ private void TestOutput(
WriteLine();

using (MarkdownWriter markdownWriter = MarkdownWriter.Create(ConsoleOut))
using (SymbolDefinitionWriter writer = new SymbolDefinitionMarkdownWriter(markdownWriter, SymbolFilterOptions, format, default(SymbolDocumentationProvider), hierarchyRoot, WellKnownUrlProviders.GitHub))
using (SymbolDefinitionWriter writer = new SymbolDefinitionMarkdownWriter(
markdownWriter,
SymbolFilterOptions,
format,
default(SymbolDocumentationProvider),
hierarchyRoot,
new GitHubDocumentationUrlProvider(DefaultUrlSegmentProvider.Hierarchical, new MicrosoftDocsUrlProvider[] { MicrosoftDocsUrlProvider.Instance })))
{
writer.WriteDocument(assemblies, cancellationToken);
}
Expand Down
10 changes: 10 additions & 0 deletions src/CommandLine/DocumentationHost.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (c) Josef Pihrt and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

namespace Roslynator.CommandLine
{
internal enum DocumentationHost
{
GitHub,
Docusaurus,
}
}
3 changes: 3 additions & 0 deletions src/CommandLine/OptionNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,19 @@ internal static class OptionNames
public const string EndOfLine = "end-of-line";
public const string FixScope = "fix-scope";
public const string Help = "help";
public const string Host = "host";
public const string IgnoredCompilerDiagnostics = "ignored-compiler-diagnostics";
public const string IgnoredMemberParts = "ignored-member-parts";
public const string IgnoredNamespaceParts = "ignored-namespace-parts";
public const string IgnoredParts = "ignored-parts";
public const string IgnoredCommonParts = "ignored-common-parts";
public const string IgnoredProjects = "ignored-projects";
public const string IgnoredRootParts = "ignored-root-parts";
public const string IgnoredScope = "ignored-scope";
public const string IgnoredTypeParts = "ignored-type-parts";
public const string IncludeContainingNamespace = "include-containing-namespace";
public const string IncludeSystemNamespace = "include-system-namespace";
public const string InheritanceStyle = "inheritance-style";
public const string Interactive = "interactive";
public const string Layout = "layout";
public const string Match = "match";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ public abstract class AbstractGenerateDocCommandLineOptions : MSBuildCommandLine
MetaValue = "<DEPTH>")]
public string Depth { get; set; }

[Option(
longName: OptionNames.Host,
Required = true,
HelpText = "Defines a host where the content will be published. Allowed values are github or docusaurus.",
MetaValue = "<HOST>")]
public string Host { get; set; }

[Option(
longName: "ignored-names",
HelpText = "Defines a list of metadata names that should be excluded from a documentation. Namespace of type names can be specified.",
Expand Down
Loading

0 comments on commit dbfc734

Please sign in to comment.