コンテンツにスキップ

archstrict

archstrictv0.4.0MIT

TypeScript module boundary checker: default-private module surfaces, layers, cycles, and a todo freeze that can only shrink.

インストール

npm install archstrict

archstrict は、ArchUnit と同じ考え方で、TypeScript のモジュール境界を検査します。 tsc や型検査ツールは型を、ESLint はスタイルを調べます。 archstrict が調べるのは、モジュールの間の境界です。 モジュールは、コードベースのほかの部分に公開用のファイル (public surface) を 1 つだけ見せます。 そのファイルを経由せずに内部を直接 import すると、違反になります。 違反の報告には、規則の ID、場所、理由、直すためのコマンドが付くので、エージェントが自分の誤りを自分で直せます。

  • 宣言したモジュール。 archstrict.config.ts は 1 つの TypeScript の値です。 declaredModules で各モジュールをディレクトリか単一のファイルとして指定し、surface でその公開用のファイルを指定します。 どのモジュールにも exclude のパターンにも当てはまらないファイルは、uncovered-module の違反になります。 設定に未知のキーがあるとエラーになり、受け付けるキーが示されます。
  • エージェントがそのまま対応できる報告。 archstrict check は、各違反を規則の ID、path:line:col、証拠、because の理由、do: のコマンドつきで表示します。 --json は同じ内容を出力し、--rule と --module で絞り込めます。
  • レイヤーとドメインの規則。 classify でファイルにタグを付け、edges が allowDeny、order、point の規則でタグ間の import を検査します。 allowDeny か point の規則に guard: true を付けると、まだどのファイルにもない import を禁止できます。 archstrict diagram は、設定を Mermaid のフローチャートとして描きます。
  • 減る一方の todo ファイル。 最初の archstrict todo は、現在の違反を archstrict.todo.json に凍結し、その後の実行はエントリを取り除くだけです。 strict に挙げたモジュールは、エントリを 1 つも持てません。
  • 編集前の問い合わせ。 archstrict rules <path> は、まだ存在しないパスでも、そのパスが属するモジュールと、適用されるタグと制約を答えます。 archstrict simulate は、ソースや設定の変更を、書き込まずにプレビューします。
  • モジュール構成の次の一手。 archstrict recommend は、実際の import のグラフから、edges の規則と公開用のファイルを提案します。 archstrict hotspots は、コミット数とファンインでモジュールにスコアを付け、一緒に変更されるモジュールの組を一覧表示します。
  1. ファイルを作る前や import を追加する前に、エージェントは npx archstrict rules <path> を実行します。
  2. 編集の後で npx archstrict check を実行し、各 do: の行のとおりに直します。
  3. Claude Code では、archstrict プラグインの PostToolUse フックが、編集のたびに archstrict check <file> を実行し、違反があればエージェントのコンテキストに返します。 このプラグインの MCP サーバーは、check、rules、search、simulate をツールとして提供します。
  4. ほかのエージェントのホストでは、npx archstrict agents が AGENTS.md に編集前の指示を加え、CI が変更のたびに archstrict check を実行します。

archstrict には Node.js 22 以降が必要です。

ターミナルウィンドウ
npm install -D archstrict
npx archstrict init
npx archstrict check

init は、最上位にあるソースのディレクトリと、最上位に単独で置かれたソースファイルのそれぞれに、モジュールを 1 つずつ宣言します。 そのため、最初の検査から、解析するすべてのファイルがどれかのモジュールに含まれます。 この最初のモジュール構成は、ファイルの目録にすぎません。 続けて npx archstrict recommend を実行し、検査を完成したアーキテクチャとして扱う前に edges の規則を加えてください。

このリポジトリの fixtures/ に、小さなプロジェクトが 2 つあります。 1 つ目では、あるファイルが billing/rounding.ts を直接 import していて、billing モジュールの公開用のファイルを経由していません。

archstrict は、その import を public-surface-bypass として、ファイル、行、列つきで報告します。 archstrict 0.3.0 で確認済み
$ archstrict check実行ディレクトリ fixtures/archstrict-bypass · 終了コード 1 · archstrict 0.3.0
[public-surface-bypass] ./fixtures/archstrict-bypass/src/app/main.ts:1:28
  '../billing/rounding.ts' resolved to a file inside module 'billing' other than its index.ts, index.tsx, index.mts, index.cts
  because: a module's public surface is its only public surface; everything else is private
  config: ./fixtures/archstrict-bypass/archstrict.config.ts:33:5 declaredModules[1] (governs)
  do: import from src/billing/index.ts instead of src/billing/rounding.ts, adding the export there first if it is missing
modules: 2
modules without a public surface: 1
edges: 1
not covered by any declared module: 0
unresolved specifiers: 0
unsupported syntax: 0
type leaks: 0
todo: 0
summary: this config freezes today's import graph, not a target architecture; no edges rule is configured yet
do: archstrict recommend
do: archstrict hotspots
do: read node_modules/archstrict/skills/archstrict/references/rearchitect.md
do: archstrict todo

2 つ目のプロジェクトでは、同じコードが billing/index.ts 経由で import しています。

import が公開用のファイルを経由すると、検査は通ります。 archstrict 0.3.0 で確認済み

ファイルを作る前に、そのパスがどのモジュールに属するかを確かめてください。

archstrict rules <path> は、そのパスが属するモジュールと、そのファイルが公開用のファイルかどうかを答えます。 archstrict 0.3.0 で確認済み
$ archstrict rules src/billing/rounding.ts実行ディレクトリ fixtures/archstrict-bypass · 終了コード 0 · archstrict 0.3.0
path: ./fixtures/archstrict-bypass/src/billing/rounding.ts
exists: true
excluded: no
module: billing
tags: (none)
surface file: no
must-be-empty: ok
importable from: (none)
friend access: (none)
allowDeny constraints: (none)
order constraints: (none)
point constraints: (none)