Mermaid 语法验证 Skill 实战指南:IB_Robot 文档 Mermaid 图的检查、修复与渲染验证

原创2026-10-13 14:02:361,609 阅读
文章标签:具身智能机器人人工智能大模型模型推理服务本地部署计算机视觉ROSopenEulerOpenHarmony深度学习语音AI AgentAscend

Mermaid 语法验证 Skill 实战指南:IB_Robot 文档 Mermaid 图的检查、修复与渲染验证

本文以 IB_Robot 仓库中 mermaid-syntax-validation 技能为蓝本,系统讲解如何对 Markdown/Sphinx 文档中的 Mermaid 图执行语法检查、仅限语法层面的最小修复,并证明生成后的 HTML 不再渲染 Mermaid 错误 SVG。读完本文,你将掌握一套「上下文检查 → 语法扫描与修复 → 真实构建 → 浏览器验证 → 结构化报告」的完整门禁流程,可直接用于该仓库 docs/ 目录及 DeepWiki 文档迁移产物的 Mermaid 图质量保障。

一、技能定位与适用场景

mermaid-syntax-validation 是 IB_Robot 仓库 .agents/skills 技能库中的文档类技能(分类为「文档」),在 AGENTS.md 中登记的功能描述为「Mermaid 图语法检查、修复与渲染验证」。它的定位是配合 deepwiki-config、deepwiki-translator、doc-link-validator 组成文档迁移与转换流水线——正如 docs/migration/README.md 所描述的,用户依次使用这 4 个技能即可完成 DeepWiki 文档的拆分、配置、翻译、生成与校验,而 Mermaid 检查是流水线的最后一环(docs/migration/README.md)。

该技能在以下场景下应当被触发:

  • 生成后的文档页面显示 Syntax error in text、Parse error、Diagram error 或 mermaid version;
  • 用户要求检查 docs/ 下所有 Markdown Mermaid 图;
  • 用户要求在保留图内容的前提下修复 Mermaid 语法;
  • Sphinx/MyST 文档流程使用 ```mermaid fenced block,并依赖浏览器端 Mermaid 渲染;
  • 静态扫描通过,但渲染后的 HTML 仍出现 Mermaid 错误 SVG;
  • 仓库使用本地 Mermaid runtime,例如 mermaid.min.js + mermaid-run.js,或 mermaid.esm.min.mjs + chunks/ 这类本地 ESM runtime。

技能本体位于 .agents/skills/mermaid-syntax-validation/SKILL.md,其目录结构如下:

.agents/skills/mermaid-syntax-validation/
├── SKILL.md                     # 技能主文档:流程、命令与门禁规则
├── references/
│   ├── context-checks.md        # 5 项上下文检查的原始定义与手工核对清单
│   └── syntax-scan-and-fix-rules.md  # 高风险模式表与语法修复规则
└── scripts/
    ├── context_check.py         # 上下文检查脚本(5 项检查一键执行)
    ├── fix_labels.py            # 语法级 label 修复脚本(幂等)
    ├── html_scan.py             # 构建产物 HTML 扫描脚本
    └── parse_check.mjs          # 基于 mermaid.parse() 的权威语法校验

二、核心原则:只修语法,不改语义

技能的工作边界是严格限定的,这是整套流程的第一条红线:

只改 Mermaid 语法。必须保留图的含义、节点文本、边含义、顺序和周围正文。

因此,执行修复时不要重写架构、重命名概念实体、简化图,或为了让解析通过而删除 label。如果可见文本必须转义(例如 label 内含冒号、括号等特殊字符),应使用 Mermaid 兼容语法并保留显示含义。这一原则在 docs/migration/README.md 的流程说明中也有对应描述:「只修 Mermaid 语法,不改变图含义、节点文本、边含义、顺序或周边正文」。

三、必做上下文检查:编辑前的 5 项门禁

在编辑任何 Markdown 文件之前,必须先运行技能脚本完成 5 项上下文检查(文档栈、本地 runtime 资源、fence 统计、含图 HTML 页面、script 标签/CDN 引用)。命令中的 <skill_dir> 指本技能目录(即 scripts/、references/ 的父目录,也就是 .agents/skills/mermaid-syntax-validation/),执行时替换为实际路径;--docs-root 等目标路径参数以当前工作目录为基准:

python -X utf8 <skill_dir>/scripts/context_check.py --docs-root docs [--build-dir docs/build/html]

该脚本对应 references/context-checks.md 中定义的 5 项检查,scripts/context_check.py 的 docstring 将其汇总为:

  1. 文档栈:定位 conf.py,报告 extensions(是否包含 myst_parser / sphinxcontrib.mermaid)、myst_fence_as_directive、mermaid_* 系列配置项与 html_js_files 中加载浏览器 runtime 的条目;
  2. 本地 runtime 资源:在 _static/(含 _static/js/)下查找 mermaid.min.js、mermaid-run.js、mermaid.esm.min.mjs、mermaid-init.js 等 UMD/ESM runtime 文件,以及 ESM 必需的 chunks/ 目录树;
  3. fence 统计:统计 docs/ 根下所有 *.md 中 ```mermaid fenced block 的数量;
  4. 含图 HTML 页面:在构建产物中找出包含 class="mermaid" 容器的页面;
  5. script 标签/CDN 引用:检查生成 HTML 中引用的 Mermaid runtime 脚本,以及是否泄漏了 cdn.jsdelivr.net、unpkg.com 等在线 CDN 引用。

