AST-Grep (ast-grep/sg) is a fast and user-friendly tool for code search, linting, and large-scale code rewriting.
Execution Environment
| Path Type | Description |
|---|---|
| Usage | Command-line tool, requires installation of ast-grep |
| Invocation Scenario | Grammar-aware code search, structured code analysis, bulk code transformation |
| Working Directory | Project root directory |
Installation
# macOS
brew install ast-grep
Linux
cargo install ast-grep
Verify Installationast-grep --version
## 核心功能
### 1. 语法感知搜索
使用 AST(抽象语法树)进行代码搜索,而非简单的文本匹配。
```bash
# 搜索特定模式
ast-grep --lang python -p "def $FUNC($$$ARGS):"
# 搜索函数调用
ast-grep --lang ts -p "console.log($$$MSG)"
# 搜索条件语句
ast-grep --lang ts -p "if ($$COND) { $$$BODY }"
2. Code Linting
AST-based code checking, more precise than traditional linters.
# 扫描项目
ast-grep scan -r sgconfig.yml
# 扫描特定目录
ast-grep scan src/
# 扫描特定文件
ast-grep scan src/main.ts
3. Code Rewriting
Bulk transformation of code patterns.
# 简单替换
ast-grep run -p "oldFunction($$$ARGS)" -r "newFunction($$ARGS)" --lang ts
# 复杂转换(使用 YAML 规则)
ast-grep run -r rule.yml
4. Rule Testing
Test whether ast-grep rules are correct.
# 测试规则
ast-grep test -r rule.yml
# 测试特定模式
ast-grep test -p "pattern" --lang ts
Rule Development Process
General Process
- Understand the query: Clarify the user's needs, ask for more details when necessary
- Write an example: Write a simple code example that matches the query
- Write a rule: Write an ast-grep rule that matches the example
- Test the rule: Use
test_match_code_ruleto verify the rule- If it does not match, remove some sub-rules and debug
- If using
insideorhas, make sure to usestopBy: end
- Search code: Use the rule to search the codebase
Rule Development Steps
- Decompose the query: Break the user query into smaller parts
- Identify sub-rules: Identify sub-rules that can be used to match the code
- Combine rules: Combine sub-rules using relational rules or composite rules
- Debug the rule: If the rule does not match the example code, remove some sub-rules and debug the non-matching parts
- Use tools: Use ast-grep mcp tools to dump the AST or dump the pattern query
- Test the rule: Use ast-grep mcp tools to test the rule against example code snippets
Rule Types
1. Atomic Rules
Match a single AST node based on intrinsic properties.
pattern - Pattern matching
# 字符串模式
pattern: console.log($ARG)
# 对象模式(更精细的控制)
pattern:
selector: field_definition
context: class { $F }
strictness: relaxed
kind - Node type matching
kind: call_expression
regex - Regular expression matching
regex: ^[a-z]+$
nthChild - Position matching
# 数字
nthChild: 1
# An+B 公式
nthChild: 2n+1
# 对象形式
nthChild:
position: 1
reverse: true
ofRule:
kind: function_declaration
range - Range matching
range:
start:
line: 0
column: 0
end:
line: 0
column: 10
2. Relational Rules
Filter the target based on its relationship with other nodes.
inside - Inside a parent node
inside:
pattern: class $C { $$$ }
stopBy: end
has - Contains a child node
has:
pattern: await $EXPR
stopBy: end
precedes - Before a node
precedes:
pattern: return $VAL
follows - After a node
follows:
pattern: import $M from '$P'
stopBy - Search termination control
# neighbor(默认):在直接周围节点不匹配时停止
stopBy: neighbor
# end:搜索到方向末尾(inside 为根,has 为叶子)
stopBy: end
# 规则对象:在周围节点匹配提供的规则时停止(包含)
stopBy:
pattern: class $END
field - Field matching
has:
field: operator
pattern: $$OP
3. Composite Rules
Combine other rules using logical operations.
all - Logical AND
all:
- kind: call_expression
- pattern: console.log($ARG)
any - Logical OR
any:
- pattern: console.log($ARG)
- pattern: console.warn($ARG)
- pattern: console.error($ARG)
not - Logical NOT
not:
pattern: console.log($ARG)
matches - Rule reuse
matches: my-utility-rule-id
Metavariables
$VAR - Single named node capture
# 有效
pattern: console.log($GREETING)
# 匹配
console.log('Hello World')
$$VAR - Single unnamed node capture
# 匹配操作符
rule:
kind: binary_expression
has:
field: operator
pattern: $$OP
$$$VAR - Multi-node capture
# 匹配零个或多个节点(非贪婪)
pattern: console.log($$$)
# 匹配可变参数
pattern: function $FUNC($$$ARGS) { $$$ }
_VAR - Non-capturing metavariable
# 不捕获,可以匹配不同内容
pattern: $_FUNC($_FUNC)
# 匹配
test(a)
testFunc(1 + 1)
Best practices for writing rules
- Always use
stopBy: end: For relational rules, ensure the search reaches the end of the direction
has:
pattern: await $EXPR
stopBy: end
- Use pattern for simple structures: Use patterns directly when the code structure is simple
pattern: console.log($ARG)
- Use rule for complex structures: Use rules to break down when the code structure is complex
rule:
kind: function_declaration
has:
pattern: await $EXPR
- Use kind for debugging: If pattern does not work, first use kind to match node types
# 先确认节点类型
kind: call_expression
# 再使用 has 或 inside
has:
pattern: console.log($ARG)
- Add stopBy when relational rules have no match: Ensure the search reaches the end
inside:
pattern: class $C { $$$ }
stopBy: end
YAML rule configuration
Simple rules
# rule.yml
id: no-console-log
language: ts
rule:
pattern: console.log($$$MSG)
Complex rules
# complex-rule.yml
id: prefer-const
language: ts
rule:
all:
- pattern: let $VAR = $INIT
- not:
pattern: $VAR = $EXPR
Rules with fixes
# fix-rule.yml
id: no-var
language: ts
rule:
pattern: var $VAR = $INIT
fix: const $VAR = $INIT
Using relational rules
# async-without-await.yml
id: async-without-await
language: ts
rule:
all:
- pattern: async function $FUNC($$$ARGS) { $$$BODY }
- not:
has:
pattern: await
stopBy: end
Common scenarios
1. Find specific code patterns
# 查找所有 console.log
ast-grep -p "console.log($$$MSG)" --lang ts
# 查找所有未使用的变量
ast-grep -p "let $VAR = $INIT" --lang ts | grep -v "$VAR ="
2. Refactor code
# 替换 var 为 const
ast-grep run -p "var $VAR = $INIT" -r "const $VAR = $INIT" --lang ts
# 重命名函数
ast-grep run -p "oldFunc($$$ARGS)" -r "newFunc($$ARGS)" --lang ts
3. Code audit
# 查找潜在的安全问题
ast-grep -p "eval($$$EXPR)" --lang js
# 查找 SQL 注入风险
ast-grep -p "query('$$SQL')" --lang py
4. API migration
# 迁移旧 API 到新 API
ast-grep run -p "oldApi($$$ARGS)" -r "newApi($$ARGS)" --lang ts
# 批量更新导入
ast-grep run -p "from 'old-lib' import $$IMPORT" -r "from 'new-lib' import $$IMPORT" --lang ts
Comparison with other tools
| Feature | ast-grep | grep | ripgrep |
|---|---|---|---|
| Syntax-aware | Yes | No | No |
| Code structure understanding | Yes | No | No |
| Cross-language support | Yes | No | No |
| Performance | Fast | Fast | Fastest |
| Rewrite functionality | Yes | No | No |
Reference resources
- Official documentation: https://ast-grep.github.io/
- GitHub: https://github.com/ast-grep/ast-grep
- Rule examples: https://ast-grep.github.io/catalog/
- Playground: https://ast-grep.github.io/playground/
- MCP server: https://github.com/ast-grep/ast-grep-mcp
Integrate with Pi workflow
Phase 1: Context retrieval
When you need to understand the code structure, use ast-grep for syntax-aware search:
# 查找特定模式
ast-grep -p "pattern" --lang <language>
Phase 4: Coding implementation
Use ast-grep for batch code transformation:
# 应用重构规则
ast-grep run -r rule.yml
Phase 5: Audit
Use ast-grep to verify code quality:
# 扫描潜在问题
ast-grep scan -r sgconfig.yml
Notes
- ast-grep needs to be installed before use
- Pattern syntax requires familiarity with AST structures
- Complex rules are recommended to be tested before applying
- It is recommended to back up code before large-scale refactoring
- Use
stopBy: endto ensure relational rule searches are complete - Metavariables must conform to syntax requirements ($VAR, $$VAR, $$$VAR)