Biome で特定のディレクトリ内のモジュールの import を制限する
特定のディレクトリからモジュールの import を制限したい
TypeScriptのプロジェクトで、アーキテクチャや依存関係の整合性を保つために、あるディレクトリから別のディレクトリへの import を制限したいことがあります。
具体的には下記のようなケース
- foo ディレクトリ配下のコードでは、bar ディレクトリ配下のモジュールを使ってはいけない
- ただし、bar ディレクトリ配下から、foo ディレクトリ配下のモジュールは使ってもよい
ESLint での制限
ESLint であれば no-restricted-imports という便利なルールがあり、下記のようにpatternsの指定で "bar/*"
を一括で制限できます。
[
{
files: ["foo/**/*.{ts,tsx}"],
rules: { "no-restricted-imports": ["error", { patterns: ["bar/*"] }] },
}
]
こうすることで、foo ディレクトリ内で bar/* を import している箇所があればエラーとなります。
しかし、Biome の noRestrictedImports
では、限定的な機能しか提供しておらず、 patterns の指定をサポートしていません。
biome search を使った疑似的なチェック
Biome v2 以降では、プラグイン機能の追加が予定されています。v2はまだリリースされていませんが、現在リリースされている v1.9 ではプラグイン追加にさきがけて、ASTを解析できる GritQL の検索機能を使った biome search
が実装されました。(2025年1月現在の最新は v1.9.4)
biome search で該当の import を探す
入力例
biome search '`"@bar/$modules"`' ./src/foo
出力例
./src/foo/index.tsx:4:41 search ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
4 │ import { Baz } from "@bar/baz";
Searched 4 files in 1122µs. Found 1 match.
foo ディレクトリ内で bar を import している箇所のファイルパスと該当行が表示されているので、これを使って疑似的なチェックを行います。
ちなみに、該当する箇所が見つからない場合は Found 0 matches.
と表示されます。
npm script で実行する
手動で都度実行するのは面倒なので、CI で実行しやすいように npm script に追加してみます。
package.json の scripts に追加
{
"scripts": {
"lint:imports": "OUTPUT=$(biome search '`\"@bar/$modules\"`' ./src/foo) && echo \"$OUTPUT\" && (echo \"$OUTPUT\" | grep -q 'Found 0 matches.' && exit 0 || (echo 'ERROR: Forbidden imports detected in ./src/foo!' && exit 1))"
}
}
処理の流れは下記の通り
- biome search の結果をシェル変数 OUTPUT に保存
- Found 0 matches. が含まれるかを grep -q でチェック
- 含まれていれば違反なし ⇒ exit 0
- 含まれなければ違反あり ⇒ exit 1(エラーで終了)
実際に npm run lint:imports
を実行すると、foo ディレクトリから bar/*
を import していればエラーとなり、見つからなければ正常終了します。
CI でもこのコマンドを使って制限できそうですね。
まとめ
一応、Biome でも特定のディレクトリ内のモジュールの import を制限する方法はありそうでした。
ただし、ESLint の no-restricted-imports に比べると手間がかかりますし、柔軟性も正確性も低いです。
現在の実装では、コメントの場合も誤検出されてしまいますし、行単位の ignore も難しいです。
多くの場合では ESLint の no-restricted-imports を使うほうが確実だと思います。
将来的に Biome でも正式に対応できると願いながらの一時的な回避策として、ご参考まで!
参考
Discussion