开发工具格式化CLI【免费下载链接】prettierPrettier is an opinionated code formatter.项目地址https://gitcode.com/gh_mirrors/pr/prettier点击查看免费下载Markdown 的引用式链接reference links将链接目标集中定义在文档底部但标签中夹杂多余空格、大小写混写时格式化器极易破坏引用匹配或语义。本文以 Prettier 仓库中的格式测试 case-and-space.md 为核心结合其快照输出与 Markdown 打印器源码系统讲解 Prettier 如何规范化引用链接标签label中的空白、保留标签大小写与图片替代文本并说明proseWrap等选项对引用定义格式的影响。读完你将掌握 Prettier 处理linkReference、imageReference、definition、footnoteReference、footnoteDefinition五类引用节点的完整规则与源码级依据。一、测试场景定位case-and-space 测的是什么case-and-space.md位于 Prettier 的格式测试目录 tests/format/markdown/linkReference/ 下文件内容刻意构造了标签内包含大量多余空格、且字母大小写混写的 Markdown 引用语法。文件名 case-and-space 直译即大小写与空格它验证的是 Prettier 在格式化引用式链接时两个相互制衡的目标折叠空白标签内[ See ... ]这种多余空格应被规范化为单个空格保留大小写AsyncGeneratorFunction、PascalCase这类大小写敏感标签不能被改写否则会破坏与文末定义definition的匹配关系。该目录下的配套用例共同构成对引用语法格式化行为的完整回归测试集除本文件外还包括collapsed.md折叠式引用[label][]full.md完整引用[text][label]shortcut.md快捷引用[label]definition.md引用定义cjk.md中日韩字符标签wrap.md、title.md换行与标题场景。每个用例目录下的 format.test.js 均只有一行runFormatTest(import.meta, [markdown]);它通过runFormatTest对目录内所有.md文件执行 markdown 解析器格式化并将输入/输出与snapshots/format.test.js.snap 中的快照比对任何输出变化都会导致测试失败。在仓库根目录通过项目的 Jest 配置见 jest.config.js运行该测试即可复现文中所有输入输出。二、case-and-space.md 完整输入与格式化输出对照原文档 case-and-space.md 按五类节点组织每类均包含带多余空格与带附加说明文字两个变体。结合快照 format.test.js.snapPrettiermarkdown 解析器默认printWidth: 80的实际转换如下。2.1linkReference标签空白被折叠输入[ See AsyncGeneratorFunction ][ See AsyncGeneratorFunction ] [ See AsyncGeneratorFunction label ][ See AsyncGeneratorFunction ] [ See AsyncGeneratorFunction ][]输出[ See AsyncGeneratorFunction ][ See AsyncGeneratorFunction ] [ See AsyncGeneratorFunction label ][ See AsyncGeneratorFunction ] [ See AsyncGeneratorFunction ][]可见链接文本第一对方括号内与引用标签第二对方括号内两侧及内部连续的多个空格均被折叠为单个空格AsyncGeneratorFunction的大小写被原样保留。2.2imageReference标签折叠alt 文本保留原始空白输入![ See AsyncGeneratorFunction ][ See AsyncGeneratorFunction ] ![ See AsyncGeneratorFunction alt ][ See AsyncGeneratorFunction ] ![ See AsyncGeneratorFunction ][]输出![ See AsyncGeneratorFunction ][ See AsyncGeneratorFunction ] ![ See AsyncGeneratorFunction alt ][ See AsyncGeneratorFunction ] ![ See AsyncGeneratorFunction ][]这是本用例中最值得注意的行为差异引用标签部分第二对方括号的空格照常折叠为单个空格但图片替代文本部分第一对方括号内在完整引用full场景下保持输入时的原始空白不变——前两行的 alt 仍是See ...。只有第三行折叠式引用[][]的 alt 才被折叠为See ...。2.3definition定义标签同样折叠空白输入[ See AsyncGeneratorFunction ]: ./index.html输出[ See AsyncGeneratorFunction ]: ./index.html引用定义reference definition的标签经折叠后为SeeAsyncGeneratorFunction与正文中的引用标签同样折叠后保持一致的规范化形式从而保证 CommonMark 的标签匹配label matching规则仍然成立。2.4footnoteReference与footnoteDefinition原样保留输入[^SeeAsyncGeneratorFunction] [^SeeAsyncGeneratorFunction]: ./index.html输出与输入逐字相同。脚注引用与脚注定义不受空白折叠规则影响原样输出。三、源码级机制解析上述行为并非偶然而是 Markdown 打印器多个处理阶段协作的结果。下面沿 Prettier 的处理管线逐层拆解。3.1 阶段一AST 按摩时预先折叠标签空白在 src/language-markdown/massage-ast/index.js 中Prettier 对三类节点统一处理if ( original.type definition || original.type linkReference || original.type imageReference ) { cloned.label collapseWhiteSpace(original.label); } // Maybe we should fix this if ( original.type imageReference original.referenceType collapsed ) { cloned.alt collapseWhiteSpace(original.alt); }collapseWhiteSpace来自collapse-white-space工具库将标签内的连续空白含空格、换行、制表符收敛为单个空格。注意这里的两个细节只折叠labellinkReference、imageReference、definition 的标签在 AST 阶段就被规范化折叠式 imageReference 才折叠alt源码注释 Maybe we should fix this 表明仅当图片引用是折叠式![...][]时才折叠 alt 文本——这正是 2.2 节中第三行 alt 被折叠、前两行 alt 保留空白的原因。3.2 阶段二打印 linkReference 时保留大小写并转义方括号核心实现在 src/language-markdown/print/mdast.js 与同文件 printLinkReferencecase linkReference: return [ [, printChildren(path, options, print), ], node.referenceType full ? printLinkReference(node) : node.referenceType collapsed ? [] : , ];function printLinkReference(node, options) { // remark-parse lowercase the label as identifier, we dont want do that const label collapseWhiteSpace(node.label); if (options?.parser mdx) { return [${label}]; } const name label.replaceAll(/[\\[\]]/g, (s) \\${s}); return [${name}]; }三点关键信息打印时再次collapseWhiteSpace与 AST 按摩阶段双重保障确保标签空白必然规范化明确拒绝小写化注释指出底层解析器remark-parse会把标签小写化为identifier而 Prettier 刻意不这样做——AsyncGeneratorFunction的大小写必须保留这是 2.1 节输出的直接依据转义方括号标签中的[、]、\会被转义\前缀避免破坏引用语法MDX 差异MDX 解析器下标签直接输出不执行转义分支。3.3 阶段三imageReference 依赖预处理恢复原始 alt 文本打印端在 case imageReference 中调用printImageAltmdast.jsfunction printImageAlt(node, options) { if (options.parser ! mdx node.originalAltText) { return node.originalAltText; } ... }originalAltText来自预处理阶段 markOriginalImageAndLinkAlt// remark 11 removes nested links so we need to recover the original alt text function markOriginalImageAndLinkAlt(ast, options) { const { originalText } options; return mapAst(ast, (node) { if (node.type image || node.type imageReference) { node.originalAltText getBracketContent( originalText, node.position.start.offset, node.position.end.offset, ); return node; } ...辅助函数 getBracketContent 从原始输入文本中按偏移量提取第一对方括号之间的内容支持转义与嵌套括号计数。也就是说alt 文本并非来自解析后的 AST 字段而是从原文逐字符恢复因此原始空白得以 1:1 保留。这解释了 2.2 节中完整引用图片 alt 空格不变的现象——Prettier 对图片 alt 采取原样照搬策略避免 alt 内容因规范化而失真。3.4 阶段四脚注节点原样输出case footnoteReference 调用 printFootnoteReferencefunction printFootnoteReference(node) { return [^${node.label}]; }脚注标签不经过空白折叠直接以[^label]形式输出而 case footnoteDefinition 则会根据内容形态决定排版若脚注定义仅含一个段落且proseWrap为never或为preserve且段落本身单行则内联输出否则以 4 空格缩进的对齐形式输出。3.5 补充规则折叠式引用保持原样shouldRemainTheSameContent 表明当节点是折叠式或快捷式引用非 full 的 linkReference以及所有 imageReference时其内容保持原样、不参与常规的文本重排function shouldRemainTheSameContent(path) { const node path.findAncestor( (node) node.type linkReference || node.type imageReference, ); return ( node (node.type ! linkReference || node.referenceType ! full) ); }四、空白折叠之外的两种特殊引用场景目录中另两个用例文件补充了大小写与空格主题之外的重要边界场景。4.1 纯数字标签issue-3835issue-3835.md 内容为[1][Test Text](http://example.com)快照显示其输出保持原样。以数字开头的标签需警惕被解析为有序列表项的干扰Prettier 在此场景下不做任何改动保证格式化的幂等性与安全性。4.2 大小写敏感标签与各类定义issue-7118issue-7118.md 覆盖了更多真实文档中常见的引用定义- see[Link to Foo][master-LinkToFoo] [master-LinkToFoo]: http://foo.com Bla bla [PascalCase][] bla. [PascalCase]: ./PascalCase.md ## [Unreleased] … [Unreleased]: https://github.com/username/project/compare/v1.0.0...HEAD快照输出显示master-LinkToFoo、PascalCase、Unreleased等连字符与大小写混写的标签全部保持原样唯一的变化是标题## [Unreleased]与正文…之间补出了一个空行——这是 Markdown 文档结构中标题与正文间空行规范化的体现与引用标签本身无关。该用例验证了 Prettier 在标签规范化上的克制只折叠空白、绝不改写标签字符从而保证与 docs/options.md 中Prettier 不会改变 Markdown 语义的整体承诺一致。五、proseWrap选项与定义排版的联动引用定义的输出形态受全局选项proseWrap影响。在 case definition 中const lineOrSpace options.proseWrap always ? line : ; return group([ printLinkReference(node), :, indent([ lineOrSpace, options.parser ! mdx node.url ? : printUrl(node.url, true), node.title null ? : [lineOrSpace, printTitle(node.title, options, false)], ]), ]);proseWrap: always时:后的分隔符是可换行的line超出printWidth即换行缩进其余取值never/preserve下固定为单个空格。该选项在 src/common/common-options.evaluate.js 中定义默认值为preserve可选值取值行为always散文超出打印宽度时换行never不换行散文块单行输出preserve保持原有换行不变默认CLI 与 API 对应写法见 docs/options.mdCLI 为--prose-wrap always|never|preserveAPI 为proseWrap: always|never|preserve。例如希望引用定义始终单行紧凑排列可配置prettier --prose-wrap never doc.md// prettier 配置 { proseWrap: never, }六、实用要点总结基于 case-and-space 用例及其快照、源码实现可将 Prettier 对 Markdown 引用语法的格式化规则归纳为四条可依赖的结论标签空白一律折叠linkReference、imageReference、definition的标签label中的连续空格在 AST 按摩阶段massage-ast/index.js与打印阶段mdast.js双重折叠为单空格标签大小写永不改写printLinkReference明确绕过解析器的小写化AsyncGeneratorFunction、PascalCase、master-LinkToFoo等标签原样保留见 issue-7118.md 输出图片 alt 文本原样保留非 MDX 解析器下完整引用图片的 alt 从原始文本恢复preprocess.js多余空格不做折叠仅折叠式图片引用的 alt 例外脚注引用与定义基本不动[^label]不折叠空白定义排版仅受proseWrap与内容形态影响。对使用者而言这意味着只要标签字符含大小写一致即使空格书写随意格式化后标签都能稳定匹配文末定义图片 alt 中的刻意排版如代码块内空白不会被破坏。若需调整引用定义换行行为通过proseWrap选项即可控制。上述规则均有 case-and-space.md 等测试用例及其快照作为可复现的验证依据。赞分享开发工具格式化CLI【免费下载链接】prettierPrettier is an opinionated code formatter.项目地址https://gitcode.com/gh_mirrors/pr/prettier点击查看免费下载相关推荐Prettier Markdown 引用式链接linkReference规范化从 issue-3835 看大小写、空白与标签匹配的格式化规则Prettier Markdown 引用式链接linkReference规范化从 issue 3835 看大小写、空白与标签匹配的格式化规则 导读 本文基开发工具格式化CLIPrettier YAML 格式化保留块标量行尾空白|- 与 - 的尾部空格处理机制解析Prettier YAML 格式化保留块标量行尾空白 | 与 的尾部空格处理机制解析 Prettier 的 YAML 格式化器基于 eemeli/yaml开发工具格式化CLIPrettier 格式化 Markdown Wiki 链接内部多余空格为何被完整保留Prettier 格式化 Markdown Wiki 链接内部多余空格为何被完整保留 Prettier 对 Markdown 的格式化遵循语法结构不变、纯文开发工具格式化CLI上一篇ABP Framework教程图书管理系统开发(6) - 作者领域层设计下一篇ABP 数据访问层Repository 模式与 ORM 集成创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考