Go developer tooling at Ignite: AST transformations and migration scaffolding

Ignite CLI scaffolding needed to modify Go applications as developers continued to change their code. My contributions replaced selected comment placeholders with syntax-based transformations, extended that approach to application configuration and IBC routes, and added module migration scaffolding. The work combined Go source analysis with explicit compatibility checks and tests for generated changes.

The problem: generated code keeps changing

Earlier scaffolding paths inserted code at special comments embedded in templates. In PR #4004, I removed import placeholders and replaced those insertions with xast helpers. An AST, or abstract syntax tree, represents the structure of source code. Here, that structure provided a way to modify Go imports and function calls without depending on the old import marker comments.

The important boundary was between the tool's assumptions and code a developer continues to edit. A marker-based approach is straightforward while the markers remain intact. Structural editing removes that dependency, but requires the tooling to understand supported source shapes and report failures when it cannot locate an expected declaration. The choice shifts maintenance from marker placement to source analysis; it does not make application structure irrelevant.

Imports and keeper wiring

In PR #4004, module scaffolding used xast.AppendImports to insert named imports and side-effect imports. The same change used xast.ModifyFunction to add a keeper argument to an Inject call inside the application's New function. A keeper is the module component being connected to the application's dependencies in this code. The PR updated import-helper options and their tests alongside the callers.

This was an incremental transition. Other modifications still used placeholders, including keeper declarations and some module lifecycle lists. Changing the import and Inject paths separately kept the contribution focused on particular transformations. It also left a clear compatibility boundary: removing one group of markers did not mean that every Ignite generator could already operate without them.

Application configuration and IBC routes

PR #4877 extended structural editing to application configuration and IBC route registration. The new code parsed Go files, located the application configuration, added the module to genesis and block lifecycle lists, and appended its configuration entry. For IBC routing, it found registerIBCModules, checked for an existing route and inserted the new route before the IBC v2 router assignment.

The added tests applied the transformation twice and checked that the relevant module entries or route appeared only once. That verifies the intended repeated-application behavior covered by those fixtures. It does not establish support for every hand-edited application: the implementation still searches for particular variable names, types and function structures. Structural editing costs more implementation complexity than string replacement, and compatibility remains a responsibility of the tooling.

Module migration scaffolding

PR #4902 added migration scaffolding for an existing module. The implementation read its consensus version, generated the next version's migration package, updated the module version and registered the handler. It rejected a missing module or an already existing target migration directory. Tests covered initial registration, appending a subsequent migration and supported variants of the registration signature.

The generated migration handler initially returned nil without changing state. The tool supplied registration and file structure; application-specific data migration logic remained work for the chain developer. This was an explicit boundary in the generated output: the scaffolder could inspect the module's version and connect a handler, but the resulting file still needed the state-transition logic appropriate to the application. Boilerplate generation alone cannot establish migration correctness.

Contribution scope

The three linked merged changes cover source transformations, application composition and module migration boilerplate. Together, they show developer tooling that works with existing Go code while making its assumptions visible through errors and tests. The supported syntax and generated no-op migration remain meaningful boundaries for developers extending the resulting applications.

Public sources