ESLint 核心规则变更提案:模板逐字段填写指南与源码落地路径
2026/9/13 2:58:14 网站建设 项目流程

ESLint 核心规则变更提案:模板逐字段填写指南与源码落地路径

【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint

ESLint 的templates/rule-change-proposal.md是提交"核心规则变更"时必须填写的 issue 模板,它决定了团队能否快速判断你的变更是否值得纳入核心。本文以该模板为骨架,逐字段讲解每一项的意图与填写要点,并结合仓库中的规则源码(如lib/rules/no-extra-semi.js)、核心规则规范(docs/src/contribute/core-rules.md)与提案流程文档,说明一个变更从模板提案到代码合入的完整路径。读完本文,你将能独立提交一份专业、完整、可被快速评估的规则变更提案,并理解提案中每个技术选项背后的 ESLint 内部机制。

一、先理解"规则变更"与"新增规则"的区别

在填写模板前,需要先明确 ESLint 对两类贡献的区分:

  • 新增规则(new rule):提交到核心库中的全新规则,使用templates/rule-proposal.md模板,其流程见 docs/src/contribute/propose-new-rule.md。自 2020 年起,ESLint 只接受与新 ECMAScript 特性相关的核心新规则,其余新规则更倾向于以插件形式发布。
  • 规则变更(rule change):对已有核心规则的行为增强或调整。这不是修 bug,而是让规则"更可配置、更贴合实际使用"的功能改进,使用 templates/rule-change-proposal.md 模板。其完整流程见 docs/src/contribute/propose-rule-change.md。

两者都要先通过"提案-审核"关口,而模板正是审核的第一道过滤网——所有字段都是为了让团队在看不到代码的情况下判断该变更是否值得进入评审流程。

二、模板逐字段精讲

字段 1:What rule do you want to change?

明确指出要变更的目标规则 ID,例如no-extra-semiquotesno-unused-vars。建议同时附上该规则当前的行为摘要,方便评审者快速定位(仓库中每条核心规则都有三份同名文件:源码、测试与文档,例如lib/rules/no-extra-semi.jstests/lib/rules/no-extra-semi.jsdocs/src/rules/no-extra-semi.md,详见 docs/src/contribute/core-rules.md 的 "File Structure" 一节)。

字段 2:What change do you want to make?

模板要求仅选择一项(在对应项的[ ]中打X),目的是让变更边界清晰、可单独评审。四个选项分别对应不同的源码机制:

  • [ ] Generate more warnings(产生更多告警):扩大规则的覆盖范围,让更多代码模式被报告。从源码结构看,这类变更通常对应规则create()中新增的 AST 访问器或更宽的判定条件。
  • [ ] Generate fewer warnings(产生更少告警):收窄规则,避免误报(false positive)。通常需要调整现有访问器中的判定逻辑。
  • [ ] Implement autofix(实现自动修复):为规则补充--fix能力。这在源码层面对应规则模块的meta.fixable(取值为"code""whitespace")以及context.report()中的fix(fixer)函数。重要meta.fixable是强制属性,若规则提供了fix函数却未声明meta.fixable,ESLint 会直接抛出错误(见 docs/src/extend/custom-rules.md)。
  • [ ] Implement suggestions(实现建议):提供供编辑器等工具手动应用的修复建议(suggestions)。对应源码中的meta.hasSuggestions: truecontext.report()suggest数组选项。与 autofix 的区别在于:autofix 由--fix自动应用,而 suggestions 不会自动执行,适合"修改可能改变行为"或"有多种合理改法"的场景。同样地,meta.hasSuggestions也是强制属性。

字段 3:How will the change be implemented?

同样只选一项,用于评估实现成本与兼容性风险:

  • [ ] A new option(新增一个配置选项):这是最常见的规则变更形式。在源码中对应meta.schema(用于校验用户传入的选项,防止非法配置)与meta.defaultOptions(为选项提供默认值,用户配置会递归合并到默认值之上)。规则通过context.options数组读取配置(注意:数组第一位是严重级别,不会出现在context.options中,规则无法感知自己被配置为"off"/"warn"/"error")。例如yoda规则的 schema 同时接受位置参数"always"/"never"与可选对象{ exceptRange: boolean },完整示例见 docs/src/extend/custom-rules.md 的 "Options Schemas" 小节。
  • [ ] A new default behavior(改变默认行为):不新增选项,而是修改规则在未配置选项时的默认表现。这类变更影响面最大,因为现有用户在不改动配置的情况下行为会发生变化,审核会格外严格。
  • [ ] Other(其他):以上均不适用的情况(例如修改规则文档、调整告警消息文案等),需要在此处详细文字说明。

