Skip to content

Commit

Permalink
Generate Mermaid HTML diagrammer from input assembly via ilspycmd (#3324
Browse files Browse the repository at this point in the history
)

* added mermaid class diagrammer

contributed from https://github.com/h0lg/netAmermaid - find earlier git history there

* reading from embedded resource instead of file

* swapped out icon to brand diagrammers as an ILSpy product

reusing linked ..\ILSpy\Images\ILSpy.ico from UI project

* added required ilspycmd options and routed call

* adjusted VS Code task to generate model.json required by the JS/CSS/HTML dev loop

* added debug launchSettings

* updated help command output

* using ILSpyX build info in generated diagrammers
removing unused code

* using explicit type where it's not obvious

* outputting in to a folder next to and named after the input assembly + " diagrammer" by default

* renamed diagrammer output to index.html

to support default web server configs in the wild

* improved instructions for creating an off-line diagrammer

* added developer-facing doco for how to edit the HTML/JS/CSS parts

* renamed to remove netAmermaid branding

* updated repo URL and doco link to new Wiki page

* copied over doco

* removed obsolete parts

* moved CLI doco into ILSpyCmd README

* removed end-user facing chapters that go into the Wiki from dev-facing doco

* updated to ilspycmd API and rebranded to ILSpy

* removed doco that's now in https://github.com/icsharpcode/ILSpy/wiki/Diagramming

* added tasks
  • Loading branch information
h0lg authored Nov 15, 2024
1 parent b4d85a5 commit 09ed31d
Show file tree
Hide file tree
Showing 28 changed files with 3,967 additions and 26 deletions.
68 changes: 68 additions & 0 deletions ICSharpCode.ILSpyCmd/IlspyCmdProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Solution;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpyX.MermaidDiagrammer;
using ICSharpCode.ILSpyX.PdbProvider;

