mcpField
A
ast-grep

ast-grep

github.com/ast-grep開発89918.1k 回インストール7 週間前に更新
リポジトリ

ast-grep について

自然言語の要望を ast-grep の構造検索ルールに変換するスキルです。構文に基づくコード検索が必要な開発者向けに、ルール作成、テスト、デバッグ、リポジトリ検索を扱います。

主な機能

  1. 01要望を AST 検索ルールに変換
  2. 02pattern、kind、関係ルールの利用
  3. 03all、any、not 条件の組み合わせ
  4. 04ルールのテストとデバッグ
  5. 05パターンまたはルールでリポジトリを検索
  6. 06AST を調べてマッチを診断

活用シーン

  1. 01エラー処理のない非同期関数の検索
  2. 02指定引数を持つ呼び出しの特定
  3. 03特定の文脈内にある構造の検索
  4. 04ルールがマッチしない原因の調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/ast-grep/agent-skill --skill ast-grep

インストール後、Claude Code で/ast-grepを入力して読み込まれたか確認します。

同梱ファイルreferences/rule_reference.md

詳細

ast-grep コード検索

概要

このスキルは、自然言語のクエリを ast-grep のルールに変換し、構造に基づいてコードを検索するのに役立ちます。ast-grep は、単なるテキストではなくコードの構造に基づいて照合する抽象構文木(AST)パターンを使用するため、大規模なコードベースでも強力かつ精密なコード検索が可能です。

このスキルを使用するタイミング

次のような場合に、このスキルを使用してください。

  • 構造マッチングを使ってコードパターンを検索したい場合(例:「エラー処理がない非同期関数をすべて探す」)
  • 特定の言語構文を見つけたい場合(例:「特定のパラメーターを持つ関数呼び出しをすべて探す」)
  • テキストだけでなく、コード構造の理解が必要な検索を依頼された場合
  • 特定の AST の特徴を持つコードの検索を依頼された場合
  • 従来のテキスト検索では対応できない複雑なコードクエリを実行する必要がある場合

一般的なワークフロー

効果的な ast-grep ルールを作成できるよう、次の手順に従ってください。

ステップ 1:クエリを理解する

ユーザーが何を見つけたいのかを明確に理解します。必要に応じて、確認の質問をしてください。

  • どのようなコードパターンや構造を探していますか?
  • どのプログラミング言語ですか?
  • 考慮すべきエッジケースやバリエーションはありますか?
  • マッチに含めるもの、または除外するものは何ですか?
ステップ 2:サンプルコードを作成する

ユーザーがマッチさせたい内容を表す簡単なコードスニペットを作成します。テスト用に一時ファイルへ保存してください。

例: 「await を使う非同期関数」を検索する場合、テストファイルを作成します。

// test_example.js
async function example() {
  const result = await fetchData();
  return result;
}
ステップ 3:ast-grep ルールを作成する

パターンを ast-grep ルールに変換します。まずシンプルなルールを作成し、必要に応じて複雑さを加えてください。

主な原則:

  • 関係ルール(inside、has)では、検索が方向の末端まで進むよう、常に stopBy: end を使用します
  • シンプルな構造には pattern を使用します
  • 複雑な構造には has/inside とともに kind を使用します
  • 複雑なクエリは、all、any、または not を使って小さなサブルールに分割します

ルールファイルの例(test_rule.yml):

id: async-with-await
language: javascript
rule:
  kind: function_declaration
  has:
    pattern: await $EXPR
    stopBy: end

包括的なルールドキュメントについては、references/rule_reference.md を参照してください。

ステップ 4:ルールをテストする

ast-grep CLI を使って、ルールがサンプルコードにマッチすることを確認します。主な方法は 2 つあります。

オプション A:インラインルールでテストする(迅速な反復向け)

echo "async function test() { await fetch(); }" | ast-grep scan --inline-rules "id: test
language: javascript
rule:
  kind: function_declaration
  has:
    pattern: await \$EXPR
    stopBy: end" --stdin

オプション B:ルールファイルでテストする(複雑なルールに推奨)

ast-grep scan --rule test_rule.yml test_example.js

