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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions src/Mermaid.Flowcharts/Flowchart.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using System.Text;
using System.Runtime.CompilerServices;
using Mermaid.Flowcharts.Links;
using Mermaid.Flowcharts.Nodes;
using Mermaid.Flowcharts.Styling;
using Mermaid.Flowcharts.Subgraphs;

[assembly: InternalsVisibleTo("Mermaid.Flowcharts.Tests")]
namespace Mermaid.Flowcharts;

public class Flowchart : IMermaidPrintable
Expand Down
9 changes: 3 additions & 6 deletions src/Mermaid.Flowcharts/Links/LinkText.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,9 @@ public LinkText() { }
private LinkText(NonEmptyString text)
=> Value = text;

public static LinkText FromString(string value)
public static LinkText FromString(string text)
{
if (string.IsNullOrWhiteSpace(value))
{
return new(value);
}
NonEmptyString value = NonEmptyString.FromString(text);

// Split on all variations of <br> tags
string[] segments = MermaidAcceptedHtmlLineBreaks.Split(value.ReplaceLineEndings());
Expand Down Expand Up @@ -61,7 +58,7 @@ public static LinkText FromString(string value)
}
}

return new(builder.ToString());
return new(NonEmptyString.FromString(builder.ToString()));
}

public override string ToString()
Expand Down
4 changes: 4 additions & 0 deletions src/Mermaid.Flowcharts/Mermaid.Flowcharts.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,8 @@
<None Include="../../README.md" Pack="true" PackagePath="" />
</ItemGroup>

<ItemGroup>
<InternalsVisibleTo Include="Mermaid.Flowcharts.Tests" />
</ItemGroup>

</Project>
10 changes: 3 additions & 7 deletions src/Mermaid.Flowcharts/Nodes/NodeText/MarkdownText.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,11 @@ private MarkdownText(NonEmptyString text)

public static MarkdownText FromString(string text)
{
if (string.IsNullOrWhiteSpace(text))
{
return new(text);
}
NonEmptyString nonEmpty = NonEmptyString.FromString(text);

NonEmptyString nonEmpty = text;
StringBuilder builder = new();
builder.Append('`');
foreach (char character in (string)nonEmpty)
foreach (char character in nonEmpty.AsSpan())
{
if (EscapedCharacters.TryGetValue(character, out string? escapedValue))
{
Expand All @@ -43,7 +39,7 @@ public static MarkdownText FromString(string text)
}
}
builder.Append('`');
return new MarkdownText(builder.ToString());
return new(NonEmptyString.FromString(builder.ToString()));
}

public override string ToString()
Expand Down
7 changes: 4 additions & 3 deletions src/Mermaid.Flowcharts/Nodes/NodeText/MermaidUnicodeText.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ private MermaidUnicodeText(NonEmptySingleLineString text)

public static MermaidUnicodeText FromString(string text)
{
NonEmptySingleLineString nonEmptySingleLine = text;
NonEmptySingleLineString nonEmptySingleLine = NonEmptySingleLineString.FromString(text);

StringBuilder builder = new();
foreach (char character in (string)nonEmptySingleLine)
foreach (char character in nonEmptySingleLine.AsSpan())
{
if (EscapedCharacters.TryGetValue(character, out string? escapedValue))
{
Expand All @@ -42,7 +43,7 @@ public static MermaidUnicodeText FromString(string text)
builder.Append(character);
}
}
return new MermaidUnicodeText(builder.ToString());
return new(NonEmptySingleLineString.FromString(builder.ToString()));
}

public override string ToString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,42 @@

namespace Mermaid.Flowcharts.NonEmptyStringTypes;

