Skip to content

Commit a4d25b1

Browse files
Add GraphDiagram option
- Refactor for polymorphic architecture - Test both diagram types
1 parent b73c335 commit a4d25b1

7 files changed

Lines changed: 224 additions & 35 deletions

File tree

mermaid-graph/Commands.cs

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,37 @@
1-
using MermaidGraph.Diagrams;
2-
using Microsoft.Build.Locator;
1+
using System.Diagnostics;
2+
using MermaidGraph.Diagrams;
33

44
namespace MermaidGraph;
55

66
/// <summary>
7-
/// The commands that can be run by `mermaid-graph`
7+
/// Specifies the type of mermaid diagram to generate.
88
/// </summary>
9-
public class Commands
9+
public enum DiagramType
1010
{
11+
/// <summary>
12+
/// Represents a general dependency graph.
13+
/// </summary>
14+
Graph,
1115

12-
public Commands()
13-
{
14-
// Ensure MSBuild is registered
15-
if (!MSBuildLocator.IsRegistered)
16-
{
17-
MSBuildLocator.RegisterDefaults();
18-
}
19-
}
16+
/// <summary>
17+
/// Represents a class diagram.
18+
/// </summary>
19+
Class
20+
}
2021

22+
/// <summary>
23+
/// The commands that can be run by `mermaid-graph`
24+
/// </summary>
25+
public class Commands
26+
{
2127
/// <summary>
2228
/// Generate the dependency graph of a Visual Studio Project.
2329
/// </summary>
2430
/// <param name="file">`.csproj` file.</param>
25-
public string Project(FileInfo file)
31+
/// <param name="diagramType"></param>
32+
public static string Project(FileInfo file, DiagramType diagramType = DiagramType.Graph)
2633
{
27-
var graph = new ClassDiagram();
34+
var graph = GetGraphType(diagramType);
2835

2936
return graph.Project(file);
3037
}
@@ -33,10 +40,18 @@ public string Project(FileInfo file)
3340
/// Generate the dependency graph of a Visual Studio Solution.
3441
/// </summary>
3542
/// <param name="file">`.sln` file.</param>
36-
public string Solution(FileInfo file)
43+
/// <param name="diagramType"></param>
44+
public static string Solution(FileInfo file, DiagramType diagramType = DiagramType.Graph)
3745
{
38-
var graph = new ClassDiagram();
46+
var graph = GetGraphType(diagramType);
3947

4048
return graph.Solution(file);
4149
}
50+
51+
private static Diagram GetGraphType(DiagramType diagramType) => diagramType switch
52+
{
53+
DiagramType.Class => new ClassDiagram(),
54+
DiagramType.Graph => new GraphDiagram(),
55+
_ => throw new NotImplementedException($"Option not supported: {diagramType}"),
56+
};
4257
}

mermaid-graph/Diagrams/ClassDiagram.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace MermaidGraph.Diagrams;
55

