name: ast-grep description: Search code by AST patterns and perform structural refactoring across files. Use when finding function calls, replacing code patterns, or refactoring syntax that regex cannot reliably match.
ast-grep
Structural code search and rewriting using AST matching instead of regex.
Contents
- Pattern Syntax
- Basic Search
- Search and Replace
- Advanced Scan with Rules
- Common Refactoring Examples
- Project Setup
Pattern Syntax
ast-grep uses pattern placeholders to match and capture AST nodes:
| Pattern | Description |
|---|---|
$VAR |
Match a single AST node and capture it as VAR |
$$$VAR |
Match zero or more AST nodes (spread) and capture as VAR |
$_ |
Anonymous placeholder (matches any single node, no capture) |
$$$_ |
Anonymous spread placeholder (matches any number of nodes) |
Shell quoting tip: Escape $ as \$VAR or wrap the pattern in single quotes to avoid shell expansion.
Supported Languages
javascript, typescript, tsx, html, css, python, go, rust, java, c, cpp, csharp, ruby, php, yaml
Commands
| Command | Description |
|---|---|
ast-grep run |
One-time search or rewrite (default) |
ast-grep scan |
Scan and rewrite by configuration |
ast-grep test |
Test ast-grep rules |
ast-grep new |
Create new project or rules |
ast-grep lsp |
Start language server |
Usage
Basic Search
Find patterns in code:
# Find console.log calls
ast-grep run --pattern 'console.log($$$ARGS)' --lang javascript .
# Find React useState hooks
ast-grep run --pattern 'const [$STATE, $SETTER] = useState($INIT)' --lang tsx .
# Find async functions
ast-grep run --pattern 'async function $NAME($$$ARGS) { $$$BODY }' --lang typescript .
# Find Express route handlers
ast-grep run --pattern 'app.$METHOD($PATH, ($$$ARGS) => { $$$BODY })' --lang javascript .
# Find Python function definitions
ast-grep run --pattern 'def $NAME($$$ARGS): $$$BODY' --lang python .
# Find Go error handling
ast-grep run --pattern 'if $ERR != nil { $$$BODY }' --lang go .
Search and Replace (Dry Run)
Preview refactoring changes without modifying files:
# Replace == with === (preview)
ast-grep run --pattern '$A == $B' --rewrite '$A === $B' --lang javascript .
# Convert function to arrow function (preview)
ast-grep run --pattern 'function $NAME($$$ARGS) { $$$BODY }' \
--rewrite 'const $NAME = ($$$ARGS) => { $$$BODY }' --lang javascript .
# Replace var with let (preview)
ast-grep run --pattern 'var $NAME = $VALUE' --rewrite 'let $NAME = $VALUE' --lang javascript .
# Add optional chaining (preview)
ast-grep run --pattern '$OBJ && $OBJ.$PROP' --rewrite '$OBJ?.$PROP' --lang javascript .
Apply Changes
Apply refactoring to files:
# Apply changes (use --update-all)
ast-grep run --pattern '$A == $B' --rewrite '$A === $B' --lang javascript --update-all .
Advanced Scan with Rules
Use inline rules for complex pattern matching with logical operators:
# Find functions containing await
ast-grep scan --inline-rules '{"id": "async-fn", "language": "javascript", "rule": {"kind": "function_declaration", "has": {"pattern": "await $EXPR"}}}' .
# Find nested if statements
ast-grep scan --inline-rules '{"id": "nested-if", "language": "javascript", "rule": {"kind": "if_statement", "inside": {"kind": "if_statement"}}}' .
# Find console.log inside catch blocks
ast-grep scan --inline-rules '{"id": "catch-log", "language": "javascript", "rule": {"pattern": "console.log($$$ARGS)", "inside": {"kind": "catch_clause"}}}' .
Rule Operators
Rules support these operators for complex matching:
all: All conditions must matchany: Any condition must matchnot: Negate a conditioninside: Node must be inside another patternhas: Node must contain another patternkind: Match AST node typepattern: Match a code pattern
Common Refactoring Examples
JavaScript/TypeScript
# Convert require to import
ast-grep run --pattern 'const $NAME = require($PATH)' \
--rewrite 'import $NAME from $PATH' --lang javascript .
# Simplify boolean return
ast-grep run --pattern 'if ($COND) { return true } else { return false }' \
--rewrite 'return !!$COND' --lang javascript .
# Convert Promise.then to async/await
ast-grep run --pattern '$PROMISE.then($CALLBACK)' \
--rewrite 'await $PROMISE' --lang javascript .
Python
# Convert string formatting
ast-grep run --pattern '"%s" % ($ARGS)' \
--rewrite 'f"{$ARGS}"' --lang python .
# Find deprecated function calls
ast-grep run --pattern 'old_function($$$ARGS)' --lang python .
React
# Find class components
ast-grep run --pattern 'class $NAME extends React.Component { $$$BODY }' --lang tsx .
# Find useEffect with empty deps
ast-grep run --pattern 'useEffect($CALLBACK, [])' --lang tsx .
Workflow
- Search first: Use
ast-grep run --patternto find matches - Preview changes: Add
--rewriteto see what would change - Verify output: Review the diff output carefully
- Apply changes: Add
--update-allto modify files - Test: Run tests to verify refactoring didn't break anything
Project Setup
Create a new ast-grep project with rules:
# Initialize project with sgconfig.yml
ast-grep new
# Create a new rule
ast-grep new rule
# Create a new test for rules
ast-grep new test
Testing Rules
# Test all rules in project
ast-grep test
# Test with specific config
ast-grep test -c ./sgconfig.yml
Language Server
# Start LSP for editor integration (use tmux for background)
tmux new -d -s ast-grep-lsp 'ast-grep lsp'
Tips
- Start with simple patterns and refine
- Use
$_for parts you don't care about capturing - Use
$$$for variable-length matches (arguments, statements) - Test patterns on a single file first:
ast-grep run --pattern '...' --lang js path/to/file.js - Use JSON output for programmatic processing:
ast-grep run --pattern '...' --json - Use
ast-grep newto scaffold rules and tests
Related Skills
- typescript: Use ast-grep for TypeScript-specific refactoring patterns.
- jscpd: Combine with duplicate detection to find and consolidate similar code.