importに制限を課すeslint-pluginを作ってみての感想

2023/02/06に公開

最近ts-archというライブラリを知りました。
設計したアーキテクチャ構造になっていることをテストできます。

importの制約はeslintの自作プラグインでもできるのではと思い作成してみました。

作成したプラグインについて

正規表現(RegExp)または文字列でimport可能なファイルパスを指定します。

設定ファイル例(.eslintrc.cjs)

module.exports = {
  ...
  "plugins": [
      "arch-imports"
  ],
  "rules": {
    "arch-imports/arch-imports": [
        "error",
        {
            // ルールを適用するファイルの拡張子
            fileExtList: ["", "ts", "tsx"],
            ruleList: [
                {
                  /**
                   * src/components下のファイルは
                   * src/componentsと src/hooksディレクトリのファイルのみimport可能
                   */
                  filePath: /src\/components\/.+/,
                  allowPathList: [
                      /src\/components\/.+/,
                      /src\/hooks\/.+/
                  ]
                },
            ]
        }
    ]
},
}

エラー表示

error  インポート不可能なファイルです。  arch-imports/arch-imports

英語に変えたほういいかも...

実装について

typescript-eslintを使ってプラグインを作成しました。
@typescript-eslint/utilsESLintUtilsにルールを手軽に作れるヘルパーメソッド(RuleCreator)があったのでそれを利用しています。
基本的にはtypescript-eslintのリポジトリにあったプラグインを見ながら作成したのでオーソドックスな実装になっていると思います。

このプラグイン特有の部分を書いておきます。

importの判定部分

自作ルールではASTのどのNodeに対してどういうLintを行うかを定義したオブジェクトを生成します。
今回はimportに対して処理を行いたかったのでImportDeclarationを指定しています。
typescript-eslintの型がとっかかりになって調査しやすかったです。

型チェック関数を定義

eslintのプラグインやルールは他のプロジェクトで使われることがメインです。
設定ファイルであるeslintrcではルールのon/offだけでなくoptionsを指定することができます。

このoptionsはtypescript-eslintの型定義上は正しい指定がされるような型になっていますが、
プラグインとしてnpmにpublishする時にはトランスパイルされてjsになっているので確実に想定通りのoptionsが設定されるとは言えません。
なので型チェック関数を定義しました。

npmのworkspacesで動作確認

上記と被りますが、eslintのプラグインやルールは他のプロジェクトで使われることがメインです。
テストコードを書いて動作保証していますが限界はあると思います。
npmのworkspaces機能を使い、自作ルール用プロジェクトと動作確認用のreactプロジェクトのモノレポ構成で開発を進めました。
npm publishしたものとのギャップが少ない状態で開発できていたと思います。

作者が想定している使い方を見せられますし、結構いいのではないかと思っています。

最後に

というわけで、eslintのプラグインを作ってみました。
そんなに複雑なコードではないので参考になれば幸いです。

一番詰まったところはeslintのプラグインを作るときに名前を"eslint-plugin"から始めないと認識されないということです....

Discussion