ESLint v7.0.0 has been released 🎉
— ESLint (@geteslint) May 8, 2020
Thanks to everyone who helped make this release happen.https://t.co/AMhSuPxJIy
ESLint 7.0.0
がリリースされました。
多数の互換性のない変更、ルール追加、オプション追加、そしてバグ修正が含まれています。
以下は主要な変更点のまとめです。
ユーザー向けの変更:
- 💥 互換性がない変更
- Node.js 8.x/11.x のサポートを終了します
overrides
設定に一致するファイルを自動的にリント対象にします--config
CLI オプションによる設定ファイル内の相対パスの扱いが変わります--ignore-path
CLI オプションによる無視ファイル内のパスの扱いが変わります- プラグインの読込元ディレクトリが変わります
- デフォルトで無視するファイルが変わります
- ディレクティブコメントに説明を書けます
eslint:recommended
設定が有効にするルールが増えます- 複数のルールのチェックが厳しくなります
- 複数の Node.js/CommonJS 向けルールが廃止されます
- 個人設定の利用がランタイム警告を出力します
- 💡 新しいルール
- 🔧 オプションが追加されたルール
プラグイン開発者向けの変更:
- 💥 互換性がない変更
- ✨ 本体への機能追加
ツール開発者 (エディタ拡張等) 向けの変更:
質問やバグ報告等ありましたら、お気軽にこちらまでお寄せください。
🏢 日本語 Issue 管理リポジトリ
👫 日本語サポート チャット (招待リンク)
🏢 本家リポジトリ
👫 本家サポート チャット (招待リンク)
[PR] ESLint は開発リソースを確保するための寄付を募っています。
応援してくださると嬉しいです。
💥 互換性がない変更
Node.js 8.x/11.x のサポートを終了します
Node.js 8.x は 2019-12-31 に、11.x は 2019-06-01 に寿命を迎えたため、ESLint もそれらのバージョンのサポートを停止しました。
ESLint 7.0.0 がサポートする Node.js のバージョンは ^10.12.0 || >=12.0.0
となります。
動作を元に戻したい場合:
この変更は元に戻せません。
古い Node.js 環境をアップグレードするまで ESLint 7 を利用しないようにしてください。
overrides 設定に一致するファイルを自動的にリント対象にします
これまで、eslint lib
のようにディレクトリを指定したとき、ESLint はディレクトリ内の *.js
ファイルをチェックしていました。Node.js が *.cjs
/*.mjs
拡張子を導入したり、TypeScript や Vue.js でも ESLint を使うようになったりしたので、この仕様は不便でした。
ESLint 7.0.0 からは *.js
に加えて overrides 設定にマッチするファイルもチェックします。例えば、
overrides:
- files: "*.js"
extends: my-config-js
- files: "*.ts"
extends: my-config-ts
のような設定がある場合、eslint lib
コマンドは lib
ディレクトリ内の *.ts
ファイルもチェックします。
なお、eslint lib/**
のように Glob パターンを指定した場合は今まで通りに動作しますのでご注意ください。overrides 設定にかかわらず Glob パターンにマッチする全てのファイルをチェックします。
プラグイン開発者へ:
あなたが管理するプラグインが *.js
以外のファイルを対象にするルールを提供する場合、recommended
設定に overrides を追加すると利用者は便利かもしれません。
動作を元に戻したい場合:
今まで通り overrides 設定にかかわらず *.js
だけをチェックしたい場合は、コマンドに --ext js
を付与してください。--ext
CLI オプションはこの新しい動作を上書きします。
--config CLI オプションによる設定ファイル内の相対パスの扱いが変わります
ignorePatterns
, overrides[].files
, overrides[].excludedFiles
設定に相対パスがあった場合、その相対パスは設定ファイルの場所を基準に解決されます (共有設定内のそれら相対パスは、利用元の.eslintrc.*
ファイルの場所を基準に解決されます)。
ESLint 7 でも基本的には同様です。しかし、--config CLI オプションで読み込んだファイルのみ、それら相対パスは CWD を基準に解決されるようになります。これは CWD にある仮想的な .eslintrc.*
ファイルから extends
されたのと同じ動作になります。
動作を元に戻したい場合:
この変更は元に戻せません。
もし、この変更が原因で意図しない挙動になった場合は、設定ファイル内の相対パスを書き換えてください。
--ignore-path CLI オプションによる無視ファイル内のパスの扱いが変わります
.eslintignore
ファイル内のパスは、そのファイルの場所を基準に解決されます。
ESLint 7 でも基本的には同様です。しかし、--ignore-path CLI オプションで読み込んだファイルのみ、それらパスは CWD を基準に解決されるようになります。
動作を元に戻したい場合:
この変更は元に戻せません。
もし、この変更が原因で意図しない挙動になった場合は、無視ファイル内のパスを書き換えてください。
プラグインの読込元ディレクトリが変わります
ESLint 6 はすべての設定ファイルに書かれた plugins
設定のプラグインを $CWD/node_modules
ディレクトリから読み込みます。この動作のため、エディタ拡張等に適切な CWD を設定しなければプラグインを利用できず、Monorepo スタイルの開発などで不便でした。
ESLint 7 では、設定ファイルに書かれた plugins
設定のプラグインは、各設定ファイルの場所を基準に読み込まれます。つまり、packages/alice/.eslintrc.yml
ファイルに書かれたプラグインは packages/alice/node_modules
ディレクトリから読み込まれます。
⚠️ 共有設定に書かれた plugins
設定のプラグインは、それを extends
する利用元の .eslintrc.*
ファイルの場所を基準に読み込まれます。そのため、共有設定からプラグインを利用する場合は引き続き peerDependencies
を利用する必要があります。
動作を元に戻したい場合:
以前と同様に $CWD/node_modules
ディレクトリからすべてのプラグインを読み込みたい場合は --resolve-plugins-relative-to .
CLI オプションを利用してください (末尾のドットに注意)。
--resolve-plugins-relative-to CLI オプションはこの新しい動作を上書きします。
デフォルトで無視するファイルが変わります
ESLint 6 がデフォルトで無視するファイルは、以下のパターンにマッチするファイルでした。
-
.*
(dotfiles) -
/node_modules/**
(CWD にあるnode_modules
ディレクトリ内) -
/bower_components/**
(CWD にあるbower_components
ディレクトリ内)
ESLint 7 では、以下のように変更されます。
-
.!(eslintrc.*)
(.eslintrc.*
設定ファイルを除く dotfiles) -
/**/node_modules/**
(node_modules
ディレクトリ内)
動作を元に戻したい場合:
以前のように .eslintrc.*
や /bower_components/**
を無視したい、またはサブディレクトリの node_modules
ディレクトリを無視したくない場合、.eslintrc.*
設定ファイルの ignorePatterns
設定を利用してください。
ignorePatterns:
- "!/*/**/node_modules/*"
- ".eslintrc.*"
- "/bower_components/*"
ディレクティブコメントに説明を書けます
ディレクティブコメントとは、/* eslint-disable */
のような ESLint の動作変更を指示するためのコメントのことです。ルールを無効にする場合、その理由を明示しておくことは良いことです。しかし、ディレクティブコメントの理由を書くための標準的な方法はありませんでした。
ESLint 7 では、空白文字に囲まれた2つ以上のハイフン --
を使ってディレクティブコメントに説明を追加できます。
/* eslint-disable a-rule -- このルールはバグっている */
doSomething()
/* eslint-disable another-rule
----------------
ここでは...(略
*/
動作を元に戻したい場合:
この変更は元に戻せません。
もし、既存のディレクティブコメントに--
が含まれていて壊れてしまった場合は、その設定を設定ファイルの overrides 等に移してください。
eslint:recommended
設定が有効にするルールが増えます
🔖 #12920
新たに 3 つのルールが有効になります。
-
no-dupe-else-if ...
if
-else if
チェーンにおいて、前のif
文の条件を満たすために絶対に真にならないif
文を報告します。 -
no-import-assign ...
import
文で作成した変数への代入 (実行時エラーになる) を報告します。 -
no-setter-return ... セッター内にある値を返す
return
を報告します。
動作を元に戻したい場合:
上記ルールを有効にしたくない場合は、設定ファイルに無効化する設定を追加してください。
extends: eslint:recommended
rules:
no-dupe-else-if: "off"
no-import-assign: "off"
no-setter-return: "off"
複数のルールのチェックが厳しくなります
🔖 #12195, #12490, #12608, #12701, #12757, #12765, #12806, #12816, #12837, #12876, #12913, #12915, #12919, #12927
以下のルールはより多くのエラーを報告するようになりました。
- accessor-pairs ... オブジェクト リテラルだけでなく、クラス メンバーもチェックするようになりました。
-
array-callback-return ... ES2019 で追加された
flatMap()
メソッドもチェックするようになりました。 - computed-property-spacing ... オブジェクト リテラルだけでなく、クラス メンバーもチェックするようになりました。
- func-names ... デフォルト エクスポートの関数宣言も名前が省略可能であるため、関数式と同じように名前の有無をチェックするようになりました。
- no-constant-condition ... 埋込式がないか、全ての埋込式が定数であるテンプレートリテラルも定数であると認識するようになりました。
- no-dupe-class-members ... 計算されたプロパティ名が定数だった場合は重複チェックをするようになりました。
- no-extra-parens ... 代入演算子の左側についてもカッコの有無をチェックするようになりました。
-
no-implied-eval ...
window.eval
のようなグローバルオブジェクトのプロパティアクセスも認識するようになりました。 - no-iterator ... 計算されたプロパティ名が定数だった場合も認識するようになりました。
- no-magic-numbers ... BigInt リテラルも認識するようになりました。
- no-proto ... 計算されたプロパティ名が定数だった場合も認識するようになりました。
- no-restricted-modules ... 埋込式がないか、全ての埋込式が定数であるテンプレートリテラルも定数であると認識するようになりました。
- quote-props ... プロパティ名としての BigInt リテラルも認識するようになりました。
-
radix ...
parseInt()
関数の第二引数が無効な数値 (2
未満 or36
より大きい) の場合もエラーを報告するようになりました。 -
use-isnan ...
case
句のNaN
もエラー報告するようになりました。 - yoda ... BigInt リテラルとテンプレートリテラルも認識するようになりました。
他にもあるかも...
動作を元に戻したい場合:
この変更は元に戻せません。
もし、新しくエラーが報告された場合はコードを修正してください。
複数の Node.js/CommonJS 向けルールが廃止されます
🔖 #12898
Node.js/CommonJS 向けのルールが非推奨になりました。
代わりに eslint-plugin-node の対応するルールをご利用ください。
動作を元に戻したい場合:
廃止されたルールは引き続き利用することができます。
ただし、廃止されたルールのコードは凍結され、今後はバグ修正や機能追加が行われません。早めの移行をお勧めします。
個人設定の利用がランタイム警告を出力します
個人設定とは、OS のホームディレクトリ (例: /home/foo/
, C:\Users\foo\
) に配置された .eslintrc.*
設定ファイルのことです。ESLint はプロジェクト内に設定ファイルが見つかると個人設定を (親ディレクトリであっても) 無視し、プロジェクト内に設定ファイルが見つからないと個人設定を (親ディレクトリでなくても) 利用します。
この個人設定の仕組みは ESLint 6.7.0 で非推奨になりました。
ESLint 7 では、個人設定の仕組みを利用すると標準エラー出力に非推奨警告を出力するようになります。
動作を元に戻したい場合:
この変更は元に戻せません。
もし、引き続きホームディレクトリの設定を利用したい場合は、--config CLI オプションで利用する設定を明示的に指定してください。もしくは、ホームディレクトリ以下に作業ディレクトリを作ってください (ESLint は親ディレクトリからも設定ファイルを探すので)。
RuleTester のチェックが厳しくなります
RuleTester がより多くの誤りを見つけるようになります。
- ルールが非標準の
node.start
/node.end
プロパティを参照していた場合にテストが失敗するようになります。代わりにnode.range
プロパティを利用してください。 - ルールが自動修正を提供するにもかかわらず、自動修正のテスト (
output
) が書かれていない場合にテストが失敗するようになります。 - 期待されるエラー内容を指示する
errors
プロパティ内に未知のプロパティがあったとき、テストが失敗するようになります (typo でテストできてなかったという事がなくなります)。
動作を元に戻したい場合:
この変更は元に戻せません。
もし、新たにテストが失敗するようになった場合は、そのルールの処理かテスト内容を更新してください。
新しい ESLint クラスが CLIEngine クラスを置き換えます
Node.js アプリケーションから ESLint を利用するための API として CLIEngine クラスが提供されています。しかし、CLIEngine クラスは同期 API を提供するため、非同期の処理が必要な並列処理・ES Modules サポート・進捗表示などの機能追加の妨げになっていました。
また、CLIEngine という名前は最初に使うべきクラスであるとの印象を抱きにくく、ブラウザ向けの機能限定版 API である Linter
クラスを先に試して「意図通りに動かない」と issue を作る人が多かったです。
ESLint 7 では、この CLIEngine クラスを廃止して、後継となる ESLint クラスを導入しました。ESLint クラスは CLIEngine と同等のメソッドを提供しますが、Promise
を返す非同期メソッドになっています。メソッドの対応は以下の通りです。
CLIEngine | ESLint |
---|---|
executeOnFiles(patterns) |
lintFiles(patterns) |
executeOnText(text, filePath, warnIgnored) |
lintText(text, options) |
getFormatter(name) |
loadFormatter(name) |
getConfigForFile(filePath) |
calculateConfigForFile(filePath) |
isPathIgnored(filePath) |
isPathIgnored(filePath) |
static outputFixes(results) |
static outputFixes(results) |
static getErrorResults(results) |
static getErrorResults(results) |
static getFormatter(name) |
(削除) |
addPlugin(pluginId, definition) |
plugins コンストラクタ オプション |
getRules() |
(未実装) |
resolveFileGlobPatterns() |
(削除) |
動作を元に戻したい場合:
現在 CLIEngine クラスは広く利用されているため、少なくとも1年間は削除されないはずです。引き続き利用することができます。
しかし、今後 CLIEngine のコードは凍結され、バグ修正や機能追加が行われません。例えば、ESLint 7.x では並列処理・ES Modules サポート・進捗表示の機能が追加される予定ですが、それらは ESLint クラスのみに実装され、CLIEngine クラスからは利用できません。早めの移行をお勧めします。
✨ 本体への機能追加
RuleTester のsuggestions
テストでmessageId
/data
を利用できます
🔖 #12635
RuleTester のsuggestions
のテストにて、message
プロパティの代わりにmessageId
/data
プロパティペアを用いてテストできるようになりました。
const { RuleTester } = require("eslint")
const rule = require("../../../lib/rules/a-rule")
new RuleTester("a-rule", rule, {
valid: [],
invalid: [
{
code: "foo",
errors: [{
messageId: "error",
data: { name: "foo" },
suggestions: [{
messageId: "suggest",
data: { name: "foo" },
output: "bar"
}],
}],
},
],
})
💡 新しいルール
default-case-last
🔖 #12668
default
句をswitch
文の末尾以外に書くことを禁止するルールが追加されました。
/*eslint default-case-last: error */
//✘ BAD
switch (foo) {
default:
break
case 0:
break
case 1:
break
}
no-restricted-exports
🔖 #12546
特定の名前の ES Modules エクスポートを禁止するルールが追加されました。
/*eslint no-restricted-exports: [error, { restrictedNamedExports: [foo, bar] }] */
//✘ BAD
export function foo() {}
let bar = 0
export { bar }
no-useless-backreference
🔖 #12690
正規表現中の無意味な後方参照を禁止するルールが追加されました。
/*eslint no-useless-backreference: error */
//✘ BAD
let a = /foo\1(bar)/
🔧 オプションが追加されたルール
array-callback-return: checkForEach
🔖 #12646
forEach()
メソッドのコールバックについてもreturn
文をチェックするオプションが追加されました。
/*eslint array-callback-return: [error, { checkForEach: true }] */
//✘ BAD
list.forEach(x => {
return x * 2
})
list.forEach(x => x * 2)
//✔ GOOD
list.forEach(x => {
x * 2
})
array-element-newline: ArrayExpression
and ArrayPattern
🔖 #11796
配列リテラルと分割代入の配列パターンとで別々の設定を行うためのオプションが追加されました。
/*eslint array-element-newline: [error, { ArrayExpression: always, ArrayPattern: never }] */
//✘ BAD
let foo = [1, 2]
let [
a,
b
] = foo
indent: offsetTernaryExpressions
🔖 #12556
三項演算子の2項目と3項目のインデントをつけるオプションが追加されました。
/*eslint indent: [error, 4, { offsetTernaryExpressions: true }] */
//✘ BAD
let foo = cond
? () => {
doSomething()
}
: () => {
doSomething()
}
//✔ GOOD
let bar = cond
? () => {
doSomething()
}
: () => {
doSomething()
}
indent: outerIIFEBody:"off"
🔖 #12706
トップレベルの即時関数呼び出しのインデントを検証しないオプションが追加されました。
/*eslint indent: [error, 4, { outerIIFEBody: "off" }]*/
//✔ GOOD
(function() {
function foo(x) {
return x + 1;
}
})();
no-extra-boolean-cast: enforceForLogicalOperands
🔖 #12734
論理式のオペランドでも不要な明示的な boolean
型変換を禁止するオプションが追加されました。
/*eslint no-extra-boolean-cast: [error, { enforceForLogicalOperands: true }] */
//✘ BAD
if (!!bar || Boolean(baz)) ;
no-magic-numbers: BigInt in the ignore
option
🔖 #12701
ignore
オプションが新たに文字列を受け入れるようになりました。各文字列は BigInt リテラルとして有効な文字列である必要があります。
/*eslint no-magic-numbers: [error, { ignore: ["123n"] }] */
//✔ GOOD
if (foo === 123n) ;
//✘ BAD
if (foo === 456n) ;
no-void: allowAsStatement
🔖 #12613
式文の最初に書くvoid
式を許可するオプションが追加されました。
/*eslint no-void: [error, { allowAsStatement: true }] */
//✔ GOOD
void doSomething()
void (async () => {
doSomething()
})().catch(handleError)
//✘ BAD
let a = void doSomething()