@eslint/eslintrc の FlatCompat がどれくらい compat なのか確認する
ESLint の設定ファイルの形式が変わったことに際して、
ESLint は eslintrc や既存のエコシステムとの互換性を確保するために @eslint/eslintrc パッケージを公開しています。
このパッケージ内の FlatCompat
クラスで eslintrc 形式の設定を flat config 内でも使えるように変換することが出来ます。
// eslint.config.js
const compat = new FlatCompat({});
export default [
...compat.extends("standard", "example"),
...compat.plugins("airbnb", "react"),
];
🤔「FlatCompat
を通せば、flat config 対応が完了するの?」 と気になったので、
- npm で公開されている shareable config を extend しただけの eslintrc 形式の設定 (★)
- ★ を
FlatCompat
で変換しただけの flat config 形式の設定
それぞれを読み込んだ ESLint の実行結果を比較してみた。
- 実験対象
- ESLint v8.39.0
- @eslint/eslintrc v2.0.2
比較用準備
eslintrc 形式の設定を書く .eslintrc.js
を用意して..
// .eslintrc.js
module.exports = {
/* 何か書く*/
};
.eslintrc.js
の値を FlatCompat
で変換して flat config 形式で読み込む eslint.config.js
を用意して…
// eslint.config.js
const { FlatCompat } = require("@eslint/eslintrc");
const js = require("@eslint/js");
const compat = new FlatCompat({
baseDirectory: __dirname,
resolvePluginsRelativeTo: __dirname,
recommendedConfig: js.configs.recommended,
});
module.exports = [...compat.extends(require.resolve("./.eslintrc.js"))];
リントエラーを発生させるための実装をいくつか用意して…
$ cat src/js.js
let hoge = "hoge";
$ cat src/tsx.tsx
let hoge = <div>{"hoge"}</div>;
シェルスクリプトを用意しました。 —print-config オプションで ESLint が最終的に構築した設定値を出力させて、差分を見ます。
OUTDIR=dist/eslint-recommended
mkdir -p $OUTDIR
TYPE=js
ESLINT_USE_FLAT_CONFIG=false npx eslint --print-config src/$TYPE.$TYPE | sed -e 's/"error"/2/g' | sed -e 's/"warn"/1/g' | sed -e 's/"off"/0/g' | jq -S > $OUTDIR/$TYPE-rc.config.json
ESLINT_USE_FLAT_CONFIG=true npx eslint --print-config src/$TYPE.$TYPE | jq -S > $OUTDIR/$TYPE-flat.config.json
# 他のファイルタイプも実行する
ESLint only (empty)
// .eslintrc.js
module.exports = {};
js ファイルの比較
% sdiff -s dist/empty/js-rc.config.json dist/empty/js-flat.config.json
"env": {}, | "languageOptions": {
"globals": {}, | "ecmaVersion": "latest",
"ignorePatterns": [], | "globals": {},
"parser": null, | "parser": "[email protected]",
"parserOptions": {}, | "parserOptions": {},
"plugins": [], | "sourceType": "module"
"rules": {}, | },
"settings": {} | "plugins": [
> "@"
> ],
> "rules": {}
flat config のみにある @
plugin は、ESLint が標準で提供しているルールの plugin (ref: default-config.js#L21)。
ESLint 内蔵の rule も 外部 plugin と同じ構造で管理されていて、default valut として設定されている部分に、新しい API として洗練されたことを感じる。
(rule を何も on にしていないので、互換性の比較は出来ない)
ESLint only (eslint:recommended)
https://eslint.org/docs/latest/use/configure/configuration-files#using-eslintrecommended
// .eslintrc.js
module.exports = { extends: ["eslint:recommended"] };
js ファイルの比較
% sdiff -ls dist/eslint-recommended/js-rc.config.json dist/eslint-recommended/js-flat.config.json
"env": {}, | "languageOptions": {
"globals": {}, | "ecmaVersion": "latest",
"ignorePatterns": [], | "globals": {},
"parser": null, | "parser": "[email protected]",
"parserOptions": {}, | "parserOptions": {},
"plugins": [], | "sourceType": "module"
> },
> "plugins": [
> "@"
> ],
}, | }
"settings": {} <
rules プロパティ に diff がない => eslint:recommended
のルールが同じ用に適用されている => FlatCompat で変換出来ている
TypeScript (@typescript-eslint/eslint-plugin)
https://typescript-eslint.io/linting/configs#recommended
// .eslintrc.js
module.exports = {
extends: ["plugin:@typescript-eslint/recommended"],
};
js ファイルの比較
$ sdiff -s dist/typescript-eslint-recommended/js-rc.config.json dist/typescript-eslint-recommended/js-flat.config.json
"env": {}, | "languageOptions": {
"globals": {}, | "ecmaVersion": "latest",
"ignorePatterns": [], | "globals": {},
"parser": "*****/node_modules/@typescript-eslint/parser/dis | "parser": "typescript-eslint/[email protected]",
"parserOptions": { | "parserOptions": {},
> "@",
}, | }
"settings": {} <
@typescript-eslint
plugin が設定されている- 適用された rule が同じ
=> FlatCompat で変換出来ている
ts ファイルの比較
$ sdiff -s dist/typescript-eslint-recommended/ts-rc.config.json dist/typescript-eslint-recommended/ts-flat.config.json
"env": {}, | "languageOptions": {
"globals": {}, | "ecmaVersion": "latest",
"ignorePatterns": [], | "globals": {},
"parser": "*****/node_modules/@typescript-eslint/parser/dis | "parser": "typescript-eslint/[email protected]",
"parserOptions": { | "parserOptions": {},
> "@",
}, | }
"settings": {} <
@typescript-eslint
plugin が設定されている- 適用された rule が同じ
=> FlatCompat で変換出来ている
flat config 同士の js ファイル と ts ファイル の比較
$ sdiff -s dist/typescript-eslint-recommended/js-flat.config.json dist/typescript-eslint-recommended/ts-flat.config.json
> "constructor-super": [
> 0
> ],
(省略)
- いくつかのルールを off にする差分が ts ファイル側にある
- eslint-recommended.ts 内の overrides による差分
=> overrides の値も FlatCompat で変換出来ている
React (eslint-plugin-react)
// .eslintrc.js
module.exports = { extends: ["plugin:react/recommended"] };
jsx ファイルの比較
$ sdiff -s dist/eslint-plugin-react-recommended/js-flat.config.json dist/eslint-plugin-react-recommended/js-flat.config.json
# 差分なし (jsファイル・jsx ファイルに適用する設定は同じ)
$ sdiff -s dist/eslint-plugin-react-recommended/jsx-rc.config.json dist/eslint-plugin-react-recommended/jsx-flat.config.json
"env": {}, | "languageOptions": {
"globals": {}, | "ecmaVersion": "latest",
"ignorePatterns": [], | "globals": {},
"parser": null, | "parser": "[email protected]",
"parserOptions": { | "parserOptions": {
"ecmaFeatures": { | "ecmaFeatures": {
"jsx": true | "jsx": true
} | }
> },
> "sourceType": "module"
> "@",
}, | }
"settings": {} <
"jsx": true
が設定されている- 適用された rule が同じ
=> FlatCompat で変換出来ている
Vue (eslint-plugin-vue)
// .eslintrc.js
module.exports = { extends: ["plugin:vue/vue3-recommended"] };
[email protected]
の時点では FlatConfig 環境に対応していない?
$ ESLINT_USE_FLAT_CONFIG=true npx eslint --print-config src/vue.vue
Oops! Something went wrong! :(
ESLint: 8.39.0
Error: Could not serialize parser object (missing 'meta' object).
結論
- plugin の shareable configs を使う分には FlatCompat で変換出来そう
- 複雑に overrides, extends が組み合わさっているものは…?