mcpField
A
ast-grep

ast-grep

github.com/coleam00开发728225 次安装2 天前更新
代码仓库

关于 ast-grep

ast-grep Code Search 帮助开发者将自然语言搜索需求转成 ast-grep 规则,以结构方式检索代码。技能涵盖规则编写、测试、调试及使用 ast-grep 命令行搜索代码库。

主要功能

  1. 01将查询转为结构化规则
  2. 02编写简单及关联规则
  3. 03在代码片段或文件中测试规则
  4. 04检查 AST 并调试匹配
  5. 05用命令行搜索代码库

适用场景

  1. 01查找包含 await 的异步函数
  2. 02定位带指定参数的调用
  3. 03搜索缺少预期模式的代码

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/coleam00/skills --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:搜索代码库

规则正确匹配示例代码后,搜索实际代码库:

对于简单模式搜索:

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)时
使用规则搜索(扫描)

基于 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. 确保关系规则的搜索方向正确
内联规则中的转义

使用 --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