ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Mermaid 新图表接入全解析:从 JISON 词法语法到类型检测、渲染触发与主题集成的四步开发指南

2026/9/7 16:19:17 拓冰建站 浏览量
Mermaid 新图表接入全解析:从 JISON 词法语法到类型检测、渲染触发与主题集成的四步开发指南 Mermaid 新图表接入全解析从 JISON 词法语法到类型检测、渲染触发与主题集成的四步开发指南【免费下载链接】mermaidGeneration of diagrams like flowcharts or sequence diagrams from text in a similar manner as markdown项目地址: https://gitcode.com/GitHub_Trending/me/mermaid本文基于 Mermaid 仓库中的社区文档 new-diagram-jison.md完整讲解在 Mermaid 中新增一种图表类型diagram/chart的 JISON 时代标准流程定义词法/语法、解析期数据存储、图表类型检测、渲染触发以及解析器作为独立模块的使用方式并深入 Directive、无障碍Accessibility、主题Theming三大通用特性的接入细节。需要特别注意文档开头已明确标注 JISON 语法在 Mermaid 中已被弃用新图表应使用 Langium 方案New Diagram 文档且采用 JISON 语法的新型图不会被接受。因此本文更适合两类读者一是维护存量 JISON 图表仓库中仍有 18 个.jison语法文件的贡献者二是希望理解 Mermaid 解析管线全貌、再过渡到 Langium 的开发者。读完后你将掌握从词法规则到最终渲染的完整调用链以及每个环节在源码中的落点。Step 1Grammar Parsing词法与语法定义以起始关键字识别图表类型新增图表的第一步是定义它的 JISON 语法。语法的起点必须能识别出文本属于该图表类型——每种图表都有一个起始关键字例如流程图以graph开头、时序图以sequenceDiagram开头。按照约定在src/diagrams下为每种图表新建独立文件夹并在其中放置parser子文件夹存放 JISON 文件。当前仓库中的实际布局印证了这一点例如时序图语法sequenceDiagram.jison流程图语法flow.jison仓库中共有 18 个此类文件覆盖 class、gantt、pie、er、state、xychart 等图表。解析期数据存储yy对象回调JISON 解析器在解析过程中会持续存储数据这些数据之后由渲染器使用。其核心机制是调用解析器的用户可以向解析器传入一个对象语法动作action中通过该对象的yy属性调用方法把解析到的信息写入数据模型。文档给出的时序图语法片段如下statement : participant actor { $$actor; } | signal { $$signal; } | note_statement { $$note; } | title message { yy.setTitle($2); } ;其中yy.setTitle($2)表示当解析器遇到title关键字时调用数据对象上的setTitle方法并传入第二个词法单元消息文本。这里有两个要点$$是 JISON 中当前产生式的语义值直接赋值$$actor是把类型标签向上层规则传递yy.xxx(...)才是真正向外部数据模型的写入动作。必须定义parseError以统一错误处理文档特别强调note 块务必为解析器定义parseError函数并调用mermaid.parseError这样才能为用户提供统一的解析错误检测方式。文档给出的示例解析器暴露了如下函数exports.parseError function (err, hash) { mermaid.parseError(err, hash); };而解析时yy对象按如下方式初始化把数据模型db挂到解析器上const parser exampleParser.parser; parser.yy db;在源码层面可以印证这条链路mermaid.ts 中parseError是 mermaid 实例上的可选回调声明于 L448 附近初始值为undefined并提供了setParseErrorHandlerL317-L318作为替代方案——注释中说明这是给无法直接赋值mermaid.parseError的宿主如 Dart interop wrapper使用的// 等价于直接设置: mermaid.parseError function(err, hash) { ... };渲染管线中handleErrorL77 起会把错误分发给mermaid.parseError。因此图表侧的exports.parseError与全局的mermaid.parseError形成了图表语法 → mermaid 全局回调的统一错误出口。Step 2Rendering渲染器文档建议编写一个渲染器拿到解析阶段存储的数据后绘制图表。阅读示例时应优先看sequenceRenderer.js而不是流程图渲染器——因为它是更通用、更典型的例子流程图渲染器与 dagre 深度耦合参考价值较低。渲染器文件放在对应图表的文件夹内。Step 3Detection of the New Diagram Type图表类型检测文档指出要在新类型检测能力上动手在diagram-api/detectType.ts中注册检测器检测逻辑应返回该图表类型的 key。文档对 key 的选择给出了明确的无障碍考量对应原文中的 aria-roledescription 小节该 key 会被用作 SVG 元素的aria-roledescription因此应该是一个能清晰描述图表类型的词。举例好的 keyUMLDeploymentDiagram读屏软件会读作 U-M-L Deployment diagram好的 keydeploymentDiagram读作 Deployment Diagram差的 keydeployment描述不充分。同时注意图表类型 key不必与语法的起始关键字相同但保持一致会更友好。当前仓库中 detectType.ts 的实现比文档写作时更模块化这有助于理解注册检测器的当代形态// L12 export const detectors: Recordstring, DetectorRecord {}; // L36-L51 export const detectType function (text: string, config?: MermaidConfig): string { text text .replace(frontMatterRegex, ) .replace(directiveRegex, ) .replace(anyCommentRegex, \n); for (const [key, { detector }] of Object.entries(detectors)) { const diagram detector(text, config); if (diagram) { return key; } } throw new UnknownDiagramError( No diagram type detected matching given configuration for text: ${text} ); };要点有三检测前先剥离 front matter、%%{init}%%指令与任意注释anyCommentRegex替换为换行保证关键字识别不被前置内容干扰检测器按注册顺序遍历第一个命中者生效——registerLazyLoadedDiagramsL66-L70的注释明确警告more specific detectors at the beginning越具体的检测器要放越前面没有任何检测器命中时抛出UnknownDiagramError而非静默失败。新图表的注册入口是addDetector(key, detector, loader?)L72-L78重复 key 会覆盖并打印 warning。若采用懒加载还可传入loader使图表检测到才加载getDiagramLoader用于取回 loader。Step 4The Final Piece — Triggering the Rendering触发渲染文档描述的最后一块拼图此时 mermaid 已能把文本识别为新类型但真正调用渲染时找不到匹配项。修复方式是在main.js的init函数中的 switch 语句新增一个 case其分支值与 Step 3 返回的图表类型 key 一致case 内的代码应调用该图表类型的渲染器并把解析器收集到的数据作为参数传入。从源码结构看这一switch 分发如今落在图表加载编排模块中如 diagram-api/loadDiagram.ts 与 diagram-orchestration.ts但类型 key → 渲染函数的分发职责未变Step 3 的 key 既是检测返回值也是分发键。仓库中的 mermaid-example-diagram 包是一个完整可运行的示例把上述四步串了起来目录结构值得对照detector.ts —— Step 3 的检测器exampleDiagramRenderer.js —— Step 2 的渲染器exampleDiagramDb.js ——yy所挂载的数据模型styles.js —— Step Theming 的图表级 getStylesparser/ —— Step 1 的语法文件。解析器作为独立模块使用Usage of the Parser as a Separate Module文档单独一节说明解析器可以脱离 mermaid 渲染管线被直接调用这在编写工具链、单测或外部集成时非常有用。Setup把数据模型挂到 yy 上const graph require(./graphDb); const flow require(./parser/flow); flow.parser.yy graph;Parsing直接解析文本flow.parser.parse(text);Data extraction从数据模型读取结果graph.getDirection(); graph.getVertices(); graph.getEdges();数据模型对象graph即文档提到的graphDb暴露getDirection/getVertices/getEdges等读取接口——解析期通过yy写入、解析后通过 getter 读取这正是存储与提取两个阶段的分工。文档同时说明mermaid API 也暴露了获取解析器的途径const parser mermaid.getParser();对应地Diagram.ts 中的getParser()方法返回图表实例持有的解析器。再次强调约束解析必须有一个 graph 对象来存储数据flow.parser.yy graph不能裸调用parse。Layoutdagre 布局的模板选择文档要求若新图表采用 dagre 布局请以flowchart-v2为模板——这样做会使其使用dagre-wrapper而非正在逐步淘汰的dagreD3。这是当时一次明确的架构迁移选错模板意味着日后要跟着迁移。Common Parts of a Diagram四大通用特性文档总结了 Mermaid 各图表类型之间的共性目标是让图表在最终用户体验上尽可能一致Directives——在图表代码内部修改图表配置的方式即%%{init: ...}%%指令Accessibility——为使用读屏器访问图表的用户提供标题、描述等附加信息Themes——Mermaid 统一的样式修改体系Comments——注释应遵循 mermaid 标准%%行注释 /%%{ }%%指令见 diagram-api/regexes.ts 中的directiveRegex、anyCommentRegex。Accessibilityaria-roledescription 与 accTitle/accDescr 标准语法Mermaid 会为图表 SVG 元素自动附加三类无障碍信息aria-roledescription、可访问标题accessible title、可访问描述accessible description。aria-roledescriptionaria-roledescription会被自动设置为 Step 3 中定义的图表类型 key 并插入 SVG 元素这就是前文强调 key 必须是可读性良好的图表类型名词的原因。可访问标题与描述的统一 JISON 语法可访问标题/描述的正式语法详见 Accessibility 文档。设计目标是各图表之间 JISON 片段保持一致因此文档给出了一段标准无障碍词法块新图表语法应原样包含/* lexical grammar */ %lex %x acc_title %x acc_descr %x acc_descr_multiline %% accTitle\s*:\s* { this.begin(acc_title);return acc_title; } acc_title(?!\n|;|#)*[^\n]* { this.popState(); return acc_title_value; } accDescr\s*:\s* { this.begin(acc_descr);return acc_descr; } acc_descr(?!\n|;|#)*[^\n]* { this.popState(); return acc_descr_value; } accDescr\s*{\s* { this.begin(acc_descr_multiline);} acc_descr_multiline[\}] { this.popState(); } acc_descr_multiline[^\}]* return acc_descr_multiline_value; statement : acc_title acc_title_value { $$$2.trim();yy.setTitle($$); } | acc_descr acc_descr_value { $$$2.trim();yy.setAccDescription($$); } | acc_descr_multiline_value { $$$1.trim();yy.setAccDescription($$); }几个词法细节值得注意%x声明了三个排他性状态exclusive statethis.begin(...)/this.popState()实现进入/离开标题或描述的逐行读取(?!\n|;|#)与[^\n]*使单行值读到行尾为止并避免误吞分号与注释符accDescr支持单行accDescr: ...形式与多行accDescr { ... }两种形态多行块在遇到}时 popState 结束。语义动作中setTitle/setAccDescription是写入数据模型的两个标准入口。commonDb标题与描述由公共模块托管文档指出设置标题/描述的函数由公共模块提供并以flowDb.js的导入为例import { setAccTitle, getAccTitle, getAccDescription, setAccDescription, clear as commonClear, } from ../../commonDb;在仓库中该模块位于 diagrams/common/commonDb.ts实际导出正是clear、setAccTitle、getAccTitle、setAccDescription、getAccDescription以及setDiagramTitle/getDiagramTitle。实现上有两个值得留意的细节所有 setter 都经过sanitizeText结合getConfig()决定转义策略做清洗防止用户文本注入破坏 SVGsetAccTitle会额外剥离前导空白replace(/^\s/g, )setAccDescription会把续行缩进归一化为\n——这就是各图表共用一个 commonDb能保持跨图表一致体验的原因。文档最后说明可访问的标题与描述会在 mermaidAPI 的render函数中被插入到 SVG 元素内。Theming接入统一主题引擎Mermaid 支持主题并内置主题引擎主题用法详见 Theming 文档。为图表接入主题时文档指出代码中只有几个关键位置样式引擎的入口在src/styles.js当前仓库为 styles.ts其中getStyles函数会在 Mermaid 应用样式时被调用该函数会进一步调用你的图表应提供的、返回新图表 CSS 的函数。图表专属的getStyles通常也放在图表目录下、命名为styles.js并接收主题 options 作为参数const getStyles (options) .line { stroke-width: 1; stroke: ${options.lineColor}; stroke-dasharray: 2; } // ... ;需要把你这个函数注册进主getStyles的themes对象。当前 styles.ts 中该对象的形态为const themes: Recordstring, DiagramStylesProvider {}文档写作时的静态写法是const themes { flowchart, flowchart-v2: flowchart, sequence, xyzDiagram, ... }现改为动态注册表你的图表 key 与对应 provider 必须一一对应否则主题切换时取不到样式颜色等 options 的具体取值定义在src/theme/theme-[xyz].js。从源码结构看当前主题文件位于 themes/ 目录如theme-default.js、theme-dark.js、theme-forest.js、theme-neo.js、theme-neutral.js等。文档的建议是如果你的图表所需的 options 能塞进现有主题文件里定义主题切换就能平滑工作、不会出岔子——即优先复用现有主题变量而非硬编码颜色。小结JISON 时代的四步与 Langium 时代的衔接把文档主线与仓库证据对照JISON 新图表接入的完整链路是步骤文档要求仓库中的现实落点Step 1 语法与解析起始关键字识别 yy存储 parseError18 个diagrams/*/parser/*.jisonmermaid.ts 的parseError回调Step 2 渲染独立 renderer放在图表文件夹内参考sequenceRenderer示例见 mermaid-example-diagramStep 3 类型检测返回语义清晰的类型 key用作 aria-roledescriptiondetectType.ts 的detectors注册表 addDetectorStep 4 触发渲染init 的 switch 新增 case把解析数据传给渲染器图表加载/编排模块按 key 分发而文档头部的弃用警告同样重要JISON 路线是存量技术packages/parser中的 Langium 语言集pie、radar、packet、wardley、treeView 等 18 个*.langium语言定义代表新的标准化方向。若你要新增图表类型应以 New DiagramLangium文档 为准本文讲解的 JISON 四步流程、无障碍标准词法块与主题接入方式则用于理解存量图表的实现与维护。【免费下载链接】mermaidGeneration of diagrams like flowcharts or sequence diagrams from text in a similar manner as markdown项目地址: https://gitcode.com/GitHub_Trending/me/mermaid创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考