Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/ClassGraph/ClassGraph.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace DiagramGenerator.ClassGraph;
namespace ClassGraph;

public class Graph
{
Expand Down
9 changes: 9 additions & 0 deletions src/ClassGraph/DiagramDirection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace ClassGraph;

public enum DiagramDirection
{
TB, // Top to Bottom
BT, // Bottom to Top
LR, // Left to Right
RL // Right to Left
}
4 changes: 2 additions & 2 deletions src/ClassGraph/IDiagramGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace DiagramGenerator.ClassGraph;
namespace ClassGraph;

public interface IDiagramGenerator
{
string Generate(Graph graph);
string Generate(Graph graph, bool highLevelOnly, DiagramDirection diagramDirection);
}
2 changes: 1 addition & 1 deletion src/ClassGraph/IGraphBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace DiagramGenerator.ClassGraph;
namespace ClassGraph;

public interface IGraphBuilder
{
Expand Down
24 changes: 18 additions & 6 deletions src/ClassGraph/MermaidGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
namespace DiagramGenerator.ClassGraph;
namespace ClassGraph;

public class MermaidGenerator : IDiagramGenerator {
private static string MDFrame =
@"```mermaid
classDiagram
direction {2}

{0}
{1}
Expand All @@ -15,16 +16,23 @@ public class MermaidGenerator : IDiagramGenerator {
{1}{2}
}}";

public string Generate(Graph graph) {
public string Generate(Graph graph, bool highLevelOnly, DiagramDirection diagramDirection) {
var allClass = new List<string>();
foreach (var @class in graph.Classes) {
var classString = GenerateClass(@class);
// fixed an issue where a class with empty name would generate invalid
// Mermaid syntax and break the entire diagram - just skip any classes with empty/whitespace names
if (string.IsNullOrWhiteSpace(@class.Name)) continue;
var classString = GenerateClass(@class, highLevelOnly);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
allClass.Add(classString);
}

var allRelation = new List<string>();
foreach (var relation in graph.Relations) {
var relationString = GenerateRelation(relation);
// if either end of the relation has empty/whitespace name, skip it to avoid breaking Mermaid syntax
if (string.IsNullOrWhiteSpace(relation.From?.Name) ||
string.IsNullOrWhiteSpace(relation.To?.Name)) continue;

var relationString = GenerateRelation(relation);
allRelation.Add(relationString);
}

Expand All @@ -40,10 +48,10 @@ public string Generate(Graph graph) {
sections += "\r\n\r\n" + relationSection;
}

return string.Format(MDFrame, sections, string.Empty);
return string.Format(MDFrame, sections, string.Empty, diagramDirection.ToString());
}

private string GenerateClass(Class @class) {
private string GenerateClass(Class @class, bool highLevelOnly) {
var lines = new List<string>();

// Add type annotation (<<interface>>, <<record>>, etc.) as first line inside class block
Expand All @@ -52,6 +60,10 @@ private string GenerateClass(Class @class) {
lines.Add($" {typeAnnotation}");
}

if (highLevelOnly) {
return string.Format(ClassFrame, @class.Name, string.Empty, string.Empty);
}

// For enums, add enum values instead of properties/methods
if (@class.Kind == TypeKind.Enum) {
foreach (var enumValue in @class.EnumValues) {
Expand Down
2 changes: 1 addition & 1 deletion src/ClassGraph/SourceGraphBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace DiagramGenerator.ClassGraph;
namespace ClassGraph;

public class SourceGraphBuilder : IGraphBuilder
{
Expand Down
27 changes: 22 additions & 5 deletions src/MermaidClassDiagramGenerator/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.CommandLine;
using DiagramGenerator.ClassGraph;
using ClassGraph;

var outputOption = new Option<FileInfo?>(
aliases: new[] { "--output", "-o" },
Expand All @@ -20,7 +20,8 @@
var tnOption = new Option<IList<string>>(
aliases: new[] { "--type-names", "-t" },
description: "Specific classes to include.",
getDefaultValue: () => new List<string>());
getDefaultValue: () => new List<string>())
{ AllowMultipleArgumentsPerToken = true };

var ignoreDependencyOption = new Option<bool>(
name: "--ignore-dependency",
Expand All @@ -44,6 +45,16 @@
description: "Additional patterns to exclude from file search (e.g., 'Migrations', 'Generated').",
getDefaultValue: () => new List<string>());

var highLevelOnlyOption = new Option<bool>(
aliases: new[] { "--high-level-only" },
description: "Exclude all properties, methods, etc from generated diagram.",
getDefaultValue: () => false);

var diagramDirectionOption = new Option<DiagramDirection>(
aliases: new[] { "--diagram-direction", "-d" },
description: "The direction that diagram should be generated (TB: Top to Bottom (default), BT: Bottom to Top, LR: Left to Right, RL: Right to Left)",
getDefaultValue: () => DiagramDirection.TB);

var rootCommand = new RootCommand("Generate mermaid.js class-diagram from C# source code files.");
rootCommand.AddOption(outputOption);
rootCommand.AddOption(nsOption);
Expand All @@ -54,6 +65,8 @@
rootCommand.AddOption(visibilityOption);
rootCommand.AddOption(verboseOption);
rootCommand.AddOption(excludePatternsOption);
rootCommand.AddOption(highLevelOnlyOption);
rootCommand.AddOption(diagramDirectionOption);

rootCommand.SetHandler((context) =>
{
Expand All @@ -66,8 +79,10 @@
var visLevel = context.ParseResult.GetValueForOption(visibilityOption);
var verbose = context.ParseResult.GetValueForOption(verboseOption);
var excludePatterns = context.ParseResult.GetValueForOption(excludePatternsOption);
var highLevelOnly = context.ParseResult.GetValueForOption(highLevelOnlyOption);
var diagramDirection = context.ParseResult.GetValueForOption(diagramDirectionOption);

Execute(output!, ns!, inputPath!, tns!, ignoreDep, excludeSys, visLevel!, verbose, excludePatterns!);
Execute(output!, ns!, inputPath!, tns!, ignoreDep, excludeSys, visLevel!, verbose, excludePatterns!, highLevelOnly, diagramDirection);
});

return await rootCommand.InvokeAsync(args);
Expand All @@ -80,7 +95,9 @@ static void Execute(FileInfo outputFile,
bool excludeSystemTypes,
string visibilityLevel,
bool verbose,
IList<string> excludePatterns)
IList<string> excludePatterns,
bool highLevelOnly,
DiagramDirection diagramDirection)
{
try
{
Expand Down Expand Up @@ -142,7 +159,7 @@ static void Execute(FileInfo outputFile,

// 3. Generate Mermaid diagram
var generator = new MermaidGenerator();
var text = generator.Generate(graph);
var text = generator.Generate(graph, highLevelOnly, diagramDirection);

// 4. Write output
File.WriteAllText(outputFile.FullName, text);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"profiles": {
"MermaidClassDiagramGenerator": {
"commandName": "Project"
}
}
}