eslint-plugin-unicorn 的 operator-assignment 规则:强制赋值运算符简写并智能识别模板字符串场景
eslint-plugin-unicorn 的 operator-assignment 规则强制赋值运算符简写并智能识别模板字符串场景【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn导读operator-assignment是 eslint-plugin-unicorn 提供的核心规则之一其目标是在可能的情况下强制使用赋值运算符简写如foo bar替代foo foo bar。它完全继承 ESLint 内置同名规则的语义与配置并额外扩展了模板字符串template literal场景的自动建议能力。本文基于规则源码 rules/operator-assignment.js、官方文档 docs/rules/operator-assignment.md 以及完整快照测试 test/snapshots/operator-assignment.js.md从使用配置、底层实现到测试验证逐层剖析帮助读者彻底理解并正确使用该规则。规则概述与定位规则功能一句话概括Require assignment operator shorthand where possible.即凡是能写成赋值运算符简写形式的地方都要求使用简写。例如把foo foo bar;改写为foo bar;。与 ESLint 内置规则的关系该规则并非凭空发明而是对 ESLint 内置operator-assignment规则的增强替代它通过 get-builtin-rule.js 中的getBuiltinRule(operator-assignment)直接取出 ESLint 内置规则作为baseRule在保留内置规则全部检查能力的基础上额外处理模板字符串场景因此文档明确声明该规则替换了 ESLint 内置的operator-assignment规则当本规则启用时Unicorn 的推荐配置会禁用内置同名规则避免重复告警。从 rules/index.js 可以看到该规则以operator-assignment名称被导出注册。推荐配置中的状态在 ✅recommended配置中默认启用在 ☑️unopinionated配置中被禁用因为该规则属于有观点的风格约束。修复能力规则同时支持两种修复方式文档中以 标注通过 ESLint 的--fixCLI 选项自动修复通过编辑器建议rule suggestions手动应用。需要注意的是模板字符串场景只提供建议suggestion而不参与--fix自动修复原因详见下文为何模板字符串只给建议一节。配置与使用配置项该规则完全复用 ESLintoperator-assignment的 schema支持两个取值rules/operator-assignment.js 中schema: baseRule.meta.schema直接继承defaultOptions: [always]取值含义是否为默认always要求尽可能使用赋值运算符简写默认值✅never禁止使用赋值运算符简写强制展开为完整赋值❌配置示例在 ESLint 配置flat config 或 legacy config 均可中启用并配置该规则// eslint.config.jsflat config import unicorn from eslint-plugin-unicorn; export default [ { plugins: { unicorn, }, rules: { // 默认行为要求简写 unicorn/operator-assignment: error, // 或者显式声明 always与默认一致 unicorn/operator-assignment: [error, always], // 或者禁止简写强制展开 unicorn/operator-assignment: [error, never], }, }, ];两种模式的典型告警always模式默认下以下代码会被标记// ❌ 应改为 foo bar; foo foo bar;never模式下语义完全反转// ❌ 在 never 模式下应改为 foo foo bar; foo bar;测试用例 test/operator-assignment.js 中给出了两种模式的 valid 对照{code: foo foo bar;, options: [never]}合法而{code: foo bar;, options: [never]}非法。模板字符串场景本规则的核心增强基本转换这是本规则区别于内置规则的最大亮点。当模板字符串以插值目标变量本身开头时规则会建议改写为赋值运算符 模板字符串尾部// ❌ foo ${foo} bar; // ✅建议写法 foo bar;对应快照 test/snapshots/operator-assignment.js.md 中的invalid(3)Message:Assignment () can be replaced with operator assignment ().Suggestion:Use \ assignment.Output:foo bar;触发条件源码级拆解从 rules/operator-assignment.js 的getTemplateLiteralProblem函数可以看出模板字符串场景必须同时满足以下全部条件才会被处理运算符必须是node.operator ! 直接返回左侧必须是简单标识符node.left.type ! Identifier直接返回因此object.foo ${object.foo} baz 这类属性赋值不会被处理在测试 valid 列表中可见右侧必须是模板字符串node.right.type ! TemplateLiteral直接返回模板字符串的第一个 quasi静态片段必须是空字符串right.quasis[0].value.raw ! 直接返回即字符串必须以${开头第一个插值表达式必须是标识符且与左侧变量同名firstExpression.name ! left.name直接返回。任何一条不满足即静默放弃处理交由内置规则原有的逻辑兜底。边界条件处理源码中还针对多种边界情况做了防护尾部为空不处理如果模板字符串去掉首插值后只剩即foo ${foo}不给出建议rules/operator-assignment.js因为此时改写为foo 毫无意义注释越界不处理通过hasCommentsOutsideRangerules/operator-assignment.js检查节点内是否还有位于模板字符串尾部区间之外的注释如赋值号左侧、模板字符串整体之前的注释若有则放弃以免重写代码时丢失注释。测试中的 valid 用例foo /* keep */ ${foo} baz;、foo /* keep */${foo} baz;、(/* keep */ foo) ${foo} baz;、foo (${foo} baz/* keep */);都是对这一防护的验证。为何模板字符串只给建议而不自动修复这是设计上深思熟虑的取舍文档明确说明The template literal case is suggestion-only because the change can affect coercion and side-effect ordering for unusual values.原因有两类类型强制转换coercion差异foo ${foo} bar中${foo} 是显式的字符串插值隐式调用 String(foo)而改写为 foo bar后若foo原本是数字会触发数字加法而非字符串拼接例如foo 1时结果天差地别求值/副作用顺序side-effect ordering差异改写后模板字符串尾部各插值表达式的求值时机相对左值引用发生了变化对于带 getter 或副作用的表达式可能产生不同结果。因此源码实现rules/operator-assignment.js将该场景封装为suggest数组仅通过编辑器建议提供修复方案而fixable能力meta.fixable: baseRule.meta.fixable只作用于内置规则原有的普通场景如foo foo bar→foo bar。模板字符串尾部区间计算getTemplateLiteralTailRangerules/operator-assignment.js负责定位首插值之后的区间以模板字符串第二个 quasi 的起始位置加 1跳过反引号后的字符边界为起点以整个模板字符串的结束位置为终点getTemplateLiteralTailText再据此切片并重新拼上反引号得到建议中的模板字符串尾部如 bar。这套区间计算保证了包括转义、换行、嵌套插值在内的各种模板字符串都能被正确切片。快照测试逐例解读快照文件 test/snapshots/operator-assignment.js.md 由 AVA 测试框架在 test/operator-assignment.js 运行时自动生成记录了全部 8 个非法用例的告警消息、输出和建议。逐例梳理如下用例输入告警内容建议输出invalid(1)foo foo bar;Assignment () can be replaced with operator assignment ().可自动修复foo bar;invalid(2)foo bar;options:neverUnexpected operator assignment () shorthand.可自动修复foo foo bar;invalid(3)foo ${foo} bar;同上可替换为 建议foo \bar;invalid(4)foo ${foo } bar;插值内有空格同上建议foo \bar;invalid(5)foo ${foo\n} bar;插值跨行同上建议foo \bar;invalid(6)foo ${foo}${bar};尾部含第二个插值同上建议foo \${bar};invalid(7)foo ${foo} ${/* keep */ bar};尾部插值含注释同上建议foo \${/* keep */ bar};invalid(8)foo ${foo} bar ${baz};混合文本与插值同上建议foo \bar ${baz};从这些用例中可以提炼出几个关键设计行为invalid(1) 是普通场景属于内置规则能力走--fix自动修复路径快照中直接给出Outputinvalid(2) 验证never模式快照中记录了Options: - never证明配置选项确实被规则读取并改变行为invalid(3)invalid(8) 全部是模板字符串增强场景它们只有Suggestion而没有直接Output直观印证了模板字符串场景仅建议、不自动修复的设计空格、换行、转义均被正确处理invalid(4)/invalid(5) 表明无论首插值内部是否有空格或跨行切片逻辑都能准确产出 bar形式的尾部注释被保留invalid(7) 中/* keep */完整保留在建议输出中多插值尾部正确拼接invalid(6)/invalid(8) 表明尾部可以包含额外的插值表达式和混合静态文本。对应地测试文件中还列出了大量 valid 用例test/operator-assignment.js用于确保规则不会误报例如// 合法不满足触发条件 foo ${foo}; // 尾部为空 foo ${bar} baz; // 首插值不是左侧变量 object.foo ${object.foo} baz; // 左侧不是 Identifier foo ${/* keep */ foo} baz; // 首 quasi 前有注释导致首个 quasi 非空 foo ${foo /* keep */} baz; // 首插值内有注释越界防护规则的配置与运行机制规则元信息meta从 rules/operator-assignment.js 可见该规则的完整元信息type继承内置规则的baseRule.meta.typedocs.recommended: true确认其属于推荐配置fixable继承内置规则的修复能力hasSuggestions: true声明提供编辑器建议schema继承内置规则的参数校验 schemadefaultOptions: [always]默认使用always模式languages: [js/js]仅作用于 JavaScript 文件。运行逻辑create函数rules/operator-assignment.js的核心逻辑为从baseRule.create(context)取到内置规则的AssignmentExpression处理器onAssignmentExpression在自定义的AssignmentExpression监听器中先调用内置处理器保证原有检查不丢若配置不是never即shouldCheckTemplateLiterals context.options[0] ! never见 rules/operator-assignment.js再额外调用getTemplateLiteralProblem处理模板字符串场景。这一内置规则 自定义扩展的组合模式是 Unicorn 中若干增强型规则的通用做法先委托给 ESLint 内置实现保证基础能力再叠加本项目特有的检查逻辑。注意never模式下模板字符串增强会被跳过shouldCheckTemplateLiterals为 false此时foo ${foo} bar是合法代码——这一点在测试 valid 列表中也有对应断言{code: foo ${foo} bar;, options: [never]}。与其他规则的关联与内置规则的关系该规则是 ESLintoperator-assignment的直接替换品Unicorn 推荐配置启用它时会关闭 ESLint 内置同名规则避免重复报告与逻辑运算符简写规则的关系如果项目中同时需要规范、||、??等逻辑赋值运算符的使用可以配合 Unicorn 的其他相关规则一起使用例如 logical-assignment-operators 同样关注赋值运算符的简写形式但聚焦于逻辑运算场景两者互补形成完整的赋值风格约束。小结operator-assignment规则通过继承 ESLint 内置规则 扩展模板字符串建议的方式为开发者提供了两方面的价值一致性统一团队代码中的赋值书写风格always模式下所有可简写的赋值都必须简写never模式下则全部展开增量增强独创的模板字符串首插值识别把foo ${foo} bar这类常见写法智能收敛为foo bar并通过仅建议的安全策略规避类型强制转换与副作用顺序带来的风险。其实现rules/operator-assignment.js、测试test/operator-assignment.js与快照test/snapshots/operator-assignment.js.md三件套完整自洽读者可以在此基础上进一步阅读源码理解 Unicorn 如何以最小代价复用并增强 ESLint 生态的既有能力。【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考