fix: quote flowchart labels with nested square brackets (#21) - #23
Conversation
A rectangle node label whose text contains a '[' — e.g. `Vosk[return []]` — breaks Mermaid's flowchart lexer: it reads the inner '[' as a new shape token and aborts the whole diagram (`got 'SQS'`). sanitize() now scans flowchart blocks for rectangle labels, walks to the balanced closing ']', and quotes any label containing a square bracket (`Vosk["return []"]`). The scan is quote-aware and shape-aware, so it leaves stadium `([...])`, parallelogram `[/.../]`, cylinder `[(...)]`, subroutine `[[...]]`, trapezoid `[/...\]`, and already-quoted labels untouched, and is idempotent on its own output. Regression coverage: invalid fixture fails the real Mermaid parser as-is and parses after sanitize(); a valid fixture exercises all five shape families end-to-end. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Greptile SummaryThis PR fixes a Mermaid render failure (issue #21) where a rectangle node label containing a
Confidence Score: 5/5Safe to merge — the transform is strictly additive, scoped to mermaid fences, and the balanced-bracket scanner correctly handles the targeted rectangle-node case. The change is a narrow, well-tested text transform inside a single function. All previously passing behaviour is guarded by regression tests, the new quoting path has thorough unit and real-parser coverage, and the fix is idempotent. The one identified edge case (non-rect shapes with deeply nested word+bracket patterns in their labels) is very unlikely to appear in real diagrams and does not affect the correctness of the targeted fix. iago/scripts/sanitize.ts — specifically the inner-shape-label boundary in Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
Input[sanitize src] --> FenceMatch[Match mermaid fences]
FenceMatch --> RewriteBlock[rewriteBlock body]
RewriteBlock --> DetectType{isFlow?}
DetectType -- yes --> QBL[quoteBracketedLabels per line]
QBL --> ScanChar{scan char}
ScanChar -- quote char --> ToggleQuote[toggle inQuote]
ToggleQuote --> ScanChar
ScanChar -- rect open bracket --> WalkBalanced[walk to balanced closing bracket]
WalkBalanced -- inner has bracket no quotes --> WrapQuotes[emit quoted label]
WalkBalanced -- else --> PassThrough[emit bracket as-is]
WrapQuotes --> ScanChar
PassThrough --> ScanChar
ScanChar -- not rect open --> EmitChar[emit char as-is]
EmitChar --> ScanChar
ScanChar -- end of line --> LeadingAt[replace LEADING AT regex]
DetectType -- no --> MsgReplace[replace semicolons in sequence messages]
LeadingAt --> Output[rewritten line]
MsgReplace --> Output
Reviews (2): Last reviewed commit: "test: pin combined leading-@ + nested-br..." | Re-trigger Greptile |
Guards the two-pass ordering (quoteBracketedLabels before LEADING_AT): `N[@utils[0]]` must become `N["@utils[0]"]`. LEADING_AT alone would stop at the first `]` and leave the still-broken `N["@utils[0"]]`; quoting the whole label first makes LEADING_AT a no-op. Pins behaviour against a future reordering of the two transforms (Greptile review on PR #23). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Quote flowchart node labels containing nested square brackets so the Mermaid lexer no longer aborts the whole diagram on `id[return []]`-style labels (#21, #23). Version bumped across cli/package.json, plugin.json, and marketplace.json (both fields). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🗺️ Change diagram — flowAuto-generated by iago. Edit or remove this block; it will be replaced on the next run. flowchart TD
Start([Mermaid block]) --> Type{Flowchart or graph?}
Type -- no --> Preserve[Keep existing sanitizer behavior]
Type -- yes --> Scan[Scan each line]
Scan --> Shape{Plain rectangle label?}
Shape -- no --> Next[Continue]
Shape -- yes --> Balanced{Balanced nested brackets?}
Balanced -- no --> Preserve
Balanced -- yes --> Quote[Wrap label text in quotes]
Quote --> LeadingAt[Apply existing leading-at repair]
Preserve --> Next
LeadingAt --> Next
Next --> Output([Valid Mermaid diagram])
|
Closes #21.
Problem
A flowchart rectangle node label whose text contains a
[— e.g.Vosk[return []]— breaks Mermaid's lexer: the inner[is read as a new shape token and the whole diagram fails to render (got 'SQS').flowchart TD G2P -- yes --> Vosk["return []"]Fix
sanitize()gains a quote-aware, shape-aware scan (quoteBracketedLabels) for flowchart/graph blocks: it findsid[…]rectangle labels, walks to the balanced closing](so nesting likearr[0]is handled), and wraps any label containing a square bracket in quotes →Vosk["return []"].It deliberately leaves untouched:
([…]), parallelogram[/…/], cylinder[(…)], subroutine[[…]], trapezoid[/…\][inside an existing quoted span — so the pass is idempotent on its own outputThis sits alongside the existing
;→,(sequence) and leading-@(flowchart) repairs; scope is still strictly inside```mermaidfences.Tests
cli/tests/sanitize.test.ts: nested-bracket quoting, non-empty index (arr[0]), all five shape families left untouched, already-quoted no-op, no re-quote inside quoted labels, idempotence, CRLF.cli/tests/mermaid-validation.test.ts): the issue's diagram verbatim asinvalid/nested-square-bracket-label.mmd(fails to parse as-is, parses aftersanitize()), plusvalid/fixtures for the quoted result and an all-shapes preservation case.Verification (full CI parity):
bun test→ 91 pass,bun run typecheckclean,bun run buildok,claude plugin validate . --strictpasses.