Mobile Factory Tech Blog

技術好きな方へ!モバイルファクトリーのエンジニアたちが楽しい技術話をお届けします!

ESLintルールのエラー文をカスタマイズしたい

こんにちは、駅メモ!開発チームエンジニアの id:hayayanai です!

駅メモ!のフロントエンド開発では、Linter として ESLint や Stylelint、それらの Vue 関連のプラグインを導入しています。

これらの開発支援を利用していく中で、既存の ESLint ルールのエラー文だけを変えたいという話が上がりました。 一般的なエラー文を出すよりも、チームとしての方針を明記した方が対応しやすいということです。

一から ESLint のカスタムルールを作る方法については、調べてみると既に多くの情報がありました。 一方で、既存のルールを上書きする方法の情報は少なく、実装に苦戦しました。

そこでこの記事では、既存のルールのエラー文を上書きしたカスタムルールを作る方法を紹介します。

サンプルプロジェクト

今回は例として no-magic-numbers のルールを上書きします。 エラー文を日本語で出力しつつ、どういう風に直して欲しいかを記載するように変更します。

サンプルを ESLint Online Playground で見る

環境

  • ESLint v9.25.1
    • Flat Config を使用

全体の構成

.
├── eslint.config.mjs
├── rules
│   ├── index.mjs
│   └── no-magic-numbers.mjs
└── src
    └── example.js

rules/index.mjs

import noMagicNumbers from "./no-magic-numbers.mjs"

export default {
  rules: {
    "no-magic-numbers": noMagicNumbers,
  },
}

rules/no-magic-numbers.mjs

/* 上書きしたいルールの RuleModule を取得する */
import { Linter } from "eslint"

const linter = new Linter({ configType: "eslintrc" }) // "flat" だと getRules の呼び出しでエラーになる
const noMagicNumbersRuleModule = linter.getRules().get("no-magic-numbers")

console.log(noMagicNumbersRuleModule)

/* 上書きして export する */
export default {
  ...noMagicNumbersRuleModule,
  meta: {
    ...noMagicNumbersRuleModule.meta,
    docs: {
      ...noMagicNumbersRuleModule.meta.docs,
      url: "https://tech.mobilefactory.jp/", // 社内のドキュメント等に置き換えると便利
    },
    messages: {
      ...noMagicNumbersRuleModule.meta.messages,
      noMagic:
        "マジックナンバーは禁止です: {{raw}}。`MAGIC_NUMBER_` から始まる定数を使用してください",
    },
  },
}

参考: console.log(noMagicNumbersRuleModule) の出力結果

{
  meta: {
    type: 'suggestion',
    docs: {
      description: 'Disallow magic numbers',
      recommended: false,
      frozen: true,
      url: 'https://eslint.org/docs/latest/rules/no-magic-numbers'
    },
    schema: [ [Object] ],
    messages: {
      useConst: "Number constants declarations must use 'const'.",
      noMagic: 'No magic number: {{raw}}.'
    }
  },
  create: [Function: create]
}

eslint.config.mjs

import myRules from "./rules/index.mjs"

/** @type {import('eslint').Linter.Config[]} */
export default [
  {
    plugins: {
      "my-rules": myRules,
    },
    rules: {
      // "no-magic-numbers": "off", // 既存のルールが有効になっているなら off にすると良い
      "my-rules/no-magic-numbers": "error",
    },
  },
]

src/example.js

let a
a = 3.14
a = 299792458

解説

大まかに以下のような流れでルールの上書きを実現しています。

  1. 既存のルールを上書きするために no-magic-numbers の RuleModule を取得
  2. 取得した RuleModule の中の、カスタマイズしたい部分を変更
  3. ルールとして export
  4. eslint.config.mjs でカスタムルールを import して有効化
  5. (必要に応じて既存のルールを off にしてエラーが重複しないようにする)

ポイントとしては以下の通りです。

  • Flat Config を使用していれば、カスタムルールのために別途プラグインの package を作るなどの手間が無くて簡単
  • RuleModule の export のされ方はプラグインによって異なるので、実装を読みつつ調整する必要あり
  • meta.messages の key(messageId) はルール毎に異なるので、console.log 等で確認しながら対応するとスムーズ

カスタマイズ後の動作確認

コマンドラインで実行

% npx eslint src/example.js

  2:5  error  マジックナンバーは禁止です: 3.14`MAGIC_NUMBER_` から始まる定数を使用してください       my-rules/no-magic-numbers
  3:5  error  マジックナンバーは禁止です: 299792458`MAGIC_NUMBER_` から始まる定数を使用してください  my-rules/no-magic-numbers

✖ 2 problems (2 errors, 0 warnings)

Cursor(VSCode) 上の表示

Cursor 上の出力結果

my-rules/no-magic-numbers のリンクをクリックすると、rules/no-magic-numbers.mjs 中の url に指定したページへ飛ぶことができます。社内ドキュメントなどをリンクとして設定すると便利だと思います。

Cursor に修正を指示すると、上書きした後のエラー文を読んで適切に提案してくれました。画像は claude-3.7-sonnet での結果です。

Cursor に修正を指示した結果

まとめ

ESLint v9 の Flat Config 環境で、既存のルールの検出方法をそのままに、エラー文を上書きしたカスタムルールを作る方法を紹介しました。 エラー文章に対応方針を書いておくと、どう直して欲しいかをエンジニアや AI に伝えやすくなります。 皆さんもぜひ試してみてください。

冒頭、実装時に苦戦したと書きましたが、執筆時 GPT に聞いたらそれっぽい方針を示してくれました…。今後頼りになるケースが増えそうで、ワクワクしてきますね!

参考