与之配套的门禁规则:

  1. 没有脚本输出,不得开始编辑任何 Markdown 文件;
  2. 最终报告的「已检查的 Mermaid runtime 文件」「docs 构建结果」「浏览器验证统计」等字段必须取自脚本输出或其后的构建/浏览器验证,不得凭记忆或推测填写;
  3. 脚本报告 WARNING(如 CDN 引用),或存在脚本未覆盖的人工判断项(conf.py monkey patch / override 语义、Sphinx 配置组合)时,必须阅读 references/context-checks.md 并按其规则处理,在报告中明确列出并说明处置方式。

在脚本不可用(如构建目录缺失)时,references/context-checks.md 还提供了逐项手工执行的 Python/PowerShell 等价命令,例如 fence 统计(Linux/bash 主路径):

python3 - <<'PY'
from pathlib import Path

print(sum(1 for path in Path("docs").rglob("*.md") for line in path.read_text(encoding="utf-8").splitlines() if line.strip() == "```mermaid"))
PY

四、Runtime 预期:Mermaid v10+ 的正确调用方式

技能对「当前本地 runtime 方案」的预期是:项目 runner(例如 mermaid-run.js)应当:

  • 等待 window.mermaid 存在;
  • 调用 window.mermaid.initialize({ startOnLoad: false, ... });
  • 在页面加载后调用 window.mermaid.run();
  • 绑定项目自定义交互,例如点击放大 modal。

一个关键版本判断:当前 Mermaid 版本应使用 mermaid.run(),把 mermaid.init() 示例视为旧写法,因为 Mermaid v10+ 已废弃该 API。

在验证手段的强弱上,技能给出明确排序:如果存在可运行的 Mermaid JS 环境,语法级检查优先使用 mermaid.parse(text, { suppressErrors: true })。静态 grep 适合初筛,但 parse() 和浏览器渲染是更强的证据——因为 parse() 与浏览器渲染使用同一解析器,复验全绿即等价于渲染通过。

五、语法风险扫描与修复:四步循环

编辑前必须完成「诊断 → 预览 → 修复 → 复验」循环,其顺序固定为 1→4,且该循环是幂等的(仅改语法;parse() 与浏览器渲染使用同一解析器,复验全绿即等价于渲染通过):

node <skill_dir>/scripts/parse_check.mjs <target_dir>                   # 1. 诊断:定位失败块
python -X utf8 <skill_dir>/scripts/fix_labels.py <target_dir> --dry-run  # 2. 预览将修改的内容
python -X utf8 <skill_dir>/scripts/fix_labels.py <target_dir>            # 3. 应用自动修复(graph/flowchart 标签语法)
node <skill_dir>/scripts/parse_check.mjs <target_dir>                   # 4. 复验:必须全绿

依赖说明:脚本依赖 mermaid、jsdom 从当前工作目录解析,缺失时必须站在目标目录之外(如仓库根)执行 npm install mermaid jsdom——npm 会在执行目录创建 node_modules,站在目标内执行会给目标目录新增文件。

parse_check.mjs 的实现要点(scripts/parse_check.mjs)包括:使用 jsdom 构造 DOM 环境并注册 window/document/navigator 全局对象;通过 mermaid.initialize({ startOnLoad: false, suppressErrorRendering: true }) 初始化;递归遍历目标目录下所有 *.md,用正则 /```mermaid\r?\n(.*?)```/gs 提取每个 fenced block 并逐一调用 mermaid.parse();全部通过时退出码为 0,否则为 1。

