Skip to content

Commit

Permalink
refactor: re-organize dotnet reference generation (#9258)
Browse files Browse the repository at this point in the history
* wip

* refactor: re-organize dotnet reference generation

* test(snapshot): update snapshots for 797dcac

* Add back md snapshots

* minor adjustments

* test(snapshot): update snapshots for d862373

* markdown escape

* fix tests

* test(snapshot): update snapshots for 2383aaa

* adjust docs

* update escape chars

* test(snapshot): update snapshots for 67d13fb

---------

Co-authored-by: Yufei Huang <[email protected]>
  • Loading branch information
yufeih and yufeih authored Sep 30, 2023
1 parent ef5eeb0 commit f16d314
Show file tree
Hide file tree
Showing 136 changed files with 4,123 additions and 1,358 deletions.
21 changes: 14 additions & 7 deletions docs/reference/docfx-json-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,19 +297,26 @@ Specifies the source projects using [File Mappings](#file-mappings).

### `output`

Defines the output folder of the generated metadata files relative to `docfx.json` directory. The `docfx metadata --output <outdir>` command line argument overrides this value.
Specifies the output folder of the generated metadata files relative to `docfx.json` directory. The `docfx metadata --output <outdir>` command line argument overrides this value.

### `outputFormat`

Specifies the generated output file format.

- `mref` (default): output as ManagedReference YAML files.
- `markdown`: Output as common-mark compliant markdown file.

### `dest`

Defines the output folder of the generated metadata files relative to `docfx.json` directory. The `docfx metadata --output <outdir>` command line argument prepends this value.
Specifies the output folder of the generated metadata files relative to `docfx.json` directory. The `docfx metadata --output <outdir>` command line argument prepends this value.

### `shouldSkipMarkup`

If set to true, DocFX would not render triple-slash-comments in source code as markdown.

### `filter`

Defines the filter configuration file, please go to [How to filter out unwanted apis attributes](../tutorial/howto_filter_out_unwanted_apis_attributes.md) for more details.
Specifies the filter configuration file, please go to [How to filter out unwanted apis attributes](../tutorial/howto_filter_out_unwanted_apis_attributes.md) for more details.

### `disableDefaultFilter`

Expand All @@ -321,7 +328,7 @@ Disables generation of view source links.

### `properties`

Defines an optional set of MSBuild properties used when interpreting project files. These are the same properties that are passed to msbuild via the `/property:name=value` command line argument.
Specifies an optional set of MSBuild properties used when interpreting project files. These are the same properties that are passed to msbuild via the `/property:name=value` command line argument.

```json
{
Expand All @@ -343,14 +350,14 @@ Do not run `dotnet restore` before building the projects.

### `namespaceLayout`

Defines how namespaces in TOC are organized:
Specifies how namespaces in TOC are organized:

- `flattened` (default): Renders namespaces as a single flat list.
- `nested`: Renders namespaces in a nested tree form.

### `memberLayout`

Defines how member pages are organized:
Specifies how member pages are organized:

- `samePage` (default): Places members in the same page as their containing type.
- `separatePages`: Places members in separate pages.
Expand All @@ -361,7 +368,7 @@ When enabled, continues documentation generation in case of compilation errors.

### `EnumSortOrder`

Defines how enum members are sorted:
Specifies how enum members are sorted:

- `alphabetic` (default): Sort enum members in alphabetic order.
- `declaringOrder`: Sort enum members in the order as they are declared in the source code.
Expand Down
146 changes: 146 additions & 0 deletions src/Docfx.Dotnet/DotnetApiCatalog.Compile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using Docfx.Common;
using Microsoft.Build.Construction;
using Microsoft.Build.Framework;
using Microsoft.Build.Logging;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.MSBuild;

#nullable enable

namespace Docfx.Dotnet;

partial class DotnetApiCatalog
{
private static async Task<List<(IAssemblySymbol symbol, Compilation compilation)>> Compile(ExtractMetadataConfig config, DotnetApiOptions options)
{
var files = config.Files?.Select(s => new FileInformation(s))
.GroupBy(f => f.Type)
.ToDictionary(s => s.Key, s => s.Distinct().ToList()) ?? new();

var msbuildProperties = config.MSBuildProperties ?? new Dictionary<string, string>();
if (!msbuildProperties.ContainsKey("Configuration"))
{
msbuildProperties["Configuration"] = "Release";
}

var msbuildLogger = new ConsoleLogger(Logger.LogLevelThreshold switch
{
LogLevel.Verbose => LoggerVerbosity.Normal,
LogLevel.Diagnostic => LoggerVerbosity.Diagnostic,
_ => LoggerVerbosity.Quiet,
});

var workspace = MSBuildWorkspace.Create(msbuildProperties);
workspace.WorkspaceFailed += (sender, e) => Logger.LogWarning($"{e.Diagnostic}");

if (files.TryGetValue(FileType.NotSupported, out var unsupportedFiles))
{
foreach (var file in unsupportedFiles)
{
Logger.LogWarning($"Skip unsupported file {file}");
}
}

var hasCompilationError = false;
var projectCompilations = new HashSet<Compilation>();
var assemblies = new List<(IAssemblySymbol, Compilation)>();

if (files.TryGetValue(FileType.Solution, out var solutionFiles))
{
foreach (var solution in solutionFiles.Select(s => s.NormalizedPath))
{
Logger.LogInfo($"Loading solution {solution}");
foreach (var project in SolutionFile.Parse(solution).ProjectsInOrder)
{
if (project.ProjectType is SolutionProjectType.KnownToBeMSBuildFormat &&
await LoadCompilationFromProject(project.AbsolutePath) is { } compilation)
{
projectCompilations.Add(compilation);
}
}
}
}

if (files.TryGetValue(FileType.Project, out var projectFiles))
{
foreach (var projectFile in projectFiles)
{
if (await LoadCompilationFromProject(projectFile.NormalizedPath) is { } compilation)
{
projectCompilations.Add(compilation);
}
}
}

foreach (var compilation in projectCompilations)
{
hasCompilationError |= compilation.CheckDiagnostics(config.AllowCompilationErrors);
assemblies.Add((compilation.Assembly, compilation));
}

if (files.TryGetValue(FileType.CSSourceCode, out var csFiles))
{
var compilation = CompilationHelper.CreateCompilationFromCSharpFiles(csFiles.Select(f => f.NormalizedPath));
hasCompilationError |= compilation.CheckDiagnostics(config.AllowCompilationErrors);
assemblies.Add((compilation.Assembly, compilation));
}

if (files.TryGetValue(FileType.VBSourceCode, out var vbFiles))
{
var compilation = CompilationHelper.CreateCompilationFromVBFiles(vbFiles.Select(f => f.NormalizedPath));
hasCompilationError |= compilation.CheckDiagnostics(config.AllowCompilationErrors);
assemblies.Add((compilation.Assembly, compilation));
}

if (files.TryGetValue(FileType.Assembly, out var assemblyFiles))
{
foreach (var assemblyFile in assemblyFiles)
{
Logger.LogInfo($"Loading assembly {assemblyFile.NormalizedPath}");
var (compilation, assembly) = CompilationHelper.CreateCompilationFromAssembly(assemblyFile.NormalizedPath, config.References);
hasCompilationError |= compilation.CheckDiagnostics(config.AllowCompilationErrors);
assemblies.Add((assembly, compilation));
}
}

if (hasCompilationError)
{
return new();
}

if (assemblies.Count <= 0)
{
Logger.LogWarning("No .NET API project detected.");
}

return assemblies;

async Task<Compilation?> LoadCompilationFromProject(string path)
{
var project = workspace.CurrentSolution.Projects.FirstOrDefault(
p => FilePathComparer.OSPlatformSensitiveRelativePathComparer.Equals(p.FilePath, path));

if (project is null)
{
Logger.LogInfo($"Loading project {path}");
if (!config.NoRestore)
{
await Process.Start("dotnet", $"restore \"{path}\"").WaitForExitAsync();
}
project = await workspace.OpenProjectAsync(path, msbuildLogger);
}

if (!project.SupportsCompilation)
{
Logger.LogInfo($"Skip unsupported project {project.FilePath}.");
return null;
}

return await project.GetCompilationAsync();
}
}
}
Loading

0 comments on commit f16d314

Please sign in to comment.