using McMaster.Extensions.CommandLineUtils;
Expand All @@ -44,6 +45,13 @@ Decompile assembly to destination directory (single C# file).
Decompile assembly to destination directory, create a project file, one source file per type,
into nicely nested directories.
ilspycmd --nested-directories -p -o c:\decompiled sample.dll
Generate a HTML diagrammer containing all type info into a folder next to the input assembly
ilspycmd sample.dll --generate-diagrammer
Generate a HTML diagrammer containing filtered type info into a custom output folder
(including types in the LightJson namespace while excluding types in nested LightJson.Serialization namespace)
ilspycmd sample.dll --generate-diagrammer -o c:\diagrammer --generate-diagrammer-include LightJson\\..+ --generate-diagrammer-exclude LightJson\\.Serialization\\..+
")]
[HelpOption("-h|--help")]
[ProjectOptionRequiresOutputDirectoryValidation]
Expand Down Expand Up @@ -114,6 +122,46 @@ class ILSpyCmdProgram
[Option("--disable-updatecheck", "If using ilspycmd in a tight loop or fully automated scenario, you might want to disable the automatic update check.", CommandOptionType.NoValue)]
public bool DisableUpdateCheck { get; }

#region MermaidDiagrammer options

// reused or quoted commands
private const string generateDiagrammerCmd = "--generate-diagrammer",
exclude = generateDiagrammerCmd + "-exclude",
include = generateDiagrammerCmd + "-include";

[Option(generateDiagrammerCmd, "Generates an interactive HTML diagrammer app from selected types in the target assembly" +
" - to the --outputdir or in a 'diagrammer' folder next to to the assembly by default.", CommandOptionType.NoValue)]
public bool GenerateDiagrammer { get; }

[Option(include, "An optional regular expression matching Type.FullName used to whitelist types to include in the generated diagrammer.", CommandOptionType.SingleValue)]
public string Include { get; set; }

[Option(exclude, "An optional regular expression matching Type.FullName used to blacklist types to exclude from the generated diagrammer.", CommandOptionType.SingleValue)]
public string Exclude { get; set; }

[Option(generateDiagrammerCmd + "-report-excluded", "Outputs a report of types excluded from the generated diagrammer" +
$" - whether by default because compiler-generated, explicitly by '{exclude}' or implicitly by '{include}'." +
" You may find this useful to develop and debug your regular expressions.", CommandOptionType.NoValue)]
public bool ReportExludedTypes { get; set; }

[Option(generateDiagrammerCmd + "-docs", "The path or file:// URI of the XML file containing the target assembly's documentation comments." +
" You only need to set this if a) you want your diagrams annotated with them and b) the file name differs from that of the assmbly." +
" To enable XML documentation output for your assmbly, see https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/#create-xml-documentation-output",
CommandOptionType.SingleValue)]
public string XmlDocs { get; set; }

/// <inheritdoc cref="ILSpyX.MermaidDiagrammer.GenerateHtmlDiagrammer.StrippedNamespaces" />
[Option(generateDiagrammerCmd + "-strip-namespaces", "Optional space-separated namespace names that are removed for brevity from XML documentation comments." +
" Note that the order matters: e.g. replace 'System.Collections' before 'System' to remove both of them completely.", CommandOptionType.MultipleValue)]
public string[] StrippedNamespaces { get; set; }

[Option(generateDiagrammerCmd + "-json-only",
"Whether to generate a model.json file instead of baking it into the HTML template." +
" This is useful for the HTML/JS/CSS development loop.", CommandOptionType.NoValue,
ShowInHelpText = false)] // developer option, output is really only useful in combination with the corresponding task in html/gulpfile.js
public bool JsonOnly { get; set; }
#endregion

private readonly IHostEnvironment _env;
public ILSpyCmdProgram(IHostEnvironment env)
{
Expand Down Expand Up @@ -157,6 +205,26 @@ private async Task<int> OnExecuteAsync(CommandLineApplication app)
SolutionCreator.WriteSolutionFile(Path.Combine(outputDirectory, Path.GetFileNameWithoutExtension(outputDirectory) + ".sln"), projects);
return 0;
}
else if (GenerateDiagrammer)
{
foreach (var file in InputAssemblyNames)
{
var command = new GenerateHtmlDiagrammer {
Assembly = file,
OutputFolder = OutputDirectory,
Include = Include,
Exclude = Exclude,
ReportExludedTypes = ReportExludedTypes,
JsonOnly = JsonOnly,
XmlDocs = XmlDocs,
StrippedNamespaces = StrippedNamespaces
};

command.Run();
}

return 0;
}
else
{
foreach (var file in InputAssemblyNames)
Expand Down
29 changes: 29 additions & 0 deletions ICSharpCode.ILSpyCmd/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"profiles": {
"no args": {
"commandName": "Project",
"commandLineArgs": ""
},
"print help": {
"commandName": "Project",
"commandLineArgs": "--help"
},
"generate diagrammer": {
"commandName": "Project",
// containing all types

// full diagrammer (~6.3 Mb!)
//"commandLineArgs": "ICSharpCode.Decompiler.dll --generate-diagrammer"

// including types in LightJson namespace while excluding types in nested LightJson.Serialization namespace, matched by what returns System.Type.FullName
//"commandLineArgs": "ICSharpCode.Decompiler.dll --generate-diagrammer --generate-diagrammer-include LightJson\\..+ --generate-diagrammer-exclude LightJson\\.Serialization\\..+"

// including types in Decompiler.TypeSystem namespace while excluding types in nested Decompiler.TypeSystem.Implementation namespace
"commandLineArgs": "ICSharpCode.Decompiler.dll --generate-diagrammer --generate-diagrammer-include Decompiler\\.TypeSystem\\..+ --generate-diagrammer-exclude Decompiler\\.TypeSystem\\.Implementation\\..+"
},
"generate diagrammer model.json": {
"commandName": "Project",
"commandLineArgs": "ICSharpCode.Decompiler.dll --generate-diagrammer --generate-diagrammer-json-only"
}
}
}
Loading

0 comments on commit 09ed31d

Please sign in to comment.