资讯动态

markdownlint MD037 规则详解:识别并自动修复强调标记内的多余空格

发布时间:2026/10/15 3:18:02 来源:尧图企业网站定制
开发工具代码质量Lint静态分析【免费下载链接】markdownlintA Node.js style checker and lint tool for Markdown/CommonMark files.项目地址https://gitcode.com/gh_mirrors/ma/markdownlint点击查看免费下载Markdown 中一行写着** bold **作者显然想加粗但渲染器却把它显示为星号加普通文本——这类手误型问题肉眼极易漏掉。markdownlint 的MD037别名no-space-in-emphasis规则专门解决这一痛点检测强调/强调整标记与文字之间的多余空格并且支持自动修复。本文以 doc/md037.md 的原始说明为主体结合 lib/md037.mjs 的完整源码实现与 test/spaces_inside_emphasis_markers.md 等真实测试场景讲清该规则的触发条件、配置方式、检测算法与已知边界。规则定位什么时候会报 MD037规则元数据定义在 lib/md037.mjs 的导出对象中export default { names: [ MD037, no-space-in-emphasis ], description: Spaces inside emphasis markers, tags: [ whitespace, emphasis ], parser: micromark, ... };标签为whitespace与emphasis因此可用这两种 tag 批量启用/禁用解析器为micromark即规则工作在 micromark 解析出的 token 流之上规则可修复FixableMD037被列入 lib/constants.mjs 的fixableRuleNames数组--fix时能自动删除多余空格。触发示例按官方文档 doc/md037.md当强调标记加粗、斜体与文字之间有空格时触发Here is some ** bold ** text. Here is some * italic * text. Here is some more __ bold __ text. Here is some more _ italic _ text.修复方式是删除标记内外的空格Here is some **bold** text. Here is some *italic* text. Here is some more __bold__ text. Here is some more _italic_ text.规则动机Rationale文档给出的原理值得展开理解在 CommonMark 规范中星号/下划线两侧被空格包围时不会被解析为强调标记。也就是说** bold **在渲染结果里根本不会加粗只会原样显示星号。规则作者认为既然你写了成对的星号多半是意图强调但写错了所以规则专门探测这种意图强调但被空格破坏了的模式而不是对所有未成对标记报警未成对的孤立标记不属于本规则职责。配置方式MD037 没有专属的额外选项遵循所有规则通用的配置形态。从 lib/configuration-strict.d.ts 的类型定义可以确认配置值为三种形式之一{ MD037: true }{ no-space-in-emphasis: warning }{ no-space-in-emphasis: { enabled: true, severity: warning } }布尔值true/false启用默认 error或禁用字符串error/warning直接指定严重级别对象形式enabled是否启用与severityerror或warning可分开设置规则 ID 与别名no-space-in-emphasis可互换使用。仓库自带的 style/ 目录下各配置集all.json、relaxed.json、prettier.json、cirosantilli.json均未单独覆盖MD037即在这些风格集里该规则保持默认启用状态。测试中可以看到别名与实际 ID 混用的真实例子例如 test/configure-file-with-severity-alias.md 用no-space-in-emphasis: errortest/configure-file-with-severity-name.md 用MD037: error两者等价。源码实现从 token 流里找出裸标记下面从源码角度完整拆解 lib/md037.mjs 的检测逻辑。该实现与常见的正则扫描不同它是基于解析结果的——这正是它能区分真强调与写坏的强调的关键。第一步收集所有包含文本内容的 tokenconst tokens filterByPredicate( parsers.micromark.tokens, (token) token.children.some((child) child.type data) );filterByPredicate定义在 helpers/micromark-helpers.cjs以迭代式深度优先方式遍历整棵 token 树把存在至少一个data子 token的节点全部收集起来因此列表、引用块、表格单元格里的内容都会被覆盖。第二步按 6 种标记类型归桶const emphasisTokensByMarker new Map(); for (const marker of [ _, __, ___, *, **, *** ]) { emphasisTokensByMarker.set(marker, []); }只考虑 6 种标记形态_、__、___、*、**、***。对每个 token遍历其data型子 tokenif ((type data) (text.length 3)) { const emphasisTokens emphasisTokensByMarker.get(text); if (emphasisTokens !inHtmlFlow(child)) { emphasisTokens.push(child); } }三个条件缺一不可type data是纯文本节点text.length 3文本长度不超过 3 个字符再配合必须恰好是 6 种标记串之一的查表筛出裸标记bare token——即 micromark 没能把它识别为强调开闭符、只是当作普通文本输出的星号/下划线片段!inHtmlFlow(child)排除处于 HTML 流htmlFlow中的片段。inHtmlFlowhelpers/micromark-helpers.cjs通过内部 symbol 标记判断 token 是否处于 HTML 块中——HTML 内容里的*不应被本规则干涉。第三步成对检查开/闭标记两侧的空格for (let i 0; i 1 emphasisTokens.length; i 2) { const startToken emphasisTokens[i]; const startSlice lines[startToken.startLine - 1].slice(startToken.endColumn - 1); const startMatch startSlice.match(/^\s\S/); ... const endToken emphasisTokens[i 1]; const endSlice lines[endToken.startLine - 1].slice(0, endToken.startColumn - 1); const endMatch endSlice.match(/\S\s$/); ... }从源码结构看其假设是同一段文本里按文档顺序出现的裸标记第 1 个是想写的开标记第 2 个是想写的闭标记依此类推两两配对i 2。对每对开标记取标记右侧的文本用^\s\S判断紧跟空格且空格后是非空白字符。若成立说明作者写成了* text的形式闭标记取标记左侧的文本用\S\s$判断非空白字符后紧跟空格。若成立说明写成了text *的形式。第四步报错并附带修复信息命中后调用 helpers/helpers.cjs 的addErroraddError( onError, startToken.startLine, undefined, startContext, // 例如 * e标记 其后的空格 [ column, count ], // 错误所在列与长度 { editColumn: column, deleteCount: count } );三个要点errorContext是标记空格开标记侧或空格标记闭标记侧的原文片段用于在编辑器里高亮问题位置count startSpaceCharacter.length - 1即需要删除的空格数连续多个空格一次报一个错误、删多个字符fixInfo中的editColumndeleteCount是修复指令。lib/markdownlint.mjs 的applyFixes会据此在对应行删除指定数量的字符内部对deleteCount做 -1的合法性校验-1表示整行删除本规则只会使用删除空格的场景。从测试快照test/markdownlint-test-scenarios.mjs.snapshot 中spaces_inside_emphasis_markers.md条目可以看到一次真实报错的完整结构{ lineNumber: 17, ruleNames: [ MD037, no-space-in-emphasis ], ruleDescription: Spaces inside emphasis markers, errorContext: * e, errorRange: [ 9, 1 ], fixInfo: { editColumn: 9, deleteCount: 1 }, severity: error }即对第 17 行Broken * emphasis * with spaces in报出开标记后多 1 个空格第 9 列删 1 字符和闭标记前多 1 个空格两条可修复错误。测试场景全覆盖哪些会报、哪些不会仓库的测试框架 test/markdownlint-test-scenarios.mjs 会自动扫描test/目录下的所有.md文件用行内{MD037}标记声明该行应触发 MD037对账后再生成修复结果快照并断言修复后不再产生任何可修复错误。围绕 MD037 有两个专用测试文件覆盖了大量边界逐一归纳如下。test/spaces_inside_emphasis_markers.md单行场景确定会触发{MD037}标记行6 种标记全形态的对称/非对称写坏* emphasis *、** strong **、*** strong and emphasis ***、_ emphasis _、__ strong __、___ strong and emphasis ___以及半边写坏的*broken emphasis *、* broken emphasis*同一行混合正常与写坏Mixed *ok emphasis* and * broken emphasis *只对写坏部分报错;词与标记粘连_flag on _words with underscores before them.、words* with asterisks* after them——下划线/星号在词中时本应无意义但成对出现且带空格时仍视为疑似意图强调列表项内部* List * item*、* List * item *表格单元格| text * text* text |、| text _text _ text |行内 HTML 元素/属性中的文本binside * HTML * content/b同时报 MD033但 MD037 对其中可解析为 Markdown 文本的部分照常检查嵌套/重叠标记中可识别的裸标记*** strong emph***、** in strong *emph***、** *strong emph***、Text * emph***strong** text等。确定不触发正常强调全部 6 种形态*Normal emphasis*…___Normal strong and emphasis___转义字符escaped\* asterisks\* \_and \_underscores完全不报代码块与行内代码markdown围栏内、反引号内的* text *含**** text ****等多余标记一律忽略——因为代码内容不是强调词内下划线/星号some_snake_case_function()、st*ar、under_score等无论是否与正常强调相邻引用块中的列表 * List with *emphasis* in blockquote写坏时如 * List * item *会报表格中的数学式写法x * y、x _ y不成对出现裸标记模式嵌入下划线的Text _emphas_i_s_ text不报CommonMark 规范中的复杂嵌套样本***strong emph***等在没有空格时不报。test/spaces-inside-emphasis-markers-multiple-lines.md跨行强调强调内容可以跨行软换行本规则同样支持Text * emphasis {MD037} emphasis * text {MD037}开标记在第 1 行、闭标记在第 2 行的场景Text *emphasis/emphasis* text不报而开标记行尾是* emphasis、闭标记行首是emphasis *时分别报。测试还包含跨行嵌套*emphasis * *emphasis、列表项内跨行强调、行内代码跨行inside * code *不报、段落内混排行内代码contains *a* mix of * emphasis不报。这印证了一个实现细节规则的判定完全基于startLine/startColumn/endColumn坐标回到原始行文本做切片lines[startToken.startLine - 1]因此天然支持 token 跨行的情形。已知边界与限制从测试文件的注释与源码逻辑可以确认以下边界行为嵌套内部的空格不检测**in strong * emph*** (internal spaces are not detected)。当裸标记出现在已被解析为强调整内部的复杂结构里时两两配对假设可能失效源码只按每段 token 内裸标记的出现顺序配对不做歧义消解——测试中此类场景被标注为{possible MD037}或注明internal spaces are not detected左空格与列表符号的区分* Emphasis* with left space is recognized as a list这一行不报 MD037——行首的*会被解析为列表符号而非裸标记因此不在候选之列而** Strong** with left space会报**不构成列表符号HTML 流整体排除inHtmlFlow过滤使 HTML 块内的文本 token 不进入候选但行内 HTML 元素内的 Markdown 文本如b.../b内的内容仍会检查这与 MD033 的职责划分一致修复的幂等性由测试保障测试框架对每个文件执行lint → applyFixes → 再 lint断言修复后不残留任何带fixInfo的错误见 test/markdownlint-test-scenarios.mjs 第 94~102 行的逻辑。实战运行与自动修复在安装了 markdownlint CLI 的环境中当前仓库版本为 0.41.0见 package.json# 检查文件MD037 默认启用 markdownlint mydoc.md # 自动修复 MD037 等可修复规则MD037 在 fixableRuleNames 中 markdownlint --fix mydoc.md # 将 MD037 降级为警告配置文件中{ MD037: warning }也可在文档内用行内指令局部禁用这是仓库测试中大量使用的手法!-- markdownlint-disable MD037 -- 一些允许 * 空格 * 的历史内容 !-- markdownlint-restore --如需理解某个具体文件为何报/不报仓库提供了一个轻量调试工具test/harness.mjs 会打印指定文件的 micromark token 树并输出 lint 结果node test/harness.mjs somefile.md对分析 MD037 这类基于 token 的规则非常有用。小结维度结论依据规则 ID / 别名MD037/no-space-in-emphasislib/md037.mjs标签whitespace,emphasisdoc/md037.md可自动修复是删除标记内侧多余空格lib/constants.mjs、fixInfo逻辑检测范围6 种标记_/__/___/*/**/***支持跨行、列表、表格、引用块test/spaces_inside_emphasis_markers.md、test/spaces-inside-emphasis-markers-multiple-lines.md排除范围代码块/行内代码、HTML 流内容、转义标记、词内星号下划线同上测试文件配置选项无专属参数通用enabled/severitylib/configuration-strict.d.tsMD037 的设计精髓在于基于解析结果的意图推断只有当 micromark 把标记当普通文本输出说明强调没生效、且标记两侧恰好是空格非空白的成对模式时才判定为意图强调但写坏了。这使得它对 snake_case 命名、数学表达式、代码内容等常见误报源免疫同时把修复指令editColumn/deleteCount直接交给--fix落地是 markdownlint 中检测修复结合得最完整的 whitespace 类规则之一。赞分享开发工具代码质量Lint静态分析【免费下载链接】markdownlintA Node.js style checker and lint tool for Markdown/CommonMark files.项目地址https://gitcode.com/gh_mirrors/ma/markdownlint点击查看免费下载相关推荐markdownlint MD037 规则详解检测与修复强调标记Emphasis Markers内部的多余空格markdownlint MD037 规则详解检测与修复强调标记Emphasis Markers内部的多余空格 MD037别名 no space in开发工具代码质量Lint静态分析markdownlint 规则 MD038 深度解析代码跨度内多余空格检测与自动修复markdownlint 规则 MD038 深度解析代码跨度内多余空格检测与自动修复 本文以 markdownlint 开源仓库中的 MD038 规则文档 h开发工具代码质量Lint静态分析markdownlint MD027 规则详解块引用符号后的多余空格检查与修复markdownlint MD027 规则详解块引用符号后的多余空格检查与修复 本文基于 markdownlint 仓库深入讲解 MD027 no mul开发工具代码质量Lint静态分析上一篇Monolith 推荐系统3 条命令跑通实时训练嵌入表到底能开多大下一篇Salt master 守护进程完全指南salt-master 命令行参考与底层实现解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

免费获取报价 →
↑