关于 ast-grep
帮助将自然语言需求转化为 ast-grep 结构化代码搜索规则的技能,适用于需要按语法结构而非文本查找代码的开发者。涵盖规则构建、测试、调试和搜索。
主要功能
- 01将需求转为 AST 搜索规则
- 02使用 pattern、kind 和关系规则
- 03组合 all、any、not 条件
- 04测试和调试规则
- 05按模式或规则扫描代码库
- 06通过 AST 检查定位匹配问题
适用场景
- 01查找缺少错误处理的异步函数
- 02定位带指定参数的函数调用
- 03搜索特定上下文中的代码结构
- 04排查规则为何没有匹配结果
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ast-grep/ agent-skill --skill ast-grep安装后在 Claude Code 中输入/ast-grep确认已加载。
附带文件references/rule_reference.md
详细介绍
ast-grep 代码搜索
概述
此技能可将自然语言查询转换为 ast-grep 规则,以进行结构化代码搜索。ast-grep 使用抽象语法树(AST)模式,根据代码结构而非单纯的文本进行匹配,从而在大型代码库中实现强大且精确的代码搜索。
何时使用此技能
在以下情况下使用此技能:
- 需要使用结构化匹配搜索代码模式(例如,“查找所有没有错误处理的异步函数”)
- 想要定位特定语言结构(例如,“查找所有带有特定参数的函数调用”)
- 请求需要理解代码结构而非单纯文本的搜索
- 要求搜索具有特定 AST 特征的代码
- 需要执行传统文本搜索无法完成的复杂代码查询
常规工作流
按照以下流程帮助用户编写有效的 ast-grep 规则:
步骤 1:理解查询
明确理解用户想要查找的内容。如有需要,请提出澄清问题:
- 他们要查找什么特定的代码模式或结构?
- 使用哪种编程语言?
- 是否需要考虑特定的边缘情况或变体?
- 匹配结果应包含或排除什么?
步骤 2:创建示例代码
编写一个简单的代码片段,表示用户想要匹配的内容。将其保存到临时文件中以便测试。
示例: 如果要搜索“使用 await 的异步函数”,请创建一个测试文件:
// test_example.js
async function example() {
const result = await fetchData();
return result;
}
步骤 3:编写 ast-grep 规则
将模式转换为 ast-grep 规则。从简单规则开始,再按需增加复杂度。
关键原则:
- 对关系规则(
inside、has)始终使用stopBy: end,以确保搜索遍历到该方向的末尾 - 对简单结构使用
pattern - 对复杂结构使用带有
has/inside的kind - 使用
all、any或not将复杂查询拆分为较小的子规则
规则文件示例(test_rule.yml):
id: async-with-await
language: javascript
rule:
kind: function_declaration
has:
pattern: await $EXPR
stopBy: end
请参阅 references/rule_reference.md,获取完整的规则文档。
步骤 4:测试规则
使用 ast-grep CLI 验证规则是否能匹配示例代码。主要有两种方法:
选项 A:使用内联规则测试(适合快速迭代)
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
选项 B:使用规则文件测试(复杂规则推荐)
ast-grep scan --rule test_rule.yml test_example.js
无匹配项时的调试方法:
- 简化规则(移除子规则)
- 如果关系规则中尚未添加
stopBy: end,则添加它 - 使用
--debug-query了解 AST 结构(见下文) - 检查
kind值是否适用于该语言 - 如果
run --pattern(而非规则)没有任何匹配项,请参阅下方的“零匹配项?”提示
步骤 5:搜索代码库
规则能够正确匹配示例代码后,即可搜索实际代码库:
搜索简单模式时:
ast-grep run --pattern 'console.log($ARG)' --lang javascript /path/to/project
搜索基于复杂规则的内容时:
ast-grep scan --rule my_rule.yml /path/to/project
使用内联规则时(不创建文件):
ast-grep scan --inline-rules "id: my-rule
language: javascript
rule:
pattern: \$PATTERN" /path/to/project
ast-grep CLI 命令
检查代码结构(--debug-query)
转储 AST 结构,以了解代码的解析方式:
ast-grep run --pattern 'async function example() { await fetch(); }' \
--lang javascript \
--debug-query=cst
可用格式:
cst:具体语法树(显示所有节点,包括标点符号)ast:抽象语法树(仅显示命名节点)pattern:显示 ast-grep 如何解析你的模式
可用于:
- 查找节点的正确
kind值 - 了解要匹配的代码结构
- 调试模式无法匹配的原因
示例:
# See the structure of your target code
ast-grep run --pattern 'class User { constructor() {} }' \
--lang javascript \
--debug-query=cst
# See how ast-grep interprets your pattern
ast-grep run --pattern 'class $NAME { $$$BODY }' \
--lang javascript \
--debug-query=pattern
测试规则(使用 --stdin 进行扫描)
针对代码片段测试规则,无需创建文件:
echo "const x = await fetch();" | ast-grep scan --inline-rules "id: test
language: javascript
rule:
pattern: await \$EXPR" --stdin
添加 --json 以获取结构化输出:
echo "const x = await fetch();" | ast-grep scan --inline-rules "..." --stdin --json
使用模式搜索(run)
基于简单模式搜索单个 AST 节点匹配项:
# 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 programmatic use
ast-grep run --pattern 'function $NAME($$$)' --lang javascript --json .
适用情况:
- 简单的单节点匹配
- 无需复杂逻辑的快速搜索
- 不需要关系规则(inside/has)时
阅读 --json 输出
--json 会输出纯 JSON 数组,不包含 matches 包装对象。对于模式 foo($ARG, $$$REST):
[{
"text": "foo(\"value\", 1, 2)",
"file": "src/app.js",
"range": { "start": { "line": 41, "column": 10 }, "end": { "line": 41, "column": 27 } },
"metaVariables": {
"single": { "ARG": { "text": "\"value\"" } },
"multi": { "REST": [ { "text": "1" }, { "text": "2" } ] }
}
}]
scan --json 使用相同的架构。
(每个匹配项还包含 lines 和 language。)range.start.line 从 0 开始计数。命名元变量($ARG)存放在 single 中,列表元变量($$$REST)以列表形式存放在 multi 中(如果没有捕获内容,则为空)。使用 jq 提取:
ast-grep run --pattern 'foo($ARG)' --lang javascript --json . \
| jq -r '.[] | "\(.file):\(.range.start.line + 1): \(.metaVariables.single.ARG.text)"'
使用规则搜索(scan)
基于 YAML 规则的搜索,适用于复杂的结构化查询:
# 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
适用场景:
- 复杂的结构化搜索
- 关系规则(inside、has、precedes、follows)
- 复合逻辑(all、any、not)
- 需要使用完整 YAML 规则的强大功能时
提示: 对于关系规则(inside/has),请始终添加 stopBy: end,以确保完整遍历。
编写有效规则的技巧
始终使用 stopBy: end
对于关系规则,除非有特定原因,否则始终使用 stopBy: end:
has:
pattern: await $EXPR
stopBy: end
这样可确保搜索遍历整个子树,而不是在遇到第一个不匹配节点时停止。
从简单开始,再增加复杂度
从可能有效的最简单规则开始:
- 先尝试
pattern - 如果不起作用,再尝试使用
kind匹配节点类型 - 根据需要添加关系规则(
has、inside) - 对于复杂逻辑,使用复合规则(
all、any、not)组合
选择合适的规则类型
- Pattern:用于简单、直接的代码匹配(例如,
console.log($ARG)) - Kind + Relational:用于复杂结构(例如,“包含 await 的函数”)
- Composite:用于逻辑组合(例如,“包含 await,但不在 try-catch 中的函数”)
通过 AST 检查进行调试
规则未能匹配时:
- 使用
--debug-query=cst查看实际的 AST 结构 - 检查元变量是否被正确检测
- 验证节点
kind是否符合预期 - 确保关系规则沿着正确的方向搜索
没有匹配项?模式匹配的是完整 AST 节点
run --pattern 匹配完整的 AST 节点,而非文本子串,因此没有匹配项可能表示“代码不存在”,也可能表示“模式的节点形状不正确”:
- 限定路径是完整节点:
env::var($ENV)不会匹配std::env::var("X")。尝试裸路径和完全限定形式,或使用$$$吸收额外的中间节点。 - 要区分两种情况:在已知包含该代码的代码片段上测试模式,并使用
--debug-query=pattern检查 ast-grep 如何解析它(run也支持此选项,不仅限于scan/规则)。如果规则没有匹配项,请按照第 4 步的调试清单排查。
内联规则中的转义
使用 --inline-rules 时,请在 shell 命令中转义元变量:
- 使用
\$VAR,而不是$VAR(shell 会将$解释为变量) - 或使用单引号:
'$VAR'在大多数 shell 中都有效
示例:
# 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)"}' .
常见用例
查找包含特定内容的函数
查找使用 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
查找特定上下文中的代码
查找类方法中的 console.log:
ast-grep scan --inline-rules "id: console-in-class
language: javascript
rule:
pattern: console.log(\$\$\$)
inside:
kind: method_definition
stopBy: end" /path/to/project
查找缺少预期模式的代码
查找没有 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
资源
references/
包含 ast-grep 规则语法的详细文档:
rule_reference.md:全面介绍 ast-grep 规则,涵盖原子规则、关系规则、复合规则和元变量
需要了解详细规则语法时,请加载这些参考资料。