public readonly record struct NonEmptySingleLineString
internal readonly record struct NonEmptySingleLineString
{
public static readonly SearchValues<char> NewLineSearchValues = SearchValues.Create("\n\r\u2028\u2029\u0085");
public NonEmptyString Value { get; }

public NonEmptySingleLineString(NonEmptyString value)
[Obsolete(error: true, message: $"Please use the factory methods instead of the default constructor to create a new {nameof(NonEmptySingleLineString)}.")]
#pragma warning disable CS8618 // This constructor is never used
public NonEmptySingleLineString() { }
#pragma warning restore CS8618
private NonEmptySingleLineString(NonEmptyString value)
{
if (value.Value.AsSpan().IndexOfAny(NewLineSearchValues) > -1)
Value = value;
}

public static NonEmptySingleLineString FromString(string value)
{
NonEmptyString nonEmpty = NonEmptyString.FromString(value);

if (nonEmpty.AsSpan().IndexOfAny(NewLineSearchValues) > -1)
{
throw new ArgumentException("Non-empty single line string must not contain any newline characters or carriage returns.", nameof(value));
}

Value = value;
return new(nonEmpty);
}

public ReadOnlySpan<char> AsSpan()
=> Value.AsSpan();

public bool Contains(char value)
=> Value.Contains(value);

public NonEmptySingleLineString Trim()
=> FromString(Value.Trim());

public static implicit operator string(NonEmptySingleLineString nesls) => nesls.Value;
public static implicit operator NonEmptySingleLineString(string s) => new(s);

public override string ToString()
=> Value;
Expand Down
32 changes: 27 additions & 5 deletions src/Mermaid.Flowcharts/NonEmptyStringTypes/NonEmptyString.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,44 @@
namespace Mermaid.Flowcharts.NonEmptyStringTypes;

public readonly record struct NonEmptyString
internal readonly record struct NonEmptyString
{
public string Value { get; }
private readonly string _value;
public string Value => _value ?? throw new InvalidOperationException($"{nameof(NonEmptyString)} value must never be null. Make sure you use the {nameof(FromString)} factory method to construct a new {nameof(NonEmptyString)}.");

public NonEmptyString(string value)
[Obsolete(error: true, message: $"Please use the factory methods instead of the default constructor to create a new {nameof(NonEmptyString)}.")]
#pragma warning disable CS8618 // This constructor is never used
public NonEmptyString() { }
#pragma warning restore CS8618
private NonEmptyString(string value)
{
_value = value;
}

public static NonEmptyString FromString(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("Non-empty string must not be null or empty or whitespace.", nameof(value));
}

Value = value;
return new(value);
}

public ReadOnlySpan<char> AsSpan()
=> Value.AsSpan();

public bool Contains(char value)
=> Value.Contains(value);

public NonEmptyString ReplaceLineEndings(string replacementText = "\n")
=> FromString(Value.ReplaceLineEndings(replacementText));

public NonEmptyString Trim()
=> FromString(Value.Trim());

public static implicit operator string(NonEmptyString nes) => nes.Value;
public static implicit operator NonEmptyString(string s) => new(s);

public override string ToString()
=> Value;
}

21 changes: 15 additions & 6 deletions src/Mermaid.Flowcharts/Numerical/Percentage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,30 @@ namespace Mermaid.Flowcharts.Numerical;
{
public double Value { get; }

public Percentage(double value)
[Obsolete(error: true, message: $"Please use the factory methods instead of the default constructor to create a new {nameof(Percentage)}.")]
#pragma warning disable CS8618 // This constructor is never used
public Percentage() { }
#pragma warning restore CS8618
private Percentage(double value)
{
Value = value;
}

public static Percentage FromDouble(double value)
{
if (double.IsNaN(value) || double.IsInfinity(value))
{
throw new ArgumentOutOfRangeException(nameof(value), "Percentage must be a real and finite number.");
}

ArgumentOutOfRangeException.ThrowIfLessThan(value, 0.0, "Percentage must not be negative.");
if (value < 0.0)
{
throw new ArgumentOutOfRangeException(nameof(value), "Percentage must not be negative.");
}

Value = value;
return new(value);
}

public static implicit operator Percentage(double value)
=> new(value);

public string ToNumericalString()
=> $"{Value.ToNumberString()}%";
}
28 changes: 20 additions & 8 deletions src/Mermaid.Flowcharts/Numerical/UnitInterval.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,34 @@ namespace Mermaid.Flowcharts.Numerical;
{
public double Value { get; }

public UnitInterval(double value)
[Obsolete(error: true, message: $"Please use the factory method instead of the default constructor to create a new {nameof(UnitInterval)}.")]
#pragma warning disable CS8618 // This constructor is never used
public UnitInterval() { }
#pragma warning restore CS8618
private UnitInterval(double value)
{
Value = value;
}

public static UnitInterval FromDouble(double value)
{
if (double.IsNaN(value) || double.IsInfinity(value))
{
throw new ArgumentOutOfRangeException(nameof(value), "Unit interval must be a real number between 0 and 1.");
}

ArgumentOutOfRangeException.ThrowIfLessThan(value, 0.0, "Unit interval should be at least 0.");
ArgumentOutOfRangeException.ThrowIfGreaterThan(value, 1.0, "Unit interval should be at most 1.");

Value = value;
}
if (value < 0.0)
{
throw new ArgumentOutOfRangeException(nameof(value), "Unit interval should be at least 0.");
}

public static implicit operator UnitInterval(double value)
=> new(value);
if (value > 1.0)
{
throw new ArgumentOutOfRangeException(nameof(value), "Unit interval should be at most 1.");
}

return new(value);
}

public string ToNumericalString()
=> Value.ToNumberString();
Expand Down
2 changes: 1 addition & 1 deletion src/Mermaid.Flowcharts/StringExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Mermaid.Flowcharts;