字段 4:Please provide some example code that this change will affect:

提供最小可复现的示例代码,放在模板的 JS 代码块中。好的示例应该做到:只包含触发变更所需的最少语法、不依赖项目上下文、能直接粘贴进RuleTester测试。从仓库的测试组织方式看,这类代码最终会成为tests/lib/rules/<rule-id>.jsinvalid(应报错)或valid(不应报错)用例的输入。

字段 5:What does the rule currently do for this code?

用文字精确描述现状:这段示例代码在当前规则下是否被报告?报告什么消息?是否可自动修复?这一描述是评审者判断"变更必要性与影响范围"的核心依据,务必基于实际运行结果(可先在本地用 ESLint 对示例代码执行npx eslint验证后再填写)。

字段 6:What will the rule do after it's changed?

描述变更后的预期行为:是否报告、消息是否变化、是否有 autofix/suggestions、默认行为是否改变。这一字段应当具体到可以被测试用例直接断言的程度——ESLint 要求每条核心规则必须附带完整的单元测试(使用RuleTester),"变更后行为"就是测试的验收标准。

三、模板之外:提案如何被审核与接受

模板提交后,规则变更需通过三项门槛(依据 docs/src/contribute/propose-rule-change.md):

  1. 符合 Core Rule Guidelines(核心规则准则):变更后的规则必须依然满足这些通用要求(详见 docs/src/contribute/propose-new-rule.md 的 "Core Rule Guidelines" 一节):
    • 广泛适用:对大量开发者有意义,不支持小众偏好;
    • 通用:描述规则的逻辑不超过两个"且"(如果规则描述需要三个以上条件,通常过于具体);
    • 原子性:规则完全独立运行,禁止感知其他规则的存在或状态;
    • 唯一性:不能与现有规则产生相同的告警(例如要求分号与禁止分号不能并存,因此semi一个规则同时处理两种风格);
    • 库无关:仅基于 JavaScript 运行时环境,不针对特定库/框架(Node.js 这类运行时环境例外);
    • 无冲突:不得与其他规则直接冲突。
  2. 有 ESLint 团队成员 champion(背书):必须有一位团队成员愿意推动该变更的评审与合入。
  3. 重要性足够:变更重要到"没有这个变更,规则就被认为是不完整的"。

值得注意的另一个背景是"冻结规则(Frozen Rules)":当规则达到功能完备(能捕获 80% 以上预期违规并覆盖大多数常见例外)后会被标记为冻结(文档中以 ❄️ 标识)。冻结规则的约定是:仍修 bug、保证对新 ECMAScript 语法和 TypeScript 语法的兼容,但不再新增任何选项(除非新选项是修 bug 或支持新语法的唯一途径)。因此在提交"新增选项"类提案前,务必先确认目标规则是否处于冻结状态——若已冻结,官方建议直接复制规则源码自行修改(见 docs/src/contribute/core-rules.md 的 "Frozen Rules" 一节)。

四、提案通过之后:从模板到合入的实现路径

ESLint 团队不会代为实现用户提出的规则变更,提案被接受后实现与文档都由提案者负责(可招募协作者,champion 的团队成员会提供指导)。落地路径如下:

1. 按三文件结构改代码

每个核心规则对应三个同名文件(以no-extra-semi为例):

  • 源码:lib/rules/no-extra-semi.js
  • 测试:tests/lib/rules/no-extra-semi.js
  • 文档:docs/src/rules/no-extra-semi.md

所有核心规则通过 lib/rules/index.js 中由LazyLoadingRuleMap构建的映射表统一注册(例如"no-extra-semi": () => require("./no-extra-semi")),因此新增源码文件后无需额外注册代码即可被加载。

2. 用 RuleTester 写单元测试

每条核心规则必须附带RuleTester单元测试才能被接受(docs/src/contribute/core-rules.md 的 "Rule Unit Tests" 一节)。测试文件与源码同名同目录层级,基本形态是:

