A command-line tool that generates Mermaid diagrams (as Markdown) from Visual Studio solutions and MSBuild C# projects.
Point it at a .slnx, .sln, or .csproj and it emits markdown containing:
- Class diagrams: classes, interfaces, structs, records, enums and delegates with their properties, methods, fields and inheritance/implementation edges.
- Project references: a flowchart of projects with their project, package and assembly references.
- Namespace dependencies: a flowchart of namespaces linked by derivations across them.
- Inheritance: a solution-wide base → derived / interface realization graph, including external (framework/package) base types.
Parsing is done with Roslyn:
the solution/project graph is loaded through MSBuildWorkspace when possible (giving
resolved references and accurate documents), and any project that will not load falls
back to a purely syntactic .cs sweep, so projects do not need to compile or restore.
Melusyn <input> [options]
| Option | Description |
|---|---|
-o, --output <path> |
output .md file (or a directory when --split) |
--split |
write one file per project plus an overview README.md |
-d, --diagrams <list> |
which diagrams to emit: Classes, References, Namespaces, Inheritance (default: all) |
-m, --members <level> |
member visibility in class diagrams: None, Public, NonPrivate, All (default: Public) |
--no-properties |
omit properties from class diagrams |
--no-methods |
omit methods from class diagrams |
--fields |
include fields in class diagrams |
--constructors |
include constructors in class diagrams |
--group-by-namespace |
one class diagram per namespace |
--direction <dir> |
flowchart direction TB, LR, BT, RL (default: TB) |
--title <text> |
document title |
--max-members <n> |
cap members shown per type (0 = unlimited) |
--include-generated |
include generated / obj output |
# whole solution, all diagrams, next to the input file
Melusyn MySolution.slnx
# a single project, everything including fields, to a chosen file
Melusyn src/App.csproj -o docs/model.md --members All --fields
# one Markdown file per project, only class and inheritance diagrams
Melusyn MySolution.sln --split -o docs/ -d Classes,InheritanceHere is the output for Melusyn running on itself:
flowchart TB
proj_Melusyn["Melusyn"]:::project
pkg_Microsoft_Build_Framework(["Microsoft.Build.Framework@18.7.1"]):::package
proj_Melusyn -.-> pkg_Microsoft_Build_Framework
pkg_Microsoft_Build_Locator(["Microsoft.Build.Locator@1.11.2"]):::package
proj_Melusyn -.-> pkg_Microsoft_Build_Locator
pkg_Microsoft_NET_StringTools(["Microsoft.NET.StringTools@18.7.1"]):::package
proj_Melusyn -.-> pkg_Microsoft_NET_StringTools
pkg_System_CommandLine(["System.CommandLine@2.0.9"]):::package
proj_Melusyn -.-> pkg_System_CommandLine
pkg_Microsoft_CodeAnalysis_CSharp(["Microsoft.CodeAnalysis.CSharp@5.6.0"]):::package
proj_Melusyn -.-> pkg_Microsoft_CodeAnalysis_CSharp
pkg_Microsoft_CodeAnalysis_CSharp_Workspaces(["Microsoft.CodeAnalysis.CSharp.Workspaces@5.6.0"]):::package
proj_Melusyn -.-> pkg_Microsoft_CodeAnalysis_CSharp_Workspaces
pkg_Microsoft_CodeAnalysis_Workspaces_MSBuild(["Microsoft.CodeAnalysis.Workspaces.MSBuild@5.6.0"]):::package
proj_Melusyn -.-> pkg_Microsoft_CodeAnalysis_Workspaces_MSBuild
classDef project fill:#dae8fc,stroke:#6c8ebf,color:#000;
classDef package fill:#d5e8d4,stroke:#82b366,color:#000;
classDef assembly fill:#ffe6cc,stroke:#d79b00,color:#000;
flowchart TB
ns_Melusyn["Melusyn"]
ns_Melusyn_Analysis["Melusyn.Analysis"]
ns_Melusyn_Cli["Melusyn.Cli"]
ns_Melusyn_Loading["Melusyn.Loading"]
ns_Melusyn_Mermaid["Melusyn.Mermaid"]
ns_Melusyn_Model["Melusyn.Model"]
ns_Melusyn_Output["Melusyn.Output"]
Nothing to show.
classDiagram
class Melusyn_Program["Program"] {
<<static>>
}
class Melusyn_Analysis_SymbolFormatting["SymbolFormatting"] {
<<static>>
+Display(ITypeSymbol) string$
+FullName(INamedTypeSymbol) string$
+NamespaceOf(INamedTypeSymbol) string$
}
class Melusyn_Analysis_TypeAnalyzer["TypeAnalyzer"] {
<<static>>
+Analyze(LoadedProject, CliOptions) ProjectModel$
}
class Melusyn_Cli_AppRunner["AppRunner"] {
<<static>>
+RunAsync(CliOptions, CancellationToken) Task~int~$
}
class Melusyn_Cli_CliOptions["CliOptions"] {
+string InputPath
+string? OutputPath
+bool Split
+IReadOnlySet~DiagramKind~ Diagrams
+MemberFilter Members
+bool IncludeProperties
+bool IncludeMethods
+bool IncludeFields
+bool IncludeConstructors
+bool GroupByNamespace
+string Direction
+string? Title
+int MaxMembersPerType
+bool ExcludeGenerated
+IncludeMember(Accessibility) bool
}
class Melusyn_Cli_CommandFactory["CommandFactory"] {
<<static>>
+Create() RootCommand$
}
class Melusyn_Cli_DiagramKind["DiagramKind"] {
<<enumeration>>
Classes
References
Namespaces
Inheritance
}
class Melusyn_Cli_MemberFilter["MemberFilter"] {
<<enumeration>>
None
Public
NonPrivate
All
}
class Melusyn_Loading_CsprojFileParser["CsprojFileParser"] {
<<static>>
+ParseMeta(string) ProjectModel$
}
class Melusyn_Loading_GeneratedFile["GeneratedFile"] {
<<static>>
+IsInBuildOutput(string?) bool$
+IsGenerated(string?) bool$
}
class Melusyn_Loading_LoadedProject["LoadedProject"] {
+ProjectModel Meta
+IReadOnlyList~SyntaxTree~ SyntaxTrees
+IReadOnlyList~MetadataReference~ MetadataReferences
}
class Melusyn_Loading_MSBuildLoader["MSBuildLoader"] {
<<static>>
+TryLoadAsync(string, string, TextWriter, CancellationToken) Task~IReadOnlyDictionary~string, ProjectData~?~$
}
class Melusyn_Loading_MSBuildLoader_ProjectData["ProjectData"] {
<<record>>
+IReadOnlyList~SyntaxTree~ SyntaxTrees
+IReadOnlyList~MetadataReference~ References
}
class Melusyn_Loading_ProjectSetLoader["ProjectSetLoader"] {
<<static>>
+LoadAsync(string, CliOptions, TextWriter, CancellationToken) Task~SolutionModel~$
}
class Melusyn_Loading_SolutionFileParser["SolutionFileParser"] {
<<static>>
+GetProjectPaths(string) IReadOnlyList~string~$
}
class Melusyn_Loading_SyntacticProjectReader["SyntacticProjectReader"] {
<<static>>
+ReadTrees(string, CliOptions) IReadOnlyList~SyntaxTree~$
}
class Melusyn_Mermaid_ClassDiagramGenerator["ClassDiagramGenerator"] {
<<static>>
+Generate(IReadOnlyList~TypeModel~, CliOptions) IReadOnlyList~DiagramSection~$
}
class Melusyn_Mermaid_DiagramSection["DiagramSection"] {
<<record>>
+string Title
+string Mermaid
}
class Melusyn_Mermaid_IdAllocator["IdAllocator"] {
+Get(string) string
+Contains(string) bool
}
class Melusyn_Mermaid_InheritanceGraphGenerator["InheritanceGraphGenerator"] {
<<static>>
+Generate(SolutionModel) DiagramSection$
}
class Melusyn_Mermaid_MermaidText["MermaidText"] {
<<static>>
+Label(string) string$
+Type(string) string$
}
class Melusyn_Mermaid_NamespaceGraphGenerator["NamespaceGraphGenerator"] {
<<static>>
+Generate(SolutionModel, CliOptions) DiagramSection$
}
class Melusyn_Mermaid_ReferenceGraphGenerator["ReferenceGraphGenerator"] {
<<static>>
+Generate(SolutionModel, CliOptions) DiagramSection$
}
class Melusyn_Mermaid_VisibilityGlyph["VisibilityGlyph"] {
<<static>>
+For(Accessibility) string$
}
class Melusyn_Model_FieldModel["FieldModel"] {
<<record>>
+string Name
+string Type
+Accessibility Accessibility
+bool IsStatic
+bool IsConst
}
class Melusyn_Model_MethodModel["MethodModel"] {
<<record>>
+string Name
+string ReturnType
+IReadOnlyList~ParameterModel~ Parameters
+Accessibility Accessibility
+bool IsStatic
+bool IsAbstract
+bool IsConstructor
}
class Melusyn_Model_PackageReferenceModel["PackageReferenceModel"] {
<<record>>
+string Name
+string? Version
}
class Melusyn_Model_ParameterModel["ParameterModel"] {
<<record>>
+string Name
+string Type
}
class Melusyn_Model_ProjectModel["ProjectModel"] {
<<record>>
+string Name
+string AssemblyName
+string Path
+string? TargetFrameworks
+IReadOnlyList~string~ ProjectReferences
+IReadOnlyList~PackageReferenceModel~ PackageReferences
+IReadOnlyList~string~ AssemblyReferences
+IReadOnlyList~TypeModel~ Types
}
class Melusyn_Model_PropertyModel["PropertyModel"] {
<<record>>
+string Name
+string Type
+Accessibility Accessibility
+bool IsStatic
+bool HasGetter
+bool HasSetter
}
class Melusyn_Model_SolutionModel["SolutionModel"] {
<<record>>
+string Name
+string Path
+IReadOnlyList~ProjectModel~ Projects
}
class Melusyn_Model_TypeModel["TypeModel"] {
<<record>>
+string Name
+string FullName
+string Namespace
+TypeModelKind Kind
+string ProjectName
+Accessibility Accessibility
+bool IsStatic
+bool IsAbstract
+bool IsSealed
+IReadOnlyList~string~ TypeParameters
+IReadOnlyList~TypeReferenceModel~ BaseTypes
+IReadOnlyList~PropertyModel~ Properties
+IReadOnlyList~MethodModel~ Methods
+IReadOnlyList~FieldModel~ Fields
+IReadOnlyList~string~ EnumMembers
}
class Melusyn_Model_TypeModelKind["TypeModelKind"] {
<<enumeration>>
Class
Interface
Struct
Record
RecordStruct
Enum
Delegate
}
class Melusyn_Model_TypeReferenceModel["TypeReferenceModel"] {
<<record>>
+string Display
+string FullName
+bool IsInterface
+bool IsResolved
}
class Melusyn_Output_DocumentWriter["DocumentWriter"] {
<<static>>
+WriteAsync(SolutionModel, CliOptions) Task~IReadOnlyList~string~~$
}
class Melusyn_Output_MarkdownComposer["MarkdownComposer"] {
<<static>>
+ComposeSingle(SolutionModel, CliOptions) string$
+ComposeOverview(SolutionModel, CliOptions) string$
+ComposeProject(ProjectModel, CliOptions) string$
+FileNameFor(ProjectModel) string$
}