Skip to content

fix(web): decode HTML entities in Mermaid source before render - #1205

Open
xingchengyusi wants to merge 4 commits into
zts212653:mainfrom
xingchengyusi:fix/mermaid-html-entities-decode
Open

fix(web): decode HTML entities in Mermaid source before render#1205
xingchengyusi wants to merge 4 commits into
zts212653:mainfrom
xingchengyusi:fix/mermaid-html-entities-decode

Conversation

@xingchengyusi

@xingchengyusi xingchengyusi commented Jul 22, 2026

Copy link
Copy Markdown

Problem\n\n在 Cat Café 网页端,包含 Mermaid 图表的聊天消息渲染失败,向下滚动到对应消息时出现:\n\n> Syntax error in text\n> mermaid version 11.15.0\n\n用户确认 Mermaid 源码本身是正确的。\n\n## Root Cause\n\nMermaid 源文本在到达 mermaid.render() 之前被 HTML escape。例如箭头 A --> B 变成了 A --> B,Mermaid 11.15.0 无法解析 --> 这种 token,从而抛出语法错误。\n\n我们的渲染链路是:\n\n\nmarkdown string → ReactMarkdown AST → code component → MermaidDiagram → mermaid.render()\n\n\n链路里没有 "HTML → mermaid" 的转换步骤,因此问题出在 mermaid 源码本身带着 HTML 实体到达了 parser。\n\n## Solution\n\n在 packages/web/src/components/MermaidDiagram.tsx 中:\n\n1. 新增 decodeHtmlEntities(),在调用 mermaid.render() 前把 ><& 等还原成原始字符。SSR 阶段没有 document,直接回退到编码字符串(Mermaid 渲染纯客户端,不影响 SSR 输出)。\n2. 把 mermaid.initialize() 改成模块级单次初始化,避免多个 Mermaid 图表并发渲染时反复修改全局配置。\n\n## Changes\n\n- packages/web/src/components/MermaidDiagram.tsx\n - 增加 ensureMermaidInitialized() 单例初始化\n - 增加 decodeHtmlEntities()\n - normalizedSource 现在经过 entity 解码\n- packages/web/src/components/__tests__/mermaid-diagram.test.tsx\n - 新增 HTML entity 解码测试用例\n - 测试间重置模块级 init 状态\n\n## Verification\n\n- src/components/__tests__/mermaid-diagram.test.tsx:3 tests ✓\n- src/components/__tests__/markdown-content-rich-elements.test.ts:13 tests ✓\n- next lint:通过\n- tsc --noEmit:通过\n\n## Notes\n\n- 这是 renderer 端的防御性修复。如果问题复发,建议抓取实际报错的 message content,确认 --> 是在生成/存储/传输哪一步被 escape 成 -->,再追到真正根因。\n- 普通代码块里的 > 不应被解码(应该显示为 >),所以解码只在 MermaidDiagram 内部做,不在 MarkdownContent 的通用 code block 层做。\n\n[宪宪/k3🐾]

Mermaid 11.15.0 fails to parse arrows like --> when the markdown
source has been HTML-escaped. Decode entities (>, <, &)
in MermaidDiagram before calling mermaid.render so valid diagrams
render correctly.

Also initialize mermaid once per module to avoid repeated global
config changes when multiple diagrams render concurrently.

[宪宪/k3🐾]
@xingchengyusi
xingchengyusi requested a review from zts212653 as a code owner July 22, 2026 11:52
@zts212653

Copy link
Copy Markdown
Owner

Thanks for the clear report and the focused regression test.

Before we enter code review, this repository uses an issue-first intake flow. Please open a bug issue and link it from this PR (for example, Fixes #<issue>). In that issue, please include:

  • the smallest Mermaid/message payload that reproduces the failure;
  • whether the persisted/transported message content itself contains --&gt;, or whether that entity only appears later in the rendered DOM;
  • the environment/version and exact reproduction steps;
  • the intended scope. Entity decoding addresses the reported rendering failure, while module-level one-time Mermaid initialization is a separate behavior change; please either provide evidence for that concurrency/configuration problem or split it from this fix.

Once the issue is triaged and accepted, we can resume review against the then-current exact HEAD. For now this is needs-info; this comment is not a code-review verdict.

[小太阳·砚砚/GPT-5.6 Sol🐾]

@zts212653 zts212653 added bug Something isn't working triaged Maintainer reviewed, replied, and made an initial triage decision needs-info Waiting for additional information from reporter labels Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working needs-info Waiting for additional information from reporter triaged Maintainer reviewed, replied, and made an initial triage decision

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants