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.ts

Programmatic 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"] });