ESLint generator-star-spacing 规则详解:统一生成器函数*星号周围的空格写法
【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint
本篇文章围绕 ESLint 内置的generator-star-spacing规则展开,系统讲解它在当前仓库(ESLint 核心)中的定义、全部配置方式(对象式与字符串简写、按函数类型的 override 覆盖)、四种星号排版风格的正误代码示例,并结合 lib/rules/generator-star-spacing.js 的源码实现与 tests/lib/rules/generator-star-spacing.js 的测试用例,说明该规则如何工作、如何自动修复,以及它作为格式化规则被移出核心的演进背景。读完本文,你将能准确配置并理解生成器函数*的空格校验规则,也能掌握阅读同类 ESLint 规则源码的基本方法。
一、背景:ECMAScript 6 生成器函数的多种合法写法
生成器(Generator)是 ECMAScript 6 引入的一种新型函数,它可以在执行过程中多次返回(yield)值。这种特殊函数通过在function关键字后放置一个*(星号)来标识,但 JavaScript 语法对星号与相邻 token 之间的空格非常宽容,导致同一种语义存在多种书写形式:
// 形式一:* 紧贴 function 关键字 function* generator() { yield "44"; yield "55"; } // 形式二:* 与 function 之间有一个空格 function *generator() { yield "44"; yield "55"; } // 形式三:* 前后都有空格 function * generator() { yield "44"; yield "55"; }以上三种写法在语法上都完全合法,但混用会破坏代码风格的一致性。generator-star-spacing规则的目标正是为*强制规定一个唯一位置,从而在团队协作中保持统一的排版习惯。这也是为什么该规则在 lib/rules/generator-star-spacing.js 的meta中被标记为type: "layout"(排版类规则)且fixable: "whitespace"(可自动修复空白问题)。
二、规则核心:围绕*的两个校验维度
该规则的本质是检查生成器函数*两边的空格情况,具体包含两个维度:
before:控制*与function关键字之间的空格。- 为
true时要求必须有空格;为false时禁止出现空格。 - 特殊说明:在对象字面量的简写方法(shorthand method,如
{ *generator() {} })中,由于不存在function关键字,因此不会检查*之前的空格。
- 为
after:控制*与函数名之间的空格;对于匿名生成器函数(没有名字),则指*与左括号(之间的空格。- 为
true时要求必须有空格;为false时禁止出现空格。
- 为
规则的默认配置为{"before": true, "after": false},即默认要求function与*之间有一个空格、*与函数名之间没有空格,对应最常见的function *generator()风格。
三、配置方式
该规则接受一个配置项,可以是对象或字符串简写两种形式。
3.1 对象形式
对象形式包含"before"和"after"两个布尔键,例如:
"generator-star-spacing": ["error", {"before": true, "after": false}]3.2 字符串简写
四种before/after组合可以简写为单个字符串:
| 完整对象 | 简写字符串 |
|---|---|
{"before": true, "after": false} | "before" |
{"before": false, "after": true} | "after" |
{"before": true, "after": true} | "both" |
{"before": false, "after": false} | "neither" |
例如:
"generator-star-spacing": ["error", "after"]在源码 lib/rules/generator-star-spacing.js 中,这四种简写通过optionDefinitions对象直接映射到对应的布尔配置:
const optionDefinitions = { before: { before: true, after: false }, after: { before: false, after: true }, both: { before: true, after: true }, neither: { before: false, after: false }, };3.3 按函数类型进行 override 覆盖
除顶层配置外,规则还允许按函数类型进一步细分配置,提供三个可选键:
named:为具名函数(命名函数声明/表达式)提供覆盖配置;anonymous:为匿名函数提供覆盖配置;method:为类方法或对象属性简写方法(property function shorthand)提供覆盖配置。
每个 override 的值既可以是{"before": ..., "after": ...}对象,也可以是上述简写字符串。示例:
"generator-star-spacing": ["error", { "before": false, "after": true, "anonymous": "neither", "method": {"before": true, "after": true} }]在该示例中,顶层"before": false, "after": true定义了默认行为(即"after"风格),而"anonymous": "neither"和"method": {"before": true, "after": true}则覆盖默认行为,分别约束匿名函数与方法/类方法的星号排版。
从源码可见,解析时每个类型都会先以顶层配置为默认值,再应用各自的 override(lib/rules/generator-star-spacing.js):
const modes = (function (option) { const defaults = optionToDefinition(option, optionDefinitions.before); return { named: optionToDefinition(option.named, defaults), anonymous: optionToDefinition(option.anonymous, defaults), method: optionToDefinition(option.method, defaults), }; })(context.options[0] || {});其中optionToDefinition(lib/rules/generator-star-spacing.js)负责把字符串简写转成对象、把对象与默认值合并,未提供的键自动回落到默认值。另外,选项的 JSON Schema 定义在 lib/rules/generator-star-spacing.js 中,named/anonymous/method每个都复用了同一个OVERRIDE_SCHEMA(允许字符串枚举或{before, after}对象),且对象形式不允许出现额外的属性(additionalProperties: false)。
3.4 函数类型的判定逻辑
源码通过checkFunction判断当前节点属于哪一类(lib/rules/generator-star-spacing.js):
let kind = "named"; if ( node.parent.type === "MethodDefinition" || (node.parent.type === "Property" && node.parent.method) ) { kind = "method"; } else if (!node.id) { kind = "anonymous"; }即:父节点是MethodDefinition(类方法)或Property且method为真(对象简写方法)时归类为method;没有id(函数名)时归类为anonymous;否则为named。测试用例 tests/lib/rules/generator-star-spacing.js 中“full configurability”一组也逐一验证了具名函数、匿名函数、类方法、对象简写方法各自的 override 生效情况。
四、四种风格的正误代码示例
以下示例均使用行内注释形式声明规则配置,可直接在 ESLint 中运行验证。
4.1before风格(默认)
配置:{"before": true, "after": false},要求*前有空格、*后无空格。
正确代码:
/*eslint generator-star-spacing: ["error", {"before": true, "after": false}]*/ function *generator() {} var anonymous = function *() {}; var shorthand = { *generator() {} };4.2after风格
配置:{"before": false, "after": true},要求*前无空格、*后有空格。
正确代码:
/*eslint generator-star-spacing: ["error", {"before": false, "after": true}]*/ function* generator() {} var anonymous = function* () {}; var shorthand = { * generator() {} };注意这里的简写方法{ * generator() {} }:由于对象简写方法没有function关键字,before维度不做检查,因此*前可以有一个空格而不报错。
4.3both风格
配置:{"before": true, "after": true},要求*前后都有空格。
正确代码:
/*eslint generator-star-spacing: ["error", {"before": true, "after": true}]*/ function * generator() {} var anonymous = function * () {}; var shorthand = { * generator() {} };4.4neither风格
配置:{"before": false, "after": false},要求*前后都无空格。
正确代码:
/*eslint generator-star-spacing: ["error", {"before": false, "after": false}]*/ function*generator() {} var anonymous = function*() {}; var shorthand = { *generator() {} };注意{ *generator() {} }同样是合法的:因为简写方法不检查before,*前保留空格不会被判定为错误。
五、override 组合的正误对比
仍然使用前文的组合配置:
/*eslint generator-star-spacing: ["error", { "before": false, "after": true, "anonymous": "neither", "method": {"before": true, "after": true} }]*/错误代码(每一行都违背了对应的规则分支):
function * generator() {} // 具名函数:默认 "after" 风格,* 前不应有空格 var anonymous = function* () {}; // 匿名函数:被 "neither" 覆盖,* 后不应有空格 var shorthand = { *generator() {} }; // 简写方法:被 method: both 覆盖,* 后应有空格 class Class { static* method() {} } // 类方法:被 method: both 覆盖,* 前后都应有空格正确代码:
function* generator() {} var anonymous = function*() {}; var shorthand = { * generator() {} }; class Class { static * method() {} }这里尤其值得注意:顶层默认是"after"风格,但methodoverride 将类方法/简写方法改写为both风格,因此class Class { static * method() {} }和{ * generator() {} }都是正确的——这正是 override 机制的实际价值:可以在同一项目中让不同函数类型各自遵循不同的星号排版约定。
六、规则如何工作与自动修复(源码级解析)
6.1 定位星号 token
规则在遍历 AST 时监听FunctionDeclaration与FunctionExpression节点(lib/rules/generator-star-spacing.js)。对每个节点:
- 通过
node.generator判断是否为生成器函数,不是则直接跳过(lib/rules/generator-star-spacing.js); - 通过
getStarToken找到*token——对类方法/简写方法,从父节点上找第一个Punctuator类型且值为*的 token(lib/rules/generator-star-spacing.js); - 用
getTokenBefore/getTokenAfter取得星号两侧的相邻 token。
6.2 判定并报告
checkSpacing会比较左右 token 之间是否真实存在字符(rightToken.range[0] - leftToken.range[1])与目标模式是否一致,不一致则按缺失/多余两种情况报告(lib/rules/generator-star-spacing.js)。规则共定义了 4 条消息(lib/rules/generator-star-spacing.js):
| messageId | 含义 |
|---|---|
missingBefore | *前缺少空格 |
missingAfter | *后缺少空格 |
unexpectedBefore | *前出现了多余空格 |
unexpectedAfter | *后出现了多余空格 |
6.3 自动修复
规则是可自动修复的(fixable: "whitespace")。修复逻辑(lib/rules/generator-star-spacing.js)为:
- 需要空格时,在星号前/后插入一个空格(
insertTextBefore/insertTextAfter); - 需要删除空格时,直接移除左 token 到右 token 之间的整个范围(
removeRange)。
测试文件 tests/lib/rules/generator-star-spacing.js 中大量“invalid + output”成对用例验证了修复行为,例如默认配置下:
// 输入(invalid) function*foo(){} // 修复后(output) function *foo(){}同时报告missingBeforeError(*前缺空格)。测试还覆盖了async函数不受影响的场景(tests/lib/rules/generator-star-spacing.js),并验证了function* foo(){}这类同时违反两个维度的情况会一次报告两条错误(missingBeforeError+unexpectedAfterError)并一次性修复到位。
七、规则现状与迁移说明
该规则在 ESLint 核心中已处于**废弃(deprecated)**状态。源码 lib/rules/generator-star-spacing.js 中的meta.deprecated表明:
- 废弃起始版本:ESLint v8.53.0;
- 核心内保留至:ESLint v11.0.0;
- 废弃原因:格式化类规则正在从 ESLint 核心移出,改由
@stylistic/eslint-plugin插件长期维护,对应规则名为generator-star-spacing(同名的格式化规则)。
另外,仓库 conf/replacements.json 中保留了历史上更早的一条规则替换记录:"generator-star": ["generator-star-spacing"],说明旧版名为generator-star的规则已合并/更名为generator-star-spacing。
八、何时不使用此规则
如果项目根本不会使用生成器函数,或者你并不关心星号周围的空格是否统一,那么完全可以不启用此规则。它属于纯排版类(layout)规则,不影响代码的运行语义,仅关乎代码风格一致性。
九、参考路径速查
- 规则文档:docs/src/rules/generator-star-spacing.md
- 规则实现:lib/rules/generator-star-spacing.js
- 规则注册入口:lib/rules/index.js(懒加载
require("./generator-star-spacing")) - 规则测试:tests/lib/rules/generator-star-spacing.js
- 历史规则替换映射:conf/replacements.json
【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考