O que é o AST-grep

O AST-grep e uma ferramenta de linha de comando para busca e refatoração de código baseada em AST (Abstract Syntax Tree). Em vez de buscar texto bruto com regex, ele entende a estrutura real do código-fonte, o que elimina falsos positivos e permite substituições cirúrgicas.

O projeto e open source, escrito em Rust, e usa o Tree-sitter como motor de parse. O Tree-sitter e a biblioteca que o Neovim, GitHub, VS Code e outros editores usam para colorir sintaxe e navegar em código. E rápido, incremental e suporta dezenas de linguagens.

O que o AST-grep fez de diferente foi identificar gargalos no binding original do Tree-sitter, reescrever partes críticas em Rust puro e publicar um benchmark mostrando ganho real de 30% na velocidade de parse. Para quem processa repositórios grandes ou roda o ast-grep em CI, esse ganho muda a equação.

Como funciona

O fluxo do AST-grep e simples: você escreve um padrão estrutural (não regex) que descreve como o trecho de código deve parecer. O motor parseia o arquivo inteiro para AST, percorre a árvore e retorna os nos que casam com o padrão. A busca e exata: ela entende tokens, operadores, blocos e chamadas de função como entidades separadas.

Por exemplo, para encontrar todos os console.log dentro de funções async em JavaScript, você escreve o padrão uma vez e o ast-grep varre milhares de arquivos em segundos. Sem regex que quebra no primeiro caso de uso real, sem grep que devolve comentários como resultado.

A reescrita em Rust foi focada nos bindings de linguagem e no loop de matching. O Tree-sitter original expõe uma API C; o AST-grep antes usava wrappers. A nova versão chama diretamente os parsers compilados para cada linguagem, eliminando overhead de FFI e alocações desnecessárias no caminho crítico.

💡
Dica

O AST-grep usa a sintaxe $VAR para capturar nos variáveis no padrão. Por exemplo, console.log($MSG) captura qualquer argumento passado para o log.

Principais recursos

O AST-grep vai além de uma ferramenta de busca. Os recursos mais usados incluem:

  • sg (CLI): busca em arquivos com padrão estrutural. Equivalente ao grep, mas AST-aware.
  • Refatoração: substitui padrões por novos trechos mantendo a estrutura. Útil para migrações de API.
  • Regras YAML: você define regras de lint personalizadas no formato YAML e roda como linter no CI.
  • Suporte a múltiplas linguagens: JavaScript, TypeScript, Python, Rust, Go, Java, C, C++, entre outras.
  • Modo interativo: mostra o match com contexto e pede confirmação antes de substituir.
  • API programática: disponível em Node.js e Python para quem quer integrar em ferramentas próprias.

O diferencial em relação ao grep simples e a ausência de falsos positivos. O diferencial em relação ao sed e a capacidade de entender contexto: substituir apenas dentro de funções, apenas em blocos if, ou apenas quando o argumento tem um determinado formato.

Como começar: instalação

O jeito mais rápido de instalar o AST-grep e via gerenciador de pacotes. Escolha o que funciona melhor no seu ambiente:

# macOS ou Linux via Homebrew
brew install ast-grep

# Via cargo (Rust instalado)
cargo install ast-grep

# Via npm
npm install -g @ast-grep/cli

Após instalar, confirme com sg --version. Para testar de imediato, navegue até qualquer repositório e rode uma busca inicial para verificar que tudo funciona.

# Buscar todos os console.log em arquivos JS
sg --pattern "console.log($$$)" --lang js .

# Buscar funções async em Python
sg --pattern "async def $FUNC($$$): $$$" --lang py .

Não precisa de configuração inicial. O AST-grep detecta a linguagem pelo arquivo automaticamente quando você usa --lang.

⚠️
Atenção

O suporte a algumas linguagens e mais maduro do que outras. Linguagens como JavaScript, TypeScript, Python e Rust tem parsers muito estáveis. Para linguagens menos comuns, verifique a lista de suporte na documentação oficial antes de depender em produção.

Exemplo prático: migrando de API

Suponha que você tem um projeto com centenas de chamadas para legacyFetch(url, opts) e quer migrar para apiFetch(url, opts). Com grep + sed isso seria arriscado. Com o AST-grep e direto:

# Checar quantas ocorrências existem
sg --pattern "legacyFetch($URL, $OPTS)" --lang js .

# Substituir de forma interativa
sg --pattern "legacyFetch($URL, $OPTS)" --rewrite "apiFetch($URL, $OPTS)" --lang js . --interactive

# Substituir todos de uma vez
sg --pattern "legacyFetch($URL, $OPTS)" --rewrite "apiFetch($URL, $OPTS)" --lang js . --update-all

