mcpField
A
ast-grep

ast-grep

github.com/code-yeongyu开发859 次安装21 周前更新
代码仓库

关于 ast-grep

ast-grep 是一项使用 AST 感知型搜索与改写工具的技能,支持 25 种语言。它面向需要按代码结构查找和转换代码的编码 Agent,并提供 Python 辅助脚本来验证模式、预览改动和执行编辑。

主要功能

  1. 01基于 AST 搜索与改写
  2. 02通过 Python 脚本搜索和替换
  3. 03离线验证匹配模式
  4. 04应用编辑前预览改动
  5. 05扫描 YAML 规则并自动修复
  6. 06列出语言并诊断二进制文件

适用场景

  1. 01按代码结构查找调用、函数或导入
  2. 02在仓库文件中执行代码迁移
  3. 03依据 YAML lint 规则检查代码
  4. 04搜索前验证匹配模式

安装

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

$npx skills add https://github.com/code-yeongyu/ast-grep-skill --skill ast-grep

安装后在 Claude Code 中输入/ast-grep确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

.gitignore
LICENSE
install.ps1
README.md
install.sh
.github/workflows/
ci.yml
references/
patterns.md
install.md
cli.md
pitfalls.md
recipes.md
sgconfig.md
yaml-rules.md
scripts/
ast_grep_helper.py
tests/
smoke.sh
smoke.ps1

详细介绍

ast-grep

sg(也以 ast-grep 的名称安装)是一款支持 25 种语言的 AST 感知型搜索和重写工具。它会将你的模式视为代码,以解析项目的相同方式解析该模式,并进行结构化匹配。当你的问题取决于 代码结构 而非文本字节时,它就是合适的工具。

此技能提供了一个 Python 包装脚本 scripts/ast_grep_helper.py,以及平台安装脚本 install.sh(POSIX)和 install.ps1(Windows)。该助手增加了离线模式验证、两遍写入技巧和二进制文件自动解析功能。请将其作为默认入口。


何时使用此技能

当用户的问题涉及 代码结构 而非字节时,请使用它:

  • “找出所有接受 Request 参数的函数。”
  • “将所有 console.log(x) 重写为 logger.info(x)。”
  • “删除所有 as any 类型断言。”
  • “在整个代码库中将 require(...) 替换为 import。”
  • “找出空的 catch 块。”
  • “将 Optional[X] 迁移为 X | None。”
  • “在这 200 个文件中应用此代码转换。”
  • “运行我们的 YAML lint 规则并列出违规项。”

如果问题以文本为中心(字符串字面量内容、注释、许可证头、文件名、跨语言正则表达式),请改用普通的 grep / rg。拿不准时,问问自己:“答案取决于该语言的语法树,还是只取决于文件的字节?”前者用 ast-grep,后者用 grep。


Agent 必须牢记的三件事

1. ast-grep 不是正则表达式

通配符是 $VAR(一个 AST 节点)和 $$$(零个或多个节点)。正则表达式语法会静默失效:

你写的内容ast-grep 的解析结果你的预期
foo|barfoo 和 bar 的按位或分别运行两次搜索
.*foo无法解析$$$ foo(如果 $$$ 是节点列表)或使用 rg
\w+无法解析使用 $VAR 捕获任意标识符
[a-z]字符类,无法解析改用 rg

完整的反模式表见 references/pitfalls.md §1。助手的 validate 子命令可以机械地检测这些问题——在手动排查“无匹配项”之前先运行它。

2. 模式必须是有效代码

模式本身必须能够解析。def $FN($$$): 会失败,因为末尾的 : 使其不完整;请使用 def $FN($$$)。不带参数或函数体的 function $NAME 会失败;请使用 function $NAME($$$) { $$$ }。各语言的完整对照表见 references/pitfalls.md §2。

3. --update-all 和 --json 不能同时使用(但不会报错)

这是编写脚本时最大的陷阱。sg run -p P -r R --json --update-all 会返回 JSON,但 不会修改文件。若要同时预览和应用更改,请分两遍运行:

sg run -p P -r R --json=compact .   # pass 1: see what would change
sg run -p P -r R --update-all .     # pass 2: actually apply

调用 replace --apply 时,助手会自动完成此操作。请阅读 references/pitfalls.md §9。


助手脚本——scripts/ast_grep_helper.py

一个单文件 Python 3 标准库包装脚本。在所有操作系统上用法相同。它是 Agent 的默认入口。

search——查找模式的所有匹配项
python3 scripts/ast_grep_helper.py search 'console.log($MSG)' --lang ts src/

首先离线验证模式。如果模式看起来像正则表达式(\w、.*、| 等),助手会退出并给出提示,不会调用 sg——省去一次往返。传入 --force 可跳过验证。

