title | eleventyNavigation | ||||||||
---|---|---|---|---|---|---|---|---|---|
Migrate to v9.x |
|
ESLint v9.0.0 is a major release of ESLint, and as such, has several breaking changes that you need to be aware of. This guide is intended to walk you through the breaking changes.
The lists below are ordered roughly by the number of users each change is expected to affect, where the first items are expected to affect the most users.
- Node.js < v18.18, v19 are no longer supported
- New default config format (
eslint.config.js
) - Removed multiple formatters
- Removed
require-jsdoc
andvalid-jsdoc
rules eslint:recommended
has been updated--quiet
no longer runs rules set to"warn"
- Change in behavior when no patterns are passed to CLI
no-constructor-return
andno-sequences
rule schemas are stricter- New checks in
no-implicit-coercion
by default - Case-sensitive flags in
no-invalid-regexp
- Stricter
/* exported */
parsing "eslint:recommended"
and"eslint:all"
strings no longer accepted in flat config
- Node.js < v18.18, v19 are no longer supported
- Removed multiple
context
methods - Removed
sourceCode.getComments()
- Function-style rules are no longer supported
meta.schema
is required for rules with optionsFlatRuleTester
is nowRuleTester
- Stricter
RuleTester
checks
- Node.js < v18.18, v19 are no longer supported
FlatESLint
is nowESLint
Linter
now expects flat config format
ESLint is officially dropping support for these versions of Node.js starting with ESLint v9.0.0. ESLint now supports the following versions of Node.js:
- Node.js v18.18.0 and above
- Node.js v20.9.0 and above
- Node.js v21 and above
To address: Make sure you upgrade to at least Node.js v18.18.0 when using ESLint v9.0.0. One important thing to double check is the Node.js version supported by your editor when using ESLint via editor integrations. If you are unable to upgrade, we recommend continuing to use ESLint v8.56.0 until you are able to upgrade Node.js.
Related issue(s): #17595
As announced in our blog post, in ESLint v9.0.0, eslint.config.js
is the new default configuration format. The previous format, eslintrc, is now deprecated and will not automatically be searched for.
To address: Update your configuration to the new format following the Configuration Migration Guide. In case you still need to use the deprecated eslintrc config format, set environment variable ESLINT_USE_FLAT_CONFIG
to false
.
Related Issues(s): #13481
ESLint v9.0.0 has removed the following formatters from the core:
Removed Formatter | Replacement npm Package |
---|---|
checkstyle |
eslint-formatter-checkstyle |
compact |
eslint-formatter-compact |
jslint-xml |
eslint-formatter-jslint-xml |
junit |
eslint-formatter-junit |
tap |
eslint-formatter-tap |
unix |
eslint-formatter-unix |
visualstudio |
eslint-formatter-visualstudio |
To address: If you are using any of these formatters via the -f
command line flag, you'll need to install the respective package for the formatter.
Related issue(s): #17524
The require-jsdoc
and valid-jsdoc
rules have been removed in ESLint v9.0.0. These rules were initially deprecated in 2018.
To address: Use the replacement rules in eslint-plugin-jsdoc
.
Related issue(s): #15820
Four new rules have been enabled in eslint:recommended
:
no-constant-binary-expression
no-empty-static-block
no-new-native-nonconstructor
no-unused-private-class-members
Additionally, the following rules have been removed from eslint:recommended
:
To address: Fix errors or disable these rules.
Related issue(s): #15576, #17446, #17596
Prior to ESLint v9.0.0, the --quiet
CLI flag would run all rules set to either "error"
or "warn"
and then hide the results from rules set to "warn"
. In ESLint v9.0.0, --quiet
will prevent rules from being executed when set to "warn"
. This can result in a performance improvement for configurations containing many rules set to "warn"
.
If --max-warnings
is used then --quiet
will not suppress the execution of rules set to "warn"
but the output of those rules will be suppressed.
To address: In most cases, this change is transparent. If, however, you are running a rule set to "warn"
that makes changes to the data available to other rules (for example, if the rule uses sourceCode.markVariableAsUsed()
), then this can result in a behavior change. In such a case, you'll need to either set the rule to "error"
or stop using --quiet
.
Related issue(s): #16450
Prior to ESLint v9.0.0, running the ESLint CLI without any file or directory patterns would result in no files being linted and would exit with code 0. This was confusing because it wasn't clear that nothing had actually happened. In ESLint v9.0.0, this behavior has been updated:
- Flat config. If you are using flat config, you can run
npx eslint
oreslint
(if globally installed) and ESLint will assume you want to lint the current directory. Effectively, passing no patterns is equivalent to passing.
. - eslintrc. If you are using the deprecated eslintrc config, you'll now receive an error when running the CLI without any patterns.
To address: In most cases, no change is necessary, and you may find some locations where you thought ESLint was running but it wasn't. If you'd like to keep the v8.x behavior, where passing no patterns results in ESLint exiting with code 0, add the --pass-on-no-patterns
flag to the CLI call.
Related issue(s): #14308
In previous versions of ESLint, no-constructor-return
and no-sequences
rules were mistakenly accepting invalid options.
This has been fixed in ESLint v9.0.0:
- The
no-constructor-return
rule does not accept any options. - The
no-sequences
rule can take one option, an object with a property"allowInParentheses"
(boolean).
{
"rules": {
"no-constructor-return": ["error"],
"no-sequences": ["error", { "allowInParentheses": false }]
}
}
To address: If ESLint reports invalid configuration for any of these rules, update your configuration.
Related issue(s): #16879
In ESLint v9.0.0, the no-implicit-coercion
rule additionally reports the following cases by default:
-(-foo);
foo - 0;
To address: If you want to retain the previous behavior of this rule, set "allow": ["-", "- -"]
.
{
"rules": {
"no-implicit-coercion": [2, { "allow": ["-", "- -"] } ],
}
}
Related issue(s): #17832
In ESLint v9.0.0, the option allowConstructorFlags
is now case-sensitive.
To address: Update your configuration if needed.
Related issue(s): #16574
Prior to ESLint v9.0.0, the /* exported */
directive incorrectly allowed the following syntax:
/* exported foo: true, bar: false */
// and
/* exported foo bar */
The true
and false
in this example had no effect on ESLint's behavior, and in fact, was a parsing bug.
In ESLint v9.0.0, any /* exported */
variables followed by a colon and value will be ignored as invalid.
To address: Update any /* exported */
directives to eliminate the colons and subsequent values, and ensure there are commas between variable names such as:
/* exported foo, bar */
Related issue(s): #17622
In ESLint v8.x, eslint.config.js
could refer to "eslint:recommended"
and "eslint:all"
configurations by inserting a string into the config array, as in this example:
// eslint.config.js
export default [
"eslint:recommended",
"eslint:all"
];
In ESLint v9.0.0, this format is no longer supported and will result in an error.
To address: Use the @eslint/js
package instead:
// eslint.config.js
import js from "@eslint/js";
export default [
js.configs.recommended,
js.configs.all
];
Related issue(s): #17488
ESLint v9.0.0 removes multiple deprecated methods from the context
object and moves them onto the SourceCode
object:
Removed on context |
Replacement(s) on SourceCode |
---|---|
context.getSource() |
sourceCode.getText() |
context.getSourceLines() |
sourceCode.getLines() |
context.getAllComments() |
sourceCode.getAllComments() |
context.getNodeByRangeIndex() |
sourceCode.getNodeByRangeIndex() |
context.getComments() |
sourceCode.getCommentsBefore() , sourceCode.getCommentsAfter() , sourceCode.getCommentsInside() |
context.getCommentsBefore() |
sourceCode.getCommentsBefore() |
context.getCommentsAfter() |
sourceCode.getCommentsAfter() |
context.getCommentsInside() |
sourceCode.getCommentsInside() |
context.getJSDocComment() |
sourceCode.getJSDocComment() |
context.getFirstToken() |
sourceCode.getFirstToken() |
context.getFirstTokens() |
sourceCode.getFirstTokens() |
context.getLastToken() |
sourceCode.getLastToken() |
context.getLastTokens() |
sourceCode.getLastTokens() |
context.getTokenAfter() |
sourceCode.getTokenAfter() |
context.getTokenBefore() |
sourceCode.getTokenBefore() |
context.getTokenByRangeStart() |
sourceCode.getTokenByRangeStart() |
context.getTokens() |
sourceCode.getTokens() |
context.getTokensAfter() |
sourceCode.getTokensAfter() |
context.getTokensBefore() |
sourceCode.getTokensBefore() |
context.getTokensBetween() |
sourceCode.getTokensBetween() |
context.parserServices |
sourceCode.parserServices |
To address: Following the recommendations in the blog post.
Related Issues(s): #16999, #13481
ESLint v9.0.0 removes the deprecated sourceCode.getComments()
method.
To address: Replace with sourceCode.getCommentsBefore()
, sourceCode.getCommentsAfter()
, or sourceCode.getCommentsInside()
.
Related Issues(s): #14744
ESLint v9.0.0 drops support for function-style rules. Function-style rules are rules created by exporting a function rather than an object with a create()
method. This rule format was deprecated in 2016.
To address: Update your rules to the most recent rule format.
The eslint-plugin/prefer-object-rule rule can help enforce the usage of object-style rules and autofix any remaining function-style rules.
Related Issues(s): #14709
As of ESLint v9.0.0, an error will be thrown if any options are passed to a rule that doesn't specify meta.schema
property.
To address:
- If your rule expects options, set
meta.schema
property to a JSON Schema format description of the rule’s options. This schema will be used by ESLint to validate configured options and prevent invalid or unexpected inputs to your rule. - If your rule doesn't expect any options, there is no action required. This change ensures that end users will not mistakenly configure options for rules that don't expect options.
- (not recommended) you can also set
meta.schema
tofalse
to disable this validation, but it is highly recommended to provide a schema if the rule expects options and omit the schema (or set[]
) if the rule doesn't expect options so that ESLint can ensure that your users' configurations are valid.
The eslint-plugin/require-meta-schema rule can help enforce that rules have schemas when required.
Related Issues(s): #14709
As announced in our blog post, the temporary FlatRuleTester
class has been renamed to RuleTester
, while the RuleTester
class from v8.x has been removed. Additionally, the FlatRuleTester
export from eslint/use-at-your-own-risk
has been removed.
To address: Update your rule tests to use the new RuleTester
. To do so, here are some of the common changes you'll need to make:
-
Be aware of new defaults for
ecmaVersion
andsourceType
. By default,RuleTester
uses the flat config default ofecmaVersion: "latest"
andsourceType: "module"
. This may cause some tests to break if they were expecting the old default ofecmaVersion: 5
andsourceType: "script"
. If you'd like to use the old default, you'll need to manually specify that in yourRuleTester
like this:// use eslintrc defaults const ruleTester = new RuleTester({ languageOptions: { ecmaVersion: 5, sourceType: "script" } });
-
Change
parserOptions
tolanguageOptions
. If you're settingecmaVersion
orsourceType
on your tests, move those fromparserOptions
tolanguageOptions
, like this:ruleTester.run("my-rule", myRule, { valid: [ { code: "foo", parserOptions: { ecmaVersion: 6 } } ] }); // becomes ruleTester.run("my-rule", myRule, { valid: [ { code: "foo", languageOptions: { ecmaVersion: 6 } } ] });
-
Translate other config keys. Keys such as
env
andparser
that used to run on the eslintrc config system must be translated into the flat config system. Please refer to the Configuration Migration Guide for details on translating other keys you may be using.
Related Issues(s): #13481
In order to aid in the development of high-quality custom rules that are free from common bugs, ESLint v9.0.0 implements several changes to RuleTester
:
- Suggestion messages must be unique. Because suggestions are typically displayed in an editor as a dropdown list, it's important that no two suggestions for the same lint problem have the same message. Otherwise, it's impossible to know what any given suggestion will do. This additional check runs automatically.
- Suggestions must generate valid syntax. In order for rule suggestions to be helpful, they need to be valid syntax.
RuleTester
now parses the output of suggestions using the same language options as thecode
value and throws an error if parsing fails.
To address: Run your rule tests using RuleTester
and fix any errors that occur. The changes you'll need to make to satisfy RuleTester
are compatible with ESLint v8.x.
Related Issues(s): #15735, #16908
As announced in our blog post, the temporary FlatESLint
class has been renamed to ESLint
, while the ESLint
class from v8.x has been renamed to LegacyESLint
.
To address: If you are currently using the ESLint
class, verify that your tests pass using the new ESLint
class. Not all of the old options are supported, so you may need to update the arguments passed to the constructor. See the Node.js API Reference for details.
If you still need the v8.x ESLint
functionality, use the LegacyESLint
class like this:
const { LegacyESLint } = require("eslint/use-at-your-own-risk");
Related Issues(s): #13481
In ESLint v9.0.0, the config
argument passed to Linter#verify
and Linter#verifyAndFix
methods should be in the flat config format.
Additionally, methods Linter#defineRule
, Linter#defineRules
, Linter#defineParser
, and Linter#getRules
are no longer available.
To address: If you are using the Linter
class, verify that your tests pass.
If you're passing configuration objects that are incompatible with the flat config format, you'll need to update the code.
// eslintrc config format
linter.verify(code, {
parserOptions: {
ecmaVersion: 6
}
});
// flat config format
linter.verify(code, {
languageOptions: {
ecmaVersion: 6
}
});
Please refer to the Configuration Migration Guide for details on translating other keys you may be using.
Rules and parsers can be defined directly in the configuration.
// eslintrc mode
linter.defineRule("my-rule1", myRule1);
linter.defineRules({
"my-rule2": myRule2,
"my-rule3": myRule3
});
linter.defineParser("my-parser", myParser);
linter.verify(code, {
rules: {
"my-rule1": "error",
"my-rule2": "error",
"my-rule3": "error"
},
parser: "my-parser"
});
// flat config mode
linter.verify(code, {
plugins: {
"my-plugin-foo": {
rules: {
"my-rule1": myRule1
}
},
"my-plugin-bar": {
rules: {
"my-rule2": myRule2,
"my-rule3": myRule3
}
}
},
rules: {
"my-plugin-foo/my-rule1": "error",
"my-plugin-bar/my-rule2": "error",
"my-plugin-bar/my-rule3": "error"
},
languageOptions: {
parser: myParser
}
});
If you still need the v8.x Linter
functionality, pass configType: "eslintrc"
to the constructor like this:
const linter = new Linter({ configType: "eslintrc" });
linter.verify(code, {
parserOptions: {
ecmaVersion: 6
}
});
linter.getRules();
Related Issues(s): #13481