Skip to content

Commit 5c29596

Browse files
Copilotjongalloway
andauthored
Address code review: extract magic numbers as named constants, improve variable names
Co-authored-by: jongalloway <68539+jongalloway@users.noreply.github.com> Agent-Logs-Url: https://github.com/jongalloway/DiagramForge/sessions/944314c7-50c9-4e41-9fb1-1781e58761f5
1 parent 69aa031 commit 5c29596

4 files changed

Lines changed: 38 additions & 20 deletions

File tree

src/DiagramForge/Layout/DefaultLayoutEngine.Wireframe.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,19 @@ public sealed partial class DefaultLayoutEngine
1212
private const double WireframeContainerPad = 12.0;
1313
private const double WireframeDefaultWidth = 320.0;
1414
private const double WireframeButtonHeight = 34.0;
15+
private const double WireframeButtonMinWidthRatio = 0.4; // fraction of DefaultWidth
16+
private const double WireframeButtonHPad = 32.0; // horizontal text padding in button
1517
private const double WireframeInputHeight = 32.0;
1618
private const double WireframeControlHeight = 22.0;
19+
private const double WireframeControlLabelGap = 8.0; // space between control and its label
20+
private const double WireframeControlMinWidth = 120.0; // minimum width for checkbox/radio
1721
private const double WireframeToggleWidth = 48.0;
1822
private const double WireframeToggleHeight = 24.0;
1923
private const double WireframeTabBarHeight = 38.0;
2024
private const double WireframeDividerHeight = 4.0;
2125
private const double WireframeBadgeHeight = 20.0;
26+
private const double WireframeBadgeMinWidth = 36.0; // minimum badge pill width
27+
private const double WireframeBadgeHPad = 16.0; // horizontal padding inside badge
2228
private const double WireframeImageHeight = 100.0;
2329
private const double WireframeImageWidth = 160.0;
2430
private const double WireframeH1FontSize = 20.0;
@@ -136,7 +142,7 @@ private static void SizeWireframeLeaf(Node node, Theme theme)
136142
case "button":
137143
{
138144
double textW = SvgRenderSupport.EstimateTextWidth(node.Label.Text, theme.FontSize);
139-
node.Width = Math.Max(WireframeDefaultWidth * 0.4, textW + 32);
145+
node.Width = Math.Max(WireframeDefaultWidth * WireframeButtonMinWidthRatio, textW + WireframeButtonHPad);
140146
node.Height = WireframeButtonHeight;
141147
break;
142148
}
@@ -149,15 +155,15 @@ private static void SizeWireframeLeaf(Node node, Theme theme)
149155
case "radio":
150156
{
151157
double textW = SvgRenderSupport.EstimateTextWidth(node.Label.Text, theme.FontSize);
152-
node.Width = Math.Max(120, WireframeControlHeight + 8 + textW);
158+
node.Width = Math.Max(WireframeControlMinWidth, WireframeControlHeight + WireframeControlLabelGap + textW);
153159
node.Height = WireframeControlHeight;
154160
break;
155161
}
156162
case "toggle":
157163
node.Width = WireframeToggleWidth
158164
+ (string.IsNullOrWhiteSpace(node.Label.Text)
159165
? 0
160-
: 8 + SvgRenderSupport.EstimateTextWidth(node.Label.Text, theme.FontSize));
166+
: WireframeControlLabelGap + SvgRenderSupport.EstimateTextWidth(node.Label.Text, theme.FontSize));
161167
node.Height = WireframeToggleHeight;
162168
break;
163169

@@ -175,7 +181,7 @@ private static void SizeWireframeLeaf(Node node, Theme theme)
175181
{
176182
double badgeFontSize = theme.FontSize * 0.8;
177183
double textW = SvgRenderSupport.EstimateTextWidth(node.Label.Text, badgeFontSize);
178-
node.Width = Math.Max(36, textW + 16);
184+
node.Width = Math.Max(WireframeBadgeMinWidth, textW + WireframeBadgeHPad);
179185
node.Height = WireframeBadgeHeight;
180186
break;
181187
}

src/DiagramForge/Parsers/Wireframe/WireframeDslParser.cs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -290,8 +290,12 @@ private static bool IsContainerEnd(string line)
290290
if (string.IsNullOrEmpty(text))
291291
return null;
292292

