name: ast-grep description: Write ast-grep rules for structural code search/analysis with AST patterns. Use when user asks to find code patterns, language constructs, or structural characteristics beyond text search.
ast-grep Code Search
Overview
NL query -> ast-grep rule. Matches AST structure, not raw text. Better precision on big repos.
When to Use
User wants:
- Structural match (ex: "async fns without error handling")
- Specific language construct (ex: "call sites with specific params")
- Query needing code structure, not text grep
- AST-shape-specific search
- Complex query text search cannot do
Workflow
1) Understand Query
Get exact target. Ask if needed: pattern/structure? language? edge cases/variants? include/exclude?
2) Create Example Code
Write small snippet of wanted match. Save temp file for tests.
Example: searching "async functions that use await":
// test_example.js
async function example() {
const result = await fetchData();
return result;
}
3) Write ast-grep Rule
Map target -> rule. Start simple. Add complexity only when needed.
Key rules:
- Always use
stopBy: endin relational rules (inside,has) so traversal reaches direction end - Use
patternfor simple structures - Use
kindwithhas/insidefor complex structures - Split complex queries with
all,any,not
Example rule file (test_rule.yml):
id: async-with-await
language: javascript
rule:
kind: function_declaration
has:
pattern: await $EXPR
stopBy: end
See references/rule_reference.md for full rule docs.
4) Test Rule
Verify rule matches example.
Option A: inline rules (fast iterate)
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
Option B: rule file (better for complex rules)
ast-grep scan --rule test_rule.yml test_example.js
If no match, debug order:
- Simplify rule (remove sub-rules)
- Add
stopBy: endto relational rules if missing - Use
--debug-queryto inspect AST (below) - Check
kindvalues for language
5) Search Codebase
After test passes, run on real repo.
Simple pattern search:
ast-grep run --pattern 'console.log($ARG)' --lang javascript /path/to/project
Complex rule search:
ast-grep scan --rule my_rule.yml /path/to/project
Inline rules (no file):
ast-grep scan --inline-rules "id: my-rule
language: javascript
rule:
pattern: \$PATTERN" /path/to/project
CLI Commands
Inspect Structure (--debug-query)
Dump parse structure. See how code/pattern parses.
ast-grep run --pattern 'async function example() { await fetch(); }' \
--lang javascript \
--debug-query=cst
Formats:
cst: Concrete Syntax Tree (includes punctuation)ast: Abstract Syntax Tree (named nodes only)pattern: ast-grep interpretation of pattern
Use for:
- Find right node
kind - Understand target code shape
- Debug non-matching patterns
Examples:
# See target code structure
ast-grep run --pattern 'class User { constructor() {} }' \
--lang javascript \
--debug-query=cst
# See pattern interpretation
ast-grep run --pattern 'class $NAME { $$$BODY }' \
--lang javascript \
--debug-query=pattern
Test Rules (scan --stdin)
Test rule on snippet, no files.
echo "const x = await fetch();" | ast-grep scan --inline-rules "id: test
language: javascript
rule:
pattern: await \$EXPR" --stdin
Structured output:
echo "const x = await fetch();" | ast-grep scan --inline-rules "..." --stdin --json
Search with Patterns (run)
Simple pattern search, single AST-node matches.
# 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 tooling
ast-grep run --pattern 'function $NAME($$$)' --lang javascript --json .
Use when:
- Simple single-node matches
- Quick search without complex logic
- No relational rules needed (
inside/has)
Search with Rules (scan)
YAML rule search, complex structural queries.
# 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
Use when:
- Complex structural search
- Relational rules (
inside,has,precedes,follows) - Composite logic (
all,any,not) - Full YAML rule power needed
Tip: For relational rules (inside/has), always add stopBy: end for full traversal.
Rule Writing Tips
Always Use stopBy: end
In relational rules, use stopBy: end unless strong reason not.
has:
pattern: await $EXPR
stopBy: end
Reason: traverse whole subtree, not stop at first non-match.
Start Simple, Then Add
- Try
pattern - If needed, use
kind - Add relational rules (
has,inside) - Add composite logic (
all,any,not)
Pick Right Rule Type
- Pattern: direct simple match (ex
console.log($ARG)) - Kind + Relational: complex structure (ex "function containing await")
- Composite: logic combos (ex "function with await but no try-catch")
Debug with AST Inspection
If no match:
--debug-query=cstfor real structure- Check metavariable detection
- Verify node
kind - Verify relational direction/search scope
Escaping Inline Rules
Shell expands $ in --inline-rules. Escape it.
\$VARinstead of$VAR- Or single quotes where possible:
'$VAR'
Example:
# 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)"}' .
Common Use Cases
Find Functions with Specific Content
Async fns using 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
Find Code Inside Specific Context
console.log inside class methods:
ast-grep scan --inline-rules "id: console-in-class
language: javascript
rule:
pattern: console.log(\$\$\$)
inside:
kind: method_definition
stopBy: end" /path/to/project
Find Missing Expected Pattern
Async fns without 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
Resources
references/
rule_reference.md: atomic, relational, composite rules + metavariables
Load when detailed syntax needed.