- 开发工具
- 代码质量
- Lint
- 静态分析
【免费下载链接】markdownlint
A Node.js style checker and lint tool for Markdown/CommonMark files.
本文以 markdownlint 仓库中的规则文档 doc/md013.md 为主线,系统讲解 MD013(别名line-length)行长度检查规则:从 8 个配置参数的完整说明,到strict/stern两种严格模式的差异,再到代码块、表格、标题的可选排除与链接行的永久豁免机制。文章结合 lib/md013.mjs 的源码实现与 test/ 目录下的十多个测试用例,帮助你彻底掌握该规则的判定逻辑,并能在真实项目中准确配置、灵活规避误报。
一、规则概述:它检查什么
MD013 是 markdownlint 内置的行长度(line length)检查规则,用于发现文档中超过设定长度上限的行。其规则元数据如下:
- 规则 ID:
MD013 - 别名(Alias):
line-length - 标签(Tags):
line_length - 解析器(Parser):
micromark(在 lib/md013.mjs 中声明)
规则被触发时,错误信息中Expected为允许的最大长度,Actual为当前行的实际长度(见 helpers/helpers.cjs 中addErrorDetailIf的拼装逻辑)。
触发该规则时的修复方式很简单:将超长的行拆分为多行。默认情况下,超过 80 个字符的行会被报告。
二、参数详解:8 个配置项全覆盖
MD013 是 markdownlint 中参数较多的规则之一,共支持 8 个参数,全部通过规则配置对象传入:
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
line_length | integer | 80 | 普通文本行的最大字符数 |
heading_line_length | integer | 80 | 标题行的最大字符数(单独设置时覆盖line_length) |
code_block_line_length | integer | 80 | 代码块行的最大字符数(单独设置时覆盖line_length) |
code_blocks | boolean | true | 是否对代码块内的行进行长度检查 |
headings | boolean | true | 是否对标题行进行长度检查 |
tables | boolean | true | 是否对表格行进行长度检查 |
stern | boolean | false | 严格但保留无空格豁免:对"本可修复"的超长行告警 |
strict | boolean | false | 最严格:任何超长行都报告,不做任何豁免 |
在源码 lib/md013.mjs 中可以看到各参数的取值与兜底逻辑:
line_length缺省时取80;heading_line_length缺省时回退到line_length的值(而非固定 80);code_block_line_length缺省时同样回退到line_length;code_blocks、tables、headings三个布尔参数在未配置时均默认为true。
这一"回退"设计意味着:你只需修改line_length,标题与代码块的长度上限会随之联动;只有当需要给它们单独设限时,才显式配置heading_line_length或code_block_line_length。
参数组合示例
将整体长度放宽到 100,同时单独收紧代码块与标题:
{ "MD013": { "line_length": 100, "heading_line_length": 60, "code_block_line_length": 120 } }三、默认行为的核心:无空白豁免机制
MD013 的默认模式有一个重要例外:当超出长度上限的部分不含空白(whitespace)时,该行不会被报告。这一机制允许你写长 URL、长 token、长文件路径而不必在中间强行断行。
规则文档 doc/md013.md 给出了如下示例(假设第 1 行刚好等于最大长度):
IF THIS LINE IS THE MAXIMUM LENGTH This line is okay because there are-no-spaces-beyond-that-length This line is a violation because there are spaces beyond that length This-line-is-okay-because-there-are-no-spaces-anywhere-within在默认模式下:
- 第 1 行正好等于上限,不违规;
- 第 2 行虽然整体超长,但超出的部分(
-no-spaces-beyond-that-length)不含空格,因此豁免; - 第 3 行超出的部分包含空格(
are spaces beyond that length),违规; - 第 4 行整行没有任何空格,豁免。
源码中的实现方式
这一机制在 lib/md013.mjs 中体现为一行精妙的正则替换:
const text = (strict || stern) ? line : line.replace(/\S*$/u, "#");默认模式下,行尾最后一串非空白字符(\S*$)会被替换为单个#,再与上限比较长度。这等效于"只统计到最后一个空格为止的内容",从而允许不可断行片段越过上限——但前提是该不可断行片段必须从上限以内开始。若空白出现在超限部分中间,替换后长度仍超限,即触发违规。在 test/long_lines.md 中,第 3 行(含空格超长)被标记{MD013},第 5 行(无空格超长)未标记,正是该机制的直观验证。
四、严格模式:strict = true
当设置strict为true时,任何超过长度上限的行都会报告违规,不再有无空白豁免。规则文档的说明是:
要禁用这一例外,将
strict设为true,任何行过长都会报告问题。
以 test/long-lines-strict.md 为例,其配置同时展示了三个长度参数的分工:
<!-- markdownlint-configure-file { "line-length": { "strict": true, "heading_line_length": 30, "code_block_line_length": 20 } } -->测试文件预期{MD013:5}、{MD013:7}、{MD013:9}、{MD013:15}、{MD013:22}五处违规,分别对应:正文超长行、更长的正文行、勉强超长的正文行、超长标题行、超长代码行。同时测试也验证了"刚好等于上限"与"上限以内"的行不违规(第 11、13 行及第 17、19、21 行标题、第 23、24 行代码均正常)。
注意:strict 模式下即使行内没有空格、完全无法换行,也照样报告——这正是 strict 的代价,适合对格式有硬性要求的团队。
五、折中模式:stern = true
stern(直译为"严厉")是介于默认与 strict 之间的模式:
对"过长且本可修复"的行告警,但允许"没有空格的长行"通过。
换句话说,stern 会报告"由于包含空格本可以拆行却未拆"的超长行,同时保留对不可断行长串的豁免。规则文档的示例说明:
- 默认模式下第 2、3 行中仅第 3 行违规;
- strict 模式下后三行全部违规;
- stern 模式下中间两行违规(第 2 行无空白豁免取消,第 3 行本就违规),但第 4 行(整行无空格)依然通过。
test/long-lines-stern.md 对这一模式做了非常全面的覆盖,预期违规行包括:
- 普通正文超长行(第 5、7 行);
- 含连续无空格片段但仍超长的行(第 13 行);
- 超长标题(第 17 行);
- 超长代码行(第 26 行);
- 列表项与块引用中的超长行(第 32、35、38、42 行)。
而以下行在 stern 模式下不违规,用于验证豁免边界:
- 第 15 行
ThisLineIsOkaytext...(整行无空格); - 第 23 行
ThisTooLongHeadingIsOkaytext(无空格标题); - 第 29 行
ThisTooLongCodeIsOkay.(无空格代码行); - 第 36、40、44 行(无空格的长列表/块引用行);
- 第 46 行(因缩进看起来像列表项的一部分而未报告)。
stern 的源码判定
stern 模式依赖正则notWrappableRe:
const notWrappableRe = /^(?:[#>\s]*\s)?\S*$/;该正则匹配"仅由可选的行首标记(#、>、空白)加上一段无空白文本组成"的行。判定逻辑位于 lib/md013.mjs:
(!(stern && notWrappableRe.test(line)) && !linkOnlyLineNumbers.has(lineNumber))即在 stern 模式下,若整行匹配notWrappableRe(无法换行),则豁免;否则按普通长度比较报告。严格模式(strict)会直接跳过这一整条豁免分支。
六、三种模式对比速查
| 行类型 | 默认 | stern: true | strict: true |
|---|---|---|---|
| 超长且含空格(可拆行) | 违规 | 违规 | 违规 |
| 超长但超限部分无空格 | 豁免 | 豁免 | 违规 |
| 整行无空格(如长 URL) | 豁免 | 豁免 | 违规 |
| 链接/图片引用定义行 | 豁免 | 豁免 | 豁免(永久) |
| 仅含单个链接/图片的独立行 | 豁免 | 豁免 | 豁免(永久) |
七、按内容类型排除:code_blocks/tables/headings
规则默认将代码块、表格、标题全部纳入长度检查,文档给出的理由很务实:
代码块默认被包含,因为文档可读性通常有此要求,且与代码规范大体兼容;但仍有一些语言不适合短行。
如果你希望排除某一类内容,把对应布尔参数设为false即可:
{ "MD013": { "code_blocks": false, "tables": false, "headings": false } }对应源码中的判定条件(lib/md013.mjs):
(includeCodeBlocks || !inCode) && (includeTables || !inTable) && (includeHeadings || !isHeading)其中"是否位于代码块/表格/标题内"是通过 micromark 解析出的 token 行号范围集合判断的:
- 标题:
atxHeading、setextHeading两类 token(lib/md013.mjs); - 代码块:
codeFenced、codeIndented两类 token(lib/md013.mjs); - 表格:
tabletoken(lib/md013.mjs)。
相关测试可对照查看:
- test/long_lines_code.md ——
code_blocks: false、tables: false时,代码块与表格内的超长行均不报告,而正文超长行仍报告{MD013}; - test/long_lines_code-default.md —— 不配置排除项时,代码块行、表格的表头/分隔行/单元格行全部报告
{MD013},证明默认纳入检查; - test/long-heading-exceptions.md ——
headings: false时超长标题不报告,但正文超长行仍报告; - test/long-lines-short-code.md 与 test/long-lines-short-headings.md —— 分别演示
code_block_line_length: 30与heading_line_length: 30的单独设限效果(含 setext 标题也参与检查)。
八、永久豁免:链接/图片引用定义与纯链接独立行
无论哪种模式(即使 strict 模式),以下两类行都永远不被该规则报告:
- 链接/图片的引用定义行,例如
[label]: https://example.org "Title"; - 独立成行(不属于段落)且内容仅为链接/图片的行,允许配合(strong)emphasis 修饰。
规则文档给出的原因是:这类行往往无法在不破坏 URL 的前提下拆分。
源码依据
引用定义行的行号来自 helpers/helpers.cjs 的getReferenceLinkImageData,其中遍历definition、gfmFootnoteDefinition等 token 并将起始行到结束行全部记入definitionLineIndices(helpers/helpers.cjs),随后在 MD013 中通过!definitionLineIndices.has(lineIndex)直接排除(lib/md013.mjs)。
"纯链接独立行"的判定更为细致(lib/md013.mjs):先收集autolink、image、link、literalAutolink等 token 的行号得到linkLineNumbers,再收集段落(paragraph)内所有data文本 token 的行号得到paragraphDataLineNumbers;两者之差linkOnlyLineNumbers就是"链接所在但段落文本不覆盖"的行——即独立链接行。判定条件为!linkOnlyLineNumbers.has(lineNumber)(lib/md013.mjs)。
测试覆盖
test/long_lines.md 是这一豁免机制的完整"测试矩阵":
- 第 7、9 行:整行为纯链接/块引用中的纯链接 → 豁免;
- 第 17、19、21 行:链接前后/中间有普通文本 → 报告
{MD013}; - 第 23、25、31、33、37、49、55、61 行:整行为引用链接、引用定义、空文本链接、强调/加粗修饰的链接或图片 → 豁免;
- 第 76、78 行:整行仅为自动链接或裸 URL → 豁免;
- 第 80、82 行:链接前后有文本 → 报告
{MD013}。
另外,test/long-lines-long-reference-definitions.md、test/long-lines-long-reference-definitions-stern.md、test/long-lines-long-reference-definitions-strict.md 三个文件进一步证明:即使开启strict/stern,引用定义行依然全部豁免——strict 版本中唯一仍被检查的是通过markdownlint-disable-next-line临时恢复检查的场景。
九、边界行为:line_length为 0 或负数
源码中的判定有一个前置条件maxLength > 0(lib/md013.mjs):
line_length配置为-1等负值时,规则被整体禁用(不报告任何违规);- 配置为
0时同样不检查。
test/long-lines-negative-line-length.md 专门记录了这一点,并说明这种配置"出现在真实项目中,为向后兼容而禁用该规则"。虽然它属于无效配置,但将其视为"关闭 MD013"的另类写法是兼容历史配置时的重要知识。
十、源码实现脉络:从 token 到报告
MD013 的完整执行流程可以概括为五步:
- 读取配置并计算各长度:
line_length、heading_line_length、code_block_line_length、strict、stern、code_blocks、tables、headings(lib/md013.mjs); - 构建内容类型行号集合:标题、代码块、表格、链接、段落文本五类行号集合,全部来自 micromark 解析出的 token(lib/md013.mjs);
- 获取引用定义行号:调用
getReferenceLinkImageData()取得definitionLineIndices; - 逐行判定:按"所在位置"选择
maxLength(代码块用codeLineLength、标题用headingLineLength,其余用lineLength),再依次应用排除条件与豁免条件(lib/md013.mjs); - 报告违规:调用
addErrorDetailIf,expected为最大长度、actual为实际长度,range精确指向超长区间[maxLength + 1, line.length - maxLength](lib/md013.mjs)。
性能方面,token 过滤与引用数据都经过 lib/cache.mjs 的filterByTypesCached/getReferenceLinkImageData缓存,同一份文档内多次调用不会重复解析,这对批量检查大量文档的场景是有利的。
十一、实战配置建议
1. 项目级配置文件
在.markdownlint.json(或.markdownlint.yaml、package.json的markdownlintConfig字段)中按团队规范配置:
{ "MD013": { "line_length": 100, "code_block_line_length": 120, "heading_line_length": 80, "stern": true } }2. 行内按需关闭
对个别无法拆分的超长行,可用行内指令临时豁免,如:
<!-- markdownlint-disable-next-line MD013 --> https://example.com/very/long/unbreakable/url/path3. 与其他风格的配合
注意 style/prettier.json 中该规则被设为false——因为 Prettier 的默认换行宽度由printWidth单独控制,若同时开启 prettier 格式化与 markdownlint,需自行决定以谁为准,避免规则冲突。
4. 快速上手运行
在仓库中可直接运行测试验证规则行为:
node --test test/markdownlint-test-scenarios.mjs或通过 test/harness.mjs 对单个测试文件执行 lint 并比对预期{MD013:行号}标记。
十二、总结
MD013 行长度规则的精髓在于"长度上限"与"豁免边界"的平衡设计:
- 默认模式允许不可断行的长串越过上限(保护 URL);
stern模式只惩罚"本可拆行却未拆"的行;strict模式取消一切豁免,强制硬性长度约束;- 代码块、表格、标题可分别独立设限或整体排除;
- 链接/图片引用定义与纯链接独立行在任何模式下永久豁免。
结合 doc/md013.md 的规则说明、lib/md013.mjs 的判定逻辑以及 test/ 中十余个针对性测试用例,你可以精确预判任意一行 Markdown 是否会被报告,从而在团队中制定出既保持文档整洁、又不误伤真实需求(长 URL、长代码、宽表格)的行长度策略。
- 开发工具
- 代码质量
- Lint
- 静态分析
【免费下载链接】markdownlint
A Node.js style checker and lint tool for Markdown/CommonMark files.
相关推荐
markdownlint 规则详解:MD013(line-length)行长校验的配置、豁免与严格模式
markdownlint 规则详解:MD013(line length)行长校验的配置、豁免与严格模式 导读 MD013(别名 line length ,标签
开发工具代码质量Lint静态分析stylelint `comment-empty-line-before` 规则全解:注释前空行的强制与豁免
stylelint comment empty line before 规则全解:注释前空行的强制与豁免 comment empty line before 是
代码质量静态分析前端markdownlint MD009(no-trailing-spaces)实战指南:行尾空格规则、参数详解与源码实现剖析
markdownlint MD009(no trailing spaces)实战指南:行尾空格规则、参数详解与源码实现剖析 本篇指南围绕 markdownlin
开发工具代码质量Lint静态分析
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考