☰
markdownlint MD013 行长度(Line length)规则完全指南:参数、豁免机制与源码实现
2026/10/15 7:43:55 网站建设 项目流程
  • 开发工具
  • 代码质量
  • Lint
  • 静态分析

【免费下载链接】markdownlint

A Node.js style checker and lint tool for Markdown/CommonMark files.

项目地址:https://gitcode.com/gh_mirrors/ma/markdownlint
点击查看免费下载

本文以 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_lengthinteger80普通文本行的最大字符数
heading_line_lengthinteger80标题行的最大字符数(单独设置时覆盖line_length)
code_block_line_lengthinteger80代码块行的最大字符数(单独设置时覆盖line_length)
code_blocksbooleantrue是否对代码块内的行进行长度检查
headingsbooleantrue是否对标题行进行长度检查
tablesbooleantrue是否对表格行进行长度检查
sternbooleanfalse严格但保留无空格豁免:对"本可修复"的超长行告警
strictbooleanfalse最严格:任何超长行都报告,不做任何豁免

在源码 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: truestrict: 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 模式),以下两类行都永远不被该规则报告:

  1. 链接/图片的引用定义行,例如[label]: https://example.org "Title";
  2. 独立成行(不属于段落)且内容仅为链接/图片的行,允许配合(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 的完整执行流程可以概括为五步:

  1. 读取配置并计算各长度:line_length、heading_line_length、code_block_line_length、strict、stern、code_blocks、tables、headings(lib/md013.mjs);
  2. 构建内容类型行号集合:标题、代码块、表格、链接、段落文本五类行号集合,全部来自 micromark 解析出的 token(lib/md013.mjs);
  3. 获取引用定义行号:调用getReferenceLinkImageData()取得definitionLineIndices;
  4. 逐行判定:按"所在位置"选择maxLength(代码块用codeLineLength、标题用headingLineLength,其余用lineLength),再依次应用排除条件与豁免条件(lib/md013.mjs);
  5. 报告违规:调用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/path

3. 与其他风格的配合

注意 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.

项目地址:https://gitcode.com/gh_mirrors/ma/markdownlint
点击查看免费下载

相关推荐

上一篇:如何在Windows和Linux上免费使用苹果PingFangSC平方字体:完整指南
下一篇:零配置打包方案:5分钟将网页变应用的终极指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询