- 开发工具
- Lint
- 格式化
- 静态分析
- 代码质量
- 前端
【免费下载链接】biome
A toolchain for web projects, aimed to provide functionalities to maintain them. Biome offers formatter and linter, usable via CLI and LSP.
无序列表(Unordered List)是 Markdown 中使用频率最高的块级元素,而嵌套无序列表的缩进处理则是格式化器中公认的难点:既要保证渲染结果不变,又要让缩进在视觉上整齐统一,还要与 Prettier 的输出保持兼容。本指南以 Biome 仓库中crates/biome_markdown_formatter/tests/specs/prettier/markdown/list/unordered.md这一真实测试用例为起点,结合biome_markdown_formatter的源码实现,完整讲解 Biome 如何规范化嵌套无序列表的缩进、统一列表标记(marker)并保证与 Prettier 快照一致。读完本文,你将掌握该测试用例的输入输出语义、缩进计算的底层逻辑,以及如何在本地运行和验证这些快照测试。
测试用例原貌:输入与预期输出
测试文件 unordered.md 的内容非常精炼,共 5 行,却覆盖了「顶层列表项 + 多层嵌套子项」的典型场景:
- first line - second line indented - third line - fourth line - fifth line与之配套的预期输出文件 unordered.md.prettier-snap 给出了格式化后的结果:
- first line - second line indented - third line - fourth line - fifth line对比输入与输出,可以提炼出 Biome 在此用例中验证的三条核心行为:
- 缩进规范化:输入中嵌套子项使用 4 个空格缩进(
- second line indented),输出被规范为 2 个空格(- second line indented);第三层嵌套的fifth line从 8 个空格收敛为 4 个空格。每一层列表的缩进宽度固定为 2 个空格。 - 标记统一:输入、输出均使用
-作为无序列表标记,且顶层与嵌套层全部保持一致,没有混用*或+。 - 结构与顺序保持:
first line、third line两个顶层项及其嵌套子项的相对顺序完全不变,仅缩进与间距被重排。
测试体系定位:Prettier 兼容性快照
这个用例不是孤立的,它位于 Biome 的 Prettier 兼容性测试体系中。整个目录 crates/biome_markdown_formatter/tests/specs/prettier/markdown/list 下存放着align.md、nested.md、ordered.md、task-list/、parser-regression/等一系列针对列表格式化的输入文件,每个输入都对应一个.prettier-snap(Prettier 的预期输出)文件;当 Biome 的输出与 Prettier 存在差异、需要额外记录自身行为时,还会生成.snap文件(例如followed-by-indented-things.md.snap、loose.md.snap、tab.md.snap)。
测试的驱动逻辑位于 prettier_tests.rs,其关键点如下:
- 通过
tests_macros::gen_tests! {"tests/specs/prettier/markdown/**/*.{md}", crate::test_snapshot, ""}自动收集tests/specs/prettier/markdown/下所有.md文件并生成测试函数; - 测试默认采用空格缩进(
IndentStyle::Space)与IndentWidth::default(),即默认缩进宽度为 2(IndentWidth的默认值定义于 lib.rs,取值范围为 0~24,见 lib.rs); - 语言模型固定为 GFM(GitHub Flavored Markdown),经由
PrettierSnapshot::new与 Biome 的MdFormatLanguage完成比对,确保 Biome 的输出与 Prettier 快照逐字一致。
因此unordered.md这类用例的作用是双重的:既是 Biome 自身回归测试的输入,也是与 Prettier 行为对齐的契约。若未来修改了列表缩进逻辑,这个用例会立刻捕捉到与 Prettier 的偏差。
源码实现:缩进与对齐是如何算出来的
格式化结果中的「每层缩进 2 个空格」并非硬编码的魔法数字,而是由 bullet_list.rs 中的ListBullet::prefix_layout计算出的「对齐宽度」(alignment)驱动的。核心逻辑可归纳为三步:
- 宽度累计:
indent_width函数(bullet_list.rs)遍历MdIndentTokenList中的每个缩进字符,按「空格计 1 列、制表符按 4 列对齐取整」的规则累计出源文件中的缩进宽度。 - 对齐宽度合成:
prefix_layout将「标记前缩进宽度 + 标记宽度 + 标记后空格宽度」三者相加得到alignment,随后通过align(" ".repeat(alignment), &content)(见 bullet_list.rs)把内容整体推进到对齐列。 - 嵌套层归一化:由于每一层嵌套都会作为一个新的
MdBulletList节点递归进入FmtAnyList(bullet_list.rs),每一层都会按自身前缀重新计算对齐宽度。当indent_width默认值为 2 时,-(标记 1 列 + 空格 1 列)恰好产生每层 2 个空格的视觉缩进——这就是测试用例输出- second line indented、- fifth line的直接来源。
标记选择则由ListMarkerPlan(bullet_list.rs)与unordered_marker_for_list(bullet_list.rs)负责:同一个解析出的列表节点内所有条目共用同一个标记(默认-),这样能避免混用-、*导致 Markdown 把原本连续的列表重新解析成多个列表。源码注释还特别指出,若列表项以「由短横线构成的主题分隔线(thematic break)」开头,则改用+或*,防止- ---被解析为分隔线而不是列表项。
另外,标记与内容之间空格的取舍在 list_marker_prefix.rs 中处理:格式化器会移除原始的post_marker_space_token,再按post_marker_len重新生成等宽空格,从而保证「标记后空格」随对齐需求而变。
缩进语义:从 4 空格/制表符输入到统一输出
为了说明缩进规范化并非只针对 4 空格,Biome 还在同目录提供了多个对照用例:
- nested.md 使用标准的 2 空格嵌套输入,输出保持不变,验证「已规范化的输入不会被破坏」;
- tab.md 的嵌套内容以制表符缩进(
\t),格式化后被统一替换为空格; - nested-tab.md 混合了制表符与空格(如
* Sub-Nested List item 1),同样被归一化为每层 2 个空格; - align.md 及其快照 align.md.prettier-snap 则覆盖了有序列表数字位数变化(
1.、11.、111.)时标记后空格自动扩展的对齐场景。
这些用例共同印证了 Biome 的列表缩进策略:不看源文件用空格还是制表符、缩进是 2 还是 4,一律按配置的indentWidth重新计算嵌套层级。而indent_width函数对制表符按「4 列取整」计算(4 - width % 4,见 bullet_list.rs),保证了与 CommonMark 规范中制表符展开语义一致。
实战验证:如何运行与复现该用例
unordered.md是自动生成的测试用例,无需手动注册。在仓库根目录下执行以下命令即可单独运行 Markdown 格式化器的全部快照测试(包含本用例):
cargo test -p biome_markdown_formatter若只想查看该用例的完整诊断输出(含输入、输出与逐项差异说明),可以运行:
cargo test -p biome_markdown_formatter test_unordered_md测试通过时,说明 Biome 的输出与 unordered.md.prettier-snap 完全一致;失败时则提示差异位置,便于定位缩进或标记选择逻辑的回归。
在实际项目中使用biome format处理 Markdown 文件时,本文描述的行为会以相同规则生效:无序列表(-、*、+开头)的多层嵌套会被统一规范为每层 2 个空格的缩进,标记保持同一列表内一致。如需调整缩进宽度,可在biome.json的formatter.indentWidth中配置(默认 2,合法范围 0~24,定义见 lib.rs),该值会直接影响嵌套列表的对齐列计算。
小结
从 5 行的 unordered.md 测试用例出发,可以看到 Biome Markdown 格式化器在嵌套无序列表上的完整设计闭环:Prettier 兼容快照定义预期行为 →bullet_list.rs中的对齐宽度计算驱动缩进归一化 →indent_width按空格/制表符统一换算 → 每层递归重建对齐。理解这条链路,无论是排查格式化差异、编写新的列表用例,还是调整缩进配置,都能做到有的放矢。若要进一步深挖,可继续阅读 bullet_list.rs 全文,其中还包含有序列表标记选择、Git diff 友好编号(1.1.1.风格)、相邻列表分隔等更多细节。
- 开发工具
- Lint
- 格式化
- 静态分析
- 代码质量
- 前端
【免费下载链接】biome
A toolchain for web projects, aimed to provide functionalities to maintain them. Biome offers formatter and linter, usable via CLI and LSP.
相关推荐
Biome Markdown 格式化器测试用例剖析:example-283 嵌套无序列表缩进规范化解析
Biome Markdown 格式化器测试用例剖析:example 283 嵌套无序列表缩进规范化解析 本文以 Biome 仓库中 Prettier 兼容性测试
开发工具Lint格式化静态分析代码质量前端Biome Markdown 格式化器中的列表续行缩进规则:从测试用例到源码实现
Biome Markdown 格式化器中的列表续行缩进规则:从测试用例到源码实现 Markdown 列表项的续行(continuation line)缩进是格式
开发工具Lint格式化静态分析代码质量前端Biome Markdown 格式化器嵌套列表 Tab 缩进处理:测试用例与底层实现剖析
Biome Markdown 格式化器嵌套列表 Tab 缩进处理:测试用例与底层实现剖析 Biome 的 Markdown 格式化器( biome_markdo
开发工具Lint格式化静态分析代码质量前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考