ast-grep-search について
ast-grep-searchは、AST構造に基づいてコードを検索・変更するast-grepのスキルです。テキスト検索では扱いにくい構造的なパターンや複数ファイルの変更に取り組む開発者向けです。
主な機能
- 01ASTベースのコードパターン検索
- 02パターン変数によるノード捕捉
- 03置換のプレビューと適用
- 04対話形式での変更確認
- 05YAMLによる再利用可能なスキャンルール
活用シーン
- 01引数の数が異なる呼び出しの検索
- 02複数ファイルにまたがるAPI利用の変更
- 03言語別コードパターンの特定
- 04コードベース固有の問題を検出するルール作成
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ laurigates/ claude-plugins --skill ast-grep-searchインストール後、Claude Code で/ast-grep-searchを入力して読み込まれたか確認します。
同梱ファイルREFERENCE.md
詳細
ast-grep による構造的なコード検索とリファクタリング
ast-grep を使用した構造的なコード検索とリファクタリングです。テキストパターンではなく、コードの AST(抽象構文木)に基づいてマッチします。
このスキルを使用する場面
| このスキルを使用する場面… | 代わりに別のものを使用する場面… |
|---|---|
| パターンが AST 構造(関数の形、呼び出し形式、引数の数)に依存する場合 | プレーンテキストや正規表現で検索する場合 → tools-plugin:rg-code-search |
| キャプチャした変数を維持しながら、多数のファイルにまたがる API 呼び出し箇所をリファクタリングする場合 | レポートを作成する一回限りのアンチパターンスキャンを実行する場合 → code-antipatterns |
| アドホックな移行で、手書きの構造的な検索と置換を行う場合 | 既知のファイル/ディレクトリを対象に機能的なリファクタリングを行う場合 → code-refactor |
| コードベース固有の問題を検出する新しい ast-grep ルールを作成する場合 | 既存のリンター用のエージェント向けフラグを調べる場合 → code-lint |
ast-grep と Grep/ripgrep の使い分け
| ast-grep を使用する場面… | grep/rg を使用する場面… |
|---|---|
| パターンがコード構造に依存する | シンプルなテキストまたは正規表現のマッチ |
| 任意の数の引数にマッチさせる必要がある | ログ、ドキュメント、設定を検索する |
| 多数のファイルにまたがってリファクタリングする | 一回限りのリテラル文字列検索 |
| アンチパターン(空の catch など)を見つける | 言語を問わない |
| 変数を維持しながら置換する | ファイル名/行を素早く確認する |
判断基準:「任意の式」「任意の引数」「任意の関数名」を表すワイルドカードが検索パターンに含まれる場合は、ast-grep を使用してください。
パターン構文
| パターン | マッチ対象 | 例 |
|---|---|---|
$VAR | 単一の AST ノード | console.log($MSG) |
$$$ARGS | 0 個以上のノード | func($$$ARGS) |
$_ | 単一のノード(キャプチャなし) | $_ == $_ |
$A == $A | 同じノードの繰り返し | x == x を検出します(x == y は検出しません) |
基本的なコマンド
パターンを検索する
# Find structural patterns
ast-grep -p 'console.log($$$)' --lang js
ast-grep -p 'def $FUNC($$$): $$$' --lang py
ast-grep -p 'fn $NAME($$$) -> $RET { $$$ }' --lang rs
# Search in specific directory
ast-grep -p 'import $PKG' --lang js src/
# JSON output for parsing
ast-grep -p 'pattern' --lang js --json=compact
検索して置換する
# Preview changes (default - shows matches)
ast-grep -p 'var $V = $X' -r 'const $V = $X' --lang js
# Apply changes to all files
ast-grep -p 'var $V = $X' -r 'const $V = $X' --lang js -U
# Interactive review
ast-grep -p 'oldAPI($$$ARGS)' -r 'newAPI($$$ARGS)' --lang py -i
# Convert function syntax
ast-grep -p 'function($$$ARGS) { return $EXPR }' \
-r '($$$ARGS) => $EXPR' --lang js -U
# Update import paths
ast-grep -p "import $NAME from '@old/$PATH'" \
-r "import $NAME from '@new/$PATH'" --lang ts -U
言語コード
| コード | 言語 | コード | 言語 |
|---|---|---|---|
js | JavaScript | py | Python |
ts | TypeScript | rs | Rust |
jsx | JSX | go | Go |
tsx | TSX | java | Java |
cpp | C++ | rb | Ruby |
c | C | php | PHP |
言語別の一般的なパターン
JavaScript/TypeScript
# Find React hooks
ast-grep -p 'const [$STATE, $SETTER] = useState($INIT)' --lang jsx
# Find async functions
ast-grep -p 'async function $NAME($$$) { $$$ }' --lang js
# Find type assertions
ast-grep -p '$EXPR as $TYPE' --lang ts
# Find empty catch blocks
ast-grep -p 'try { $$$ } catch ($E) { }' --lang js
# Find eval usage (security)
ast-grep -p 'eval($$$)' --lang js
# Find innerHTML (XSS risk)
ast-grep -p '$ELEM.innerHTML = $$$' --lang js
# Find specific imports
ast-grep -p "import { $$$IMPORTS } from '$PKG'" --lang js
Python
# Find class definitions
ast-grep -p 'class $NAME($$$BASES): $$$' --lang py
# Find decorated functions
ast-grep -p '@$DECORATOR\ndef $FUNC($$$): $$$' --lang py
# Find dangerous shell calls
ast-grep -p 'os.system($$$)' --lang py
# Find SQL concatenation (injection risk)
ast-grep -p '"SELECT * FROM " + $VAR' --lang py
Rust
# Find unsafe blocks
ast-grep -p 'unsafe { $$$ }' --lang rs
# Find impl blocks
ast-grep -p 'impl $TRAIT for $TYPE { $$$ }' --lang rs
# Find public functions
ast-grep -p 'pub fn $NAME($$$) { $$$ }' --lang rs
Go
# Find goroutines
ast-grep -p 'go $FUNC($$$)' --lang go
# Find defer statements
ast-grep -p 'defer $FUNC($$$)' --lang go
# Find error handling
ast-grep -p 'if err != nil { $$$ }' --lang go
よくあるリファクタリングのレシピ
# Replace deprecated API calls
ast-grep -p 'oldAPI.$METHOD($$$)' -r 'newAPI.$METHOD($$$)' --lang js -U
# Rename a function across files
ast-grep -p 'oldName($$$ARGS)' -r 'newName($$$ARGS)' --lang py -U
# Remove console.log statements
ast-grep -p 'console.log($$$)' -r '' --lang js -U
# Convert require to import
ast-grep -p 'const $NAME = require($PKG)' \
-r 'import $NAME from $PKG' --lang js -i
# Add error handling wrapper
ast-grep -p 'await $EXPR' \
-r 'await $EXPR.catch(handleError)' --lang ts -i
コマンドラインフラグ
| フラグ | 用途 |
|---|---|
-p, --pattern | 検索パターン |
-r, --rewrite | 置換パターン |
-l, --lang | 対象言語 |
-i, --interactive | 変更を一つずつ確認する |
-U, --update-all | すべての変更を適用する |
--json | JSON 出力(compact、stream、pretty) |
-A N | マッチ箇所の後の行数 |
-B N | マッチ箇所の前の行数 |
-C N | マッチ箇所の前後の行数 |
--debug-query | パターン解析をデバッグする |
YAML ルール(スキャンモード)
再利用可能なルールには、YAML 設定を使用して ast-grep scan を実行します。
# Scan with config
ast-grep scan -c sgconfig.yml
# Run specific rule
ast-grep scan -r rule-name
# Initialize a rules project
ast-grep new project my-linter
ast-grep new rule no-console-log
最小限のルールファイル:
id: no-empty-catch
language: JavaScript
severity: warning
message: Empty catch block hides errors
rule:
pattern: try { $$$ } catch ($E) { }
fix: |
try { $$$ } catch ($E) { console.error($E) }
YAML ルールの構文、制約、変換、テストの詳細については、REFERENCE.md を参照してください。
エージェント向けの最適化
| コンテキスト | コマンド |
|---|---|
| 素早い構造検索 | ast-grep -p 'pattern' --lang js --json=compact |
| マッチ数を数える | ast-grep -p 'pattern' --lang js --json=stream | wc -l |
| ファイル一覧のみ | ast-grep -p 'pattern' --json=stream | jq -r '.file' | sort -u |
| 一括リファクタリング | ast-grep -p 'old' -r 'new' --lang js -U |
| ルールを使用してスキャンする | ast-grep scan --json |
| パターンをデバッグする | ast-grep -p 'pattern' --debug-query --lang js |
クイックリファレンス
# 1. Search for pattern
ast-grep -p 'pattern' --lang js src/
# 2. Preview rewrite
ast-grep -p 'old' -r 'new' --lang js
# 3. Apply rewrite
ast-grep -p 'old' -r 'new' --lang js -U
# 4. Scan with rules
ast-grep scan -c sgconfig.yml
# 5. Debug pattern
ast-grep -p 'pattern' --debug-query --lang js
コメント
Markdown 対応