claude ast-grep skill
This commit is contained in:
82
claude/.claude/skills/ast-grep/SKILL.md
Normal file
82
claude/.claude/skills/ast-grep/SKILL.md
Normal file
@@ -0,0 +1,82 @@
|
||||
---
|
||||
name: ast-grep
|
||||
description: "Structural code search and rewriting with ast-grep (AST-aware grep). Use instead of rg/grep when searching for code *structure* rather than text: find all calls/definitions matching a shape, match across formatting/line breaks, extract matched sub-parts (function names, arguments), or perform safe codemod-style rewrites. Works for Rust, TS/JS, Python, Go, Java, C/C++, and most tree-sitter languages."
|
||||
---
|
||||
|
||||
# ast-grep: structural search & rewrite
|
||||
|
||||
ast-grep matches code by AST shape, not text. Prefer it over `rg` when the target spans lines, when formatting varies, or when you need to rewrite code safely.
|
||||
|
||||
## Pattern syntax
|
||||
|
||||
Patterns are **valid code snippets** with meta-variables:
|
||||
|
||||
| Syntax | Matches |
|
||||
|---|---|
|
||||
| `$VAR` | exactly one AST node (UPPERCASE names only) |
|
||||
| `$$$` / `$$$ARGS` | zero or more nodes (args, params, statements) |
|
||||
| `$_` | one node, non-capturing |
|
||||
| repeated `$A` | backreference: `$A == $A` matches `x == x`, not `x == y` |
|
||||
|
||||
## Search
|
||||
|
||||
```bash
|
||||
ast-grep -p '$X.unwrap()' -l rust src/ # find all .unwrap() calls
|
||||
ast-grep -p 'fn $NAME($$$) -> $RET { $$$ }' -l rust . # multi-line shapes ok
|
||||
ast-grep -p 'await $EXPR' -l ts src/
|
||||
```
|
||||
|
||||
- `-l <lang>` is required unless searching by file extension is unambiguous; use it anyway.
|
||||
- **Always single-quote patterns** — double quotes let the shell eat `$VAR`.
|
||||
- Pattern must parse as valid code for that language (e.g. a bare `match $E { $$$ }` works in Rust because it's a valid expression).
|
||||
|
||||
## Structured output (for scripting / extraction)
|
||||
|
||||
```bash
|
||||
ast-grep -p 'pub fn $F($$$) { $$$ }' -l rust src/ --json=compact
|
||||
```
|
||||
|
||||
JSON gives `file`, `range`, `text`, and `metaVariables.single.F.text` — use this to extract e.g. all matching function names instead of parsing grep output.
|
||||
|
||||
## Rewrite
|
||||
|
||||
```bash
|
||||
# Preview as diff (default: prints diff, does NOT modify files)
|
||||
ast-grep -p '$X.lock().unwrap()' --rewrite '$X.lock().expect("poisoned")' -l rust src/
|
||||
# Apply all edits
|
||||
ast-grep -p '...' --rewrite '...' -l rust src/ --update-all
|
||||
```
|
||||
|
||||
Preview first, then `--update-all`. The rewrite is a text template: metavars are substituted, unmatched metavars become empty strings.
|
||||
|
||||
## YAML rules (when patterns aren't enough)
|
||||
|
||||
For context-sensitive matches (inside/has/not), use `scan --inline-rules`:
|
||||
|
||||
```bash
|
||||
ast-grep scan --inline-rules 'id: unwrap-in-closure
|
||||
language: rust
|
||||
rule:
|
||||
pattern: $X.unwrap()
|
||||
inside:
|
||||
kind: closure_expression
|
||||
stopBy: end
|
||||
message: unwrap inside closure' src/
|
||||
```
|
||||
|
||||
Rule keys:
|
||||
- **Atomic:** `pattern`, `kind` (node type, e.g. `closure_expression`), `regex`
|
||||
- **Relational:** `inside`, `has`, `follows`, `precedes` — add `stopBy: end` to search beyond direct parent/child
|
||||
- **Composite:** `all`, `any`, `not`
|
||||
- Optional `fix: <template>` per rule; `constraints:` to filter metavars (e.g. `X: {regex: '^foo'}`)
|
||||
|
||||
To discover node kinds for `kind:`, match a sample with `--json` (each match reports its node) or just use a pattern instead.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- `$var` (lowercase) is not a metavariable; use `$VAR`.
|
||||
- Single-quote patterns in the shell.
|
||||
- `kind` combined with `pattern` doesn't re-parse the pattern; if a snippet is ambiguous, use the pattern object form: `pattern: {context: 'class A { $F = $V }', selector: field_definition}`.
|
||||
- `all: [{kind: a}, {kind: b}]` tests the *same* node twice — for "contains both", use `all: [has: {...}, has: {...}]`.
|
||||
- Regexes use Rust regex syntax (no backreferences/lookaround).
|
||||
- Fall back to `rg` for plain-text/comment/string searches — ast-grep only matches code nodes.
|
||||
Reference in New Issue
Block a user