ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Prettier 如何格式化 Markdown 列表中的代码块:从测试用例到源码实现解析

Prettier 如何格式化 Markdown 列表中的代码块:从测试用例到源码实现解析 Prettier 如何格式化 Markdown 列表中的代码块从测试用例到源码实现解析【免费下载链接】prettierPrettier is an opinionated code formatter.项目地址: https://gitcode.com/gh_mirrors/pr/prettier本文以 Prettier 仓库中的 Markdown 格式化测试用例 tests/format/markdown/list/codeblock.md 为切入点深入讲解 Prettier 在格式化列表项内嵌套围栏代码块fenced code block时的缩进对齐规则、空行压缩策略与围栏长度调整逻辑并结合 src/language-markdown/print/code.js 与 src/language-markdown/print/list.js 的源码实现说明这些行为背后的设计约束。读完本文你将能准确预测 Prettier 对列表内代码块的格式化结果并理解其绝不把内容误判为缩进代码块的核心设计原则。一、测试用例定位列表内代码块格式化的标准样本在 Prettier 仓库中Markdown 格式化行为通过输入文件 Jest 快照的方式固化。本文关联的 codeblock.md 就是这样一个标准输入样本它刻意构造了四组列表项 嵌套代码块两个有序列表项1. ol01、2. ol02每项后跟一个缩进 4 空格的js围栏代码块代码块内部含有连续两个空行两个无序列表项- ul01、- ul02结构完全相同。该样本专门用来回答一个问题当代码块出现在列表项内部时Prettier 会把它输出成什么样答案是快照文件 tests/format/markdown/list/snapshots/format.test.js.snap第 147–223 行为codeblock.md对应的输入/输出对照。驱动该测试的代码只有一行tests/format/markdown/list/format.test.jsrunFormatTest(import.meta, [markdown], { proseWrap: always });其含义是对list目录下全部.md输入文件分别以markdown解析器快照中同时标注parsers: [markdown]运行格式化并固定启用proseWrap: always选项其余选项如printWidth: 80、tabWidth: 2取默认值。runFormatTest由 tests/config/format-test-setup.js 注入全局。二、输入与输出逐行对照四个关键行为把快照中的输入、输出并列可以清楚看到 Prettier 对同一输入施加的四类改写行为输入输出有序列表代码块缩进4 空格3 空格与1.前缀右缘对齐无序列表代码块缩进4 空格2 空格与-前缀右缘对齐代码块内连续空行const a 1;后接 2 个空行压缩为 1 个空行围栏标记与语言js保持不变3 个反引号 js输出片段节选自 format.test.js.snap1. ol01 js const a 1; const b 2;ul01const a 1; const b 2;三个值得注意的细节 1. **对齐基准是列表标记的右缘**1. 长度为 3所以有序列表内的代码块缩进 3 空格- 长度为 2所以无序列表内的代码块缩进 2 空格。代码块整体包括开合围栏与列表项首行文本对齐。 2. **列表项之间保持一个空行**ol01 的代码块与 ol02 之间保留空行保证两个列表项在视觉上独立。 3. **代码块内部的空行被压缩**输入中代码块内存在的两个连续空行这是作者故意放置的不干净内容输出中被规整为单个空行这是 Prettier 对代码块内空白的统一清理。 ## 三、源码实现一围栏长度与空行的生成逻辑 代码块的打印逻辑位于 [src/language-markdown/print/code.js](https://link.gitcode.com/i/67812743a3022b5fadb50d115c8095a3) - printFencedCodeBlock第 26–44 行负责生成围栏先取节点内容mdx 解析器下通过 getFencedCodeBlockValue 从原始文本还原普通 markdown 直接用 node.value再调用 printCodeFences 计算围栏。 - printCodeFences第 10–24 行决定围栏长度styleUnit.repeat(Math.max(3, getMaxContinuousCount(value, styleUnit) 1))。即**至少 3 个反引号若代码内容中本身含更长的连续反引号序列围栏长度会自动加长**连续 N 个反引号 → 使用 N1 个反引号闭合避免围栏提前终止。同时它把内容中的换行统一替换为 hardline使输出使用 Prettier 规范化后的换行符。 - 代码内容在输出前还会经过 replaceEndOfLine 处理并最终通过 align 文档节点统一缩进——空行压缩行为即发生在文档构建阶段连续 hardline 在打印层被折叠为单行或由解析器清洗空行这正是快照中两个空行变一个的实现基础。 ## 四、源码实现二列表内对齐为何是恰好而非随意 列表打印的核心在 [src/language-markdown/print/list.js](https://link.gitcode.com/i/dbf787607a1bd853601724ca56d0ca9f) 的 printListItem第 95–117 行。对列表项内的每个子节点它计算一个对齐量 js const alignment .repeat( clamp(options.tabWidth - listPrefix.length, 0, 3), // 4 will cause indented code block ); return [alignment, align(alignment, print())];这里有两层约束注释里写得很直白对齐宽度上限被 clamp 到 3注释// 4 will cause indented code block表明如果对齐空格达到 4 个及以上CommonMark 解析器会把后续内容重新解析为缩进代码块indented code block彻底改变语义。因此 Prettier 宁可牺牲严格对齐也绝不冒险超过 3 个空格。这解释了为什么有序列表项前缀1.长 3内代码块缩进恰好为 3、无序列表项前缀-长 2内缩进恰好为 2——这正是对齐到标记右缘与不超过 3 空格两个约束相交的结果。对齐量还受tabWidth影响options.tabWidth - listPrefix.length意味着在tabWidth: 4且无序列表前缀 2时对齐量会是min(2, 3) 2在默认tabWidth: 2时则取 0。换言之代码块的精确缩进由列表前缀宽度与tabWidth共同决定。此外printList中的getPrefix第 56–90 行还会在列表被requiredIndent第 125–143 行判定需要更深缩进例如列表后续紧邻缩进代码块时通过前后补充空格把前缀撑到足够宽度但同样被限制在前后各不超过 3/4 个空格的安全范围内。五、选项影响tabWidth 与 proseWraptabWidth快照目录 tests/format/markdown/list/tab-width/ 下的 indented-code-block.md 与对应快照专门验证了tabWidth: 4时嵌套列表与缩进代码块的缩进变化嵌套项从 2 空格变为 4 空格缩进代码块保持原缩进。这说明tabWidth影响的是嵌套层级与对齐而缩进代码块内容本身不重排。proseWrap本次测试固定使用always见 src/language-markdown/options.js 中对proseWrap的声明它主要影响段落文本换行对代码块内部不做折行处理——代码块内容始终按原样输出仅做换行符与空行规整。六、本地复现与验证在仓库根目录执行 Jest 即可复现本文全部结论yarn jest tests/format/markdown/list也可单独针对该样本运行yarn jest tests/format/markdown/list -t codeblock若想观察真实 CLI 行为用仓库内置的 prettier 格式化该文件yarn prettier tests/format/markdown/list/codeblock.md --parser markdown --prose-wrap always输出应与快照中的 output 部分完全一致。修改 codeblock.md 后运行yarn jest tests/format/markdown/list -u可更新快照注意仓库为只读研究环境此处仅说明测试工作流。七、延伸阅读同一目录下的相关样本tests/format/markdown/list/目录还包含大量与列表 代码块场景相关的兄弟测试可作为深入研究的入口followed-by-indented-things.md列表项后紧跟顶层/嵌套缩进代码块时requiredIndent的判定indent.md列表缩进与代码块、引用、嵌套列表的混合场景issue-17652.md代码块与嵌套列表的先后顺序对输出结构的影响tab-width/indented-code-block.mdtabWidth: 4下的回归样本。结语围绕 codeblock.md 这一个测试样本可以完整还原 Prettier 处理列表内代码块的三条主线对齐到列表标记右缘、代码块内空行与换行规整、以及绝不触发缩进代码块语义的对齐上限3 空格。理解 code.js 与 list.js 中的实现细节能帮助你准确预测任意列表内代码块的格式化结果也解释了为什么 Prettier 有时看起来没对齐——那是它为了保住 Markdown 语义正确性而做出的刻意取舍。【免费下载链接】prettierPrettier is an opinionated code formatter.项目地址: https://gitcode.com/gh_mirrors/pr/prettier创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表