🎯 模式语法 >>>
ast-grep 使用模式代码构建 AST 树并匹配目标代码
模式匹配
a + 1
可匹配嵌套表达式:const b = a + 1、funcCall(a + 1)、deeplyNested({ target: a + 1 })
元变量
$META_VARIABLE
以 $ 开头,后跟大写字母 A-Z、下划线 _ 或数字 1-9,匹配单个 AST 节点
有效元变量
$META, $META_VAR, $META_VAR1, $_, $_123
无效元变量
$invalid, $Svalue, $123, $KEBAB-CASE, $
🔤 多元变量 >>>
使用 $$$ 匹配零个或多个 AST 节点
函数参数
console.log($$$ARGS)
console.log() // 匹配零个节点
console.log('hello world') // 匹配一个节点
console.log('debug: ', key, value) // 匹配多个节点
console.log(...args) // 匹配展开运算符
函数参数
function $FUNC($$$ARGS) { $$$ }
function foo(bar) { return bar }
function noop() {}
function add(a, b, c) { return a + b + c }
🎯 元变量捕获 >>>
相同名称的元变量匹配相同内容
捕获示例
$A == $A
// 匹配这些
a == a
1 + 1 == 1 + 1
// 不匹配这些
a == b
1 + 1 == 2
非捕获匹配
$_FUNC($_FUNC)
以下划线开头的元变量不会被捕获,可优化匹配速度
⚛️ 原子规则 >>>
定义最基本的匹配规则,确定语法节点是否匹配
pattern
rule:
pattern: console.log($GREETING)
根据模式语法匹配单个语法节点
Pattern Object
pattern:
selector: field_definition
context: class A { $FIELD = $INIT }
使用对象指定在更大上下文中的子语法节点
strictness
pattern:
strictness: cst # cst, smart, ast, relaxed, signature
控制模式匹配策略:cst(最严格)、smart(默认)、ast、relaxed、signature(最宽松)
🏷️ kind 规则 >>>
指定 tree-sitter 解析器定义的 AST 节点类型
基本用法
rule:
kind: field_definition
class Test {
a = 123 // 匹配此行
}
常用 kind 名称
kind: if_statement
kind: expression
kind: function_declaration
kind: class_declaration
可在 ast-grep playground 中查看完整的 kind 名称
🔍 regex 规则 >>>
使用正则表达式匹配节点文本内容
基本用法
rule:
regex: 'prototype'
匹配文本内容包含 'prototype' 的节点
组合使用
rule:
kind: pair
has:
field: key
regex: 'prototype'
var a = {
prototype: anotherObject // 匹配
}
🔢 nthChild 规则 >>>
匹配第 N 个子节点
基本用法
rule:
pattern: $A
nthChild:
position: 1
of: expression_statement
匹配作为 expression_statement 第一个子节点的节点
位置选项
nthChild:
position: 0 # 第一个子节点(从0开始)
of: statement_list
📏 range 规则 >>>
匹配特定行范围内的节点
基本用法
rule:
pattern: $A
range:
start: 10
end: 20
匹配位于第 10 到 20 行之间的节点
仅开始行
rule:
range:
start: 100
匹配从第 100 行开始的所有节点
🔗 关系规则 >>>
基于周围节点过滤目标节点
inside - 在...内部
rule:
pattern: await $PROMISE
inside:
kind: for_in_statement
stopBy: end
匹配在 for_in_statement 内部的 await 表达式
has - 包含
rule:
kind: pair
has:
field: key
regex: 'prototype'
匹配包含特定 key 的 pair 节点
➡️ follows & precedes >>>
基于节点位置关系进行匹配
follows - 跟随
pattern: console.log('hello');
follows:
pattern: console.log('world');
console.log('hello'); // 不匹配
console.log('world');
console.log('hello'); // 匹配!!
precedes - 前置
pattern: console.log('world');
precedes:
pattern: console.log('hello');
匹配在特定节点之前的节点
🛑 stopBy 选项 >>>
控制关系规则的搜索范围
stopBy: end
has:
stopBy: end
pattern: $MY_PATTERN
搜索直到到达根节点、叶节点或首尾兄弟节点
stopBy: neighbor (默认)
has:
stopBy: neighbor
pattern: $MY_PATTERN
仅匹配直接子节点
stopBy: 自定义规则
inside:
stopBy:
kind: function
pattern: function test($$$) { $$$ }
当遇到 function 节点时停止搜索
🔀 组合规则 >>>
使用逻辑运算符组合多个规则
any - 任意匹配
rule:
pattern: await $PROMISE
inside:
any:
- kind: for_in_statement
- kind: for_statement
- kind: while_statement
- kind: do_statement
匹配在任意一种循环内部的 await 表达式
all - 全部匹配
rule:
all:
- pattern: console.log($$$)
- inside:
kind: function_declaration
同时满足所有条件的节点
❌ not 规则 >>>
排除匹配特定规则的节点
基本用法
rule:
pattern: console.log($$$)
not:
inside:
kind: function_declaration
匹配不在函数声明内部的 console.log
组合使用
rule:
any:
- pattern: console.log($$$)
- pattern: console.error($$$)
not:
inside:
kind: test_block
匹配 console.log 或 console.error,但不在测试块中
🎯 matches 规则 >>>
使用外部规则匹配节点
基本用法
rule:
matches: my-rule-id
匹配由 my-rule-id 定义的规则
组合使用
rule:
any:
- matches: console-rule
- matches: debug-rule
not:
inside:
kind: test_block
复用已定义的规则进行组合匹配
🔧 实用规则 >>>
提供额外的实用功能
inside - 在...内部
rule:
pattern: $A
inside:
pattern: function test($$$) { $$$ }
stopBy:
kind: function
查找在名为 test 的函数内部的节点
has - 包含
rule:
kind: object
has:
kind: pair
field: key
regex: 'dangerous'
匹配包含特定键值对的对象
📝 编写规则技巧 >>>
编写高效准确的 ast-grep 规则的最佳实践
使用 pattern 对象解决歧义
pattern:
selector: field_definition
context: class A { $FIELD = $INIT }
当简单字符串模式无法解析时,提供上下文帮助解析器
选择合适的 strictness
pattern:
strictness: smart # 默认,跳过未命名节点
# strictness: cst # 最严格,匹配所有节点
# strictness: ast # 仅匹配命名节点
# strictness: relaxed # 忽略注释和未命名节点
# strictness: signature # 仅匹配节点类型
根据需求选择严格度级别
🎨 field 选项 >>>
指定节点的特定字段进行匹配
指定字段
kind: pair
has:
field: key
regex: 'prototype'
var a = {
prototype: anotherObject // 匹配
}
var a = {
normalKey: prototype // 不匹配
}
确保匹配特定字段的值,而非任意子节点
💡 高级用法 >>>
ast-grep 的高级功能和技巧
嵌套关系规则
rule:
pattern: await $PROMISE
inside:
any:
- kind: for_in_statement
- kind: for_statement
not:
kind: try_statement
组合多个关系规则进行精确匹配
元变量在 fix 中使用
rule:
pattern: console.log($MSG)
fix: logger.info($MSG)
关系规则中捕获的元变量可在 fix 中使用