- 开发工具
- 代码质量
- Lint
- 静态分析
【免费下载链接】markdownlint
A Node.js style checker and lint tool for Markdown/CommonMark files.
本指南以 markdownlint 仓库中的规则测试样例 test/no-multiple-blanks.md 及其配套文档 doc/md012.md 为核心,完整讲解 MD012(别名no-multiple-blanks)规则的检测语义、maximum参数配置、代码块豁免逻辑与自动修复机制。读完本文,你将能独立阅读该规则的标记式测试文件、准确预判每一个报错行号,并在自己的项目中用maximum定制空行上限或通过applyFixes一键修复。
规则速览:标签、别名与参数
MD012 是 markdownlint 内置的"多个连续空行"检查规则,其正式定义位于 doc/md012.md(同时收录于规则总表 doc/Rules.md):
- 名称 / 别名:
MD012、no-multiple-blanks - 标签(Tags):
blank_lines、whitespace - 参数(Parameters):
maximum,类型integer,默认值1,表示允许的连续空行最大数量 - 可修复性(Fixable):部分违规可由工具自动修复
该规则的触发条件是文档中出现连续多个空行。按默认配置,正文之间只允许保留 1 个空行,出现 2 个及以上连续空行即构成违规:
Some text here Some more text here修复方式为删除多余空行:
Some text here Some more text here规则设计者的理由(Rationale)写得很明确:除了代码块内部之外,空行不承载任何渲染语义,连续堆叠空行没有任何用途。这也是它在默认规则集中保持开启的核心理由。
阅读测试文件的标记约定
markdownlint 仓库的规则测试文件采用一种"内联期望标记"约定:每一处预期报错都用{MD012:行号}形式直接写在测试文本中,由测试框架 test/markdownlint-test-scenarios.mjs 解析(其标记正则位于该文件第 40 行),并与真实 lint 结果逐一比对;最终比对结果固化在快照文件 test/markdownlint-test-scenarios.mjs.snapshot 中。因此,测试文件里每一行{MD012:n}都是"该行号处应报 MD012"的声明,是我们理解规则行为的权威教材。
逐行拆解 no-multiple-blanks.md 测试样例
关联文档 test/no-multiple-blanks.md 全文 24 行,在默认配置(maximum = 1)下逐行分析如下:
| 行号 | 内容 | 分析 |
|---|---|---|
| 1 | # Heading | 非空行,计数清零 |
| 2 | (空行) | 计数 1,未超过上限 |
| 3 | Text | 非空行,计数清零 |
| 4 | (空行) | 计数 1,未超过上限 |
| 5 | Text | 非空行,计数清零 |
| 6–7 | 连续 2 个空行 | 第 7 行计数达到 2,报{MD012:7} |
| 8 | Text | 计数清零 |
| 9–11 | 连续 3 个空行 | 第 10 行计数 2 报错,第 11 行计数 3 报错 |
| 12 | Text | 计数清零 |
| 13–16 | 连续 4 个空行 | 第 14、15、16 行分别以计数 2、3、4 各报一次 |
| 17 | Text | 计数清零 |
| 18 | (空行) | 计数 1,未超过上限 |
| 19 | Text | 计数清零 |
| 20–21 | 连续 2 个空行 | 第 21 行报{MD012:21} |
| 22 | Text | 计数清零 |
| 23 | (空行) | 计数 1,未超过上限 |
| 24 | Text | 计数清零 |
由此可见,n个连续空行在默认配置下会报出n - 1条错误:空行计数从 1 开始,一旦超过maximum,超出的每一行都会触发一次违规。快照 test/markdownlint-test-scenarios.mjs.snapshot(对应no-multiple-blanks.md的用例,位于第 35832 行附近)证实了这一点,逐条列出了第 7、10、11、14、15、16、21 行共 7 条错误,且每条错误的errorDetail均为Expected: 1; Actual: 2/3/4——Expected对应配置的maximum,Actual对应该行处的累计空行计数。
报错行号的两个关键规则
从上面的拆解可以提炼出两个对任何 markdownlint 使用者都有价值的规律:
- 错误标记在"超出的空行"上:连续
n个空行时,第 2 到第n个空行(即超出第一个的每一行)各自报告一次,错误行号即该空行的实际行号; - 报错行号与该行
Actual值一一对应:第k个连续空行报错时,Actual恰为k,所以错误行号完全可预测,这也是测试文件能用{MD012:行号}精确标注的原因。
从源码看检测与豁免逻辑
规则实现位于 lib/md012.mjs,核心算法非常简洁:
const maximum = Number(params.config.maximum || 1); const { lines } = params; const codeBlockLineNumbers = new Set(); for (const codeBlock of filterByTypesCached([ "codeFenced", "codeIndented" ])) { addRangeToSet(codeBlockLineNumbers, codeBlock.startLine, codeBlock.endLine); } let count = 0; for (const [ lineIndex, line ] of lines.entries()) { const inCode = codeBlockLineNumbers.has(lineIndex + 1); count = (inCode || (line.trim().length > 0)) ? 0 : count + 1; if (maximum < count) { addErrorDetailIf( onError, lineIndex + 1, maximum, count, undefined, undefined, undefined, { "deleteCount": -1 } ); } }逐段理解其含义:
- 参数读取:
params.config.maximum || 1取出配置值,未配置时回落为默认值 1,Number()保证其为数值; - 代码块行号收集:通过 lib/cache.mjs 的
filterByTypesCached缓存机制,从 micromark 解析出的 token 中筛选codeFenced(围栏代码块)与codeIndented(缩进代码块)两类 token,再借助 helpers/micromark-helpers.cjs 的addRangeToSet(其实现见该文件第 61 行)把每个代码块的起止行区间加入集合; - 逐行扫描:对每一行,若该行处于代码块内(
inCode)或行内容去除空白后非空(line.trim().length > 0),则计数重置为 0;否则计数加 1。这就是文档中"代码块内的连续空行不会触发规则"的源码级证据; - 上报错误:当累计计数
count超过maximum时,通过 helpers/helpers.cjs 的addErrorDetailIf(第 285 行)上报一条Expected: maximum; Actual: count的错误,同时附带{ "deleteCount": -1 }的修复信息,表示"整行删除"。
此外,filterByTypesCached基于规则参数做了按参数序列化的缓存(见 lib/cache.mjs 第 60 行),意味着同一份解析结果在同一次 lint 中被多条规则共享,这也是规则可以放心调用它的性能前提。
maximum 参数与自定义配置
maximum允许你放宽或收紧连续空行的上限。仓库提供了配套测试 test/no-multiple-blanks-maximum.md,其文件末尾通过内联配置指令将上限改为 3:
<!-- markdownlint-configure-file { "no-multiple-blanks": { "maximum": 3 } } -->对比默认样例可以直观看到差异:该文件中连续 3 个空行不再报错,只有连续 4 个空行才会在第 4 行起逐行报错(如第 16 行、第 21–22 行、第 27–29 行、第 36 行,其中第 21–22 行的Actual分别为 4、5)。快照文件中对应用例同样逐条验证了这些Expected: 3; Actual: 4/5/6的错误。
在.markdownlint.json等全局配置文件中的写法等价为:
{ "no-multiple-blanks": { "maximum": 3 } }如果希望完全关闭该规则,将配置值设为false即可,例如本仓库大量测试文件(如 test/blanks-around-headings.md 系列)在专门验证空行类规则时会用它来隔离干扰。设置maximum为大于 1 的值通常与"要求标题上下留多个空行"的场景配合使用:当 MD022 等规则需要多于一个空行时,文档 doc/Rules.md 明确提示应同步调整 MD012(见该文档 MD022 小节第 772–775 行的说明),否则会与 MD012 的默认上限互相冲突。
自动修复:整行删除的 deleteCount 机制
MD012 属于可自动修复的规则之一,这一点可以从 lib/constants.mjs 的fixableRuleNames列表(其中包含MD012)得到确认。当规则上报错误时携带的修复信息是:
{ "deleteCount": -1 }在 markdownlint 的修复约定中,deleteCount为-1表示"删除整行"。修复引擎 lib/markdownlint.mjs 的applyFix函数(第 1207 行起)对deleteCount === -1的情况直接返回null表示该行被删除;applyFixes(第 1222 行起)则会先按"从下到上、整行删除优先、从右到左、长到短"的次序排序去重,再逐条应用,避免行号漂移导致误删。
快照中no-multiple-blanks.md用例的fixed字段展示了修复结果:所有连续空行被压缩到只剩 1 个,但每一处仍保留一个{MD012:n}标记——因为测试标记本身所在的行是"超出的空行"被删除后剩下的那行,这种保留保证了快照比对不会因修复后的文本行号错位而失真。
在自己项目中一键修复的用法(参见 README.md 的 Fixing 一节):
import { applyFixes } from "markdownlint"; import { lint as lintSync } from "markdownlint/sync"; const results = lintSync({ "strings": { "content": original } }); const fixed = applyFixes(original, results.content);值得注意的是,修复信息在进入引擎前还要经过 lib/markdownlint.mjs 第 570 行起的校验逻辑:deleteCount必须是不小于-1且不超过该行长度的数值,超界会直接抛出fixInfo.deleteCount错误,这保证了规则作者上报的修复信息始终安全可执行。
与相邻空行规则的协同
MD012 只关心"空行本身是否连续堆叠",与它相邻的空白规则各司其职,理解这些边界有助于避免配置打架:
- MD022(blanks-around-headings):要求标题上下保留指定数量的空行,默认 1。若把
lines_above/lines_below配成大于 1,就必须同步调大 MD012 的maximum(见 doc/Rules.md 的明确提示); - MD031(blanks-around-fences):要求围栏代码块前后有空行,其测试文件(如 test/blanks-around-fences-in-lists.md)同样通过禁用
no-multiple-blanks来隔离干扰; - MD009(no-trailing-spaces):处理行尾空白,与空行计数无直接关系,但列表项内的"空行"(实际含空格的行)会同时牵涉两条规则,仓库测试 test/trailing-spaces-in-lists-*.md 系列展示了这种组合场景。
小结
通过 test/no-multiple-blanks.md 这份样例,我们完整掌握了 MD012 规则的三层事实:语义上,默认只允许 1 个连续空行,n个空行报n-1条错误,错误行号即超出部分的空行行号;实现上,lib/md012.mjs 通过 micromark token 精确排除代码块区间,再逐行扫描计数上报;工程上,maximum参数可定制上限,{ "deleteCount": -1 }修复信息支持通过applyFixes自动清理。理解这些细节后,你不仅能读懂仓库中任何{MD012:n}标记的测试文件,也能在自己的 Markdown 项目中精准预测、定制并修复连续空行问题。
- 开发工具
- 代码质量
- Lint
- 静态分析
【免费下载链接】markdownlint
A Node.js style checker and lint tool for Markdown/CommonMark files.
相关推荐
markdownlint MD012 规则详解:no-multiple-blanks 连续空行检测与自动修复
markdownlint MD012 规则详解:no multiple blanks 连续空行检测与自动修复 本文以 markdownlint 仓库中的真实测试
开发工具代码质量Lint静态分析markdownlint MD012 规则详解:禁止连续多个空行(no-multiple-blanks)
markdownlint MD012 规则详解:禁止连续多个空行(no multiple blanks) 本文围绕 markdownlint 项目的 MD012
开发工具代码质量Lint静态分析markdownlint 规则 MD012 深度解析:连续空行(no-multiple-blanks)检测原理与 maximum 配置实战
markdownlint 规则 MD012 深度解析:连续空行(no multiple blanks)检测原理与 maximum 配置实战 markdownli
开发工具代码质量Lint静态分析
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考