DESIGN.md 的 sourceMap 设计:lint 如何精确指向具体令牌路径
DESIGN.md 的 sourceMap 设计lint 如何精确指向具体令牌路径【免费下载链接】design.mdA format specification for describing a visual identity to coding agents. DESIGN.md gives agents a persistent, structured understanding of a design system.项目地址: https://gitcode.com/GitHub_Trending/de/design.mdDESIGN.md 是一款面向编程代理Coding Agent的视觉标识格式规范它把机器可读的设计令牌和人类可读的设计说明写进同一个 Markdown 文件。当你运行lint命令时每条发现Finding都带有一个path字段能精确定位到colors.primary、typography.body-md.fontSize这样的令牌路径——这背后靠的正是sourceMap源码映射这套轻量定位设计。一、先认识 lint 的路标Finding 的 path 字段运行一条命令即可校验你的 DESIGN.mdnpx google/design.md lint DESIGN.md输出的 JSON 报告里每条 finding 长这样{ severity: warning, path: components.button-primary, message: textColor (#ffffff) on backgroundColor (#1A1C1E) has contrast ratio 15.42:1 — passes WCAG AA. }path就是路标它用点分路径描述令牌在 YAML 令牌树中的位置让开发者或 AI Agent一眼知道该修哪一行配置而不是一句模糊的你的颜色有问题。path字段的类型定义非常简洁就在 model/spec.tsexport interface Finding { severity: Severity; // error | warning | info path?: string; // 令牌路径如 colors.primary message: string; rule?: string; } 注意path是可选的——结构性问题如整个文件缺少 typography 定义没有具体令牌可指此时path自然省略。二、sourceMap 数据结构三行代码定义出的定位能力sourceMap 的核心类型定义在 parser/spec.ts只有三个字段export interface SourceLocation { line: number; // 所在行 column: number; // 所在列 block: frontmatter | number; // 来源frontmatter 还是第 N 个代码块 }它作为ParsedDesignSystem的一部分随解析结果一起传递见 parser/spec.tsexport interface ParsedDesignSystem { colors?: Recordstring, any; typography?: Recordstring, Recordstring, any; // ...其他令牌分区 sourceMap: Mapstring, SourceLocation; // 顶层键 → 源位置 }这个 Map 记录的是顶层 YAML 键如colors、typography、或者写错的colours到其出生地的映射。为什么还需要block字段因为 DESIGN.md 允许把令牌写在 frontmatter 之外——正文中任意数量的yaml围栏代码块都会被合并sourceMap 能告诉规则引擎这个键到底来自哪个块从而生成第 2 个代码块里重复定义了 spacing这类精准提示。三、sourceMap 如何构建边解析边打点解析逻辑位于 parser/handler.ts流程分三步第 1 步扫描 Markdown AST收集 YAML 块及其起始行解析器使用 unified remark 系列把整篇文档解析成语法树遍历过程中记录每个 yaml 节点的行号parser/handler.tsblocks.push({ yaml: yamlNode.value, block: frontmatter, // 或代码块序号 startLine: node.position?.start.line ?? 1 });第 2 步逐块解析 YAML为每个顶层键写入 sourceMapsourceMap.set(key, { line: block.startLine, column: 0, block: block.block });见 parser/handler.ts这一行就是打点的关键动作——键名做 Key块起始行做 Value简单直接。第 3 步合并时顺便查重多个块中出现同名顶层键会直接报DUPLICATE_SECTION错误并利用 sourceMap 中的block值生成可读描述Section spacing is defined in both frontmatter and code block 2。整个流水线由 lint.ts 串联ParserHandler解析 sourceMap→ModelHandler令牌解析与符号表→runLinter规则引擎→TailwindEmitterHandler导出主题sourceMap 就诞生在第一棒供后续所有环节查询。四、消费侧 ①拼出令牌路径的 symbolTable光有顶层行号还不够。path: colors.primary这种叶子级路径来自模型层的符号表symbolTable定义见 model/spec.ts/** Flat lookup: colors.primary → ResolvedColor */ symbolTable: Mapstring, ResolvedValue;模型层通过递归遍历函数 forEachLeaf 把嵌套令牌对象拍平成点分路径background.light、typography.h1.fontSize每一个非法值报错时都会把当前路径写进 findingfindings.push({ severity: error, path: colors.${name}, message: ${raw} is not a valid color. ..., });见 model/handler.ts于是像typography.body-md.fontSize、rounded.sm这类深路径就自然形成了——路径即坐标规则、修复器、导出器共享同一套寻址方式。五、消费侧 ②sourceMap 直接驱动拼写纠错类规则sourceMap 最出彩的消费场景在unknown-key规则rules/unknown-key.ts。模型层先借 sourceMap 的键集合圈出所有非标准顶层键model/handler.tsconst unknownKeys [...input.sourceMap.keys()].filter( key !SCHEMA_KEY_SET.has(key) );规则再用Levenshtein 编辑距离阈值 ≤ 2实现见 rules/levenshtein.ts判断未知键是不是标准键的笔误你写的键编辑距离判定lint 输出colours1疑似colors笔误path: colours 提示 did you mean colors?rounding1疑似rounded笔误path: rounding 提示brand-palette远大于 2合法的自定义扩展键静默放行 ✅这种只报笔误、放过扩展键的策略让 DESIGN.md 保持了 schema 的开放性同时又不会让colours:这种低级拼写错误悄悄失效相关测试见 unknown-key.test.ts。姊妹规则token-like-ignored更进一步当一个未知键的值看起来全是十六进制色值或字号见 rules/token-like-ignored.ts说明它八成是被放错位置的令牌区同样以path指向该顶层键。六、效果演示一条 path 串联定位、诊断与修复假设你的 DESIGN.md 里有这么个 typo 和一对低对比度组件--- colours: primary: #1A1C1E components: button-primary: backgroundColor: {colors.tertiary} textColor: {colors.neutral} ---lint 报告会是{ findings: [ { severity: warning, path: colours, message: Unknown key \colours\ — did you mean \colors\? }, { severity: warning, path: components.button-primary, message: textColor (#F7F5F2) on backgroundColor (#B8422E) has contrast ratio 4.18:1, below WCAG AA minimum of 4.5:1. } ], summary: { errors: 0, warnings: 2, infos: 0 } }两条 path 各司其职colours—— 顶层键坐标来自sourceMap圈定的 unknownKeyscomponents.button-primary—— 组件级令牌路径来自symbolTable的点分寻址对比度规则实现见 rules/contrast-ratio.ts。对 AI Agent 而言这种路径 诊断 建议的结构化输出可以直接转化为编辑动作先按path定位令牌再按message判断改法。这也是 DESIGN.md 把 lint 设计成 JSON 优先的根本原因——给机器看的报告才需要精确到令牌级的坐标系。七、设计小结轻量 sourceMap 的三个取舍设计选择取舍理由只映射顶层键而非每个叶子叶子级定位交给 symbolTable 的点分路径sourceMap 保持 O(顶层键数)实现极简line取块起始行而非键的精确行解析层不深入 YAML AST 内部换取实现简单行号用于指到哪个块已足够用block区分来源而非行号区间DESIGN.md 允许多块合并块身份是比行号更稳定的身份证如果你想动手验证完整规范文档在 docs/spec.md一条命令跑起来试试npx google/design.md lint DESIGN.md延伸阅读完整格式规范docs/spec.md项目理念PHILOSOPHY.md示例设计系统examples/heritage/ 等三个示例目录lint 规则入口linter/rules/index.ts解析器实现parser/handler.ts模型与符号表model/handler.ts【免费下载链接】design.mdA format specification for describing a visual identity to coding agents. DESIGN.md gives agents a persistent, structured understanding of a design system.项目地址: https://gitcode.com/GitHub_Trending/de/design.md创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
