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
import { baseWriterVersion } from '@getforma/compiler';Values and functions
baseWriterVersion#
declare function baseWriterVersion(version: string): WriterVersion;Related declarations: WriterVersion
collectDiagnostics#
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#
declare const COMPILER_WRITER_VERSION: WriterVersion;Related declarations: WriterVersion
crc32#
declare function crc32(...chunks: readonly Uint8Array[]): number;CRC-32/ISO-HDLC, streaming chunks without inserting boundary or skipped bytes.
DIAGNOSTIC_CATALOGUE#
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#
declare function diagnosticEntry(code: string): DiagnosticEntry;The catalogue entry for a code. Throws on a code the catalogue lacks.
Related declarations: DiagnosticEntry
dumpFmir#
declare function dumpFmir(bytes: Uint8Array): string;Stable lossless representation shared with forma-ir::dump_ir.
encodeFmirSections#
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#
declare class FmirContainerError extends Error {
readonly code: string;
constructor(code: string, message: string);
}formaSsrPlugin#
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#
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#
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#
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#
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#
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#
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 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.
DiagnosticChainLink#
interface DiagnosticChainLink {
component: string;
file: string;
line: number;
column: number;
}One link of a composition chain, from the page down (BUILD-403).
Member notes
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 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:
- 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.
- 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/buildgathers 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 FmirSection {
id: number;
flags: number;
bytes: Uint8Array;
}IrResult#
interface IrResult {
binary: Uint8Array;
islands: ReturnType<IrEmitContext['getIslands']>;
}Related declarations: IrEmitContext
KeyPath#
interface KeyPath {
listOffset: number;
segments: readonly string[];
}PropsSchema#
type PropsSchema = readonly (readonly SchemaField[])[];Related declarations: SchemaField
SchemaField#
interface SchemaField {
name: string;
file: string;
line: number;
column: number;
type: SchemaType;
}Related declarations: SchemaType
SchemaType#
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 SourcePosition {
opcodeOffset: number;
file: string;
line: number;
column: number;
component: string;
}SsrEntryProduct#
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 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 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#
type BinaryBindingOperator = '+' | '-' | '*' | '/' | '%' | '**' | '===' | '!==' | '<' | '<=' | '>' | '>=' | '&&' | '||';BindingRecord#
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#
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#
interface CanonicalField {
readonly name: string;
readonly type: SchemaType;
}Related declarations: SchemaType
CanonicalSchema#
type CanonicalSchema = readonly (readonly CanonicalField[])[];Related declarations: CanonicalField
FmirContainer#
interface FmirContainer {
writer: WriterVersion;
bodyLength: number;
checksum: number;
sections: FmirDescriptor[];
}Related declarations: FmirDescriptor, WriterVersion
FmirDescriptor#
interface FmirDescriptor extends FmirSection {
offset: number;
length: number;
}Related declarations: FmirSection
IslandRenderMode#
type IslandRenderMode = 'ssr' | 'browserOnly';UnaryBindingOperator#
type UnaryBindingOperator = '!' | '+' | '-';