293-
// Strip **bold** markers for label text (bold styling comes from wireframe:bold metadata)
294-
bool isBold = text.StartsWith("**", StringComparison.Ordinal) && text.EndsWith("**", StringComparison.Ordinal) && text.Length > 4;
293+
// Strip **bold** markers for label text (bold styling comes from wireframe:bold metadata).
294+
// Minimum: "**x**" = 5 chars: 2 open markers + 1 body char + 2 close markers.
295+
const int BoldWrapperLength = 4; // "**" prefix + "**" suffix
296+
bool isBold = text.StartsWith("**", StringComparison.Ordinal)
297+
&& text.EndsWith("**", StringComparison.Ordinal)
298+
&& text.Length > BoldWrapperLength;
295299
if (isBold)
296300
text = text[2..^2].Trim();
297301

@@ -304,20 +308,27 @@ private static bool IsContainerEnd(string line)
304308

305309
private static Node? ParseBracketComponent(string line, string nodeId)
306310
{
307-
// [on] / [off] → Toggle
308-
if (string.Equals(line, "[on]", StringComparison.OrdinalIgnoreCase)
309-
|| (line.Length > 4 && string.Equals(line[..4], "[on]", StringComparison.OrdinalIgnoreCase) && line[4] == ' '))
311+
// [on] / [off] → Toggle (case-insensitive, optional trailing label)
312+
const string OnToken = "[on]";
313+
const string OffToken = "[off]";
314+
315+
if (string.Equals(line, OnToken, StringComparison.OrdinalIgnoreCase)
316+
|| (line.Length > OnToken.Length
317+
&& string.Equals(line[..OnToken.Length], OnToken, StringComparison.OrdinalIgnoreCase)
318+
&& line[OnToken.Length] == ' '))
310319
{
311-
var label = line.Length > 5 ? line[5..].Trim() : string.Empty;
320+
var label = line.Length > OnToken.Length + 1 ? line[(OnToken.Length + 1)..].Trim() : string.Empty;
312321
var n = new Node(nodeId, label);
313322
n.Metadata["wireframe:kind"] = "toggle";
314323
n.Metadata["wireframe:on"] = true;
315324
return n;
316325
}
317-
if (string.Equals(line, "[off]", StringComparison.OrdinalIgnoreCase)
318-
|| (line.Length > 5 && string.Equals(line[..5], "[off]", StringComparison.OrdinalIgnoreCase) && line[5] == ' '))
326+
if (string.Equals(line, OffToken, StringComparison.OrdinalIgnoreCase)
327+
|| (line.Length > OffToken.Length
328+
&& string.Equals(line[..OffToken.Length], OffToken, StringComparison.OrdinalIgnoreCase)
329+
&& line[OffToken.Length] == ' '))
319330
{
320-
var label = line.Length > 6 ? line[6..].Trim() : string.Empty;
331+
var label = line.Length > OffToken.Length + 1 ? line[(OffToken.Length + 1)..].Trim() : string.Empty;
321332
var n = new Node(nodeId, label);
322333
n.Metadata["wireframe:kind"] = "toggle";
323334
n.Metadata["wireframe:on"] = false;

src/DiagramForge/Rendering/SvgNodeWriter.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,8 @@ private static void AppendClassNode(
765765
private const string WfCheckColor = "#2A2A2A";
766766
private const double WfStroke = 1.2;
767767
private const double WfRadius = 4.0;
768+
private const double WfCheckmarkInsetRatio = 0.2; // relative inset for tick path endpoints
769+
private const double WfDropdownChevronSize = 4.5; // half-width of the dropdown chevron arrow
768770

769771
private static void AppendWireframeNode(StringBuilder sb, Node node, string kind, Theme theme)
770772
{
@@ -910,9 +912,9 @@ private static void AppendWfCheckbox(StringBuilder sb, Node node, Theme theme)
910912
{
911913
double cx = boxSize / 2;
912914
double cy = topY + boxSize / 2;
913-
// Checkmark tick: two-segment path
914-
double t = boxSize * 0.2;
915-
sb.AppendLine($""" <polyline points="{SvgRenderSupport.F(t)},{SvgRenderSupport.F(cy)} {SvgRenderSupport.F(cx * 0.75)},{SvgRenderSupport.F(topY + boxSize - t)} {SvgRenderSupport.F(boxSize - t)},{SvgRenderSupport.F(topY + t)}" fill="none" stroke="{SvgRenderSupport.Escape(WfCheckColor)}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>""");
915+
// Checkmark tick: two-segment polyline (left-bottom valley → right-top peak)
916+
double inset = boxSize * WfCheckmarkInsetRatio;
917+
sb.AppendLine($""" <polyline points="{SvgRenderSupport.F(inset)},{SvgRenderSupport.F(cy)} {SvgRenderSupport.F(cx * 0.75)},{SvgRenderSupport.F(topY + boxSize - inset)} {SvgRenderSupport.F(boxSize - inset)},{SvgRenderSupport.F(topY + inset)}" fill="none" stroke="{SvgRenderSupport.Escape(WfCheckColor)}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>""");
916918
}
917919

918920
if (!string.IsNullOrWhiteSpace(node.Label.Text))
@@ -989,8 +991,7 @@ private static void AppendWfDropdown(StringBuilder sb, Node node, Theme theme)
989991
// Chevron icon on the right
990992
double chevX = node.Width - 18;
991993
double chevY = node.Height / 2;
992-
double chevS = 4.5;
993-
sb.AppendLine($""" <polyline points="{SvgRenderSupport.F(chevX - chevS)},{SvgRenderSupport.F(chevY - chevS * 0.6)} {SvgRenderSupport.F(chevX)},{SvgRenderSupport.F(chevY + chevS * 0.6)} {SvgRenderSupport.F(chevX + chevS)},{SvgRenderSupport.F(chevY - chevS * 0.6)}" fill="none" stroke="{SvgRenderSupport.Escape(WfSubtleText)}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>""");
994+
sb.AppendLine($""" <polyline points="{SvgRenderSupport.F(chevX - WfDropdownChevronSize)},{SvgRenderSupport.F(chevY - WfDropdownChevronSize * 0.6)} {SvgRenderSupport.F(chevX)},{SvgRenderSupport.F(chevY + WfDropdownChevronSize * 0.6)} {SvgRenderSupport.F(chevX + WfDropdownChevronSize)},{SvgRenderSupport.F(chevY - WfDropdownChevronSize * 0.6)}" fill="none" stroke="{SvgRenderSupport.Escape(WfSubtleText)}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>""");
994995

995996
// Vertical separator line before chevron
996997
sb.AppendLine($""" <line x1="{SvgRenderSupport.F(node.Width - 28)}" y1="5" x2="{SvgRenderSupport.F(node.Width - 28)}" y2="{SvgRenderSupport.F(node.Height - 5)}" stroke="{SvgRenderSupport.Escape(WfInputBorder)}" stroke-width="0.8"/>""");

src/DiagramForge/Rendering/SvgRenderer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ int GetGroupDepth(Group group, HashSet<string>? visiting = null)
128128
foreach (var edge in diagram.Edges)
129129
{
130130
// Wireframe containment edges are layout-only; they must not produce visible SVG.
131-
if (edge.Metadata.TryGetValue("wireframe:containment", out var wfc) && wfc is true)
131+
if (edge.Metadata.TryGetValue("wireframe:containment", out var isWireframeContainment) && isWireframeContainment is true)
132132
continue;
133133

134134
if (!diagram.Nodes.TryGetValue(edge.SourceId, out var source)
@@ -148,7 +148,7 @@ int GetGroupDepth(Group group, HashSet<string>? visiting = null)
148148
foreach (var edge in diagram.Edges)
149149
{
150150
// Wireframe containment edges are layout-only; they must not produce visible SVG.
151-
if (edge.Metadata.TryGetValue("wireframe:containment", out var wfc2) && wfc2 is true)
151+
if (edge.Metadata.TryGetValue("wireframe:containment", out var isWireframeContainmentOverlay) && isWireframeContainmentOverlay is true)
152152
continue;
153153

154154
if (!diagram.Nodes.TryGetValue(edge.SourceId, out var source)

0 commit comments

Comments
 (0)