资讯动态

markdownlint 有序列表序号前缀规则(MD029 / ol-prefix)实战:ordered 风格与括号分隔符场景详解

发布时间:2026/10/16 9:16:16 来源:尧图企业网站定制
开发工具代码质量Lint静态分析【免费下载链接】markdownlintA Node.js style checker and lint tool for Markdown/CommonMark files.项目地址https://gitcode.com/gh_mirrors/ma/markdownlint点击查看免费下载本文以 markdownlint 仓库中的测试场景文档 test/ordered_list_item_prefix_ordered-paren.md 为骨架系统讲解 MD029ol-prefix有序列表序号前缀规则的完整行为四种style配置的差异、1)这种括号分隔符前缀的解析方式、!-- markdownlint-configure-file --文件级配置注释的用法以及自动修复fixInfo/applyFixes背后的源码实现。读完本文你将能精确掌控有序列表编号风格并理解如何用源码与测试用例验证该规则的所有边界行为。一、场景文档在讲什么test/ordered_list_item_prefix_ordered-paren.md是 markdownlint 测试体系中的一份场景测试scenario用例它用最简短的 Markdown 片段定义了一个清晰的正反例对照# ordered_list_item_prefix_ordered-paren Good list: 1) Do this. 2) Do that. 3) ??? 4) Profit! Bad list: 1) Do this. 1) Do nothing. {MD029} 1) ??? {MD029} 1) Failed! {MD029} !-- markdownlint-configure-file { ol-prefix: { style: ordered } } --这份文档一次性地覆盖了三个知识要点规则本体MD029别名ol-prefix要求有序列表的编号前缀符合某种既定风格配置方式style被配置为ordered即要求编号必须从 1 开始并逐项递增测试约定行尾{MD029}是测试脚手架声明这一行应当报 MD029 错误的标记见下文测试体系一节。其中Good list四个前缀依次为1) 2) 3) 4)完全符合递增要求而Bad list四个前缀全部写成了1)从第二项开始不再递增因此第二至第四行各触发一次 MD029。值得留意的是这份文档特意选用了括号分隔符1)而不是常见的点号1.。它在仓库中还有一份几乎逐字相同的姊妹用例 test/ordered_list_item_prefix_ordered.md使用1.写法两者唯一区别就是分隔符。这说明 MD029 的检查逻辑与分隔符类型无关——无论1.还是1)规则只关心前缀中的数值部分。二、MD029 规则参数、语义与默认行为2.1 规则元信息按规则文档 doc/md029.md 的记载名称MD029别名ol-prefix标签Tagsol可修复性部分违规可由工具自动修复Fixable: Some violations can be fixed by tooling参数style字符串类型默认one_or_orderedstyle的合法取值共有四种style取值要求编号形态示例源码中的示例标签one所有编号都必须是11. / 1. / 1.1/1/1ordered编号从 1 开始逐项递增1. / 2. / 3.1/2/3one_or_ordered默认全1或递增均可两者都接受—zero所有编号都必须是00. / 0. / 0.0/0/0对应的实现位于 lib/md029.mjs 第 7~12 行const listStyleExamples { one: 1/1/1, ordered: 1/2/3, zero: 0/0/0 }; const listStyles Object.keys(listStyleExamples);其中1/1/1、1/2/3、0/0/0正是规则报错信息errorDetail中Style:后缀所展示的内容可对照测试快照验证。2.2 规则语义规则文档对 MD029 的触发条件描述如下有序列表若没有以1.开头或编号没有按数值顺序递增具体取决于配置的 style就会触发本规则同时它也支持较少见的0.前缀模式既可作为首个前缀也可用于全部前缀。style: one时的合法列表1. Do this. 1. Do that. 1. Done.style: ordered时的合法列表1. Do this. 2. Do that. 3. Done.0. Do this. 1. Do that. 2. Done.三种写法在one_or_ordered下全部合法style: zero时的合法列表0. Do this. 0. Do that. 0. Done.所有 style 下都非法的示例编号既不统一也不递增1. Do this. 3. Done.此外规则还支持用 0 补齐位数的编号前缀例如... 08. Item 09. Item 10. Item 11. Item ...这种08. / 09. / 10.的写法常用于让多位数编号在视觉上对齐同样纳入 MD029 的检查范围。2.3 默认 style 的自动判定逻辑在默认的one_or_ordered模式下规则并非简单地都放行而是会根据列表的实际形态自动推断出更贴切的风格然后按该风格严格校验。相关逻辑在 lib/md029.mjs 第 38~57 行let expected 1; let incrementing false; // Check for incrementing number pattern 1/2/3 or 0/1/2 if (listItemPrefixes.length 2) { const first getOrderedListItemValue(listItemPrefixes[0]); const second getOrderedListItemValue(listItemPrefixes[1]); if ((second.value ! 1) || (first.value 0)) { incrementing true; if (first.value 0) { expected 0; } } } // Determine effective style const listStyle listStyles.includes(style) ? style : (incrementing ? ordered : one); if (listStyle zero) { expected 0; } else if (listStyle one) { expected 1; }从源码结构可以推断出默认模式的判定策略列表至少有 2 项时比较第一个与第二个前缀数值若第二个前缀不等于1或第一个前缀是0则判定为递增型incrementing true自动套用ordered风格校验起点期望值取第一个前缀的值0则从 0 起否则从 1 起否则判定为one风格要求所有编号均为1。这解释了为何ordered风格下0. / 1. / 2.也是合法列表——规则对以 0 起始的递增序列给予了支持。2.4 违规示例与源码级修复信息对本文开头Bad list部分规则为每一处违规生成如下结构的错误对象摘录自 test/markdownlint-test-scenarios.mjs.snapshot 中ordered_list_item_prefix_ordered-paren.md的测试快照{ lineNumber: 13, ruleNames: [ MD029, ol-prefix ], ruleDescription: Ordered list item prefix, errorDetail: Expected: 2; Actual: 1; Style: 1/2/3, errorRange: [ 1, 3 ], fixInfo: { editColumn: 1, deleteCount: 1, insertText: 2 }, severity: error }第二行1) Do nothing.期望值为 2、实际值为 1第三行期望 3、第四行期望 4。该错误对象的生成逻辑位于 lib/md029.mjs 第 59~81 行其中修复信息按以下规则构造const fixInfo { editColumn: orderedListItemValue.column, deleteCount: orderedListItemValue.value.toString().length, insertText: expected.toString() };即在编号数值的起始列editColumn删除掉实际数值全部位数deleteCount再插入期望值insertText。这正是自动修复能精准工作的基础——例如把1)原地改成2)、3)、4)。三、1)括号分隔符解析层面如何工作3.1 micromark 解析器与 token 结构markdownlint 采用micromark解析器并按 CommonMark 规范解析 Markdown。MD029 内部通过 helpers/micromark-helpers.cjs 提供的getDescendantsByType遍历 token 树function getDescendantsByType(parent, typePath) { let tokens Array.isArray(parent) ? parent : [ parent ]; for (const type of typePath) { const predicate (token) Array.isArray(type) ? type.includes(token.type) : (type token.type); tokens tokens.flatMap((t) t.children.filter(predicate)); } return tokens; }该辅助函数按 token 类型路径逐层向下收集后代节点。在 lib/md029.mjs 中MD029 用它取出所有有序列表 token、每个列表的listItemPrefix以及前缀内部的listItemValuefor (const listOrdered of filterByTypesCached([ listOrdered ])) { const listItemPrefixes getDescendantsByType(listOrdered, [ listItemPrefix ]); ... }function getOrderedListItemValue(listItemPrefix) { const listItemValue getDescendantsByType(listItemPrefix, [ listItemValue ])[0]; return { column: listItemValue.startColumn, value: Number(listItemValue.text) }; }3.2 为什么1)与1.走同一套逻辑从 token 结构看micromark 把1.和1)这类前缀统一拆成独立的listItemPrefix节点数值部分再作为listItemValue子节点单独暴露getOrderedListItemValue只读取listItemValue.text并做Number(...)转换完全不关心前缀后面的分隔符是点号还是右括号。因此1) Do this. / 2) Do that. / 3) ??? / 4) Profit!判定为合法1) Do this. / 1) Do nothing. / ...判定为违规报错信息与1.版本完全一致。这一点可以由仓库中两份几乎同构的测试文件交叉印证ordered_list_item_prefix_ordered-paren.md括号版与 test/ordered_list_item_prefix_ordered.md点号版在测试快照中产生的错误行号、errorDetailExpected: 2; Actual: 1; Style: 1/2/3乃至修复后的fixed内容都一一对应仅分隔符字符不同。四、!-- markdownlint-configure-file --文件级规则配置4.1 语法与作用范围场景文档末尾的 HTML 注释是 markdownlint 提供的文件级配置机制!-- markdownlint-configure-file { ol-prefix: { style: ordered } } --按 README.md 中的说明该指令的语法为配置!-- markdownlint-configure-file { options.config JSON } --要点如下注释内承载一段options.config格式的 JSON用于调整一个或多个规则的配置配置对整个文件生效与注释所处位置无关若文件中有多个此类注释则自上而下依次应用默认按 JSON 解析也可通过options.configParsers支持其他格式注释内容不会被渲染成可见的 HTML。例如 README.md 中给出的等价多行写法!-- markdownlint-configure-file { hr-style: { style: --- }, no-trailing-spaces: false } --场景文档中采用单行紧凑 JSON 写法配置ol-prefix: { style: ordered }效果等价于在lint调用的options.config中传入{ MD029: { style: ordered }, ol-prefix: { style: ordered } }4.2 与整文件禁用指令的区分同样出现在文件中的 HTML 注释指令还包括见 README.md!-- markdownlint-disable --/!-- markdownlint-enable --禁用/启用所有规则!-- markdownlint-disable-line --/!-- markdownlint-disable-next-line --仅影响当前行/下一行!-- markdownlint-disable-file MD001 MD005 --/!-- markdownlint-enable-file MD001 MD005 --按规则名禁用/启用整个文件!-- markdownlint-capture --/!-- markdownlint-restore --捕获并恢复规则配置!-- markdownlint-configure-file { ... } --修改文件级规则配置其中markdownlint-configure-file的独特之处在于它不是关闭规则而是改变规则参数——这正是测试场景能在一个文件里既展示ordered 风格下的合法列表又展示违规列表的原因整个文件都在style: ordered的约束下接受校验。4.3 配置解析实现配置注释的解析由parse-configuration.mjs等相关模块处理lib/parse-configuration.mjs支持多种配置来源JSON/JSONC/YAML/TOML/INI 等格式并同时接受规则编号MD029与规则别名ol-prefix两种键名。在 doc/md029.md 的参数表中style参数合法值被明确限定为one/one_or_ordered/ordered/zero四种仓库中另有专门测试 test/invalid-ul-style-style.md 之类的用例来覆盖非法取值场景对应 MD004/MD030 系列的风格参数校验MD029 的style同理受到类型与取值范围的校验约束。五、测试体系场景文档如何被自动化验证5.1 测试驱动与{MD029}标记约定test/ordered_list_item_prefix_ordered-paren.md不是给人阅读的普通文档而是由测试脚手架消费的输入。其测试驱动位于 test/markdownlint-test-scenarios.mjsfunction createTestForFile(file) { return (t) ( Promise.all([ fs.readFile(file, utf8), lint({ files: [ file ] }) ]) ... ); }关键流程为读取./test目录下所有.md文件逐个调用lint({ files: [ file ] })用正则/\{(MD\d)(?::([-]?)(\d))?\}/g扫描文档中的{MD029}标记把出现标记的行号解析为期望报错位置将实际 lint 结果与期望位置逐一比对t.assert.deepEqual(actual, expected, ...)对每条错误执行applyFixes(content, errors)生成修复后的文档并与快照对比最后对修复结果再次 lint断言可修复的错误全部被修复t.assert.deepEqual(unfixed, [], ...)。因此文档第 13、14、15 行的{MD029}标记分别声明了这三行必须各自触发一次 MD029 错误。若规则行为发生变化测试会立即失败从而起到规则行为契约的作用。5.2 快照与自动修复验证测试快照 test/markdownlint-test-scenarios.mjs.snapshot 中保存了本场景的完整预期结果。对ordered_list_item_prefix_ordered-paren.md而言第 13~15 行各报告一条错误errorDetail依次为Expected: 2; Actual: 1; Style: 1/2/3、Expected: 3; Actual: 1; Style: 1/2/3、Expected: 4; Actual: 1; Style: 1/2/3自动修复applyFixes后的文档把Bad list改为1) Do this. 2) Do nothing. {MD029} 3) ??? {MD029} 4) Failed! {MD029}即所有编号被原地改写为 2、3、4 的递增序列快照同时断言修复后的文档再 lint 不会残留任何可修复错误。5.3 相邻测试用例构成的矩阵test/目录下围绕有序列表前缀还有一组同族用例共同构成 MD029 的行为矩阵测试文件配置的style覆盖要点test/ordered-list-item-prefix-one.mdone全1.合法递增、乱序、0.开头均报错test/ordered-list-item-prefix-ordered.mdordered1./2./3.合法0./1./2.也合法重复编号、跳号报错test/ordered-list-item-prefix-zero.mdzero全0.合法其余编号一律报错test/ordered-list-item-prefix-zero-alternate.mdzero全0.合法1./递增序列均报错test/ordered-list-item-prefix-double-digits-ordered.mdordered多位数9→10→11递增合法跳号、倒序报错0.后接10.报错test/ordered-list-item-prefix-sublists-ordered.mdordered嵌套子列表父子列表各自独立递增校验test/ordered_list_item_prefix.mdone点号分隔符 one风格本场景的点号镜像test/ordered_list_item_prefix-paren.mdone括号分隔符 one风格test/ordered_list_item_prefix_ordered.mdordered点号分隔符 ordered风格本文场景test/ordered_list_item_prefix_ordered-paren.mdordered括号分隔符 ordered风格由此可以得到一个非常实用的结论MD029 的检查完全由配置的 style 前缀数值序列决定与分隔符.或)无关而嵌套列表中父子两层列表是各自独立计数的ordered风格下子列表也从 1 重新开始。六、实际使用命令行与 API 集成6.1 安装与命令行检查markdownlint 本体是 Node.js 库安装方式见 README.mdnpm install markdownlint --save-dev命令行场景通常配合 markdownlint-cli 等 CLI 工具使用直接用 Node.js API 时核心调用是lintimport { lint } from markdownlint/promise; const results await lint({ files: [ path/to/ordered_list_item_prefix_ordered-paren.md ] });规则默认全部开启。若要全局统一 MD029 风格可在options.config中配置import { lint } from markdownlint/promise; const results await lint({ files: [ docs/**/*.md ], config: { MD029: { style: ordered // 或 one / one_or_ordered / zero } } });由于MD029与ol-prefix是同一规则的两个名称配置时二者等价。6.2 自动修复MD029 被 lib/constants.mjs 中的fixableRuleNames标记为可修复规则测试代码在 test/markdownlint-test-scenarios.mjs 中断言所有带fixInfo的错误必须属于可修复规则集合。配合applyFixes即可自动修正编号import { lint } from markdownlint/promise; import { applyFixes } from markdownlint; const results await lint({ files: [ doc.md ] }); const errors results[doc.md]; if (errors.length 0) { const fixed applyFixes(markdownContent, errors); // 将 fixed 写回文件即可完成自动修复 }需要说明的修复语义在ordered风格下applyFixes会把违规编号依次改写为期望的递增序列如 2、3、4在one风格下则把所有编号统一改写为1。以本文场景为例修复结果与快照中fixed字段一致且修复后重新 lint 不再有任何可修复错误。6.3 项目级配置示例若希望在项目全局使用ordered风格同时为个别文件保留默认的one_or_ordered宽松模式可以结合两种机制全局在options.config或.markdownlint.json等配置文件中设置MD029: { style: ordered }单文件在该文件内使用!-- markdownlint-configure-file { ol-prefix: { style: one_or_ordered } } --覆盖为宽松模式。文件级配置优先于全局配置这正是markdownlint-configure-file指令最具实用价值之处。七、已知注意事项与边界情况规则文档 doc/md029.md 特别提醒了一类容易误报的情况当两个列表项之间出现缩进不当的代码块或类似结构时解析器会认为列表被拦腰截断成两个列表从而对第二个列表重新编号校验1. First list text Code blockSecond list以上代码块未缩进导致列表断裂。修复方式是把代码块缩进到所属列表项内部 markdown 1. First list text Code blockStill first list缩进后的代码块成为第一个列表项的一部分后续编号继续递增为 2列表不再断裂。这条经验对为什么我的有序列表突然从 1 重新开始类问题非常关键——**多数情况下不是规则误报而是文档结构本身被解析成了两个列表**。 ## 八、小结 围绕 test/ordered_list_item_prefix_ordered-paren.md 这一场景文档可以提炼出 MD029 规则的完整知识图谱 1. MD029ol-prefix负责校验有序列表编号前缀style 有 one / ordered / one_or_ordered / zero 四种取值默认 one_or_ordered 会根据列表实际形态自动选择更严格的判定方式[lib/md029.mjs](https://link.gitcode.com/i/3462d7f10447e8d8dab16932bc5e591d) 2. 括号分隔符 1) 与点号分隔符 1. 在解析与校验上完全等价规则只读取前缀的数值部分 3. !-- markdownlint-configure-file -- 可对单个文件覆盖规则配置是本场景中 style: ordered 生效的载体 4. {MD029} 行内标记配合 [test/markdownlint-test-scenarios.mjs](https://link.gitcode.com/i/a9c3a8d522dea4314fcd91d4b0ddcdcc) 与快照文件构成规则行为的自动化契约保证实现与文档、测试三者一致 5. MD029 支持自动修复且修复后文档可再次通过 lint 校验。 在编写或审查 Markdown 文档时只要把握编号要么全 1、要么从 1或 0严格递增、要么全 0三条铁律并留意代码块缩进对列表连续性的影响即可完全掌控 markdownlint 对有序列表的检查行为。赞分享开发工具代码质量Lint静态分析【免费下载链接】markdownlintA Node.js style checker and lint tool for Markdown/CommonMark files.项目地址https://gitcode.com/gh_mirrors/ma/markdownlint点击查看免费下载相关推荐CCX 前端工程 ESLint 配置全解Vue 3 TypeScript 的 Flat Config 实践CCX 前端工程 ESLint 配置全解Vue 3 TypeScript 的 Flat Config 实践 CCXClaude / Codex / Ge开发工具代码质量Lint静态分析markdownlint MD029ol-prefix有序列表编号风格检查规则详解markdownlint MD029ol prefix有序列表编号风格检查规则详解 MD029 是 markdownlint 提供的有序列表项编号前缀开发工具代码质量Lint静态分析markdownlint MD029 有序列表编号前缀规则ol-prefix深度解析与实战指南markdownlint MD029 有序列表编号前缀规则ol prefix深度解析与实战指南 导读 MD029 是 markdownlint 中负责校验开发工具代码质量Lint静态分析上一篇Kivy 属性系统Properties完全指南声明式属性、自动事件分发与内存优化下一篇chezmoi 的 promptStringOnce 模板函数详解在 init 阶段记忆式收集字符串配置创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