Skip to content
forma.
v3.0
☰
Browse documentation
Start here
Build interfaces
Native rendering
Tooling
Security and operations
Architecture
Application guides
API reference

Docs/API reference

FORMA 3.0

@getforma/compiler

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

View source ↗Markdown ↓Source 2006423
On this page

Generated from the published 3.0.0 TypeScript declarations. Signatures, overloads and JSDoc are taken from the package; private class members are omitted. Declaration links point to version-pinned package files. External type versions identify the installed dependency declarations used here; they do not narrow the package's published dependency or peer compatibility ranges.

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.

Read the usage guide or all entry points.

29 exports · published 3.0.0 declarations

ts
import { baseWriterVersion } from '@getforma/compiler';

Values and functions

baseWriterVersion#

Function export · Declaration, line 419

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

Related declarations: WriterVersion

collectDiagnostics#

Function export · Declaration, line 357

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

COMPILER_WRITER_VERSION#

Value export · Declaration, line 420

ts
declare const COMPILER_WRITER_VERSION: WriterVersion;

Related declarations: WriterVersion

crc32#

Function export · Declaration, line 422

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

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

DIAGNOSTIC_CATALOGUE#

Value export · Declaration, line 314

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

diagnosticEntry#

Function export · Declaration, line 316

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

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

Related declarations: DiagnosticEntry

dumpFmir#

Function export · Declaration, line 447

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

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

encodeFmirSections#

Function export · Declaration, line 443

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, WriterVersion

FmirContainerError#

Class export · Declaration, line 438

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

formaSsrPlugin#

Function export · Declaration, line 416

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 (from esbuild; installed declarations 0.28.2), SsrPluginOptions

formatDiagnostic#

Function export · Declaration, line 370

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

generateRealIr#

Function export · Declaration, line 411

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

getSsrEntryProducts#

Function export · Declaration, line 27

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 (from esbuild; installed declarations 0.28.2), SsrEntryProduct

IrEmitContext#

Class export · Declaration, line 138

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, CanonicalSchema, IslandRenderMode, PropsSchema, SourcePosition

Member notes

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 · Declaration, line 365

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

readFmirContainer#

Function export · Declaration, line 445

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

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

Related declarations: FmirContainer, WriterVersion

Exported types

Diagnostic#

Interface export · Declaration, line 327

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

Member notes

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.

DiagnosticEntry#

Interface export · Declaration, line 296

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, 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

Member notes

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 · Declaration, line 423

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

IrResult#

Interface export · Declaration, line 401

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

Related declarations: IrEmitContext

KeyPath#

Interface export · Declaration, line 52

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

PropsSchema#

Type alias export · Declaration, line 51

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

Related declarations: SchemaField

SchemaField#

Interface export · Declaration, line 44

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

Related declarations: SchemaType

SchemaType#

Type alias export · Declaration, line 29

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 · Declaration, line 56

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

SsrEntryProduct#

Interface export · Declaration, line 4

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 · Declaration, line 379

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

Member notes

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 · Declaration, line 418

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

Referenced declaration types

These types appear in the published signatures but are not separate named exports from this entry point. They are shown to explain the contract, not as additional import paths.

BinaryBindingOperator#

Referenced type; not separately importable from this entry point. · Declaration, line 70

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

BindingRecord#

Referenced type; not separately importable from this entry point. · Declaration, line 95

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

BindingValue#

Referenced type; not separately importable from this entry point. · Declaration, line 71

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, UnaryBindingOperator

CanonicalField#

Referenced type; not separately importable from this entry point. · Declaration, line 64

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

Related declarations: SchemaType

CanonicalSchema#

Referenced type; not separately importable from this entry point. · Declaration, line 68

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

Related declarations: CanonicalField

FmirContainer#

Referenced type; not separately importable from this entry point. · Declaration, line 432

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

Related declarations: FmirDescriptor, WriterVersion

FmirDescriptor#

Referenced type; not separately importable from this entry point. · Declaration, line 428

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

Related declarations: FmirSection

IslandRenderMode#

Referenced type; not separately importable from this entry point. · Declaration, line 123

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

UnaryBindingOperator#

Referenced type; not separately importable from this entry point. · Declaration, line 69

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

Find your next answer.

Search Forma 3.0 documentation, guides and examples.