created: 2025-12-16
modified: 2026-05-09
reviewed: 2026-04-25
name: ast-grep-search
description: Find and replace code patterns structurally with ast-grep. Use when matching code by AST structure, finding functions with specific signatures, or detecting anti-patterns regex cannot match.
user-invocable: false
allowed-tools: Bash(sg *), Bash(ast-grep *), Read, Grep, Glob
model: sonnet
ast-grep Structural Code Search & Refactoring
Structural code search and refactoring using ast-grep — matches code by its AST (abstract syntax tree) rather than text patterns.
When to Use This Skill
| Use this skill when... |
Use something else instead when... |
| The pattern depends on AST structure (function shape, call form, argument count) |
Searching plain text or regex matches → tools-plugin:rg-code-search |
| Refactoring API call sites across many files while preserving captured variables |
Running a one-shot anti-pattern scan with a report → code-antipatterns |
| Hand-written structural search/replace for an ad-hoc migration |
Functional refactors of a known file/directory → code-refactor |
| Building a new ast-grep rule for a codebase-specific smell |
Looking up agentic flags for an existing linter → code-lint |
When to Use ast-grep vs Grep/ripgrep
| Use ast-grep when... |
Use grep/rg when... |
| Pattern depends on code structure |
Simple text or regex match |
| Need to match any number of arguments |
Searching logs, docs, config |
| Refactoring across many files |
One-off literal string search |
| Finding anti-patterns (empty catch, etc.) |
Language doesn't matter |
| Replacing while preserving variables |
Quick filename/line check |
Decision rule: If your search pattern contains wildcards for "any expression," "any arguments," or "any function name," use ast-grep.
Pattern Syntax
| Pattern |
Matches |
Example |
$VAR |
Single AST node |
console.log($MSG) |
$$$ARGS |
Zero or more nodes |
func($$$ARGS) |
$_ |
Single node (no capture) |
$_ == $_ |
$A == $A |
Same node repeated |
Finds x == x (not x == y) |
Essential Commands
Search for Patterns
# 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
Search and Replace
# 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
Language Codes
| Code |
Language |
Code |
Language |
js |
JavaScript |
py |
Python |
ts |
TypeScript |
rs |
Rust |
jsx |
JSX |
go |
Go |
tsx |
TSX |
java |
Java |
cpp |
C++ |
rb |
Ruby |
c |
C |
php |
PHP |
Common Patterns by Language
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
Common Refactoring Recipes
# 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
Command-Line Flags
| Flag |
Purpose |
-p, --pattern |
Search pattern |
-r, --rewrite |
Replacement pattern |
-l, --lang |
Target language |
-i, --interactive |
Review changes one by one |
-U, --update-all |
Apply all changes |
--json |
JSON output (compact, stream, pretty) |
-A N |
Lines after match |
-B N |
Lines before match |
-C N |
Lines around match |
--debug-query |
Debug pattern parsing |
YAML Rules (Scan Mode)
For reusable rules, use ast-grep scan with YAML configuration:
# 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
Minimal rule file:
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) }
For comprehensive YAML rule syntax, constraints, transformations, and testing, see REFERENCE.md.
Agentic Optimizations
| Context |
Command |
| Quick structural search |
ast-grep -p 'pattern' --lang js --json=compact |
| Count matches |
ast-grep -p 'pattern' --lang js --json=stream | wc -l |
| File list only |
ast-grep -p 'pattern' --json=stream | jq -r '.file' | sort -u |
| Batch refactor |
ast-grep -p 'old' -r 'new' --lang js -U |
| Scan with rules |
ast-grep scan --json |
| Debug pattern |
ast-grep -p 'pattern' --debug-query --lang js |
Quick Reference
# 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