Mermaid Requirement Diagram 实战指南:用 SysML 语义建模需求与元素关联
Mermaid Requirement Diagram 实战指南用 SysML 语义建模需求与元素关联【免费下载链接】mermaidGeneration of diagrams like flowcharts or sequence diagrams from text in a similar manner as markdown项目地址: https://gitcode.com/GitHub_Trending/me/mermaid需求图Requirement Diagram是 Mermaid 家族中面向需求工程与系统建模的图表类型。它以文本描述需求及其相互之间、以及与其它文档化元素之间的连接关系建模规格遵循 SysML v1.6 定义。本文将以 packages/mermaid/src/docs/syntax/requirementDiagram.md 为核心骨架结合本仓库的解析器、数据库层、渲染器与形状实现源码为你完整讲解 requirement 语法、6 种需求类型、7 种关系类型、方向控制与样式系统并深入底层源码揭示每个节点与边的真实渲染原理帮助你从会画进阶到画得准、画得专业。需求图能做什么在大型项目尤其是软件需求规格说明书、系统设计文档、合规跟踪矩阵中需求往往不是孤立存在的一个功能需求可能被某个测试用例验证verifies一个设计约束可能被某个设计文档细化refines一条高层需求又可能追溯到traces若干子需求。Mermaid Requirement Diagram 正是为此而生——它允许你声明六种 SysML 需求类型requirement、functionalRequirement、interfaceRequirement、performanceRequirement、physicalRequirement、designConstraint声明轻量级element元素节点把需求关联到文档、代码文件、测试套件等外部对象用七种语义关系contains / copies / derives / satisfies / verifies / refines / traces把节点连成需求网以 Top-to-Bottom 等方向渲染并通过style、classDef精确控制每个节点的视觉表现。从源码结构看这一功能是一个完整的语法解析 数据建模 布局渲染独立子图模块位于 packages/mermaid/src/diagrams/requirement/核心代码分为四层Jison 解析器 requirementDiagram.jison、数据模型与存储 requirementDb.ts、图元类型定义 types.ts、SVG 渲染器 requirementRenderer.ts。第一个需求图Hello, Requirement渲染需求图非常直接。以requirementDiagram关键字开头然后依次声明节点与关系即可requirementDiagram requirement test_req { id: 1 text: the test text. risk: high verifymethod: test } element test_entity { type: simulation } test_entity - satisfies - test_req这段代码声明了一个名为test_req的需求携带 id、text、risk、verifymethod 四个属性一个名为test_entity的元素以及一条从元素指向需求的satisfies满足关系。你可以在官方演示页 demos/requirements.html 或直接复制上述代码到支持 Mermaid 的环境中查看渲染效果仓库的 e2e/diagrams/requirement/sample.mmd 保存着结构相同的可直接运行的验证样例。语法总览三类组件与两条铁律一张需求图只包含三类组件requirement需求、element元素、relationship关系。每条定义都遵循固定的文法。理解文法前先记住两个通用要点尖括号词汇是可枚举关键字。文档中用word如risk、type、method表示的词汇取值都有明确枚举表而user_defined_...表示任何用户可自由输入的位置。关于文本引号的重要约定所有用户输入都可以加引号也可以不加。例如id: here is an example与id: here is an example都合法。但不加引号的输入要格外小心——解析器在输入中一旦检测到其它关键字就会解析失败。实践建议包含空格、特殊符号或疑似与关键字冲突的内容一律用双引号包裹。这一规则在解析器词法定义中有直接体现requirementDiagram.jison 中为引号串与裸串分别建立了string、unqString词法状态其中裸串的正则L99显式排除了:、,、{、}、、、-、等字符而关键字 token如id、risk、low、contains在词法匹配中优先级更高——这正是不加引号时撞上关键字即报错的底层原因。声明 Requirement六种类型与四大属性一条需求定义包含需求类型、名称name、id、text、risk、验证方法verification method语法如下type user_defined_name { id: user_defined_id text: user_defined text risk: risk verifymethod: method }其中 type、risk、method 三处都是 SysML 定义的枚举值关键字可选值Typerequirement、functionalRequirement、interfaceRequirement、performanceRequirement、physicalRequirement、designConstraintRiskLow、Medium、HighVerificationMethodAnalysis、Inspection、Test、Demonstration上表与 requirementDb.ts 中定义的枚举常量一一对应需求类型映射为RequirementType其展示文案为 Requirement、Functional Requirement 等带空格的人性化名称risk 映射为RiskLevelLow / Medium / High验证方法映射为VerifyTypeAnalysis / Demonstration / Inspection / Test。在 types.ts 中它们被收窄为 TypeScript 联合类型RequirementType六种需求类型的字符串字面量联合RiskLevelLow | Medium | HighVerifyTypeAnalysis | Demonstration | Inspection | Test。值得一提的底层细节是单个属性的顺序并不强制。requirementDiagram.jison 中requirementBody的文法允许 id / text / risk / verifyMethod 以任意顺序递归拼接解析时通过setNewReqId、setNewReqText、setNewReqRisk、setNewReqVerifyMethod分别写入当前草稿需求并在addRequirement落库后调用resetLatestRequirement()清空草稿——所以你不必死记属性书写顺序。另外注意词法分析采用%options case-insensitiveL7因此RISK、risk、Risk均被识别。声明 Element轻量挂载点元素定义包含元素名称、类型与文档引用三者均为用户自定义内容。设计意图是让 element 保持轻量同时允许把需求连接到其它文档的某个片段element user_defined_name { type: user_defined_type docref: user_defined_ref }其中type与docref都可有可无——从 requirementDb.ts 的getInitialElement()可以看到默认值为空字符串。语法层面元素体仅包含TYPE与DOCREF两条属性规则requirementDiagram.jison因此即使写成element test_elem { }空体也合法本仓库样式章节的示例正是如此用法。值得注意文档关键字写作docref全小写而示例代码中常写作docRef。由于解析器大小写不敏感两种写法皆可。元素名、类型、文档引用同需求一样支持引号与 Markdown 排版。Markdown 格式化与富文本标签凡是允许用户自定义文本的位置节点名称、需求 text、元素 docref 等你都拥有两种增强手段用双引号包围文本example text在引号内使用 Markdown 格式**bold text** and *italics*。例如requirementDiagram requirement __test_req__ { id: 1 text: *italicized text* **bold text** risk: high verifymethod: test }该特性在渲染链路中获得完整支持渲染时 requirementRenderer.ts 把整张图交给统一渲染管线节点文本经由 requirementBox.ts 的addText()通过createText生成标签分类为markdown-node-label即按 Markdown 标签渲染同时文本会先经sanitizeText与decodeEntities处理以保证安全。需要说明的是__test_req__这类外层文本中的下划线强调是否生效取决于 HTML 标签htmlLabels配置若关闭 HTML 标签则退化为纯文本输出。声明 Relationship七种语义关系与双向写法关系由源节点、目标节点与关系类型三部分组成两种书写方向等价{name of source} - type - {name of destination}或反向{name of destination} - type - {name of source}其中源/目标必须是前面已定义的 requirement 或 element 节点名。关系类型共七种contains、copies、derives、satisfies、verifies、refines、traces定义于 requirementDb.ts 的Relationships常量。每条关系都会在图上打上标签即类型。先看一个直观例子test_req - copies - test_entity2与test_entity2 - copies - test_req完全等价关系方向由箭头指向决定。源码层面最有趣的差异在视觉呈现查看 requirementDb.ts 中getData()对关系的边Edge构建逻辑会发现contains包含是唯一的实线关系其它六种关系一律渲染为虚线并通过stroke-dasharray: 10,7实现箭头形态也不同contains在起始端使用填充菱形端点requirement_contains代表聚合/整体-部分其余关系在结束端使用普通箭头requirement_arrow。这与 SysML 中 containment 用实线组合、其它关系用虚线的约定一致也是区分结构从属与行为/文档关联的视觉信号。综合大示例用满所有能力下面这段示例同时用到了六种需求类型、三类 element 与全部七种关系中的六种适合作为自检模板直接复制运行requirementDiagram requirement test_req { id: 1 text: the test text. risk: high verifymethod: test } functionalRequirement test_req2 { id: 1.1 text: the second test text. risk: low verifymethod: inspection } performanceRequirement test_req3 { id: 1.2 text: the third test text. risk: medium verifymethod: demonstration } interfaceRequirement test_req4 { id: 1.2.1 text: the fourth test text. risk: medium verifymethod: analysis } physicalRequirement test_req5 { id: 1.2.2 text: the fifth test text. risk: medium verifymethod: analysis } designConstraint test_req6 { id: 1.2.3 text: the sixth test text. risk: medium verifymethod: analysis } element test_entity { type: simulation } element test_entity2 { type: word doc docRef: reqs/test_entity } element test_entity3 { type: test suite docRef: github.com/all_the_tests } test_entity - satisfies - test_req2 test_req - traces - test_req2 test_req - contains - test_req3 test_req3 - contains - test_req4 test_req4 - derives - test_req5 test_req5 - refines - test_req6 test_entity3 - verifies - test_req5 test_req - copies - test_entity2不难看出这种文本化建模可以自然表达一套典型的需求追溯矩阵父需求test_reqtraces追溯到子功能需求test_req2同时contains包含性能需求test_req3性能需求再层层细分为test_req4 → test_req5 → test_req6最终由测试套件元素test_entity3verifies验证物理需求。仓库配套的真实用例 packages/examples/src/examples/requirement.ts 中也有类似结构的渲染示例可供对照。控制渲染方向direction 语句需求图默认自上而下渲染可通过direction语句调整布局方向合法取值TB—— Top to Bottom自上而下默认BT—— Bottom to Top自下而上LR—— Left to Right从左到右RL—— Right to Left从右到左示例requirementDiagram direction LR requirement test_req { id: 1 text: the test text. risk: high verifymethod: test } element test_entity { type: simulation } test_entity - satisfies - test_req方向信息在数据库层的默认值为TB见 requirementDb.ts 的private direction TB解析器把四个方向的词法 token 逐一映射为yy.setDirection(TB | BT | RL | LR)requirementDiagram.jison最终通过getData()返回的direction字段交给布局算法决定节点是纵向排布还是横向排布。样式系统从直接改色到可复用类需求与元素均支持直接样式与类样式两种手段。作为经验法则style/classDef/class等语句接受一个节点名列表与一个类名列表支持一次给多个节点/类同时赋值唯一例外是:::速记语法——它一次只能作用于一个节点但可以为该节点同时挂多个类。直接样式Direct Styling用style关键字直接施加 CSS 样式可同时列出多个节点并以逗号分隔多个样式项requirementDiagram requirement test_req { id: 1 text: styling example risk: low verifymethod: test } element test_entity { type: simulation } style test_req fill:#ffa,stroke:#000, color: green style test_entity fill:#f9f,stroke:#333, color: blue类定义classDef用classDef定义可复用样式随后可将任意节点关联到该类requirementDiagram requirement test_req { id: 1 text: class styling example risk: low verifymethod: test } element test_entity { type: simulation } classDef important fill:#f96,stroke:#333,stroke-width:4px classDef test fill:#ffa,stroke:#000默认类default class只要某个类被命名为default它就会自动应用到所有节点classDef default fill:#f9f,stroke:#333,stroke-width:4px;具体样式或类应在默认类之后定义从而覆盖默认样式。该机制的实现证据同样在 requirementDb.ts无论 requirement 还是 element其初始classes数组都预置了[default]getData()把cssClasses classes.join( )写到节点上而先写默认类、后追加具体类的方式天然保证了后者可覆盖前者。应用类Applying Classes两种语法方式一使用class关键字一次性把多个节点关联到多个类下面的写法等价于class test_req important加class test_entity importantclass test_req,test_entity important方式二使用:::速记既可在节点定义时内联挂类也可在定义后单独给单个节点挂类requirement test_req:::important { id: 1 text: class styling example risk: low verifymethod: test }element test_elem { } test_elem:::myClass综合样式示例把直接样式与类样式叠加使用可精确控制每个节点的最终外观requirementDiagram requirement test_req:::important { id: 1 text: class styling example risk: low verifymethod: test } element test_entity { type: simulation } classDef important font-weight:bold class test_entity important style test_entity fill:#f9f,stroke:#333样式系统的源码实现样式并不只是渲染时贴字符串那么简单它牵涉一个三级流水线。文法层面requirementDiagram.jisonstyle、classDef、class关键字分别落到styleStatement、classDefStatement、classStatement规则样式的 CSS 片段被切分为styleComponent字母、数字、冒号、#、-、%、分号等 token后拼装回字符串。数据层面requirementDb.tssetCssStyle(ids, styles)负责style语句把样式按,拆开推入目标节点的cssStylesdefineClass(ids, style)负责classDef会把包含color的样式项单独拆出textStyles用于文字着色并把类内样式实时同步到所有已挂载该类的节点setClass(ids, classNames)负责class与:::将类名写入节点classes的同时把该类已注册样式合并进节点cssStyles。主题变量层面styles.js 定义了若干与主题强相关的选择器requirementBackground、requirementBorderColor、requirementBorderSize、requirementTextColor、relationColor、relationLabelBackground等——这意味着直接改主题变量即可全局换肤genColor还会依据themeVariables.borderColorArray/bkgColorArray为不同节点生成按colorIndex轮换的着色方案。此外在 neo 外观下关系线宽采用options.strokeWidth经典外观下为1px。一张图的完整生命周期解析 → 建模 → 布局 → 绘制为便于你排查问题或为 Mermaid 做二次开发这里梳理需求图从文本到 SVG 的四层流水线与本仓库源码逐一对应解析Parse入口由 requirementDiagram.ts 注册提供 Jison 解析器、RequirementDB、渲染器与样式。检测器 requirementDetector.ts 识别首行关键字requirementDiagram后分发到本模块。建模DBrequirementDb.ts 以 Map 结构保存 requirements 与 elements、数组保存 relations 与 classes。其初始值刻意将每个节点的类设为[default]由此保证默认类应用于全部节点。getData()把内部模型统一投影为布局引擎的Node[]/Edge[]并为每个节点设置shape requirementBox。布局LayoutrequirementRenderer.ts 从全局配置读取layout决定 dagre 或 elk 等已注册布局算法、lookclassic / neo / handDrawn 等外观、nodeSpacing默认 50、rankSpacing默认 50并把箭头 marker 区分为neo与经典两套requirement_contains(_neo)/requirement_arrow(_neo)。绘制Render节点形状由 requirementBox.ts 完成——矩形框内自上而下依次渲染类型头、加粗的节点名然后是需求属性行ID:/Text:/Risk:/Verification:或元素属性行Type:/Doc Ref:最后按内容是否溢出决定是否追加分隔线。边框填充采用 rough.js 绘制当look非 handDrawn 时强制roughness 0、实心填充以获得规整的直角矩形。另外该图类型完整支持公共能力title图标题、accTitle与accDescr无障碍标题/描述在词法与文法中均有对应规则requirementDiagram.jison渲染时标题位置受titleTopMargin默认 25控制输出尺寸受useMaxWidth约束。质量保障解析与渲染都有测试兜底需求图并非孤例实验性功能仓库内有一整套测试体系为其保驾护航单元级解析测试 requirementDiagram.spec.js 覆盖各种合法/非法输入数据库行为测试 requirementDb.spec.ts 验证节点/关系/类的增删与样式合并逻辑端到端渲染测试 requirementDiagram-unified.spec.js 与 neo 主题测试 requirementDiagram-neo-themes.spec.ts 会把渲染结果与快照对比可直接运行的样例 e2e/diagrams/requirement/sample.mmd 体现了需求元素的典型追溯场景satisfies / traces / contains / copies。常见坑与最佳实践小结基于文档约定与源码行为给出几条实操建议文本一律加引号更稳妥id、text、type、docRef、名称等字段只要含空格、标点或可能命中关键字如值为test、high、contains等务必用...包裹解析器大小写不敏感大小写混写不会规避关键字冲突。属性顺序可任意需求体与元素体内部属性可以乱序书写但关键字 tokenid:、text:等与值之间需保持键: 值且每行一个的形态。善用contains的语义它渲染为实线 组合菱形端点适合表达结构分解其余六种均为虚线 普通箭头适合表达追溯与验证类关联二者视觉差异天然帮你区分组成与关联。先classDef default再写专项样式默认类会被自动应用到全部节点在其后定义的具体样式或类即可覆盖它实现全局基调 局部强调。复杂需求网配合direction LR节点横向排布通常能显著缓解长文本需求矩形导致的纵向堆叠问题。至此从基础语法到七种关系、六种需求类型再到样式系统与源码级渲染原理你已经掌握了 Mermaid Requirement Diagram 的完整使用栈。把它用起来你的需求文档就能以可维护的纯文本形式获得一份可读、可检索、可持续演进的需求关系图。【免费下载链接】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),仅供参考