Ferramentas Go para desenvolvedores na Ignite: AST e scaffolding de migrações

O scaffolding do Ignite CLI precisava modificar aplicações Go enquanto os desenvolvedores continuavam alterando seu código. Minhas contribuições substituíram determinados placeholders de comentários por transformações baseadas em sintaxe, estenderam essa abordagem à configuração da aplicação e às rotas IBC, e adicionaram scaffolding de migrações de módulos. O trabalho combinou análise de código Go com verificações explícitas de compatibilidade e testes das mudanças geradas.

O problema: o código gerado continua mudando

Os caminhos anteriores de scaffolding inseriam código em comentários especiais nos templates. No PR #4004, removi placeholders de imports e substituí essas inserções por helpers xast. AST, ou árvore sintática abstrata, representa a estrutura do código-fonte. Nesse caso, a estrutura permitiu modificar imports e chamadas de função Go sem depender dos antigos comentários de marcação dos imports.

A fronteira importante estava entre as suposições da ferramenta e o código que o desenvolvedor continua editando. A abordagem com marcadores é simples enquanto eles permanecem intactos. A edição estrutural elimina essa dependência, mas exige que a ferramenta entenda os formatos de código suportados e relate falhas quando não consegue localizar uma declaração esperada. A escolha desloca a manutenção da posição dos marcadores para a análise do código; não torna irrelevante a estrutura da aplicação.

Imports e composição dos keepers

No PR #4004, o scaffolding de módulos passou a usar xast.AppendImports para inserir imports nomeados e imports por efeitos colaterais. A mesma mudança usou xast.ModifyFunction para adicionar um argumento de keeper a uma chamada Inject dentro da função New da aplicação. Keeper é o componente do módulo conectado às dependências da aplicação nesse código. O PR atualizou as opções dos helpers de import e seus testes junto com os pontos de chamada.

Foi uma transição incremental. Outras modificações ainda usavam placeholders, incluindo declarações de keepers e algumas listas de ciclo de vida dos módulos. Alterar separadamente os caminhos de imports e Inject manteve a contribuição focada em transformações específicas. Isso também deixou um limite claro de compatibilidade: remover um grupo de marcadores não significava que todos os geradores Ignite já podiam operar sem eles.

Configuração da aplicação e rotas IBC

O PR #4877 estendeu a edição estrutural à configuração da aplicação e ao registro de rotas IBC. O novo código fazia o parsing de arquivos Go, localizava a configuração da aplicação, adicionava o módulo às listas de gênese e ciclo de vida dos blocos e acrescentava sua entrada de configuração. No roteamento IBC, encontrava registerIBCModules, verificava a presença de uma rota e inseria a nova rota antes da atribuição do roteador IBC v2.

Os testes adicionados aplicavam a transformação duas vezes e verificavam que as entradas relevantes do módulo ou a rota apareciam apenas uma vez. Isso verifica o comportamento pretendido de aplicação repetida coberto por essas fixtures. Não comprova suporte a toda aplicação editada manualmente: a implementação ainda busca nomes de variáveis, tipos e estruturas de funções específicos. A edição estrutural exige mais complexidade de implementação que a substituição de strings, e a compatibilidade continua sendo responsabilidade da ferramenta.

Scaffolding de migrações de módulos

O PR #4902 adicionou scaffolding de migrações para um módulo existente. A implementação lia sua versão de consenso, gerava o pacote de migração da próxima versão, atualizava a versão do módulo e registrava o handler. Ela rejeitava um módulo inexistente ou um diretório da migração de destino já existente. Os testes cobriam o registro inicial, a adição de uma migração seguinte e variantes suportadas da assinatura de registro.

O handler de migração gerado inicialmente retornava nil sem alterar o estado. A ferramenta fornecia o registro e a estrutura de arquivos; a lógica de migração dos dados da aplicação continuava sendo trabalho do desenvolvedor da chain. Esse era um limite explícito no código gerado: o scaffolder podia inspecionar a versão do módulo e conectar um handler, mas o arquivo resultante ainda precisava da lógica de transição de estado adequada à aplicação. A geração de boilerplate sozinha não comprova a correção da migração.

Escopo das contribuições

As três mudanças integradas vinculadas cobrem transformações de código, composição da aplicação e boilerplate de migrações de módulos. Juntas, mostram ferramentas que trabalham sobre código Go existente e tornam suas suposições visíveis por meio de erros e testes. A sintaxe suportada e a migração gerada sem alteração de estado continuam sendo limites relevantes para desenvolvedores que estendem as aplicações resultantes.

Fontes públicas