/** * @file Type-level primitives for formal state machine verification. * @description * This file provides a Domain Specific Language (DSL) of transition decorators. * These functions serve two purposes: * 1. At runtime, they preserve the transition function and attach non-enumerable metadata. * 2. At design/build time, they brand transition functions with rich type metadata. * * This allows a static analysis tool (like `ts-morph`) to read your source code * and generate a formal Statechart (JSON) that perfectly matches your implementation, * including resolving Class Constructors to their names. */ /** * Options passed to async transition functions, including cancellation support. */ export interface TransitionOptions { /** AbortSignal for cancelling long-running async operations. */ signal: AbortSignal; } /** * A unique symbol used to "brand" a type with metadata. * This key allows the static analyzer to find the metadata within a complex type signature. */ export declare const META_KEY: unique symbol; /** * Non-enumerable property key for storing metadata on function objects at runtime. * @internal */ export declare const RUNTIME_META: unique symbol; /** * Local definition of Machine type to avoid circular imports. * @internal */ type Machine = { readonly context: C; }; /** * Helper type representing a Class Constructor. * Used to reference target states by their class definition rather than magic strings. */ export type ClassConstructor = new (...args: any[]) => any; /** * Metadata describing a Guard condition. */ export interface GuardMeta { /** The name of the guard (e.g., "isAdmin"). */ name: string; /** Optional documentation explaining the logic. */ description?: string; } /** * Metadata describing an Invoked Service (async operation). */ export interface InvokeMeta { /** The name of the service source (e.g., "fetchUserData"). */ src: string; /** The state class to transition to on success. */ onDone: ClassConstructor; /** The state class to transition to on error. */ onError: ClassConstructor; /** Optional description. */ description?: string; } /** * Metadata describing a generic Action (side effect). */ export interface ActionMeta { /** The name of the action (e.g., "logAnalytics"). */ name: string; /** Optional description. */ description?: string; } /** * The comprehensive shape of metadata that can be encoded into a transition's type. */ export interface TransitionMeta { /** The target state class this transition leads to. */ target?: ClassConstructor; /** A human-readable description of the transition. */ description?: string; /** An array of guards that must be true for this transition to be enabled. */ guards?: GuardMeta[]; /** A service to invoke upon taking this transition (or entering the state). */ invoke?: InvokeMeta; /** Fire-and-forget side effects associated with this transition. */ actions?: ActionMeta[]; } /** * The Branded Type. * It takes a function type `F` and intersects it with a hidden metadata object `M`. * This is the mechanism that carries information from your code to the compiler API. * * @typeParam F - Original transition function type. * @typeParam M - Metadata merged onto that function type. */ export type WithMeta any, M extends TransitionMeta> = Annotated; /** * Value carrying type-level metadata without changing its callable runtime shape. * * @typeParam T - Annotated object or function. * @typeParam M - Metadata represented by the annotation. */ export type Annotated = T & { [META_KEY]: M; }; type AnyFunction = (...args: any[]) => any; /** * Extracts metadata already carried by an annotated transition. * * @typeParam F - Possibly annotated function type. */ export type MetadataOf = F extends { [META_KEY]: infer M extends TransitionMeta; } ? M : {}; /** * Unary type transformation suitable for use with {@link pipe}. * @typeParam Input - Accepted value type. * @typeParam Output - Resulting value type. */ export type Operator = (value: Input) => Output; /** * Reusable decorator that adds metadata without changing a transition's call signature. * @typeParam M - Metadata fragment added by the operator. */ export type MetadataOperator = (transition: F) => WithMeta & M>; /** * Applies operators from left to right while preserving each intermediate type. * * This is deliberately a standalone function: machine snapshots stay plain values, * and the same composition helper works for transition functions or other values. * * @param value - Initial value passed to the first operator. * @param operators - Unary transformations applied in declaration order. * @returns The final operator result, or `value` when no operators are supplied. * @example * ```ts * const login = pipe( * (user: User) => new LoggedIn({ user }), * transitionTo(LoggedIn), * describe('Authenticate the current user'), * action({ name: 'auditLogin' }), * ); * ``` */ /** * Returns `value` unchanged. * @typeParam A - Input and result type. */ export declare function pipe(value: A): A; /** * Applies one typed operator. * @typeParam A - Input type. * @typeParam B - Result type. */ export declare function pipe(value: A, ab: Operator): B; /** * Applies two typed operators. * @typeParam A - Input type. * @typeParam B - Intermediate type. * @typeParam C - Result type. */ export declare function pipe(value: A, ab: Operator, bc: Operator): C; /** * Applies three typed operators. * @typeParam A - Input type. * @typeParam B - First intermediate type. * @typeParam C - Second intermediate type. * @typeParam D - Result type. */ export declare function pipe(value: A, ab: Operator, bc: Operator, cd: Operator): D; /** * Applies four typed operators. * @typeParam A - Input type. * @typeParam B - First intermediate type. * @typeParam C - Second intermediate type. * @typeParam D - Third intermediate type. * @typeParam E - Result type. */ export declare function pipe(value: A, ab: Operator, bc: Operator, cd: Operator, de: Operator): E; /** * Applies five typed operators. * @typeParam A - Input type. * @typeParam B - First intermediate type. * @typeParam C - Second intermediate type. * @typeParam D - Third intermediate type. * @typeParam E - Fourth intermediate type. * @typeParam F - Result type. */ export declare function pipe(value: A, ab: Operator, bc: Operator, cd: Operator, de: Operator, ef: Operator): F; /** * Applies six typed operators. * @typeParam A - Input type. * @typeParam B - First intermediate type. * @typeParam C - Second intermediate type. * @typeParam D - Third intermediate type. * @typeParam E - Fourth intermediate type. * @typeParam F - Fifth intermediate type. * @typeParam G - Result type. */ export declare function pipe(value: A, ab: Operator, bc: Operator, cd: Operator, de: Operator, ef: Operator, fg: Operator): G; /** * Runtime metadata interface (resolved class names as strings) */ export interface RuntimeTransitionMeta { target?: string; description?: string; guards?: Array<{ name: string; description?: string; }>; invoke?: { src: string; onDone: string; onError: string; description?: string; }; actions?: Array<{ name: string; description?: string; }>; } /** * Defines a transition to a target state class. * * @param target - The Class Constructor of the state being transitioned to. * @param implementation - The implementation function returning the new state instance. * @returns The implementation function, branded with target metadata. * @typeParam T - Target state constructor. * @typeParam F - Transition implementation type, including parameters and return. * * @example * login = transitionTo(LoggedInMachine, (user) => new LoggedInMachine({ user })); */ export declare function transitionTo(target: T): MetadataOperator<{ target: T; }>; /** * Direct form of {@link transitionTo}; annotates `implementation` immediately. * @typeParam T - Target constructor. * @typeParam F - Implementation type. */ export declare function transitionTo(target: T, implementation: F): WithMeta & { target: T; }>; /** * Annotates a transition with a description for documentation generation. * * @param text - The description text. * @param transition - The transition function (or wrapper) to annotate. * @returns A reusable operator when `transition` is omitted, otherwise the same callable transition. * @typeParam F - Annotated transition function type. * @example * logout = describe("Logs the user out", transitionTo(LoggedOut, ...)); */ export declare function describe(text: string): MetadataOperator<{ description: string; }>; /** * Direct form of {@link describe}; annotates `transition` immediately. * @typeParam F - Annotated transition type. */ export declare function describe(text: string, transition: F): WithMeta & { description: string; }>; /** * Annotates a transition with a Guard condition. * Note: This only adds metadata. You must still implement the `if` check inside your function. * * @deprecated Use the runtime `guard()` primitive instead. Its `options.description` is used for static analysis. * @param guard - Object containing the name and optional description of the guard. * @param transition - The transition function to guard. * @returns A reusable metadata operator or the annotated transition. * @typeParam G - Guard metadata literal. * @typeParam F - Annotated transition function type. * @example * delete = guarded({ name: "isAdmin" }, transitionTo(Deleted, ...)); */ export declare function guarded(guard: G): MetadataOperator<{ guards: [G]; }>; /** * Direct form of {@link guarded}; annotates `transition` immediately. * @typeParam G - Guard metadata. * @typeParam F - Annotated transition type. */ export declare function guarded(guard: G, transition: F): WithMeta & { guards: [G]; }>; /** * Annotates a transition with an Invoked Service (asynchronous effect). * * This decorator records extraction metadata; it does not schedule or execute * the function. Execution remains the responsibility of the caller or runner. * * @param service - configuration for the service (source, onDone target, onError target). * @param implementation - The async function implementation that receives an AbortSignal. * @returns A reusable operator or the same callable implementation with invoke metadata. * @typeParam D - Success target constructor. * @typeParam E - Error target constructor. * @typeParam F - Abort-aware implementation function. * @example * load = invoke( * { src: "fetchData", onDone: LoadedMachine, onError: ErrorMachine }, * async ({ signal }) => { * const response = await fetch('/api/data', { signal }); * return new LoadedMachine({ data: await response.json() }); * } * ); */ type InvokeService = { src: string; onDone: D; onError: E; description?: string; }; type InvokeOperator = any>(implementation: F) => WithMeta & { invoke: InvokeService; }>; /** * Curried form of `invoke`; returns an operator for an abort-aware implementation. * @typeParam D - Success target constructor. * @typeParam E - Error target constructor. */ export declare function invoke(service: InvokeService): InvokeOperator; /** * Direct form of {@link invoke}; annotates `implementation` immediately. * @typeParam D - Success target constructor. * @typeParam E - Error target constructor. * @typeParam F - Abort-aware implementation type. */ export declare function invoke any>(service: InvokeService, implementation: F): WithMeta & { invoke: InvokeService; }>; /** * Annotates a transition with a side-effect Action. * Useful for logging, analytics, or external event firing that doesn't change state structure. * This decorator records metadata; it does not execute the described action. * * @param action - Object containing the name and optional description. * @param transition - The transition function to annotate. * @returns A reusable operator or the same callable transition with action metadata. * @typeParam A - Action metadata literal. * @typeParam F - Annotated transition function type. * @example * click = action({ name: "trackClick" }, (ctx) => ...); */ export declare function action(action: A): MetadataOperator<{ actions: [A]; }>; /** * Direct form of {@link action}; annotates `transition` immediately. * @typeParam A - Action metadata. * @typeParam F - Annotated transition type. */ export declare function action(actionMeta: A, transition: F): WithMeta & { actions: [A]; }>; /** * Configuration options for guard behavior when conditions fail. * * @typeParam C - Context read by the condition and fallback. * @typeParam TFailure - Machine type returned by a configured fallback. */ export interface GuardOptions = Machine> { /** Failure policy. Defaults to throwing `errorMessage` or `Guard condition failed`. */ onFail?: 'throw' | 'ignore' | GuardFallback; /** Custom error message used only by `'throw'` mode. */ errorMessage?: string; /** Human-readable description attached to runtime extraction metadata. */ description?: string; } /** * Machine or machine-bound function returned when a guard fails. * * Function fallbacks receive the original transition arguments and the current * machine as `this`. They cannot be used with context-only invocation. * * @typeParam C - Current context type. * @typeParam TFailure - Machine returned by the fallback. */ export type GuardFallback = Machine> = ((this: Machine, ...args: any[]) => TFailure) | TFailure; /** * A guarded transition that checks conditions at runtime before executing. * Can be called with either machine or context as 'this' binding. * * @typeParam C - Context inspected by the guard condition. * @typeParam TSuccess - Machine returned when the condition passes. * @typeParam TFailure - Machine returned by the configured failure policy. */ export type GuardedTransition, TFailure extends Machine = Machine> = { (...args: any[]): TSuccess | TFailure | Promise; readonly __guard: true; readonly condition: (ctx: C, ...args: any[]) => boolean | Promise; readonly transition: (...args: any[]) => TSuccess; }; /** * Creates a synchronous runtime guard that checks conditions before executing transitions. * This provides actual runtime protection with synchronous execution - use this for the majority of cases. * * **IMPORTANT - Context-Bound Limitation:** * Guards accept calls with either `this === machine` or `this === context`, but when called * with context-only binding, the guard normalizes to `{ context }` before passing to the transition. * This means: * - ✅ Transitions can access `this.context` * - ❌ Transitions CANNOT call `this.otherTransition()` (no transitions property) * - Recommended: Use guards only with machine-bound transitions for full composition support * * @template C - The context type * @template TSuccess - The transition return type when condition passes * @template TFailure - The fallback return type when condition fails (defaults to Machine) * @param condition - Synchronous function that returns true if transition should proceed * @param transition - The transition function to execute if condition passes * @param options - Configuration for guard failure behavior * @returns A synchronous guarded transition function * @throws {Error} When the condition fails in `'throw'` mode. * @throws {Error} When `'ignore'` or a function fallback is used with context-only binding. * * @example * ```typescript * const machine = createMachine({ balance: 100 }, { * withdraw: guard( * (ctx, amount) => ctx.balance >= amount, * function(this: Machine<{balance: number}>, amount: number) { * // ✅ Can access this.context * return createMachine({ balance: this.context.balance - amount }, this); * // ❌ Cannot call this.otherTransition() if guard was called with context-only binding * }, * { onFail: 'throw', errorMessage: 'Insufficient funds' } * ) * }); * * machine.withdraw(50); // ✅ Works synchronously * machine.withdraw(200); // ❌ Throws "Insufficient funds" * ``` */ export declare function guard, TFailure extends Machine = Machine>(condition: (ctx: C, ...args: any[]) => boolean, transition: (...args: any[]) => TSuccess, options?: GuardOptions): (...args: any[]) => TSuccess | TFailure; /** * Creates a runtime guard that checks conditions before executing transitions. * This provides actual runtime protection, unlike the `guarded` primitive which only adds metadata. * Use this when your condition or transition logic is asynchronous. * * **IMPORTANT - Context-Bound Limitation:** * Guards accept calls with either `this === machine` or `this === context`, but when called * with context-only binding, the guard normalizes to `{ context }` before passing to the transition. * This means: * - ✅ Transitions can access `this.context` * - ❌ Transitions CANNOT call `this.otherTransition()` (no transitions property) * - Recommended: Use guards only with machine-bound transitions for full composition support * * @template C - The context type * @template TSuccess - The transition return type when condition passes * @template TFailure - The fallback return type when condition fails (defaults to Machine) * @param condition - Function that returns true if transition should proceed (can be async) * @param transition - The transition function to execute if condition passes * @param options - Configuration for guard failure behavior * @returns A guarded transition function that returns a Promise * @throws {Error} Through the returned promise when the condition fails in `'throw'` mode. * @throws {Error} Through the returned promise when a machine-only failure policy is used with context-only binding. * * @example * ```typescript * const machine = createMachine({ balance: 100 }, { * withdraw: guardAsync( * async (ctx, amount) => { * // Simulate API call to check balance * await new Promise(resolve => setTimeout(resolve, 100)); * return ctx.balance >= amount; * }, * async function(this: Machine<{balance: number}>, amount: number) { * // Simulate API call to process withdrawal * await new Promise(resolve => setTimeout(resolve, 100)); * // ✅ Can access this.context * return createMachine({ balance: this.context.balance - amount }, this); * // ❌ Cannot call this.otherTransition() if guard was called with context-only binding * }, * { onFail: 'throw', errorMessage: 'Insufficient funds' } * ) * }); * * await machine.withdraw(50); // ✅ Works * await machine.withdraw(200); // ❌ Throws "Insufficient funds" * ``` */ export declare function guardAsync, TFailure extends Machine = Machine>(condition: (ctx: C, ...args: any[]) => boolean | Promise, transition: (...args: any[]) => TSuccess, options?: GuardOptions): GuardedTransition; /** * Creates a branded synchronous guard with condition and transition metadata. * * `guard()` is also synchronous; `guardSync()` additionally returns the * `GuardedTransition` inspection surface (`__guard`, `condition`, and * `transition`). Use `guardAsync()` for promise-returning conditions. * * @template C - The context type * @template TSuccess - The transition return type when the condition passes * @template TFailure - The fallback return type when the condition fails * @param condition - Function that returns true if transition should proceed (must be synchronous) * @param transition - The transition function to execute if condition passes (must be synchronous) * @param options - Configuration for guard failure behavior * @returns A synchronous guarded transition function * @throws {Error} When the condition fails in `'throw'` mode. * @throws {Error} When a machine-only failure policy is used with context-only binding. * * @example * ```typescript * const machine = createMachine({ balance: 100 }, { * withdraw: guardSync( * (ctx, amount) => ctx.balance >= amount, * function(amount: number) { * return createMachine({ balance: this.context.balance - amount }, this); * }, * { onFail: 'throw', errorMessage: 'Insufficient funds' } * ) * }); * * machine.withdraw(50); // ✅ Works synchronously * machine.withdraw(200); // ❌ Throws "Insufficient funds" * ``` */ export declare function guardSync, TFailure extends Machine = Machine>(condition: (ctx: C, ...args: any[]) => boolean, transition: (...args: any[]) => TSuccess, options?: GuardOptions): GuardedTransition; /** * Fluent API for creating synchronous guarded transitions. * Provides a more readable way to define conditional transitions with synchronous execution. * * @template C - The context type * @param condition - Synchronous function that returns true if transition should proceed * @returns A fluent interface for defining the guarded transition * * @example * ```typescript * const machine = createMachine({ isAdmin: false }, { * deleteUser: whenGuard((ctx) => ctx.isAdmin) * .do(function(userId: string) { * return createMachine({ ...this.context, deleted: userId }, this); * }) * .else(function() { * return createMachine({ ...this.context, error: 'Unauthorized' }, this); * }) * }); * ``` */ export declare function whenGuard(condition: (ctx: C, ...args: any[]) => boolean): { /** * Define the transition to execute when the condition passes. * Returns a guarded transition that can optionally have an else clause. */ do>(transition: (...args: any[]) => T): (...args: any[]) => T | Machine; }; /** * Fluent API for creating asynchronous guarded transitions. * Provides a more readable way to define conditional transitions with async execution. * * @template C - The context type * @param condition - Function that returns true if transition should proceed (can be async) * @returns A fluent interface for defining the guarded transition * * @example * ```typescript * const machine = createMachine({ isAdmin: false }, { * deleteUser: whenGuardAsync(async (ctx) => { * // Simulate API call * await checkPermissions(ctx.userId); * return ctx.isAdmin; * }) * .do(async function(userId: string) { * await deleteUserFromDB(userId); * return createMachine({ ...this.context, deleted: userId }, this); * }) * .else(function() { * return createMachine({ ...this.context, error: 'Unauthorized' }, this); * }) * }); * ``` */ export declare function whenGuardAsync(condition: (ctx: C, ...args: any[]) => boolean | Promise): { /** * Define the transition to execute when the condition passes. * Returns a guarded transition that can optionally have an else clause. */ do>(transition: (...args: any[]) => T): GuardedTransition>; }; /** * Flexible metadata wrapper for functional and type-state patterns. * * This function allows attaching metadata to values that don't use the class-based * MachineBase pattern. It's particularly useful for: * - Functional machines created with createMachine() * - Type-state discriminated unions * - Generic machine configurations * * @param meta - Partial metadata object describing states, transitions, etc. * @param value - The value to annotate (machine, config, factory function, etc.) * @returns The value unchanged, or a reusable unary annotation when value is omitted * @typeParam M - Metadata fragment attached to the value. * @typeParam T - Annotated object or function type. * @throws {TypeError} If the direct form receives `undefined` instead of an object or function. * * @example * // Annotate a functional machine * const machine = metadata( * { * target: IdleState, * description: "Counter machine with increment/decrement" * }, * createMachine({ count: 0 }, { ... }) * ); * * @example * // Annotate a factory function * export const createCounter = metadata( * { description: "Creates a counter starting at 0" }, * () => createMachine({ count: 0 }, { ... }) * ); */ export declare function metadata>(meta: M): (value: T) => Annotated; /** * Direct form of {@link metadata}; annotates `value` immediately. * @typeParam M - Metadata shape. * @typeParam T - Annotated value type. */ export declare function metadata, T extends object>(meta: M, value: T): Annotated; export {}; //# sourceMappingURL=primitives.d.ts.map