ast-code-graph について
コーディングエージェント向けのコード構造分析スキルです。ast-grepと解析・グラフ構築スクリプトを組み合わせ、通常のテキスト検索ではなく、リファクタリングや移行に役立つ構造検索と依存分析を行います。
主な機能
- 01AST構造に基づくコード検索
- 02構造的な書き換えの確認と適用
- 03呼び出し元とモジュール依存の分析
- 04デッドコードと循環インポートの検出
- 05スクリプト処理用のJSON出力
活用シーン
- 01コードシンボルの安全な名前変更
- 02関数変更の影響範囲を評価
- 03プロジェクト全体のコードパターン移行
- 04未使用エクスポートや循環依存の検出
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ rolandbrecht/ agent-skills --skill ast-code-graphインストール後、Claude Code で/ast-code-graphを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
package-lock.jsonpackage.jsonreferences/ast-grep-cheatsheet.mdgraph-schema.mdquery-patterns.mdscripts/build-graph.pyparse-js.mjstests/test_build_graph.pytest-parse-js.mjstests/fixtures/sample_helper.pysample_module.pysample-cjs.jssample-esm.mjssample-no-exports.js詳細
AST とコードグラフのインデックス作成
概要
テキストベースの検索(grep、ripgrep)では、文字列の一致を見つけます。AST ベースの分析では構造を理解し、関数定義、関数呼び出し、コメント、文字列リテラルを区別できます。
主要なツール: ast-grep(sg / ast-grep)— 構造に基づくコード検索、リンティング、書き換えを行う高速な Rust ベースの CLI です。解析には tree-sitter を使用し、標準で 20 以上の言語をサポートしています。
基本原則: 問いがコードの構造に関するものなら AST 分析を使用します。テキストの内容に関するものなら grep を使用します。
トリガーパターン
このスキルを使用する状況の詳しい例:
| カテゴリ | クエリの例 |
|---|---|
| 構造パターン検索 | 「依存配列のない useEffect」、「try-catch のない async 関数」、「例外処理のない User.objects.get()」、「src/api/ 以外にある fetch() 呼び出し」、「クラスメソッド内の console.log」、「エラー処理のないルートハンドラー」 |
| コードの一括移行 | すべての async ハンドラーをラップする、すべての X() 呼び出しを Y() に置き換える、すべてのルートハンドラーにエラー処理を追加する、数百のファイルにわたって非推奨の API パターンを書き換える |
| 依存関係と影響分析 | 「analyzePayment は何に依存しているか」、「X を変更した場合の影響範囲」、「./lib/database.js に依存するモジュール」、「直接および間接の依存関係」 |
| 安全な名前変更 | 「fetchUserData を安全に getUserData に名前変更する」、TypeScript/JavaScript のコードベース全体で名前を変更する |
| デッドコードと循環インポート | 「どこからもインポートされていないエクスポート」、「webpack バンドルの原因となる循環インポート」、未使用のエクスポート、ソースコードで実際に使われている npm 依存関係 |
| ast-grep ルール | ast-grep ルールを書く、sg パターン、ast-grep の構文 |
使用するタイミング
次のようなタスクでは、このスキルを使用します。
| タスク | AST が grep より優れている理由 |
|---|---|
| リファクタリング/名前変更 | grep ではコメントや文字列内の文字列も見つかりますが、AST ではシンボルだけを見つけられます |
| デッドコードの検出 | grep では、エクスポートがほかの場所で実際にインポートされているか判別できません |
| 依存関係の追跡 | 「X が依存するモジュールは何か?」を知るには、import/require の理解が必要です |
| 影響分析 | 「関数 X を変更したら何が壊れるか?」を知るには、呼び出しグラフのたどり直しが必要です |
| 循環依存の検出 | インポートグラフ全体を構築し、分析する必要があります |
| コードの移行 | コードベース全体にわたって、非推奨の API パターンを構造的に書き換えます |
| カスタムリンティング | 標準のリンターではカバーできない、プロジェクト固有のパターンを適用します |
このスキルを使用しないケース:
- 特定の文字列、エラーメッセージ、設定値を検索する場合 →
grepを使用します - 名前や拡張子でファイルを探す場合 →
find/fdを使用します - コードベースが 5 ファイル未満で、すべて読める場合 → そのままファイルを読みます
前提条件
このツールを使って検索する前に、システムに ast-grep がネイティブインストールされているか必ず確認してください。
which ast-grep || which sg
インストールされている場合は、セマンティック検索にネイティブバイナリを直接使用します。絶対に必要な場合を除き、Docker コンテナや複雑なラッパースクリプト経由で実行しようとしないでください。
インストールされていない場合は、OS に応じて次のいずれかの方法でインストールできます。
- Node.js:
npm install -g @ast-grep/cli - MacOS(Homebrew):
brew install ast-grep - Rust(Cargo):
cargo install ast-grep --locked
スクリプトの依存関係
グラフ構築と AST 解析に付属スクリプトを使用するには、追加の依存関係が必要です。
- JS/TS の解析(
scripts/parse-js.mjs):Node.js v14 以降、acorn、acorn-walkが必要です。実行前に、これらがグローバルまたはast-code-graphディレクトリにインストールされているか確認してください。インストールされていない場合は、ast-code-graphディレクトリでnpm install acorn acorn-walkを実行するか、グローバルにnpm install -g acorn acorn-walkを実行してインストールできます。 - Python グラフビルダー(
scripts/build-graph.py):Python 3.8 以降が必要です(標準ライブラリのみを使用し、外部依存関係はありません)。
フェーズ 1:検索 — 構造からコードを見つける
ast-grep(推奨 — すべての言語)
ast-grep は、検索対象のコードそのもののように見えるパターン構文を使用し、任意の AST ノードに一致する $METAVAR ワイルドカードを利用します。
基本的なパターン検索:
# Find all calls to console.log
ast-grep -p 'console.log($MSG)' -l js src/
# Find all require() calls
ast-grep -p 'require($MOD)' -l js src/
# Find all async functions
ast-grep -p 'async function $NAME($$$PARAMS) { $$$BODY }' -l js src/
# Find if-else without braces
ast-grep -p 'if ($COND) $STMT' -l js src/
主なメタ変数構文:
$NAME— 単一の AST ノードに一致します(正規表現の.のようなものです)。例:foo($ARG)はfoo(a)に一致しますが、foo(a, b)には一致しません。$$$ARGS— 0 個以上のノードに一致します(正規表現の.*のようなものです)。例:foo($$$ARGS)はfoo()、foo(a)、foo(a, b)に一致します。これが最もよくある落とし穴です!引数やブロック本体に一致させる場合、ノードを 1 つだけ指定したいのでなければ、デフォルトで$$$を使いましょう。$_— 名前のない一致です(後で参照する必要がない場合に使います)。
TypeScript のジェネリック呼び出しには、別のパターンが必要です:
TypeScript/TSX では、useState<string>('') のような呼び出しで、<string> は独立した type_arguments AST ノードとして扱われます。パターン useState($$$ARGS) はこれに一致しません。すべてを網羅するには、2 回に分けて検索する必要があります:
# Non-generic calls (works for all languages)
ast-grep -p 'useState($$$ARGS)' src/
# Generic TypeScript calls like useState<T>()
ast-grep -p 'useState<$T>($$$ARGS)' -l tsx src/
ast-grep -p 'useState<$T>($$$ARGS)' -l ts src/
型引数が string | null のようなユニオン型の場合は、$T の代わりに $$$T を使ってください。
書き換えプレビュー付きで検索:
# Preview replacing var with const
ast-grep -p 'var $NAME = $VALUE' -r 'const $NAME = $VALUE' -l js src/
# Apply interactively (prompts y/n per match)
ast-grep -p 'var $NAME = $VALUE' -r 'const $NAME = $VALUE' -l js --interactive src/
パターンの詳細については、ast-grep-cheatsheet.md を参照してください。
フェーズ 2:JSON 出力をスクリプトに渡す
多くの場合、一致結果をターミナルに表示するだけでは不十分です。複雑な分析では、一致結果を JSON としてエクスポートし、スクリプトで処理することをおすすめします。これは、グラフの構築、未使用コードの検出、レポートの生成に特に有効です。
JSON を生成して保存する:
# Export all function definitions to a file for secondary analysis
ast-grep -p 'function $NAME($$$PARAMS) { $$$BODY }' -l typescript --json src/ > functions.json
次に、簡単な Python または Node.js のスクリプトを書いて functions.json を読み込み、必要なノードのテキスト、行番号、関係を抽出します!
(例:JSON を解析して、特定の命名規則に従う関数を見つけたり、すべての import 元を抽出して依存関係グラフを構築したりします。)
フェーズ 3:複雑なワークフロー(ステップごと)
複雑な構造上の課題を解決するための詳細な手順を紹介します。
ワークフロー A:影響分析(X を変更した場合、何が壊れるか?)
- 検索:
ast-grepを使って対象シンボルXの定義を見つけ、正確な名前とモジュールパスを確認します。 - 直接の呼び出し元を見つける:
ast-grepを使って、Xをインポートするすべての import 文と、X()のすべての関数呼び出しを見つけます。結果を JSON ファイルに保存します。 - 分析:コードベースが大きい場合は、簡単なスクリプトで JSON を解析し、
Xを呼び出すファイルや関数の一覧を作成します。 - 反復(推移的な呼び出し元):必要に応じて、
Xを呼び出す関数について同じ手順を繰り返し、完全な呼び出しグラフを構築します。(または、Python プロジェクトの場合は、フェーズ 4 で紹介する同梱のbuild-graph.pyスクリプトを使います。)
ワークフロー B:安全なリファクタリング/移行
- 検索:
ast-grep -p '<pattern>' src/を実行し、古いパターンに一致する箇所をすべて見つけます。 - 確認:
--jsonを追加して一致の詳細を確認し、パターンが意図しないコード範囲を取得していないことを確認します(例:ブロックには$BODYではなく$$$BODYを使っていることを確認します)。 - プレビュー:
-r '<rewrite>'を追加し、置換結果が標準出力に表示されることを確認します。いくつかの境界ケースも確認してください。 - 適用:
--interactiveを追加して変更を選択的に適用するか、確信がある場合は--interactiveを外します(ただし、通常は適用後に検証するようにしてください)。 - 検証:検索パターン
ast-grep -p '<pattern>'を再実行し、一致数が 0 であることを確認します。
シンボルの名前変更には、複数回の検索が必要です。関数定義、呼び出し箇所、import/export 文は構造上異なる AST ノード型であるため、1 つのパターンですべてを捉えることはできません:
# Pass 1: rename the definition
ast-grep -p 'function oldName($$$P) { $$$B }' -r 'function newName($$$P) { $$$B }' -l ts src/
# Pass 2: rename all call sites (also catches bare references like arr.map(oldName))
ast-grep -p 'oldName($$$ARGS)' -r 'newName($$$ARGS)' -l ts src/
# Pass 3: rename named imports
ast-grep -p 'import { oldName } from $MOD' -r 'import { newName } from $MOD' -l ts src/
注:AST の一致は識別子を厳密に判定するため、単純な sed による置換とは異なり、oldNameHelper には影響しません。
フェーズ 4:同梱グラフビルダー(フォールバック)
ast-grep と JSON パイプラインは強力ですが、単純なパターンマッチングを超える完全な AST の走査が必要な場合に備えて、このスキルには一般的なグラフ構築タスク用のスクリプトが同梱されています。
特に、デッドコードや循環依存関係を確認するときに使用してください。
🤖 AI エージェントへの注意: これらの同梱スクリプトを呼び出すときは、
<SKILL_DIR>をこのSKILL.mdファイルがあるディレクトリの絶対パスに置き換えて、絶対パスを作成する必要があります。ユーザーのプロジェクトルートからの相対パスで実行しないでください。失敗します。
Python コードベース:
python3 <SKILL_DIR>/scripts/build-graph.py <directory> [flags]
# Common Flags:
# --callers <symbol> (find direct and transitive callers)
# --unused (find dead code / unreferenced symbols)
# --depends-on <mod> (find reverse dependencies)
# --cycles (detect circular imports)
JavaScript/TypeScript コードベース:
# Export a quick symbol list with line numbers
node <SKILL_DIR>/scripts/parse-js.mjs <file> --symbols
クイックリファレンス
| したいこと... | ast-grep コマンド |
|---|---|
foo() の呼び出しをすべて検索する | ast-grep -p 'foo($$$ARGS)' src/ |
| 関数定義を検索する | ast-grep -p 'function $NAME($$$P) { $$$B }' src/ |
| 未使用のインポートを検索する | ast-grep scan --inline-rules '...' src/ |
oldFn → newFn に名前を変更する | 3 回に分けて実行:定義、呼び出し箇所、インポート(ワークフロー B を参照) |
var → const に変換する | ast-grep -p 'var $N = $V' -r 'const $N = $V' --interactive src/ |
| スクリプト用に JSON を出力する | ast-grep -p '<pattern>' --json src/ > out.json |
| 変更の影響を確認する | グラフを構築 → すべての推移的な呼び出し元を検索する(逆方向 BFS) |
関連ファイル
- ast-grep-cheatsheet.md — ast-grep のパターンと CLI の完全なリファレンス
- graph-schema.md — ER 図を含む、ノードとエッジの型定義
- query-patterns.md — 例を含む、クエリパターンの詳細なクックブック
- scripts/parse-js.mjs — JS/TS AST 解析用のクロスプラットフォーム Node.js スクリプト
- scripts/build-graph.py — Python コードグラフビルダー