O AST-grep preserva a formatação original do código. Ele não reformata, não muda indentação, não toca em nada fora do padrão. Isso facilita o code review: o diff mostra exatamente o que mudou, nada mais.

Para projetos com TypeScript, adicione --lang ts ou use um arquivo de configuração sgconfig.yml que lista as linguagens e pastas a varrer automaticamente.

Comparação com alternativas

As alternativas mais usadas no mesmo espaço são grep/ripgrep, comby, semgrep e jscodeshift. Cada um tem seu nicho:

  • grep/ripgrep: o mais rápido para texto bruto. Mas regex em código quebra com multilinhas e comentários. Não entende AST.
  • comby: busca estrutural sem AST real. Funciona bem para templates simples, mas não tem semântica de linguagem.
  • semgrep: também AST-based, muito popular em segurança (SAST). Mais lento e tem plano pago para uso comercial amplo.
  • jscodeshift: poderoso para JS/TS, mas exige escrever codemods em JavaScript. Curva de aprendizado maior.

O AST-grep se posiciona como o ripgrep do mundo estrutural: rápido, simples de usar no terminal e open source sem restrições. Para auditorias de segurança avançadas, o semgrep ainda tem mais regras prontas. Para o dia a dia do dev que quer buscar e refatorar rápido, o ast-grep ganha.

🚀
Pro tip

Combine o AST-grep com o pre-commit ou hooks de git para bloquear padrões problemáticos antes do commit. Defina suas regras em YAML e adicione ao pipeline de lint do projeto.

Pontos positivos e limitações

Pontos positivos:

  • Extremamente rápido, especialmente após a reescrita em Rust
  • Zero falsos positivos para padrões bem definidos
  • Sintaxe de padrão simples, aprende em minutos
  • CLI, API Node.js e API Python disponíveis
  • Open source com licença MIT

Limitações reais:

  • Padrões muito complexos podem ser difíceis de expressar
  • Não entende semântica de tipos como um compilador
  • Documentação de regras YAML ainda e menos madura que a CLI
  • Suporte a linguagens menos comuns inexistente ou experimental

Para a grande maioria dos casos de uso de um time de desenvolvimento web ou backend, essas limitações não vao aparecer no dia a dia.

Casos de uso reais

Quatro perfis que tiram valor real do AST-grep hoje:

  • Dev em migração de dependência: troca todas as chamadas de uma biblioteca antiga pela nova sem revisar arquivo por arquivo. O --rewrite faz o trabalho bruto; o dev revisa o diff.
  • Tech lead fazendo code review em escala: cria regras YAML que proíbem padrões problemáticos e roda no CI. Qualquer PR que violar e bloqueado automaticamente.
  • Engenheiro de segurança: varre repositórios buscando padrões de vulnerabilidade conhecidos antes de uma auditoria.
  • Dev de tooling interno: usa a API Python ou Node.js para construir codemods que transformam código legado seguindo convenções novas do time.

Dicas e boas práticas

💡
Dica

Use $$$ (três cifraos) para capturar zero ou mais nos. E diferente de $VAR que captura exatamente um no. Para argumentos variadicos de função, sempre prefira $$$ARGS.

💡
Dica

Comece testando seu padrão sem o --rewrite. Veja o que casou antes de substituir qualquer coisa.

🔴
Cuidado

O flag --update-all reescreve arquivos sem confirmação. Sempre commite ou stash suas mudanças antes de rodar uma substituição em massa.

🚀
Pro tip

Crie um arquivo sgconfig.yml na raiz do projeto com as linguagens, pastas incluídas/excluídas e regras de lint. Assim qualquer membro do time roda sg scan e obtem os mesmos resultados sem flags manuais.

Vale a pena?

Para qualquer dev que já perdeu tempo com grep que retorna comentários como resultado, ou com sed que quebra em multilinhas, a resposta e sim. O AST-grep resolve exatamente esse problema com uma curva de aprendizado de menos de uma hora.

Se você trabalha em repositórios grandes, com migrations frequentes de API, ou quer adicionar lint personalizado ao CI sem pagar por uma solução enterprise, o ast-grep e a escolha mais prática disponível hoje. A reescrita em Rust que trouxe 30% de ganho de velocidade e um bom sinal de que o projeto tem compromisso com qualidade técnica de longo prazo.

O próximo passo e instalar (brew install ast-grep ou cargo install ast-grep), abrir um repositório e rodar a primeira busca. A documentação oficial em ast-grep.GitHub.io tem exemplos por linguagem que funcionam como ponto de partida.