mcpField
A
ast-grep

ast-grep

github.com/ast-grep开发89918.1k 次安装6 周前更新
代码仓库

关于 ast-grep

帮助将自然语言需求转化为 ast-grep 结构化代码搜索规则的技能,适用于需要按语法结构而非文本查找代码的开发者。涵盖规则构建、测试、调试和搜索。

主要功能

  1. 01将需求转为 AST 搜索规则
  2. 02使用 pattern、kind 和关系规则
  3. 03组合 all、any、not 条件
  4. 04测试和调试规则
  5. 05按模式或规则扫描代码库
  6. 06通过 AST 检查定位匹配问题

适用场景

  1. 01查找缺少错误处理的异步函数
  2. 02定位带指定参数的函数调用
  3. 03搜索特定上下文中的代码结构
  4. 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

无匹配项时的调试方法:

  1. 简化规则(移除子规则)
  2. 如果关系规则中尚未添加 stopBy: end,则添加它
  3. 使用 --debug-query 了解 AST 结构(见下文)
  4. 检查 kind 值是否适用于该语言
  5. 如果 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

这样可确保搜索遍历整个子树,而不是在遇到第一个不匹配节点时停止。

从简单开始,再增加复杂度

从可能有效的最简单规则开始:

  1. 先尝试 pattern
  2. 如果不起作用,再尝试使用 kind 匹配节点类型
  3. 根据需要添加关系规则(has、inside)
  4. 对于复杂逻辑,使用复合规则(all、any、not)组合
选择合适的规则类型
  • Pattern:用于简单、直接的代码匹配(例如,console.log($ARG))
  • Kind + Relational:用于复杂结构(例如,“包含 await 的函数”)
  • Composite:用于逻辑组合(例如,“包含 await,但不在 try-catch 中的函数”)
通过 AST 检查进行调试

规则未能匹配时:

  1. 使用 --debug-query=cst 查看实际的 AST 结构
  2. 检查元变量是否被正确检测
  3. 验证节点 kind 是否符合预期
  4. 确保关系规则沿着正确的方向搜索
没有匹配项?模式匹配的是完整 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 规则,涵盖原子规则、关系规则、复合规则和元变量

需要了解详细规则语法时,请加载这些参考资料。

评论

支持 Markdown