VSCode で Typescript + Javascript + JSON が混在する環境で ESLint を設定する

# 環境

* VSCode - v1.81.0
* Node.js - v16.14.2
* eslint - v8.46.0
* prettier - v3.0.1

# やりたい事

* typescriptで開発
    * typescript 固有の linter を使いたい
* webpack.config tsconfig 等の package の設定を json ｜ js で作成
    * js は JS固有、JSONはJSON固有の linter 使いたい
* 事前にバグを除去したい（←重要）
* 保存時に実行したい

# 結論

* `.eslintrc`の`override`プロパティを利用して、全て個別に定義する

::: note info
【情報】
デフォルトを typescript の設定とし、override で他のファイルの設定すると`@typescript-eslint/parser`の`parserOptions`が邪魔になる事が多々ある。

```bash
> eslint . --ignore-path=.gitignore --ignore-path=.eslintignore

Oops! Something went wrong! :(

ESLint: 8.46.0

Error: Error while loading rule '@typescript-eslint/no-base-to-string': You have used a rule which requires parserServices 
to be generated. You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser.
```

:::

* VSCode の フォーマッタ設定を変更する
    * デフォルトのフォーマッタを `prettier` に。
    * 保存時、貼り付け時、文字入力時の自動フォーマットをON
    * 保存時に ESLint でフォーマット
    * ESLint が動作するファイルの種類をデフォルトから増やす（default = javascript, javascriptreact, typescript, typescriptreact, html, vue, markdown）
        * `json` - package.json, webpack.config.json 等
        * `jsonc` - tsconfig.json 等

## 前提

* lint 対象のファイルの種類が１種類であれば 正しく lint できる事

## 必要なパッケージ

* eslint
* prettier
* eslint-config-prettier
* eslint-plugin-prettier
* @types/eslint
* @types/prettier
* [ typescript 関連 ]
    * @typescript-eslint/eslint-plugin
    * @typescript-eslint/parser
* [ javascript 関連 ]
    * @babel/core
    * @babel/preset-env
    * @babel/eslint-parser
* [ json 関連 ]
    * jsonc-eslint-parser
    * eslint-plugin-jsonc

```bash:installコマンド
npm i -D eslint prettier eslint-config-prettier eslint-plugin-prettier @types/eslint @types/prettier @typescript-eslint/eslint-plugin @typescript-eslint/parser @babel/core @babel/preset-env @babel/eslint-parser jsonc-eslint-parser eslint-plugin-jsonc
```
※installコマンドは未検証なので、エラるようなら個別にinstall推奨

## .eslintrc

`ESLint`の設定ファイル
本投稿では、Javascript で記述。
VSCode なら Javascript でも Typescript の型チェック機能の恩恵を傍受できるので。

参考 [Configure ESLint | ESLint](https://eslint.org/docs/latest/use/configure/)

```javascript:.eslintrc.cjs
// @ts-check

/** @type {import("eslint").Linter.Config} */
module.exports = {
  
  // 全てのファイルに対する共通設定
  rules: {
    "comma-dangle": ["error", { objects: "only-multiline" }], // 好みで
  },

  //...(略)...

  // ファイル個別の設定
  overrides:[
    // [typescript]
    /** @type {import("eslint").Linter.ConfigOverride<import("eslint").Linter.RulesRecord>} */
    {
      files: "**/*.{ts,tsx}",
      env: {
        es6: true,
        node:true,
        // etc...
      },
      plugins: ["@typescript-eslint"],
      extends: [
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:@typescript-eslint/recommended-requiring-type-checking", // 任意
        "prettier",
      ],
      parser: "@typescript-eslint/parser",
      parserOptions: {
        ecmaVersion: "latest",
        sourceType: "module",
        project: ["./tsconfig.json"],
        tsconfigRootDir: __dirname,
      },
    },

    // [javascript]
    /** @type {import("eslint").Linter.ConfigOverride<import("eslint").Linter.RulesRecord>} */
    {
      files: "**/*.{js,cjs,mjs}"
      env: {
        es2022: true,
        node: true,
        // etc...
      },
      extends: [
        "eslint:recommended",
        "plugin:prettier/recommended",
        "prettier",
      ],
      parser: "@babel/eslint-parser",
      parserOptions: {
        requireConfigFile: false,
        babelOptions: {
          babelrc: false,
          configFile: false,
          presets: ["@babel/preset-env"],
        },
      },
    },

    // [json]
    /** @type {import("eslint").Linter.ConfigOverride<import("eslint").Linter.RulesRecord>} */
    {
      files: "**/*.json",
      extends: [
        "eslint:recommended",
        "plugin:jsonc/recommended-with-jsonc",
        "plugin:jsonc/prettier",
        "prettier",
      ],
      parser: "jsonc-eslint-parser",
      rules: {
        "jsonc/comma-dangle": ["error", "never"], // JSON.parse() でエラるのでほぼ必須
      },
    },
  ],
};
```

## .pretiierrc

`Pritiier`のconfigファイル。

同じく Javascript で記述。理由も同じ。一部 `ESLint` と機能が競合するので、注意する。
最悪の場合、ESLint と同様 [`override`](https://prettier.io/docs/en/configuration.html#configuration-overrides) プロパティを用いて、ファイルの種類毎に個別設定する必要が出てくるかも。


参考 [Options | prittier.io](https://prettier.io/docs/en/options.html)

```javascript:.pretiierrc.js
/** @type {import("prettier").Options} */
module.exports = {
  /**
   * 折返しをする文字数
   * @see https://prettier.io/docs/en/options.html#print-width
   */
  printWidth: 80,

  /**
   * 末尾のカンマ
   * ※ object のみ、function のみ 等細かい設定はできないみたい
   * <code>
   * ver obj0 = { a: 0, b: 1 };
   * ver obj1 = {
   *   a:0,
   *   b:1, // <- この位置にカンマを入れるか
   * };
   * 
   * function (a, b){ ... };
   * function (
   *   a,
   *   b, // <- この位置にカンマを入れるか
   * ){
   *   ...
   * };
   * </code>
   * @see https://prettier.io/docs/en/options.html#trailing-commas
   */
  trailingComma: "none", // ESLint の comma-dangle に任せる

  /**
   * タブ->スペースに変換する際の文字数
   * @see https://prettier.io/docs/en/options.html#tab-width
   */
  tabWidth: 2,

  /**
   * コード行端のセミコロン
   * @see https://prettier.io/docs/en/options.html#semicolons
   */
  semi: true,

  /**
   * 改行コード
   * @see https://prettier.io/docs/en/options.html#end-of-line
   */
  endOfLine: "lf",

  /**
   * 文字列リテラルの引用符
   * @see https://prettier.io/docs/en/options.html#quotes
   */
  singleQuote: false,
};

```

## .vscode/settings.json

手動で作成するか、VSCodeの設定を開き、上部の「設定の検索」からプロパティ名で検索して設定する。（本稿では、ワークスペースのみに設定）

```jsonc:.vscode/settings.json
{
  // [common]
  // 自動フォーマット
  "editor.formatOnSave": true, // ファイル保存時
  "editor.formatOnPaste": true, // ペースト時
  "editor.formatOnType": true, // 文字入力時
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true // ファイル保存時に ESLint でフォーマット
  },
  "editor.defaultFormatter": "esbenp.prettier-vscode", // デフォルトフォーマッターをPrettierに指定
  // [eslint]
  "eslint.validate": [
    "json",
    "jsonc"
  ], // lint する追加のファイル
}
```

了