--- name: mermaid-check description: 检查并修复 zero2Agent 项目中 mermaid 图表的语法问题。当用户说"mermaid 渲染错误""图表语法检查""mermaid 不显示""flowchart 报错""检查 mermaid"时触发。也适用于用户提到某篇文章的 mermaid 图无法渲染、显示 syntax error 的场景。 --- # Mermaid 语法检查与修复 本项目使用 mermaid 9.4.3(CDN 加载),配置 `htmlLabels: false`,`securityLevel: 'loose'`。 图表写在 ` ```mermaid ` 代码围栏中,由 `_layouts/default.html` 中的 JS 转换后渲染。 --- ## 渲染管线原理 ``` ```mermaid 代码围栏 ↓ kramdown 渲染
原始文本(HTML 实体转义)
↓ 项目 JS(default.html) code.textContent → 原始 mermaid 文本(含
、-->、| 等) ↓ srcToInnerHTML() 转换 innerHTML: 转义 < > & 但保留
为真实 HTML 标签 ↓ mermaid.init() 读取 innerHTML → entityDecode() → 解析器 ``` ### 关键函数 srcToInnerHTML ```javascript function srcToInnerHTML(src) { return src .replace(/&/g, '&') .replace(//g, '>') .replace(/<br\s*\/?>/gi, '
'); } ``` 原理:先将所有 HTML 特殊字符转义,再把 `
` 从实体还原为真实标签。 mermaid 的 entityDecode 通过 `escape()`/`unescape()` 能正确处理: - `-->` → 解码回 `-->` - `
` (真实标签) → escape 变为 `%3Cbr/%3E` → unescape 变回 `
` - `|` → escape 变为 `%7C` → unescape 变回 `|` --- ## 使用 Node.js 验证 mermaid 语法 安装 mermaid CLI: ```bash npm install -g @mermaid-js/mermaid-cli ``` 验证单个图表: ```bash echo 'flowchart LR A[text] -->|label| B' > /tmp/test.mmd npx mmdc -i /tmp/test.mmd -o /tmp/test.svg 2>&1 ``` 批量验证项目中所有 mermaid 块: ```bash python3 << 'EOF' import re, os, subprocess, tempfile base = os.getcwd() errors = [] for root, dirs, files in os.walk(base): dirs[:] = [d for d in dirs if d not in ['.git', '.claude', 'node_modules']] for f in files: if not f.endswith('.md'): continue path = os.path.join(root, f) with open(path) as fh: content = fh.read() for m in re.finditer(r'```mermaid\n(.*?)\n```', content, re.DOTALL): block = m.group(1) line = content[:m.start()].count('\n') + 1 with tempfile.NamedTemporaryFile(suffix='.mmd', mode='w', delete=False) as tmp: tmp.write(block) tmp_path = tmp.name result = subprocess.run( ['npx', 'mmdc', '-i', tmp_path, '-o', '/dev/null'], capture_output=True, text=True ) os.unlink(tmp_path) if result.returncode != 0: errors.append((path, line, result.stderr.strip())) if errors: for path, line, err in errors: print(f'{path}:{line}') print(f' {err[:200]}') print() else: print('All mermaid blocks pass syntax check') EOF ``` --- ## 常见 Bug 与修复方案 ### Bug 1:`\n` 在代码围栏中不是换行 **现象**:节点标签想换行,写了 `A[第一行\n第二行]`,渲染出错或显示字面 `\n` **原因**:`\n` 只是两个字符(反斜杠+n),mermaid 不认识 **修复**:用 `
` 或 `
` ``` A[第一行
第二行] ``` ### Bug 2:Unicode 特殊符号导致 syntax error(已验证) **现象**:`C[读文件 × 5]` 报 "Syntax error in graph" **原因**:mermaid 9.4.3 的 JISON 解析器无法处理 `×` (U+00D7) 等 Unicode 特殊字符。通过本地 HTML 隔离测试确认:去掉 `×` 后同一图表立即恢复正常。 **已知有问题的字符(未加引号时)**: - `×` (U+00D7 乘号) — 已确认触发 syntax error - `→` (U+2192 右箭头) — 已确认干扰箭头语法 - `←` (U+2190 左箭头) — 同上 - `:` (U+FF1A 全角冒号) — 已确认在 `([用户:...])` 中触发 error **安全的 Unicode 字符**(已确认可用): - CJK 汉字(中文标签正常) - `=` `_` `-` `?` 等 ASCII 符号 - `
` `
` 在代码围栏中正常工作 - 以上所有有问题的字符在**引号包裹的标签** `["..."]` 中均安全 **修复方案**(二选一): 方案 A — 替换为 ASCII 等价: ``` C[读文件 x5] -- × → x A -->|8k to 64k| B -- → → to A([用户: 帮我审查]) -- : → : ``` 方案 B — 用双引号包裹标签(推荐,保留原始字符): ``` C["读文件 × 5"] A(["用户:帮我做代码审查"]) ``` **核心规则**:非 CJK 的 Unicode 符号在**未加引号**的标签中不安全。加上 `"..."` 引号即可解决。 ### Bug 3:`
` 中的 `
` 导致解析失败 **现象**:写在 `
` 中的 `
` 被浏览器 HTML 解析器消费,textContent 在节点标签中间断行 **原因**:浏览器先于 mermaid 解析 HTML,`
` 变成 DOM 元素 **修复**:使用 ` ```mermaid ` 代码围栏(kramdown 保留原始文本) ```markdown ` ` `mermaid flowchart LR A[第一行
第二行] --> B ` ` ` ``` ### Bug 4:`div.textContent = src` 破坏 entityDecode **现象**:代码围栏图表初次渲染无法显示 **原因**:`textContent` 赋值导致 innerHTML 中 `
` 变为 `<br>`。mermaid 的 entityDecode 内部用临时 div 的 innerHTML 解码实体时,`
` 被解析为真实 HTML 元素,然后被 textContent 吞掉 **修复**:使用 srcToInnerHTML() 转换——先转义所有 HTML 字符,再将 `<br>` 恢复为真实 `
` 标签 ### Bug 5:主题切换后 mermaid 图表损坏 **现象**:切换深色/浅色模式后图表无法重新渲染 **原因**:rerenderMermaid 中用 `el.innerHTML = src` 直接设置原始文本,`
` 和 `>` 被当作 HTML 解析 **修复**:rerenderMermaid 也必须使用 srcToInnerHTML() 转换 ### Bug 6:初始化时 mermaid 不根据当前主题渲染 **现象**:浅色模式下 mermaid 图显示为深色背景 **原因**:`` 中 mermaid.initialize() 硬编码了 `theme: 'dark'` **修复**:读取 `data-theme` 属性动态选择主题变量 ### Bug 7:subgraph 标题含特殊字符 **现象**:`subgraph 内部框架` 报错 **修复**:用引号包裹 `subgraph FW["内部框架"]` ### Bug 8:edge label 含引号或特殊字符 **现象**:`-->|含"引号"的文本|` 报错 **修复**:整个 edge label 加引号 `-->|"含引号的文本"|` --- ## 检查流程 ### Step 1:扫描 ```bash grep -rn '```mermaid' --include="*.md" . | grep -v ".claude/" ``` 如仍有 `
`,先转为代码围栏。 ### Step 2:模式匹配检测 对每个 mermaid block 检查: | 问题 | 检测 | 修复 | |------|------|------| | 使用 `
` | grep | 转为代码围栏 | | `\n` 在节点标签中 | `\\n` 在方括号/花括号内 | → `
` | | Unicode 箭头 `→` `←` | 正则 | → ASCII 文本 | | `×` 乘号 (U+00D7) | 正则 `×` | → ASCII `x` | | 其他 Unicode 符号 | 非 CJK 非 ASCII 字符 | 替换或用引号包裹 | | subgraph 标题无引号 | `subgraph \w+ [` 后无引号 | 加引号 | | 嵌套引号 | `"` 在已有引号标签内 | 移除或转义 | ### Step 3:验证 有 mmdc 就用 mmdc 验证,没有则依赖模式匹配。 --- ## 节点标签换行正确写法 ```mermaid flowchart LR A[第一行
第二行] --> B[单行] C["含特殊字符
如括号()"] --> D{判断} ``` 规则: - 用 `
` 或 `
` 换行 - 不要用 `\n` - 含 `(){}[]#&` 等特殊字符时用双引号包裹整个标签 - edge label 中含特殊字符也用引号:`-->|"文本"|`