From 663a91ebb3a9e73286b3789dee20d2794d81380c Mon Sep 17 00:00:00 2001 From: Max Vorchakov Date: Thu, 8 Feb 2024 15:50:42 +0100 Subject: [PATCH] Implemented workflow visualization --- .vscode/settings.json | 8 -- Directory.Build.props | 1 + PowerPipe.sln | 19 ++-- .../PowerPipeVisualizationConfiguration.cs | 46 -------- .../DiagramsService.cs | 102 ------------------ .../IDiagramService.cs | 8 -- .../Mermaid/Graph/Enum/Link.cs | 9 -- .../Mermaid/Graph/Enum/Shape.cs | 7 -- .../Graph/Extensions/LinkExtensions.cs | 20 ---- .../Graph/Extensions/ShapeExtensions.cs | 27 ----- .../Mermaid/Graph/Interfaces/IGraph.cs | 6 -- .../Mermaid/Graph/Interfaces/INode.cs | 14 --- .../Mermaid/Graph/Interfaces/IRenderTo.cs | 6 -- .../Mermaid/Graph/Relation.cs | 43 -------- .../VisualizationMiddleware.cs | 71 ------------ .../ApplicationBuilderExtension.cs | 18 ++++ ...nsions.MicrosoftDependencyInjection.csproj | 19 ++++ .../ServiceCollectionExtension.cs | 29 +++++ .../Antlr/Extensions/ParserExtensions.cs | 2 +- .../Antlr/PipelineLexer.g4 | 0 .../Antlr/PipelineLexer.tokens | 0 .../Antlr/PipelineParser.g4 | 0 .../Antlr/PipelineParserVisitor.cs | 19 ++-- .../Antlr/gen/PipelineLexer.cs | 7 +- .../Antlr/gen/PipelineLexer.interp | 0 .../Antlr/gen/PipelineLexer.java | 0 .../Antlr/gen/PipelineLexer.tokens | 0 .../Antlr/gen/PipelineParser.cs | 7 +- .../Antlr/gen/PipelineParser.tokens | 0 .../Antlr/gen/PipelineParserBaseListener.cs | 7 +- .../Antlr/gen/PipelineParserBaseVisitor.cs | 7 +- .../Antlr/gen/PipelineParserListener.cs | 7 +- .../Antlr/gen/PipelineParserVisitor.cs | 7 +- .../PowerPipeVisualizationConfiguration.cs | 69 ++++++++++++ .../IPipelineDiagramService.cs | 16 +++ .../Mermaid/Graph/Enum/Link.cs | 12 +++ .../Mermaid/Graph/Enum/Shape.cs | 17 +++ .../Graph/Extensions/LinkExtensions.cs | 29 +++++ .../Graph/Extensions/ShapeExtensions.cs | 42 ++++++++ .../Mermaid/Graph/Graph.cs | 22 +++- .../Mermaid/Graph/Interfaces/IGraph.cs | 13 +++ .../Mermaid/Graph/Interfaces/INode.cs | 30 ++++++ .../Mermaid/Graph/Interfaces/IRenderTo.cs | 14 +++ .../Mermaid/Graph/Nodes/AddIfElseNode.cs | 34 +++++- .../Mermaid/Graph/Nodes/AddIfNode.cs | 30 +++++- .../Mermaid/Graph/Nodes/AddNode.cs | 26 ++++- .../Mermaid/Graph/Nodes/IfNode.cs | 30 +++++- .../Mermaid/Graph/Nodes/ParallelNode.cs | 29 ++++- .../Mermaid/Graph/Relation.cs | 66 ++++++++++++ .../PipelineDiagramsService.cs | 97 +++++++++++++++++ .../PipelineVisualizationMiddleware.cs | 93 ++++++++++++++++ .../PowerPipe.Visualization.csproj} | 12 --- .../index.html | 102 +++++++++++------- src/PowerPipe/Builder/PipelineBuilder.cs | 6 +- .../PowerPipe.Visualization.Core.Tests.csproj | 19 ---- .../Program.cs | 60 ----------- .../PowerPipe.Visualization.WebTest.csproj | 13 --- .../Program.cs | 10 -- .../Properties/launchSettings.json | 28 ----- .../appsettings.Development.json | 8 -- .../appsettings.json | 9 -- 61 files changed, 828 insertions(+), 624 deletions(-) delete mode 100644 .vscode/settings.json delete mode 100644 src/PowerPipe.Visualization.Core/Configurations/PowerPipeVisualizationConfiguration.cs delete mode 100644 src/PowerPipe.Visualization.Core/DiagramsService.cs delete mode 100644 src/PowerPipe.Visualization.Core/IDiagramService.cs delete mode 100644 src/PowerPipe.Visualization.Core/Mermaid/Graph/Enum/Link.cs delete mode 100644 src/PowerPipe.Visualization.Core/Mermaid/Graph/Enum/Shape.cs delete mode 100644 src/PowerPipe.Visualization.Core/Mermaid/Graph/Extensions/LinkExtensions.cs delete mode 100644 src/PowerPipe.Visualization.Core/Mermaid/Graph/Extensions/ShapeExtensions.cs delete mode 100644 src/PowerPipe.Visualization.Core/Mermaid/Graph/Interfaces/IGraph.cs delete mode 100644 src/PowerPipe.Visualization.Core/Mermaid/Graph/Interfaces/INode.cs delete mode 100644 src/PowerPipe.Visualization.Core/Mermaid/Graph/Interfaces/IRenderTo.cs delete mode 100644 src/PowerPipe.Visualization.Core/Mermaid/Graph/Relation.cs delete mode 100644 src/PowerPipe.Visualization.Core/VisualizationMiddleware.cs create mode 100644 src/PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection/ApplicationBuilderExtension.cs create mode 100644 src/PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection/PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection.csproj create mode 100644 src/PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection/ServiceCollectionExtension.cs rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Antlr/Extensions/ParserExtensions.cs (93%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Antlr/PipelineLexer.g4 (100%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Antlr/PipelineLexer.tokens (100%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Antlr/PipelineParser.g4 (100%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Antlr/PipelineParserVisitor.cs (81%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Antlr/gen/PipelineLexer.cs (99%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Antlr/gen/PipelineLexer.interp (100%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Antlr/gen/PipelineLexer.java (100%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Antlr/gen/PipelineLexer.tokens (100%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Antlr/gen/PipelineParser.cs (98%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Antlr/gen/PipelineParser.tokens (100%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Antlr/gen/PipelineParserBaseListener.cs (96%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Antlr/gen/PipelineParserBaseVisitor.cs (96%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Antlr/gen/PipelineParserListener.cs (95%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Antlr/gen/PipelineParserVisitor.cs (93%) create mode 100644 src/PowerPipe.Visualization/Configurations/PowerPipeVisualizationConfiguration.cs create mode 100644 src/PowerPipe.Visualization/IPipelineDiagramService.cs create mode 100644 src/PowerPipe.Visualization/Mermaid/Graph/Enum/Link.cs create mode 100644 src/PowerPipe.Visualization/Mermaid/Graph/Enum/Shape.cs create mode 100644 src/PowerPipe.Visualization/Mermaid/Graph/Extensions/LinkExtensions.cs create mode 100644 src/PowerPipe.Visualization/Mermaid/Graph/Extensions/ShapeExtensions.cs rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Mermaid/Graph/Graph.cs (66%) create mode 100644 src/PowerPipe.Visualization/Mermaid/Graph/Interfaces/IGraph.cs create mode 100644 src/PowerPipe.Visualization/Mermaid/Graph/Interfaces/INode.cs create mode 100644 src/PowerPipe.Visualization/Mermaid/Graph/Interfaces/IRenderTo.cs rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Mermaid/Graph/Nodes/AddIfElseNode.cs (55%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Mermaid/Graph/Nodes/AddIfNode.cs (54%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Mermaid/Graph/Nodes/AddNode.cs (52%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Mermaid/Graph/Nodes/IfNode.cs (54%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/Mermaid/Graph/Nodes/ParallelNode.cs (57%) create mode 100644 src/PowerPipe.Visualization/Mermaid/Graph/Relation.cs create mode 100644 src/PowerPipe.Visualization/PipelineDiagramsService.cs create mode 100644 src/PowerPipe.Visualization/PipelineVisualizationMiddleware.cs rename src/{PowerPipe.Visualization.Core/PowerPipe.Visualization.Core.csproj => PowerPipe.Visualization/PowerPipe.Visualization.csproj} (68%) rename src/{PowerPipe.Visualization.Core => PowerPipe.Visualization}/index.html (65%) delete mode 100644 tests/PowerPipe.Visualization.Core.Tests/PowerPipe.Visualization.Core.Tests.csproj delete mode 100644 tests/PowerPipe.Visualization.Core.Tests/Program.cs delete mode 100644 tests/PowerPipe.Visualization.WebTest/PowerPipe.Visualization.WebTest.csproj delete mode 100644 tests/PowerPipe.Visualization.WebTest/Program.cs delete mode 100644 tests/PowerPipe.Visualization.WebTest/Properties/launchSettings.json delete mode 100644 tests/PowerPipe.Visualization.WebTest/appsettings.Development.json delete mode 100644 tests/PowerPipe.Visualization.WebTest/appsettings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 2b774d1..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "antlr4.generation": { - "mode": "external", - "language": "CSharp", - "listeners": false, - "visitors": true - } -} \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props index be75675..d035ba0 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,7 @@ net6.0;net7.0;net8.0 + logo.png true diff --git a/PowerPipe.sln b/PowerPipe.sln index 7c48859..12d0f7d 100644 --- a/PowerPipe.sln +++ b/PowerPipe.sln @@ -10,11 +10,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{5A41 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerPipe.Sample", "samples\PowerPipe.Sample\PowerPipe.Sample.csproj", "{931462F7-C5FE-4A73-9F2C-75D79AD6F9F0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerPipe.Visualization.Core", "src\PowerPipe.Visualization.Core\PowerPipe.Visualization.Core.csproj", "{2AB1CB82-0B84-494B-A391-4D1EB73B52D5}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerPipe.Visualization", "src\PowerPipe.Visualization\PowerPipe.Visualization.csproj", "{2AB1CB82-0B84-494B-A391-4D1EB73B52D5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerPipe.Visualization.Core.Tests", "tests\PowerPipe.Visualization.Core.Tests\PowerPipe.Visualization.Core.Tests.csproj", "{3B916DBD-B3D5-4377-A93E-E33793B9C959}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection", "src\PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection\PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection.csproj", "{50C7988C-E66C-410D-8B09-35FD707D5A7C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowerPipe.Visualization.WebTest", "tests\PowerPipe.Visualization.WebTest\PowerPipe.Visualization.WebTest.csproj", "{65DC6F69-7661-4ECF-B818-34FAB0DF8C49}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{CFF6E12F-B083-428E-990C-D1221F97D7D0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -42,16 +42,13 @@ Global {2AB1CB82-0B84-494B-A391-4D1EB73B52D5}.Debug|Any CPU.Build.0 = Debug|Any CPU {2AB1CB82-0B84-494B-A391-4D1EB73B52D5}.Release|Any CPU.ActiveCfg = Release|Any CPU {2AB1CB82-0B84-494B-A391-4D1EB73B52D5}.Release|Any CPU.Build.0 = Release|Any CPU - {3B916DBD-B3D5-4377-A93E-E33793B9C959}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3B916DBD-B3D5-4377-A93E-E33793B9C959}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3B916DBD-B3D5-4377-A93E-E33793B9C959}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3B916DBD-B3D5-4377-A93E-E33793B9C959}.Release|Any CPU.Build.0 = Release|Any CPU - {65DC6F69-7661-4ECF-B818-34FAB0DF8C49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {65DC6F69-7661-4ECF-B818-34FAB0DF8C49}.Debug|Any CPU.Build.0 = Debug|Any CPU - {65DC6F69-7661-4ECF-B818-34FAB0DF8C49}.Release|Any CPU.ActiveCfg = Release|Any CPU - {65DC6F69-7661-4ECF-B818-34FAB0DF8C49}.Release|Any CPU.Build.0 = Release|Any CPU + {50C7988C-E66C-410D-8B09-35FD707D5A7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {50C7988C-E66C-410D-8B09-35FD707D5A7C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {50C7988C-E66C-410D-8B09-35FD707D5A7C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {50C7988C-E66C-410D-8B09-35FD707D5A7C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {931462F7-C5FE-4A73-9F2C-75D79AD6F9F0} = {5A41270C-1028-4CDE-B6B9-F867B1FBB613} + {7307FC89-968C-4769-B1A3-C3C2F7B439A8} = {CFF6E12F-B083-428E-990C-D1221F97D7D0} EndGlobalSection EndGlobal diff --git a/src/PowerPipe.Visualization.Core/Configurations/PowerPipeVisualizationConfiguration.cs b/src/PowerPipe.Visualization.Core/Configurations/PowerPipeVisualizationConfiguration.cs deleted file mode 100644 index 215a372..0000000 --- a/src/PowerPipe.Visualization.Core/Configurations/PowerPipeVisualizationConfiguration.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace PowerPipe.Visualization.Core.Configurations; - -public class PowerPipeVisualizationConfiguration -{ - internal ICollection AssembliesToScan { get; set; } = new List(); - - internal ICollection TypesToScan { get; set; } = new List(); - - public PowerPipeVisualizationConfiguration ScanFromAssembly(Assembly assembly) - { - AssembliesToScan.Add(assembly); - - return this; - } - - public PowerPipeVisualizationConfiguration ScanFromAssemblies(params Assembly[] assemblies) - { - foreach (var assembly in assemblies) - { - ScanFromAssembly(assembly); - } - - return this; - } - - public PowerPipeVisualizationConfiguration ScanFromType(Type type) - { - TypesToScan.Add(type); - - return this; - } - - public PowerPipeVisualizationConfiguration ScanFromTypes(params Type[] types) - { - foreach (var type in types) - { - ScanFromType(type); - } - - return this; - } -} diff --git a/src/PowerPipe.Visualization.Core/DiagramsService.cs b/src/PowerPipe.Visualization.Core/DiagramsService.cs deleted file mode 100644 index a0ec997..0000000 --- a/src/PowerPipe.Visualization.Core/DiagramsService.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; -using Antlr4.Runtime; -using ICSharpCode.Decompiler; -using ICSharpCode.Decompiler.CSharp; -using ICSharpCode.Decompiler.TypeSystem; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using PowerPipe.Visualization.Core.Antlr; -using PowerPipe.Visualization.Core.Configurations; -using PowerPipe.Visualization.Core.Mermaid.Graph.Interfaces; - -namespace PowerPipe.Visualization.Core; - -public class DiagramsService : IDiagramService -{ - private static readonly Regex PipelineBuilderRegex = new Regex(@"(new PipelineBuilder)[\s\S]*(;)", RegexOptions.Compiled); - - private readonly PowerPipeVisualizationConfiguration _configuration; - - private readonly ILogger _logger; - - private readonly List _diagrams; - - public DiagramsService(IOptions configuration, ILoggerFactory loggerFactory) - { - ArgumentNullException.ThrowIfNull(configuration); - ArgumentNullException.ThrowIfNull(loggerFactory); - - _configuration = configuration.Value; - - _logger = loggerFactory.CreateLogger(); - - _diagrams = new List(); - } - - public ICollection GetDiagrams() - { - if (_diagrams.Count > 0) - return _diagrams; - - try - { - var typesToDecompile = GetTypesToDecompile(); - - var decompiledTypes = DecompileTypes(typesToDecompile); - - _diagrams.AddRange(ProcessDecompiledTypes(decompiledTypes)); - } - catch (Exception e) - { - _logger.LogDebug("Exception occured during retrieving of diagrams. {Exception}", e); - } - - return _diagrams; - } - - private IEnumerable GetTypesToDecompile() - { - var types = _configuration.TypesToScan.Where(it => it is not null).ToList(); - - foreach (var assembly in _configuration.AssembliesToScan.Where(it => it is not null)) - types.AddRange(assembly.GetTypes()); - - return types; - } - - private IEnumerable DecompileTypes(IEnumerable types) => - types.Select(type => - { - var decompiler = new CSharpDecompiler(type.Assembly.Location, new DecompilerSettings()); - - return decompiler.DecompileTypeAsString(new FullTypeName(type.FullName)); - }); - - private IEnumerable ProcessDecompiledTypes(IEnumerable decompiledTypes) => - decompiledTypes - .Select(decompiledType => - { - var input = PipelineBuilderRegex.Match(decompiledType).ToString(); - - if (string.IsNullOrEmpty(input)) - { - return null; - } - - var inputStream = new AntlrInputStream(input); - var pipelineLexer = new PipelineLexer(inputStream); - var commonTokenStream = new CommonTokenStream(pipelineLexer); - var pipelineParser = new PipelineParser(commonTokenStream); - - var startContext = pipelineParser.start(); - - var visitor = new PipelineParserVisitor(); - var graph = (IGraph)visitor.Visit(startContext); - - return graph.Render(); - }) - .Where(it => it is not null); -} diff --git a/src/PowerPipe.Visualization.Core/IDiagramService.cs b/src/PowerPipe.Visualization.Core/IDiagramService.cs deleted file mode 100644 index 7b064fa..0000000 --- a/src/PowerPipe.Visualization.Core/IDiagramService.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Collections.Generic; - -namespace PowerPipe.Visualization.Core; - -public interface IDiagramService -{ - ICollection GetDiagrams(); -} diff --git a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Enum/Link.cs b/src/PowerPipe.Visualization.Core/Mermaid/Graph/Enum/Link.cs deleted file mode 100644 index 0f4109e..0000000 --- a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Enum/Link.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace PowerPipe.Visualization.Core.Mermaid.Graph.Enum; - -public enum Link -{ - /// - /// --> - /// - Arrow, -} diff --git a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Enum/Shape.cs b/src/PowerPipe.Visualization.Core/Mermaid/Graph/Enum/Shape.cs deleted file mode 100644 index e4f9dbf..0000000 --- a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Enum/Shape.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace PowerPipe.Visualization.Core.Mermaid.Graph.Enum; - -public enum Shape -{ - RoundEdges, - Rhombus, -} diff --git a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Extensions/LinkExtensions.cs b/src/PowerPipe.Visualization.Core/Mermaid/Graph/Extensions/LinkExtensions.cs deleted file mode 100644 index a482e7e..0000000 --- a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Extensions/LinkExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Text; -using PowerPipe.Visualization.Core.Mermaid.Graph.Enum; - -namespace PowerPipe.Visualization.Core.Mermaid.Graph.Extensions; - -public static class LinkExtensions -{ - public static void RenderTo(this Link link, StringBuilder builder) - { - switch (link) - { - case Link.Arrow: - builder.Append("-->"); - break; - default: - throw new ArgumentOutOfRangeException(nameof(link), link, null); - } - } -} diff --git a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Extensions/ShapeExtensions.cs b/src/PowerPipe.Visualization.Core/Mermaid/Graph/Extensions/ShapeExtensions.cs deleted file mode 100644 index ac93e62..0000000 --- a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Extensions/ShapeExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using PowerPipe.Visualization.Core.Mermaid.Graph.Enum; - -namespace PowerPipe.Visualization.Core.Mermaid.Graph.Extensions; - -public static class ShapeExtensions -{ - public static string RenderStart(this Shape shape) - { - return shape switch - { - Shape.RoundEdges => "(", - Shape.Rhombus => "{", - _ => throw new ArgumentOutOfRangeException(nameof(shape), shape, null) - }; - } - - public static string RenderEnd(this Shape shape) - { - return shape switch - { - Shape.RoundEdges => ")", - Shape.Rhombus => "}", - _ => throw new ArgumentOutOfRangeException(nameof(shape), shape, null) - }; - } -} diff --git a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Interfaces/IGraph.cs b/src/PowerPipe.Visualization.Core/Mermaid/Graph/Interfaces/IGraph.cs deleted file mode 100644 index c688f28..0000000 --- a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Interfaces/IGraph.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace PowerPipe.Visualization.Core.Mermaid.Graph.Interfaces; - -public interface IGraph -{ - string Render(); -} diff --git a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Interfaces/INode.cs b/src/PowerPipe.Visualization.Core/Mermaid/Graph/Interfaces/INode.cs deleted file mode 100644 index 9f1efb0..0000000 --- a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Interfaces/INode.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; -using System.Text; -using PowerPipe.Visualization.Core.Mermaid.Graph.Enum; - -namespace PowerPipe.Visualization.Core.Mermaid.Graph.Interfaces; - -public interface INode : IRenderTo -{ - string Id { get; } - - Shape Shape { get; } - - IEnumerable LinkTo(INode destination, Link link, string text); -} diff --git a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Interfaces/IRenderTo.cs b/src/PowerPipe.Visualization.Core/Mermaid/Graph/Interfaces/IRenderTo.cs deleted file mode 100644 index 0e4a4ad..0000000 --- a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Interfaces/IRenderTo.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace PowerPipe.Visualization.Core.Mermaid.Graph.Interfaces; - -public interface IRenderTo -{ - void RenderTo(T target); -} diff --git a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Relation.cs b/src/PowerPipe.Visualization.Core/Mermaid/Graph/Relation.cs deleted file mode 100644 index 318171f..0000000 --- a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Relation.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Text; -using PowerPipe.Visualization.Core.Mermaid.Graph.Extensions; -using PowerPipe.Visualization.Core.Mermaid.Graph.Enum; -using PowerPipe.Visualization.Core.Mermaid.Graph.Interfaces; - -namespace PowerPipe.Visualization.Core.Mermaid.Graph; - -public class Relation : IRenderTo -{ - public Relation(INode from, INode to, Link link, string text) - { - From = from; - To = to; - Link = link; - Text = text; - } - - public INode From { get; } - - public INode To { get; } - - public Link Link { get; } - - public string Text { get; } - - public void RenderTo(StringBuilder builder) - { - builder.Append(From.Id).Append(' '); - - Link.RenderTo(builder); - builder.Append(' '); - - if (!string.IsNullOrEmpty(Text)) - { - builder - .Append("|\"") - .Append(Text) - .Append("\"|") - .Append(' '); - } - builder.AppendLine(To.Id); - } -} diff --git a/src/PowerPipe.Visualization.Core/VisualizationMiddleware.cs b/src/PowerPipe.Visualization.Core/VisualizationMiddleware.cs deleted file mode 100644 index 56ee089..0000000 --- a/src/PowerPipe.Visualization.Core/VisualizationMiddleware.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; - -namespace PowerPipe.Visualization.Core; - -public class VisualizationMiddleware -{ - private readonly RequestDelegate _next; - - private Func IndexStream { get; } = () => typeof(VisualizationMiddleware).GetTypeInfo().Assembly - .GetManifestResourceStream("PowerPipe.Visualization.Core.index.html"); - - public VisualizationMiddleware(RequestDelegate next) - { - _next = next; - } - - public async Task Invoke(HttpContext httpContext) - { - var httpMethod = httpContext.Request.Method; - var path = httpContext.Request.Path.Value; - - if (httpMethod == "GET" && Regex.IsMatch(path, $"^/?{Regex.Escape("powerpipe")}/?$", RegexOptions.IgnoreCase)) - { - var relativeIndexUrl = string.IsNullOrEmpty(path) || path.EndsWith('/') - ? "index.html" - : $"{path.Split('/').Last()}/index.html"; - - RespondWithRedirect(httpContext.Response, relativeIndexUrl); - return; - } - - if (httpMethod == "GET" && Regex.IsMatch(path, $"^/{Regex.Escape("powerpipe")}/?index.html$", RegexOptions.IgnoreCase)) - { - await RespondWithIndexHtml(httpContext.Response); - return; - } - - await _next(httpContext); - } - - private void RespondWithRedirect(HttpResponse response, string location) - { - response.StatusCode = 301; - response.Headers["Location"] = location; - } - - private async Task RespondWithIndexHtml(HttpResponse response) - { - response.StatusCode = 200; - response.ContentType = "text/html;charset=utf-8"; - - await using var stream = IndexStream(); - using var reader = new StreamReader(stream); - - // Inject arguments before writing to response - var htmlBuilder = new StringBuilder(await reader.ReadToEndAsync()); - // foreach (var entry in GetIndexArguments()) - // { - // htmlBuilder.Replace(entry.Key, entry.Value); - // } - - await response.WriteAsync(htmlBuilder.ToString(), Encoding.UTF8); - } -} diff --git a/src/PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection/ApplicationBuilderExtension.cs b/src/PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection/ApplicationBuilderExtension.cs new file mode 100644 index 0000000..0c33ab7 --- /dev/null +++ b/src/PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection/ApplicationBuilderExtension.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Builder; +using PowerPipe.Visualization; + +namespace Microsoft.Extensions.DependencyInjection; + +/// +/// Extension methods for configuring PowerPipe visualization middleware. +/// +public static class ApplicationBuilderExtension +{ + /// + /// Adds PowerPipe visualization middleware to the application's request pipeline. + /// + /// The instance. + /// The instance for method chaining. + public static IApplicationBuilder UsePowerPipeVisualization(this IApplicationBuilder app) => + app.UseMiddleware(); +} diff --git a/src/PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection/PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection.csproj b/src/PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection/PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection.csproj new file mode 100644 index 0000000..ba5fe7a --- /dev/null +++ b/src/PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection/PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + + + + true + + + + + + + + + + + diff --git a/src/PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection/ServiceCollectionExtension.cs b/src/PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection/ServiceCollectionExtension.cs new file mode 100644 index 0000000..93c1c04 --- /dev/null +++ b/src/PowerPipe.Visualization.Extensions.MicrosoftDependencyInjection/ServiceCollectionExtension.cs @@ -0,0 +1,29 @@ +using System; +using Microsoft.Extensions.Options; +using PowerPipe.Visualization; +using PowerPipe.Visualization.Configurations; + +namespace Microsoft.Extensions.DependencyInjection; + +/// +/// Provides extension methods for configuring PowerPipe.Visualization in Microsoft Dependency Injection (DI) services. +/// +public static class ServiceCollectionExtension +{ + /// + /// Registers Services required for pipeline visualization + /// + /// Service collection + /// The action used to configure the options + /// Service collection + public static IServiceCollection AddPowerPipeVisualization( + this IServiceCollection services, Action configuration) + { + var config = new PowerPipeVisualizationConfiguration(); + configuration.Invoke(config); + + services.AddSingleton(_ => Options.Options.Create(config)); + + return services.AddSingleton(); + } +} diff --git a/src/PowerPipe.Visualization.Core/Antlr/Extensions/ParserExtensions.cs b/src/PowerPipe.Visualization/Antlr/Extensions/ParserExtensions.cs similarity index 93% rename from src/PowerPipe.Visualization.Core/Antlr/Extensions/ParserExtensions.cs rename to src/PowerPipe.Visualization/Antlr/Extensions/ParserExtensions.cs index 4b3a3a2..ff152a1 100644 --- a/src/PowerPipe.Visualization.Core/Antlr/Extensions/ParserExtensions.cs +++ b/src/PowerPipe.Visualization/Antlr/Extensions/ParserExtensions.cs @@ -1,7 +1,7 @@ using System; using Antlr4.Runtime.Tree; -namespace PowerPipe.Visualization.Core.Antlr.Extensions; +namespace PowerPipe.Visualization.Antlr.Extensions; internal static class ParserExtensions { diff --git a/src/PowerPipe.Visualization.Core/Antlr/PipelineLexer.g4 b/src/PowerPipe.Visualization/Antlr/PipelineLexer.g4 similarity index 100% rename from src/PowerPipe.Visualization.Core/Antlr/PipelineLexer.g4 rename to src/PowerPipe.Visualization/Antlr/PipelineLexer.g4 diff --git a/src/PowerPipe.Visualization.Core/Antlr/PipelineLexer.tokens b/src/PowerPipe.Visualization/Antlr/PipelineLexer.tokens similarity index 100% rename from src/PowerPipe.Visualization.Core/Antlr/PipelineLexer.tokens rename to src/PowerPipe.Visualization/Antlr/PipelineLexer.tokens diff --git a/src/PowerPipe.Visualization.Core/Antlr/PipelineParser.g4 b/src/PowerPipe.Visualization/Antlr/PipelineParser.g4 similarity index 100% rename from src/PowerPipe.Visualization.Core/Antlr/PipelineParser.g4 rename to src/PowerPipe.Visualization/Antlr/PipelineParser.g4 diff --git a/src/PowerPipe.Visualization.Core/Antlr/PipelineParserVisitor.cs b/src/PowerPipe.Visualization/Antlr/PipelineParserVisitor.cs similarity index 81% rename from src/PowerPipe.Visualization.Core/Antlr/PipelineParserVisitor.cs rename to src/PowerPipe.Visualization/Antlr/PipelineParserVisitor.cs index c18d096..0f490a3 100644 --- a/src/PowerPipe.Visualization.Core/Antlr/PipelineParserVisitor.cs +++ b/src/PowerPipe.Visualization/Antlr/PipelineParserVisitor.cs @@ -1,13 +1,15 @@ using System.Collections.Generic; -using PowerPipe.Visualization.Core.Antlr.Extensions; -using PowerPipe.Visualization.Core.Mermaid.Graph; -using PowerPipe.Visualization.Core.Mermaid.Graph.Interfaces; -using PowerPipe.Visualization.Core.Mermaid.Graph.Nodes; +using PowerPipe.Visualization.Antlr.Extensions; +using PowerPipe.Visualization.Mermaid.Graph; +using PowerPipe.Visualization.Mermaid.Graph.Interfaces; +using PowerPipe.Visualization.Mermaid.Graph.Nodes; -namespace PowerPipe.Visualization.Core.Antlr; +namespace PowerPipe.Visualization.Antlr; +/// public class PipelineParserVisitor : PipelineParserBaseVisitor { + /// public override IGraph VisitStart(PipelineParser.StartContext context) { var pipelineNodes = new List(); @@ -22,16 +24,18 @@ public override IGraph VisitStart(PipelineParser.StartContext context) } } - pipelineNodes.Add(new AddNode("END OF PIPELINE")); + pipelineNodes.Add(new AddNode("END OF WORKFLOW")); return new Graph(pipelineNodes); } + /// public override INode VisitAddStep(PipelineParser.AddStepContext context) { return new AddNode(context.DATA().GetStepName()); } + /// public override INode VisitAddIfStep(PipelineParser.AddIfStepContext context) { return new AddIfNode( @@ -39,6 +43,7 @@ public override INode VisitAddIfStep(PipelineParser.AddIfStepContext context) context.DATA().GetStepName()); } + /// public override INode VisitAddIfElseStep(PipelineParser.AddIfElseStepContext context) { var (step1, step2) = context.DATA2().GetTwoStepsNames(); @@ -49,6 +54,7 @@ public override INode VisitAddIfElseStep(PipelineParser.AddIfElseStepContext con step2); } + /// public override INode VisitIfStep(PipelineParser.IfStepContext context) { var children = new List(); @@ -66,6 +72,7 @@ public override INode VisitIfStep(PipelineParser.IfStepContext context) return new IfNode(context.OPENPREDICATE().GetOpenPredicateName(), children); } + /// public override INode VisitParallelStep(PipelineParser.ParallelStepContext context) { var children = new List(); diff --git a/src/PowerPipe.Visualization.Core/Antlr/gen/PipelineLexer.cs b/src/PowerPipe.Visualization/Antlr/gen/PipelineLexer.cs similarity index 99% rename from src/PowerPipe.Visualization.Core/Antlr/gen/PipelineLexer.cs rename to src/PowerPipe.Visualization/Antlr/gen/PipelineLexer.cs index 19ca3ac..46ad6f1 100644 --- a/src/PowerPipe.Visualization.Core/Antlr/gen/PipelineLexer.cs +++ b/src/PowerPipe.Visualization/Antlr/gen/PipelineLexer.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -// Generated from /Users/maksym.vorchakov/Work/Documents/Projects/Personal/PowerPipe/src/PowerPipe.Visualization.Core/Antlr/PipelineLexer.g4 by ANTLR 4.6.6 +// Generated from /Users/maksym.vorchakov/Work/Documents/Projects/Personal/PowerPipe/src/PowerPipe.Visualization/Antlr/PipelineLexer.g4 by ANTLR 4.6.6 // Unreachable code detected #pragma warning disable 0162 @@ -18,8 +18,9 @@ #pragma warning disable 1591 // Ambiguous reference in cref attribute #pragma warning disable 419 +#pragma warning disable CS3021 -namespace PowerPipe.Visualization.Core.Antlr { +namespace PowerPipe.Visualization.Antlr { using Antlr4.Runtime; using Antlr4.Runtime.Atn; using Antlr4.Runtime.Misc; @@ -338,4 +339,4 @@ public override IVocabulary Vocabulary public static readonly ATN _ATN = new ATNDeserializer().Deserialize(_serializedATN.ToCharArray()); } -} // namespace PowerPipe.Visualization.Core.Antlr +} // namespace PowerPipe.Visualization.Antlr diff --git a/src/PowerPipe.Visualization.Core/Antlr/gen/PipelineLexer.interp b/src/PowerPipe.Visualization/Antlr/gen/PipelineLexer.interp similarity index 100% rename from src/PowerPipe.Visualization.Core/Antlr/gen/PipelineLexer.interp rename to src/PowerPipe.Visualization/Antlr/gen/PipelineLexer.interp diff --git a/src/PowerPipe.Visualization.Core/Antlr/gen/PipelineLexer.java b/src/PowerPipe.Visualization/Antlr/gen/PipelineLexer.java similarity index 100% rename from src/PowerPipe.Visualization.Core/Antlr/gen/PipelineLexer.java rename to src/PowerPipe.Visualization/Antlr/gen/PipelineLexer.java diff --git a/src/PowerPipe.Visualization.Core/Antlr/gen/PipelineLexer.tokens b/src/PowerPipe.Visualization/Antlr/gen/PipelineLexer.tokens similarity index 100% rename from src/PowerPipe.Visualization.Core/Antlr/gen/PipelineLexer.tokens rename to src/PowerPipe.Visualization/Antlr/gen/PipelineLexer.tokens diff --git a/src/PowerPipe.Visualization.Core/Antlr/gen/PipelineParser.cs b/src/PowerPipe.Visualization/Antlr/gen/PipelineParser.cs similarity index 98% rename from src/PowerPipe.Visualization.Core/Antlr/gen/PipelineParser.cs rename to src/PowerPipe.Visualization/Antlr/gen/PipelineParser.cs index 5ef9ddc..d743ea1 100644 --- a/src/PowerPipe.Visualization.Core/Antlr/gen/PipelineParser.cs +++ b/src/PowerPipe.Visualization/Antlr/gen/PipelineParser.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -// Generated from /Users/maksym.vorchakov/Work/Documents/Projects/Personal/PowerPipe/src/PowerPipe.Visualization.Core/Antlr/PipelineParser.g4 by ANTLR 4.6.6 +// Generated from /Users/maksym.vorchakov/Work/Documents/Projects/Personal/PowerPipe/src/PowerPipe.Visualization/Antlr/PipelineParser.g4 by ANTLR 4.6.6 // Unreachable code detected #pragma warning disable 0162 @@ -18,8 +18,9 @@ #pragma warning disable 1591 // Ambiguous reference in cref attribute #pragma warning disable 419 +#pragma warning disable CS3021 -namespace PowerPipe.Visualization.Core.Antlr { +namespace PowerPipe.Visualization.Antlr { using Antlr4.Runtime; using Antlr4.Runtime.Atn; using Antlr4.Runtime.Misc; @@ -554,4 +555,4 @@ public ParallelStepContext parallelStep() { public static readonly ATN _ATN = new ATNDeserializer().Deserialize(_serializedATN.ToCharArray()); } -} // namespace PowerPipe.Visualization.Core.Antlr +} // namespace PowerPipe.Visualization.Antlr diff --git a/src/PowerPipe.Visualization.Core/Antlr/gen/PipelineParser.tokens b/src/PowerPipe.Visualization/Antlr/gen/PipelineParser.tokens similarity index 100% rename from src/PowerPipe.Visualization.Core/Antlr/gen/PipelineParser.tokens rename to src/PowerPipe.Visualization/Antlr/gen/PipelineParser.tokens diff --git a/src/PowerPipe.Visualization.Core/Antlr/gen/PipelineParserBaseListener.cs b/src/PowerPipe.Visualization/Antlr/gen/PipelineParserBaseListener.cs similarity index 96% rename from src/PowerPipe.Visualization.Core/Antlr/gen/PipelineParserBaseListener.cs rename to src/PowerPipe.Visualization/Antlr/gen/PipelineParserBaseListener.cs index f3a6f76..711de7f 100644 --- a/src/PowerPipe.Visualization.Core/Antlr/gen/PipelineParserBaseListener.cs +++ b/src/PowerPipe.Visualization/Antlr/gen/PipelineParserBaseListener.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -// Generated from /Users/maksym.vorchakov/Work/Documents/Projects/Personal/PowerPipe/src/PowerPipe.Visualization.Core/Antlr/PipelineParser.g4 by ANTLR 4.6.6 +// Generated from /Users/maksym.vorchakov/Work/Documents/Projects/Personal/PowerPipe/src/PowerPipe.Visualization/Antlr/PipelineParser.g4 by ANTLR 4.6.6 // Unreachable code detected #pragma warning disable 0162 @@ -18,8 +18,9 @@ #pragma warning disable 1591 // Ambiguous reference in cref attribute #pragma warning disable 419 +#pragma warning disable CS3021 -namespace PowerPipe.Visualization.Core.Antlr { +namespace PowerPipe.Visualization.Antlr { using Antlr4.Runtime.Misc; using IErrorNode = Antlr4.Runtime.Tree.IErrorNode; @@ -139,4 +140,4 @@ public virtual void VisitTerminal([NotNull] ITerminalNode node) { } /// The default implementation does nothing. public virtual void VisitErrorNode([NotNull] IErrorNode node) { } } -} // namespace PowerPipe.Visualization.Core.Antlr +} // namespace PowerPipe.Visualization.Antlr diff --git a/src/PowerPipe.Visualization.Core/Antlr/gen/PipelineParserBaseVisitor.cs b/src/PowerPipe.Visualization/Antlr/gen/PipelineParserBaseVisitor.cs similarity index 96% rename from src/PowerPipe.Visualization.Core/Antlr/gen/PipelineParserBaseVisitor.cs rename to src/PowerPipe.Visualization/Antlr/gen/PipelineParserBaseVisitor.cs index 103c2c3..ce44cd0 100644 --- a/src/PowerPipe.Visualization.Core/Antlr/gen/PipelineParserBaseVisitor.cs +++ b/src/PowerPipe.Visualization/Antlr/gen/PipelineParserBaseVisitor.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -// Generated from /Users/maksym.vorchakov/Work/Documents/Projects/Personal/PowerPipe/src/PowerPipe.Visualization.Core/Antlr/PipelineParser.g4 by ANTLR 4.6.6 +// Generated from /Users/maksym.vorchakov/Work/Documents/Projects/Personal/PowerPipe/src/PowerPipe.Visualization/Antlr/PipelineParser.g4 by ANTLR 4.6.6 // Unreachable code detected #pragma warning disable 0162 @@ -18,8 +18,9 @@ #pragma warning disable 1591 // Ambiguous reference in cref attribute #pragma warning disable 419 +#pragma warning disable CS3021 -namespace PowerPipe.Visualization.Core.Antlr { +namespace PowerPipe.Visualization.Antlr { using Antlr4.Runtime.Misc; using Antlr4.Runtime.Tree; using IToken = Antlr4.Runtime.IToken; @@ -111,4 +112,4 @@ public partial class PipelineParserBaseVisitor : AbstractParseTreeVisito /// The visitor result. public virtual Result VisitParallelStep([NotNull] PipelineParser.ParallelStepContext context) { return VisitChildren(context); } } -} // namespace PowerPipe.Visualization.Core.Antlr +} // namespace PowerPipe.Visualization.Antlr diff --git a/src/PowerPipe.Visualization.Core/Antlr/gen/PipelineParserListener.cs b/src/PowerPipe.Visualization/Antlr/gen/PipelineParserListener.cs similarity index 95% rename from src/PowerPipe.Visualization.Core/Antlr/gen/PipelineParserListener.cs rename to src/PowerPipe.Visualization/Antlr/gen/PipelineParserListener.cs index 95d35b3..dc9e8de 100644 --- a/src/PowerPipe.Visualization.Core/Antlr/gen/PipelineParserListener.cs +++ b/src/PowerPipe.Visualization/Antlr/gen/PipelineParserListener.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -// Generated from /Users/maksym.vorchakov/Work/Documents/Projects/Personal/PowerPipe/src/PowerPipe.Visualization.Core/Antlr/PipelineParser.g4 by ANTLR 4.6.6 +// Generated from /Users/maksym.vorchakov/Work/Documents/Projects/Personal/PowerPipe/src/PowerPipe.Visualization/Antlr/PipelineParser.g4 by ANTLR 4.6.6 // Unreachable code detected #pragma warning disable 0162 @@ -18,8 +18,9 @@ #pragma warning disable 1591 // Ambiguous reference in cref attribute #pragma warning disable 419 +#pragma warning disable CS3021 -namespace PowerPipe.Visualization.Core.Antlr { +namespace PowerPipe.Visualization.Antlr { using Antlr4.Runtime.Misc; using IParseTreeListener = Antlr4.Runtime.Tree.IParseTreeListener; using IToken = Antlr4.Runtime.IToken; @@ -108,4 +109,4 @@ public interface IPipelineParserListener : IParseTreeListener { /// The parse tree. void ExitParallelStep([NotNull] PipelineParser.ParallelStepContext context); } -} // namespace PowerPipe.Visualization.Core.Antlr +} // namespace PowerPipe.Visualization.Antlr diff --git a/src/PowerPipe.Visualization.Core/Antlr/gen/PipelineParserVisitor.cs b/src/PowerPipe.Visualization/Antlr/gen/PipelineParserVisitor.cs similarity index 93% rename from src/PowerPipe.Visualization.Core/Antlr/gen/PipelineParserVisitor.cs rename to src/PowerPipe.Visualization/Antlr/gen/PipelineParserVisitor.cs index 236706d..5200267 100644 --- a/src/PowerPipe.Visualization.Core/Antlr/gen/PipelineParserVisitor.cs +++ b/src/PowerPipe.Visualization/Antlr/gen/PipelineParserVisitor.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -// Generated from /Users/maksym.vorchakov/Work/Documents/Projects/Personal/PowerPipe/src/PowerPipe.Visualization.Core/Antlr/PipelineParser.g4 by ANTLR 4.6.6 +// Generated from /Users/maksym.vorchakov/Work/Documents/Projects/Personal/PowerPipe/src/PowerPipe.Visualization/Antlr/PipelineParser.g4 by ANTLR 4.6.6 // Unreachable code detected #pragma warning disable 0162 @@ -18,8 +18,9 @@ #pragma warning disable 1591 // Ambiguous reference in cref attribute #pragma warning disable 419 +#pragma warning disable CS3021 -namespace PowerPipe.Visualization.Core.Antlr { +namespace PowerPipe.Visualization.Antlr { using Antlr4.Runtime.Misc; using Antlr4.Runtime.Tree; using IToken = Antlr4.Runtime.IToken; @@ -81,4 +82,4 @@ public interface IPipelineParserVisitor : IParseTreeVisitor { /// The visitor result. Result VisitParallelStep([NotNull] PipelineParser.ParallelStepContext context); } -} // namespace PowerPipe.Visualization.Core.Antlr +} // namespace PowerPipe.Visualization.Antlr diff --git a/src/PowerPipe.Visualization/Configurations/PowerPipeVisualizationConfiguration.cs b/src/PowerPipe.Visualization/Configurations/PowerPipeVisualizationConfiguration.cs new file mode 100644 index 0000000..3b29274 --- /dev/null +++ b/src/PowerPipe.Visualization/Configurations/PowerPipeVisualizationConfiguration.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace PowerPipe.Visualization.Configurations; + +/// +/// Represents the configuration settings for PowerPipe visualization. +/// +public class PowerPipeVisualizationConfiguration +{ + internal ICollection AssembliesToScan { get; set; } = new List(); + + internal ICollection TypesToScan { get; set; } = new List(); + + /// + /// Adds an assembly to the list of assemblies to be scanned for types. + /// + /// The assembly to be scanned. + /// The updated PowerPipeVisualizationConfiguration instance. + public PowerPipeVisualizationConfiguration ScanFromAssembly(Assembly assembly) + { + AssembliesToScan.Add(assembly); + + return this; + } + + /// + /// Adds multiple assemblies to the list of assemblies to be scanned for types. + /// + /// The assemblies to be scanned. + /// The updated PowerPipeVisualizationConfiguration instance. + public PowerPipeVisualizationConfiguration ScanFromAssemblies(params Assembly[] assemblies) + { + foreach (var assembly in assemblies) + { + ScanFromAssembly(assembly); + } + + return this; + } + + /// + /// Adds a type to the list of types to be scanned. + /// + /// The type to be scanned. + /// The updated PowerPipeVisualizationConfiguration instance. + public PowerPipeVisualizationConfiguration ScanFromType(Type type) + { + TypesToScan.Add(type); + + return this; + } + + /// + /// Adds multiple types to the list of types to be scanned. + /// + /// The types to be scanned. + /// The updated PowerPipeVisualizationConfiguration instance. + public PowerPipeVisualizationConfiguration ScanFromTypes(params Type[] types) + { + foreach (var type in types) + { + ScanFromType(type); + } + + return this; + } +} diff --git a/src/PowerPipe.Visualization/IPipelineDiagramService.cs b/src/PowerPipe.Visualization/IPipelineDiagramService.cs new file mode 100644 index 0000000..4b625df --- /dev/null +++ b/src/PowerPipe.Visualization/IPipelineDiagramService.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace PowerPipe.Visualization; + + +/// +/// Represents a service for creating diagrams. +/// +public interface IPipelineDiagramService +{ + /// + /// Parses diagrams to mermaid. + /// + /// Dictionary of diagrams where the Key is the name of the file where the diagram was found. + IDictionary GetDiagrams(); +} diff --git a/src/PowerPipe.Visualization/Mermaid/Graph/Enum/Link.cs b/src/PowerPipe.Visualization/Mermaid/Graph/Enum/Link.cs new file mode 100644 index 0000000..e8278cd --- /dev/null +++ b/src/PowerPipe.Visualization/Mermaid/Graph/Enum/Link.cs @@ -0,0 +1,12 @@ +namespace PowerPipe.Visualization.Mermaid.Graph.Enum; + +/// +/// Represents a relation type. +/// +public enum Link +{ + /// + /// --> + /// + Arrow, +} diff --git a/src/PowerPipe.Visualization/Mermaid/Graph/Enum/Shape.cs b/src/PowerPipe.Visualization/Mermaid/Graph/Enum/Shape.cs new file mode 100644 index 0000000..638e8a9 --- /dev/null +++ b/src/PowerPipe.Visualization/Mermaid/Graph/Enum/Shape.cs @@ -0,0 +1,17 @@ +namespace PowerPipe.Visualization.Mermaid.Graph.Enum; + +/// +/// Represents the shapes that can be used in a Mermaid graph visualization. +/// +public enum Shape +{ + /// + /// Nodes with round edges. + /// + RoundEdges, + + /// + /// Rhombus-shaped nodes. + /// + Rhombus, +} diff --git a/src/PowerPipe.Visualization/Mermaid/Graph/Extensions/LinkExtensions.cs b/src/PowerPipe.Visualization/Mermaid/Graph/Extensions/LinkExtensions.cs new file mode 100644 index 0000000..f002746 --- /dev/null +++ b/src/PowerPipe.Visualization/Mermaid/Graph/Extensions/LinkExtensions.cs @@ -0,0 +1,29 @@ +using System; +using System.Text; +using PowerPipe.Visualization.Mermaid.Graph.Enum; + +namespace PowerPipe.Visualization.Mermaid.Graph.Extensions; + +/// +/// Provides extension methods for rendering Mermaid graph links. +/// +public static class LinkExtensions +{ + /// + /// Renders the specified link type to the provided . + /// + /// The link type to render. + /// The used for rendering. + /// Thrown when an unsupported link type is provided. + public static void RenderTo(this Link link, StringBuilder builder) + { + switch (link) + { + case Link.Arrow: + builder.Append("-->"); + break; + default: + throw new ArgumentOutOfRangeException(nameof(link), link, null); + } + } +} diff --git a/src/PowerPipe.Visualization/Mermaid/Graph/Extensions/ShapeExtensions.cs b/src/PowerPipe.Visualization/Mermaid/Graph/Extensions/ShapeExtensions.cs new file mode 100644 index 0000000..84bce07 --- /dev/null +++ b/src/PowerPipe.Visualization/Mermaid/Graph/Extensions/ShapeExtensions.cs @@ -0,0 +1,42 @@ +using System; +using PowerPipe.Visualization.Mermaid.Graph.Enum; + +namespace PowerPipe.Visualization.Mermaid.Graph.Extensions; + +/// +/// Provides extension methods for rendering the start and end symbols of Mermaid graph shapes. +/// +public static class ShapeExtensions +{ + /// + /// Renders the start symbol for the specified shape. + /// + /// The shape for which the start symbol is rendered. + /// The rendered start symbol as a string. + /// Thrown when an unsupported shape is provided. + public static string RenderStart(this Shape shape) + { + return shape switch + { + Shape.RoundEdges => "(", + Shape.Rhombus => "{", + _ => throw new ArgumentOutOfRangeException(nameof(shape), shape, null) + }; + } + + /// + /// Renders the end symbol for the specified shape. + /// + /// The shape for which the end symbol is rendered. + /// The rendered end symbol as a string. + /// Thrown when an unsupported shape is provided. + public static string RenderEnd(this Shape shape) + { + return shape switch + { + Shape.RoundEdges => ")", + Shape.Rhombus => "}", + _ => throw new ArgumentOutOfRangeException(nameof(shape), shape, null) + }; + } +} diff --git a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Graph.cs b/src/PowerPipe.Visualization/Mermaid/Graph/Graph.cs similarity index 66% rename from src/PowerPipe.Visualization.Core/Mermaid/Graph/Graph.cs rename to src/PowerPipe.Visualization/Mermaid/Graph/Graph.cs index 3a40de0..a5c6237 100644 --- a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Graph.cs +++ b/src/PowerPipe.Visualization/Mermaid/Graph/Graph.cs @@ -1,13 +1,20 @@ using System.Collections.Generic; using System.Text; -using PowerPipe.Visualization.Core.Mermaid.Graph.Enum; -using PowerPipe.Visualization.Core.Mermaid.Graph.Interfaces; -using PowerPipe.Visualization.Core.Mermaid.Graph.Nodes; +using PowerPipe.Visualization.Mermaid.Graph.Enum; +using PowerPipe.Visualization.Mermaid.Graph.Interfaces; +using PowerPipe.Visualization.Mermaid.Graph.Nodes; -namespace PowerPipe.Visualization.Core.Mermaid.Graph; +namespace PowerPipe.Visualization.Mermaid.Graph; +/// +/// Represents a Mermaid graph with nodes and relations. +/// public class Graph : IGraph { + /// + /// Initializes a new instance of the class with the specified nodes. + /// + /// The list of nodes in the graph. public Graph(List nodes) { Nodes = nodes; @@ -16,10 +23,17 @@ public Graph(List nodes) LinkNodes(Nodes); } + /// + /// Gets the list of nodes in the graph. + /// public List Nodes { get; } + /// + /// Gets the list of relations in the graph. + /// public List Relations { get; } + /// public string Render() { var builder = new StringBuilder(); diff --git a/src/PowerPipe.Visualization/Mermaid/Graph/Interfaces/IGraph.cs b/src/PowerPipe.Visualization/Mermaid/Graph/Interfaces/IGraph.cs new file mode 100644 index 0000000..4df03e1 --- /dev/null +++ b/src/PowerPipe.Visualization/Mermaid/Graph/Interfaces/IGraph.cs @@ -0,0 +1,13 @@ +namespace PowerPipe.Visualization.Mermaid.Graph.Interfaces; + +/// +/// Represents an interface for rendering Mermaid graphs. +/// +public interface IGraph +{ + /// + /// Renders the Mermaid graph as a string. + /// + /// The rendered Mermaid graph as a string. + string Render(); +} diff --git a/src/PowerPipe.Visualization/Mermaid/Graph/Interfaces/INode.cs b/src/PowerPipe.Visualization/Mermaid/Graph/Interfaces/INode.cs new file mode 100644 index 0000000..c1b7892 --- /dev/null +++ b/src/PowerPipe.Visualization/Mermaid/Graph/Interfaces/INode.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Text; +using PowerPipe.Visualization.Mermaid.Graph.Enum; + +namespace PowerPipe.Visualization.Mermaid.Graph.Interfaces; + +/// +/// Represents an interface for a node in a Mermaid graph. +/// +public interface INode : IRenderTo +{ + /// + /// Gets the identifier of the node. + /// + string Id { get; } + + /// + /// Gets the shape of the node. + /// + Shape Shape { get; } + + /// + /// Creates and returns relations from the current node to a destination node. + /// + /// The destination node. + /// The type of link to create. + /// The text associated with the link. + /// An enumerable collection of relations created. + IEnumerable LinkTo(INode destination, Link link, string text); +} diff --git a/src/PowerPipe.Visualization/Mermaid/Graph/Interfaces/IRenderTo.cs b/src/PowerPipe.Visualization/Mermaid/Graph/Interfaces/IRenderTo.cs new file mode 100644 index 0000000..e170a20 --- /dev/null +++ b/src/PowerPipe.Visualization/Mermaid/Graph/Interfaces/IRenderTo.cs @@ -0,0 +1,14 @@ +namespace PowerPipe.Visualization.Mermaid.Graph.Interfaces; + +/// +/// Represents an interface for rendering an object to a specified target. +/// +/// The type of target to render to. +public interface IRenderTo +{ + /// + /// Renders the object to the specified target. + /// + /// The target to render the object to. + void RenderTo(T target); +} diff --git a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Nodes/AddIfElseNode.cs b/src/PowerPipe.Visualization/Mermaid/Graph/Nodes/AddIfElseNode.cs similarity index 55% rename from src/PowerPipe.Visualization.Core/Mermaid/Graph/Nodes/AddIfElseNode.cs rename to src/PowerPipe.Visualization/Mermaid/Graph/Nodes/AddIfElseNode.cs index 87025c1..a241079 100644 --- a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Nodes/AddIfElseNode.cs +++ b/src/PowerPipe.Visualization/Mermaid/Graph/Nodes/AddIfElseNode.cs @@ -1,14 +1,23 @@ using System; using System.Collections.Generic; using System.Text; -using PowerPipe.Visualization.Core.Mermaid.Graph.Extensions; -using PowerPipe.Visualization.Core.Mermaid.Graph.Enum; -using PowerPipe.Visualization.Core.Mermaid.Graph.Interfaces; +using PowerPipe.Visualization.Mermaid.Graph.Extensions; +using PowerPipe.Visualization.Mermaid.Graph.Enum; +using PowerPipe.Visualization.Mermaid.Graph.Interfaces; -namespace PowerPipe.Visualization.Core.Mermaid.Graph.Nodes; +namespace PowerPipe.Visualization.Mermaid.Graph.Nodes; +/// +/// Represents a node in a Mermaid graph for an "if-else" condition. +/// public class AddIfElseNode : INode { + /// + /// Initializes a new instance of the class. + /// + /// The name of the predicate associated with the "if-else" condition. + /// The name of the first child node. + /// The name of the second child node. public AddIfElseNode(string predicateName, string firstChildName, string secondChildName) { Id = Guid.NewGuid().ToString("N"); @@ -18,16 +27,32 @@ public AddIfElseNode(string predicateName, string firstChildName, string secondC SecondChild = new AddNode(secondChildName); } + /// + /// Gets the unique identifier of the node. + /// public string Id { get; } + /// + /// Gets the shape of the node. + /// public Shape Shape { get; } + /// + /// Gets the name of the predicate associated with the "if-else" condition. + /// public string PredicateName { get; } + /// + /// Gets the first child node associated with the "if" branch. + /// public INode FirstChild { get; } + /// + /// Gets the second child node associated with the "else" branch. + /// public INode SecondChild { get; } + /// public IEnumerable LinkTo(INode destination, Link link, string text) { var relations = new List @@ -47,6 +72,7 @@ public IEnumerable LinkTo(INode destination, Link link, string text) return relations; } + /// public void RenderTo(StringBuilder target) { target diff --git a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Nodes/AddIfNode.cs b/src/PowerPipe.Visualization/Mermaid/Graph/Nodes/AddIfNode.cs similarity index 54% rename from src/PowerPipe.Visualization.Core/Mermaid/Graph/Nodes/AddIfNode.cs rename to src/PowerPipe.Visualization/Mermaid/Graph/Nodes/AddIfNode.cs index 61f73a4..cae491e 100644 --- a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Nodes/AddIfNode.cs +++ b/src/PowerPipe.Visualization/Mermaid/Graph/Nodes/AddIfNode.cs @@ -1,14 +1,22 @@ using System; using System.Collections.Generic; using System.Text; -using PowerPipe.Visualization.Core.Mermaid.Graph.Extensions; -using PowerPipe.Visualization.Core.Mermaid.Graph.Enum; -using PowerPipe.Visualization.Core.Mermaid.Graph.Interfaces; +using PowerPipe.Visualization.Mermaid.Graph.Extensions; +using PowerPipe.Visualization.Mermaid.Graph.Enum; +using PowerPipe.Visualization.Mermaid.Graph.Interfaces; -namespace PowerPipe.Visualization.Core.Mermaid.Graph.Nodes; +namespace PowerPipe.Visualization.Mermaid.Graph.Nodes; +/// +/// Represents a node in a Mermaid graph for an "if" condition. +/// public class AddIfNode : INode { + /// + /// Initializes a new instance of the class. + /// + /// The name of the predicate associated with the "if" condition. + /// The name of the child node. public AddIfNode(string predicateName, string childName) { Id = Guid.NewGuid().ToString("N"); @@ -17,14 +25,27 @@ public AddIfNode(string predicateName, string childName) Child = new AddNode(childName); } + /// + /// Gets the unique identifier of the node. + /// public string Id { get; } + /// + /// Gets the shape of the node. + /// public Shape Shape { get; } + /// + /// Gets the name of the predicate associated with the "if" condition. + /// public string PredicateName { get; } + /// + /// Gets the child node associated with the "if" condition. + /// public INode Child { get; } + /// public IEnumerable LinkTo(INode destination, Link link, string text) { var relations = new List { new Relation(this, Child, Link.Arrow, "Yes") }; @@ -40,6 +61,7 @@ public IEnumerable LinkTo(INode destination, Link link, string text) return relations; } + /// public void RenderTo(StringBuilder target) { target diff --git a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Nodes/AddNode.cs b/src/PowerPipe.Visualization/Mermaid/Graph/Nodes/AddNode.cs similarity index 52% rename from src/PowerPipe.Visualization.Core/Mermaid/Graph/Nodes/AddNode.cs rename to src/PowerPipe.Visualization/Mermaid/Graph/Nodes/AddNode.cs index 93f33d0..7bfc906 100644 --- a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Nodes/AddNode.cs +++ b/src/PowerPipe.Visualization/Mermaid/Graph/Nodes/AddNode.cs @@ -2,14 +2,21 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using PowerPipe.Visualization.Core.Mermaid.Graph.Extensions; -using PowerPipe.Visualization.Core.Mermaid.Graph.Enum; -using PowerPipe.Visualization.Core.Mermaid.Graph.Interfaces; +using PowerPipe.Visualization.Mermaid.Graph.Extensions; +using PowerPipe.Visualization.Mermaid.Graph.Enum; +using PowerPipe.Visualization.Mermaid.Graph.Interfaces; -namespace PowerPipe.Visualization.Core.Mermaid.Graph.Nodes; +namespace PowerPipe.Visualization.Mermaid.Graph.Nodes; +/// +/// Represents a generic node in a Mermaid graph. +/// public class AddNode : INode { + /// + /// Initializes a new instance of the class with the specified name. + /// + /// The name of the node. public AddNode(string name) { Id = Guid.NewGuid().ToString("N"); @@ -17,17 +24,28 @@ public AddNode(string name) Shape = Shape.RoundEdges; } + /// + /// Gets the unique identifier of the node. + /// public string Id { get; } + /// + /// Gets the shape of the node. + /// public Shape Shape { get; } + /// + /// Gets the name of the node. + /// public string Name { get; } + /// public IEnumerable LinkTo(INode destination, Link link, string text) { return destination is null ? Enumerable.Empty() : new[] { new Relation(this, destination, Link.Arrow, string.Empty) }; } + /// public void RenderTo(StringBuilder target) { target diff --git a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Nodes/IfNode.cs b/src/PowerPipe.Visualization/Mermaid/Graph/Nodes/IfNode.cs similarity index 54% rename from src/PowerPipe.Visualization.Core/Mermaid/Graph/Nodes/IfNode.cs rename to src/PowerPipe.Visualization/Mermaid/Graph/Nodes/IfNode.cs index 3d724eb..2bbf5e2 100644 --- a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Nodes/IfNode.cs +++ b/src/PowerPipe.Visualization/Mermaid/Graph/Nodes/IfNode.cs @@ -1,14 +1,22 @@ using System; using System.Collections.Generic; using System.Text; -using PowerPipe.Visualization.Core.Mermaid.Graph.Enum; -using PowerPipe.Visualization.Core.Mermaid.Graph.Extensions; -using PowerPipe.Visualization.Core.Mermaid.Graph.Interfaces; +using PowerPipe.Visualization.Mermaid.Graph.Extensions; +using PowerPipe.Visualization.Mermaid.Graph.Enum; +using PowerPipe.Visualization.Mermaid.Graph.Interfaces; -namespace PowerPipe.Visualization.Core.Mermaid.Graph.Nodes; +namespace PowerPipe.Visualization.Mermaid.Graph.Nodes; +/// +/// Represents a node in a Mermaid graph for an "if" condition with multiple children. +/// public class IfNode : INode { + /// + /// Initializes a new instance of the class. + /// + /// The name of the predicate associated with the "if" condition. + /// The list of child nodes associated with the "if" condition. public IfNode(string predicateName, List children) { Id = Guid.NewGuid().ToString("N"); @@ -17,14 +25,27 @@ public IfNode(string predicateName, List children) Children = children; } + /// + /// Gets or sets the unique identifier of the node. + /// public string Id { get; set; } + /// + /// Gets the shape of the node. + /// public Shape Shape { get; } + /// + /// Gets or sets the name of the predicate associated with the "if" condition. + /// public string PredicateName { get; set; } + /// + /// Gets or sets the list of child nodes associated with the "if" condition. + /// public List Children { get; set; } + /// public IEnumerable LinkTo(INode destination, Link link, string text) { var relations = new List { new Relation(this, Children[0], Link.Arrow, "Yes") }; @@ -40,6 +61,7 @@ public IEnumerable LinkTo(INode destination, Link link, string text) return relations; } + /// public void RenderTo(StringBuilder target) { target diff --git a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Nodes/ParallelNode.cs b/src/PowerPipe.Visualization/Mermaid/Graph/Nodes/ParallelNode.cs similarity index 57% rename from src/PowerPipe.Visualization.Core/Mermaid/Graph/Nodes/ParallelNode.cs rename to src/PowerPipe.Visualization/Mermaid/Graph/Nodes/ParallelNode.cs index f9f75e7..b1b3ee8 100644 --- a/src/PowerPipe.Visualization.Core/Mermaid/Graph/Nodes/ParallelNode.cs +++ b/src/PowerPipe.Visualization/Mermaid/Graph/Nodes/ParallelNode.cs @@ -2,13 +2,21 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using PowerPipe.Visualization.Core.Mermaid.Graph.Enum; -using PowerPipe.Visualization.Core.Mermaid.Graph.Interfaces; +using PowerPipe.Visualization.Mermaid.Graph.Enum; +using PowerPipe.Visualization.Mermaid.Graph.Interfaces; -namespace PowerPipe.Visualization.Core.Mermaid.Graph.Nodes; +namespace PowerPipe.Visualization.Mermaid.Graph.Nodes; +/// +/// Represents a node in a Mermaid graph for parallel processing. +/// public class ParallelNode : INode { + /// + /// Initializes a new instance of the class. + /// + /// The title associated with the parallel node. + /// The list of child nodes associated with the parallel node. public ParallelNode(string title, List children) { Id = Guid.NewGuid().ToString("N"); @@ -16,13 +24,27 @@ public ParallelNode(string title, List children) Children = children; } + /// + /// Gets or sets the unique identifier of the node. + /// public string Id { get; set; } + /// + /// Gets the shape of the node. + /// public Shape Shape { get; } + /// + /// Gets the title associated with the parallel node. + /// public string Title { get; } + /// + /// Gets or sets the list of child nodes associated with the parallel node. + /// public List Children { get; set; } + + /// public IEnumerable LinkTo(INode destination, Link link, string text) { if (destination is null) @@ -40,6 +62,7 @@ public IEnumerable LinkTo(INode destination, Link link, string text) return relations; } + /// public void RenderTo(StringBuilder target) { target diff --git a/src/PowerPipe.Visualization/Mermaid/Graph/Relation.cs b/src/PowerPipe.Visualization/Mermaid/Graph/Relation.cs new file mode 100644 index 0000000..3c3fc17 --- /dev/null +++ b/src/PowerPipe.Visualization/Mermaid/Graph/Relation.cs @@ -0,0 +1,66 @@ +using System.Text; +using PowerPipe.Visualization.Mermaid.Graph.Extensions; +using PowerPipe.Visualization.Mermaid.Graph.Enum; +using PowerPipe.Visualization.Mermaid.Graph.Interfaces; + +namespace PowerPipe.Visualization.Mermaid.Graph; + +/// +/// Represents a relation between two nodes in a Mermaid graph. +/// +public class Relation : IRenderTo +{ + /// + /// Initializes a new instance of the class. + /// + /// The source node of the relation. + /// The destination node of the relation. + /// The type of link between the nodes. + /// The text associated with the relation. + public Relation(INode from, INode to, Link link, string text) + { + From = from; + To = to; + Link = link; + Text = text; + } + + /// + /// Gets the source node of the relation. + /// + public INode From { get; } + + /// + /// Gets the destination node of the relation. + /// + public INode To { get; } + + /// + /// Gets the type of link between the nodes. + /// + public Link Link { get; } + + /// + /// Gets the text associated with the relation. + /// + public string Text { get; } + + /// + public void RenderTo(StringBuilder builder) + { + builder.Append(From.Id).Append(' '); + + Link.RenderTo(builder); + builder.Append(' '); + + if (!string.IsNullOrEmpty(Text)) + { + builder + .Append("|\"") + .Append(Text) + .Append("\"|") + .Append(' '); + } + builder.AppendLine(To.Id); + } +} diff --git a/src/PowerPipe.Visualization/PipelineDiagramsService.cs b/src/PowerPipe.Visualization/PipelineDiagramsService.cs new file mode 100644 index 0000000..314b38b --- /dev/null +++ b/src/PowerPipe.Visualization/PipelineDiagramsService.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using Antlr4.Runtime; +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.CSharp; +using ICSharpCode.Decompiler.TypeSystem; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using PowerPipe.Visualization.Antlr; +using PowerPipe.Visualization.Configurations; +using PowerPipe.Visualization.Mermaid.Graph.Interfaces; + +namespace PowerPipe.Visualization; + +/// +public class PipelineDiagramsService : IPipelineDiagramService +{ + private readonly Regex _pipelineBuilderRegex = new(@"(new PipelineBuilder)[\s\S]*(;)", RegexOptions.Compiled); + private readonly Dictionary _diagrams; + + private readonly PowerPipeVisualizationConfiguration _configuration; + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + /// Diagrams visualization configuration + /// Logger factory + public PipelineDiagramsService(IOptions configuration, ILoggerFactory loggerFactory) + { + ArgumentNullException.ThrowIfNull(configuration, nameof(configuration)); + ArgumentNullException.ThrowIfNull(loggerFactory, nameof(loggerFactory)); + + _configuration = configuration.Value; + + _logger = loggerFactory.CreateLogger(); + + _diagrams = new Dictionary(); + } + + /// + public IDictionary GetDiagrams() + { + if (_diagrams.Count > 0) + return _diagrams; + + try + { + foreach (var type in GetTypesToDecompile()) + { + var decompiler = new CSharpDecompiler(type.Assembly.Location, new DecompilerSettings()); + + _diagrams.Add(type.Name, ProcessDecompiledType(decompiler.DecompileTypeAsString(new FullTypeName(type.FullName)))); + } + } + catch (Exception e) + { + _logger.LogDebug("Exception occured during retrieving of diagrams. {Exception}", e); + } + + return _diagrams; + } + + private List GetTypesToDecompile() + { + var types = _configuration.TypesToScan.Where(it => it is not null).ToList(); + + foreach (var assembly in _configuration.AssembliesToScan.Where(it => it is not null)) + types.AddRange(assembly.GetTypes()); + + return types; + } + + private string ProcessDecompiledType(string decompiledType) + { + var input = _pipelineBuilderRegex.Match(decompiledType).ToString(); + + if (string.IsNullOrEmpty(input)) + { + return null; + } + + var inputStream = new AntlrInputStream(input); + var pipelineLexer = new PipelineLexer(inputStream); + var commonTokenStream = new CommonTokenStream(pipelineLexer); + var pipelineParser = new PipelineParser(commonTokenStream); + + var startContext = pipelineParser.start(); + + var visitor = new PipelineParserVisitor(); + var graph = (IGraph)visitor.Visit(startContext); + + return graph.Render(); + } +} diff --git a/src/PowerPipe.Visualization/PipelineVisualizationMiddleware.cs b/src/PowerPipe.Visualization/PipelineVisualizationMiddleware.cs new file mode 100644 index 0000000..1a33727 --- /dev/null +++ b/src/PowerPipe.Visualization/PipelineVisualizationMiddleware.cs @@ -0,0 +1,93 @@ +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Mime; +using System.Reflection; +using System.Text; +using System.Text.Json; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; + +namespace PowerPipe.Visualization; + +/// +/// Middleware for handling visualization requests related to PowerPipe. +/// +public class PipelineVisualizationMiddleware +{ + private const string IndexHtml = "index.html"; + private const string EndpointPattern = "^/?powerpipe/?$"; + private const string IndexEndpointPattern = $"^/?powerpipe/?{IndexHtml}$"; + private const string DiagramIndexKey = "%DIAGRAMS%"; + + private readonly IPipelineDiagramService _pipelineDiagramService; + + private readonly RequestDelegate _next; + + private Func IndexStream { get; } = () => typeof(PipelineVisualizationMiddleware).GetTypeInfo().Assembly + .GetManifestResourceStream("PowerPipe.Visualization.index.html"); + + /// + /// Initializes a new instance of the class. + /// + /// Service to parse diagrams. + /// The next middleware in the pipeline. + public PipelineVisualizationMiddleware(IPipelineDiagramService pipelineDiagramService, RequestDelegate next) + { + _pipelineDiagramService = pipelineDiagramService; + _next = next; + } + + /// + /// Invokes the middleware to handle HTTP requests. + /// + /// The context of the HTTP request. + /// A task representing the asynchronous operation. + public async Task Invoke(HttpContext httpContext) + { + var httpMethod = httpContext.Request.Method; + var path = httpContext.Request.Path.Value; + + if (httpMethod is WebRequestMethods.Http.Get && + Regex.IsMatch(path, EndpointPattern, RegexOptions.IgnoreCase)) + { + var relativeIndexUrl = string.IsNullOrEmpty(path) || path.EndsWith('/') + ? IndexHtml + : $"{path.Split('/').Last()}/{IndexHtml}"; + + RespondWithRedirect(httpContext.Response, relativeIndexUrl); + return; + } + + if (httpMethod is WebRequestMethods.Http.Get && + Regex.IsMatch(path, IndexEndpointPattern, RegexOptions.IgnoreCase)) + { + await RespondWithIndexHtml(httpContext.Response); + return; + } + + await _next(httpContext); + } + + private static void RespondWithRedirect(HttpResponse response, string location) + { + response.StatusCode = 301; + response.Headers["Location"] = location; + } + + private async Task RespondWithIndexHtml(HttpResponse response) + { + response.StatusCode = 200; + response.ContentType = MediaTypeNames.Text.Html; + + await using var stream = IndexStream(); + using var reader = new StreamReader(stream); + + var htmlBuilder = new StringBuilder(await reader.ReadToEndAsync()); + htmlBuilder.Replace(DiagramIndexKey, JsonSerializer.Serialize(_pipelineDiagramService.GetDiagrams())); + + await response.WriteAsync(htmlBuilder.ToString(), Encoding.UTF8); + } +} diff --git a/src/PowerPipe.Visualization.Core/PowerPipe.Visualization.Core.csproj b/src/PowerPipe.Visualization/PowerPipe.Visualization.csproj similarity index 68% rename from src/PowerPipe.Visualization.Core/PowerPipe.Visualization.Core.csproj rename to src/PowerPipe.Visualization/PowerPipe.Visualization.csproj index 50f7493..4537d92 100644 --- a/src/PowerPipe.Visualization.Core/PowerPipe.Visualization.Core.csproj +++ b/src/PowerPipe.Visualization/PowerPipe.Visualization.csproj @@ -1,14 +1,6 @@ - - net8.0 - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - @@ -30,8 +22,4 @@ - - - - diff --git a/src/PowerPipe.Visualization.Core/index.html b/src/PowerPipe.Visualization/index.html similarity index 65% rename from src/PowerPipe.Visualization.Core/index.html rename to src/PowerPipe.Visualization/index.html index f7c2cbf..5fbc054 100644 --- a/src/PowerPipe.Visualization.Core/index.html +++ b/src/PowerPipe.Visualization/index.html @@ -1,6 +1,6 @@ - + PowerPipe visualization @@ -15,7 +15,8 @@ .sidebar .nav-link { font-weight: 500; color: #333; } .sidebar .nav-link.active { color: #2470dc; } .navbar-brand { padding-top: .75rem; padding-bottom: .75rem; font-size: 1rem; background-color: rgba(0, 0, 0, .25); box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25); } - .navbar { top: .25rem; right: 1rem; padding: .75rem 1rem; border-width: 0; border-radius: 0; } + .navbar { right: 1rem; padding: .75rem 1rem; border-width: 0; border-radius: 0; } + #diagram { text-align: center; } @@ -42,15 +43,7 @@ Workflows


-