code-structural-search について
ast-grepを使ったコード構造検索スキルです。キーワードではなく構文パターンに基づいてコードを検索・変更したい開発者やコーディングエージェントを対象とします。言語別の例と、ripgrepで候補を絞ってからAST照合する手順を示します。
主な機能
- 01ASTベースのコードパターン検索
- 0220以上の言語に対応
- 03言語別のパターン例
- 04ripgrepで絞り込む検索手順
- 05構造に基づくリファクタリングパターン
- 06パターン検証のガイド
活用シーン
- 01引数の数で関数を検索
- 02エラー処理やデータベースクエリのパターン特定
- 03潜在的なセキュリティ問題のコード監査
- 04リファクタリング対象の非推奨APIを検索
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ oimiragieo/ agent-studio --skill code-structural-searchインストール後、Claude Code で/code-structural-searchを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
PATTERNS.mdREADME.mdcommands/code-structural-search.mdhooks/post-execute.cjspre-execute.cjsreferences/research-requirements.mdrules/code-structural-search.mdschemas/input.schema.jsonoutput.schema.jsonscripts/main.cjstemplates/implementation-template.md詳細
コードの構造検索
AST ベースのコードパターンマッチングには ast-grep を使用します。
使用する場面
- キーワードではなく、構造でコードを検索する
- 「引数が3つの関数をすべて検索する」
- 「X を継承するクラスをすべて検索する」
- 「データベースクエリをすべて検索する」
- 「エラーハンドリングのパターンをすべて検索する」
- 正確なコードのリファクタリング(特定のパターンを変更する)
インターフェース
Skill({ skill: 'code-structural-search', args: 'pattern-here --lang ts' });
言語サポート
ast-grep は tree-sitter を介して20以上の言語をサポートしています。
| 言語 | フラグ | ファイル拡張子 |
|---|---|---|
| JavaScript | --lang js | .js, .jsx |
| TypeScript | --lang ts | .ts, .tsx |
| Python | --lang py | .py, .pyi |
| Go | --lang go | .go |
| Rust | --lang rs | .rs |
| Java | --lang java | .java |
| C | --lang c | .c, .h |
| C++ | --lang cpp | .cpp, .cc, .hpp, .hh |
| C# | --lang cs | .cs |
| Kotlin | --lang kt | .kt, .kts |
| Swift | --lang swift | .swift |
| PHP | --lang php | .php |
| Ruby | --lang rb | .rb |
| Lua | --lang lua | .lua |
| Elixir | --lang ex | .ex, .exs |
| HTML | --lang html | .html, .htm |
| CSS | --lang css | .css |
| JSON | --lang json | .json |
| Bash | --lang bash | .sh, .bash |
| Thrift | --lang thrift | .thrift |
パターンの例
JavaScript/TypeScript
すべての関数を検索する:
function $NAME($ARGS) { $$ }
引数がちょうど2つの関数を検索する:
function $NAME($A, $B) { $$ }
非同期関数を検索する:
async function $NAME($ARGS) { $$ }
クラスメソッドを検索する:
class $NAME {
$METHOD($ARGS) { $$ }
}
アロー関数を検索する:
const $NAME = ($ARGS) => { $$ }
console.log 文を検索する:
console.log($$$)
try-catch ブロックを検索する:
try { $$ } catch ($ERR) { $$ }
Python
すべての関数を検索する:
def $NAME($ARGS): $$$
クラス定義を検索する:
class $NAME: $$$
非同期関数を検索する:
async def $NAME($ARGS): $$$
インポートを検索する:
import $MODULE
from インポートを検索する:
from $MODULE import $$$
Go
すべての関数を検索する:
func $NAME($ARGS) $RETURN { $$ }
構造体定義を検索する:
type $NAME struct { $$$ }
インターフェース定義を検索する:
type $NAME interface { $$$ }
Rust
すべての関数を検索する:
fn $NAME($ARGS) -> $RETURN { $$ }
impl ブロックを検索する:
impl $NAME { $$$ }
pub 関数を検索する:
pub fn $NAME($ARGS) -> $RETURN { $$ }
Java
すべてのメソッドを検索する:
public $RETURN $NAME($ARGS) { $$ }
クラス定義を検索する:
public class $NAME { $$$ }
インターフェース定義を検索する:
public interface $NAME { $$$ }
パターン構文
| 記号 | 意味 | 例 |
|---|---|---|
$NAME | 単一のノード/識別子 | function $NAME() {} |
$$$ | 0個以上の文/ノード | class $NAME { $$$ } |
$$ | 0個以上の文(ブロック) | if ($COND) { $$ } |
$_ | 名前のないワイルドカード(破棄) | console.log($_) |
パフォーマンス
- 速度:検索1回あたり50ms未満(通常)
- セマンティック検索(フェーズ1)との併用が最適です
- 最初に ripgrep を使ってファイルを見つけます
他のツールとの比較
Ripgrep(grep)との比較:
- Ripgrep:高速なテキスト検索で、キーワードを見つけます
- ast-grep:構造検索で、正確なコードパターンを見つけます
- まず ripgrep を使用し、その後 ast-grep で絞り込みます
セマンティック検索(フェーズ1)との比較:
- セマンティック検索:コードの意味を理解します
- ast-grep:コードの構造を理解します
- 併用:最良の結果が得られます(フェーズ2)
使用ワークフロー
-
ripgrep で幅広く検索します:
Skill({ skill: 'ripgrep', args: 'authenticate --type ts' }) -
ast-grep で構造的に絞り込みます:
Skill({ skill: 'code-structural-search', args: 'function authenticate($$$) { $$ } --lang ts' }) -
フェーズ1で意味を理解します:
Skill({ skill: 'code-semantic-search', args: 'authentication logic' })
よくあるユースケース
セキュリティパターン
検証されていない入力を検索する:
router.post($PATH, ($REQ, $RES) => { $$ })
SQL クエリ(インジェクションの可能性あり)を検索する:
db.query(`SELECT * FROM ${$VAR}`)
eval の使用箇所を検索する:
eval($$$)
コード品質パターン
深くネストされた関数を検索する:
function $NAME($ARGS) {
if ($COND) {
if ($COND2) {
if ($COND3) { $$ }
}
}
}
パラメーターが5個を超える関数を検索する:
function $NAME($A, $B, $C, $D, $E, $F, $$$) { $$ }
未使用の変数を検索する:
const $NAME = $VALUE;
リファクタリングパターン
古い API の使用箇所を検索します:
oldAPI.deprecatedMethod($$$)
コールバックパターンを検索します(async/await に変換します):
$FUNC($ARGS, ($ERR, $DATA) => { $$ })
React のクラスコンポーネントを検索します(フックに変換します):
class $NAME extends React.Component { $$$ }
厳守事項
- 必ず
--langフラグで言語を指定してください — 言語フラグを指定しないと、ast-grep はヒューリスティックを適用し、誤検出が発生します。正確な AST 解析のために、--lang ts、--lang pyなどを指定してください。 - 必ず最初に ripgrep/キーワード検索で対象を絞り込んでください — コードベース全体を対象とした構造検索は時間がかかります。まず ripgrep で候補ファイルを見つけてから、ast-grep で正確に検索してください。
- 構造的なコードパターンに正規表現を使用しないでください — 正規表現は書式の違い、ネスト構造、複数行のコードで機能しません。AST パターンは書式に依存せず、意味的に正確です。
- プロジェクト全体で実行する前に、必ず既知の一致箇所でパターンをテストしてください — 構文が誤ったパターンは、何も一致しなくても気づかないことがあります。広範囲に適用する前に、既知の例が少なくとも 1 つ見つかることを確認してください。
- 可変長の引数リストには
*や.ではなく、必ず$$$を使用してください — ast-grep はメタ変数の構文($NAME、$$$、$$)を使用します。パターン内で正規表現やグロブの構文を使うと、気づかないまま失敗します。
アンチパターン
| アンチパターン | 失敗する理由 | 正しい方法 |
|---|---|---|
--lang フラグを指定しない | 誤ったパーサーが適用され、誤検出や見落としが発生する | 必ず --lang ts、--lang py などを指定する |
| ripgrep で事前に絞り込まず、プロジェクト全体を検索する | 大規模なコードベースでは時間がかかり、無関係な結果が多くなる | まず ripgrep で候補ファイルを特定する |
| 構造検索に正規表現を使用する | 複数行、空白の違い、ネスト構造で機能しない | ast-grep の AST パターン($NAME、$$$ など)を使う |
| テストしていないパターンをコードベース全体に適用する | パターンが誤っていても、何も返さず気づかない | まず既知の一致箇所 1 つでテストする |
ワイルドカードに * や . を使う | ast-grep の有効な構文ではないため、無視されるかエラーになる | 単一ノードには $NAME、並びには $$$ を使う |
メモリープロトコル(必須)
開始前:
.claude/context/memory/learnings.md を読みます。
完了後:
- 新しいパターン →
.claude/context/memory/learnings.md - 見つかった問題 →
.claude/context/memory/issues.md - 決定事項 →
.claude/context/memory/decisions.md
中断されることを前提にしてください。メモリーに記録されていなければ、実施されていないものとみなします。