ESLint v2.0.0 迁移指南:从 0.x/1.x 升级到第二个大版本的完整变更解析
【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint
ESLint v2.0.0 是项目历史上第二个大版本(major)发布,它在 0.x 与 1.x 时代的工作方式之上引入了大量破坏性变更,包括规则 Schema 不再校验严重级别、ecmaFeatures全面迁移为parserOptions、移除多条旧规则、修正全局作用域分析、SourceCode构造函数开始处理 Unicode BOM,以及插件不再自带默认配置等。本文以仓库内官方迁移文档 docs/src/use/migrating-to-2.0.0.md 为主线,逐条拆解每项变更的成因、影响范围与具体改法,并对照当前仓库源码(如 lib/languages/js/source-code/source-code.js、lib/rules/strict.js、conf/globals.js 等)验证这些设计在后续版本中的延续形态,帮助规则开发者、插件作者与配置维护者在升级时一次到位。
重要:如果你是从 0.x 直接升级,请先以 Migrating to 1.0.0 为起点,再阅读本文处理 1.x → 2.0.0 的增量变更。
规则 Schema 不再负责校验自身严重级别
变更原因
在旧版本中,由于规则 schema 工作方式上的一个历史遗留怪癖(quirk),当规则选项足够复杂时,规则开发者不得不把规则严重级别(0、1、2)也纳入规则自己的 schema 中参与校验。这会导致出现如下形式的 schema:
module.exports = { type: "array", items: [ { enum: [0, 1, 2], }, { enum: ["always", "never"], }, ], minItems: 1, maxItems: 2, };这种做法让规则开发者感到困惑——严重级别是 ESLint 核心机制的一部分,本不该由每条规则自己去验证。因此在 v2.0.0 中,规则不再需要检查自己的严重级别。
迁移改法
如果你导出的规则 schema 中包含对严重级别的校验,需要做三处修改:
- 从 schema 中移除严重级别那一项;
- 将
minItems从 1 调整为 0; - 将
maxItems减去 1。
上面示例正确转换后的 schema 为:
module.exports = { type: "array", items: [ { enum: ["always", "never"], }, ], minItems: 0, maxItems: 1, };从当前仓库的实现看,现代规则普遍采用meta.defaultOptions与meta.schema分离的写法(例如 lib/rules/strict.js 中defaultOptions: ["safe"]与 schema 并列),正是延续了 v2.0.0 确立的"严重级别与规则选项解耦"这一设计原则。
移除的规则及其替代方案
v2.0.0 废弃了以下规则,并创建新规则取而代之。迁移时需更新规则配置以使用新规则;同时,v2.0.0 会在你使用已被移除的规则时给出警告,并提示对应的替代规则,以降低升级过程中的意外。
| 已移除规则 | 替代规则 |
|---|---|
| no-arrow-condition | 由 no-confusing-arrow 与 no-constant-condition 组合替代,同时开启这两条规则可获得与no-arrow-condition相同的功能 |
| no-empty-label | no-labels,配合{"allowLoop": true, "allowSwitch": true}选项 |
| space-after-keywords | keyword-spacing |
| space-before-keywords | keyword-spacing |
| space-return-throw-case | keyword-spacing |
其中keyword-spacing合并了三条空格类规则的能力,负责强制关键字前后的一致间距。这些被移除的规则文档仍保留在仓库的 docs/src/rules/ 目录中(如 no-arrow-condition.md、space-after-keywords.md 等),便于查阅历史语义。值得一提的是,keyword-spacing本身在后续版本中(ESLint 8.53.0 起)也被标记为 deprecated,原因是格式化类规则正逐步移出 ESLint 核心,其实现与废弃说明可以在 lib/rules/keyword-spacing.js 的meta中看到。
配置级联(Cascading)行为变更
变更内容
在 v2.0.0 之前,如果同一目录下同时存在.eslintrc文件与包含 ESLint 配置信息的package.json,两份文件的设置会被合并。v2.0.0 之后,当两者同时存在时,只使用.eslintrc.*文件中的设置,package.json中的 ESLint 配置被忽略;只有在目录中不存在任何.eslintrc.*文件时,package.json中的 ESLint 配置才会被使用。
迁移改法
如果同一目录下同时存在.eslintrc.*与带 ESLint 配置信息的package.json,请将配置合并到其中一个文件中(推荐保留.eslintrc.*),避免配置二义性。
这一"就近优先、单一来源"的思想在仓库后续的配置架构中得到了延续:现代 flat config 通过 lib/config/flat-config-array.js 与 lib/config/flat-config-schema.js 实现更严格的配置合并与 schema 校验,配置查找规则比 v2.0.0 时代更加明确。
内置全局变量与es6环境
变更内容
v2.0.0 之前,ES6 标准化的新全局变量(如Promise、Map、Set、Symbol)被直接包含在内置全局环境中。这带来一个隐患:即使代码运行在 ES5 环境(没有 Promise 可用),no-undef也会放行Promise构造函数的使用。v2.0.0 之后,内置环境仅包含标准 ES5 全局变量,新增的 ES6 全局变量被移入es6环境。
这一点在当前仓库的 conf/globals.js 中仍可验证:Map、Promise、Set、Symbol、WeakMap、WeakSet等 ES6 全局对象被单独归类列出,而不是混入 ES5 基础全局变量。
迁移改法
如果你在编写 ES6 代码,需要显式开启es6环境(如果尚未开启):
// 在 .eslintrc 中 { env: { es6: true, } } // 或者在配置注释中 /*eslint-env es6*/语言选项:从ecmaFeatures到parserOptions
变更内容
v2.0.0 之前,启用语言特性靠配置中的ecmaFeatures。v2.0.0 做了三项调整:
ecmaFeatures属性整体移入顶层parserOptions之下;- 所有 ES6 相关的
ecmaFeatures标志被移除,统一由parserOptions.ecmaVersion取代,其取值可为 3、5(默认)或 6; ecmaFeatures.modules标志被parserOptions.sourceType取代,取值为"script"(默认)或"module"(用于 ES6 模块)。
被移除的 ES6 特性标志完整清单如下:
arrowFunctions—— 箭头函数binaryLiterals—— 二进制字面量blockBindings——let与const块级绑定classes—— class 类语法defaultParams—— 默认函数参数destructuring—— 解构赋值forOf——for-of循环generators—— 生成器modules—— 模块与全局严格模式objectLiteralComputedProperties—— 对象字面量计算属性名objectLiteralDuplicateProperties—— 严格模式下对象字面量重复属性objectLiteralShorthandMethods—— 对象字面量简写方法objectLiteralShorthandProperties—— 对象字面量简写属性octalLiterals—— 八进制字面量regexUFlag—— 正则表达式u标志regexYFlag—— 正则表达式y标志restParams—— 剩余参数(rest parameters)spread—— 数组展开运算符(spread operator)superInFunctions—— 函数内部对super的引用templateStrings—— 模板字符串unicodeCodePointEscapes—— 码点转义(code point escapes)
迁移改法
如果你使用了上述任一 ES6 标志,例如:
{ ecmaFeatures: { arrowFunctions: true, } }应改为通过ecmaVersion开启 ES6:
{ parserOptions: { ecmaVersion: 6, } }如果你使用的是非 ES6 标志(如jsx),需要把整个ecmaFeatures移入parserOptions:
{ ecmaFeatures: { jsx: true, } }改为:
{ parserOptions: { ecmaFeatures: { jsx: true, } } }如果你曾用ecmaFeatures.modules开启 ES6 模块支持:
{ ecmaFeatures: { modules: true, } }改为:
{ parserOptions: { sourceType: "module", } }规则内部context用法的同步更新
如果你的自定义规则内部使用了context.ecmaFeatures,需要按以下方式更新:
- 若使用 ES6 特性标志(如
context.ecmaFeatures.blockBindings),改写为检查context.parserOptions.ecmaVersion > 5; - 若使用
context.ecmaFeatures.modules,改写为检查 Program 节点的sourceType属性是否为"module"; - 若使用非 ES6 特性标志(如
context.ecmaFeatures.jsx),改写为检查context.parserOptions.ecmaFeatures.jsx。
(在后续引入 flat config 的版本中,这类语言信息统一通过context.languageOptions暴露,如context.languageOptions.ecmaVersion、context.languageOptions.sourceType。)
插件测试(RuleTester)的同步更新
如果你的插件中包含使用ecmaFeatures的规则,并且用 RuleTester 测试,需要同步更新传入的选项。例如:
var ruleTester = new RuleTester(); ruleTester.run("no-var", rule, { valid: [ { code: "let x;", parserOptions: { ecmaVersion: 6 }, }, ], });如果你在配置、自定义/插件规则及其测试中均未使用ecmaFeatures,则无需任何改动。
"eslint:recommended"新增的 11 条规则
v2.0.0 向"eslint:recommended"预设中新增了以下 11 条规则:
{ "extends": "eslint:recommended" }新增规则清单:
- constructor-super
- no-case-declarations
- no-class-assign
- no-const-assign
- no-dupe-class-members
- no-empty-pattern
- no-new-symbol
- no-self-assign
- no-this-before-super
- no-unexpected-multiline
- no-unused-labels
这批规则几乎都围绕 ES6 新语法(class、解构、Symbol、标签等)的易错场景设计,与上文"语言选项升级到 ES6"的变更配套出现。
迁移改法
如果不想被这些规则提示,可以显式关闭它们:
{ "extends": "eslint:recommended", "rules": { "no-case-declarations": 0, "no-class-assign": 0, "no-const-assign": 0, "no-dupe-class-members": 0, "no-empty-pattern": 0, "no-new-symbol": 0, "no-self-assign": 0, "no-this-before-super": 0, "no-unexpected-multiline": 0, "no-unused-labels": 0, "constructor-super": 0 } }作用域分析(Scope Analysis)变更
变更内容
v2.0.0 修复了作用域分析中的若干 bug:此前对全局变量的定义方式处理不完整。原始设计中,Variable对象与Reference对象互为引用:
Variable#references属性是一个Reference对象数组,表示引用了该变量的所有引用;Reference#resolved属性是被引用的Variable对象。
但在 1.x 及以前,以下几类变量和引用在上述属性中取的是错误的值(空值):
- 全局作用域中的
var声明; - 全局作用域中的
function声明; - 配置文件中定义的变量;
/* global */注释中定义的变量。
v2.0.0 之后,这些变量与引用在上述属性中都有了正确的值。相应地,Scope#through属性(保存Reference#resolved为null的引用)的值也因此发生变化。
迁移改法
如果你曾用Scope#through来查找内置全局变量,需要改写代码。以查找window全局变量为例,1.x 时代的绕路写法是:
var globalScope = context.getScope(); globalScope.through.forEach(function (reference) { if (reference.identifier.name === "window") { checkForWindow(reference); } });之所以要绕道Scope#through,是因为window的定义当时无法被正确找到,它才被塞进了"无法解析"的引用集合中。v2.0.0 补回了正确的声明,因此window不再位于Scope#through中,可以直接从全局作用域的变量集合中取出并遍历其引用:
var globalScope = context.getScope(); var variable = globalScope.set.get("window"); if (variable) { variable.references.forEach(checkForWindow); }这一修正使"通过Scope#through反向找全局变量"的 hack 不再必要,全局变量的获取路径变得直接。仓库中的内置规则也大量沿用这套语义:例如 lib/rules/camelcase.js 用scope.through遍历未定义全局变量(// Undefined globals),lib/rules/no-console.js 注释明确指出scope.through包含所有对未定义变量的引用,并在console未定义时通过scope.through.filter(isConsole)兜底——这些都是 v2.0.0 作用域模型稳定之后的典型用法。作用域分析底层依赖 escope 生态(相关接口见lib/languages/js/下的作用域相关实现),如需深入了解可继续阅读仓库中关于作用域管理器的扩展文档 docs/src/extend/scope-manager-interface.md。
使用eslint:recommended时的默认值变更
此变更影响那些继承eslint:recommended,并且只以"严重级别"方式开启no-multiple-empty-lines或func-style的配置,例如:
{ "extends": "eslint:recommended", "rules": { "no-multiple-empty-lines": 2, "func-style": 2 } }问题在于这两条规则在 1.x 中被eslint:recommended强加了与规则自身默认值相冲突的默认配置:
no-multiple-empty-lines规则本身没有默认例外,但 1.x 的eslint:recommended给它套了一层默认值,允许最多两个空行;func-style规则自身默认配置为"expression",但 1.x 的eslint:recommended把它默认成了"declaration"。
v2.0.0 移除了这些冲突的默认值,因此升级后可能开始看到与这两条规则相关的 lint 错误。
迁移改法
如果想保持旧行为,需要把默认值显式写进配置:为no-multiple-empty-lines加上{"max": 2},并把func-style改为"declaration":
{ "extends": "eslint:recommended", "rules": { "no-multiple-empty-lines": [2, { "max": 2 }], "func-style": [2, "declaration"] } }从当前源码看,lib/rules/no-multiple-empty-lines.js 的 schema 已支持max、maxEOF、maxBOF等多个整数参数(required: ["max"]),且不再内置任何来自 recommended 的隐性默认值——配置必须显式给出,正是 v2.0.0 去除隐性默认的延续。
SourceCode构造函数(Node API)的 BOM 处理
变更内容
v2.0.0 让SourceCode构造函数支持 Unicode BOM:如果第一个参数text带有 BOM,构造函数会把this.hasBOM设为true,并从文本中剥离 BOM。
var SourceCode = require("eslint").SourceCode; var code = new SourceCode("\uFEFFvar foo = bar;", ast); assert(code.hasBOM === true); assert(code.text === "var foo = bar;");因此第二个参数ast也应当是基于剥离 BOM 之后的文本解析出来的。
迁移改法
如果你在自己的代码中使用SourceCode构造函数,请先剥离 BOM 再解析源码:
var ast = yourParser.parse(text.replace(/^\uFEFF/, ""), options); var sourceCode = new SourceCode(text, ast);这一 BOM 约定在当前仓库的实现中被完整保留:在 lib/languages/js/source-code/source-code.js 的SourceCode构造函数中(第 264 行起的类定义),构造时通过text.charCodeAt(0) === 0xfeff检测文本是否带 BOM,设置this.hasBOM = textHasBOM || !!hasBOM,并以this.text = textHasBOM ? text.slice(1) : text存储剥离 BOM 后的文本(第 331–344 行)。注释还专门说明了这一"向后兼容的 BOM 处理":Linter 会提前剥离 BOM,并把hasBOM属性传给构造函数,以简化各语言实现对 BOM 的处理。
另外,当前仓库中hasBOM属性还承担了规则层面的语义:内置规则 lib/rules/unicode-bom.js 正是通过sourceCode.hasBOM来判断文件是否需要 BOM(requireBOM === "always"时若没有 BOM 则报错,"never"时有 BOM 则报错),说明 BOM 状态已成为SourceCode公开且稳定的 API 属性。在 Linter 内部(lib/linter/linter.js 的ensureText),也通过hasBOM与text反向重组原始文本(hasBOM ? "\uFEFF" + text : text),保证整条链路的信息不丢失。
规则默认值变更:strict规则
strict规则的默认值从"function"改为"safe"。这一默认值在当前仓库中依然如此:lib/rules/strict.js 中meta.defaultOptions: ["safe"],且 schema 支持["never", "global", "function", "safe"]四种取值。升级后如果沿用旧配置且未显式指定模式,会收到行为差异相关的提示,建议按需在配置中显式声明"strict": ["error", "function"]或"strict": ["error", "safe"],以明确预期。
插件不再拥有默认配置(rulesConfig被移除)
变更内容
v2.0.0 之前,插件可以在自身中通过rulesConfig指定默认配置,任何人使用该插件时这些配置会被自动应用——这与 ESLint 在其他所有场景中"默认什么都不开启"的行为相悖。为了让插件行为与整体保持一致,v2.0.0 移除了插件中的rulesConfig支持。
迁移改法
如果你在配置文件中使用了插件,需要手动在配置文件中逐一开启该插件的规则。也就是说,插件的规则默认关闭,由使用方显式决定启用哪些规则及其选项,从而让"引入插件"与"生效规则"两个动作彻底解耦。
升级检查清单
综合全文,从 1.x 升级到 v2.0.0 时可按下表逐项核对:
| 变更项 | 需要做的事 |
|---|---|
| 规则 Schema | 移除严重级别项,minItems改 0,maxItems减 1 |
| 已移除规则 | 改用替代规则,关注 CLI 输出的替代提示 |
| 配置级联 | 同一目录的.eslintrc.*与package.json配置二选一合并 |
| 全局变量 | ES6 代码显式开启env: { es6: true }或/*eslint-env es6*/ |
| 语言选项 | ecmaFeatures迁入parserOptions,ES6 用ecmaVersion: 6,模块用sourceType: "module" |
规则内context | context.ecmaFeatures.*改写为parserOptions/ ProgramsourceType判断 |
| RuleTester | 测试选项中改用parserOptions: { ecmaVersion: 6 } |
| recommended 新增规则 | 不需要的可显式关闭 |
| 作用域分析 | 全局变量改用globalScope.set.get(name).references,不再走Scope#through |
| recommended 默认值 | no-multiple-empty-lines显式加{"max": 2},func-style显式"declaration" |
SourceCode | 传入构造函数的 AST 必须基于剥离 BOM 后的文本解析 |
strict规则 | 默认值变为"safe",按需显式声明 |
| 插件 | 手动开启插件规则,rulesConfig不再生效 |
v2.0.0 的绝大多数变更方向——规则自校验最小化、配置显式化、语言能力集中到parserOptions、作用域语义修正——都在当前仓库的源码与后续文档中得到了继承和强化,理解这份迁移指南,也就同时理解了现代 ESLint 配置与规则开发模型的设计来源。
【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考