DESIGN.md 自定义 lint 规则教程:LintRule 接口与 runner 机制全解
DESIGN.md 自定义 lint 规则教程LintRule 接口与 runner 机制全解【免费下载链接】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 是 Google 开源的设计系统描述规范它把机器可读的设计令牌YAML front matter和人类可读的设计说明Markdown 正文结合在一个文件里让 AI 编码代理对产品的视觉身份形成持久、结构化的理解。项目自带一套命令行校验器linter本文带你完整看懂它的两大扩展点——LintRule 接口与runner 执行机制并掌握如何编写、注入自定义 lint 规则。为什么 DESIGN.md 需要 linter设计令牌文件写得再漂亮也难免出错。比如引用了不存在的令牌{colors.nonexistent}断链引用组件背景/文字色对比度低于 WCAG AA 标准4.5:1定义了颜色却没有primary代理只能自动猜测定义了颜色令牌却从未被任何组件使用linter 会对解析后的设计系统运行 11 条内置规则输出结构化 JSON 报告含errors/warnings/infos三类计数供代理和 CI 直接消费。完整规则清单见 README.md 的 “Linting Rules” 一节格式规范详见 docs/spec.md。这些内置规则各自是 packages/cli/src/linter/linter/rules/ 目录下一个独立文件但框架本身完全开放你可以向 runner 传入任意规则数组这正是编写自定义 lint 规则的前提。看懂 LintRule 接口三个核心类型全部类型定义都在 types.ts 里一共三个逐个理解即可。LintRule入状态、出发现的“纯函数”LintRule是最底层的规则形态——一个接收DesignSystemState解析后的完整设计系统状态、返回Finding[]发现数组的函数见 types.ts。它有两个关键约束只读只能读取state绝不修改它纯净无副作用、不碰网络和文件DesignSystemState是规则的“唯一事实来源”包含colors、typography、rounded、spacing、components五个 Map外加一张扁平查找表symbolTable如colors.primary直接查到解析后的颜色对象完整定义见 model/spec.ts。RuleDescriptor规则的“身份证”纯函数没法自我描述RuleDescriptor就是给函数补上元信息的包装name规则名、severity默认严重级别、description规则描述和run函数体。所有内置规则都采用这种形态例如断链引用检查broken-ref定义见 broken-ref.ts。Finding规则发现的输出格式每条发现由四个字段组成severity级别、path问题位置如components.button-primary、message可读描述、rule规则名。注意severity与rule都可以省略——框架会自动注入后文说明。runner 机制详解从规则到报告的执行引擎runner 的核心逻辑在 runner.ts 中只有两个函数机制却值得细看。runLinter自动识别规则形态并汇总结果runLinter(state, rules)接收状态和规则数组缺省使用 index.ts 中按固定顺序排列的 11 条内置规则逐条执行并汇总。它最巧妙的一点是同时兼容两种规则形态用类型守卫探测数组首元素——是带run方法的描述符就直接desc.run(state)是纯函数就直接调用为每条发现补齐缺失的severity取描述符默认值和rule名按级别统计数量生成summary这意味着同一段调用代码里你可以混用“裸函数”和“描述符”两种写法。preEvaluate按修复优先级分级preEvaluate见 runner.ts先跑完所有规则再把发现按严重级别分组成一份“分级编辑清单”分组含义对应级别fixes必须优先修复的错误errorimprovements值得改进的警告warningsuggestions纯信息性建议info这样 AI 代理拿到报告后可以“先修错误、再优化警告、最后参考建议”优先级一目了然。自定义 lint 规则实战三种典型场景场景一只运行部分规则如果不需要全部 11 条规则直接传子集即可——runner 会跳过其余规则。官方测试 runner.test.ts 就演示了“只跑 missing-primary 这一条”的用法。传空数组则完全静默返回空的发现列表。场景二写一条自己的规则一条规则本质上就是一个纯函数。比如“组件缺少 padding 定义时给出警告”function missingPadding(state: DesignSystemState): RuleFinding[] { const findings: RuleFinding[] []; for (const [name, comp] of state.components) { if (!comp.properties.has(padding)) { findings.push({ path: components.${name}, message: 组件 ${name} 未定义 padding。, }); } } return findings; }注意发现里不用写severity交给描述符或框架注入即可。场景三把自定义规则接入官方 API库入口lint()支持通过options.rules换入自己的规则集定义见 lint.ts。用法import { lint } from google/design.md/linter; const report lint(markdown, { rules: [ (state) missingPadding(state).map(f ({ severity: warning, path: f.path, message: f.message, })), ], }); console.log(report.findings); // 你的自定义规则产出的发现 console.log(report.summary); // { errors, warnings, infos } 小贴士想让某条发现使用不同于规则默认值的级别直接在发现对象上写severity字段框架会优先采用它见 index.ts 的toLintRule。内置broken-ref规则正是用这个技巧把“未知组件子令牌”从 error 降为 warning见 broken-ref.ts。想让自定义规则与内置规则共存把内置DEFAULT_RULES拼进同一个数组即可。命令行如何配合自定义规则命令行入口适合日常快速校验它运行的是内置规则集# 内置规则校验输出结构化 JSON npx google/design.md lint DESIGN.md发现 error 时退出码为 1可用作 CI 质量门禁。而自定义规则走库 API上一节的lint()两者共享同一个 runner 引擎结果格式完全一致。总结LintRule 入状态、出发现的纯函数RuleDescriptor 纯函数 名称 默认级别是规则的“身份证”runLinter自动识别两种规则形态并汇总summarypreEvaluate把结果按修复优先级分三组写规则只需一件事只读DesignSystemState返回发现数组不写任何框架代码库 API 的lint(content, { rules })是注入自定义规则的官方入口 相关源码索引规则类型定义packages/cli/src/linter/linter/rules/types.ts执行引擎packages/cli/src/linter/linter/runner.ts内置规则注册表packages/cli/src/linter/linter/rules/index.ts设计系统状态模型packages/cli/src/linter/model/spec.ts库入口含自定义规则选项packages/cli/src/linter/lint.ts规则行为测试示例packages/cli/src/linter/linter/runner.test.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),仅供参考