Skip to content

fix(c4): allow '#' in title and accDescription - #8039

Open
filipsajdak wants to merge 2 commits into
mermaid-js:developfrom
filipsajdak:bug/8030_c4-title-hash
Open

filipsajdak wants to merge 2 commits into
mermaid-js:developfrom
filipsajdak:bug/8030_c4-title-hash

Conversation

@filipsajdak

@filipsajdak filipsajdak commented Aug 7, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

A # anywhere in a C4 title breaks the whole diagram:

C4Context
title Relationship to a boundary (#4864)
Person(customerA, "Banking Customer A")
Lexical error on line 2. Unrecognized text.

accDescription has the same defect.

Cause

c4Diagram.jison matched both values with [^#\n;]+:

"title"\s[^#\n;]+                         return 'title';
"accDescription"\s[^#\n;]+                return 'accDescription';

The # in the character class ends the token early, and the remainder of the line then fails to lex. C4's comment syntax is %%, with its own \%\% lexer rules, and the grammar has no # comment rule at all, so nothing depends on that exclusion.

Verified through mermaid.parse, so the same preprocessing as the render path:

input before after
title Relationship to a boundary (#4864) Lexical error parses
title Relationship to a boundary parses parses
accDescription covers issue #4864 Lexical error parses
accTitle: covers #4864 parses parses

accTitle: / accDescr: use different lexer rules and were already unaffected. This also looks C4-specific: sequenceDiagram accepts a # in its title despite carrying a similar-looking exclusion.

Change

Drop # from the two character classes. \n and ; still terminate the value, so nothing else about the rules changes. Two parser tests cover a # in each.

Found while adding the Cypress case @pbrolin47 asked for in #7874, where a (#4864) in the test's own title was what made that test fail.

Fixes #8030

Summary

  • Allow # characters in C4 title and accDescription values.
  • Preserve newline and semicolon termination behavior.
  • Add parser tests for both value types.
  • Add a Mermaid patch changeset.

@netlify

netlify Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for mermaid-js ready!

Name Link
🔨 Latest commit 0e8cfbf
🔍 Latest deploy log https://app.netlify.com/projects/mermaid-js/deploys/6ad128c1da2553621fcde577
😎 Deploy Preview https://deploy-preview-8039--mermaid-js.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@changeset-bot

changeset-bot Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 0e8cfbf

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
mermaid Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added the Type: Bug / Error Something isn't working or is incorrect label Aug 7, 2026
@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

We couldn't safely recover the incremental review. No full review was started, and the last reviewed checkpoint was preserved. Retry later, or explicitly request a full review by commenting @coderabbitai full review.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 71e6cc67-32e6-44b0-8306-f807774472db

📥 Commits

Reviewing files that changed from the base of the PR and between fe0e237 and d8b36b2.

📒 Files selected for processing (3)
  • .changeset/c4-title-hash.md
  • packages/mermaid/src/diagrams/c4/parser/c4Diagram.jison
  • packages/mermaid/src/diagrams/c4/parser/c4Diagram.spec.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • .changeset/c4-title-hash.md
  • packages/mermaid/src/diagrams/c4/parser/c4Diagram.spec.ts
  • packages/mermaid/src/diagrams/c4/parser/c4Diagram.jison

Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review.

📝 Walkthrough

The C4 lexer now accepts # in title and accDescription values while stopping at newlines or semicolons. Parser tests verify value preservation, and a patch changeset documents the fix.

Changes: C4 hash value parsing

Layer / File(s) Summary
Expand C4 value lexer patterns
packages/mermaid/src/diagrams/c4/parser/c4Diagram.jison
The lexer accepts # in title and accDescription values while retaining newline and semicolon termination.
Validate preserved hash values
packages/mermaid/src/diagrams/c4/parser/c4Diagram.spec.ts, .changeset/c4-title-hash.md
Tests verify parsed values containing #. The changeset records the patch fix.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 9dff9

C4 titles and accessibility descriptions can now contain # characters without lexical errors, with parser coverage for both values. No current merge-blocking risk is identified.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the primary change: allowing '#' in C4 title and accDescription values.
Description check ✅ Passed The description explains the problem, cause, implementation, tests, affected grammar rules, and linked issue. It does not use the repository template headings or include the task checklist, but it con…
Linked Issues check ✅ Passed The changes directly satisfy issue [#8030] by allowing '#' in C4 title values and adding parser coverage. The lexer preserves newline and semicolon termination, and the accDescription fix is consisten…
Out of Scope Changes check ✅ Passed All changes are directly related to the linked issue: the C4 lexer fix, parser tests, and a patch changeset. No unrelated code or scope expansion is present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 1…
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@mermaid-js/examples

npm i https://pkg.pr.new/@mermaid-js/examples@8039

mermaid

npm i https://pkg.pr.new/mermaid@8039

@mermaid-js/layout-elk

npm i https://pkg.pr.new/@mermaid-js/layout-elk@8039

@mermaid-js/layout-tidy-tree

npm i https://pkg.pr.new/@mermaid-js/layout-tidy-tree@8039

@mermaid-js/mermaid-zenuml

npm i https://pkg.pr.new/@mermaid-js/mermaid-zenuml@8039

@mermaid-js/parser

npm i https://pkg.pr.new/@mermaid-js/parser@8039

@mermaid-js/tiny

npm i https://pkg.pr.new/@mermaid-js/tiny@8039

commit: 0e8cfbf

@codecov

codecov Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.46%. Comparing base (e28fbd9) to head (0e8cfbf).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #8039      +/-   ##
===========================================
- Coverage    81.15%   79.46%   -1.70%     
===========================================
  Files          623      601      -22     
  Lines        86032    77232    -8800     
  Branches     19003    15707    -3296     
===========================================
- Hits         69822    61370    -8452     
- Misses       15203    15862     +659     
+ Partials      1007        0    -1007     
Flag Coverage Δ
e2e ?
unit 79.46% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.
see 195 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@argos-ci

argos-ci Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Argos notifications ↗︎

Awaiting the start of a new Argos build…

@filipsajdak

Copy link
Copy Markdown
Collaborator Author

Force-pushed to remove the Co-Authored-By: Claude / Claude-Session: trailers from the commit message. Message-only rewrite - the tree is byte-identical, verified with git diff <old-tip> <new-tip> returning empty, so the fix itself is unchanged and any review you have already done still applies.

This was raised in review on #7859, citing the project's own rule against tagging commits as AI-authored. Since this repo merges rather than squashes, the message would land on develop verbatim, so it had to be corrected before merge rather than after.

Nothing else about the PR moved: same single commit, same diff, same tests.

@filipsajdak

Copy link
Copy Markdown
Collaborator Author

Gentle nudge - this one has been open since 08-07 with no review yet.

It is a 1-line grammar fix plus tests: c4Diagram.jison excluded # from the character class for title and accDescription, but C4's comment syntax is %% and the grammar has no # comment rule, so the exclusion never served a purpose. It closes #8030, and it is also what made the Cypress case requested during the #7874 review look red for an unrelated reason.

One note on the checks so they do not put you off: the Netlify reds are stale rather than real. This PR last built on 08-07, inside the outage window described in #8049, and Netlify passes on PRs opened since. lint, unit-test, build and argos are all green.

No urgency - just flagging it, since it is small and self-contained enough to be easy to lose.

@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@filipsajdak

Copy link
Copy Markdown
Collaborator Author

Synced with develop (merge 56cba6a3b, no conflicts) - this branch had drifted 270 commits behind, which is what the red Netlify deploy preview was: the docs build on a base that predates the current toolchain, not anything this PR changes. Its own diff is unchanged and still three files:

.changeset/c4-title-hash.md                                |  5 +
packages/mermaid/src/diagrams/c4/parser/c4Diagram.jison    |  4 +-
packages/mermaid/src/diagrams/c4/parser/c4Diagram.spec.ts  | 16 ++

171 C4 tests green on the merge.

Gentle nudge while I am here, and no rush at all - open since 08-07, and I last flagged it on 08-20. It is a one-line grammar fix: c4Diagram.jison excluded # from the character class for title and accDescription, so a perfectly ordinary title like title C4 #1 silently lost its text. Happy to leave it sitting if the queue is full - just did not want it to look like it was waiting on me.

@filipsajdak

Copy link
Copy Markdown
Collaborator Author

Correcting the last line of my previous comment.

I said the red Netlify checks were "the docs build on a base that predates the current toolchain". I do not have evidence for that, and I should have checked my own notes before writing it: those failures are the repo-wide intermittent one I filed as #8049, which since 2026-08-07 has hit roughly 78% of deploy previews across unrelated authors, this PR's 2026-08-11 build among them.

The deploy preview is green on the synced head, in about two minutes - which matches the timing signature of a real build rather than the ~20-second death that marks the failing ones. But one green run cannot tell the two explanations apart, since #8049 has always had successes interleaved. So: the checks are green now, the sync was worth doing on its own merits, and I am not claiming it is what fixed them.

Everything else in that comment stands - clean merge, diff unchanged, tests green.

@filipsajdak

Copy link
Copy Markdown
Collaborator Author

The unit-test red on the synced head is not this PR either, and it is a new one worth flagging for everyone rather than just for me.

FAIL packages/mermaid/src/diagram-api/regexes.spec.ts
  > stripAnyComments > scales linearly on deep indents
AssertionError: expected 13.093625561670422 to be less than 8

That is a wall-clock ratio assertion. It landed on develop yesterday with perf(flowchart): avoid O(n^2) parse cost on deeply-indented diagrams, and it times stripAnyComments on a 4000-line and a 16000-line input and requires the ratio to stay under 8. This branch is a one-line change to c4Diagram.jison; it does not touch the scanner, and the merge is simply the first time this branch has had the test.

Run locally on this branch's head, five times in a row: 5 passes, no failures. So the implementation is linear as intended and the CI run was a loaded runner, which is the failure mode the test's own comment anticipates - "the bar is set at 8 so ordinary timing noise on a loaded machine cannot fail it". On a shared runner 8x headroom turns out not to be enough.

Not my call what to do about it, and I do not want to speak for the author. If it would help I can open an issue with the numbers rather than leaving it to be rediscovered one PR at a time - say the word.

@coderabbitai

coderabbitai Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@filipsajdak

Copy link
Copy Markdown
Collaborator Author

Synced with develop (d8b36b2ec, clean merge). unit-test and lint are green; the PR's own diff is unchanged, still three files.

Correcting what I said about the flaky test on 09-04

The red here was stripAnyComments > scales linearly on deep indents, a wall-clock ratio assertion that came in with perf(flowchart): avoid O(n^2) parse cost on deeply-indented diagrams. I reported it as passing 5 of 5 locally and implied it was a CI-runner artifact.

That was too strong. Today it failed on my own machine, on the first run after a pnpm install. So I measured it properly instead of leaving one number on the record:

condition failures
spec alone, 6 runs 0 / 6
alongside the c4 suite, 6 runs 0 / 6
first run after pnpm install (machine still busy) 1 / 1

1 failure in 13 local runs, and the one failure came while the machine was still finishing an install. That is a better description than either "it passes locally" or "it is broken": the implementation is linear, and the assertion is sensitive to whatever else the machine is doing. The bar is large / small < 8; the failing observations were 13.09 on CI and a similar order locally.

Not my call what to do about it, and I do not want to speak for the author. Recorded here because I put a weaker claim on this thread three days ago and it deserves the correction.

@filipsajdak

Copy link
Copy Markdown
Collaborator Author

The e2e-required red that appeared here overnight is not a test failure, and it is not this PR - filed as #8235 with the measurements.

e2e (1) was cancelled at 30m05s, at [1106/1235]. A scoped e2e run puts the whole mmd-snapshots.spec.ts suite on a single shard (E2E_SCOPED_MATRIX: '[1]'), where a full run spreads it over eight, and the job cap is 30 minutes. That path has been finishing in about 26 minutes for two weeks:

PR date e2e (1)
#8058 08-27 26m31s
#8041 09-02 26m18s
#8143 09-02 26m01s
this one 09-07 30m05s, cancelled

Two other people's branches hit the same 30-minute wall in the same three days - codex/state-diagram-link-styles (1810s) and cursor/fix-sequence-katex-note-over-padding (1804s) - so it is the scoped path rather than anything about a .jison change. #8235 has the full table, including which recent cancellations were merely superseded pushes rather than timeouts.

Everything else here is green: unit-test, lint, build, CodeQL. The PR's own diff is unchanged at three files, and it is still the one-line grammar fix plus tests.

I have not pushed anything to force a re-run. It would probably go green - 30m05s against a 30m cap is a coin flip - but spending a full e2e run to reroll a dice throw seemed worse than saying plainly what the red is. Happy to re-trigger it if you would rather see it green before reviewing.

@filipsajdak

Copy link
Copy Markdown
Collaborator Author

Closing the loop on the flaky test, because the maintainers fixed it and did a better job of it than my framing did.

I had characterised stripAnyComments > scales linearly on deep indents as load-sensitive and measured it at 1 failure in 13 local runs. True, but it stopped at "noisy". Two commits on master went further:

  • 45b9c9b38 takes the minimum over five trials instead of one average, on the reasoning that noise only ever adds time, so the minimum is the stable estimate.
  • 3c21bbf27 then deleted the deep indents case outright, having found it was non-discriminating: the released regex scales 4.1x on 4x input for that shape against 15x for the two genuinely quadratic ones, so the case could never have failed for the reason its name gave. At several megabytes per input it was measuring memory bandwidth rather than algorithmic scaling.

That is the sharper diagnosis: not "this assertion is noisy" but "this assertion cannot detect the regression it guards". Worth saying plainly since I had it on this thread as a flake.

Both fixes are on master and not yet on develop, so this branch still carries the old case until the release merge-back lands.

The current e2e-required red here is separate and unchanged - the scoped-e2e 30-minute timeout filed as #8235.

The lexer rules for `title` and `accDescription` excluded `#` from their
character class, so a `#` anywhere in either value terminated the token and
the remainder of the line failed to lex with "Lexical error ... Unrecognized
text". C4's comment syntax is `%%` and the grammar has no `#` comment rule,
so the exclusion served no purpose.

Fixes mermaid-js#8030
@filipsajdak
filipsajdak force-pushed the bug/8030_c4-title-hash branch from d8b36b2 to 9dff9f1 Compare September 18, 2026 07:15
@filipsajdak

Copy link
Copy Markdown
Collaborator Author

@pbrolin47 this is ready for review: CI is green, Argos included, and it is mergeable.
Argos: no changes found. It is a parser fix that lets # appear in a C4 title and accDescription, so no rendered diagram moves.
Closes #8030.

@filipsajdak

Copy link
Copy Markdown
Collaborator Author

Gentle ping, no hurry: this is one commit that closes #8030, it touches the parser only (no renderer or snapshot change), and checks are green. develop is merged in, so it is current. @knsv @sidharthv96 @pbrolin47, could one of you take a look when you have a moment? The status of the whole C4 series is in #7849.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Type: Bug / Error Something isn't working or is incorrect

Projects

None yet

Development

Successfully merging this pull request may close these issues.

C4: a '#' in 'title' breaks parsing with a lexical error

1 participant