マッチしない場合のデバッグ:

  1. ルールをシンプルにします(サブルールを削除します)
  2. 関係ルールに stopBy: end がない場合は追加します
  3. --debug-query を使って AST の構造を確認します(下記を参照)
  4. kind の値がその言語で正しいか確認します
  5. run --pattern(ルールではありません)でマッチ数が 0 件になる場合は、下記の「マッチが 0 件?」のヒントを参照してください
ステップ 5:コードベースを検索する

ルールがサンプルコードに正しくマッチしたら、実際のコードベースを検索します。

シンプルなパターン検索の場合:

ast-grep run --pattern 'console.log($ARG)' --lang javascript /path/to/project

複雑なルールベースの検索の場合:

ast-grep scan --rule my_rule.yml /path/to/project

インラインルールの場合(ファイルを作成しない場合):

ast-grep scan --inline-rules "id: my-rule
language: javascript
rule:
  pattern: \$PATTERN" /path/to/project

ast-grep CLI コマンド

コード構造を調べる(--debug-query)

AST の構造を出力して、コードがどのように解析されるかを確認します。

ast-grep run --pattern 'async function example() { await fetch(); }' \
  --lang javascript \
  --debug-query=cst

利用可能な形式:

  • cst:具体構文木(句読点を含むすべてのノードを表示)
  • ast:抽象構文木(名前付きノードのみを表示)
  • pattern:ast-grep がパターンをどのように解釈するかを表示

次の用途に使用します:

  • ノードの正しい kind の値を見つける
  • マッチさせたいコードの構造を理解する
  • パターンがマッチしない理由をデバッグする

例:

# See the structure of your target code
ast-grep run --pattern 'class User { constructor() {} }' \
  --lang javascript \
  --debug-query=cst

# See how ast-grep interprets your pattern
ast-grep run --pattern 'class $NAME { $$$BODY }' \
  --lang javascript \
  --debug-query=pattern
ルールをテストする(--stdin を使った scan)

ファイルを作成せずに、コードスニペットに対してルールをテストします。

echo "const x = await fetch();" | ast-grep scan --inline-rules "id: test
language: javascript
rule:
  pattern: await \$EXPR" --stdin

構造化された出力には --json を追加します:

echo "const x = await fetch();" | ast-grep scan --inline-rules "..." --stdin --json
パターンで検索する(run)

単一の AST ノードにマッチする、シンプルなパターンベースの検索です。

# Basic pattern search
ast-grep run --pattern 'console.log($ARG)' --lang javascript .

# Search specific files
ast-grep run --pattern 'class $NAME' --lang python /path/to/project

# JSON output for programmatic use
ast-grep run --pattern 'function $NAME($$$)' --lang javascript --json .

使用する場面:

  • シンプルな単一ノードのマッチ
  • 複雑なロジックを必要としない簡易検索
  • 関係ルール(inside/has)が不要な場合
--json 出力の読み取り

--json は、一致した項目をラップする matches を含まない、JSON の配列を出力します。パターンが foo($ARG, $$$REST) の場合:

[{
  "text": "foo(\"value\", 1, 2)",
  "file": "src/app.js",
  "range": { "start": { "line": 41, "column": 10 }, "end": { "line": 41, "column": 27 } },
  "metaVariables": {
    "single": { "ARG": { "text": "\"value\"" } },
    "multi": { "REST": [ { "text": "1" }, { "text": "2" } ] }
  }
}]

scan --json も同じスキーマを使用します。

(各一致項目には lines と language も含まれます。)range.start.line は 0 始まりです。名前付きメタ変数($ARG)は single に、リストメタ変数($$$REST)はリストとして multi に格納されます(キャプチャがない場合は空です)。jq で抽出します:

ast-grep run --pattern 'foo($ARG)' --lang javascript --json . \
  | jq -r '.[] | "\(.file):\(.range.start.line + 1): \(.metaVariables.single.ARG.text)"'
ルールを使った検索(scan)

複雑な構造クエリ向けの YAML ルールベースの検索です:

# With rule file
ast-grep scan --rule my_rule.yml /path/to/project

# With inline rules
ast-grep scan --inline-rules "id: find-async
language: javascript
rule:
  kind: function_declaration
  has:
    pattern: await \$EXPR
    stopBy: end" /path/to/project

# JSON output
ast-grep scan --rule my_rule.yml --json /path/to/project

