Extensions register mappers, transforms, emitters, and policy schemas. They run after built-ins and follow the same deterministic phase order.
1export default (ctx) => {
2 // v0.3.1+: automatically namespaced context
3 ctx.logger.info("Setting up frontend...");
4 ctx.registerEmitter("frontend", myEmitter);
5
6 // Need to register globally?
7 ctx.root.registerTargetEmitter("frontend", "myExt:frontend");
8};Registration Surface
Extensions can register mappers (DeclBundle -> DomainIR), transforms (DomainIR -> TargetIR), emitters (TargetIR -> files), and policy schemas.
Phases and Determinism
Extensions should register hooks only. Avoid side effects at import time so execution stays deterministic and testable.
Automatic Namespacing
Since v0.3.1, the CLI automatically wraps your extension function in a namespaced context. This prevents accidental collisions between different extensions. A mapper registered as 'foo' in 'my-ext' becomes 'my-ext:foo'.
The Unified Logger
Use ctx.logger instead of console.log. It provides consistent, color-coded, and namespaced output (info, success, warn, error).
Root Access
If your extension absolutely needs to register a target globally or access core registries without a namespace prefix, use ctx.root.
CLI Usage
Load extensions with --ext in the CLI. Order matters and follows the provided list. You can point to a file path or an installed npm package.
1npx irgen --targets=frontend --ext=./ext/my-ext.ts examples/app.dsl.ts
2npx irgen --targets=frontend --ext=irgen-ext-php-shared-hosting examples/app.dsl.tsProgrammatic Usage
Extensions can also be loaded through the Codegen API for controlled integration in scripts or tests.
1import { Codegen } from "irgen";
2import myExt from "./my-ext.js";
3
4const cg = new Codegen({ extensions: [myExt] });
5await cg.generate({ entries: ["./app.dsl.ts"], targets: ["frontend"] });