选项:

  • --lang ts(或 25 种语言中的任意一种;接受 js、py、rs、kt 等别名)
  • --globs '!**/*.test.ts'(可重复使用;添加前缀 ! 以排除)
  • -C 3(上下文行数)
  • --json-out(输出原始 JSON,而非人类可读格式)
replace——按模式重写,默认试运行
# Dry-run preview (default — no files mutated)
python3 scripts/ast_grep_helper.py replace 'console.log($MSG)' 'logger.info($MSG)' --lang ts src/

# Actually apply
python3 scripts/ast_grep_helper.py replace 'console.log($MSG)' 'logger.info($MSG)' --lang ts src/ --apply

助手会:

  1. 验证 pattern 和 rewrite 中是否存在可通过提示检测到的错误。
  2. 使用 --json=compact 运行第一遍,收集匹配项并显示预览。
  3. 如果设置了 --apply,则使用 --update-all 运行第二遍,修改文件。
scan——运行 YAML 规则
# Discover sgconfig.yml from cwd and run all rules
python3 scripts/ast_grep_helper.py scan src/

# Run a single rule file
python3 scripts/ast_grep_helper.py scan -r rules/no-console.yml src/

# Apply auto-fixes
python3 scripts/ast_grep_helper.py scan -U src/

# CI-friendly GitHub annotations
python3 scripts/ast_grep_helper.py scan --report-style short src/
validate——离线检查模式(不调用 sg)

适用于 CI lint、提交前钩子和快速检查:

python3 scripts/ast_grep_helper.py validate '\w+' --lang ts
# → exit 2: regex \w not supported. Use $VAR for identifiers.

python3 scripts/ast_grep_helper.py validate 'console.log($MSG)' --lang ts
# → exit 0: pattern looks plausible for ast-grep.
langs / doctor / install
python3 scripts/ast_grep_helper.py langs       # list 25 supported languages and aliases
python3 scripts/ast_grep_helper.py doctor      # check ast-grep binary availability
python3 scripts/ast_grep_helper.py install     # delegate to install.sh / install.ps1

new 和 test 子命令会直接转发给 sg new 和 sg test。


直接使用 sg(当辅助工具不够用时)

这个辅助工具有自己的使用倾向。若要完全掌控,请改用 sg。该技能随附了一份 CLI 速查表,位于 references/cli.md。基本用法:

# Search
sg run -p 'console.log($MSG)' --lang ts src/

# Search with JSON for scripting
sg run -p 'console.log($MSG)' --lang ts --json=compact src/ | jq '.[] | .file'

# Rewrite, dry-run
sg run -p 'console.log($MSG)' -r 'logger.info($MSG)' --lang ts --json=compact src/

# Rewrite, apply
sg run -p 'console.log($MSG)' -r 'logger.info($MSG)' --lang ts --update-all src/

# Pattern from stdin (great for ad-hoc experiments)
echo 'console.log("hi")' | sg run -p 'console.log($MSG)' --lang js --stdin

# Debug a pattern that returns 0 matches
sg run -p '<your pattern>' --lang <lang> --debug-query=ast --stdin <<< '<sample-code>'

# Run YAML rules
sg scan src/

# Inline YAML rule (one-off)
sg scan --inline-rules '
id: no-todo
language: TypeScript
severity: warning
rule: { pattern: TODO }' src/

在 shell 中直接使用 sg 时,务必用单引号括住模式,以免 shell 展开 $VAR。


决策树——何时使用什么

USER asks for "find/rewrite/codemod"
│
├─ structural pattern (function shape, call, class, import, control flow)
│  └→ ast-grep (this skill)
│
├─ text pattern (regex, alternation, character classes, file names)
│  └→ rg / grep
│
├─ semantic question (what variable does this refer to? does this throw?)
│  └→ LSP tools, TypeScript compiler, Pyright, Semgrep with type inference
│
└─ multiple repos / federated search
   └→ a search engine + then ast-grep / rg / LSP per-repo

如果用户说“查找所有”或“每个”,当目标具有结构特征(函数、类、调用、导入、语句)时,默认使用 ast-grep。当目标是文本(字符串内容、注释、许可证标头、文件名、标识符子串)时,默认使用 rg。


重写时务必先运行 dry-run

错误的模式可能会悄无声息地重写错误内容。因此,辅助工具的 replace 默认采用 dry-run。流程如下:

  1. 搜索以确认匹配项:helper search '<pattern>' --lang X .
  2. 以 dry-run 方式重写:helper replace '<pattern>' '<rewrite>' --lang X .(不加 --apply)
  3. 检查 dry-run 摘要:匹配项数量、受影响的文件,以及各位置的预览。
  4. 如果不正确:优化模式,返回第 1 步。
  5. 如果正确:helper replace '<pattern>' '<rewrite>' --lang X . --apply。