使用する場面:

  • 複雑な構造検索
  • 関係性ルール(inside、has、precedes、follows)
  • 複合ロジック(all、any、not)
  • 完全な YAML ルールの機能が必要な場合

ヒント: 関係性ルール(inside/has)では、完全に走査できるよう、常に stopBy: end を追加してください。

効果的なルールを作成するためのヒント

常に stopBy: end を使用する

関係性ルールでは、特別な理由がない限り、常に stopBy: end を使用してください:

has:
  pattern: await $EXPR
  stopBy: end

これにより、最初に一致しないノードで停止せず、検索がサブツリー全体を走査します。

シンプルなルールから始め、徐々に複雑にする

機能する可能性のある、最もシンプルなルールから始めます:

  1. まず pattern を試します
  2. うまくいかない場合は、kind でノードタイプとの一致を試します
  3. 必要に応じて関係性ルール(has、inside)を追加します
  4. 複雑なロジックには、複合ルール(all、any、not)を組み合わせます
適切なルールタイプを使用する
  • パターン:単純で直接的なコードの一致に使用します(例:console.log($ARG))
  • Kind + 関係性:複雑な構造に使用します(例:「await を含む関数」)
  • 複合:論理的な組み合わせに使用します(例:「try-catch の外で await を含む関数」)
AST 検査でデバッグする

ルールが一致しない場合:

  1. --debug-query=cst を使用して、実際の AST 構造を確認します
  2. メタ変数が正しく検出されているか確認します
  3. ノードの kind が想定どおりか確認します
  4. 関係性ルールが正しい方向を検索しているか確認します
一致がゼロ?パターンは AST ノード全体に一致します

run --pattern はテキストの部分文字列ではなく、AST ノード全体に一致するため、一致がゼロの場合は「コードが存在しない」か「パターンのノード形状が誤っている」ことを意味します:

  • 修飾パスはノード全体として扱われます:env::var($ENV) は std::env::var("X") に一致しません。修飾なしの形式と完全修飾形式の両方を試すか、$$$ を使って間にあるノードを吸収してください。
  • その違いを確認するには、コードを含むことがわかっているスニペットでパターンを試し、--debug-query=pattern を使って ast-grep の解析結果を調べます(scan/ルールだけでなく、run でも動作します)。ルールで一致がゼロの場合は、手順 4 のデバッグチェックリストに従ってください。
インラインルールのエスケープ

--inline-rules を使用する場合、シェルコマンド内のメタ変数をエスケープしてください:

  • $VAR の代わりに \$VAR を使用します(シェルが $ を変数として解釈するためです)
  • または、シングルクォートを使用します:'$VAR' はほとんどのシェルで機能します

例:

# Correct: escaped $
ast-grep scan --inline-rules "rule: {pattern: 'console.log(\$ARG)'}" .

# Or use single quotes
ast-grep scan --inline-rules 'rule: {pattern: "console.log($ARG)"}' .

よくあるユースケース

特定の内容を含む関数を検索する

await を使用する非同期関数を検索します:

ast-grep scan --inline-rules "id: async-await
language: javascript
rule:
  all:
    - kind: function_declaration
    - has:
        pattern: await \$EXPR
        stopBy: end" /path/to/project
特定のコンテキスト内のコードを検索する

クラスメソッド内の console.log を検索します:

ast-grep scan --inline-rules "id: console-in-class
language: javascript
rule:
  pattern: console.log(\$\$\$)
  inside:
    kind: method_definition
    stopBy: end" /path/to/project
期待されるパターンがないコードを検索する

try-catch のない非同期関数を検索します:

ast-grep scan --inline-rules "id: async-no-trycatch
language: javascript
rule:
  all:
    - kind: function_declaration
    - has:
        pattern: await \$EXPR
        stopBy: end
    - not:
        has:
          pattern: try { \$\$\$ } catch (\$E) { \$\$\$ }
          stopBy: end" /path/to/project

リソース

references/

ast-grep のルール構文に関する詳細なドキュメントが含まれています:

  • rule_reference.md:アトミックルール、関係性ルール、複合ルール、メタ変数を網羅した ast-grep ルールの包括的なドキュメント

ルール構文の詳細情報が必要な場合は、これらのリファレンスを読み込んでください。

コメント