# @getforma/compiler

The native compiler's esbuild plugin, diagnostics, declared schemas and FMIR utilities.

This package runs in a Node build toolchain. formaSsrPlugin compiles the admitted native subset; it does not execute arbitrary JavaScript inside Rust. Read the compiler guide before using its lower-level FMIR building blocks.

Published declaration: [@getforma/compiler@3.0.0](https://unpkg.com/@getforma/compiler@3.0.0/dist/index.d.ts).

## Values and functions

### baseWriterVersion

Function export

```ts
declare function baseWriterVersion(version: string): WriterVersion;
```



Related declarations: [`WriterVersion`](/docs/3.0/api-compiler/#symbol-WriterVersion)

### collectDiagnostics

Function export

```ts
declare function collectDiagnostics<T>(fn: () => T): {
    result: T;
    diagnostics: Diagnostic[];
};
```

Run `fn` and return what it returns together with every diagnostic reported
while it ran. Synchronous only: the compiler's walk is, and a module-level
stack is what lets the signal pass, the analyzer and the walker report into
one list without threading a sink through every signature. A report goes to
every open collection, so a nested one sees its own part and the outer one
sees everything.

Reports still print their line as at compiler 0.3.6; collecting adds to it.

Related declarations: [`Diagnostic`](/docs/3.0/api-compiler/#symbol-Diagnostic)

### COMPILER_WRITER_VERSION

Value export

```ts
declare const COMPILER_WRITER_VERSION: WriterVersion;
```



Related declarations: [`WriterVersion`](/docs/3.0/api-compiler/#symbol-WriterVersion)

### crc32

Function export

```ts
declare function crc32(...chunks: readonly Uint8Array[]): number;
```

CRC-32/ISO-HDLC, streaming chunks without inserting boundary or skipped bytes.

### DIAGNOSTIC_CATALOGUE

Value export

```ts
declare const DIAGNOSTIC_CATALOGUE: readonly DiagnosticEntry[];
```

Every code the compiler and the build can report, by family. The order is
the documentation's order.

Related declarations: [`DiagnosticEntry`](/docs/3.0/api-compiler/#symbol-DiagnosticEntry)

### diagnosticEntry

Function export

```ts
declare function diagnosticEntry(code: string): DiagnosticEntry;
```

The catalogue entry for a code. Throws on a code the catalogue lacks.

Related declarations: [`DiagnosticEntry`](/docs/3.0/api-compiler/#symbol-DiagnosticEntry)

### dumpFmir

Function export

```ts
declare function dumpFmir(bytes: Uint8Array): string;
```

Stable lossless representation shared with forma-ir::dump_ir.

### encodeFmirSections

Function export

```ts
declare function encodeFmirSections(sections: readonly FmirSection[], writer?: WriterVersion): Uint8Array;
```

Pack sections in canonical ascending order; flags and unknown payloads are preserved.

Related declarations: [`FmirSection`](/docs/3.0/api-compiler/#symbol-FmirSection), [`WriterVersion`](/docs/3.0/api-compiler/#symbol-WriterVersion)

### FmirContainerError

Class export

```ts
declare class FmirContainerError extends Error {
    readonly code: string;
    constructor(code: string, message: string);
}
```



### formaSsrPlugin

Function export

```ts
declare function formaSsrPlugin(options: SsrPluginOptions): Plugin;
```

Compile a paired browser/native product. Requires esbuild write:false: the
caller publishes outputFiles only after the complete build succeeds.

Related declarations: [`Plugin`](https://unpkg.com/esbuild@0.28.2/lib/main.d.ts#L300) (from `esbuild`; installed declarations `0.28.2`), [`SsrPluginOptions`](/docs/3.0/api-compiler/#symbol-SsrPluginOptions)

### formatDiagnostic

Function export

```ts
declare function formatDiagnostic(d: Diagnostic): string;
```

One diagnostic as a block of text for a failing `--strict` build:
`file:line:column  CODE  message`, then its why and fix.

Related declarations: [`Diagnostic`](/docs/3.0/api-compiler/#symbol-Diagnostic)

### generateRealIr

Function export

```ts
declare function generateRealIr(entryPointPath: string): IrResult | null;
```

Generate real IR by parsing the entry point, resolving the component,
extracting its h() tree, and walking it to produce FMIR binary.

Returns the FMIR binary and island info, or null if any step fails (publication is refused).

Related declarations: [`IrResult`](/docs/3.0/api-compiler/#symbol-IrResult)

### getSsrEntryProducts

Function export

```ts
declare function getSsrEntryProducts(result: BuildResult): readonly SsrEntryProduct[];
```

Read this exact successful esbuild result's compiler products. Call after
`await build()`/`rebuild()`, or from the caller's final guarded onEnd publisher.
An earlier onEnd callback is not a successful publication boundary: later
plugins may still refuse the build. No callback or mutable onStart state is
exposed. The caller commits these records with its output graph/manifest.

Browser-only builds have no native products. Callers must independently match
every configured SSR entry; absence must never imply static or Browser mode.

Related declarations: [`BuildResult`](https://unpkg.com/esbuild@0.28.2/lib/main.d.ts#L226) (from `esbuild`; installed declarations `0.28.2`), [`SsrEntryProduct`](/docs/3.0/api-compiler/#symbol-SsrEntryProduct)

### IrEmitContext

Class export

```ts
declare class IrEmitContext {
    stringIndex(value: string): number | undefined;
    setPropsSchema(schema: PropsSchema): void;
    getPropsSchema(): PropsSchema;
    appendPropsSchema(schema: PropsSchema): number;
    setIslandContract(islandId: number, mode: IslandRenderMode, bindings: readonly BindingRecord[]): void;
    addKeyPath(listOffset: number, segments: readonly string[]): void;
    setSourcePositions(positions: readonly SourcePosition[]): void;
    setIslandSchemaObject(islandId: number, schemaObject: number): void;
    dump(): string;
    addString(s: string): number;
    addSlot(name: string, typeHint: number, source?: number, defaultBytes?: Uint8Array, reference?: boolean): number;
    addTemporarySlot(typeHint: number): number;
    addConstantSlot(value: unknown, typeHint: number): number;
    constantSlot(id: number): {
        value: unknown;
    } | undefined;
    recordClosedProjection(source: number, key: string, target: number): void;
    beginSlotCapture(): void;
    endSlotCapture(): number[];
    recordSlotRef(id: number): void;
    setIslandSlotIds(islandId: number, slotIds: number[]): void;
    nextMarker(): number;
    peekNextIslandId(): number;
    addIsland(name: string, trigger: number, slotIds: number[], byteOffset: number, schemaObject?: number): number;
    emit(byte: number): void;
    emitU16(val: number): void;
    emitU32(val: number): void;
    opcodeLen(): number;
    patchU32(pos: number, val: number): void;
    toBinary(): Uint8Array;
    getIslands(): Array<{
        id: number;
        name: string;
        trigger: number;
        slotIds: number[];
        contract?: {
            mode: IslandRenderMode;
            digest: string;
            schema: CanonicalSchema;
        };
    }>;
}
```

Forma Compiler - FMIR Binary Buffer

IrEmitContext accumulates FMIR v3 bytecode, strings, slots, islands,
props schema and optional key paths/source positions — and serializes them into the binary format the
Rust-side walker reads to produce HTML.

It is a buffer, not a compiler: the AST → opcode translation lives entirely
in ir-walk.ts (walkHTree / walkCallExpression), which is what the SSR plugin
drives. Only Static and Dynamic subtrees reach the bytecode — Island
subtrees stay as client-side JS behind ISLAND_START/ISLAND_END markers.

Related declarations: [`BindingRecord`](/docs/3.0/api-compiler/#type-BindingRecord), [`CanonicalSchema`](/docs/3.0/api-compiler/#type-CanonicalSchema), [`IslandRenderMode`](/docs/3.0/api-compiler/#type-IslandRenderMode), [`PropsSchema`](/docs/3.0/api-compiler/#symbol-PropsSchema), [`SourcePosition`](/docs/3.0/api-compiler/#symbol-SourcePosition)

**`stringIndex`**

Look up an already-emitted name without interning new bytes.

**`setPropsSchema`**

Declared page object zero and its nested object types.

**`appendPropsSchema`**

Append a declared component schema without changing the page's root object.

**`setIslandContract`**

Metadata belongs to one declared component, while input slots belong to its call.

**`addKeyPath`**

FORMA-181 may attach a path without changing LIST operands.

**`setSourcePositions`**

Optional diagnostics, using 1-based UTF-16 columns.

**`dump`**

Lossless canonical diagnostic dump, shared with forma-ir.

**`addString`**

Intern a string, return its index. Deduplicates.

**`addSlot`**

Register a new slot, return its id.

`reference` says whether creating the slot also counts as USING it inside
the island subtree currently being captured. It is true for every slot
minted because an opcode needs one, and false for a slot merely DECLARED —
a signal the walk found in scope but that no binding on the page reads.
Capture bookkeeping supports the bytecode walk only. Island input lists
are independently constructed from ordered declared fields; local signals
and captured defaults never enter the state envelope as handler props.
Verified by: packages/compiler/tests/island-registry.test.ts > "local signal defaults and list scratch values stay outside declared inputs"

**`addTemporarySlot`**

A private projection/list scratch slot. Its label has no binding semantics.

**`addConstantSlot`**

Explicit closed constants distinguish empty text from an absent legacy default.

**`constantSlot`**

Closed provenance is distinct from a schema hint, including literal null.

**`recordClosedProjection`**

Compiler-known PROP result; still independently validated by native flow.

**`beginSlotCapture`**

Begin capturing slot ids referenced while walking an island subtree.

**`endSlotCapture`**

End the innermost capture; returns the captured slot ids sorted ascending.

**`recordSlotRef`**

Record a slot-id reference into every active capture set.
Called by addSlot for slots minted because an opcode needs them; call it
directly when an opcode reuses a pre-existing slot (an in-scope signal, a
list item binding) without addSlot.

**`setIslandSlotIds`**

Ordered declared inputs may repeat a slot, including a current LIST row.
The native walker snapshots them at ISLAND_START before the row advances.

**`nextMarker`**

Get a fresh marker id for DYN_TEXT.

**`peekNextIslandId`**

Peek at the next island id without incrementing the counter.

**`addIsland`**

Register a new island entry.

**`emit`**

Emit a raw byte.

**`emitU16`**

Emit u16 little-endian.

**`emitU32`**

Emit u32 little-endian.

**`opcodeLen`**

Get current opcode buffer length (for offset calculations).

**`patchU32`**

Patch a u32 at a previous position (for back-patching body lengths).

**`toBinary`**

Build the complete canonical FMIR v3 binary.

**`getIslands`**

Get registered island entries (for build.ts to generate client registry).

### makeDiagnostic

Function export

```ts
declare function makeDiagnostic(code: string, file: string, line: number, column: number, message: string): Diagnostic;
```

Make a diagnostic from a code and an already-located position, without
printing it: for a caller that prints its own line (`@getforma/build`).

Related declarations: [`Diagnostic`](/docs/3.0/api-compiler/#symbol-Diagnostic)

### readFmirContainer

Function export

```ts
declare function readFmirContainer(bytes: Uint8Array, reader?: WriterVersion): FmirContainer;
```

Header/table reader used by diagnostics and compiler conformance tests.

Related declarations: [`FmirContainer`](/docs/3.0/api-compiler/#type-FmirContainer), [`WriterVersion`](/docs/3.0/api-compiler/#symbol-WriterVersion)

## Exported types

### Diagnostic

Interface export

```ts
interface Diagnostic {
    code: string;
    file: string;
    line: number;
    column: number;
    message: string;
    why: string;
    fix: string;
    strict: boolean;
    chain?: DiagnosticChainLink[];
}
```

One report, as a build gathers it.

Related declarations: [`DiagnosticChainLink`](/docs/3.0/api-compiler/#symbol-DiagnosticChainLink)

**`code`**

The stable code, e.g. `BUILD-101`.

**`file`**

The file to edit, as the compiler read it (absolute in a real build).

**`line`**

1-based line in that file, as authored (JSX mapped back); 0 when unknown.

**`column`**

1-based column; 0 when unknown.

**`message`**

The specific report: the construct, what happens, and its fix.

**`why`**

The catalogue's why for the code.

**`fix`**

The catalogue's fix for the code.

**`strict`**

Whether `--strict` fails the build on it (false only for notes).

**`chain`**

BUILD-403: the composition chain, from the page down to the component refused.

### DiagnosticChainLink

Interface export

```ts
interface DiagnosticChainLink {
    component: string;
    file: string;
    line: number;
    column: number;
}
```

One link of a composition chain, from the page down (BUILD-403).

**`component`**

The component's name where it is called (the page root first).

**`file`**

The file the call is in (for the root: the page component's file).

### DiagnosticEntry

Interface export

```ts
interface DiagnosticEntry {
    code: string;
    title: string;
    why: string;
    fix: string;
    strict: boolean;
}
```

Forma Compiler - Coded build diagnostics (FORMA-119; DR-1, L-3, N12)

Every construct the compiler cannot represent in a server-rendered module is
reported here, with a stable code, the file, the line and the column, one
line of why and one of fix. The catalogue below is the single list of codes;
`packages/compiler/docs/subset.md` documents each one, and a test keeps the two equal.

Codes are numbered by family (L-3). BUILD-303, BUILD-408, BUILD-504, BUILD-706 and BUILD-708
are retired and reserved after the declared-state migration. Current
nonfatal build notes are explicitly marked with strict=false.

Codes are numbered by family (L-3):

  BUILD-1xx  an unsupported native subtree
  BUILD-2xx  an attribute or prop dropped or left empty
  BUILD-3xx  an unresolved text, conditional or list expression
  BUILD-4xx  a component the compiler does not inline
  BUILD-5xx  a signal the compiler cannot name
  BUILD-6xx  the page module and its closed native contract
  BUILD-7xx  a construct adoption does not handle; `browserOnly()` is the way out
  BUILD-8xx  the build package (reported by

**getforma** /build, catalogued here)
BUILD-9xx  the compiler's own deprecated entry points (logged when called)

A code never changes meaning. A new construct gets a new code; a retired one
stays reserved.

What a report does, in order:

1. It prints a source-located reason diagnostic with its stable code. Native
expressions that cannot form a declared contract also throw BUILD-610,
independent of strict mode; historical warning-only behavior is archived.
2. It hands the diagnostic, with its location, to the collector the caller
opened with [collectDiagnostics](/docs/3.0/api-compiler/#symbol-collectDiagnostics), if any. The SSR plugin opens one
per page; `@getforma/build` gathers them all, writes them as JSON on
request, and always fails publication when any error remains.

Verified by: packages/compiler/tests/diagnostics-conformance.test.ts

**`code`**

The stable code, `BUILD-<family><nn>`.

**`title`**

What the code names, in a few words.

**`why`**

One line: what happens to the page.

**`fix`**

One line: what to write instead.

**`strict`**

Whether this is a publication error. False only for explicitly nonfatal build notes.

### FmirSection

Interface export

```ts
interface FmirSection {
    id: number;
    flags: number;
    bytes: Uint8Array;
}
```



### IrResult

Interface export

```ts
interface IrResult {
    binary: Uint8Array;
    islands: ReturnType<IrEmitContext['getIslands']>;
}
```



Related declarations: [`IrEmitContext`](/docs/3.0/api-compiler/#symbol-IrEmitContext)

### KeyPath

Interface export

```ts
interface KeyPath {
    listOffset: number;
    segments: readonly string[];
}
```



### PropsSchema

Type alias export

```ts
type PropsSchema = readonly (readonly SchemaField[])[];
```



Related declarations: [`SchemaField`](/docs/3.0/api-compiler/#symbol-SchemaField)

### SchemaField

Interface export

```ts
interface SchemaField {
    name: string;
    file: string;
    line: number;
    column: number;
    type: SchemaType;
}
```



Related declarations: [`SchemaType`](/docs/3.0/api-compiler/#symbol-SchemaType)

### SchemaType

Type alias export

```ts
type SchemaType = {
    kind: 'boolean' | 'string' | 'number' | 'date';
} | {
    kind: 'enum';
    variants: readonly string[];
} | {
    kind: 'array';
    element: SchemaType;
} | {
    kind: 'optional';
    inner: SchemaType;
} | {
    kind: 'object';
    object: number;
};
```



### SourcePosition

Interface export

```ts
interface SourcePosition {
    opcodeOffset: number;
    file: string;
    line: number;
    column: number;
    component: string;
}
```



### SsrEntryProduct

Interface export

```ts
interface SsrEntryProduct {
    readonly page: string;
    readonly mode: 'ssr';
    readonly sourceEntry: string;
    readonly browserEntry: string;
    readonly irFile: string;
    readonly irHash: string;
    readonly browserRequired: boolean;
    readonly islands: readonly Readonly<{
        name: string;
        mode: 'ssr' | 'browserOnly';
    }>[];
}
```

One successfully compiled native/browser entry, before caller publication.

### SsrPluginOptions

Interface export

```ts
interface SsrPluginOptions {
    page: string;
    outDir: string;
    entryPoint?: string;
    clientEntryPoint?: string;
    browserEntryPoints?: readonly {
        path: string;
        entryPoint: string;
    }[];
    strict?: boolean;
    onDiagnostics?: (diagnostics: Diagnostic[], page: string) => void;
}
```

Forma Compiler - esbuild SSR Plugin

Captures one source graph for native IR and browser registration metadata,
returning both outputs without publishing partial builds.

Related declarations: [`Diagnostic`](/docs/3.0/api-compiler/#symbol-Diagnostic)

**`page`**

Page name (e.g., 'platform-login') -- used for the output .ir filename

**`outDir`**

Output directory for .ir files

**`entryPoint`**

Entry point path (e.g., 'src/platform/onboarding/app.ts') for real IR emission

**`clientEntryPoint`**

Browser entry whose literal registry receives the paired metadata.

**`browserEntryPoints`**

Private entry aliases supplied by the shared build graph for this same
physical client entry in explicit Browser mode. Dependencies remain shared.

**`strict`**

Legacy compatibility option. All unsupported native constructs fail in 3.0;
false cannot restore warning-only publication.

**`onDiagnostics`**

Receives the page's diagnostics after each emission (`@getforma/build`
gathers them for its result, its JSON report and aggregate failure).

### WriterVersion

Type alias export

```ts
type WriterVersion = readonly [
    number,
    number,
    number
];
```



## Referenced declaration types

### BinaryBindingOperator

Referenced type; not separately importable from this entry point.

```ts
type BinaryBindingOperator = '+' | '-' | '*' | '/' | '%' | '**' | '===' | '!==' | '<' | '<=' | '>' | '>=' | '&&' | '||';
```



### BindingRecord

Referenced type; not separately importable from this entry point.

```ts
type BindingRecord = {
    kind: 'signal' | 'text';
    value: BindingValue;
} | {
    kind: 'attribute';
    name: string;
    value: BindingValue;
} | {
    kind: 'show';
    value: BindingValue;
    then: readonly BindingRecord[];
    else: readonly BindingRecord[];
} | {
    kind: 'list';
    value: BindingValue;
    key: readonly string[];
    body: readonly BindingRecord[];
} | {
    kind: 'child';
    name: string;
    fields: readonly {
        name: string;
        value: BindingValue;
    }[];
} | {
    kind: 'capture';
    value: unknown;
};
```



Related declarations: [`BindingValue`](/docs/3.0/api-compiler/#type-BindingValue)

### BindingValue

Referenced type; not separately importable from this entry point.

```ts
type BindingValue = {
    kind: 'constant';
    value: unknown;
} | {
    kind: 'prop';
    path: readonly string[];
} | {
    kind: 'signal' | 'row' | 'capture';
    id: number;
    path: readonly string[];
} | {
    kind: 'nullish';
    source: BindingValue;
    fallback: unknown;
} | {
    kind: 'unary';
    operator: UnaryBindingOperator;
    value: BindingValue;
} | {
    kind: 'binary';
    operator: BinaryBindingOperator;
    left: BindingValue;
    right: BindingValue;
};
```



Related declarations: [`BinaryBindingOperator`](/docs/3.0/api-compiler/#type-BinaryBindingOperator), [`UnaryBindingOperator`](/docs/3.0/api-compiler/#type-UnaryBindingOperator)

### CanonicalField

Referenced type; not separately importable from this entry point.

```ts
interface CanonicalField {
    readonly name: string;
    readonly type: SchemaType;
}
```



Related declarations: [`SchemaType`](/docs/3.0/api-compiler/#symbol-SchemaType)

### CanonicalSchema

Referenced type; not separately importable from this entry point.

```ts
type CanonicalSchema = readonly (readonly CanonicalField[])[];
```



Related declarations: [`CanonicalField`](/docs/3.0/api-compiler/#type-CanonicalField)

### FmirContainer

Referenced type; not separately importable from this entry point.

```ts
interface FmirContainer {
    writer: WriterVersion;
    bodyLength: number;
    checksum: number;
    sections: FmirDescriptor[];
}
```



Related declarations: [`FmirDescriptor`](/docs/3.0/api-compiler/#type-FmirDescriptor), [`WriterVersion`](/docs/3.0/api-compiler/#symbol-WriterVersion)

### FmirDescriptor

Referenced type; not separately importable from this entry point.

```ts
interface FmirDescriptor extends FmirSection {
    offset: number;
    length: number;
}
```



Related declarations: [`FmirSection`](/docs/3.0/api-compiler/#symbol-FmirSection)

### IslandRenderMode

Referenced type; not separately importable from this entry point.

```ts
type IslandRenderMode = 'ssr' | 'browserOnly';
```



### UnaryBindingOperator

Referenced type; not separately importable from this entry point.

```ts
type UnaryBindingOperator = '!' | '+' | '-';
```

