API Stability Notice
Macroforge is under active development. The API is not yet stable and may change between versions. Some documentation sections may be outdated.
Decode
The Decode macro generates JSON decoding methods with cycle and
forward-reference support, plus comprehensive runtime validation. This enables
safe parsing of complex JSON structures including circular references.
Generated Output
For classes (class_handler), the macro generates static methods plus
standalone functions (nameDecode, nameDecodeWithContext, nameIs) that delegate to them:
static decode(input: unknown, opts?: DecodeOptions): { success: true; value: T } | { success: false; errors: Array<{ field: string; message: string }> }- Auto-detects JSON string vs object; never throws.opts.freezefreezes all decoded objects.static decodeWithContext(value, ctx): T | PendingRef- Internal method used for nested/cyclic graphs; throwsDecodeErroron structural errorsstatic hasShape(obj): boolean- Checks all required JSON keys are presentstatic is(value): value is T- Type guard: instanceof check, thenhasShape, then a fulldecodestatic validateField(field, value)/static validateFields(partial)- Run the field validators on input that has not been decoded, typedunknown- A synthesized
constructor(props)that assigns all decoded fields
Interfaces and type aliases get the standalone-function forms of the same
surface (there is no class to attach statics to), except that only an object-shaped
alias has fields to validate, so no other alias gets validateField/validateFields. Enums (enum_handler) get nameDecode/nameDecodeWithContext/nameIs; unlike the other
shapes, the enum decode function throws an Error on invalid values
rather than returning a result union.
A type alias of a primitive, plain (type Port = number) or branded
(type Meters = $Newtype<number>), decodes to that primitive: decode rejects
any other typeof, hasShape checks the typeof, and is additionally runs
the alias’s validators. Validators go on the alias itself:
/** @derive(Decode) */
/** @endec(nonNegative, finite) */
type Meters = $Newtype<number>;
metersDecode(-1); // { success: false, errors: [{ field: "_root", ... }] }
metersIs("12"); // falseAlias-level validators on any other alias shape are an expansion error; put them on the fields instead.
Validation (see validation) runs during decoding and reports failures
through the errors array of the result union. Field-level options are parsed by field; see the parent endec module for the option and validator
reference.