var rule = require("../../../lib/rules/no-extra-semi"); var RuleTester = require("eslint").RuleTester; var ruleTester = new RuleTester(); ruleTester.run("no-extra-semi", rule, { valid: ["var x = 5;", "function foo() {}"], invalid: [ { code: "var x = 5;;", errors: [{ messageId: "unexpected" }], }, ], });

其中valid对应"规则不应报告"的代码,invalid对应"应报告"的代码,其errors断言直接对应模板字段 6 描述的"变更后行为"。

3. 验证性能影响

变更可能影响 lint 性能,npm run perf会在启用全部核心规则的情况下给出 ESLint 运行总耗时;建议在main分支与变更分支上各跑一次对比(示例输出见 docs/src/contribute/core-rules.md 的 "Performance Testing" 一节)。

4. 提交 Pull Request

遵循 docs/src/contribute/pull-requests.md 的流程:基于 issue 创建独立分支(一个分支只解决一个 issue)→ 按 code conventions 修改并提交 → rebase 到上游 → 跑通测试 → 提交 PR。提交信息使用 Conventional Commits 格式,规则变更通常对应feat标签(向后兼容的增强或新增告警的规则变更)。

五、源码佐证:以 no-extra-semi 为例看模板字段的落地形态

仓库中的lib/rules/no-extra-semi.js是一个可以直接对照模板字段理解的真实实现(注意:该规则已在 ESLint v8.53.0 被标记为废弃,计划迁移至 ESLint Stylistic,但它的结构仍能清晰展示核心规则的标准形态):

  • meta.type = "suggestion":说明其报告的是"可以做得更好"的建议类问题(对应模板"变更类型"的语义层级);
  • meta.fixable = "code":对应"Implement autofix"选项——该规则可被--fix自动修复,源码中context.report({ ..., fix: ... })使用FixTracker保留分号周边的 token 后删除多余分号;
  • meta.schema = []:表示该规则不接受任何选项(对应"新增选项"类变更中 schema 的写法:无选项时用空数组即可,若提供选项但未定义 schema,ESLint 会直接报错);
  • meta.messages = { unexpected: "Unnecessary semicolon." }:通过messageId集中管理告警文案,context.report()中仅引用messageId: "unexpected",这正是"变更后行为"字段在测试中断言的对象;
  • meta.deprecated:展示了废弃规则的元信息结构(deprecatedSinceavailableUntilreplacedBy),也提醒提案者:某些规则可能正处于被替代/移除的路径上,变更前需确认其维护状态。

如果提案是"给该规则新增一个选项",那么改动点就是schema中加入 JSON Schema 描述、通过context.options读取选项值、并利用meta.defaultOptions提供默认值——这三处正是模板字段 3 "A new option" 的源码落点。

六、如果核心不接受:自定义规则与插件永远是你的备选

ESLint 被设计为完全可插拔:即使核心拒绝某项变更,你依然可以把规则复制到自己的项目中,或将其发布为插件,行为完全一致(自定义规则与核心规则使用同一套 API,见 docs/src/extend/custom-rules.md)。对于冻结规则,官方文档也明确建议"复制规则源码并按其需求修改"。因此,模板的本质不是"进入核心的许可",而是"让社区对规则演进方向达成共识"的沟通工具——无论最终归属核心还是插件,模板中梳理的"现状 vs 变更后行为 vs 影响示例"都是实现高质量规则变更的通用方法论。

总结:一份高质量提案的检查清单

  1. 规则 ID 明确,且确认其非冻结、非废弃状态;
  2. 变更类型与实现方式各只勾选一项,与源码机制对应(autofix ↔fixable+fix(),suggestions ↔hasSuggestions+suggest,new option ↔schema+defaultOptions);
  3. 示例代码最小可复现,能直接转换为RuleTester用例;
  4. "当前行为"与"变更后行为"描述精确到可断言程度;
  5. 变更后的规则仍满足核心规则六项准则(广泛适用、通用、原子、唯一、库无关、无冲突);
  6. 有团队成员愿意 champion,且变更的重要性足以支撑"规则不完整"的论断。

把这份清单与模板逐字段对照填写,你的提案就已经站在了被认真评估的起跑线上。后续实现阶段,可随时回到本仓库查阅 docs/src/contribute/core-rules.md、docs/src/extend/custom-rules.md 与lib/rules/目录下的真实规则源码作为参照。

【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询