From d96ae2be8eeadd0d4597422c43797d6db61bfd65 Mon Sep 17 00:00:00 2001 From: wowbios Date: Thu, 5 Mar 2026 15:24:02 +0300 Subject: [PATCH 1/2] Update README.md with Mermaid.js v11 compatibility, add Flowchart API status, and provide quick examples. Introduce new AdvancedShape class and Edge animation and curve enums for enhanced flowchart capabilities. --- README.md | 62 ++++++-- src/FluentMermaid/Flowchart/AdvancedShape.cs | 52 +++++++ .../Flowchart/Enum/EdgeAnimationSpeed.cs | 7 + src/FluentMermaid/Flowchart/Enum/EdgeCurve.cs | 17 +++ src/FluentMermaid/Flowchart/Enum/Link.cs | 17 ++- src/FluentMermaid/Flowchart/Enum/Shape.cs | 3 +- .../EdgeAnimationSpeedExtensions.cs | 14 ++ .../Extensions/EdgeCurveExtensions.cs | 24 +++ .../Flowchart/Extensions/LinkExtensions.cs | 15 +- .../Flowchart/Extensions/ShapeExtensions.cs | 4 +- src/FluentMermaid/Flowchart/FlowChart.cs | 4 +- .../Flowchart/Interfaces/IAdvancedGraph.cs | 36 +++++ .../Flowchart/Interfaces/IAdvancedSubGraph.cs | 5 + .../Flowchart/Interfaces/IEdgeStyling.cs | 20 +++ .../Interfaces/IFlowChartAdvanced.cs | 6 + .../Flowchart/Nodes/AdvancedTextNode.cs | 70 +++++++++ .../Flowchart/Nodes/EdgeStylingNode.cs | 142 ++++++++++++++++++ .../Flowchart/Nodes/FlowchartRootNode.cs | 122 ++++++++++++++- .../Flowchart/Nodes/SubGraphNode.cs | 100 +++++++++++- src/FluentMermaid/Flowchart/Relation.cs | 11 +- src/FluentMermaidLibrary.sln | 29 ++++ .../FlowchartRenderingTests.cs | 90 +++++++++++ .../FluentMermaid.Tests.csproj | 29 ++++ tests/FluentMermaid.Tests/GlobalUsings.cs | 1 + 24 files changed, 846 insertions(+), 34 deletions(-) create mode 100644 src/FluentMermaid/Flowchart/AdvancedShape.cs create mode 100644 src/FluentMermaid/Flowchart/Enum/EdgeAnimationSpeed.cs create mode 100644 src/FluentMermaid/Flowchart/Enum/EdgeCurve.cs create mode 100644 src/FluentMermaid/Flowchart/Extensions/EdgeAnimationSpeedExtensions.cs create mode 100644 src/FluentMermaid/Flowchart/Extensions/EdgeCurveExtensions.cs create mode 100644 src/FluentMermaid/Flowchart/Interfaces/IAdvancedGraph.cs create mode 100644 src/FluentMermaid/Flowchart/Interfaces/IAdvancedSubGraph.cs create mode 100644 src/FluentMermaid/Flowchart/Interfaces/IEdgeStyling.cs create mode 100644 src/FluentMermaid/Flowchart/Interfaces/IFlowChartAdvanced.cs create mode 100644 src/FluentMermaid/Flowchart/Nodes/AdvancedTextNode.cs create mode 100644 src/FluentMermaid/Flowchart/Nodes/EdgeStylingNode.cs create mode 100644 tests/FluentMermaid.Tests/FlowchartRenderingTests.cs create mode 100644 tests/FluentMermaid.Tests/FluentMermaid.Tests.csproj create mode 100644 tests/FluentMermaid.Tests/GlobalUsings.cs diff --git a/README.md b/README.md index 3ae3aa9..2128e06 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,61 @@ # FluentMermaid -![MIT License](https://img.shields.io/github/license/wowbios/FluentMermaid) ![Nuget version](https://img.shields.io/nuget/v/FluentMermaid?color=blue) -.NET api for generating mermaid syntax markdown that then could be rendered with [Mermaid.js](https://mermaid-js.github.io/mermaid/#/) +.NET api for generating mermaid syntax markdown that then could be rendered with [Mermaid.js](https://mermaid.js.org/) Supported platforms: `.netstandard 2.0` -Tested with Mermaid js v9.1.1 +Tested with Mermaid js [v11.12.3](https://github.com/mermaid-js/mermaid/releases/tag/mermaid%4011.12.3) ### For examples look at [WIKI repo page](https://github.com/wowbios/FluentMermaid/wiki/) +## Flowchart API status (Mermaid v11) + +- Backward compatible API: `FlowChart.Create(...)` and existing `TextNode/Link/SubGraph/Interaction/Styling`. +- Advanced additive API: `FlowChart.CreateAdvanced(...)`. + +### Coverage matrix + +- Legacy shapes (`[]`, `()`, `(( ))`, `{{ }}` etc): supported. +- Expanded shapes syntax (`A@{ shape: ... }`): supported via `CreateAdvanced` + `TextNode(string, string shapeAlias)`. +- Special shapes `icon` / `image`: supported via `IconNode(...)` / `ImageNode(...)`. +- Edge IDs (`e1@-->`) and edge-level options (`animate/animation/curve`): supported via advanced `Link(... edgeId ...)` + `EdgeStyling`. +- Link styles (`linkStyle` index/default): supported via `EdgeStyling`. + +### Quick examples + +```csharp +using FluentMermaid.Enums; +using FluentMermaid.Flowchart; +using FluentMermaid.Flowchart.Enum; + +var chart = FlowChart.CreateAdvanced(Orientation.LeftToRight); + +var a = chart.TextNode("Manual input", AdvancedShape.SlopedRectangle); +var b = chart.IconNode("fa:user", "User Icon", "square", "t", 60); +var c = chart.ImageNode(new Uri("https://example.com/image.png"), "Image", "t", 60, 60, false); + +chart.Link(a, b, "e1", Link.Arrow, "", 1); +chart.Link(b, c, Link.Thick, "next", 1); // old API still works + +chart.EdgeStyling.SetAnimated("e1"); +chart.EdgeStyling.SetAnimation("e1", EdgeAnimationSpeed.Fast); +chart.EdgeStyling.SetCurve("e1", EdgeCurve.Linear); +chart.EdgeStyling.LinkStyleDefault("color:blue"); + +var mermaid = chart.Render(); +``` + # Roadmap -- [x] [Flowchart](https://mermaid-js.github.io/mermaid/#/flowchart) -- [x] [Sequence diagram](https://mermaid-js.github.io/mermaid/#/sequenceDiagram) -- [x] [Class diagram](https://mermaid-js.github.io/mermaid/#/classDiagram) -- [x] [Pie chart](https://mermaid-js.github.io/mermaid/#/pie) -- [x] [State diagram](https://mermaid-js.github.io/mermaid/#/stateDiagram) -- [ ] [Entity relationship](https://mermaid-js.github.io/mermaid/#/entityRelationshipDiagram) https://github.com/wowbios/FluentMermaid/issues/18 -- [ ] [User journey](https://mermaid-js.github.io/mermaid/#/user-journey) https://github.com/wowbios/FluentMermaid/issues/19 -- [ ] [Gantt](https://mermaid-js.github.io/mermaid/#/gantt) https://github.com/wowbios/FluentMermaid/issues/20 -- [ ] [Requirement](https://mermaid-js.github.io/mermaid/#/requirementDiagram) https://github.com/wowbios/FluentMermaid/issues/21 -- [ ] [Git graph](https://mermaid-js.github.io/mermaid/#/gitgraph) https://github.com/wowbios/FluentMermaid/issues/22 +- [x] [Flowchart](https://mermaid.js.org/syntax/flowchart.html) +- [x] [Sequence diagram](https://mermaid.js.org/syntax/sequenceDiagram.html) +- [x] [Class diagram](https://mermaid.js.org/syntax/classDiagram.html) +- [x] [Pie chart](https://mermaid.js.org/syntax/pie.html) +- [x] [State diagram](https://mermaid.js.org/syntax/stateDiagram.html) +- [ ] [Entity relationship](https://mermaid.js.org/syntax/entityRelationshipDiagram.html) https://github.com/wowbios/FluentMermaid/issues/18 +- [ ] [User journey](https://mermaid.js.org/syntax/userJourney.html) https://github.com/wowbios/FluentMermaid/issues/19 +- [ ] [Gantt](https://mermaid.js.org/syntax/gantt.html) https://github.com/wowbios/FluentMermaid/issues/20 +- [ ] [Requirement](https://mermaid.js.org/syntax/requirementDiagram.html) https://github.com/wowbios/FluentMermaid/issues/21 +- [ ] [Git graph](https://mermaid.js.org/syntax/gitgraph.html) https://github.com/wowbios/FluentMermaid/issues/22 - [ ] Flowchart fluent API https://github.com/wowbios/FluentMermaid/issues/15 - [ ] Class diagram fluent API https://github.com/wowbios/FluentMermaid/issues/16 diff --git a/src/FluentMermaid/Flowchart/AdvancedShape.cs b/src/FluentMermaid/Flowchart/AdvancedShape.cs new file mode 100644 index 0000000..133a826 --- /dev/null +++ b/src/FluentMermaid/Flowchart/AdvancedShape.cs @@ -0,0 +1,52 @@ +namespace FluentMermaid.Flowchart; + +public static class AdvancedShape +{ + public const string Bang = "bang"; + public const string NotchedRectangle = "notch-rect"; + public const string Cloud = "cloud"; + public const string Hourglass = "hourglass"; + public const string Bolt = "bolt"; + public const string BraceLeft = "brace-l"; + public const string BraceRight = "brace-r"; + public const string Braces = "braces"; + public const string LeanRight = "lean-r"; + public const string LeanLeft = "lean-l"; + public const string Cylinder = "cyl"; + public const string Diamond = "diam"; + public const string Delay = "delay"; + public const string HorizontalCylinder = "h-cyl"; + public const string LinedCylinder = "lin-cyl"; + public const string CurvedTrapezoid = "curv-trap"; + public const string DividedRectangle = "div-rect"; + public const string Document = "doc"; + public const string RoundedRectangle = "rounded"; + public const string Triangle = "tri"; + public const string Fork = "fork"; + public const string WindowPane = "win-pane"; + public const string FilledCircle = "f-circ"; + public const string LinedDocument = "lin-doc"; + public const string LinedRectangle = "lin-rect"; + public const string NotchedPentagon = "notch-pent"; + public const string FlippedTriangle = "flip-tri"; + public const string SlopedRectangle = "sl-rect"; + public const string InvertedTrapezoid = "trap-t"; + public const string StackedDocuments = "docs"; + public const string StackedRectangle = "st-rect"; + public const string Odd = "odd"; + public const string Flag = "flag"; + public const string Hexagon = "hex"; + public const string Trapezoid = "trap-b"; + public const string Rectangle = "rect"; + public const string Circle = "circle"; + public const string SmallCircle = "sm-circ"; + public const string DoubleCircle = "dbl-circ"; + public const string FramedCircle = "fr-circ"; + public const string BowTieRectangle = "bow-rect"; + public const string FramedRectangle = "fr-rect"; + public const string CrossedCircle = "cross-circ"; + public const string TaggedDocument = "tag-doc"; + public const string TaggedRectangle = "tag-rect"; + public const string Stadium = "stadium"; + public const string Text = "text"; +} diff --git a/src/FluentMermaid/Flowchart/Enum/EdgeAnimationSpeed.cs b/src/FluentMermaid/Flowchart/Enum/EdgeAnimationSpeed.cs new file mode 100644 index 0000000..d4fcd60 --- /dev/null +++ b/src/FluentMermaid/Flowchart/Enum/EdgeAnimationSpeed.cs @@ -0,0 +1,7 @@ +namespace FluentMermaid.Flowchart.Enum; + +public enum EdgeAnimationSpeed +{ + Fast, + Slow +} diff --git a/src/FluentMermaid/Flowchart/Enum/EdgeCurve.cs b/src/FluentMermaid/Flowchart/Enum/EdgeCurve.cs new file mode 100644 index 0000000..97e1b26 --- /dev/null +++ b/src/FluentMermaid/Flowchart/Enum/EdgeCurve.cs @@ -0,0 +1,17 @@ +namespace FluentMermaid.Flowchart.Enum; + +public enum EdgeCurve +{ + Basis, + BumpX, + BumpY, + Cardinal, + CatmullRom, + Linear, + MonotoneX, + MonotoneY, + Natural, + Step, + StepAfter, + StepBefore +} diff --git a/src/FluentMermaid/Flowchart/Enum/Link.cs b/src/FluentMermaid/Flowchart/Enum/Link.cs index 2e84cd1..adec26a 100644 --- a/src/FluentMermaid/Flowchart/Enum/Link.cs +++ b/src/FluentMermaid/Flowchart/Enum/Link.cs @@ -1,4 +1,4 @@ -namespace FluentMermaid.Flowchart.Enum; +namespace FluentMermaid.Flowchart.Enum; public enum Link { @@ -16,11 +16,21 @@ public enum Link /// -.- /// Dotted, + + /// + /// -.-> + /// + DottedArrow, /// /// ==> /// Thick, + + /// + /// === + /// + ThickOpen, /// /// --o @@ -46,4 +56,9 @@ public enum Link /// x--x /// CrossDouble, + + /// + /// ~~~ + /// + Invisible, } \ No newline at end of file diff --git a/src/FluentMermaid/Flowchart/Enum/Shape.cs b/src/FluentMermaid/Flowchart/Enum/Shape.cs index cf1e849..a41cd54 100644 --- a/src/FluentMermaid/Flowchart/Enum/Shape.cs +++ b/src/FluentMermaid/Flowchart/Enum/Shape.cs @@ -1,7 +1,8 @@ -namespace FluentMermaid.Flowchart.Enum; +namespace FluentMermaid.Flowchart.Enum; public enum Shape { + Rectangle, RoundEdges, Stadium, Subroutine, diff --git a/src/FluentMermaid/Flowchart/Extensions/EdgeAnimationSpeedExtensions.cs b/src/FluentMermaid/Flowchart/Extensions/EdgeAnimationSpeedExtensions.cs new file mode 100644 index 0000000..83b7d09 --- /dev/null +++ b/src/FluentMermaid/Flowchart/Extensions/EdgeAnimationSpeedExtensions.cs @@ -0,0 +1,14 @@ +using FluentMermaid.Flowchart.Enum; + +namespace FluentMermaid.Flowchart.Extensions; + +internal static class EdgeAnimationSpeedExtensions +{ + public static string Render(this EdgeAnimationSpeed speed) + => speed switch + { + EdgeAnimationSpeed.Fast => "fast", + EdgeAnimationSpeed.Slow => "slow", + _ => throw new ArgumentOutOfRangeException(nameof(speed), speed, null) + }; +} diff --git a/src/FluentMermaid/Flowchart/Extensions/EdgeCurveExtensions.cs b/src/FluentMermaid/Flowchart/Extensions/EdgeCurveExtensions.cs new file mode 100644 index 0000000..298eefd --- /dev/null +++ b/src/FluentMermaid/Flowchart/Extensions/EdgeCurveExtensions.cs @@ -0,0 +1,24 @@ +using FluentMermaid.Flowchart.Enum; + +namespace FluentMermaid.Flowchart.Extensions; + +internal static class EdgeCurveExtensions +{ + public static string Render(this EdgeCurve curve) + => curve switch + { + EdgeCurve.Basis => "basis", + EdgeCurve.BumpX => "bumpX", + EdgeCurve.BumpY => "bumpY", + EdgeCurve.Cardinal => "cardinal", + EdgeCurve.CatmullRom => "catmullRom", + EdgeCurve.Linear => "linear", + EdgeCurve.MonotoneX => "monotoneX", + EdgeCurve.MonotoneY => "monotoneY", + EdgeCurve.Natural => "natural", + EdgeCurve.Step => "step", + EdgeCurve.StepAfter => "stepAfter", + EdgeCurve.StepBefore => "stepBefore", + _ => throw new ArgumentOutOfRangeException(nameof(curve), curve, null) + }; +} diff --git a/src/FluentMermaid/Flowchart/Extensions/LinkExtensions.cs b/src/FluentMermaid/Flowchart/Extensions/LinkExtensions.cs index 5fce996..8364502 100644 --- a/src/FluentMermaid/Flowchart/Extensions/LinkExtensions.cs +++ b/src/FluentMermaid/Flowchart/Extensions/LinkExtensions.cs @@ -1,4 +1,4 @@ -using System.Text; +using System.Text; using FluentMermaid.Flowchart.Enum; namespace FluentMermaid.Flowchart.Extensions; @@ -19,9 +19,15 @@ public static void RenderTo( RenderSingle('-', "--"); break; case Link.Dotted: - RenderDouble("-.", '.', "-"); + RenderDouble("-", '.', "-"); + break; + case Link.DottedArrow: + RenderDouble("-", '.', "->"); break; case Link.Thick: + RenderSingle('=', "=>"); + break; + case Link.ThickOpen: RenderSingle('=', "=="); break; case Link.Circle: @@ -38,6 +44,11 @@ public static void RenderTo( break; case Link.CrossDouble: RenderDouble("x", '-', "-x"); + break; + case Link.Invisible: + for (var i = 0; i < length + 2; i++) + builder.Append('~'); + break; default: throw new ArgumentOutOfRangeException(nameof(link), link, null); diff --git a/src/FluentMermaid/Flowchart/Extensions/ShapeExtensions.cs b/src/FluentMermaid/Flowchart/Extensions/ShapeExtensions.cs index a7dd07c..510df5f 100644 --- a/src/FluentMermaid/Flowchart/Extensions/ShapeExtensions.cs +++ b/src/FluentMermaid/Flowchart/Extensions/ShapeExtensions.cs @@ -1,4 +1,4 @@ -using FluentMermaid.Flowchart.Enum; +using FluentMermaid.Flowchart.Enum; namespace FluentMermaid.Flowchart.Extensions; @@ -7,6 +7,7 @@ internal static class ShapeExtensions public static string RenderStart(this Shape shape) => shape switch { + Shape.Rectangle => "[", Shape.RoundEdges => "(", Shape.Stadium => "([", Shape.Subroutine => "[[", @@ -26,6 +27,7 @@ public static string RenderStart(this Shape shape) public static string RenderEnd(this Shape shape) => shape switch { + Shape.Rectangle => "]", Shape.RoundEdges => ")", Shape.Stadium => "])", Shape.Subroutine => "]]", diff --git a/src/FluentMermaid/Flowchart/FlowChart.cs b/src/FluentMermaid/Flowchart/FlowChart.cs index ccb8042..5349eaf 100644 --- a/src/FluentMermaid/Flowchart/FlowChart.cs +++ b/src/FluentMermaid/Flowchart/FlowChart.cs @@ -1,4 +1,4 @@ -using FluentMermaid.Enums; +using FluentMermaid.Enums; using FluentMermaid.Flowchart.Interfaces; using FluentMermaid.Flowchart.Nodes; @@ -7,4 +7,6 @@ namespace FluentMermaid.Flowchart; public static class FlowChart { public static IFlowChart Create(Orientation orientation) => new FlowchartRootNode(orientation); + + public static IFlowChartAdvanced CreateAdvanced(Orientation orientation) => new FlowchartRootNode(orientation); } \ No newline at end of file diff --git a/src/FluentMermaid/Flowchart/Interfaces/IAdvancedGraph.cs b/src/FluentMermaid/Flowchart/Interfaces/IAdvancedGraph.cs new file mode 100644 index 0000000..7fe599c --- /dev/null +++ b/src/FluentMermaid/Flowchart/Interfaces/IAdvancedGraph.cs @@ -0,0 +1,36 @@ +using FluentMermaid.Enums; +using FluentMermaid.Flowchart.Enum; + +namespace FluentMermaid.Flowchart.Interfaces; + +public interface IAdvancedGraph : IGraph +{ + INode TextNode(string content, string shapeAlias); + + INode IconNode( + string icon, + string? label = null, + string? form = null, + string? position = null, + int? height = null); + + INode ImageNode( + Uri imageUrl, + string? label = null, + string? position = null, + int? width = null, + int? height = null, + bool? constraint = null); + + IAdvancedSubGraph AdvancedSubGraph(string title, Orientation orientation); + + IAdvancedSubGraph AdvancedSubGraph(string id, string title, Orientation orientation); + + void Link( + INode from, + INode to, + string edgeId, + Link link, + string text, + int length = 1); +} diff --git a/src/FluentMermaid/Flowchart/Interfaces/IAdvancedSubGraph.cs b/src/FluentMermaid/Flowchart/Interfaces/IAdvancedSubGraph.cs new file mode 100644 index 0000000..8162751 --- /dev/null +++ b/src/FluentMermaid/Flowchart/Interfaces/IAdvancedSubGraph.cs @@ -0,0 +1,5 @@ +namespace FluentMermaid.Flowchart.Interfaces; + +public interface IAdvancedSubGraph : ISubGraph, IAdvancedGraph +{ +} diff --git a/src/FluentMermaid/Flowchart/Interfaces/IEdgeStyling.cs b/src/FluentMermaid/Flowchart/Interfaces/IEdgeStyling.cs new file mode 100644 index 0000000..d64499f --- /dev/null +++ b/src/FluentMermaid/Flowchart/Interfaces/IEdgeStyling.cs @@ -0,0 +1,20 @@ +using FluentMermaid.Flowchart.Enum; + +namespace FluentMermaid.Flowchart.Interfaces; + +public interface IEdgeStyling : INode +{ + void SetAnimated(string edgeId, bool value = true); + + void SetAnimation(string edgeId, EdgeAnimationSpeed speed); + + void SetCurve(string edgeId, EdgeCurve curve); + + void SetClass(string edgeId, string className); + + void LinkStyle(int linkIndex, string css); + + void LinkStyle(IEnumerable linkIndexes, string css); + + void LinkStyleDefault(string css); +} diff --git a/src/FluentMermaid/Flowchart/Interfaces/IFlowChartAdvanced.cs b/src/FluentMermaid/Flowchart/Interfaces/IFlowChartAdvanced.cs new file mode 100644 index 0000000..fb57648 --- /dev/null +++ b/src/FluentMermaid/Flowchart/Interfaces/IFlowChartAdvanced.cs @@ -0,0 +1,6 @@ +namespace FluentMermaid.Flowchart.Interfaces; + +public interface IFlowChartAdvanced : IFlowChart, IAdvancedGraph +{ + IEdgeStyling EdgeStyling { get; } +} diff --git a/src/FluentMermaid/Flowchart/Nodes/AdvancedTextNode.cs b/src/FluentMermaid/Flowchart/Nodes/AdvancedTextNode.cs new file mode 100644 index 0000000..0546176 --- /dev/null +++ b/src/FluentMermaid/Flowchart/Nodes/AdvancedTextNode.cs @@ -0,0 +1,70 @@ +using System.Globalization; +using System.Text; +using FluentMermaid.Extensions; +using FluentMermaid.Flowchart.Interfaces; + +namespace FluentMermaid.Flowchart.Nodes; + +internal sealed record AdvancedTextNode : Node +{ + private readonly List _attributes = new(); + + public AdvancedTextNode( + IGraph graph, + string id, + params NodeAttribute[] attributes) + : base(graph, id) + { + _attributes.AddRange(attributes); + } + + public override void RenderTo(StringBuilder builder) + { + builder.Append(Id).Append("@{ "); + + var hasWrittenAttribute = false; + foreach (NodeAttribute attribute in _attributes) + { + if (hasWrittenAttribute) + builder.Append(", "); + + builder.Append(attribute.Key).Append(": "); + if (attribute.QuoteValue) + { + builder.Append('"'); + builder.WriteEscaped(attribute.Value); + builder.Append('"'); + } + else + { + builder.Append(attribute.Value); + } + + hasWrittenAttribute = true; + } + + builder.AppendLine(" }"); + } + + internal readonly struct NodeAttribute + { + public NodeAttribute(string key, string value, bool quoteValue = false) + { + Key = key; + Value = value; + QuoteValue = quoteValue; + } + + public string Key { get; } + + public string Value { get; } + + public bool QuoteValue { get; } + + public static NodeAttribute FromBool(string key, bool value) + => new(key, value ? "true" : "false"); + + public static NodeAttribute FromInt(string key, int value) + => new(key, value.ToString(CultureInfo.InvariantCulture)); + } +} diff --git a/src/FluentMermaid/Flowchart/Nodes/EdgeStylingNode.cs b/src/FluentMermaid/Flowchart/Nodes/EdgeStylingNode.cs new file mode 100644 index 0000000..278d2fb --- /dev/null +++ b/src/FluentMermaid/Flowchart/Nodes/EdgeStylingNode.cs @@ -0,0 +1,142 @@ +using System.Text; +using FluentMermaid.Flowchart.Enum; +using FluentMermaid.Flowchart.Extensions; +using FluentMermaid.Flowchart.Interfaces; + +namespace FluentMermaid.Flowchart.Nodes; + +internal sealed class EdgeStylingNode : IEdgeStyling +{ + private readonly Dictionary _edgeProperties = new(); + private readonly List _edgePropertiesOrder = new(); + private readonly List<(string edgeId, string className)> _edgeClasses = new(); + private readonly List<(string selector, string css)> _linkStyles = new(); + + public string Id { get; } = "edgeStyling"; + + public void SetAnimated(string edgeId, bool value = true) + => GetOrCreate(edgeId).Animate = value; + + public void SetAnimation(string edgeId, EdgeAnimationSpeed speed) + => GetOrCreate(edgeId).Animation = speed; + + public void SetCurve(string edgeId, EdgeCurve curve) + => GetOrCreate(edgeId).Curve = curve; + + public void SetClass(string edgeId, string className) + { + EnsureEdgeId(edgeId); + if (string.IsNullOrWhiteSpace(className)) + throw new ArgumentException("Class name should not be null or empty", nameof(className)); + + _edgeClasses.Add((edgeId, className)); + } + + public void LinkStyle(int linkIndex, string css) + { + if (linkIndex < 0) + throw new ArgumentException("Link index should be non-negative", nameof(linkIndex)); + EnsureCss(css); + + _linkStyles.Add((linkIndex.ToString(), css)); + } + + public void LinkStyle(IEnumerable linkIndexes, string css) + { + if (linkIndexes is null) + throw new ArgumentNullException(nameof(linkIndexes)); + EnsureCss(css); + + var indexes = linkIndexes.ToArray(); + if (indexes.Length == 0) + throw new ArgumentException("At least one link index should be provided", nameof(linkIndexes)); + if (indexes.Any(i => i < 0)) + throw new ArgumentException("All link indexes should be non-negative", nameof(linkIndexes)); + + _linkStyles.Add((string.Join(",", indexes), css)); + } + + public void LinkStyleDefault(string css) + { + EnsureCss(css); + _linkStyles.Add(("default", css)); + } + + public void RenderTo(StringBuilder builder) + { + foreach (string edgeId in _edgePropertiesOrder) + { + EdgeProperties props = _edgeProperties[edgeId]; + var pairs = new List(3); + + if (props.Animate.HasValue) + pairs.Add($"animate: {(props.Animate.Value ? "true" : "false")}"); + if (props.Animation.HasValue) + pairs.Add($"animation: {props.Animation.Value.Render()}"); + if (props.Curve.HasValue) + pairs.Add($"curve: {props.Curve.Value.Render()}"); + + if (pairs.Count == 0) + continue; + + builder + .Append(edgeId) + .Append("@{ ") + .Append(string.Join(", ", pairs)) + .AppendLine(" }"); + } + + foreach ((string edgeId, string className) in _edgeClasses) + { + builder + .Append("class ") + .Append(edgeId) + .Append(' ') + .AppendLine(className); + } + + foreach ((string selector, string css) in _linkStyles) + { + builder + .Append("linkStyle ") + .Append(selector) + .Append(' ') + .Append(css) + .AppendLine(";"); + } + } + + private EdgeProperties GetOrCreate(string edgeId) + { + EnsureEdgeId(edgeId); + + if (_edgeProperties.TryGetValue(edgeId, out EdgeProperties? value)) + return value; + + var props = new EdgeProperties(); + _edgeProperties[edgeId] = props; + _edgePropertiesOrder.Add(edgeId); + return props; + } + + private static void EnsureEdgeId(string edgeId) + { + if (string.IsNullOrWhiteSpace(edgeId)) + throw new ArgumentException("Edge id should not be null or empty", nameof(edgeId)); + } + + private static void EnsureCss(string css) + { + if (string.IsNullOrWhiteSpace(css)) + throw new ArgumentException("CSS should not be null or empty", nameof(css)); + } + + private sealed class EdgeProperties + { + public bool? Animate { get; set; } + + public EdgeAnimationSpeed? Animation { get; set; } + + public EdgeCurve? Curve { get; set; } + } +} diff --git a/src/FluentMermaid/Flowchart/Nodes/FlowchartRootNode.cs b/src/FluentMermaid/Flowchart/Nodes/FlowchartRootNode.cs index e83cd93..ba6d35f 100644 --- a/src/FluentMermaid/Flowchart/Nodes/FlowchartRootNode.cs +++ b/src/FluentMermaid/Flowchart/Nodes/FlowchartRootNode.cs @@ -1,4 +1,4 @@ -using System.Text; +using System.Text; using FluentMermaid.Enums; using FluentMermaid.Extensions; using FluentMermaid.Flowchart.Enum; @@ -8,7 +8,7 @@ namespace FluentMermaid.Flowchart.Nodes; -internal class FlowchartRootNode : IFlowChart +internal class FlowchartRootNode : IFlowChartAdvanced { internal FlowchartRootNode(Orientation orientation) { @@ -21,9 +21,11 @@ internal FlowchartRootNode(Orientation orientation) public IStyling Styling { get; } = new Styling.Styling("styling"); - private HashSet Nodes { get; } = new(); + public IEdgeStyling EdgeStyling { get; } = new EdgeStylingNode(); - private HashSet Relations { get; } = new(); + private List Nodes { get; } = new(); + + private List Relations { get; } = new(); public INode TextNode(string content, Shape shape) { @@ -39,18 +41,104 @@ public ISubGraph SubGraph(string title, Orientation orientation) return subgraph; } + public IAdvancedSubGraph AdvancedSubGraph(string title, Orientation orientation) + { + var subgraph = new SubGraphNode(CreateNodeId(), title, orientation); + Nodes.Add(subgraph); + return subgraph; + } + + public IAdvancedSubGraph AdvancedSubGraph(string id, string title, Orientation orientation) + { + var subgraph = new SubGraphNode(id, title, orientation); + Nodes.Add(subgraph); + return subgraph; + } + public void Link( INode from, INode to, Link link, string text, int length = 1) + => AddRelation(from, to, link, text, length); + + public void Link( + INode from, + INode to, + string edgeId, + Link link, + string text, + int length = 1) + => AddRelation(from, to, link, text, length, edgeId); + + public INode TextNode(string content, string shapeAlias) { - if (length < 1) - throw new ArgumentException("Link length should be more or equal 1", nameof(length)); + if (string.IsNullOrWhiteSpace(shapeAlias)) + throw new ArgumentException("Shape alias should not be null or empty", nameof(shapeAlias)); - Relation relation = new(from, to, link, text, length); - Relations.Add(relation); + AdvancedTextNode textNode = new( + this, + CreateNodeId(), + new AdvancedTextNode.NodeAttribute("shape", shapeAlias), + new AdvancedTextNode.NodeAttribute("label", content, true)); + + Nodes.Add(textNode); + return textNode; + } + + public INode IconNode(string icon, string? label = null, string? form = null, string? position = null, int? height = null) + { + if (string.IsNullOrWhiteSpace(icon)) + throw new ArgumentException("Icon should not be null or empty", nameof(icon)); + + var attrs = new List + { + new("icon", icon, true) + }; + if (!string.IsNullOrWhiteSpace(form)) + attrs.Add(new("form", form!, true)); + if (!string.IsNullOrWhiteSpace(label)) + attrs.Add(new("label", label!, true)); + if (!string.IsNullOrWhiteSpace(position)) + attrs.Add(new("pos", position!, true)); + if (height.HasValue) + attrs.Add(AdvancedTextNode.NodeAttribute.FromInt("h", height.Value)); + + AdvancedTextNode node = new(this, CreateNodeId(), attrs.ToArray()); + Nodes.Add(node); + return node; + } + + public INode ImageNode( + Uri imageUrl, + string? label = null, + string? position = null, + int? width = null, + int? height = null, + bool? constraint = null) + { + if (imageUrl is null) + throw new ArgumentNullException(nameof(imageUrl)); + + var attrs = new List + { + new("img", imageUrl.ToString(), true) + }; + if (!string.IsNullOrWhiteSpace(label)) + attrs.Add(new("label", label!, true)); + if (!string.IsNullOrWhiteSpace(position)) + attrs.Add(new("pos", position!, true)); + if (width.HasValue) + attrs.Add(AdvancedTextNode.NodeAttribute.FromInt("w", width.Value)); + if (height.HasValue) + attrs.Add(AdvancedTextNode.NodeAttribute.FromInt("h", height.Value)); + if (constraint.HasValue) + attrs.Add(new("constraint", constraint.Value ? "on" : "off", true)); + + AdvancedTextNode node = new(this, CreateNodeId(), attrs.ToArray()); + Nodes.Add(node); + return node; } public string Render() @@ -67,9 +155,27 @@ public string Render() Interaction.RenderTo(builder); Styling.RenderTo(builder); + EdgeStyling.RenderTo(builder); return builder.ToString(); } private string CreateNodeId() => "id" + Nodes.Count; + + private void AddRelation( + INode from, + INode to, + Link link, + string text, + int length, + string? edgeId = null) + { + if (length < 1) + throw new ArgumentException("Link length should be more or equal 1", nameof(length)); + if (edgeId is not null && string.IsNullOrWhiteSpace(edgeId)) + throw new ArgumentException("Edge id should not be empty", nameof(edgeId)); + + Relation relation = new(from, to, link, text, length, edgeId); + Relations.Add(relation); + } } diff --git a/src/FluentMermaid/Flowchart/Nodes/SubGraphNode.cs b/src/FluentMermaid/Flowchart/Nodes/SubGraphNode.cs index 493881b..1a7df94 100644 --- a/src/FluentMermaid/Flowchart/Nodes/SubGraphNode.cs +++ b/src/FluentMermaid/Flowchart/Nodes/SubGraphNode.cs @@ -1,4 +1,4 @@ -using System.Text; +using System.Text; using FluentMermaid.Enums; using FluentMermaid.Extensions; using FluentMermaid.Flowchart.Enum; @@ -6,7 +6,7 @@ namespace FluentMermaid.Flowchart.Nodes; -internal record SubGraphNode : ISubGraph +internal record SubGraphNode : IAdvancedSubGraph { public SubGraphNode( string id, @@ -24,9 +24,9 @@ public SubGraphNode( public Orientation Orientation { get; } - private HashSet Nodes { get; } = new(); + private List Nodes { get; } = new(); - private HashSet Relations { get; } = new(); + private List Relations { get; } = new(); public INode TextNode(string content, Shape shape) { @@ -42,6 +42,20 @@ public ISubGraph SubGraph(string title, Orientation orientation) return subgraph; } + public IAdvancedSubGraph AdvancedSubGraph(string title, Orientation orientation) + { + var subgraph = new SubGraphNode(CreateNodeId(), title, orientation); + Nodes.Add(subgraph); + return subgraph; + } + + public IAdvancedSubGraph AdvancedSubGraph(string id, string title, Orientation orientation) + { + var subgraph = new SubGraphNode(id, title, orientation); + Nodes.Add(subgraph); + return subgraph; + } + public void RenderTo(StringBuilder builder) { builder @@ -68,11 +82,87 @@ public void RenderTo(StringBuilder builder) private string CreateNodeId() => Id + "Sub" + Nodes.Count; public void Link(INode @from, INode to, Link link, string text, int length = 1) + => AddRelation(@from, to, link, text, length); + + public void Link(INode from, INode to, string edgeId, Link link, string text, int length = 1) + => AddRelation(from, to, link, text, length, edgeId); + + public INode TextNode(string content, string shapeAlias) + { + if (string.IsNullOrWhiteSpace(shapeAlias)) + throw new ArgumentException("Shape alias should not be null or empty", nameof(shapeAlias)); + + AdvancedTextNode textNode = new( + this, + CreateNodeId(), + new AdvancedTextNode.NodeAttribute("shape", shapeAlias), + new AdvancedTextNode.NodeAttribute("label", content, true)); + Nodes.Add(textNode); + return textNode; + } + + public INode IconNode(string icon, string? label = null, string? form = null, string? position = null, int? height = null) + { + if (string.IsNullOrWhiteSpace(icon)) + throw new ArgumentException("Icon should not be null or empty", nameof(icon)); + + var attrs = new List + { + new("icon", icon, true) + }; + if (!string.IsNullOrWhiteSpace(form)) + attrs.Add(new("form", form!, true)); + if (!string.IsNullOrWhiteSpace(label)) + attrs.Add(new("label", label!, true)); + if (!string.IsNullOrWhiteSpace(position)) + attrs.Add(new("pos", position!, true)); + if (height.HasValue) + attrs.Add(AdvancedTextNode.NodeAttribute.FromInt("h", height.Value)); + + AdvancedTextNode node = new(this, CreateNodeId(), attrs.ToArray()); + Nodes.Add(node); + return node; + } + + public INode ImageNode( + Uri imageUrl, + string? label = null, + string? position = null, + int? width = null, + int? height = null, + bool? constraint = null) + { + if (imageUrl is null) + throw new ArgumentNullException(nameof(imageUrl)); + + var attrs = new List + { + new("img", imageUrl.ToString(), true) + }; + if (!string.IsNullOrWhiteSpace(label)) + attrs.Add(new("label", label!, true)); + if (!string.IsNullOrWhiteSpace(position)) + attrs.Add(new("pos", position!, true)); + if (width.HasValue) + attrs.Add(AdvancedTextNode.NodeAttribute.FromInt("w", width.Value)); + if (height.HasValue) + attrs.Add(AdvancedTextNode.NodeAttribute.FromInt("h", height.Value)); + if (constraint.HasValue) + attrs.Add(new("constraint", constraint.Value ? "on" : "off", true)); + + AdvancedTextNode node = new(this, CreateNodeId(), attrs.ToArray()); + Nodes.Add(node); + return node; + } + + private void AddRelation(INode from, INode to, Link link, string text, int length, string? edgeId = null) { if (length < 1) throw new ArgumentException("Link length should be more or equal 1", nameof(length)); + if (edgeId is not null && string.IsNullOrWhiteSpace(edgeId)) + throw new ArgumentException("Edge id should not be empty", nameof(edgeId)); - Relation relation = new(from, to, link, text, length); + Relation relation = new(from, to, link, text, length, edgeId); Relations.Add(relation); } } \ No newline at end of file diff --git a/src/FluentMermaid/Flowchart/Relation.cs b/src/FluentMermaid/Flowchart/Relation.cs index 61c17d3..4da3b9b 100644 --- a/src/FluentMermaid/Flowchart/Relation.cs +++ b/src/FluentMermaid/Flowchart/Relation.cs @@ -1,4 +1,4 @@ -using System.Text; +using System.Text; using FluentMermaid.Extensions; using FluentMermaid.Flowchart.Enum; using FluentMermaid.Flowchart.Extensions; @@ -12,13 +12,15 @@ internal Relation( INode to, Link link, string text, - int length) + int length, + string? edgeId = null) { From = @from; To = to; Text = text; Length = length; Link = link; + EdgeId = edgeId; } public INode From { get; } @@ -31,12 +33,17 @@ internal Relation( public int Length { get; } + public string? EdgeId { get; } + public void RenderTo(StringBuilder builder) { builder .Append(From.Id) .Append(' '); + if (!string.IsNullOrWhiteSpace(EdgeId)) + builder.Append(EdgeId).Append('@'); + Link.RenderTo(builder, Length); builder.Append(' '); diff --git a/src/FluentMermaidLibrary.sln b/src/FluentMermaidLibrary.sln index 6be5685..6352d98 100644 --- a/src/FluentMermaidLibrary.sln +++ b/src/FluentMermaidLibrary.sln @@ -2,15 +2,44 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentMermaid", "FluentMermaid\FluentMermaid.csproj", "{557AD2F1-1C76-46F2-919E-D8AB7D599099}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentMermaid.Tests", "..\tests\FluentMermaid.Tests\FluentMermaid.Tests.csproj", "{D60C8DD9-CEF6-424A-973F-71AAAB770A0B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {557AD2F1-1C76-46F2-919E-D8AB7D599099}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {557AD2F1-1C76-46F2-919E-D8AB7D599099}.Debug|Any CPU.Build.0 = Debug|Any CPU + {557AD2F1-1C76-46F2-919E-D8AB7D599099}.Debug|x64.ActiveCfg = Debug|Any CPU + {557AD2F1-1C76-46F2-919E-D8AB7D599099}.Debug|x64.Build.0 = Debug|Any CPU + {557AD2F1-1C76-46F2-919E-D8AB7D599099}.Debug|x86.ActiveCfg = Debug|Any CPU + {557AD2F1-1C76-46F2-919E-D8AB7D599099}.Debug|x86.Build.0 = Debug|Any CPU {557AD2F1-1C76-46F2-919E-D8AB7D599099}.Release|Any CPU.ActiveCfg = Release|Any CPU {557AD2F1-1C76-46F2-919E-D8AB7D599099}.Release|Any CPU.Build.0 = Release|Any CPU + {557AD2F1-1C76-46F2-919E-D8AB7D599099}.Release|x64.ActiveCfg = Release|Any CPU + {557AD2F1-1C76-46F2-919E-D8AB7D599099}.Release|x64.Build.0 = Release|Any CPU + {557AD2F1-1C76-46F2-919E-D8AB7D599099}.Release|x86.ActiveCfg = Release|Any CPU + {557AD2F1-1C76-46F2-919E-D8AB7D599099}.Release|x86.Build.0 = Release|Any CPU + {D60C8DD9-CEF6-424A-973F-71AAAB770A0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D60C8DD9-CEF6-424A-973F-71AAAB770A0B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D60C8DD9-CEF6-424A-973F-71AAAB770A0B}.Debug|x64.ActiveCfg = Debug|Any CPU + {D60C8DD9-CEF6-424A-973F-71AAAB770A0B}.Debug|x64.Build.0 = Debug|Any CPU + {D60C8DD9-CEF6-424A-973F-71AAAB770A0B}.Debug|x86.ActiveCfg = Debug|Any CPU + {D60C8DD9-CEF6-424A-973F-71AAAB770A0B}.Debug|x86.Build.0 = Debug|Any CPU + {D60C8DD9-CEF6-424A-973F-71AAAB770A0B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D60C8DD9-CEF6-424A-973F-71AAAB770A0B}.Release|Any CPU.Build.0 = Release|Any CPU + {D60C8DD9-CEF6-424A-973F-71AAAB770A0B}.Release|x64.ActiveCfg = Release|Any CPU + {D60C8DD9-CEF6-424A-973F-71AAAB770A0B}.Release|x64.Build.0 = Release|Any CPU + {D60C8DD9-CEF6-424A-973F-71AAAB770A0B}.Release|x86.ActiveCfg = Release|Any CPU + {D60C8DD9-CEF6-424A-973F-71AAAB770A0B}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection EndGlobal diff --git a/tests/FluentMermaid.Tests/FlowchartRenderingTests.cs b/tests/FluentMermaid.Tests/FlowchartRenderingTests.cs new file mode 100644 index 0000000..5bdd550 --- /dev/null +++ b/tests/FluentMermaid.Tests/FlowchartRenderingTests.cs @@ -0,0 +1,90 @@ +using FluentMermaid.Enums; +using FluentMermaid.Flowchart; +using FluentMermaid.Flowchart.Enum; + +namespace FluentMermaid.Tests; + +public class FlowchartRenderingTests +{ + [Fact] + public void LinkRendering_UsesCurrentMermaidLengthRules() + { + var chart = FlowChart.Create(Orientation.LeftToRight); + var start = chart.TextNode("Start", Shape.Rectangle); + var end = chart.TextNode("End", Shape.Rectangle); + + chart.Link(start, end, Link.Thick, "", 1); + chart.Link(start, end, Link.Dotted, "", 2); + + string rendered = Normalize(chart.Render()); + + Assert.Contains("id0 ==> id1", rendered); + Assert.Contains("id0 -..- id1", rendered); + } + + [Fact] + public void LinkRendering_SupportsInvisibleAndDottedArrowLinks() + { + var chart = FlowChart.Create(Orientation.LeftToRight); + var a = chart.TextNode("A", Shape.Rectangle); + var b = chart.TextNode("B", Shape.Rectangle); + + chart.Link(a, b, Link.Invisible, "", 1); + chart.Link(a, b, Link.DottedArrow, "", 1); + + string rendered = Normalize(chart.Render()); + + Assert.Contains("id0 ~~~ id1", rendered); + Assert.Contains("id0 -.-> id1", rendered); + } + + [Fact] + public void AdvancedApi_RendersExpandedShapeSyntax() + { + var chart = FlowChart.CreateAdvanced(Orientation.LeftToRight); + chart.TextNode("Manual input", AdvancedShape.SlopedRectangle); + + string rendered = Normalize(chart.Render()); + + Assert.Contains("id0@{ shape: sl-rect, label: \"Manual input\" }", rendered); + } + + [Fact] + public void AdvancedApi_RendersIconAndImageNodes() + { + var chart = FlowChart.CreateAdvanced(Orientation.LeftToRight); + chart.IconNode("fa:user", "User Icon", "square", "t", 60); + chart.ImageNode(new Uri("https://example.com/image.png"), "Image Label", "t", 60, 60, false); + + string rendered = Normalize(chart.Render()); + + Assert.Contains("id0@{ icon: \"fa:user\", form: \"square\", label: \"User Icon\", pos: \"t\", h: 60 }", rendered); + Assert.Contains("id1@{ img: \"https://example.com/image.png\", label: \"Image Label\", pos: \"t\", w: 60, h: 60, constraint: \"off\" }", rendered); + } + + [Fact] + public void AdvancedApi_RendersEdgeIdAndEdgeProperties() + { + var chart = FlowChart.CreateAdvanced(Orientation.LeftToRight); + var a = chart.TextNode("A", Shape.Rectangle); + var b = chart.TextNode("B", Shape.Rectangle); + + chart.Link(a, b, "e1", Link.Arrow, "", 1); + chart.EdgeStyling.SetAnimated("e1"); + chart.EdgeStyling.SetAnimation("e1", EdgeAnimationSpeed.Fast); + chart.EdgeStyling.SetCurve("e1", EdgeCurve.Linear); + chart.EdgeStyling.SetClass("e1", "animate"); + chart.EdgeStyling.LinkStyle(0, "stroke:#ff3"); + chart.EdgeStyling.LinkStyleDefault("color:blue"); + + string rendered = Normalize(chart.Render()); + + Assert.Contains("id0 e1@--> id1", rendered); + Assert.Contains("e1@{ animate: true, animation: fast, curve: linear }", rendered); + Assert.Contains("class e1 animate", rendered); + Assert.Contains("linkStyle 0 stroke:#ff3;", rendered); + Assert.Contains("linkStyle default color:blue;", rendered); + } + + private static string Normalize(string input) => input.Replace("\r\n", "\n"); +} diff --git a/tests/FluentMermaid.Tests/FluentMermaid.Tests.csproj b/tests/FluentMermaid.Tests/FluentMermaid.Tests.csproj new file mode 100644 index 0000000..829cf53 --- /dev/null +++ b/tests/FluentMermaid.Tests/FluentMermaid.Tests.csproj @@ -0,0 +1,29 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/tests/FluentMermaid.Tests/GlobalUsings.cs b/tests/FluentMermaid.Tests/GlobalUsings.cs new file mode 100644 index 0000000..8c927eb --- /dev/null +++ b/tests/FluentMermaid.Tests/GlobalUsings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file From 03a481141cef6b363bd88f34247343d22993536f Mon Sep 17 00:00:00 2001 From: wowbios Date: Thu, 5 Mar 2026 15:27:25 +0300 Subject: [PATCH 2/2] workflow --- .github/workflows/codeql-analysis.yml | 20 +++++++++++++------- .github/workflows/dotnet.yml | 6 +++--- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index f5eec7e..a517cbd 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -38,11 +38,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -53,10 +53,16 @@ jobs: # queries: security-extended,security-and-quality - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + + - name: Restore dependencies + run: dotnet restore src/FluentMermaidLibrary.sln -nologo -v minimal + + - name: Build + run: dotnet build src/FluentMermaidLibrary.sln --no-restore -nologo -v minimal # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -69,4 +75,4 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 6b82d58..47bd354 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -21,8 +21,8 @@ jobs: with: dotnet-version: 8.0.x - name: Restore dependencies - run: dotnet restore src/FluentMermaidLibrary.sln + run: dotnet restore src/FluentMermaidLibrary.sln -nologo -v minimal - name: Build - run: dotnet build --no-restore src/FluentMermaidLibrary.sln + run: dotnet build --no-restore src/FluentMermaidLibrary.sln -nologo -v minimal - name: Test - run: dotnet test src/FluentMermaidLibrary.sln --no-build --verbosity normal + run: dotnet test src/FluentMermaidLibrary.sln --no-build -nologo -v minimal