refactor(dedup): share TruncateText across Markdown generators

`TruncateText` was copy-pasted verbatim in three Markdown generators
(`SqlServer.QueryBreakdownGenerator`, `SqlServer.SqlStatementGenerator`,
`Expressions.ExpressionGenerator`). Pulled out to a new
`Strata.SqlTools.Markdown.Internal.MarkdownTextHelpers` static class
(internal — no public-API change).

Each call site keeps its own one-line private wrapper for source
readability so existing `TruncateText(...)` calls in the generators
need no edits.

Deliberately *not* unified across the same three files:
- `EscapeMermaidText` (QueryBreakdownGenerator) vs `EscapeMermaidText`
  (SqlStatementGenerator) — the QBG version intentionally escapes
  `[]{}()` for Mermaid node syntax; the SSG version only escapes
  quotes/newlines because it writes into `Note right of DB: ...`
  contexts where brackets render fine.
- `EscapeMarkdown` (ExpressionGenerator) — a different escape set
  again, targeting Markdown rather than Mermaid.

Also deliberately *not* refactored: `SqlServer.UpdateBreakdown.TryParse`
≡ `SqlServer.ProcedureBreakdown.TryParse` prelude (empty-check +
parser + prefix regex + extract setup/finish clauses). The 30-line
duplication is real, but every extraction shape (tuple return,
`out`-flavored helper, context type) is measurably worse than the
duplicated original. Leaving it.

All 1180 tests stay green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Thom Lamb
2026-05-27 16:24:51 -05:00
co-authored by Claude Opus 4.7
parent d4b66838b5
commit 4b5348c53a
4 changed files with 24 additions and 29 deletions
@@ -361,13 +361,7 @@ public class ExpressionGenerator : IVisitor<string>
}
private static string TruncateText(string text, int maxLength)
{
if (string.IsNullOrWhiteSpace(text) || text.Length <= maxLength)
{
return text;
}
return string.Concat(text.AsSpan(0, maxLength), "...");
}
=> Internal.MarkdownTextHelpers.TruncateText(text, maxLength);
#region IVisitor Implementation
@@ -0,0 +1,21 @@
namespace Strata.SqlTools.Markdown.Internal;
/// <summary>
/// Small text utilities shared by the Markdown generators.
/// Kept <c>internal</c> so they don't widen the public surface of this assembly.
/// </summary>
internal static class MarkdownTextHelpers
{
/// <summary>
/// Truncates a string to <paramref name="maxLength"/> characters, appending an ellipsis when truncated.
/// Returns the input unchanged when null/whitespace or already short enough.
/// </summary>
public static string TruncateText(string text, int maxLength)
{
if (string.IsNullOrWhiteSpace(text) || text.Length <= maxLength)
{
return text;
}
return string.Concat(text.AsSpan(0, maxLength), "...");
}
}
@@ -191,17 +191,7 @@ public static class QueryBreakdownGenerator
.Replace(">", "&gt;");
}
/// <summary>
/// Truncates text to a maximum length and adds ellipsis if needed.
/// </summary>
private static string TruncateText(string text, int maxLength)
{
if (string.IsNullOrWhiteSpace(text) || text.Length <= maxLength)
{
return text;
}
return string.Concat(text.AsSpan(0, maxLength), "...");
}
=> Internal.MarkdownTextHelpers.TruncateText(text, maxLength);
}
@@ -112,18 +112,8 @@ public static class SqlStatementGenerator
.Replace("\r", "");
}
/// <summary>
/// Truncates text to a maximum length.
/// </summary>
private static string TruncateText(string text, int maxLength)
{
if (string.IsNullOrWhiteSpace(text) || text.Length <= maxLength)
{
return text;
}
return string.Concat(text.AsSpan(0, maxLength), "...");
}
=> Internal.MarkdownTextHelpers.TruncateText(text, maxLength);
/// <summary>
/// Cleans table name for use in Mermaid diagrams.