eslintと仲良くなりたい(1)

どうにもeslintに苦手意識があって眠れない夜を過ごしているので、手を動かしながらステップバイステップでeslintを理解していく試みです。長編になりそうなので、何回かに分けて書きます。

以下はeslint v9、Flat configを前提にします。

最初の設定

エラーになりそうなサンプルのコードを用意する。

var me = 'naoty'
console.log('hello')

シンプルな設定を書く。rules以下にルール名をキー、severityを値にわたす。

  • offまたは0: 無効
  • warnまたは1: warnにする
  • errorまたは2: errorにする
+export default [
+  {
+    rules: {
+      "no-unused-vars": "error",
+    },
+  },
+];

実行は単にeslintを実行すればいい。npm scriptは設定してないので、以降はnpxコマンドを経由して実行する。

% npx eslint
/home/naoty/repos/localhost/hello-eslint/main.js
  1:5  error  'me' is assigned a value but never used  no-unused-vars

✖ 1 problem (1 error, 0 warnings)

確かにエラーになった。

ルールを調べる

https://eslint.org/docs/latest/rules/ にルールがまとまっている。ダブルクォーテーションに統一したいので、quotesというルールを適用したい。

ルールによってはオプションを指定することができ、値に配列をわたし、第1要素にseverity、第2要素以降にオプションを指定する。

 export default [
   {
     rules: {
       "no-unused-vars": "error",
+      quotes: ["error", "double"],
     },
   },
 ];
% npx eslint
/home/naoty/repos/localhost/hello-eslint/main.js
  1:5   error  'me' is assigned a value but never used  no-unused-vars
  1:12  error  Strings must use doublequote               quotes
  2:13  error  Strings must use doublequote               quotes

✖ 3 problems (3 errors, 0 warnings)
  2 errors and 0 warnings potentially fixable with the `--fix` option.

シングルクォーテーションがエラーになった。エラーメッセージに--fixオプションで修正可能と書いてあるので修正してみる。

% npx eslint --fix
/home/naoty/repos/localhost/hello-eslint/main.js
  1:5  error  'me' is assigned a value but never used  no-unused-vars

✖ 1 problem (1 error, 0 warnings)

修正可能なエラーは出なくなり、確かにコードがダブルクォーテーションを使うように修正された。

推奨設定をつかう

ルールは膨大にあるのでひとつずつ調べて設定するのは大変。なので、eslintには推奨された設定をまとめたものが用意されている。

+import js from "@eslint/js";

 export default [
+  js.configs.recommended,
-  {
-    rules: {
-      "no-unused-vars": "error",
-      quotes: ["error", "double"],
-    },
-  },
 ];

推奨設定に含まれているものは https://eslint.org/docs/latest/rules/ のなかのrecommendedマークがついているもので、実装を確認すると、recommendedは単にrulesを含むオブジェクトに過ぎないことがわかる。

実行してみる。

% npx eslint
/home/naoty/repos/localhost/hello-eslint/main.js
  1:5  error  'me' is assigned a value but never used  no-unused-vars
  2:1  error  'console' is not defined                   no-undef

✖ 2 problems (2 errors, 0 warnings)

新しいエラーが出るようになった。

グローバル変数の設定

consolewindowなどのグローバル変数は定義していないので、なにも設定しないと未定義エラーとしてみなされてしまう。

こうしたグローバル変数はlanguageOptions.globalsという項目で設定できる。キーにはグローバル変数、値には以下のいずれかを設定する。

  • writableまたはtrue: 読み書き可
  • readonlyまたはfalse: 読み取りのみ
 import eslint from "@eslint/js";
 
 export default [
+  {
+    languageOptions: {
+      globals: {
+        console: "readonly",
+      },
+    },
+  },
   eslint.configs.recommended,
 ];
% npx eslint
/home/naoty/repos/localhost/hello-eslint/main.js
  1:5  error  'me' is assigned a value but never used  no-unused-vars

✖ 1 problem (1 error, 0 warnings)

未定義エラーは出なくなった。

consolewindowといったグローバル変数を調べ上げるのも大変なので、globalsというパッケージを使うのが一般的みたいだ。

 import eslint from "@eslint/js";
+import globals from "globals";
 
 export default [
   {
     languageOptions: {
       globals: {
-        console: "readonly",
+        ...globals.browser,
+        ...globals.node,
       },
     },
   },
   eslint.configs.recommended,
 ];

globalsの中身はでかいJSONファイルになっていて、ここで各環境のグローバル変数が定義されている。

推奨設定のカスタマイズ

運用をはじめると、recommendedで追加したルールを上書きしたり、新しいルールを追加したりしたくなってくる。そんなときは、rulesはあとに設定されたものを優先するため、recommendedよりあとにルールを追加するだけでいい。recommendedの中身は単なるrulesなので。

recommendedではエラーになっていた未使用の変数を無視するようにし、recommendedでは特に触れてなかったvarの使用を禁止するようにする。

 import eslint from "@eslint/js";
 import globals from "globals";
 
 export default [
   {
     languageOptions: {
       globals: {
         ...globals.browser,
         ...globals.node,
       },
     },
   },
   eslint.configs.recommended,
+  {
+    rules: {
+      "no-unused-vars": "off",
+      "no-var": "error",
+    },
+  },
 ];
% npx eslint
/home/naoty/repos/localhost/hello-eslint/main.js
  1:1  error  Unexpected var, use let or const instead  no-var

✖ 1 problem (1 error, 0 warnings)
  1 error and 0 warnings potentially fixable with the `--fix` option.

未使用の変数は無視され、varの使用だけがエラーになった。

To Be Continued...

ここまではなんとなくわかっている範囲だったので、次回以降いよいよ謎が深まってくるTypeScriptやPrettierをはじめとしたプラグインの設定について書きたいです。

その(2)