fix_labels.py 的自动修复范围(scripts/fix_labels.py)仅覆盖 graph/flowchart 图,sequence/state/class 图跳过:

  1. 标签引号翻倍(DeepWiki 导出/翻译引入,如 A[""x""] → A["x"]);
  2. 标签内部引号转义(A[a "b"] → A["a #quot;b#quot;"]);
  3. 含特殊字符但未加引号的标签(A[profile: {d: 0}] → A["profile: {d: 0}"]);
  4. 匿名节点分配 ID(["label"] → mmd_anon_N["label"]);
  5. 边标签特殊字符加引号(-->|Returns X[]| → -->|"Returns X[]"|)。

其中 #quot; 是 Mermaid 的 HTML entity 形式,用于在保留可见文本(显示为 ")的前提下转义内部引号。

高风险模式表

当 fix_labels.py 应用后 parse_check.mjs 仍有失败块时,禁止凭经验直接手工编辑,必须先阅读 references/syntax-scan-and-fix-rules.md,按下表逐行定位失败模式并按其「仅语法修复」列处理:

模式 失败原因 仅语法修复 自动修复
A --> ["label"] 匿名节点作为边端点 创建稳定节点 id:A --> node_id["label"] 手工(行中括号不处理,避免误伤边标签内括号)
["label"] 独立声明 匿名节点声明 创建稳定节点 id:node_id["label"] fix_labels.py(分配 mmd_anon_N)
subgraph "ID" ["Title"] subgraph 写法不兼容 subgraph ID["Title"] 手工(subgraph 语句行跳过)
A -- "label" --> B 旧式边 label 可能失败 `A --> "label"
A --> B : "label" flowchart 旧式尾随 label `A --> "label"
`A --> /topic (type) B` edge label 含未加引号的括号
B{func(arg)} diamond 节点 label 含未加引号的括号 B{"func(arg)"} fix_labels.py
A --> B: file.py:1-2 in stateDiagram-v2 transition label 内含额外冒号 A --> B: file.py#58;1-2 手工(非 graph/flowchart,脚本跳过)
A[""label""] 标签引号翻倍(DeepWiki 导出/翻译引入),空标签边界 去重外层引号并转义内部引号:A["label"] fix_labels.py
A[k: {v}] 方括号标签内未加引号的 { 被解析为菱形开始 A["k: {v}"] fix_labels.py
`A --> Returns X[] B` edge label 内未加引号的 [] 触发节点形状解析

注意:静态 grep 只能初筛部分模式,[]、{}、"" 翻倍这类问题只有 parse() 能稳定暴露,因此修复循环必须以 parse_check.mjs 为准。

无 JS runtime 时的静态初筛回退

当无法运行 parse_check.mjs(无 JS runtime)时,按 references/syntax-scan-and-fix-rules.md 的「静态语法初筛」节用 grep 定位可疑行,再按高风险模式表处理,并在报告中说明未做 parse 验证的原因。例如:

python3 - <<'PY'
from pathlib import Path
import re

patterns = [
    r'^\s*\["',
    r'--?>\s*\["',
    r'\.->\s*\["',
    r'^\s*subgraph\s+"[^"]+"\s+\[',
    r'\s--\s*"',
    r'\s--"',
]
compiled = [re.compile(pattern) for pattern in patterns]
for path in sorted(Path("docs").rglob("*.md")):
    for line_number, line in enumerate(path.read_text(encoding="utf-8", errors="ignore").splitlines(), 1):
        if any(pattern.search(line) for pattern in compiled):
            print(f"{path}:{line_number}:{line}")
PY

三类修复规则

Flowchart 边 Label:使用 pipe label 语法。当 label 含有 (、)、/、:、<、>、, 或其他标点时,优先加引号:

A -->|"label with (parentheses), /slashes, or :colon"| B

Flowchart 节点 Label:节点形状内的 label 如果包含标点,应加引号:

B{"get_scene_file(scene_name, platform)"}
C["/base_velocity_controller/commands (std_msgs/Float64MultiArray)"]

State Diagram Transition Label:stateDiagram-v2 使用 A --> B: label。如果 label 自身还需要额外冒号,应把内部冒号转成 Mermaid entity 文本:

Idle --> GoalEvaluation: handle_goal()<br/>episode_recorder.py#58;277-288

这里的 #58; 是冒号的 HTML entity 写法,渲染后显示为 file.py:277-288,从而保留原内容——这是「除 Mermaid 语法转义外,保持可见 label 不变」原则的典型体现。

六、构建验证:真实文档构建与产物扫描

修复后必须运行真实文档构建。项目有文档化命令时优先使用项目命令,常见 Sphinx 命令包括:

sphinx-build -M html source build

或从文档项目根目录运行:

python3 -m sphinx -b html docs/source docs/build/html

随后用技能脚本扫描生成 HTML(bash 与 Windows PowerShell 均可直接运行;匹配文件逐行输出到 stdout,扫描统计输出到 stderr):

python -X utf8 <skill_dir>/scripts/html_scan.py --build-dir docs/build/html --scan errors
python -X utf8 <skill_dir>/scripts/html_scan.py --build-dir docs/build/html --scan cdn
  • --scan errors:扫描 Mermaid 错误文本(Syntax error in text / Parse error / mermaid version / Diagram error)。期望退出码 0 且 stdout 无匹配文件;出现任何匹配都是失败。
  • --scan cdn:扫描是否意外引入在线 runtime 依赖(cdn.jsdelivr.net / unpkg.com)。对要求离线可用的文档,期望退出码 0 且 stdout 无匹配文件;允许在线的文档出现匹配时,须在报告中说明在线依赖及处置。
  • 构建目录缺失或其中没有 HTML 文件时,脚本以退出码 2 报错——此时不得视为验证通过,应先修正 --build-dir 或重新构建(scripts/html_scan.py 明确定义了退出码语义)。

再用同一脚本确认本地 runtime 文件已复制到生成产物的 _static 目录(stdout 逐项列出找到的资产,可直接作为报告「已检查的 Mermaid runtime 文件」字段的证据):

python -X utf8 <skill_dir>/scripts/html_scan.py --build-dir docs/build/html --scan runtime
  • 使用本地浏览器 runtime 的项目(UMD:mermaid.min.js + runner;ESM:.mjs 入口 + chunks/)期望退出码 0。
  • ESM 入口存在但旁边没有 chunks/ 目录时,脚本输出 WARNING 并以退出码 1 提示核查 ESM runtime 是否完整。
  • 服务端渲染(png/svg 直出)的项目没有浏览器 runtime 属正常,退出码 1 不代表失败,但须在报告中说明渲染方式。

七、浏览器验证:最终渲染防线

Sphinx 成功并不够——Mermaid 语法通常是在浏览器端才真正解析。因此修复后必须从生成的 HTML 根目录启动临时本地服务:

python3 -m http.server 8765 --bind 127.0.0.1 --directory docs/build/html &
SERVER_PID=$!

使用浏览器自动化打开每个包含 .mermaid 的 HTML 页面,并检查每个 Mermaid 容器:

  • 包含 svg;
  • SVG 的 aria-roledescription 不是 error;
  • 文本不匹配 Syntax error in text|Parse error|Diagram error|mermaid version。

如果项目实现了点击放大功能,还要验证交互:

  • 点击渲染后的 .mermaid 图会打开 .mermaid-modal 或项目自定义 modal;
  • 滚轮输入会改变克隆 SVG 的 transform 或缩放状态;
  • 支持拖拽时,拖拽会移动放大后的 SVG;
  • Escape、关闭按钮、点击背景均可关闭 modal。

验证后必须关闭临时服务:

kill "$SERVER_PID"

八、最终报告格式

技能要求最终报告必须包含以下字段,缺失即视为未执行对应门禁步骤:

  • context_check.py 的输出摘要(文档栈、runtime 文件、fence 数、含图页面数);
  • 修改的文件;
  • 修复的具体语法类别(存在手工修复时须注明依据:高风险模式表的行或「修复规则」章节的条目,作为审计记录);
  • parse_check.mjs 结果(N/N 块通过);
  • 已检查的 Mermaid runtime 文件,包括本地/CDN 结果;
  • docs 构建结果;
  • 浏览器验证统计:检查页数、Mermaid 图数量、失败数;
  • 如果项目实现点击放大,包含点击放大验证结果;
  • docs 构建中剩余的非 Mermaid warning;
  • 确认临时服务已关闭。

技能内置的示例报告:

Context check: myst_parser + sphinxcontrib.mermaid, 211 fences, local runtime mermaid.min.js + mermaid-run.js, 56 HTML pages with mermaid, no CDN.
Parse check: 211/211 mermaid blocks passed (3 manual fixes per pattern table rows: subgraph legacy syntax, stateDiagram colon).
Changed 4 Markdown files, syntax-only Mermaid edits.
Runtime check: local mermaid.min.js + mermaid-run.js copied, no CDN runtime references.
Sphinx build: passed.
Browser Mermaid QA: 56 pages, 142 diagrams, 0 failures.
Click-to-zoom QA: modal open, wheel zoom, drag pan, ESC close passed.
Generated HTML error text scan: no output.
Temporary HTTP server stopped.

九、禁止事项与红线清单

  • 不要只依赖静态 grep 或 sphinx-build;
  • 不要为了避免语法错误而删除 label;
  • 除非用户明确要求,不要改变图语义、来源引用、标题或正文;
  • 除非用户明确要求,不要修改 sphinxcontrib-mermaid 等依赖版本号;
  • 对要求离线可用的文档,不要重新引入 CDN runtime 依赖;
  • 不要让临时 HTTP 服务残留运行。

十、在仓库中的落地:脚本实现与真实文档佐证

脚本实现要点

四个脚本构成了完整的「检查 → 诊断 → 修复 → 复验 → 产物扫描」工具链,可以从源码层面印证本文描述的流程:

  • scripts/context_check.py:通过 CONF_KEYS 列表(extensions、myst_fence_as_directive、html_js_files、mermaid_version、mermaid_output_format、mermaid_init_config、mermaid_include_elk、mermaid_fullscreen、mermaid_use_local 等)逐项正则提取 conf.py 配置;RUNTIME_FILES 定义 runtime 资产清单;CDN_RE 匹配 cdn.jsdelivr.net|unpkg.com。若发现 conf.py 中既无 sphinxcontrib.mermaid 也无 myst_parser,或存在 mermaid 容器但无本地 runtime script 引用,会输出 WARNING。缺失 conf.py / 构建目录时仅报告而不视为错误(仓库可能对接外部 Sphinx 项目)。
  • scripts/parse_check.mjs:以 jsdom + mermaid.initialize({ startOnLoad: false, suppressErrorRendering: true }) 建立与浏览器一致的解析环境,逐个 fenced block 调用 mermaid.parse(),输出 total/passed/failed 统计并打印失败块的文件、块号、错误信息与块内容头部。
  • scripts/fix_labels.py:BLOCK_RE 只触碰 ```mermaid fenced block;DIAGRAM_HEAD_RE 限定仅处理 graph/flowchart 图;STATMENT_KEYWORDS(classDef、style、click、%%、subgraph、end 等)保护的语句行跳过;支持 --dry-run 预览;处理 UTF-8 BOM 文件时保持 BOM 不变;由于逻辑幂等,对已修复的源再次运行会报告 0 处变更。
  • scripts/html_scan.py:ERROR_TEXT_RE 匹配四种 Mermaid 错误文本;CDN_RE 匹配在线 runtime 依赖;runtime 扫描把 _static/(含 _static/js/)下找到的 runtime 资产逐项输出到 stdout,作为报告的运行证据;ESM 入口无 chunks/ 时给出 WARNING 并返回 1。

仓库中的真实 Mermaid 图样例

本仓库的 docs/ 目录本身就是该技能的适用对象。例如 docs/unify.md 的总体架构图使用 flowchart TB,并且大量采用了技能文档要求的「稳定节点 id + 带引号标题」规范写法,如:

flowchart TB
    subgraph ENTRY["ROS 进程与业务入口"]
        DISPATCHER["ScheduledActionDispatcherNode<br/>产品动作调用方"]
        SCHEDULER["GlobalInferenceSchedulerNode"]
    end

而 docs/roadmap.md 的里程碑路线图使用 graph TD 与 subgraph "阶段 N: ..." 的中文子图命名。这两类图正好覆盖了技能「subgraph 写法兼容」「中文/标点标签转义」等典型检查点;docs/unify.md 的「策略 Facade」流程图还展示了 STAGES -->|"Torch / single-role"| SESSION 这类 pipe label 加引号的推荐写法。

在文档迁移流水线中的位置

mermaid-syntax-validation 是文档迁移流水线的最后一道质量闸门。按 docs/migration/README.md 的流程,翻译和生成完成后即使用该技能对 Mermaid 图进行语法检查、最小修复和渲染验证,推荐检查内容包括:统计 Mermaid fence 数量、静态扫描高风险语法(匿名节点、旧式边标签、带括号或冒号的未加引号标签)、修复后执行真实 Sphinx 构建、浏览器确认渲染正常且无错误文本;当 DeepWiki 源内容更新时,增量更新流程的最后一步同样是运行 mermaid-syntax-validation(docs/migration/README.md)。

整体而言,该技能把「Mermaid 图在文档发布链路中渲染失败」这一高频问题,收敛为可脚本化、可审计、可复验的四阶段门禁流程,其「只修语法、保留语义」的边界与「报告字段必须取自脚本输出」的证据纪律,保证了任何人工干预都留有依据、任何验证结论都可追溯——这也是它在 .agents/skills/README.md 中被列为独立文档技能的原因。

登录后查看全文
IB_Robot