Rome useTemplate 规则详解:用模板字符串替代字符串拼接的检测与自动修复
【免费下载链接】toolsUnified developer tools for JavaScript, TypeScript, and the web项目地址: https://gitcode.com/gh_mirrors/to/tools
Rome(当前仓库tools)内置的useTemplate代码风格 lint 规则,用于检测 JavaScript/TypeScript 代码中不必要的字符串拼接,并推荐使用 ES6 模板字符串(Template Literal)取而代之。本文以该规则为核心,完整讲解其触发条件、诊断输出格式、自动修复行为与底层实现原理,并结合仓库源码与测试用例,帮助你准确理解该规则的使用边界,在项目中放心地开启它。
规则概览
- 规则名称:
useTemplate - 所属分类:
lint/style/useTemplate - 引入版本:v0.7.0(见 use_template.rs 中
declare_rule!声明的version: "0.7.0") - 推荐程度:recommended(Rome 官方推荐启用)
- 修复能力:可自动修复(FIXABLE),修复类别为 QuickFix,适用性标记为
MaybeIncorrect
规则的核心主张只有一句话:Template literals are preferred over string concatenation——优先使用模板字符串,而不是+运算符做字符串拼接。这是rome_js_analyze分析器在 style 分类下众多规则之一,注册入口见 analyzers/style.rs。
触发条件:什么代码会被判定为不合规
从源码实现(use_template.rs 的is_unnecessary_string_concat_expression函数)可以归纳出该规则的判定逻辑:
- 只检查
+运算符(JsBinaryOperator::Plus)的二元表达式,其他运算符直接跳过; - 只要表达式左侧或右侧满足以下任一条件,即判定为不必要的字符串拼接:
- 操作数是字符串字面量(且该字符串不含换行符或反引号
`); - 操作数是模板字符串;
- 操作数是另一个被判定为不必要的字符串拼接的
+表达式(递归检查)。
- 操作数是字符串字面量(且该字符串不含换行符或反引号
关键边界:两个字符串字面量相加("foo" + "bar")属于合法写法,不会触发规则;包含换行符或反引号的字符串也不会被标记(因为这类字符串无法无痛地转换为模板字符串,见has_new_line_or_tick检查)。
Invalid:会触发诊断的代码
以下来自官方文档的示例全部会命中规则:
console.log(foo + "baz"); console.log(1 * 2 + "foo"); console.log(1 + "foo" + 2 + "bar" + "baz" + 3); console.log((1 + "foo") * 2); console.log("foo" + 1);测试快照 invalid.jsonc 中还有更多覆盖,包括:
const foo = 'bar'; console.log('foo' + `bar${`baz${'bat' + 'bam'}`}` + 'boo'); // 嵌套模板字符串参与拼接 console.log('foo' + 1 + 2); // 数字与字符串混合拼接 foo() + ' bar'; // 函数调用结果与字符串拼接 console.log('${foo.' + bar + '.baz}'); // 字符串中本就有 ${ 占位符值得注意的是,即便字符串内部已经包含${、`等模板字符串特殊字符(例如'${foo.' + bar + '.baz}'),规则依然会触发,并在修复时对$、`等字符进行转义,保证修复结果语义不变。
Valid:不会触发诊断的代码
console.log("foo" + "bar"); // 两个纯字符串字面量拼接,不触发 console.log(foo() + "\n"); // 字符串含换行符,不触发对应测试文件 valid.jsonc。
诊断输出与自动修复
当规则命中时,Rome CLI 会输出带FIXABLE标记的详细诊断信息,并附上 Suggested fix。以console.log(foo + "baz")为例,官方文档展示了完整输出:
style/useTemplate.js:1:13 lint/style/useTemplate FIXABLE ✖ Template literals are preferred over string concatenation. > 1 │ console.log(foo + "baz"); │ ^^^^^^^^^^^ ℹ Suggested fix: Use a TemplateLiteral. 1 │ console.log(`-${foo}baz`-); │ console.log(`${foo}baz`);诊断消息中的核心文案Template literals are preferred over string concatenation.由源码 use_template.rs 中的diagnostic方法生成,使用markup!宏强调关键字;修复建议Use a TemplateLiteral.则来自action方法(同文件 L112-L128)。
修复示例对照
| 原始代码 | 修复后代码 |
|---|---|
console.log(foo + "baz") | console.log(`${foo}baz`) |
console.log(1 * 2 + "foo") | console.log(`${1 * 2}foo`) |
console.log(1 + "foo" + 2 + "bar" + "baz" + 3) | console.log(`${1}foo${2}bar${3}`) |
console.log((1 + "foo") * 2) | console.log((`${1}foo`) * 2) |
console.log("foo" + 1) | console.log(`foo${1}`) |
注意最后一个修复:(1 + "foo") * 2中+表达式位于乘法表达式内部,修复时只替换被命中的+子表达式,外层括号与乘法保持不变——说明修复是基于 AST 节点的精准替换,不会破坏外层运算语义。
底层实现原理:从 AST 匹配到模板字符串生成
该规则基于rome_js_analyze的规则框架实现,通过declare_rule!宏声明,主要逻辑分四步(use_template.rs):
1. 查询与筛选(run)
规则的查询类型是Ast<JsBinaryExpression>,即每个二元表达式节点都会进入该规则。run方法先调用is_unnecessary_string_concat_expression判断是否为不必要的字符串拼接,再调用collect_binary_add_expression把形如1 + 2 + 3 + (1 * 2)的连续+链递归摊平成[1, 2, 3, (1 * 2)]的表达式列表(见 collect_binary_add_expression)。
最后还有一个重要过滤:摊平后的列表中必须至少有一个非纯字符串字面量的表达式才报错——这正是"foo" + "bar"不触发规则的原因。
2. 抑制逻辑(suppressed_nodes)
规则遍历查询节点的整棵子树,遇到JS_BINARY_EXPRESSION节点就将其标记为可抑制,其余子树直接跳过,从而保证// rome-ignore等抑制注释能覆盖到所有相关子表达式。
3. 诊断生成(diagnostic)
对命中的表达式生成规则诊断,消息统一为Template literals are preferred over string concatenation.,并标记为可修复(FIXABLE)。
4. 修复动作(action)
action是自动修复的核心,通过 convert_expressions_to_js_template 把摊平后的表达式列表合并成一个模板字符串:
- 字符串字面量→ 去掉引号后作为模板字符串的纯文本块(chunk),其中
${和`会被转义为\${、```,避免破坏模板语义; - 已有的模板字符串→ 通过
flatten_template_element_list递归展开嵌套模板(如`${1 + 2 + `${a}test`}bar`会被展开为[1, 2, a, "test", "bar"],见 flatten_template_element_list),并入外层模板; - 其他表达式→ 作为
${expr}插值元素放入模板,并去除表达式两侧多余空格,让生成的模板更整洁(源码注释举例:若不 trim,1 * (2 + "foo") + "bar"会生成`${1 * (2 + "foo") }bar`这种带多余空格的丑陋结果)。
最终通过make::js_template_expression构造出`...`节点,用mutation.replace_node替换原二元表达式节点。修复类别为ActionCategory::QuickFix,适用性为Applicability::MaybeIncorrect——意味着工具无法 100% 保证修复结果正确,建议结合代码评审使用。
在项目中启用与使用
由于该规则是recommended规则,使用 Rome 默认配置(rome.json)时即会自动启用。如需显式配置,可在rome.json的 linter 配置中调整:
{ "linter": { "enabled": true, "rules": { "style": { "useTemplate": "error" // 或 "warn"、"off" } } } }规则禁用方法(如行内// rome-ignore lint/style/useTemplate: <reason>)与规则选项的完整说明,可参考 linter 指南。
运行检查与自动修复的命令(以本地rome_cli为例):
# 仅检查,输出诊断 cargo run -p rome_cli -- check path/to/file.js # 应用可用的自动修复 cargo run -p rome_cli -- check --apply path/to/file.js注意:修复适用性标记为
MaybeIncorrect,使用--apply批量修复后建议运行测试确认行为无变化,尤其是涉及${、`、换行等特殊字符的拼接场景。
测试覆盖:快照驱动的规则质量保障
useTemplate的测试采用 Rome 标准的 JSONC 快照测试体系(测试框架见 spec_tests.rs):
- invalid.jsonc:24 个不合规用例,覆盖纯字符串拼接、混合类型拼接、嵌套模板、
${与`特殊字符转义、注释保留等边界场景; - valid.jsonc:合规用例,验证
"foo" + "bar"与含换行字符串不误报; - 对应的 invalid.jsonc.snap / valid.jsonc.snap 快照文件锁定诊断输出与修复结果,防止规则行为在后续迭代中发生无意的回归。
总结
useTemplate是 Rome 推荐启用的 style 类规则,它精准识别"字符串与表达式混拼"的+表达式,并提供基于 AST 的自动修复,把拼接改写为语义等价的模板字符串。理解它的触发边界(两个字符串字面量拼接、含换行/反引号的字符串不触发)与修复策略(嵌套模板展平、特殊字符转义、表达式去空格),有助于你在团队中安全地落地这条规则,写出更一致、更可读的字符串构造代码。
【免费下载链接】toolsUnified developer tools for JavaScript, TypeScript, and the web项目地址: https://gitcode.com/gh_mirrors/to/tools
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考