拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Prettier SCSS 格式行为变更解析:PR 19928 为什么开始保留单元素列表中的尾随逗号

Prettier SCSS 格式行为变更解析PR #19928 为什么开始保留单元素列表中的尾随逗号【免费下载链接】prettierPrettier is an opinionated code formatter.项目地址: https://gitcode.com/gh_mirrors/pr/prettier本篇指南解析 Prettier 尚未发布的 SCSS 格式行为变更changelog 条目 changelog_unreleased/scss/19928.md源自 PR #19928作者 kovsuPrettier 的 SCSS 解析器今后会原样保留单元素括号列表里的尾随逗号trailing comma而不是像之前那样把它静默删除。读完后你能准确理解该变更影响的语法范围、它与trailingComma配置项的关系以及 src/language-css/print/parenthesized-value-group.js 中hasTrailingComma与printTrailingComma两个函数的判定逻辑从而在 CI 或代码评审中预判 diff 走向。一、变更内容(a,)不再被压成(a)changelog 条目给出的最小复现如下// Input $list: (a,); // Prettier stable $list: (a); // Prettier main $list: (a,);在 SCSS 里括号列表末尾的逗号具有类型语义它用来区分「单元素列表」和「单个值」。$list: (a,)表示一个只有一个元素a的列表而$list: (a)表示一个标量值a。对依赖列表 API如nth、length、list.append、each展开等的 SCSS 代码库来说两者行为并不等价。旧版 Prettier 会把这个逗号删掉造成语义漂移PR #19928 修复后Prettier 对这种单元素列表的尾随逗号保持不动——既不新增也不删除。需要注意的边界只有单元素的括号列表受此「保留」逻辑保护。多元素列表(1, 2,)的尾随逗号仍按既有规则处理见下文测试证据函数参数里的尾逗号foo(1,)也依然会被去除。该逻辑只挂在scss解析器上普通css解析器不存在这种列表语义行为不变。二、源码实现hasTrailingComma与printTrailingCommaSCSS 括号值的打印入口是 src/language-css/print/parenthesized-value-group.js对应value-paren_group节点见 src/language-css/printer-postcss.js 的分发逻辑。相关判定由两个函数完成1.hasTrailingComma从源码文本探测「用户是否写了逗号」function hasTrailingComma({ node, parent }, options) { if (parent.type ! value-paren_group) { return false; } const nodes node.type value-comma_group ? node.groups : [node]; const lastValue nodes.findLast((child) child.type ! value-comment); if (!lastValue) { return false; } const nextCharacter getNextNonSpaceNonCommentCharacter( options.originalText, locEnd(lastValue), ); return nextCharacter ,; }它取出括号组内最后一个非注释值节点跳过value-comment所以注释后的空行不会干扰判断再从options.originalText里向后找第一个非空白、非注释字符工具函数来自 src/utilities/get-next-non-space-non-comment-character.js若该字符是,即认定源码中存在尾随逗号。这正是 changelog 中(a,)场景的探测依据。2.printTrailingComma决定这个逗号要不要打出来function printTrailingComma(path, options) { if ( (isVarFunctionNode(path.grandparent) || (options.parser scss path.grandparent?.type ! value-func path.parent.groups.length 1 !isKeyValuePairNode(path.parent.groups[0]))) hasTrailingComma(path, options) ) { return ,; } if ( path.node.type ! value-comment !( path.node.type value-comma_group path.node.groups.every((group) group.type value-comment) ) shouldPrintTrailingComma(options) path.callParent(() isSCSSMapItemNode(path, options)) ) { return ifBreak(,); } return ; }从源码结构看打印策略分为两层第一层PR #19928 的保留逻辑当外层是变量赋值节点isVarFunctionNode或当前是scss解析器、父级括号组只含一个 grouppath.parent.groups.length 1即单元素列表、且该 group 不是键值对!isKeyValuePairNode时只要hasTrailingComma探测到源码里有逗号就直接返回,。注意这条分支没有读options.trailingComma——所以无论trailingComma配成什么$list: (a,)都原样保留。排除isKeyValuePairNode的意义在于($key: value,)这种单条 map 的尾逗号仍交给第二层按trailingComma选项处理。第二层既有的 map/列表尾逗号开关命中isSCSSMapItemNode且shouldPrintTrailingComma(options)为真时返回ifBreak(,)——即仅在换行时插入尾逗号。ifBreak保证单行 map 不受影响。shouldPrintTrailingComma定义在 src/language-css/print/misc.jsfunction shouldPrintTrailingComma(options) { return options.trailingComma es5 || options.trailingComma all; }也就是说trailingComma: none时第二层不插逗号es5默认值与all时多行 map 的换行位置会补上尾逗号。三、与trailingComma选项的协作矩阵仓库内的格式测试套件 tests/format/scss/trailing-comma/format.test.js 正是对trailingComma: none与trailingComma: es5两种取值分别跑同一批 SCSS 样例runFormatTest(import.meta, [scss], { trailingComma: none }); runFormatTest(import.meta, [scss], { trailingComma: es5 });快照 tests/format/scss/trailing-comma/snapshots/format.test.js.snap 里保留了可直接对照的预期输出单元素列表——逗号始终保留两层取值输出一致// 输入 $single-string: (a,); $single-space-list: (1 2 3,); $single-nested-list: ((1, 2),); // trailingComma: es5 与 none 的输出相同 $single-string: (a,); $single-space-list: (1 2 3,); $single-nested-list: ((1, 2),);这就是 PR #19928 修复点的直接回归验证$single-string对应 changelog 中的$list: (a,)案例在两种trailingComma取值下都保留了尾逗号。多元素列表与函数参数——尾逗号仍被去除// 输入 $multiple-items: (1, 2,); $single-argument: foo(1,); // 输出两种取值相同 $multiple-items: (1, 2); $single-argument: foo(1);单条 map——受trailingComma选项控制// 输入 $single-entry-map: (a: 1,); // trailingComma: es5 $single-entry-map: ( a: 1, ); // trailingComma: none $single-entry-map: ( a: 1 );换行 map 的注释协同——ifBreak的行为细节快照中trailing-comma.scss样例展示了注释与逗号的相对位置trailingComma: es5时逗号打在注释之前overlay: 1202, // The comma shoud be...none时则不加逗号。另外 tests/format/scss/trailing-comma/trailing-comma.scss 中那行注释本身就说明了这条既有规则// The comma shoud be printed before the comment when trailing-comma es5。非括号值的尾逗号——不受本次变更影响快照中$test: 1,;在两种取值下都输出为$test: 1;即变量值本身而非括号列表末尾的冗余逗号依旧被清理。四、如何验证该行为该行为由 Prettier 自带的格式测试基建runFormatTest配置见 tests/config/format-test/驱动快照即上文引用的.snap文件。仓库为只读参考时你只需要知道相关样例集中在 tests/format/scss/trailing-comma/ 目录测试入口、SCSS 输入文件与快照一一对应更广泛的 map/列表场景可在 tests/format/scss/map/、tests/format/scss/interpolation/ 等目录中找到补充用例若在自己的项目中复现只需对含$list: (a,);的文件分别以--trailing-comma none与--trailing-comma es5运行 SCSS 格式化对比输出即可确认单元素列表逗号在两种取值下都保留多行 map 则随取值变化。五、升级时的预期管理会减少 diff 的场景SCSS 代码库中手写的单元素括号列表(a,)、(1 2 3,)、嵌套的((1, 2),)等在升级到包含 PR #19928 的版本后尾逗号不再被格式器删除相关文件的格式化 diff 会减少甚至归零。不会变化的场景CSS非 SCSS文件、多元素列表、函数参数、以及trailingComma控制的多行 map 尾逗号规则均维持现状。语义提醒保留逗号的前提是「源码原本就有逗号」。如果你从未写(1,)Prettier 也不会主动为你补上——这是「保守保留」而非「强制添加」。小结PR #19928 让 Prettier 在 SCSS 单元素括号列表这一窄而关键的语法点上从「改写」转向「尊重作者意图」hasTrailingComma基于原始文本探测逗号存在性printTrailingComma的第一层分支对 scss 变量中的单元素列表无条件保留第二层继续沿用trailingComma选项管理 map 场景。该逻辑仅作用于scss解析器测试基线完整落在 tests/format/scss/trailing-comma/ 目录中可作为行为变更的权威对照。【免费下载链接】prettierPrettier is an opinionated code formatter.项目地址: https://gitcode.com/gh_mirrors/pr/prettier创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门