【JavaScript】ESLintの設定を読み解く②

## 目的
ESLintの設定をカスタマイズして利用する方法を調べる。

## 背景
TypeScriptのプロジェクトをVSCodeで編集している。
コーディングルール統一のために"Lint"というものが入っているらしいが、
今のままでは全面エラーで真っ赤になるため、諸々設定の変更が必要とのこと。
ライブラリの導入までは先行メンバが実施してくれているので、今回はカスタマイズ方法がわかればよい。

## カスタマイズ結果
.eslint.jsをこんな風にしてみた。

```js:.eslint.js
/* eslint-disable */
module.exports = {
  root: true,
  env: {
    'googleappsscript/googleappsscript': true,
  },
  globals: { // example
    Underscore: true,
    Moment: true
  },
  // files: ['*.ts'],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    sourceType: 'module',
  },
  plugins: [
    'googleappsscript',
    '@typescript-eslint',
    'prettier',
  ],
  extends: [
    'standard',
    'prettier',
    'eslint:recommended',
    // 'prettier/@typescript-eslint',
  ],
  rules: {  // example
    // 変なところで改行したがるのでprettierは無効化（★１）
    // 'prettier/prettier': [1, {
    //   useTabs: false,
    //   tabWidth: 4,
    //   endOfLine: 'auto',
    //   singleQuote: true
    // }],

    /** コード品質に関するルール */
    // ==,!= より ===,!== 推奨。スプシの読み書きあるので警告にしておく。
    'eqeqeq': 'warn',
    // 文末セミコロン必須
    'semi': ['error','always'],
    'no-var': 'error',
    'no-tabs': 'error',
    // break時の行先指定用ラベル使用禁止。loopは許す。
    'no-labels': ['error',{ 'allowLoop': true }],
    // 宣言されていない変数の参照は不問（★２）
    'no-undef': 'off',
    // 未使用の変数や関数は宣言禁止、ただし大文字or日本語始まりは許す（★２）
    'no-unused-vars': ['error', { 'varsIgnorePattern': '[A-Z0-9]|[^\x00-\x7F].+' }],
    // まだ宣言されていない識別子への参照は不問（★３）
    'no-use-before-define': 'off',

    /** スタイルに関するルール */
    // 1インデント4スペース。switch文のcaseは1インデント下げる。
    'indent': ['error', 4, {SwitchCase: 1}],
    // クォーテーションはシングル
    'quotes': ['error', 'single', { 'avoidEscape': true }],
    // 配列を表すカッコ([])と中身の間にスペース挟んではいけない
    'array-bracket-spacing': ['error', 'never'],
    // 単一行ブロックを表すカッコ({})と中身の間には必ずスペースが必要
    'block-spacing': 'error',
    // コンマ前のスペースNG、コンマ後ろにスペース必要
    'comma-spacing': ['error', { 'before': false, 'after': true }],
    // 中置演算子(+-=?など)の前後にスペース必要
    'space-infix-ops': 'error',
    // コメント周りの空白に関するルール。チェックしない。
    'spaced-comment': 'off',
    // ブロックを表すカッコ({})と中身の間の空行禁止。(class,switch文の{}内は許可)
    'padded-blocks': ['error', { 'blocks': 'never' }],
    // ifやforなど特定予約語の後の空白。チェックしない。
    // ※prettierは要空白だが、可読性影響小＆現行空白なしが大多数のため不問。
    'keyword-spacing': 'off',

    /** 命名規則 */
    '@typescript-eslint/naming-convention': [
      'error',
      { // classやtypeなどは頭大文字（★４）
        'selector': 'typeLike',
        'format': ['PascalCase'],
      },
      { // 変数名はキャメルケース
        'selector': 'variable',
        'format': ['camelCase'],
      },
    ]
  }
}
```

* 変なところで改行したがるのでprettierは無効化（★１）
prettierは1行の長さが一定を超えると勝手に改行を入れてくれるのだが、
↓のようなケースでコンマごとに全部改行を入れてくる。
`arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];`
1行の最大長を拡張して自動改行の発生を抑止してみたが、
今度は1行の最大長に合わせて人間が意図的に入れていた改行を消してしまう。
pritterにお任せするのはやめて、eslintでフォーマットのルールも指定することにした。

* 宣言されていない変数の参照は不問
／未使用の変数や関数は宣言禁止、ただし大文字or日本語始まりは許す（★２）
eslintはファイルを超えた参照はチェックできないらしく、
これらのルールは下記のような別ファイルのクラスへの参照がひっかかるので不問とした。
```XXTransaction.ts
class XXTransaction{ // デフォルト設定だとno-unused-varsに抵触
}
```
```XXService.ts
class XXService{
    method(){ var tran = new XXTransaction(); } // デフォルト設定だとnewの部分がno-undefに抵触
}
```
.eslint.jsのglobalsに、
グローバルに参照する変数名なりクラス名なりを定義しておけばno-undefにはならないが、
数が多く、後々メンテできなくなりそうなので、以下のように設定することにした。
・no-undef→本当に参照できないものはコンパイルエラーになるのでeslintチェックしない。
・no-unused-vars→大文字始まりのもの（多分class）はチェック対象外とした。

* まだ宣言されていない識別子への参照は不問（★３）
本プロジェクトでは、VOにあたるクラスが自身の自身のインスタンスをメンバに持ち、
そのインスタンス経由で内部のデータにアクセスさせる作りになっていたが、
メンバの宣言部がこのルールにひっかかるので不問とした。
```XXMaster.ts
class XXMaster{
    private static instance: XXMaster; // デフォルト設定だとno-use-before-defineに抵触
}
```

* classやtypeなどは頭大文字（★４）
★２で「大文字始まりの宣言は(classであり、
他のファイルで使われるはずなので)使われていなくてもOK」
ということでno-unused-vars:offにしたので、
classは必ず大文字始まりになるようルール付けした。


あとはprettierではエラーになるのに、eslintではエラーにならない、
というものがないように、eslintのスタイルに関するルールを整えていった。

### 所感
上記のカスタマイズで、現状のコーディングに沿わせたルールを適用することができた。
pretierによる自動改行が気に入らないので全面的に無効化させてしまったが、
スタイルに関するルールが想像以上に細かく設定が面倒だった。
改行以外のルールについては納得のいくものばかりだったので、
改行の件は目をつぶってpretier様に従った方が楽だったかもしれない。

## 残った課題
* 特定のルールだけfixさせたいが「error Parsing error: The keyword 'class' is reserved」に阻まれる
`npx eslint --no-eslintrc --rule 'no-use-before-define: "error"' ./src/*/*.ts`
上記のように、--no-eslintrc オプションと、--rule '[ルール名と設定] オプションを使って、
特定のルールについてのみ検査・修正を行うことができるそうなのだが、
私の環境では下記のエラーが発生し、うまく動かなかった。
```
C:\workspace\projectX\src\package\XXTransaction.ts
  1:1  error  Parsing error: The keyword 'class' is reserved
```
ネットの情報を元に、.eslintrc.js上で、
envに"es6": true,を追加する、parserOptionsに"ecmaVersion": 2018を追加するなどの対策を試したが解決に至らなかった。