ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Prettier 对 Markdown 空 front-matter 的识别与保留:从 empty-2.md 测试用例看前置元数据的解析与打印原理

Prettier 对 Markdown 空 front-matter 的识别与保留:从 empty-2.md 测试用例看前置元数据的解析与打印原理 开发工具格式化CLI【免费下载链接】prettierPrettier is an opinionated code formatter.项目地址https://gitcode.com/gh_mirrors/pr/prettier点击查看免费下载本文以 Prettier 仓库中的格式化测试用例 empty-2.md 为核心结合src/main/front-matter/下的解析、打印与嵌入实现剖析 Prettier 在格式化 Markdown 时如何处理空 front-matter---\n---以及如何区分文档开头的元数据定界符与正文中间的水平线分隔符thematic break。读完本文你将掌握 front-matter 的完整识别规则、空元数据为何能原样保留的底层原因以及如何通过测试快照验证这些行为。一、empty-2.md 到底在测试什么该测试用例全文只有 10 行--- --- # Title 1 Hello, world --- text它由两部分构成文档开头连续两行---构成一个没有内容的前置元数据块空 front-matter。文档中部在正文段落之后再出现一行---这在 Markdown 语义中是标准的水平线thematic break。这个用例设计得非常精妙它同时考察了 Prettier 的两项能力——能否识别空的 front-matter并原样保留以及能否将正文中间的---正确地当作水平线而非误认为 front-matter 的延续。对应的 format.test.js 只有一行通过runFormatTest(import.meta, [markdown])将本目录下所有.md文件交给 markdown 解析器与打印机做格式化快照测试。在snapshots/format.test.js.snap 中empty-2.md format 1的输入与输出逐字一致input --- --- # Title 1 Hello, world --- text output --- --- # Title 1 Hello, world --- text也就是说空 front-matter 被完整保留中间的---依然作为水平线存在整个文档格式化前后零改动。这个输入等于输出的结论本身就是测试要验证的稳定行为。二、前置元数据的识别规则源码级解析要理解空 front-matter 为何被识别需要看解析器的核心实现 src/main/front-matter/parse.js。2.1 定界符与语言推断getFrontMatter首先取文本最前面的 3 个字符DELIMITER_LENGTH 3作为起始定界符parse.js#L4、L31-L36---按 YAML 处理按 TOML 处理若开头不是这两种定界符直接判定不存在 front-matter。随后解析器从定界符后寻找第一个换行将起始定界符与第一个换行之间的内容视为显式语言声明explicitLanguageparse.js#L43-L45。语言最终取值规则是parse.js#L52-L53let language explicitLanguage; language || startDelimiter ? toml : yaml;即显式声明优先未声明时按定界符推断为toml或yaml。对于 empty-2.md第 1 行---后紧跟换行显式语言为空因此 language 被推断为yaml。2.2 结束定界符的查找解析器从第一个换行之后开始查找\n---或\n作为结束定界符parse.js#L47-L50。这里的关键是从第 2 行开始查找因此 empty-2.md 中第 2 行的---就是结束定界符第 1、2 两行构成完整的空 front-matter 块value为空字符串而第 8 行的---由于位置靠后、且在此之前结束定界符已经匹配天然不会被卷入元数据。此外源码中还兼容了 pandoc 等 Markdown 处理器的习惯当起始定界符为---且语言为 yaml 时若找不到\n---还会尝试用\n...作为结束定界符parse.js#L55-L63。这意味着即使元数据结尾写作...也能被正确识别。2.3 返回值结构识别成功后会返回一个结构化的FrontMatter对象parse.js#L80-L100包含language、explicitLanguage、value、startDelimiter、endDelimiter、raw原始文本切片以及起止位置信息。其中raw字段是后续原样打印的关键——它完整保留了从文件开头到结束定界符的所有原始字符。三、关键歧义消解为什么正文中间的---不会被误吞这是 empty-2.md 最有价值的地方同一份文档里出现了两组---Prettier 凭什么只把第一组当作 front-matter答案在 Markdown 解析层的插件注册中。Prettier 通过 unified 生态解析 Markdown并在 src/language-markdown/parse/unified-plugins/front-matter.js 中注册了一个专用 tokenizerproto.blockMethods [frontMatter, ...proto.blockMethods]; proto.blockTokenizers.frontMatter tokenizer; // ... tokenizer.onlyAtStart true;两个细节决定了行为onlyAtStart true该 tokenizer 只在文档最开头被尝试匹配正文中间出现的---根本不会进入 front-matter 的匹配流程。blockMethods置于最前frontMatter 的块级匹配优先级最高确保文档一开头若有定界符会优先按元数据处理。因此empty-2.md 中第 8 行的---会走普通的 Markdown 块级解析被识别为水平线thematic break并原样输出——这与快照结果完全吻合。从源码结构看这种开头元数据 正文水平线的场景正是为了验证 front-matter 解析不会越界吞掉后续内容。四、打印阶段空 front-matter 为何能原样保留解析之后进入打印阶段涉及两个模块分工明确。4.1 兜底打印原样输出 rawsrc/main/front-matter/print.js 的逻辑极其简单function printFrontMatter({ node }) { return node.raw; }即把解析阶段切出的原始文本raw一字不差地输出。对于无内容可格式化的空 front-matter这就是最稳妥的保留策略。4.2 嵌入格式化只有 YAML/TOML 内容才被重新排版Prettier 支持把 front-matter 当作可嵌入的子语言进行格式化实现在 src/main/front-matter/embed.js。其中SUPPORTED_EMBED_LANGUAGES new Set([yaml, toml])只有这两种语言才会触发嵌入逻辑embed.js#L5-L8有内容时将value交给对应的 yaml/toml 解析器重新格式化然后以起始定界符 硬换行 格式化后的内容 硬换行 结束定界符的结构重组输出embed.js#L21-L28、L33-L40内容为空时正是 empty-2.md 的情形doc保持空字符串直接输出定界符与空行embed.js#L29-L31因此---\n---及其后的空行被完整保留。在 src/main/parser-and-printer.js 的核心打印流程中front-matter 节点会优先尝试嵌入打印isEmbedFrontMatter判定不满足嵌入条件时回落到 4.1 的原样打印——这套先 embed、后 print的机制保证了空元数据既不会被破坏也不会被误格式化。五、同目录测试文件的横向对照tests/format/markdown/front-matter/目录下还有其他三个用例与 empty-2.md 互为补充共同覆盖 front-matter 的边界情况用例文件输入特征快照表现与原理empty-2.md空 front-matter 正文中部水平线---整体零改动空元数据原样保留中部---作为水平线empty.md空 front-matter 正文__123__/**456**front-matter 保持---\n---不变正文的__123__被规范化为**123**见快照证明元数据与正文格式化相互隔离custom-parser.md起始定界符后跟自定义语言名---mycustomparser自定义语言不在 yaml/toml 支持集内不触发嵌入格式化可以推断其元数据走 print 分支原样保留unicode.mdYAML 值含中文与 emojititle: ABC 漢字 元数据逐字保留正文## Retrospective不变见快照验证非 ASCII 内容不会在解析中被破坏这组用例从空块、自定义语言、Unicode 内容、块级歧义四个维度把 front-matter 的解析边界测了个遍empty-2.md 在其中承担的是歧义消解这一最容易被忽视的职责。六、在本地运行与验证这些测试如果你希望在自己的环境中复现上述结论可以在仓库根目录执行yarn jest tests/format/markdown/front-matter该命令会读取format.test.js中的runFormatTest(import.meta, [markdown])将目录内每个.md文件按默认选项printWidth: 80见快照中的 options 段格式化并与 快照文件 比对。若行为发生变更Jest 会提示快照差异在确认新行为正确后可通过yarn jest tests/format/markdown/front-matter -u更新快照。七、实战建议与边界情况结合上述源码分析在实际使用 Prettier 格式化带 front-matter 的 Markdown 时有几点值得注意空 front-matter 是合法输入---\n---这种有定界符无内容的写法常见于某些静态站点生成器对空配置的占位会被 Prettier 完整保留不会被删除或改写。正文请放心使用---作为水平线只要它不是出现在文档最开头就不会被误判为元数据定界符可以安全地在章节之间使用水平线分隔。YAML/TOML 内容会被二次格式化当 front-matter 中确实有配置内容时Prettier 会用对应解析器重新排版因此建议保持配置内容的缩进与空行规范避免格式化产生大范围 diff若使用自定义语言如---mycustomparser则不会触发嵌入格式化内容将按原样保留。多字节与 emoji 内容安全front-matter 的值按原始文本切片处理中文、emoji 等非 ASCII 字符不会被截断或转义。总而言之empty-2.md 虽然只是十行的小测试文件但它背后串起了parse → embed/print的完整 front-matter 处理链路是理解 Prettier 如何优雅处理元数据与正文边界的最佳入口。赞分享开发工具格式化CLI【免费下载链接】prettierPrettier is an opinionated code formatter.项目地址https://gitcode.com/gh_mirrors/pr/prettier点击查看免费下载相关推荐Prettier 中的 requirePragma 与空 Front Matter为何 Markdown 文件在不含 pragma 时保持原样Prettier 中的 requirePragma 与空 Front Matter为何 Markdown 文件在不含 pragma 时保持原样 导读 在 Pr开发工具格式化CLIPrettier Markdown 内联 HTML 格式化剖析从测试用例看折行、空白与块级元素的处理规则Prettier Markdown 内联 HTML 格式化剖析从测试用例看折行、空白与块级元素的处理规则 本文以 Prettier 仓库中的格式测试用例 te开发工具格式化CLIPrettier 对 Pandoc 风格 YAML Front Matter 的识别与格式化含 ... 结束分隔符解析Prettier 对 Pandoc 风格 YAML Front Matter 的识别与格式化含 ... 结束分隔符解析 导读 本文围绕 Prettier 源开发工具格式化CLI创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表