在代码重构和迁移的日常工作中,我们常常需要批量查找特定模式的代码——比如找到所有使用旧 API 的调用点,或者找出不符合新规范的写法。传统的文本搜索(grep)在面对复杂语法时往往力不从心,而编写完整的静态分析工具又过于笨重。

ast-grep 提供了一个优雅的中间方案。这款由 Rust 编写的 CLI 工具让你可以用「写代码的方式」来搜索代码——它基于抽象语法树(AST)进行匹配,能理解代码的语法结构而非仅仅是文本。

项目速览

属性内容
GitHubast-grep/ast-grep
⭐ Stars13.3k
🔧 语言Rust
⚡ 特点AST 结构匹配、20+ 语言支持、代码重写
📅 更新活跃开发中

核心概念

ast-grep 的核心理念很简单:用代码搜代码

传统的 grep 只能处理文本,而 ast-grep 解析代码的 AST 后进行结构匹配。你可以写一个模式代码(pattern code),ast-grep 会找到所有语法结构与之匹配的代码片段。

# 搜索所有 console.log 调用
sg --pattern 'console.log($ARGS)' --lang ts

安装

支持多种安装方式:

# npm
npm install --global @ast-grep/cli

# Homebrew
brew install ast-grep

# Cargo
cargo install ast-grep

# pip
pip install ast-grep-cli

基础用法

1. 命令行搜索

# 查找所有未使用的变量(以 _ 开头)
sg --pattern 'const $_ = $INIT' --lang ts

# 查找所有 setState 调用
sg --pattern 'setState($VALUE)' --lang ts

2. 使用规则文件

创建 .ast-grep/rules/no-console.yml

id: no-console
language: ts
rule:
  pattern: console.log($$$ARGS)
message: 请勿在生产代码中保留 console.log
severity: warning

然后运行:

sg scan

3. 代码重写

# 将所有 var 替换为 const
sg --pattern 'var $NAME = $INIT' --rewrite 'const $NAME = $INIT' --lang ts

高级特性

多语言支持

基于 tree-sitter 解析器,ast-grep 支持 20+ 编程语言:

  • JavaScript / TypeScript
  • Python
  • Rust
  • Go
  • Java
  • C / C++
  • Ruby
  • 更多…

元变量

使用 $ 开头的标识符作为通配符:

  • $MATCH - 匹配任意单个 AST 节点
  • $$$ARGS - 匹配多个节点(展开匹配)
# 匹配任意函数调用
sg --pattern '$FUNC($$$ARGS)' --lang ts

在线 Playground

ast-grep Playground 提供了实时测试环境,可以即时验证你的搜索模式:

// 输入模式
const $NAME = require('$MODULE')

// 匹配结果
const fs = require('fs')        // ✓ 匹配
const path = require('path')    // ✓ 匹配
import { readFile } from 'fs'   // ✗ 不匹配(不同的语法结构)

典型应用场景

场景示例
代码迁移批量替换弃用的 API 调用
规范检查强制团队代码风格一致性
漏洞扫描查找潜在的安全风险模式
重构辅助识别需要拆分的复杂函数
教学演示展示代码模式的分布情况

与同类工具对比

工具匹配方式重写能力易用性
grep文本有限⭐⭐⭐
ast-grepAST 结构⭐⭐⭐⭐
ESLintAST + 规则中等⭐⭐⭐
SemgrepAST 结构⭐⭐⭐⭐

相比 Semgrep,ast-grep 更轻量、启动更快;相比 ESLint,它的搜索语法更直观,无需编写复杂的访问者模式代码。

总结

ast-grep 填补了「文本搜索」和「完整静态分析」之间的空白。对于需要批量处理代码但又不想投入大量工具链建设的团队来说,它是一个高效的折中选择。

# 一句话总结
sg --pattern '旧代码模式' --rewrite '新代码模式' --lang ts

如果你经常需要处理代码迁移、规范落地或批量重构,ast-grep 值得加入你的工具箱。