绝不要应用未经 dry-run 的重写。


当 sg 返回 0 个匹配项,但你确定代码确实存在时

按优先顺序:

  1. 运行 helper validate '<pattern>' --lang <lang>——检查正则用法错误、缺少函数体以及 Python 末尾冒号问题。
  2. 检查 --lang——sg 会根据扩展名推断语言;如果传入 .tsx 文件却使用 --lang ts(而不是 tsx),JSX 将无法解析。
  3. 检查解析后的模式:sg run -p '<pattern>' --lang <lang> --debug-query=ast --stdin <<< '<sample>'。如果显示 ERROR 节点,说明模式格式有误。
  4. 检查目标文件的 AST:sg run -p '$_' --lang <lang> --debug-query=cst path/to/file | head -40——找到你试图匹配的 kind。
  5. 试试交互式演练场:https://ast-grep.github.io/playground.html——粘贴代码和模式,查看具体情况。

不要盲目尝试各种变体。每次失败都有原因;应将其找出来。


何时使用 YAML 规则,何时使用内联 -p 模式

以下情况使用内联 -p:

  • 一次性临时查询。
  • 模式简单(没有约束条件或修复模板)。
  • 正在探索。

以下情况使用 YAML 规则(放在 rules/ 下的文件,通过 sg scan 运行):

  • 模式会重复使用(lint 规则、在 CI 中运行的 codemod)。
  • 需要使用 constraints、transform、复杂的 inside/has 或组合逻辑。
  • 需要自动修复(fix: 字段)。
  • 需要测试规则(通过 sg test 进行快照测试)。

完整的 YAML 规则架构见 references/yaml-rules.md。项目配置(sgconfig.yml、ruleDirs、utilDirs)见 references/sgconfig.md。


输出规范

  • sg run --json=compact 会生成匹配对象数组:{ file, range: {start, end}, text, replacement?, lines, language, ... }。可通过管道传给 jq 进行后续处理。
  • 不使用 --json 时,sg 会输出适合在终端查看、带颜色且易于阅读的内容。
  • 辅助工具默认输出易于阅读的内容(文件:行:列 + 匹配预览)。传入 --json-out 可获取原始 JSON。
  • 辅助工具的 replace 始终会生成摘要:匹配项数量、文件数量以及各位置的预览。

向用户总结时,务必注明受影响的文件数量,不能只说匹配项数量。用户关心影响范围。

必读内容(按优先级排序)

  1. references/patterns.md — 元变量、命名规则、严格程度级别。不确定模式为何无法匹配时阅读。
  2. references/pitfalls.md — 失败模式指南。对 0 个匹配结果感到意外时阅读。
  3. references/recipes.md — 按语言分类的可复制粘贴模式。开始新任务时先阅读。
  4. references/cli.md — sg run、sg scan、sg test、sg new、sg lsp。辅助工具不够用时阅读。
  5. references/yaml-rules.md — YAML 规则架构。内联模式无法满足需求时阅读。
  6. references/sgconfig.md — 项目级配置。为真实项目设置 sg scan 时阅读。
  7. references/install.md — 各操作系统的安装方法。仅在 install.sh / install.ps1 失败时阅读。

不变量(不得违反)

  • 搜索前先验证。 通过程序生成模式时,先调用 helper validate。它能捕获正则误用这一类错误,而这类错误约占“0 个匹配结果”调试会话的 70%。
  • 应用前先试运行。 未先检查匹配结果时,绝不要运行 sg run -r ... --update-all。辅助工具的 replace 默认会强制执行此操作。
  • 分两次写入。 直接使用 sg 预览并应用时,分两次调用——--json 会忽略 --update-all。
  • 在 Shell 中对模式使用单引号。 使用 '$VAR',而不是 "$VAR"。Shell 会将双引号中的 $VAR 展开为空字符串,从而破坏模式。
  • 模式是代码,不是正则表达式。 如果模式需要 |、.*、\w 或 [a-z],请改用 rg。不要试图强行让 ast-grep 采用正则表达式的形式。
  • 从标准输入读取时必须指定 --lang。 使用 --stdin 进行管道传输时,请明确设置 --lang;sg 无法根据扩展名推断语言。
  • Linux:优先使用 ast-grep 而非 sg,因为 sg 与 setgroups 冲突。辅助工具会处理此问题;如果直接调用 sg,请为其设置别名:alias sg=ast-grep。

评论

支持 Markdown