66
internal class ClassDiagram : Diagram
77
{
8+
/// <inheritdoc />
89
public override void Header(string title)
910
{
1011
base.Header(title);
@@ -15,7 +16,7 @@ public override void Header(string title)
1516
/// Generate the dependency graph of a Visual Studio Project.
1617
/// </summary>
1718
/// <param name="file">`.csproj` file.</param>
18-
public string Project(FileInfo file)
19+
public override string Project(FileInfo file)
1920
{
2021
Header(file.Name);
2122
using var projectCollection = new ProjectCollection();
@@ -35,7 +36,7 @@ public string Project(FileInfo file)
3536
/// Generate the dependency graph of a Visual Studio Solution.
3637
/// </summary>
3738
/// <param name="file">`.sln` file.</param>
38-
public string Solution(FileInfo file)
39+
public override string Solution(FileInfo file)
3940
{
4041
Header(file.Name);
4142
var solutionFile = SolutionFile.Parse(file.FullName);

mermaid-graph/Diagrams/Diagram.cs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,37 @@
11
using System.Text;
2+
using Microsoft.Build.Locator;
23

34
namespace MermaidGraph.Diagrams;
45

5-
public class Diagram
6+
/// <summary>
7+
/// The Diagram abstract class implements shared functionality for Mermaid diagram generation,
8+
/// including initializing the graph output and managing the graph buffer.
9+
/// </summary>
10+
public abstract class Diagram : IMermaidDiagram
611
{
12+
/// <summary>
13+
/// Code block fence
14+
/// </summary>
715
public const string Fence = "```";
16+
17+
/// <summary>
18+
/// Mermaid code block
19+
/// </summary>
820
public const string MermaidBegin = Fence + "mermaid";
921

1022
internal readonly StringBuilder Graph = new();
1123

24+
/// <summary>
25+
/// Initialize the Diagram class and ensure MSBuild is registered.
26+
/// </summary>
27+
protected Diagram()
28+
{
29+
if (!MSBuildLocator.IsRegistered)
30+
{
31+
MSBuildLocator.RegisterDefaults();
32+
}
33+
}
34+
1235
/// <summary>
1336
/// Initialize the graph output
1437
/// </summary>
@@ -26,8 +49,14 @@ public virtual void Header(string title)
2649
}
2750

2851
/// <summary>
29-
/// Get the mermaid diagram markdown text.
52+
/// Get the mermaid diagram Markdown text.
3053
/// </summary>
3154
/// <returns>The contents of the graph buffer.</returns>
3255
public override string ToString() => Graph.ToString();
33-
}
56+
57+
/// <inheritdoc />
58+
public abstract string Project(FileInfo file);
59+
60+
/// <inheritdoc />
61+
public abstract string Solution(FileInfo file);
62+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
using Microsoft.Build.Construction;
2+
using Microsoft.Build.Evaluation;
3+
4+
namespace MermaidGraph.Diagrams;
5+
6+
internal class GraphDiagram : Diagram
7+
{
8+
/// <inheritdoc />
9+
public override void Header(string title)
10+
{
11+
base.Header(title);
12+
Graph.AppendLine("graph TD");
13+
}
14+
15+
/// <summary>
16+
/// Generate the dependency graph of a Visual Studio Project.
17+
/// </summary>
18+
/// <param name="file">`.csproj` file.</param>
19+
public override string Project(FileInfo file)
20+
{
21+
Header(file.Name);
22+
using var projectCollection = new ProjectCollection();
23+
var project = projectCollection.LoadProject(file.FullName);
24+
GraphProject(project);
25+
Graph.AppendLine(Fence);
26+
var graph = Graph.ToString();
27+
28+
// Cleanup
29+
Graph.Clear();
30+
projectCollection.UnloadAllProjects();
31+
32+
return graph;
33+
}
34+
35+
/// <summary>
36+
/// Generate the dependency graph of a Visual Studio Solution.
37+
/// </summary>
38+
/// <param name="file">`.sln` file.</param>
39+
public override string Solution(FileInfo file)
40+
{
41+
Header(file.Name);
42+
var solutionFile = SolutionFile.Parse(file.FullName);
43+
var solutionName = Path.GetFileNameWithoutExtension(file.Name);
44+
var solutionId = $"{solutionName}";
45+
Graph.AppendLine($$"""
46+
class {{solutionName}}{
47+
type solution
48+
}
49+
""");
50+
51+
using var projectCollection = new ProjectCollection();
52+
53+
foreach (var project in solutionFile.ProjectsInOrder)
54+
{
55+
if (project.ProjectType != SolutionProjectType.KnownToBeMSBuildFormat) continue;
56+
57+
var projectPath = project.AbsolutePath;
58+
var projectName = Path.GetFileNameWithoutExtension(projectPath);
59+
Graph.AppendLine($" {solutionId} --> {projectName}");
60+
var projectFile = new FileInfo(projectPath);
61+
if (projectFile.Exists)
62+
{
63+
var referenceProject = projectCollection.LoadProject(projectFile.FullName);
64+
GraphProject(referenceProject);
65+
}
66+
}
67+
68+
Graph.AppendLine(Fence);
69+
var graph = Graph.ToString();
70+
71+
// Cleanup
72+
Graph.Clear();
73+
projectCollection.UnloadAllProjects();
74+
75+
return graph;
76+
}
77+
78+
private void GraphProject(Project project)
79+
{
80+
var projectName = Path.GetFileNameWithoutExtension(project.FullPath);
81+
var type = project.GetPropertyValue("OutputType");
82+
var targetFramework = project.GetPropertyValue("TargetFramework") ?? project.GetPropertyValue("TargetFrameworks");
83+
Graph.AppendLine($$"""
84+
class {{projectName}}{
85+
type {{type}}
86+
target {{targetFramework}}
87+
}
88+
""");
89+
90+
foreach (var item in project.GetItems("ProjectReference"))
91+
{
92+
var refPath = item.EvaluatedInclude;
93+
var refName = Path.GetFileNameWithoutExtension(refPath);
94+
Graph.AppendLine($" {projectName} ..> {refName}");
95+
}
96+
97+
foreach (var item in project.GetItems("PackageReference"))
98+
{
99+
var packageName = item.EvaluatedInclude;
100+
var version = item.GetMetadataValue("Version");
101+
Graph.AppendLine($$"""
102+
class {{packageName}}{
103+
type NuGet
104+
version {{version}}
105+
}
106+
""");
107+
108+
Graph.AppendLine($" {projectName} ..> {packageName}");
109+
}
110+
}
111+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
namespace MermaidGraph.Diagrams;
2+
3+
/// <summary>
4+
/// This file defines the IMermaidDiagram interface and the Diagram abstract class.
5+
/// The IMermaidDiagram interface provides methods for generating Mermaid diagrams
6+
/// from Visual Studio project (*.csproj) and solution (*.sln) files.
7+
/// </summary>
8+
public interface IMermaidDiagram
9+
{
10+
/// <summary>
11+
/// Generate the diagram from a visual studio project file (*.csproj)
12+
/// </summary>
13+
/// <param name="file">The project file</param>
14+
/// <returns>Mermaid Markdown</returns>
15+
public string Project(FileInfo file);
16+
17+
/// <summary>
18+
/// Generate the diagram from a visual studio solution file (*.sln)
19+
/// </summary>
20+
/// <param name="file">The solution file.</param>
21+
/// <returns>Mermaid Markdown</returns>
22+
public string Solution(FileInfo file);
23+
}

mermaid-graph/Program.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
namespace MermaidGraph;
22

3-
// ReSharper disable UnusedMember.Global
4-
53
/// <summary>
64
/// mermaid-graph.exe
75
/// </summary>
@@ -11,15 +9,18 @@ public sealed class Program
119
/// Outputs a mermaid graph of the dependency diagram for a project, or whole solution.
1210
/// </summary>
1311
/// <param name="path">Full path to the solution (*.sln) or project (*.csproj) file that will be mapped.</param>
12+
/// <param name="diagramType">The type of diagram to generate (e.g., Graph or Class).</param>
1413
/// <returns>HResult</returns>
15-
public static int Main(string? path)
14+
public static int Main(string? path, DiagramType diagramType = DiagramType.Graph)
1615
{
1716
if (path is null)
1817
{
19-
System.CommandLine.DragonFruit.CommandLine.ExecuteAssembly(typeof(AutoGeneratedProgram).Assembly, ["--help"], "");
18+
System.CommandLine.DragonFruit.CommandLine
19+
.ExecuteAssembly(typeof(AutoGeneratedProgram).Assembly, ["--help"], "");
20+
2021
return 1;
2122
}
22-
23+
2324
var file = new FileInfo(path);
2425
if (!file.Exists)
2526
{
@@ -31,13 +32,13 @@ public static int Main(string? path)
3132
{
3233
if (path.EndsWith(".csproj"))
3334
{
34-
Console.WriteLine(new Commands().Project(file));
35+
Console.WriteLine(Commands.Project(file, diagramType));
3536
return 0;
3637
}
3738

3839
if (path.EndsWith(".sln"))
3940
{
40-
Console.WriteLine(new Commands().Solution(file));
41+
Console.WriteLine(Commands.Solution(file, diagramType));
4142
return 0;
4243
}
4344
}
@@ -50,4 +51,4 @@ public static int Main(string? path)
5051
Console.WriteLine($"Error: Unsupported file type - {path}");
5152
return 3;
5253
}
53-
}
54+
}

0 commit comments

Comments
 (0)