public static class StringExtensions
internal static class StringExtensions
{
public static string Repeat(this string text, int count)
{
Expand Down
5 changes: 3 additions & 2 deletions src/Mermaid.Flowcharts/Styling/Attributes/Color.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ public readonly record struct Color(byte Red, byte Green, byte Blue) : ICssAttri
public static Color FromRGB(byte red, byte green, byte blue)
=> new(red, green, blue);

public static Color FromHex(NonEmptySingleLineString hex)
public static Color FromHex(string hex)
{
string s = ((string)hex).Trim();
NonEmptySingleLineString nes = NonEmptySingleLineString.FromString(hex);
string s = nes.Trim();
if (s.Length == 0)
{
throw new ArgumentException("Hex color must not be empty or whitespace.", nameof(hex));
Expand Down
2 changes: 1 addition & 1 deletion src/Mermaid.Flowcharts/Styling/Attributes/DashOffset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public NumericalDashOffset(double size)
}

public static LengthDashOffset Length(double size, Unit unit) => new(size, unit);
public static PercentageDashOffset Percentage(Percentage percentageOffset) => new(percentageOffset);
public static PercentageDashOffset Percentage(double percentageOffset) => new(Numerical.Percentage.FromDouble(percentageOffset));
public static NumericalDashOffset Number(double size) => new(size);

public string ToMermaidString()
Expand Down
2 changes: 1 addition & 1 deletion src/Mermaid.Flowcharts/Styling/Attributes/DashSize.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public NumericalDashSize(double size)
}

public static LengthDashSize Length(double size, Unit unit) => new(size, unit);
public static PercentageDashSize Percentage(Percentage percentageSize) => new(percentageSize);
public static PercentageDashSize Percentage(double percentageSize) => new(Numerical.Percentage.FromDouble(percentageSize));
public static NumericalDashSize Number(double size) => new(size);

public string ToMermaidString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,22 @@ namespace Mermaid.Flowcharts.Styling.Attributes.Fonts;

public partial record FontFamilyComponent
{
public NonEmptySingleLineString Value { get; }
public string Value { get; }

public FontFamilyComponent(NonEmptySingleLineString value)
public FontFamilyComponent(string name)
{
if (((string)value).Contains('"') || ((string)value).Contains('\''))
NonEmptySingleLineString nes = NonEmptySingleLineString.FromString(name);
if (nes.Contains('"') || nes.Contains('\''))
{
throw new ArgumentException("Font family component must not contain single or double quotes.", nameof(value));
throw new ArgumentException("Font family component must not contain single or double quotes.", nameof(name));
}

if (!SpaceOrHyphenSeparatedWordsRegex().IsMatch(value))
if (!SpaceOrHyphenSeparatedWordsRegex().IsMatch(nes.AsSpan()))
{
throw new ArgumentException("Font family component must only contain words that are separated by at most one space.", nameof(value));
throw new ArgumentException("Font family component must only contain words that are separated by at most one space.", nameof(name));
}

Value = value;
Value = nes;
}

[GeneratedRegex("^[a-zA-Z]+([ -][a-zA-Z]+)*$")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public LengthFontSize(double size, Unit unit)

public static AbsoluteFontSize Absolute(AbsoluteSize size) => new(size);
public static RelativeFontSize Relative(RelativeSize size) => new(size);
public static PercentageFontSize Percentage(Percentage sizePercentage) => new(sizePercentage);
public static PercentageFontSize Percentage(double sizePercentage) => new(Numerical.Percentage.FromDouble(sizePercentage));
public static LengthFontSize Length(double size, Unit unit) => new(size, unit);

public string ToMermaidString()
Expand Down
19 changes: 13 additions & 6 deletions src/Mermaid.Flowcharts/Styling/Attributes/Opacity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,18 @@ namespace Mermaid.Flowcharts.Styling.Attributes;

public readonly record struct Opacity : ICssAttribute
{
public double Value { get; }
public UnitInterval Interval { get; }

public Opacity(double value)
[Obsolete(error: true, message: $"Please use the factory methods instead of the default constructor to create a new {nameof(Opacity)}.")]
#pragma warning disable CS8618 // This constructor is never used
public Opacity() { }
#pragma warning restore CS8618
private Opacity(UnitInterval value)
{
Interval = value;
}

public static Opacity FromDouble(double value)
{
if (double.IsNaN(value))
{
Expand All @@ -24,11 +33,9 @@ public Opacity(double value)
throw new ArgumentOutOfRangeException(nameof(value), "Opacity must not be greater than 1.");
}

Value = value;
return new(UnitInterval.FromDouble(value));
}

public static implicit operator Opacity(double value) => new(value);

public string ToCss()
=> Value.ToNumberString();
=> Interval.Value.ToNumberString();
}
2 changes: 1 addition & 1 deletion src/Mermaid.Flowcharts/Styling/Attributes/StrokeWidth.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public NumericalStrokeWidth(double width)
}

public static LengthStrokeWidth Length(double width, Unit unit) => new(width, unit);
public static PercentageStrokeWidth Percentage(Percentage percentageWidth) => new(percentageWidth);
public static PercentageStrokeWidth Percentage(double percentageWidth) => new(Numerical.Percentage.FromDouble(percentageWidth));
public static NumericalStrokeWidth Number(double width) => new(width);

public string ToMermaidString()
Expand Down
Loading