@doeixd/machine 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +952 -13
- package/dist/cjs/development/index.js +691 -0
- package/dist/cjs/development/index.js.map +4 -4
- package/dist/cjs/production/index.js +5 -1
- package/dist/esm/development/index.js +698 -0
- package/dist/esm/development/index.js.map +4 -4
- package/dist/esm/production/index.js +5 -1
- package/dist/types/extract.d.ts +71 -0
- package/dist/types/extract.d.ts.map +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/multi.d.ts +838 -0
- package/dist/types/multi.d.ts.map +1 -0
- package/dist/types/primitives.d.ts +202 -0
- package/dist/types/primitives.d.ts.map +1 -0
- package/dist/types/runtime-extract.d.ts +53 -0
- package/dist/types/runtime-extract.d.ts.map +1 -0
- package/package.json +6 -2
- package/src/extract.ts +452 -67
- package/src/index.ts +49 -0
- package/src/multi.ts +1145 -0
- package/src/primitives.ts +134 -0
- package/src/react.ts +349 -28
- package/src/runtime-extract.ts +141 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../src/index.ts", "../../../src/generators.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * @file A tiny, immutable, and type-safe state machine library for TypeScript.\n * @author doeixd\n * @version 1.0.0\n */\n\n// =============================================================================\n// SECTION: CORE TYPES & INTERFACES\n// =============================================================================\n\n/**\n * A utility type that represents either a value of type T or a Promise that resolves to T.\n * @template T - The value type.\n */\nexport type MaybePromise<T> = T | Promise<T>;\n\n/**\n * The fundamental shape of any machine: a `context` object for state, and methods for transitions.\n * @template C - The context (state) object type.\n */\nexport type Machine<C extends object> = {\n /** The readonly state of the machine. */\n readonly context: C;\n} & Record<string, (...args: any[]) => Machine<any>>;\n\n/**\n * The shape of an asynchronous machine, where transitions can return Promises.\n * @template C - The context (state) object type.\n */\nexport type AsyncMachine<C extends object> = {\n /** The readonly state of the machine. */\n readonly context: C;\n} & Record<string, (...args: any[]) => MaybePromise<AsyncMachine<any>>>;\n\n\n// =============================================================================\n// SECTION: TYPE UTILITIES & INTROSPECTION\n// =============================================================================\n\n/**\n * Extracts the context type `C` from a machine type `M`.\n * @template M - The machine type.\n * @example type Ctx = Context<Machine<{ count: number }>> // { count: number }\n */\nexport type Context<M extends { context: any }> = M[\"context\"];\n\n/**\n * Extracts the transition function signatures from a machine, excluding the context property.\n * @template M - The machine type.\n */\nexport type Transitions<M extends BaseMachine<any>> = Omit<M, \"context\">;\n\n/**\n * Extracts the argument types for a specific transition function in a Machine.\n * @template M - The machine type.\n * @template K - The transition function name.\n */\nexport type TransitionArgs<M extends Machine<any>, K extends keyof M & string> =\n M[K] extends (...args: infer A) => any ? A : never;\n\n/**\n * Extracts the names of all transitions as a string union type.\n * @template M - The machine type.\n * @example\n * type Names = TransitionNames<Machine<{ count: number }> & { increment: () => any }>\n * // Names = \"increment\"\n */\nexport type TransitionNames<M extends BaseMachine<any>> = keyof Omit<M, \"context\"> & string;\n\n/**\n * Base machine type that both Machine and AsyncMachine extend from.\n * @template C - The context object type.\n */\nexport type BaseMachine<C extends object> = {\n /** The readonly state of the machine. */\n readonly context: C;\n} & Record<string, (...args: any[]) => any>;\n\n/**\n * Helper to make a type deeply readonly (freezes nested objects).\n * Useful for ensuring immutability of context at the type level.\n * @template T - The type to make readonly.\n */\nexport type DeepReadonly<T> = {\n readonly [P in keyof T]: T[P] extends object\n ? T[P] extends (...args: any[]) => any\n ? T[P]\n : DeepReadonly<T[P]>\n : T[P];\n};\n\n/**\n * Infers the machine type from a machine factory function.\n * @template F - The factory function type.\n * @example\n * const factory = () => createMachine({ count: 0 }, { ... });\n * type MyMachine = InferMachine<typeof factory>; // Extracts the return type\n */\nexport type InferMachine<F extends (...args: any[]) => any> = ReturnType<F>;\n\n/**\n * A discriminated union type representing an event that can be dispatched to a machine.\n * This is automatically generated from a machine's type signature, ensuring full type safety.\n * @template M - The machine type.\n * @example\n * type CounterEvent = Event<Machine<{ count: number }>& { add: (n: number) => any }>\n * // CounterEvent = { type: \"add\"; args: [number] }\n */\nexport type Event<M extends BaseMachine<any>> = {\n [K in keyof Omit<M, \"context\"> & string]: M[K] extends (...args: infer A) => any\n ? { type: K; args: A }\n : never\n}[keyof Omit<M, \"context\"> & string];\n\n\n// =============================================================================\n// SECTION: MACHINE CREATION (FUNCTIONAL & OOP)\n// =============================================================================\n\n/**\n * Creates a synchronous state machine from a context and transition functions.\n * This is the core factory for the functional approach.\n *\n * @template C - The context object type.\n * @param context - The initial state context.\n * @param fns - An object containing transition function definitions.\n * @returns A new machine instance.\n */\nexport function createMachine<C extends object, T extends Record<string, (this: C, ...args: any[]) => any>>(\n context: C,\n fns: T\n): { context: C } & T {\n return Object.assign({ context }, fns);\n}\n\n/**\n * Creates an asynchronous state machine from a context and async transition functions.\n *\n * @template C - The context object type.\n * @param context - The initial state context.\n * @param fns - An object containing async transition function definitions.\n * @returns A new async machine instance.\n */\nexport function createAsyncMachine<C extends object, T extends Record<string, (this: C, ...args: any[]) => any>>(\n context: C,\n fns: T\n): { context: C } & T {\n return Object.assign({ context }, fns);\n}\n\n/**\n * Creates a machine factory - a higher-order function that simplifies machine creation.\n * Instead of writing transition logic that creates new machines, you just write\n * pure context transformation functions.\n *\n * @template C - The context object type.\n * @returns A factory configurator function.\n *\n * @example\n * const counterFactory = createMachineFactory<{ count: number }>()({\n * increment: (ctx) => ({ count: ctx.count + 1 }),\n * add: (ctx, n: number) => ({ count: ctx.count + n })\n * });\n *\n * const counter = counterFactory({ count: 0 });\n * const next = counter.increment(); // Returns new machine with count: 1\n */\nexport function createMachineFactory<C extends object>() {\n return <T extends Record<string, (ctx: C, ...args: any[]) => C>>(\n transformers: T\n ) => {\n type MachineFns = {\n [K in keyof T]: (\n this: C,\n ...args: T[K] extends (ctx: C, ...args: infer A) => C ? A : never\n ) => Machine<C>;\n };\n\n const fns = Object.fromEntries(\n Object.entries(transformers).map(([key, transform]) => [\n key,\n function (this: C, ...args: any[]) {\n const newContext = (transform as any)(this, ...args);\n return createMachine(newContext, fns as any);\n },\n ])\n ) as MachineFns;\n\n return (initialContext: C): Machine<C> & MachineFns => {\n return createMachine(initialContext, fns);\n };\n };\n}\n\n\n// =============================================================================\n// SECTION: ADVANCED CREATION & IMMUTABLE HELPERS\n// =============================================================================\n\n/**\n * Creates a new machine instance with an updated context, preserving all original transitions.\n * This is the primary, type-safe utility for applying state changes.\n *\n * @template M - The machine type.\n * @param machine - The original machine instance.\n * @param newContextOrFn - The new context object or an updater function.\n * @returns A new machine instance of the same type with the updated context.\n */\nexport function setContext<M extends Machine<any>>(\n machine: M,\n newContextOrFn: Context<M> | ((ctx: Readonly<Context<M>>) => Context<M>)\n): M {\n const { context, ...transitions } = machine;\n const newContext =\n typeof newContextOrFn === \"function\"\n ? (newContextOrFn as (ctx: Readonly<Context<M>>) => Context<M>)(context)\n : newContextOrFn;\n\n return createMachine(newContext, transitions) as M;\n}\n\n/**\n * Creates a new machine by overriding or adding transition functions to an existing machine.\n * Ideal for mocking in tests or decorating functionality. The original machine is unchanged.\n *\n * @template M - The original machine type.\n * @template T - An object of new or overriding transition functions.\n * @param machine - The base machine instance.\n * @param overrides - An object containing the transitions to add or overwrite.\n * @returns A new machine instance with the merged transitions.\n */\nexport function overrideTransitions<\n M extends Machine<any>,\n T extends Record<string, (this: Context<M>, ...args: any[]) => any>\n>(\n machine: M,\n overrides: T\n): Machine<Context<M>> & Omit<Transitions<M>, keyof T> & T {\n const { context, ...originalTransitions } = machine;\n const newTransitions = { ...originalTransitions, ...overrides };\n return createMachine(context, newTransitions) as any;\n}\n\n/**\n * Creates a new machine by adding new transition functions.\n * This utility will produce a compile-time error if you attempt to add a\n * transition that already exists, preventing accidental overrides.\n *\n * @template M - The original machine type.\n * @template T - An object of new transition functions, whose keys must not exist in M.\n * @param machine - The base machine instance.\n * @param newTransitions - An object containing the new transitions to add.\n * @returns A new machine instance with the combined original and new transitions.\n */\nexport function extendTransitions<\n M extends Machine<any>,\n T extends Record<string, (this: Context<M>, ...args: any[]) => any> & {\n [K in keyof T]: K extends keyof M ? never : T[K];\n }\n>(machine: M, newTransitions: T): M & T {\n const { context, ...originalTransitions } = machine;\n const combinedTransitions = { ...originalTransitions, ...newTransitions };\n return createMachine(context, combinedTransitions) as M & T;\n}\n\n/**\n * Creates a builder function from a \"template\" machine instance.\n * This captures the behavior of a machine and returns a factory that can stamp out\n * new instances with different initial contexts. Excellent for class-based machines.\n *\n * @template M - The machine type.\n * @param templateMachine - An instance of a machine to use as the template.\n * @returns A function that builds new machines of type M.\n */\nexport function createMachineBuilder<M extends Machine<any>>(\n templateMachine: M\n): (context: Context<M>) => M {\n const { context, ...transitions } = templateMachine;\n return (newContext: Context<M>): M => {\n return createMachine(newContext, transitions) as M;\n };\n}\n\n/**\n * Pattern match on a machine's state based on a discriminant property in the context.\n * This provides type-safe exhaustive matching for state machines.\n *\n * @template M - The machine type.\n * @template K - The discriminant key in the context.\n * @template R - The return type.\n * @param machine - The machine to match against.\n * @param discriminantKey - The key in the context to use for matching (e.g., \"status\").\n * @param handlers - An object mapping each possible value to a handler function.\n * @returns The result of the matched handler.\n *\n * @example\n * const result = matchMachine(\n * machine,\n * 'status',\n * {\n * idle: (ctx) => \"Machine is idle\",\n * loading: (ctx) => \"Loading...\",\n * success: (ctx) => `Success: ${ctx.data}`,\n * error: (ctx) => `Error: ${ctx.error}`\n * }\n * );\n */\nexport function matchMachine<\n M extends Machine<any>,\n K extends keyof Context<M> & string,\n R\n>(\n machine: M,\n discriminantKey: K,\n handlers: {\n [V in Context<M>[K] & string]: (ctx: Context<M>) => R;\n }\n): R {\n const discriminant = machine.context[discriminantKey] as Context<M>[K] & string;\n const handler = handlers[discriminant];\n if (!handler) {\n throw new Error(`No handler found for state: ${String(discriminant)}`);\n }\n return handler(machine.context);\n}\n\n/**\n * Type-safe helper to assert that a machine's context has a specific discriminant value.\n * This narrows the type of the context based on the discriminant.\n *\n * @template M - The machine type.\n * @template K - The discriminant key.\n * @template V - The discriminant value.\n * @param machine - The machine to check.\n * @param key - The discriminant key to check.\n * @param value - The expected value.\n * @returns True if the discriminant matches, with type narrowing.\n *\n * @example\n * if (hasState(machine, 'status', 'loading')) {\n * // machine.context.status is narrowed to 'loading'\n * }\n */\nexport function hasState<\n M extends Machine<any>,\n K extends keyof Context<M>,\n V extends Context<M>[K]\n>(\n machine: M,\n key: K,\n value: V\n): machine is M & { context: Context<M> & { [P in K]: V } } {\n return machine.context[key] === value;\n}\n\n\n// =============================================================================\n// SECTION: RUNTIME & EVENT DISPATCHER\n// =============================================================================\n\n/**\n * Runs an asynchronous state machine with a managed lifecycle and event dispatch capability.\n * This is the \"interpreter\" for async machines, handling state updates and side effects.\n *\n * @template M - The initial machine type.\n * @param initial - The initial machine state.\n * @param onChange - Optional callback invoked with the new machine state after every transition.\n * @returns An object with a `state` getter for the current context and an async `dispatch` function.\n */\nexport function runMachine<M extends AsyncMachine<any>>(\n initial: M,\n onChange?: (m: M) => void\n) {\n let current = initial;\n\n async function dispatch<E extends Event<typeof current>>(event: E): Promise<M> {\n const fn = (current as any)[event.type];\n if (typeof fn !== 'function') {\n throw new Error(`[Machine] Unknown event type '${String(event.type)}' on current state.`);\n }\n const nextState = await fn.apply(current.context, event.args);\n current = nextState;\n onChange?.(current);\n return current;\n }\n\n return {\n /** Gets the context of the current state of the machine. */\n get state(): Context<M> {\n return current.context;\n },\n /** Dispatches a type-safe event to the machine, triggering a transition. */\n dispatch,\n };\n}\n\n/**\n * An optional base class for creating machines using an Object-Oriented style.\n *\n * This class provides the fundamental structure required by the library: a `context`\n * property to hold the state. By extending `MachineBase`, you get a clear and\n * type-safe starting point for defining states and transitions as classes and methods.\n *\n * Transitions should be implemented as methods that return a new instance of a\n * state machine class (often `new MyClass(...)` or by using a `createMachineBuilder`).\n * The `context` is marked `readonly` to enforce the immutable update pattern.\n *\n * @template C - The context object type that defines the state for this machine.\n *\n * @example\n * // Define a simple counter state\n * class Counter extends MachineBase<{ readonly count: number }> {\n * constructor(count = 0) {\n * super({ count });\n * }\n *\n * increment(): Counter {\n * // Return a new instance for the next state\n * return new Counter(this.context.count + 1);\n * }\n *\n * add(n: number): Counter {\n * return new Counter(this.context.count + n);\n * }\n * }\n *\n * const machine = new Counter(5);\n * const nextState = machine.increment(); // Returns a new Counter instance\n *\n * console.log(machine.context.count); // 5 (original is unchanged)\n * console.log(nextState.context.count); // 6 (new state)\n */\nexport class MachineBase<C extends object> {\n /**\n * The immutable state of the machine.\n * To change the state, a transition method must return a new machine instance\n * with a new context object.\n */\n public readonly context: C;\n\n /**\n * Initializes a new machine instance with its starting context.\n * @param context - The initial state of the machine.\n */\n constructor(context: C) {\n this.context = context;\n // Object.freeze can provide additional runtime safety against accidental mutation,\n // though it comes with a minor performance cost. It's a good practice for ensuring purity.\n // Object.freeze(this.context);\n }\n}\n\n\n/**\n * Applies an update function to a machine's context, returning a new machine.\n * This is a simpler alternative to `setContext` when you always use an updater function.\n *\n * @template C - The context object type.\n * @param m - The machine to update.\n * @param update - A function that takes the current context and returns the new context.\n * @returns A new machine with the updated context.\n *\n * @example\n * const updated = next(counter, (ctx) => ({ count: ctx.count + 1 }));\n */\nexport function next<C extends object>(\n m: Machine<C>,\n update: (ctx: Readonly<C>) => C\n): Machine<C> {\n const { context, ...transitions } = m;\n return createMachine(update(context), transitions) as Machine<C>;\n}\n\n/**\n * A type representing either a synchronous Machine or a Promise that resolves to a Machine.\n * Useful for functions that can return either sync or async machines.\n *\n * @template C - The context object type.\n *\n * @example\n * function getMachine(): MachineLike<{ count: number }> {\n * if (Math.random() > 0.5) {\n * return createMachine({ count: 0 }, { ... });\n * } else {\n * return Promise.resolve(createMachine({ count: 0 }, { ... }));\n * }\n * }\n */\nexport type MachineLike<C extends object> =\n | Machine<C>\n | Promise<Machine<C>>;\n\n/**\n * A type representing the result of a machine transition.\n * Can be either:\n * - A new machine state\n * - A tuple of [machine, cleanup function] where cleanup is called when leaving the state\n *\n * This enables state machines with side effects that need cleanup (e.g., subscriptions, timers).\n *\n * @template C - The context object type.\n *\n * @example\n * function transition(): MachineResult<{ count: number }> {\n * const interval = setInterval(() => console.log(\"tick\"), 1000);\n * const machine = createMachine({ count: 0 }, { ... });\n * return [machine, () => clearInterval(interval)];\n * }\n */\nexport type MachineResult<C extends object> =\n | Machine<C>\n | [Machine<C>, () => void | Promise<void>];\n\n\n// =============================================================================\n// SECTION: GENERATOR-BASED COMPOSITION\n// =============================================================================\n\nexport {\n run,\n step,\n yieldMachine,\n runSequence,\n createFlow,\n runWithDebug,\n runAsync,\n stepAsync\n} from './generators';\n", "/**\n * @file Generator-based state machine composition utilities.\n * @description\n * This module provides a generator-based approach to composing state machine transitions.\n * Instead of chaining method calls or using composition functions, you can write\n * imperative-style code using generators that feels like sequential, synchronous code\n * while maintaining the immutability and type safety of the state machine model.\n *\n * This pattern is particularly useful for:\n * - Multi-step workflows where each step depends on the previous\n * - Complex transition logic that would be unwieldy with chaining\n * - When you want imperative control flow (if/else, loops) with immutable state\n * - Testing scenarios where you want to control the flow step-by-step\n *\n * @example\n * ```typescript\n * const result = run(function* (machine) {\n * // Each yield passes control back and receives the next state\n * let m = yield* step(machine.increment());\n * m = yield* step(m.add(5));\n * if (m.context.count > 10) {\n * m = yield* step(m.reset());\n * }\n * return m.context.count;\n * }, initialMachine);\n * ```\n */\n\nimport { Machine } from './index';\n\n/**\n * Runs a generator-based state machine flow to completion.\n *\n * This function executes a generator that yields machine states and returns a final value.\n * Each yield passes the current machine state back to the generator, allowing you to\n * write imperative-style code while maintaining immutability.\n *\n * **How it works:**\n * 1. The generator function receives the initial machine\n * 2. Each `yield` expression produces a new machine state\n * 3. That state is sent back into the generator via `next()`\n * 4. The generator can use the received state for the next operation\n * 5. When the generator returns, that value is returned from `run()`\n *\n * **Key insight:** The generator doesn't mutate state—it yields new immutable states\n * at each step, creating a clear audit trail of state transitions.\n *\n * @template C - The context object type for the machine.\n * @template T - The return type of the generator (can be any type).\n *\n * @param flow - A generator function that receives a machine and yields machines,\n * eventually returning a value of type T.\n * @param initial - The initial machine state to start the flow.\n *\n * @returns The final value returned by the generator.\n *\n * @example Basic usage with counter\n * ```typescript\n * const counter = createMachine({ count: 0 }, {\n * increment: function() {\n * return createMachine({ count: this.count + 1 }, this);\n * },\n * add: function(n: number) {\n * return createMachine({ count: this.count + n }, this);\n * }\n * });\n *\n * const finalCount = run(function* (m) {\n * m = yield* step(m.increment()); // count: 1\n * m = yield* step(m.add(5)); // count: 6\n * m = yield* step(m.increment()); // count: 7\n * return m.context.count;\n * }, counter);\n *\n * console.log(finalCount); // 7\n * ```\n *\n * @example Conditional logic\n * ```typescript\n * const result = run(function* (m) {\n * m = yield* step(m.increment());\n *\n * if (m.context.count > 5) {\n * m = yield* step(m.reset());\n * } else {\n * m = yield* step(m.add(10));\n * }\n *\n * return m;\n * }, counter);\n * ```\n *\n * @example Loops and accumulation\n * ```typescript\n * const sum = run(function* (m) {\n * let total = 0;\n *\n * for (let i = 0; i < 5; i++) {\n * m = yield* step(m.increment());\n * total += m.context.count;\n * }\n *\n * return total;\n * }, counter);\n * ```\n *\n * @example Error handling\n * ```typescript\n * const result = run(function* (m) {\n * try {\n * m = yield* step(m.riskyOperation());\n * m = yield* step(m.processResult());\n * } catch (error) {\n * m = yield* step(m.handleError(error));\n * }\n * return m;\n * }, machine);\n * ```\n */\nexport function run<C extends object, T>(\n flow: (m: Machine<C>) => Generator<Machine<C>, T, Machine<C>>,\n initial: Machine<C>\n): T {\n // Create the generator by calling the flow function with the initial machine\n const generator = flow(initial);\n\n // Track the current machine state as we iterate\n let current = initial;\n\n // Iterate the generator until completion\n while (true) {\n // Send the current machine state into the generator and get the next yielded value\n // The generator receives `current` as the result of its last yield expression\n const { value, done } = generator.next(current);\n\n // If the generator has returned (done), we have our final value\n if (done) {\n return value;\n }\n\n // Otherwise, the yielded value becomes our new current state\n // This state will be sent back into the generator on the next iteration\n current = value;\n }\n}\n\n/**\n * A helper function to yield a machine state and receive the next state back.\n *\n * This function creates a mini-generator that yields the provided machine and\n * returns whatever value the outer runner sends back. It's designed to be used\n * with `yield*` (yield delegation) inside your main generator.\n *\n * **Why use this helper?**\n * - Makes the intent clear: \"step to this state\"\n * - Provides a consistent API for state transitions\n * - Enables type inference for the received state\n * - Works seamlessly with the `run()` function\n *\n * **What `yield*` does:**\n * `yield*` delegates to another generator. When you write `yield* step(m)`,\n * control passes to the `step` generator, which yields `m`, then returns the\n * value sent back by the runner.\n *\n * @template C - The context object type for the machine.\n *\n * @param m - The machine state to yield.\n *\n * @returns A generator that yields the machine and returns the received state.\n *\n * @example Basic stepping\n * ```typescript\n * run(function* (machine) {\n * // Yield this state and receive the next one\n * const next = yield* step(machine.increment());\n * console.log(next.context.count);\n * return next;\n * }, counter);\n * ```\n *\n * @example Without step (more verbose)\n * ```typescript\n * run(function* (machine) {\n * // This is what step() does internally\n * const next = yield machine.increment();\n * return next;\n * }, counter);\n * ```\n *\n * @example Chaining with step\n * ```typescript\n * run(function* (m) {\n * m = yield* step(m.action1());\n * m = yield* step(m.action2());\n * m = yield* step(m.action3());\n * return m;\n * }, machine);\n * ```\n */\nexport function step<C extends object>(\n m: Machine<C>\n): Generator<Machine<C>, Machine<C>, Machine<C>> {\n // Create an immediately-invoked generator that:\n // 1. Yields the provided machine\n // 2. Receives a value back (the next state)\n // 3. Returns that received value\n return (function* () {\n const received = yield m;\n return received;\n })();\n}\n\n/**\n * Alternative to `step` that doesn't require `yield*`.\n * This is semantically identical but uses direct yielding.\n *\n * Use this if you prefer the simpler syntax without delegation.\n *\n * @template C - The context object type.\n * @param m - The machine to yield.\n * @returns The same machine (passed through).\n *\n * @example\n * ```typescript\n * run(function* (m) {\n * m = yield m.increment(); // No yield* needed\n * m = yield m.add(5);\n * return m;\n * }, counter);\n * ```\n */\nexport function yieldMachine<C extends object>(m: Machine<C>): Machine<C> {\n return m;\n}\n\n/**\n * Runs multiple generator flows in sequence, passing the result of each to the next.\n *\n * This is useful for composing multiple generator-based workflows into a pipeline.\n *\n * @template C - The context object type.\n * @param initial - The initial machine state.\n * @param flows - An array of generator functions to run in sequence.\n * @returns The final machine state after all flows complete.\n *\n * @example\n * ```typescript\n * const flow1 = function* (m: Machine<{ count: number }>) {\n * m = yield* step(m.increment());\n * return m;\n * };\n *\n * const flow2 = function* (m: Machine<{ count: number }>) {\n * m = yield* step(m.add(5));\n * return m;\n * };\n *\n * const result = runSequence(counter, [flow1, flow2]);\n * console.log(result.context.count); // 6\n * ```\n */\nexport function runSequence<C extends object>(\n initial: Machine<C>,\n flows: Array<(m: Machine<C>) => Generator<Machine<C>, Machine<C>, Machine<C>>>\n): Machine<C> {\n return flows.reduce((machine, flow) => {\n return run(flow, machine);\n }, initial);\n}\n\n/**\n * Creates a reusable generator flow that can be composed into other flows.\n *\n * This allows you to define common state machine patterns as reusable building blocks.\n *\n * @template C - The context object type.\n * @param flow - A generator function representing a reusable flow.\n * @returns A function that can be used with `yield*` in other generators.\n *\n * @example\n * ```typescript\n * // Define a reusable flow\n * const incrementThrice = createFlow(function* (m: Machine<{ count: number }>) {\n * m = yield* step(m.increment());\n * m = yield* step(m.increment());\n * m = yield* step(m.increment());\n * return m;\n * });\n *\n * // Use it in another flow\n * const result = run(function* (m) {\n * m = yield* incrementThrice(m);\n * m = yield* step(m.add(10));\n * return m;\n * }, counter);\n * ```\n */\nexport function createFlow<C extends object>(\n flow: (m: Machine<C>) => Generator<Machine<C>, Machine<C>, Machine<C>>\n): (m: Machine<C>) => Generator<Machine<C>, Machine<C>, Machine<C>> {\n return flow;\n}\n\n/**\n * Runs a generator flow with debugging output at each step.\n *\n * This is useful for understanding the state transitions in your flow.\n *\n * @template C - The context object type.\n * @template T - The return type.\n * @param flow - The generator function to run.\n * @param initial - The initial machine state.\n * @param logger - Optional custom logger function.\n * @returns The final value from the generator.\n *\n * @example\n * ```typescript\n * const result = runWithDebug(function* (m) {\n * m = yield* step(m.increment());\n * m = yield* step(m.add(5));\n * return m.context.count;\n * }, counter);\n *\n * // Output:\n * // Step 0: { count: 0 }\n * // Step 1: { count: 1 }\n * // Step 2: { count: 6 }\n * // Final: 6\n * ```\n */\nexport function runWithDebug<C extends object, T>(\n flow: (m: Machine<C>) => Generator<Machine<C>, T, Machine<C>>,\n initial: Machine<C>,\n logger: (step: number, machine: Machine<C>) => void = (step, m) => {\n console.log(`Step ${step}:`, m.context);\n }\n): T {\n const generator = flow(initial);\n let current = initial;\n let stepCount = 0;\n\n logger(stepCount, current);\n\n while (true) {\n const { value, done } = generator.next(current);\n\n if (done) {\n console.log('Final:', value);\n return value;\n }\n\n current = value;\n stepCount++;\n logger(stepCount, current);\n }\n}\n\n// =============================================================================\n// ASYNC GENERATOR SUPPORT\n// =============================================================================\n\n/**\n * Async version of `run` for async state machines.\n *\n * This allows you to use async/await inside your generator flows while maintaining\n * the same compositional benefits.\n *\n * @template C - The context object type.\n * @template T - The return type.\n * @param flow - An async generator function.\n * @param initial - The initial machine state.\n * @returns A promise that resolves to the final value.\n *\n * @example\n * ```typescript\n * const result = await runAsync(async function* (m) {\n * m = yield* stepAsync(await m.fetchData());\n * m = yield* stepAsync(await m.processData());\n * return m.context;\n * }, asyncMachine);\n * ```\n */\nexport async function runAsync<C extends object, T>(\n flow: (m: Machine<C>) => AsyncGenerator<Machine<C>, T, Machine<C>>,\n initial: Machine<C>\n): Promise<T> {\n const generator = flow(initial);\n let current = initial;\n\n while (true) {\n const { value, done } = await generator.next(current);\n\n if (done) {\n return value;\n }\n\n current = value;\n }\n}\n\n/**\n * Async version of `step` for async generators.\n *\n * @template C - The context object type.\n * @param m - The machine to yield.\n * @returns An async generator.\n *\n * @example\n * ```typescript\n * await runAsync(async function* (m) {\n * m = yield* stepAsync(await m.asyncOperation());\n * return m;\n * }, machine);\n * ```\n */\nexport async function* stepAsync<C extends object>(\n m: Machine<C>\n): AsyncGenerator<Machine<C>, Machine<C>, Machine<C>> {\n const received = yield m;\n return received;\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACuHO,SAAS,IACd,MACA,SACG;AAEH,QAAM,YAAY,KAAK,OAAO;AAG9B,MAAI,UAAU;AAGd,SAAO,MAAM;AAGX,UAAM,EAAE,OAAO,KAAK,IAAI,UAAU,KAAK,OAAO;AAG9C,QAAI,MAAM;AACR,aAAO;AAAA,IACT;AAIA,cAAU;AAAA,EACZ;AACF;AAuDO,SAAS,KACd,GAC+C;AAK/C,SAAQ,aAAa;AACnB,UAAM,WAAW,MAAM;AACvB,WAAO;AAAA,EACT,EAAG;AACL;AAqBO,SAAS,aAA+B,GAA2B;AACxE,SAAO;AACT;AA4BO,SAAS,YACd,SACA,OACY;AACZ,SAAO,MAAM,OAAO,CAAC,SAAS,SAAS;AACrC,WAAO,IAAI,MAAM,OAAO;AAAA,EAC1B,GAAG,OAAO;AACZ;AA6BO,SAAS,WACd,MACkE;AAClE,SAAO;AACT;AA6BO,SAAS,aACd,MACA,SACA,SAAsD,CAACA,OAAM,MAAM;AACjE,UAAQ,IAAI,QAAQA,KAAI,KAAK,EAAE,OAAO;AACxC,GACG;AACH,QAAM,YAAY,KAAK,OAAO;AAC9B,MAAI,UAAU;AACd,MAAI,YAAY;AAEhB,SAAO,WAAW,OAAO;AAEzB,SAAO,MAAM;AACX,UAAM,EAAE,OAAO,KAAK,IAAI,UAAU,KAAK,OAAO;AAE9C,QAAI,MAAM;AACR,cAAQ,IAAI,UAAU,KAAK;AAC3B,aAAO;AAAA,IACT;AAEA,cAAU;AACV;AACA,WAAO,WAAW,OAAO;AAAA,EAC3B;AACF;AA2BA,eAAsB,SACpB,MACA,SACY;AACZ,QAAM,YAAY,KAAK,OAAO;AAC9B,MAAI,UAAU;AAEd,SAAO,MAAM;AACX,UAAM,EAAE,OAAO,KAAK,IAAI,MAAM,UAAU,KAAK,OAAO;AAEpD,QAAI,MAAM;AACR,aAAO;AAAA,IACT;AAEA,cAAU;AAAA,EACZ;AACF;AAiBA,gBAAuB,UACrB,GACoD;AACpD,QAAM,WAAW,MAAM;AACvB,SAAO;AACT;;;ADpSO,SAAS,cACd,SACA,KACoB;AACpB,SAAO,OAAO,OAAO,EAAE,QAAQ,GAAG,GAAG;AACvC;AAUO,SAAS,mBACd,SACA,KACoB;AACpB,SAAO,OAAO,OAAO,EAAE,QAAQ,GAAG,GAAG;AACvC;AAmBO,SAAS,uBAAyC;AACvD,SAAO,CACL,iBACG;AAQH,UAAM,MAAM,OAAO;AAAA,MACjB,OAAO,QAAQ,YAAY,EAAE,IAAI,CAAC,CAAC,KAAK,SAAS,MAAM;AAAA,QACrD;AAAA,QACA,YAAsB,MAAa;AACjC,gBAAM,aAAc,UAAkB,MAAM,GAAG,IAAI;AACnD,iBAAO,cAAc,YAAY,GAAU;AAAA,QAC7C;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO,CAAC,mBAA+C;AACrD,aAAO,cAAc,gBAAgB,GAAG;AAAA,IAC1C;AAAA,EACF;AACF;AAgBO,SAAS,WACd,SACA,gBACG;AACH,QAAM,EAAE,SAAS,GAAG,YAAY,IAAI;AACpC,QAAM,aACJ,OAAO,mBAAmB,aACrB,eAA6D,OAAO,IACrE;AAEN,SAAO,cAAc,YAAY,WAAW;AAC9C;AAYO,SAAS,oBAId,SACA,WACyD;AACzD,QAAM,EAAE,SAAS,GAAG,oBAAoB,IAAI;AAC5C,QAAM,iBAAiB,EAAE,GAAG,qBAAqB,GAAG,UAAU;AAC9D,SAAO,cAAc,SAAS,cAAc;AAC9C;AAaO,SAAS,kBAKd,SAAY,gBAA0B;AACtC,QAAM,EAAE,SAAS,GAAG,oBAAoB,IAAI;AAC5C,QAAM,sBAAsB,EAAE,GAAG,qBAAqB,GAAG,eAAe;AACxE,SAAO,cAAc,SAAS,mBAAmB;AACnD;AAWO,SAAS,qBACd,iBAC4B;AAC5B,QAAM,EAAE,SAAS,GAAG,YAAY,IAAI;AACpC,SAAO,CAAC,eAA8B;AACpC,WAAO,cAAc,YAAY,WAAW;AAAA,EAC9C;AACF;AA0BO,SAAS,aAKd,SACA,iBACA,UAGG;AACH,QAAM,eAAe,QAAQ,QAAQ,eAAe;AACpD,QAAM,UAAU,SAAS,YAAY;AACrC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,+BAA+B,OAAO,YAAY,CAAC,EAAE;AAAA,EACvE;AACA,SAAO,QAAQ,QAAQ,OAAO;AAChC;AAmBO,SAAS,SAKd,SACA,KACA,OAC0D;AAC1D,SAAO,QAAQ,QAAQ,GAAG,MAAM;AAClC;AAgBO,SAAS,WACd,SACA,UACA;AACA,MAAI,UAAU;AAEd,iBAAe,SAA0C,OAAsB;AAC7E,UAAM,KAAM,QAAgB,MAAM,IAAI;AACtC,QAAI,OAAO,OAAO,YAAY;AAC5B,YAAM,IAAI,MAAM,iCAAiC,OAAO,MAAM,IAAI,CAAC,qBAAqB;AAAA,IAC1F;AACA,UAAM,YAAY,MAAM,GAAG,MAAM,QAAQ,SAAS,MAAM,IAAI;AAC5D,cAAU;AACV,yCAAW;AACX,WAAO;AAAA,EACT;AAEA,SAAO;AAAA;AAAA,IAEL,IAAI,QAAoB;AACtB,aAAO,QAAQ;AAAA,IACjB;AAAA;AAAA,IAEA;AAAA,EACF;AACF;AAsCO,IAAM,cAAN,MAAoC;AAAA;AAAA;AAAA;AAAA;AAAA,EAYzC,YAAY,SAAY;AACtB,SAAK,UAAU;AAAA,EAIjB;AACF;AAeO,SAAS,KACd,GACA,QACY;AACZ,QAAM,EAAE,SAAS,GAAG,YAAY,IAAI;AACpC,SAAO,cAAc,OAAO,OAAO,GAAG,WAAW;AACnD;",
|
|
6
|
-
"names": ["step"]
|
|
3
|
+
"sources": ["../../../src/index.ts", "../../../src/generators.ts", "../../../src/primitives.ts", "../../../src/extract.ts", "../../../src/runtime-extract.ts", "../../../src/multi.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * @file A tiny, immutable, and type-safe state machine library for TypeScript.\n * @author doeixd\n * @version 1.0.0\n */\n\n// =============================================================================\n// SECTION: CORE TYPES & INTERFACES\n// =============================================================================\n\n/**\n * A utility type that represents either a value of type T or a Promise that resolves to T.\n * @template T - The value type.\n */\nexport type MaybePromise<T> = T | Promise<T>;\n\n/**\n * The fundamental shape of any machine: a `context` object for state, and methods for transitions.\n * @template C - The context (state) object type.\n */\nexport type Machine<C extends object> = {\n /** The readonly state of the machine. */\n readonly context: C;\n} & Record<string, (...args: any[]) => Machine<any>>;\n\n/**\n * The shape of an asynchronous machine, where transitions can return Promises.\n * @template C - The context (state) object type.\n */\nexport type AsyncMachine<C extends object> = {\n /** The readonly state of the machine. */\n readonly context: C;\n} & Record<string, (...args: any[]) => MaybePromise<AsyncMachine<any>>>;\n\n\n// =============================================================================\n// SECTION: TYPE UTILITIES & INTROSPECTION\n// =============================================================================\n\n/**\n * Extracts the context type `C` from a machine type `M`.\n * @template M - The machine type.\n * @example type Ctx = Context<Machine<{ count: number }>> // { count: number }\n */\nexport type Context<M extends { context: any }> = M[\"context\"];\n\n/**\n * Extracts the transition function signatures from a machine, excluding the context property.\n * @template M - The machine type.\n */\nexport type Transitions<M extends BaseMachine<any>> = Omit<M, \"context\">;\n\n/**\n * Extracts the argument types for a specific transition function in a Machine.\n * @template M - The machine type.\n * @template K - The transition function name.\n */\nexport type TransitionArgs<M extends Machine<any>, K extends keyof M & string> =\n M[K] extends (...args: infer A) => any ? A : never;\n\n/**\n * Extracts the names of all transitions as a string union type.\n * @template M - The machine type.\n * @example\n * type Names = TransitionNames<Machine<{ count: number }> & { increment: () => any }>\n * // Names = \"increment\"\n */\nexport type TransitionNames<M extends BaseMachine<any>> = keyof Omit<M, \"context\"> & string;\n\n/**\n * Base machine type that both Machine and AsyncMachine extend from.\n * @template C - The context object type.\n */\nexport type BaseMachine<C extends object> = {\n /** The readonly state of the machine. */\n readonly context: C;\n} & Record<string, (...args: any[]) => any>;\n\n/**\n * Helper to make a type deeply readonly (freezes nested objects).\n * Useful for ensuring immutability of context at the type level.\n * @template T - The type to make readonly.\n */\nexport type DeepReadonly<T> = {\n readonly [P in keyof T]: T[P] extends object\n ? T[P] extends (...args: any[]) => any\n ? T[P]\n : DeepReadonly<T[P]>\n : T[P];\n};\n\n/**\n * Infers the machine type from a machine factory function.\n * @template F - The factory function type.\n * @example\n * const factory = () => createMachine({ count: 0 }, { ... });\n * type MyMachine = InferMachine<typeof factory>; // Extracts the return type\n */\nexport type InferMachine<F extends (...args: any[]) => any> = ReturnType<F>;\n\n/**\n * A discriminated union type representing an event that can be dispatched to a machine.\n * This is automatically generated from a machine's type signature, ensuring full type safety.\n * @template M - The machine type.\n * @example\n * type CounterEvent = Event<Machine<{ count: number }>& { add: (n: number) => any }>\n * // CounterEvent = { type: \"add\"; args: [number] }\n */\nexport type Event<M extends BaseMachine<any>> = {\n [K in keyof Omit<M, \"context\"> & string]: M[K] extends (...args: infer A) => any\n ? { type: K; args: A }\n : never\n}[keyof Omit<M, \"context\"> & string];\n\n\n// =============================================================================\n// SECTION: MACHINE CREATION (FUNCTIONAL & OOP)\n// =============================================================================\n\n/**\n * Creates a synchronous state machine from a context and transition functions.\n * This is the core factory for the functional approach.\n *\n * @template C - The context object type.\n * @param context - The initial state context.\n * @param fns - An object containing transition function definitions.\n * @returns A new machine instance.\n */\nexport function createMachine<C extends object, T extends Record<string, (this: C, ...args: any[]) => any>>(\n context: C,\n fns: T\n): { context: C } & T {\n return Object.assign({ context }, fns);\n}\n\n/**\n * Creates an asynchronous state machine from a context and async transition functions.\n *\n * @template C - The context object type.\n * @param context - The initial state context.\n * @param fns - An object containing async transition function definitions.\n * @returns A new async machine instance.\n */\nexport function createAsyncMachine<C extends object, T extends Record<string, (this: C, ...args: any[]) => any>>(\n context: C,\n fns: T\n): { context: C } & T {\n return Object.assign({ context }, fns);\n}\n\n/**\n * Creates a machine factory - a higher-order function that simplifies machine creation.\n * Instead of writing transition logic that creates new machines, you just write\n * pure context transformation functions.\n *\n * @template C - The context object type.\n * @returns A factory configurator function.\n *\n * @example\n * const counterFactory = createMachineFactory<{ count: number }>()({\n * increment: (ctx) => ({ count: ctx.count + 1 }),\n * add: (ctx, n: number) => ({ count: ctx.count + n })\n * });\n *\n * const counter = counterFactory({ count: 0 });\n * const next = counter.increment(); // Returns new machine with count: 1\n */\nexport function createMachineFactory<C extends object>() {\n return <T extends Record<string, (ctx: C, ...args: any[]) => C>>(\n transformers: T\n ) => {\n type MachineFns = {\n [K in keyof T]: (\n this: C,\n ...args: T[K] extends (ctx: C, ...args: infer A) => C ? A : never\n ) => Machine<C>;\n };\n\n const fns = Object.fromEntries(\n Object.entries(transformers).map(([key, transform]) => [\n key,\n function (this: C, ...args: any[]) {\n const newContext = (transform as any)(this, ...args);\n return createMachine(newContext, fns as any);\n },\n ])\n ) as MachineFns;\n\n return (initialContext: C): Machine<C> & MachineFns => {\n return createMachine(initialContext, fns);\n };\n };\n}\n\n\n// =============================================================================\n// SECTION: ADVANCED CREATION & IMMUTABLE HELPERS\n// =============================================================================\n\n/**\n * Creates a new machine instance with an updated context, preserving all original transitions.\n * This is the primary, type-safe utility for applying state changes.\n *\n * @template M - The machine type.\n * @param machine - The original machine instance.\n * @param newContextOrFn - The new context object or an updater function.\n * @returns A new machine instance of the same type with the updated context.\n */\nexport function setContext<M extends Machine<any>>(\n machine: M,\n newContextOrFn: Context<M> | ((ctx: Readonly<Context<M>>) => Context<M>)\n): M {\n const { context, ...transitions } = machine;\n const newContext =\n typeof newContextOrFn === \"function\"\n ? (newContextOrFn as (ctx: Readonly<Context<M>>) => Context<M>)(context)\n : newContextOrFn;\n\n return createMachine(newContext, transitions) as M;\n}\n\n/**\n * Creates a new machine by overriding or adding transition functions to an existing machine.\n * Ideal for mocking in tests or decorating functionality. The original machine is unchanged.\n *\n * @template M - The original machine type.\n * @template T - An object of new or overriding transition functions.\n * @param machine - The base machine instance.\n * @param overrides - An object containing the transitions to add or overwrite.\n * @returns A new machine instance with the merged transitions.\n */\nexport function overrideTransitions<\n M extends Machine<any>,\n T extends Record<string, (this: Context<M>, ...args: any[]) => any>\n>(\n machine: M,\n overrides: T\n): Machine<Context<M>> & Omit<Transitions<M>, keyof T> & T {\n const { context, ...originalTransitions } = machine;\n const newTransitions = { ...originalTransitions, ...overrides };\n return createMachine(context, newTransitions) as any;\n}\n\n/**\n * Creates a new machine by adding new transition functions.\n * This utility will produce a compile-time error if you attempt to add a\n * transition that already exists, preventing accidental overrides.\n *\n * @template M - The original machine type.\n * @template T - An object of new transition functions, whose keys must not exist in M.\n * @param machine - The base machine instance.\n * @param newTransitions - An object containing the new transitions to add.\n * @returns A new machine instance with the combined original and new transitions.\n */\nexport function extendTransitions<\n M extends Machine<any>,\n T extends Record<string, (this: Context<M>, ...args: any[]) => any> & {\n [K in keyof T]: K extends keyof M ? never : T[K];\n }\n>(machine: M, newTransitions: T): M & T {\n const { context, ...originalTransitions } = machine;\n const combinedTransitions = { ...originalTransitions, ...newTransitions };\n return createMachine(context, combinedTransitions) as M & T;\n}\n\n/**\n * Creates a builder function from a \"template\" machine instance.\n * This captures the behavior of a machine and returns a factory that can stamp out\n * new instances with different initial contexts. Excellent for class-based machines.\n *\n * @template M - The machine type.\n * @param templateMachine - An instance of a machine to use as the template.\n * @returns A function that builds new machines of type M.\n */\nexport function createMachineBuilder<M extends Machine<any>>(\n templateMachine: M\n): (context: Context<M>) => M {\n const { context, ...transitions } = templateMachine;\n return (newContext: Context<M>): M => {\n return createMachine(newContext, transitions) as M;\n };\n}\n\n/**\n * Pattern match on a machine's state based on a discriminant property in the context.\n * This provides type-safe exhaustive matching for state machines.\n *\n * @template M - The machine type.\n * @template K - The discriminant key in the context.\n * @template R - The return type.\n * @param machine - The machine to match against.\n * @param discriminantKey - The key in the context to use for matching (e.g., \"status\").\n * @param handlers - An object mapping each possible value to a handler function.\n * @returns The result of the matched handler.\n *\n * @example\n * const result = matchMachine(\n * machine,\n * 'status',\n * {\n * idle: (ctx) => \"Machine is idle\",\n * loading: (ctx) => \"Loading...\",\n * success: (ctx) => `Success: ${ctx.data}`,\n * error: (ctx) => `Error: ${ctx.error}`\n * }\n * );\n */\nexport function matchMachine<\n M extends Machine<any>,\n K extends keyof Context<M> & string,\n R\n>(\n machine: M,\n discriminantKey: K,\n handlers: {\n [V in Context<M>[K] & string]: (ctx: Context<M>) => R;\n }\n): R {\n const discriminant = machine.context[discriminantKey] as Context<M>[K] & string;\n const handler = handlers[discriminant];\n if (!handler) {\n throw new Error(`No handler found for state: ${String(discriminant)}`);\n }\n return handler(machine.context);\n}\n\n/**\n * Type-safe helper to assert that a machine's context has a specific discriminant value.\n * This narrows the type of the context based on the discriminant.\n *\n * @template M - The machine type.\n * @template K - The discriminant key.\n * @template V - The discriminant value.\n * @param machine - The machine to check.\n * @param key - The discriminant key to check.\n * @param value - The expected value.\n * @returns True if the discriminant matches, with type narrowing.\n *\n * @example\n * if (hasState(machine, 'status', 'loading')) {\n * // machine.context.status is narrowed to 'loading'\n * }\n */\nexport function hasState<\n M extends Machine<any>,\n K extends keyof Context<M>,\n V extends Context<M>[K]\n>(\n machine: M,\n key: K,\n value: V\n): machine is M & { context: Context<M> & { [P in K]: V } } {\n return machine.context[key] === value;\n}\n\n\n// =============================================================================\n// SECTION: RUNTIME & EVENT DISPATCHER\n// =============================================================================\n\n/**\n * Runs an asynchronous state machine with a managed lifecycle and event dispatch capability.\n * This is the \"interpreter\" for async machines, handling state updates and side effects.\n *\n * @template M - The initial machine type.\n * @param initial - The initial machine state.\n * @param onChange - Optional callback invoked with the new machine state after every transition.\n * @returns An object with a `state` getter for the current context and an async `dispatch` function.\n */\nexport function runMachine<M extends AsyncMachine<any>>(\n initial: M,\n onChange?: (m: M) => void\n) {\n let current = initial;\n\n async function dispatch<E extends Event<typeof current>>(event: E): Promise<M> {\n const fn = (current as any)[event.type];\n if (typeof fn !== 'function') {\n throw new Error(`[Machine] Unknown event type '${String(event.type)}' on current state.`);\n }\n const nextState = await fn.apply(current.context, event.args);\n current = nextState;\n onChange?.(current);\n return current;\n }\n\n return {\n /** Gets the context of the current state of the machine. */\n get state(): Context<M> {\n return current.context;\n },\n /** Dispatches a type-safe event to the machine, triggering a transition. */\n dispatch,\n };\n}\n\n/**\n * An optional base class for creating machines using an Object-Oriented style.\n *\n * This class provides the fundamental structure required by the library: a `context`\n * property to hold the state. By extending `MachineBase`, you get a clear and\n * type-safe starting point for defining states and transitions as classes and methods.\n *\n * Transitions should be implemented as methods that return a new instance of a\n * state machine class (often `new MyClass(...)` or by using a `createMachineBuilder`).\n * The `context` is marked `readonly` to enforce the immutable update pattern.\n *\n * @template C - The context object type that defines the state for this machine.\n *\n * @example\n * // Define a simple counter state\n * class Counter extends MachineBase<{ readonly count: number }> {\n * constructor(count = 0) {\n * super({ count });\n * }\n *\n * increment(): Counter {\n * // Return a new instance for the next state\n * return new Counter(this.context.count + 1);\n * }\n *\n * add(n: number): Counter {\n * return new Counter(this.context.count + n);\n * }\n * }\n *\n * const machine = new Counter(5);\n * const nextState = machine.increment(); // Returns a new Counter instance\n *\n * console.log(machine.context.count); // 5 (original is unchanged)\n * console.log(nextState.context.count); // 6 (new state)\n */\nexport class MachineBase<C extends object> {\n /**\n * The immutable state of the machine.\n * To change the state, a transition method must return a new machine instance\n * with a new context object.\n */\n public readonly context: C;\n\n /**\n * Initializes a new machine instance with its starting context.\n * @param context - The initial state of the machine.\n */\n constructor(context: C) {\n this.context = context;\n // Object.freeze can provide additional runtime safety against accidental mutation,\n // though it comes with a minor performance cost. It's a good practice for ensuring purity.\n // Object.freeze(this.context);\n }\n}\n\n\n/**\n * Applies an update function to a machine's context, returning a new machine.\n * This is a simpler alternative to `setContext` when you always use an updater function.\n *\n * @template C - The context object type.\n * @param m - The machine to update.\n * @param update - A function that takes the current context and returns the new context.\n * @returns A new machine with the updated context.\n *\n * @example\n * const updated = next(counter, (ctx) => ({ count: ctx.count + 1 }));\n */\nexport function next<C extends object>(\n m: Machine<C>,\n update: (ctx: Readonly<C>) => C\n): Machine<C> {\n const { context, ...transitions } = m;\n return createMachine(update(context), transitions) as Machine<C>;\n}\n\n/**\n * A type representing either a synchronous Machine or a Promise that resolves to a Machine.\n * Useful for functions that can return either sync or async machines.\n *\n * @template C - The context object type.\n *\n * @example\n * function getMachine(): MachineLike<{ count: number }> {\n * if (Math.random() > 0.5) {\n * return createMachine({ count: 0 }, { ... });\n * } else {\n * return Promise.resolve(createMachine({ count: 0 }, { ... }));\n * }\n * }\n */\nexport type MachineLike<C extends object> =\n | Machine<C>\n | Promise<Machine<C>>;\n\n/**\n * A type representing the result of a machine transition.\n * Can be either:\n * - A new machine state\n * - A tuple of [machine, cleanup function] where cleanup is called when leaving the state\n *\n * This enables state machines with side effects that need cleanup (e.g., subscriptions, timers).\n *\n * @template C - The context object type.\n *\n * @example\n * function transition(): MachineResult<{ count: number }> {\n * const interval = setInterval(() => console.log(\"tick\"), 1000);\n * const machine = createMachine({ count: 0 }, { ... });\n * return [machine, () => clearInterval(interval)];\n * }\n */\nexport type MachineResult<C extends object> =\n | Machine<C>\n | [Machine<C>, () => void | Promise<void>];\n\n\n// =============================================================================\n// SECTION: GENERATOR-BASED COMPOSITION\n// =============================================================================\n\nexport {\n run,\n step,\n yieldMachine,\n runSequence,\n createFlow,\n runWithDebug,\n runAsync,\n stepAsync\n} from './generators';\n\n// =============================================================================\n// SECTION: TYPE-LEVEL METADATA PRIMITIVES\n// =============================================================================\n\nexport {\n transitionTo,\n describe,\n guarded,\n invoke,\n action,\n metadata,\n META_KEY,\n type TransitionMeta,\n type GuardMeta,\n type InvokeMeta,\n type ActionMeta,\n type ClassConstructor,\n type WithMeta\n} from './primitives';\n\n// =============================================================================\n// SECTION: STATECHART EXTRACTION\n// =============================================================================\n\nexport {\n extractMachine,\n extractMachines,\n generateChart,\n type MachineConfig,\n type ExtractionConfig\n} from './extract';\n\n// =============================================================================\n// SECTION: RUNTIME EXTRACTION\n// =============================================================================\n\nexport {\n extractFunctionMetadata,\n extractStateNode,\n generateStatechart,\n extractFromInstance\n} from './runtime-extract';\n\n// Export runtime metadata symbol and type (for advanced use)\nexport { RUNTIME_META, type RuntimeTransitionMeta } from './primitives';\n\n\nexport * from './multi'", "/**\n * @file Generator-based state machine composition utilities.\n * @description\n * This module provides a generator-based approach to composing state machine transitions.\n * Instead of chaining method calls or using composition functions, you can write\n * imperative-style code using generators that feels like sequential, synchronous code\n * while maintaining the immutability and type safety of the state machine model.\n *\n * This pattern is particularly useful for:\n * - Multi-step workflows where each step depends on the previous\n * - Complex transition logic that would be unwieldy with chaining\n * - When you want imperative control flow (if/else, loops) with immutable state\n * - Testing scenarios where you want to control the flow step-by-step\n *\n * @example\n * ```typescript\n * const result = run(function* (machine) {\n * // Each yield passes control back and receives the next state\n * let m = yield* step(machine.increment());\n * m = yield* step(m.add(5));\n * if (m.context.count > 10) {\n * m = yield* step(m.reset());\n * }\n * return m.context.count;\n * }, initialMachine);\n * ```\n */\n\nimport { Machine } from './index';\n\n/**\n * Runs a generator-based state machine flow to completion.\n *\n * This function executes a generator that yields machine states and returns a final value.\n * Each yield passes the current machine state back to the generator, allowing you to\n * write imperative-style code while maintaining immutability.\n *\n * **How it works:**\n * 1. The generator function receives the initial machine\n * 2. Each `yield` expression produces a new machine state\n * 3. That state is sent back into the generator via `next()`\n * 4. The generator can use the received state for the next operation\n * 5. When the generator returns, that value is returned from `run()`\n *\n * **Key insight:** The generator doesn't mutate state—it yields new immutable states\n * at each step, creating a clear audit trail of state transitions.\n *\n * @template C - The context object type for the machine.\n * @template T - The return type of the generator (can be any type).\n *\n * @param flow - A generator function that receives a machine and yields machines,\n * eventually returning a value of type T.\n * @param initial - The initial machine state to start the flow.\n *\n * @returns The final value returned by the generator.\n *\n * @example Basic usage with counter\n * ```typescript\n * const counter = createMachine({ count: 0 }, {\n * increment: function() {\n * return createMachine({ count: this.count + 1 }, this);\n * },\n * add: function(n: number) {\n * return createMachine({ count: this.count + n }, this);\n * }\n * });\n *\n * const finalCount = run(function* (m) {\n * m = yield* step(m.increment()); // count: 1\n * m = yield* step(m.add(5)); // count: 6\n * m = yield* step(m.increment()); // count: 7\n * return m.context.count;\n * }, counter);\n *\n * console.log(finalCount); // 7\n * ```\n *\n * @example Conditional logic\n * ```typescript\n * const result = run(function* (m) {\n * m = yield* step(m.increment());\n *\n * if (m.context.count > 5) {\n * m = yield* step(m.reset());\n * } else {\n * m = yield* step(m.add(10));\n * }\n *\n * return m;\n * }, counter);\n * ```\n *\n * @example Loops and accumulation\n * ```typescript\n * const sum = run(function* (m) {\n * let total = 0;\n *\n * for (let i = 0; i < 5; i++) {\n * m = yield* step(m.increment());\n * total += m.context.count;\n * }\n *\n * return total;\n * }, counter);\n * ```\n *\n * @example Error handling\n * ```typescript\n * const result = run(function* (m) {\n * try {\n * m = yield* step(m.riskyOperation());\n * m = yield* step(m.processResult());\n * } catch (error) {\n * m = yield* step(m.handleError(error));\n * }\n * return m;\n * }, machine);\n * ```\n */\nexport function run<C extends object, T>(\n flow: (m: Machine<C>) => Generator<Machine<C>, T, Machine<C>>,\n initial: Machine<C>\n): T {\n // Create the generator by calling the flow function with the initial machine\n const generator = flow(initial);\n\n // Track the current machine state as we iterate\n let current = initial;\n\n // Iterate the generator until completion\n while (true) {\n // Send the current machine state into the generator and get the next yielded value\n // The generator receives `current` as the result of its last yield expression\n const { value, done } = generator.next(current);\n\n // If the generator has returned (done), we have our final value\n if (done) {\n return value;\n }\n\n // Otherwise, the yielded value becomes our new current state\n // This state will be sent back into the generator on the next iteration\n current = value;\n }\n}\n\n/**\n * A helper function to yield a machine state and receive the next state back.\n *\n * This function creates a mini-generator that yields the provided machine and\n * returns whatever value the outer runner sends back. It's designed to be used\n * with `yield*` (yield delegation) inside your main generator.\n *\n * **Why use this helper?**\n * - Makes the intent clear: \"step to this state\"\n * - Provides a consistent API for state transitions\n * - Enables type inference for the received state\n * - Works seamlessly with the `run()` function\n *\n * **What `yield*` does:**\n * `yield*` delegates to another generator. When you write `yield* step(m)`,\n * control passes to the `step` generator, which yields `m`, then returns the\n * value sent back by the runner.\n *\n * @template C - The context object type for the machine.\n *\n * @param m - The machine state to yield.\n *\n * @returns A generator that yields the machine and returns the received state.\n *\n * @example Basic stepping\n * ```typescript\n * run(function* (machine) {\n * // Yield this state and receive the next one\n * const next = yield* step(machine.increment());\n * console.log(next.context.count);\n * return next;\n * }, counter);\n * ```\n *\n * @example Without step (more verbose)\n * ```typescript\n * run(function* (machine) {\n * // This is what step() does internally\n * const next = yield machine.increment();\n * return next;\n * }, counter);\n * ```\n *\n * @example Chaining with step\n * ```typescript\n * run(function* (m) {\n * m = yield* step(m.action1());\n * m = yield* step(m.action2());\n * m = yield* step(m.action3());\n * return m;\n * }, machine);\n * ```\n */\nexport function step<C extends object>(\n m: Machine<C>\n): Generator<Machine<C>, Machine<C>, Machine<C>> {\n // Create an immediately-invoked generator that:\n // 1. Yields the provided machine\n // 2. Receives a value back (the next state)\n // 3. Returns that received value\n return (function* () {\n const received = yield m;\n return received;\n })();\n}\n\n/**\n * Alternative to `step` that doesn't require `yield*`.\n * This is semantically identical but uses direct yielding.\n *\n * Use this if you prefer the simpler syntax without delegation.\n *\n * @template C - The context object type.\n * @param m - The machine to yield.\n * @returns The same machine (passed through).\n *\n * @example\n * ```typescript\n * run(function* (m) {\n * m = yield m.increment(); // No yield* needed\n * m = yield m.add(5);\n * return m;\n * }, counter);\n * ```\n */\nexport function yieldMachine<C extends object>(m: Machine<C>): Machine<C> {\n return m;\n}\n\n/**\n * Runs multiple generator flows in sequence, passing the result of each to the next.\n *\n * This is useful for composing multiple generator-based workflows into a pipeline.\n *\n * @template C - The context object type.\n * @param initial - The initial machine state.\n * @param flows - An array of generator functions to run in sequence.\n * @returns The final machine state after all flows complete.\n *\n * @example\n * ```typescript\n * const flow1 = function* (m: Machine<{ count: number }>) {\n * m = yield* step(m.increment());\n * return m;\n * };\n *\n * const flow2 = function* (m: Machine<{ count: number }>) {\n * m = yield* step(m.add(5));\n * return m;\n * };\n *\n * const result = runSequence(counter, [flow1, flow2]);\n * console.log(result.context.count); // 6\n * ```\n */\nexport function runSequence<C extends object>(\n initial: Machine<C>,\n flows: Array<(m: Machine<C>) => Generator<Machine<C>, Machine<C>, Machine<C>>>\n): Machine<C> {\n return flows.reduce((machine, flow) => {\n return run(flow, machine);\n }, initial);\n}\n\n/**\n * Creates a reusable generator flow that can be composed into other flows.\n *\n * This allows you to define common state machine patterns as reusable building blocks.\n *\n * @template C - The context object type.\n * @param flow - A generator function representing a reusable flow.\n * @returns A function that can be used with `yield*` in other generators.\n *\n * @example\n * ```typescript\n * // Define a reusable flow\n * const incrementThrice = createFlow(function* (m: Machine<{ count: number }>) {\n * m = yield* step(m.increment());\n * m = yield* step(m.increment());\n * m = yield* step(m.increment());\n * return m;\n * });\n *\n * // Use it in another flow\n * const result = run(function* (m) {\n * m = yield* incrementThrice(m);\n * m = yield* step(m.add(10));\n * return m;\n * }, counter);\n * ```\n */\nexport function createFlow<C extends object>(\n flow: (m: Machine<C>) => Generator<Machine<C>, Machine<C>, Machine<C>>\n): (m: Machine<C>) => Generator<Machine<C>, Machine<C>, Machine<C>> {\n return flow;\n}\n\n/**\n * Runs a generator flow with debugging output at each step.\n *\n * This is useful for understanding the state transitions in your flow.\n *\n * @template C - The context object type.\n * @template T - The return type.\n * @param flow - The generator function to run.\n * @param initial - The initial machine state.\n * @param logger - Optional custom logger function.\n * @returns The final value from the generator.\n *\n * @example\n * ```typescript\n * const result = runWithDebug(function* (m) {\n * m = yield* step(m.increment());\n * m = yield* step(m.add(5));\n * return m.context.count;\n * }, counter);\n *\n * // Output:\n * // Step 0: { count: 0 }\n * // Step 1: { count: 1 }\n * // Step 2: { count: 6 }\n * // Final: 6\n * ```\n */\nexport function runWithDebug<C extends object, T>(\n flow: (m: Machine<C>) => Generator<Machine<C>, T, Machine<C>>,\n initial: Machine<C>,\n logger: (step: number, machine: Machine<C>) => void = (step, m) => {\n console.log(`Step ${step}:`, m.context);\n }\n): T {\n const generator = flow(initial);\n let current = initial;\n let stepCount = 0;\n\n logger(stepCount, current);\n\n while (true) {\n const { value, done } = generator.next(current);\n\n if (done) {\n console.log('Final:', value);\n return value;\n }\n\n current = value;\n stepCount++;\n logger(stepCount, current);\n }\n}\n\n// =============================================================================\n// ASYNC GENERATOR SUPPORT\n// =============================================================================\n\n/**\n * Async version of `run` for async state machines.\n *\n * This allows you to use async/await inside your generator flows while maintaining\n * the same compositional benefits.\n *\n * @template C - The context object type.\n * @template T - The return type.\n * @param flow - An async generator function.\n * @param initial - The initial machine state.\n * @returns A promise that resolves to the final value.\n *\n * @example\n * ```typescript\n * const result = await runAsync(async function* (m) {\n * m = yield* stepAsync(await m.fetchData());\n * m = yield* stepAsync(await m.processData());\n * return m.context;\n * }, asyncMachine);\n * ```\n */\nexport async function runAsync<C extends object, T>(\n flow: (m: Machine<C>) => AsyncGenerator<Machine<C>, T, Machine<C>>,\n initial: Machine<C>\n): Promise<T> {\n const generator = flow(initial);\n let current = initial;\n\n while (true) {\n const { value, done } = await generator.next(current);\n\n if (done) {\n return value;\n }\n\n current = value;\n }\n}\n\n/**\n * Async version of `step` for async generators.\n *\n * @template C - The context object type.\n * @param m - The machine to yield.\n * @returns An async generator.\n *\n * @example\n * ```typescript\n * await runAsync(async function* (m) {\n * m = yield* stepAsync(await m.asyncOperation());\n * return m;\n * }, machine);\n * ```\n */\nexport async function* stepAsync<C extends object>(\n m: Machine<C>\n): AsyncGenerator<Machine<C>, Machine<C>, Machine<C>> {\n const received = yield m;\n return received;\n}\n", "/**\n * @file Type-level primitives for formal state machine verification.\n * @description\n * This file provides a Domain Specific Language (DSL) of wrapper functions.\n * These functions serve two purposes:\n * 1. At Runtime: They are identity functions (no-ops). They return your code exactly as is.\n * 2. At Design/Build Time: They \"brand\" your transition functions with rich type metadata.\n *\n * This allows a static analysis tool (like `ts-morph`) to read your source code\n * and generate a formal Statechart (JSON) that perfectly matches your implementation,\n * including resolving Class Constructors to their names.\n */\n\n// =============================================================================\n// SECTION: CORE METADATA TYPES\n// =============================================================================\n\n/**\n * A unique symbol used to \"brand\" a type with metadata.\n * This key allows the static analyzer to find the metadata within a complex type signature.\n */\nexport const META_KEY = Symbol(\"MachineMeta\");\n\n/**\n * Runtime metadata symbol.\n * Non-enumerable property key for storing metadata on function objects at runtime.\n * @internal\n */\nexport const RUNTIME_META = Symbol('__machine_runtime_meta__');\n\n/**\n * Helper type representing a Class Constructor.\n * Used to reference target states by their class definition rather than magic strings.\n */\nexport type ClassConstructor = new (...args: any[]) => any;\n\n/**\n * Metadata describing a Guard condition.\n */\nexport interface GuardMeta {\n /** The name of the guard (e.g., \"isAdmin\"). */\n name: string;\n /** Optional documentation explaining the logic. */\n description?: string;\n}\n\n/**\n * Metadata describing an Invoked Service (async operation).\n */\nexport interface InvokeMeta {\n /** The name of the service source (e.g., \"fetchUserData\"). */\n src: string;\n /** The state class to transition to on success. */\n onDone: ClassConstructor;\n /** The state class to transition to on error. */\n onError: ClassConstructor;\n /** Optional description. */\n description?: string;\n}\n\n/**\n * Metadata describing a generic Action (side effect).\n */\nexport interface ActionMeta {\n /** The name of the action (e.g., \"logAnalytics\"). */\n name: string;\n /** Optional description. */\n description?: string;\n}\n\n/**\n * The comprehensive shape of metadata that can be encoded into a transition's type.\n */\nexport interface TransitionMeta {\n /** The target state class this transition leads to. */\n target?: ClassConstructor;\n /** A human-readable description of the transition. */\n description?: string;\n /** An array of guards that must be true for this transition to be enabled. */\n guards?: GuardMeta[];\n /** A service to invoke upon taking this transition (or entering the state). */\n invoke?: InvokeMeta;\n /** Fire-and-forget side effects associated with this transition. */\n actions?: ActionMeta[];\n}\n\n/**\n * The Branded Type.\n * It takes a function type `F` and intersects it with a hidden metadata object `M`.\n * This is the mechanism that carries information from your code to the compiler API.\n */\nexport type WithMeta<\n F extends (...args: any[]) => any,\n M extends TransitionMeta\n> = F & { [META_KEY]: M };\n\n// =============================================================================\n// SECTION: RUNTIME METADATA ATTACHMENT\n// =============================================================================\n\n/**\n * Runtime metadata interface (resolved class names as strings)\n */\nexport interface RuntimeTransitionMeta {\n target?: string;\n description?: string;\n guards?: Array<{ name: string; description?: string }>;\n invoke?: {\n src: string;\n onDone: string;\n onError: string;\n description?: string;\n };\n actions?: Array<{ name: string; description?: string }>;\n}\n\n/**\n * Attaches runtime metadata to a function object.\n * Merges with existing metadata if present.\n *\n * @param fn - The function to attach metadata to\n * @param metadata - Partial metadata to merge\n * @internal\n */\nfunction attachRuntimeMeta(fn: any, metadata: Partial<RuntimeTransitionMeta>): void {\n // Read existing metadata (may be undefined)\n const existing = fn[RUNTIME_META] || {};\n\n // Shallow merge for simple properties\n const merged: any = { ...existing, ...metadata };\n\n // Deep merge for array properties\n if (metadata.guards && existing.guards) {\n merged.guards = [...existing.guards, ...metadata.guards];\n } else if (metadata.guards) {\n merged.guards = [...metadata.guards];\n }\n\n if (metadata.actions && existing.actions) {\n merged.actions = [...existing.actions, ...metadata.actions];\n } else if (metadata.actions) {\n merged.actions = [...metadata.actions];\n }\n\n // Replace invoke entirely (not an array, can't merge)\n // Last invoke wins (this matches XState semantics)\n\n // Define or redefine the metadata property\n Object.defineProperty(fn, RUNTIME_META, {\n value: merged,\n enumerable: false,\n writable: false,\n configurable: true // CRITICAL: Must be configurable for re-definition\n });\n}\n\n// =============================================================================\n// SECTION: ANNOTATION PRIMITIVES (THE DSL)\n// =============================================================================\n\n/**\n * Defines a transition to a target state class.\n *\n * @param target - The Class Constructor of the state being transitioned to.\n * @param implementation - The implementation function returning the new state instance.\n * @returns The implementation function, branded with target metadata.\n *\n * @example\n * login = transitionTo(LoggedInMachine, (user) => new LoggedInMachine({ user }));\n */\nexport function transitionTo<\n T extends ClassConstructor,\n F extends (...args: any[]) => any\n>(\n _target: T,\n implementation: F\n): WithMeta<F, { target: T }> {\n // Attach runtime metadata with class name\n attachRuntimeMeta(implementation, {\n target: _target.name || _target.toString()\n });\n\n return implementation as any;\n}\n\n/**\n * Annotates a transition with a description for documentation generation.\n *\n * @param text - The description text.\n * @param transition - The transition function (or wrapper) to annotate.\n * @example\n * logout = describe(\"Logs the user out\", transitionTo(LoggedOut, ...));\n */\nexport function describe<\n F extends (...args: any[]) => any,\n M extends TransitionMeta\n>(\n _text: string,\n transition: WithMeta<F, M>\n): WithMeta<F, M & { description: string }> {\n // Attach runtime metadata\n attachRuntimeMeta(transition, {\n description: _text\n });\n\n return transition as any;\n}\n\n/**\n * Annotates a transition with a Guard condition.\n * Note: This only adds metadata. You must still implement the `if` check inside your function.\n *\n * @param guard - Object containing the name and optional description of the guard.\n * @param transition - The transition function to guard.\n * @example\n * delete = guarded({ name: \"isAdmin\" }, transitionTo(Deleted, ...));\n */\nexport function guarded<\n F extends (...args: any[]) => any,\n M extends TransitionMeta\n>(\n guard: GuardMeta,\n transition: WithMeta<F, M>\n): WithMeta<F, M & { guards: [typeof guard] }> {\n // Attach runtime metadata\n // Note: guards is an array, will be merged by attachRuntimeMeta\n attachRuntimeMeta(transition, {\n guards: [guard]\n });\n\n return transition as any;\n}\n\n/**\n * Annotates a transition with an Invoked Service (asynchronous effect).\n *\n * @param service - configuration for the service (source, onDone target, onError target).\n * @param implementation - The async function implementation.\n * @example\n * load = invoke(\n * { src: \"fetchData\", onDone: LoadedMachine, onError: ErrorMachine },\n * async () => { ... }\n * );\n */\nexport function invoke<\n D extends ClassConstructor,\n E extends ClassConstructor,\n F extends (...args: any[]) => any\n>(\n service: { src: string; onDone: D; onError: E; description?: string },\n implementation: F\n): WithMeta<F, { invoke: typeof service }> {\n // Attach runtime metadata with class names resolved\n attachRuntimeMeta(implementation, {\n invoke: {\n src: service.src,\n onDone: service.onDone.name || service.onDone.toString(),\n onError: service.onError.name || service.onError.toString(),\n description: service.description\n }\n });\n\n return implementation as any;\n}\n\n/**\n * Annotates a transition with a side-effect Action.\n * Useful for logging, analytics, or external event firing that doesn't change state structure.\n *\n * @param action - Object containing the name and optional description.\n * @param transition - The transition function to annotate.\n * @example\n * click = action({ name: \"trackClick\" }, (ctx) => ...);\n */\nexport function action<\n F extends (...args: any[]) => any,\n M extends TransitionMeta\n>(\n action: ActionMeta,\n transition: WithMeta<F, M>\n): WithMeta<F, M & { actions: [typeof action] }> {\n // Attach runtime metadata\n // Note: actions is an array, will be merged by attachRuntimeMeta\n attachRuntimeMeta(transition, {\n actions: [action]\n });\n\n return transition as any;\n}\n\n/**\n * Flexible metadata wrapper for functional and type-state patterns.\n *\n * This function allows attaching metadata to values that don't use the class-based\n * MachineBase pattern. It's particularly useful for:\n * - Functional machines created with createMachine()\n * - Type-state discriminated unions\n * - Generic machine configurations\n *\n * @param meta - Partial metadata object describing states, transitions, etc.\n * @param value - The value to annotate (machine, config, factory function, etc.)\n * @returns The value unchanged (identity function at runtime)\n *\n * @example\n * // Annotate a functional machine\n * const machine = metadata(\n * {\n * target: IdleState,\n * description: \"Counter machine with increment/decrement\"\n * },\n * createMachine({ count: 0 }, { ... })\n * );\n *\n * @example\n * // Annotate a factory function\n * export const createCounter = metadata(\n * { description: \"Creates a counter starting at 0\" },\n * () => createMachine({ count: 0 }, { ... })\n * );\n */\nexport function metadata<T>(_meta: Partial<TransitionMeta>, value: T): T {\n // At runtime, this is a no-op identity function\n // At compile-time/static-analysis, the metadata can be extracted from the type signature\n return value;\n}", "/**\n * @file Static Statechart Extractor for @doeixd/machine\n * @description\n * This build-time script uses the TypeScript Compiler API via `ts-morph` to analyze\n * your machine source code. It reads the \"type-level metadata\" encoded by the\n * primitives (`transitionTo`, `guarded`, etc.) and generates a formal, JSON-serializable\n * statechart definition compatible with tools like Stately Viz.\n *\n * This script does NOT execute your code. It performs a purely static analysis of the types.\n *\n * @usage\n * 1. Ensure you have `ts-node` and `ts-morph` installed: `npm install -D ts-node ts-morph`\n * 2. Create a configuration object or use .statechart.config.ts\n * 3. Run the script from your project root: `npx ts-node ./scripts/extract-statechart.ts`\n */\n\nimport { Project, Type, Node } from 'ts-morph';\n\n// =============================================================================\n// SECTION: CONFIGURATION TYPES\n// =============================================================================\n\n/**\n * Configuration for a single machine to extract\n */\nexport interface MachineConfig {\n /** Path to the source file containing the machine */\n input: string;\n /** Array of class names that represent states */\n classes: string[];\n /** Output file path (optional, defaults to stdout) */\n output?: string;\n /** Top-level ID for the statechart */\n id: string;\n /** Name of the class that represents the initial state */\n initialState: string;\n /** Optional description of the machine */\n description?: string;\n}\n\n/**\n * Global extraction configuration\n */\nexport interface ExtractionConfig {\n /** Array of machines to extract */\n machines: MachineConfig[];\n /** Validate output against XState JSON schema (optional) */\n validate?: boolean;\n /** Output format (json, mermaid, or both) */\n format?: 'json' | 'mermaid' | 'both';\n /** Watch mode - auto-regenerate on file changes */\n watch?: boolean;\n /** Verbose logging */\n verbose?: boolean;\n}\n\n// =============================================================================\n// SECTION: CORE ANALYSIS LOGIC\n// =============================================================================\n\n/**\n * Recursively traverses a `ts-morph` Type object and serializes it into a\n * plain JSON-compatible value. It's smart enough to resolve class constructor\n * types into their string names.\n *\n * @param type - The `ts-morph` Type object to serialize.\n * @param verbose - Enable debug logging\n * @returns A JSON-compatible value (string, number, object, array).\n */\nfunction typeToJson(type: Type, verbose = false): any {\n // --- Terminal Types ---\n const symbol = type.getSymbol();\n if (symbol && symbol.getDeclarations().some(Node.isClassDeclaration)) {\n return symbol.getName(); // Resolve class types to their string name\n }\n if (type.isStringLiteral()) return type.getLiteralValue();\n if (type.isNumberLiteral()) return type.getLiteralValue();\n if (type.isBooleanLiteral()) return type.getLiteralValue();\n if (type.isString()) return 'string';\n if (type.isNumber()) return 'number';\n if (type.isBoolean()) return 'boolean';\n\n // --- Recursive Types ---\n if (type.isArray()) {\n const elementType = type.getArrayElementTypeOrThrow();\n return [typeToJson(elementType, verbose)];\n }\n\n // --- Object Types ---\n if (type.isObject() || type.isIntersection()) {\n const obj: { [key: string]: any } = {};\n const properties = type.getProperties();\n\n // Filter out symbol properties and internal properties\n for (const prop of properties) {\n const propName = prop.getName();\n\n // Skip symbol properties (those starting with \"__@\")\n if (propName.startsWith('__@')) continue;\n\n const declaration = prop.getValueDeclaration();\n if (!declaration) continue;\n\n try {\n obj[propName] = typeToJson(declaration.getType(), verbose);\n } catch (e) {\n if (verbose) console.error(` Warning: Failed to serialize property ${propName}:`, e);\n obj[propName] = 'unknown';\n }\n }\n\n // If we got an empty object, return null (no metadata)\n return Object.keys(obj).length > 0 ? obj : null;\n }\n\n if (verbose) {\n console.error(` Unhandled type: ${type.getText()}`);\n }\n\n return 'unknown'; // Fallback for unhandled types\n}\n\n// =============================================================================\n// SECTION: AST-BASED METADATA EXTRACTION\n// =============================================================================\n\n/**\n * Resolves a class name from an AST node (handles identifiers and typeof expressions)\n */\nfunction resolveClassName(node: Node): string {\n // Handle: LoggingInMachine\n if (Node.isIdentifier(node)) {\n return node.getText();\n }\n\n // Handle: typeof LoggingInMachine\n if (Node.isTypeOfExpression(node)) {\n return node.getExpression().getText();\n }\n\n return 'unknown';\n}\n\n/**\n * Parses an object literal expression into a plain JavaScript object\n */\nfunction parseObjectLiteral(obj: Node): any {\n if (!Node.isObjectLiteralExpression(obj)) {\n return {};\n }\n\n const result: any = {};\n\n for (const prop of obj.getProperties()) {\n if (Node.isPropertyAssignment(prop)) {\n const name = prop.getName();\n const init = prop.getInitializer();\n\n if (init) {\n if (Node.isStringLiteral(init)) {\n result[name] = init.getLiteralValue();\n } else if (Node.isNumericLiteral(init)) {\n result[name] = init.getLiteralValue();\n } else if (init.getText() === 'true' || init.getText() === 'false') {\n result[name] = init.getText() === 'true';\n } else if (Node.isIdentifier(init)) {\n result[name] = init.getText();\n } else if (Node.isObjectLiteralExpression(init)) {\n result[name] = parseObjectLiteral(init);\n } else if (Node.isArrayLiteralExpression(init)) {\n result[name] = init.getElements().map(el => {\n if (Node.isObjectLiteralExpression(el)) {\n return parseObjectLiteral(el);\n }\n return el.getText();\n });\n }\n }\n }\n }\n\n return result;\n}\n\n/**\n * Parses an invoke service configuration, resolving class names for onDone/onError\n */\nfunction parseInvokeService(obj: Node): any {\n if (!Node.isObjectLiteralExpression(obj)) {\n return {};\n }\n\n const service: any = {};\n\n for (const prop of obj.getProperties()) {\n if (Node.isPropertyAssignment(prop)) {\n const name = prop.getName();\n const init = prop.getInitializer();\n\n if (!init) continue;\n\n if (name === 'onDone' || name === 'onError') {\n // Resolve class names for state targets\n service[name] = resolveClassName(init);\n } else if (Node.isStringLiteral(init)) {\n service[name] = init.getLiteralValue();\n } else if (Node.isIdentifier(init)) {\n service[name] = init.getText();\n }\n }\n }\n\n return service;\n}\n\n/**\n * Recursively extracts metadata from a call expression chain\n * Handles nested DSL primitive calls like: describe(text, guarded(guard, transitionTo(...)))\n */\nfunction extractFromCallExpression(call: Node, verbose = false): any | null {\n if (!Node.isCallExpression(call)) {\n return null;\n }\n\n const expression = call.getExpression();\n const fnName = Node.isIdentifier(expression) ? expression.getText() : null;\n\n if (!fnName) {\n return null;\n }\n\n const metadata: any = {};\n const args = call.getArguments();\n\n switch (fnName) {\n case 'transitionTo':\n // Args: (target, implementation)\n if (args[0]) {\n metadata.target = resolveClassName(args[0]);\n }\n // The second argument might be another call expression, but we don't recurse there\n // because transitionTo is the innermost wrapper\n break;\n\n case 'describe':\n // Args: (description, transition)\n if (args[0] && Node.isStringLiteral(args[0])) {\n metadata.description = args[0].getLiteralValue();\n }\n // Recurse into wrapped transition\n if (args[1] && Node.isCallExpression(args[1])) {\n const nested = extractFromCallExpression(args[1], verbose);\n if (nested) {\n Object.assign(metadata, nested);\n }\n }\n break;\n\n case 'guarded':\n // Args: (guard, transition)\n if (args[0]) {\n const guard = parseObjectLiteral(args[0]);\n if (Object.keys(guard).length > 0) {\n metadata.guards = [guard];\n }\n }\n // Recurse into wrapped transition\n if (args[1] && Node.isCallExpression(args[1])) {\n const nested = extractFromCallExpression(args[1], verbose);\n if (nested) {\n Object.assign(metadata, nested);\n }\n }\n break;\n\n case 'invoke':\n // Args: (service, implementation)\n if (args[0]) {\n const service = parseInvokeService(args[0]);\n if (Object.keys(service).length > 0) {\n metadata.invoke = service;\n }\n }\n break;\n\n case 'action':\n // Args: (action, transition)\n if (args[0]) {\n const actionMeta = parseObjectLiteral(args[0]);\n if (Object.keys(actionMeta).length > 0) {\n metadata.actions = [actionMeta];\n }\n }\n // Recurse into wrapped transition\n if (args[1] && Node.isCallExpression(args[1])) {\n const nested = extractFromCallExpression(args[1], verbose);\n if (nested) {\n Object.assign(metadata, nested);\n }\n }\n break;\n\n default:\n // Not a DSL primitive we recognize\n return null;\n }\n\n return Object.keys(metadata).length > 0 ? metadata : null;\n}\n\n/**\n * Extracts metadata by parsing the AST of DSL primitive calls.\n * This is the new approach that solves the generic type parameter resolution problem.\n *\n * @param member - The class member (property declaration) to analyze\n * @param verbose - Enable debug logging\n * @returns The extracted metadata object, or `null` if no metadata is found.\n */\nfunction extractMetaFromMember(member: Node, verbose = false): any | null {\n // Only process property declarations (methods with initializers)\n if (!Node.isPropertyDeclaration(member)) {\n if (verbose) console.error(` ⚠️ Not a property declaration`);\n return null;\n }\n\n const initializer = member.getInitializer();\n if (!initializer) {\n if (verbose) console.error(` ⚠️ No initializer`);\n return null;\n }\n\n // Check if it's a call expression (DSL primitive call)\n if (!Node.isCallExpression(initializer)) {\n if (verbose) console.error(` ⚠️ Initializer is not a call expression`);\n return null;\n }\n\n // Extract metadata by parsing the call chain\n const metadata = extractFromCallExpression(initializer, verbose);\n\n if (metadata && verbose) {\n console.error(` ✅ Extracted metadata:`, JSON.stringify(metadata, null, 2));\n }\n\n return metadata;\n}\n\n/**\n * Analyzes a single class symbol to find all annotated transitions and effects,\n * building a state node definition for the final statechart.\n *\n * @param classSymbol - The `ts-morph` Symbol for the class to analyze.\n * @param verbose - Enable verbose logging\n * @returns A state node object (e.g., `{ on: {...}, invoke: [...] }`).\n */\nfunction analyzeStateNode(classSymbol: any, verbose = false): object {\n const chartNode: any = { on: {} };\n const classDeclaration = classSymbol.getDeclarations()[0];\n if (!classDeclaration || !Node.isClassDeclaration(classDeclaration)) {\n if (verbose) {\n console.error(`⚠️ Warning: Could not get class declaration for ${classSymbol.getName()}`);\n }\n return chartNode;\n }\n\n const className = classSymbol.getName();\n if (verbose) {\n console.error(` Analyzing state: ${className}`);\n }\n\n for (const member of classDeclaration.getInstanceMembers()) {\n const memberName = member.getName();\n if (verbose) {\n console.error(` Checking member: ${memberName}`);\n }\n\n // NEW: Use AST-based extraction instead of type-based\n const meta = extractMetaFromMember(member, verbose);\n if (!meta) continue;\n\n if (verbose) {\n console.error(` Found transition: ${memberName}`);\n }\n\n // Separate `invoke` metadata from standard `on` transitions, as it's a\n // special property of a state node in XState/Stately syntax.\n const { invoke, actions, guards, ...onEntry } = meta;\n\n if (invoke) {\n if (!chartNode.invoke) chartNode.invoke = [];\n chartNode.invoke.push({\n src: invoke.src,\n onDone: { target: invoke.onDone },\n onError: { target: invoke.onError },\n description: invoke.description,\n });\n if (verbose) {\n console.error(` → Invoke: ${invoke.src}`);\n }\n }\n\n // If there's a target, it's a standard event transition.\n if (onEntry.target) {\n const transition: any = { target: onEntry.target };\n\n // Add description if present\n if (onEntry.description) {\n transition.description = onEntry.description;\n }\n\n // Add guards as 'cond' property\n if (guards) {\n transition.cond = guards.map((g: any) => g.name).join(' && ');\n if (verbose) {\n console.error(` → Guard: ${transition.cond}`);\n }\n }\n\n // Add actions array\n if (actions && actions.length > 0) {\n transition.actions = actions.map((a: any) => a.name);\n if (verbose) {\n console.error(` → Actions: ${transition.actions.join(', ')}`);\n }\n }\n\n chartNode.on[memberName] = transition;\n if (verbose) {\n console.error(` → Target: ${onEntry.target}`);\n }\n }\n }\n\n return chartNode;\n}\n\n// =============================================================================\n// SECTION: MAIN ORCHESTRATOR\n// =============================================================================\n\n/**\n * Extracts a single machine configuration to a statechart\n *\n * @param config - Machine configuration\n * @param project - ts-morph Project instance\n * @param verbose - Enable verbose logging\n * @returns The generated statechart object\n */\nexport function extractMachine(\n config: MachineConfig,\n project: Project,\n verbose = false\n): any {\n if (verbose) {\n console.error(`\\n🔍 Analyzing machine: ${config.id}`);\n console.error(` Source: ${config.input}`);\n }\n\n const sourceFile = project.getSourceFile(config.input);\n if (!sourceFile) {\n throw new Error(`Source file not found: ${config.input}`);\n }\n\n const fullChart: any = {\n id: config.id,\n initial: config.initialState,\n states: {},\n };\n\n if (config.description) {\n fullChart.description = config.description;\n }\n\n for (const className of config.classes) {\n const classDeclaration = sourceFile.getClass(className);\n if (!classDeclaration) {\n console.warn(`⚠️ Warning: Class '${className}' not found in '${config.input}'. Skipping.`);\n continue;\n }\n const classSymbol = classDeclaration.getSymbolOrThrow();\n const stateNode = analyzeStateNode(classSymbol, verbose);\n fullChart.states[className] = stateNode;\n }\n\n if (verbose) {\n console.error(` ✅ Extracted ${config.classes.length} states`);\n }\n\n return fullChart;\n}\n\n/**\n * Extracts multiple machines based on configuration\n *\n * @param config - Full extraction configuration\n * @returns Array of generated statecharts\n */\nexport function extractMachines(config: ExtractionConfig): any[] {\n const verbose = config.verbose ?? false;\n\n if (verbose) {\n console.error(`\\n📊 Starting statechart extraction`);\n console.error(` Machines to extract: ${config.machines.length}`);\n }\n\n const project = new Project();\n project.addSourceFilesAtPaths(\"src/**/*.ts\");\n project.addSourceFilesAtPaths(\"examples/**/*.ts\");\n\n const results: any[] = [];\n\n for (const machineConfig of config.machines) {\n try {\n const chart = extractMachine(machineConfig, project, verbose);\n results.push(chart);\n } catch (error) {\n console.error(`❌ Error extracting machine '${machineConfig.id}':`, error);\n if (!verbose) {\n console.error(` Run with --verbose for more details`);\n }\n }\n }\n\n if (verbose) {\n console.error(`\\n✅ Extraction complete: ${results.length}/${config.machines.length} machines extracted`);\n }\n\n return results;\n}\n\n/**\n * Legacy function for backwards compatibility\n * Extracts a single hardcoded machine configuration\n * @deprecated Use extractMachine or extractMachines instead\n */\nexport function generateChart() {\n // --- 🎨 CONFIGURATION 🎨 ---\n // Adjust these settings to match your project structure.\n\n const config: MachineConfig = {\n input: \"examples/authMachine.ts\",\n classes: [\n \"LoggedOutMachine\",\n \"LoggingInMachine\",\n \"LoggedInMachine\",\n \"SessionExpiredMachine\",\n \"ErrorMachine\"\n ],\n id: \"auth\",\n initialState: \"LoggedOutMachine\",\n description: \"Authentication state machine\"\n };\n\n // --- End Configuration ---\n\n console.error(\"🔍 Using legacy generateChart function\");\n console.error(\"⚠️ Consider using extractMachines() with a config file instead\\n\");\n\n const project = new Project();\n project.addSourceFilesAtPaths(\"src/**/*.ts\");\n project.addSourceFilesAtPaths(\"examples/**/*.ts\");\n\n try {\n const chart = extractMachine(config, project, true);\n console.log(JSON.stringify(chart, null, 2));\n } catch (error) {\n console.error(`❌ Error:`, error);\n process.exit(1);\n }\n}\n\n// This allows the script to be executed directly from the command line.\nif (require.main === module) {\n generateChart();\n}", "/**\n * @file Runtime statechart extraction utilities\n * @description Extract statecharts from running machine instances using Symbol-based metadata\n */\n\nimport { RUNTIME_META, type RuntimeTransitionMeta } from './primitives';\n\n/**\n * Extract metadata from a single function if it has runtime metadata attached\n *\n * @param fn - Function to extract from\n * @returns Metadata object or null if no metadata\n */\nexport function extractFunctionMetadata(fn: any): RuntimeTransitionMeta | null {\n if (typeof fn !== 'function') {\n return null;\n }\n\n const meta = fn[RUNTIME_META];\n return meta || null;\n}\n\n/**\n * Extract state node from a machine class instance\n *\n * @param stateInstance - Instance of a machine state class\n * @returns State node with transitions\n */\nexport function extractStateNode(stateInstance: any): any {\n const stateNode: any = { on: {} };\n const invoke: any[] = [];\n\n // Iterate over all properties\n for (const key in stateInstance) {\n const value = stateInstance[key];\n\n if (typeof value !== 'function') {\n continue;\n }\n\n const meta = extractFunctionMetadata(value);\n if (!meta) {\n continue;\n }\n\n // Separate invoke from transitions\n if (meta.invoke) {\n invoke.push({\n src: meta.invoke.src,\n onDone: { target: meta.invoke.onDone },\n onError: { target: meta.invoke.onError },\n description: meta.invoke.description\n });\n }\n\n // If has target, it's a transition\n if (meta.target) {\n const transition: any = { target: meta.target };\n\n if (meta.description) {\n transition.description = meta.description;\n }\n\n if (meta.guards && meta.guards.length > 0) {\n transition.cond = meta.guards.map(g => g.name).join(' && ');\n }\n\n if (meta.actions && meta.actions.length > 0) {\n transition.actions = meta.actions.map(a => a.name);\n }\n\n stateNode.on[key] = transition;\n }\n }\n\n if (invoke.length > 0) {\n stateNode.invoke = invoke;\n }\n\n return stateNode;\n}\n\n/**\n * Generate a complete statechart from multiple state class instances\n *\n * @param states - Object mapping state names to state instances\n * @param config - Chart configuration\n * @returns XState-compatible statechart JSON\n *\n * @example\n * const chart = generateStatechart({\n * 'LoggedOut': new LoggedOutMachine(),\n * 'LoggedIn': new LoggedInMachine()\n * }, {\n * id: 'auth',\n * initial: 'LoggedOut'\n * });\n */\nexport function generateStatechart(\n states: Record<string, any>,\n config: { id: string; initial: string; description?: string }\n): any {\n const chart: any = {\n id: config.id,\n initial: config.initial,\n states: {}\n };\n\n if (config.description) {\n chart.description = config.description;\n }\n\n for (const [stateName, stateInstance] of Object.entries(states)) {\n chart.states[stateName] = extractStateNode(stateInstance);\n }\n\n return chart;\n}\n\n/**\n * Convenience function to extract statechart from a single machine instance\n * Useful for simple machines with a single context but multiple transitions\n *\n * @param machineInstance - Machine instance\n * @param config - Chart configuration\n * @returns XState-compatible statechart JSON\n */\nexport function extractFromInstance(\n machineInstance: any,\n config: { id: string; stateName?: string }\n): any {\n const stateName = config.stateName || machineInstance.constructor.name || 'State';\n\n return {\n id: config.id,\n initial: stateName,\n states: {\n [stateName]: extractStateNode(machineInstance)\n }\n };\n}\n", "/**\n * @file multi.ts - Advanced operational patterns for state machine orchestration.\n * @description\n * This module provides optional, higher-level abstractions for managing machines.\n * They solve common ergonomic and integration challenges without compromising the\n * immutable core of the library.\n *\n * It introduces three patterns:\n *\n * 1. **Runner (`createRunner`):** A stateful controller for ergonomic control\n * of a single, immutable machine. Solves state reassignment.\n *\n * 2. **Ensemble (`createEnsemble`):** A functional pattern for orchestrating logic\n * over an external, framework-agnostic state store.\n *\n * 3. **MultiMachine (`createMultiMachine`):** A class-based alternative to the\n * Ensemble for OOP-style orchestration.\n */\n\nimport {\n Machine,\n Context,\n TransitionArgs,\n TransitionNames,\n // Transitions,\n} from './index';\n\n// =============================================================================\n// SECTION 1: THE MANAGED STATE RUNNER\n// =============================================================================\n\n/**\n * A mapped type that creates a new object type with the same transition methods\n * as the machine `M`, but pre-bound to update a Runner's internal state.\n *\n * When you call a method on `BoundTransitions`, it automatically transitions the\n * runner's state and returns the new machine instance. This is the key mechanism\n * that eliminates the need for manual state reassignment in imperative code.\n *\n * @template M - The machine type, which can be a union of multiple machine states.\n *\n * @example\n * // If your machine has these transitions:\n * // increment: () => Machine\n * // add: (n: number) => Machine\n * // Then BoundTransitions<typeof machine> provides:\n * // increment: () => Machine (auto-updates runner state)\n * // add: (n: number) => Machine (auto-updates runner state)\n */\nexport type BoundTransitions<M extends Machine<any>> = {\n [K in TransitionNames<M>]: (\n ...args: TransitionArgs<M, K>\n ) => M[K] extends (...args: any[]) => infer R ? R : never;\n};\n\n/**\n * A stateful controller that wraps an immutable machine instance, providing a\n * stable API for imperative state transitions without manual reassignment.\n *\n * The Runner holds the \"current\" machine state internally and updates it whenever\n * an action is called. This solves the ergonomic problem of having to write:\n * `machine = machine.transition()` over and over. Instead, you just call\n * `runner.actions.transition()` and the runner manages the state for you.\n *\n * **Use Runner for:**\n * - Complex local component state (React, Vue, Svelte components)\n * - Scripts that need clean imperative state management\n * - Situations where you have a single, self-contained state machine\n *\n * **Don't use Runner for:**\n * - Global application state (use Ensemble instead)\n * - Multiple interconnected machines\n *\n * @template M - The machine type (can be a union of states for Type-State patterns).\n */\nexport type Runner<M extends Machine<any>> = {\n /**\n * The current, raw machine instance. This property is essential for\n * type-narrowing in Type-State Programming patterns.\n *\n * Since machines can be unions of different state types, you can narrow\n * the type by checking `runner.state.context` properties, and TypeScript\n * will automatically narrow which transitions are available.\n *\n * @example\n * if (runner.state.context.status === 'loggedIn') {\n * // runner.state is now typed as LoggedInMachine\n * console.log(runner.state.context.username);\n * runner.actions.logout(); // Only available when logged in\n * }\n */\n readonly state: M;\n\n /**\n * A direct, readonly accessor to the context of the current machine state.\n * This is a convenience property equivalent to `runner.state.context`.\n *\n * @example\n * console.log(runner.context.count); // Same as runner.state.context.count\n */\n readonly context: Context<M>;\n\n /**\n * A stable object containing all available transition methods, pre-bound to\n * update the runner's state. This is the primary way to trigger transitions.\n *\n * When you call `runner.actions.someTransition()`, the runner automatically:\n * 1. Calls the transition on the current machine\n * 2. Updates `runner.state` with the new machine instance\n * 3. Fires the `onChange` callback (if provided to createRunner)\n * 4. Returns the new machine instance\n *\n * Note: For union-type machines, you must first narrow the type of `runner.state`\n * to ensure a given action is available at compile time.\n *\n * @example\n * runner.actions.increment(); // Automatically updates runner.state\n * runner.actions.add(5); // Returns new machine instance\n */\n readonly actions: BoundTransitions<M>;\n\n /**\n * Manually sets the runner to a new machine state. Useful for resetting state\n * or synchronizing with external events.\n *\n * This method bypasses the normal transition path and directly updates the\n * runner's internal state. The `onChange` callback will be called.\n *\n * @param newState - The new machine instance to set.\n *\n * @example\n * const reset = createCounterMachine({ count: 0 });\n * runner.setState(reset); // Jump back to initial state\n */\n setState(newState: M): void;\n};\n\n/**\n * Creates a Managed State Runner by wrapping a pure, immutable machine instance\n * in a stateful controller. This eliminates the need for `machine = machine.transition()`\n * reassignment, providing a more ergonomic, imperative API for complex local state.\n *\n * **How it works:**\n * 1. The runner holds a reference to the current machine internally\n * 2. When you call `runner.actions.transition()`, it calls the transition on the\n * current machine and automatically updates the runner's internal state\n * 3. The runner exposes a stable `actions` object that always reflects what\n * transitions are available on the *current* machine (important for Type-State)\n * 4. The `onChange` callback is invoked after every state change\n *\n * **Key difference from just calling transitions directly:**\n * Instead of: `let machine = createMachine(...); machine = machine.increment();`\n * You write: `const runner = createRunner(machine); runner.actions.increment();`\n *\n * The runner *is* the state holder, so you never need to reassign variables.\n *\n * @template M - The machine type.\n * @param initialMachine - The starting machine instance.\n * @param onChange - Optional callback fired after every state transition. Receives\n * the new machine state, allowing you to react to changes (e.g., update a UI,\n * log state changes, or trigger side effects).\n * @returns A `Runner` instance with `state`, `context`, `actions`, and `setState()`.\n *\n * @example\n * // Simple counter example\n * const counterMachine = createCounterMachine({ count: 0 });\n * const runner = createRunner(counterMachine, (newState) => {\n * console.log('Count is now:', newState.context.count);\n * });\n *\n * runner.actions.increment(); // Logs: \"Count is now: 1\"\n * runner.actions.add(5); // Logs: \"Count is now: 6\"\n * console.log(runner.context.count); // 6\n *\n * @example\n * // Type-State example with conditional narrowing\n * type AuthMachine = LoggedOutState | LoggedInState;\n *\n * const runner = createRunner(createLoggedOutMachine());\n *\n * // Narrow the type to access login\n * if (runner.state.context.status === 'loggedOut') {\n * runner.actions.login('alice'); // Only works in loggedOut state\n * }\n *\n * // Now it's logged in, so we can call logout\n * if (runner.state.context.status === 'loggedIn') {\n * runner.actions.logout();\n * }\n */\nexport function createRunner<M extends Machine<any>>(\n initialMachine: M,\n onChange?: (newState: M) => void\n): Runner<M> {\n let currentMachine = initialMachine;\n\n const setState = (newState: M) => {\n currentMachine = newState;\n onChange?.(newState);\n };\n\n // Capture the original transitions from the initial machine\n const { context: _initialContext, ...originalTransitions } = initialMachine;\n\n const actions = new Proxy({} as BoundTransitions<M>, {\n get(_target, prop: string) {\n const transition = (currentMachine as any)[prop];\n if (typeof transition !== 'function') {\n // Return undefined for properties that aren't valid transitions on the current state\n return undefined;\n }\n\n return (...args: any[]) => {\n const nextState = transition.apply(currentMachine.context, args);\n // Ensure the next state has all the original transitions\n // by reconstructing it with the original transition functions\n const nextStateWithTransitions = Object.assign(\n { context: nextState.context },\n originalTransitions\n ) as M;\n setState(nextStateWithTransitions);\n return nextStateWithTransitions;\n };\n },\n });\n\n return {\n get state() {\n return currentMachine;\n },\n get context() {\n return currentMachine.context;\n },\n actions,\n setState,\n };\n}\n\n// =============================================================================\n// SECTION 2: THE ENSEMBLE (FRAMEWORK-AGNOSTIC ORCHESTRATION)\n// =============================================================================\n\n/**\n * Defines the contract for an external, user-provided state store. The Ensemble\n * uses this interface to read and write the machine's context, allowing it to\n * plug into any state management solution (React, Solid, Zustand, etc.).\n *\n * **The power of this abstraction:**\n * Your machine logic is completely decoupled from how or where the state is stored.\n * The same machine factories can work with React's `useState`, Solid's `createSignal`,\n * a plain object, or any custom store implementation.\n *\n * **Implementation examples:**\n * - React: `{ getContext: () => state, setContext: setState }`\n * - Solid: `{ getContext: () => store, setContext: (newCtx) => Object.assign(store, newCtx) }`\n * - Plain object: `{ getContext: () => context, setContext: (ctx) => Object.assign(context, ctx) }`\n *\n * @template C - The shared context object type.\n *\n * @example\n * // Implement a simple in-memory store\n * let sharedContext = { status: 'idle' };\n * const store: StateStore<typeof sharedContext> = {\n * getContext: () => sharedContext,\n * setContext: (newCtx) => { sharedContext = newCtx; }\n * };\n *\n * @example\n * // Implement a React-based store\n * function useAppStore() {\n * const [state, setState] = useState({ status: 'idle' });\n * return {\n * getContext: () => state,\n * setContext: setState\n * };\n * }\n */\nexport interface StateStore<C extends object> {\n /**\n * A function that returns the current, up-to-date context from the external store.\n * Called whenever the Ensemble needs the latest state.\n */\n getContext: () => C;\n\n /**\n * A function that takes a new context and updates the external store.\n * Called by transitions to persist state changes.\n *\n * @param newContext - The new context object to persist.\n */\n setContext: (newContext: C) => void;\n}\n\n/**\n * A mapped type that finds all unique transition names across a union of machine types.\n *\n * This type extracts the union of all methods from all possible machine states,\n * excluding the `context` property. This is used to create the `actions` object\n * on an Ensemble, which can have methods from any of the machine states.\n *\n * At runtime, the Ensemble validates that an action is valid for the current state\n * before executing it.\n *\n * @template AllMachines - A union of all possible machine types in an Ensemble.\n *\n * @example\n * type IdleState = Machine<{ status: 'idle' }> & { fetch: () => LoadingState };\n * type LoadingState = Machine<{ status: 'loading' }> & { cancel: () => IdleState };\n * type AllStates = IdleState | LoadingState;\n *\n * // AllTransitions<AllStates> = { fetch: (...) => ..., cancel: (...) => ... }\n * // (Both fetch and cancel are available, but each is only valid in its state)\n */\ntype AllTransitions<AllMachines extends Machine<any>> = Omit<\n { [K in keyof AllMachines]: AllMachines[K] }[keyof AllMachines],\n 'context'\n>;\n\n/**\n * The Ensemble object. It provides a stable, unified API for orchestrating a\n * state machine whose context is managed by an external store.\n *\n * The Ensemble acts as the \"director,\" determining which machine \"actor\" is\n * currently active based on the state of the shared context. Unlike a Runner,\n * which manages local state, an Ensemble plugs into external state management\n * (like React's useState, Solid's signal, or a global store).\n *\n * **Key characteristics:**\n * - Dynamically reconstructs the current machine based on context\n * - Validates transitions at runtime for the current state\n * - Integrates seamlessly with framework state managers\n * - Same factories can be reused across different frameworks\n *\n * **Use Ensemble for:**\n * - Global application state\n * - Framework integration (React, Solid, Vue, etc.)\n * - Complex workflows that span multiple components\n * - Decoupling business logic from UI framework\n *\n * @template AllMachines - A union type of all possible machine states.\n * @template C - The shared context type.\n */\nexport type Ensemble<AllMachines extends Machine<any>, C extends object> = {\n /**\n * A direct, readonly accessor to the context from the provided `StateStore`.\n * This is always up-to-date with the external store.\n */\n readonly context: C;\n\n /**\n * The current, fully-typed machine instance. This is dynamically created on-demand\n * based on the context state. Use this for type-narrowing with Type-State patterns.\n *\n * The machine is reconstructed on every access, so it always reflects the\n * current state of the context.\n */\n readonly state: AllMachines;\n\n /**\n * A stable object containing all possible actions from all machine states.\n * The Ensemble performs a runtime check to ensure an action is valid for the\n * current state before executing it.\n *\n * The `actions` object itself is stable (doesn't change), but the methods\n * available on it dynamically change based on the current state.\n */\n readonly actions: AllTransitions<AllMachines>;\n};\n\n/**\n * Creates an Ensemble to orchestrate a state machine over an external state store.\n * This is the primary tool for framework integration, as it decouples pure state\n * logic (defined in factories) from an application's state management solution\n * (defined in store).\n *\n * **How it works:**\n * 1. You provide a `StateStore` that can read and write your application's state\n * 2. You define factory functions that create machines for each state\n * 3. You provide a `getDiscriminant` accessor that tells the Ensemble which\n * factory to use based on the current context\n * 4. The Ensemble dynamically constructs the right machine and provides a stable\n * `actions` object to call transitions\n *\n * **Why this pattern?**\n * Your business logic (machines) is completely separated from your state management\n * (React, Solid, Zustand). You can change state managers without rewriting machines,\n * and you can test machines in isolation without framework dependencies.\n *\n * @template C - The shared context type.\n * @template F - An object of functions that create machine instances for each state.\n * Each factory receives the context and returns a Machine instance for that state.\n * @param store - The user-provided `StateStore` that reads/writes the context.\n * @param factories - An object mapping state discriminant keys to factory functions.\n * Each factory receives the context and returns a machine instance.\n * @param getDiscriminant - An accessor function that takes the context and returns\n * the key of the current state in the `factories` object. This provides full\n * refactoring safety—if you rename a property in your context, TypeScript will\n * catch it at the accessor function.\n * @returns An `Ensemble` instance with `context`, `state`, and `actions`.\n *\n * @example\n * // Using a simple in-memory store\n * let sharedContext = { status: 'idle' as const, data: null };\n * const store = {\n * getContext: () => sharedContext,\n * setContext: (newCtx) => { sharedContext = newCtx; }\n * };\n *\n * // Define factories for each state\n * const factories = {\n * idle: (ctx) => createMachine(ctx, {\n * fetch: () => store.setContext({ ...ctx, status: 'loading' })\n * }),\n * loading: (ctx) => createMachine(ctx, {\n * succeed: (data: any) => store.setContext({ status: 'success', data }),\n * fail: (error: string) => store.setContext({ status: 'error', error })\n * }),\n * success: (ctx) => createMachine(ctx, {\n * retry: () => store.setContext({ status: 'loading', data: null })\n * }),\n * error: (ctx) => createMachine(ctx, {\n * retry: () => store.setContext({ status: 'loading', data: null })\n * })\n * };\n *\n * // Create the ensemble with a discriminant accessor\n * const ensemble = createEnsemble(store, factories, (ctx) => ctx.status);\n *\n * // Use the ensemble\n * ensemble.actions.fetch();\n * console.log(ensemble.context.status); // 'loading'\n *\n * @example\n * // React integration example\n * function useAppEnsemble() {\n * const [context, setContext] = useState({ status: 'idle' as const, data: null });\n *\n * const store: StateStore<typeof context> = {\n * getContext: () => context,\n * setContext: (newCtx) => setContext(newCtx)\n * };\n *\n * const ensemble = useMemo(() =>\n * createEnsemble(store, factories, (ctx) => ctx.status),\n * [context] // Re-create ensemble if context changes\n * );\n *\n * return ensemble;\n * }\n *\n * // In your component:\n * function MyComponent() {\n * const ensemble = useAppEnsemble();\n * return (\n * <>\n * <p>Status: {ensemble.context.status}</p>\n * <button onClick={() => ensemble.actions.fetch()}>\n * Fetch Data\n * </button>\n * </>\n * );\n * }\n */\nexport function createEnsemble<\n C extends object,\n F extends Record<string, (context: C) => Machine<C>>\n>(\n store: StateStore<C>,\n factories: F,\n getDiscriminant: (context: C) => keyof F\n): Ensemble<ReturnType<F[keyof F]>, C> {\n type AllMachines = ReturnType<F[keyof F]>;\n\n const getCurrentMachine = (): AllMachines => {\n const context = store.getContext();\n const currentStateName = getDiscriminant(context);\n const factory = factories[currentStateName];\n\n if (!factory) {\n throw new Error(\n `[Ensemble] Invalid state: No factory found for state \"${String(currentStateName)}\".`\n );\n }\n return factory(context) as AllMachines;\n };\n\n const actions = new Proxy({} as AllTransitions<AllMachines>, {\n get(_target, prop: string) {\n const currentMachine = getCurrentMachine();\n const action = (currentMachine as any)[prop];\n\n if (typeof action !== 'function') {\n throw new Error(\n `[Ensemble] Transition \"${prop}\" is not valid in the current state.`\n );\n }\n\n // Return a function that, when called, executes the transition.\n // The transition itself is responsible for calling `store.setContext`.\n return (...args: any[]) => {\n return action.apply(currentMachine.context, args);\n };\n },\n });\n\n return {\n get context() {\n return store.getContext();\n },\n get state() {\n return getCurrentMachine();\n },\n actions,\n };\n}\n\n// =============================================================================\n// SECTION 3: GENERATOR INTEGRATION\n// =============================================================================\n\n/**\n * Executes a generator-based workflow using a Managed State Runner.\n *\n * This provides the cleanest syntax for multi-step imperative workflows, as the\n * `yield` keyword is only used for control flow, not state passing. Unlike the\n * basic `run()` function from the core library, this works directly with a Runner,\n * making it perfect for complex local state orchestration.\n *\n * **Syntax benefits:**\n * - No need to manually thread state through a chain of transitions\n * - `yield` is purely for control flow, not for passing state\n * - Can use regular `if`/`for` statements without helpers\n * - Generator return value is automatically your final result\n *\n * @param flow - A generator function that receives the `Runner` instance. The\n * generator can yield values (returned by transitions) and use them for control\n * flow, or just yield for side effects.\n * @param initialMachine - The machine to start the flow with. A runner will be\n * created from this automatically.\n * @returns The final value returned by the generator (the `return` statement).\n *\n * @example\n * // Simple sequential transitions\n * const result = runWithRunner(function* (runner) {\n * yield runner.actions.increment();\n * yield runner.actions.add(10);\n * if (runner.context.count > 5) {\n * yield runner.actions.reset();\n * }\n * return runner.context;\n * }, createCounterMachine());\n * console.log(result); // { count: 0 }\n *\n * @example\n * // Complex workflow with Type-State narrowing\n * const result = runWithRunner(function* (runner) {\n * // Start logged out\n * if (runner.state.context.status === 'loggedOut') {\n * yield runner.actions.login('alice');\n * }\n *\n * // Now logged in, fetch profile\n * if (runner.state.context.status === 'loggedIn') {\n * yield runner.actions.fetchProfile();\n * }\n *\n * // Return final context\n * return runner.context;\n * }, createAuthMachine());\n */\nexport function runWithRunner<M extends Machine<any>, T>(\n flow: (runner: Runner<M>) => Generator<any, T, any>,\n initialMachine: M\n): T {\n const runner = createRunner(initialMachine);\n const generator = flow(runner);\n let result = generator.next();\n while (!result.done) {\n result = generator.next();\n }\n return result.value;\n}\n\n/**\n * Executes a generator-based workflow using an Ensemble.\n *\n * This pattern is ideal for orchestrating complex sagas or workflows that\n * interact with a global, framework-managed state. Like `runWithRunner`,\n * it provides clean imperative syntax for multi-step workflows, but operates\n * on an Ensemble's external store rather than internal state.\n *\n * **Key differences from runWithRunner:**\n * - Works with external state stores (React, Solid, etc.)\n * - Useful for global workflows and sagas\n * - State changes automatically propagate to the framework\n * - Great for testing framework-agnostic state logic\n *\n * @param flow - A generator function that receives the `Ensemble` instance.\n * The generator can read `ensemble.context` and call `ensemble.actions`.\n * @param ensemble - The `Ensemble` to run the workflow against. Its context\n * is shared across the entire workflow.\n * @returns The final value returned by the generator (the `return` statement).\n *\n * @example\n * // Multi-step workflow with an ensemble\n * const result = runWithEnsemble(function* (ensemble) {\n * // Fetch initial data\n * if (ensemble.context.status === 'idle') {\n * yield ensemble.actions.fetch();\n * }\n *\n * // Process the data\n * if (ensemble.context.status === 'success') {\n * yield ensemble.actions.process(ensemble.context.data);\n * }\n *\n * return ensemble.context;\n * }, ensemble);\n *\n * @example\n * // Testing a workflow without a UI framework\n * const store: StateStore<AppContext> = {\n * getContext: () => context,\n * setContext: (newCtx) => Object.assign(context, newCtx)\n * };\n *\n * const ensemble = createEnsemble(store, factories, (ctx) => ctx.status);\n *\n * // Run a complex workflow and assert the result\n * const result = runWithEnsemble(function* (e) {\n * yield e.actions.login('alice');\n * yield e.actions.fetchProfile();\n * yield e.actions.updateEmail('alice@example.com');\n * return e.context;\n * }, ensemble);\n *\n * expect(result.userEmail).toBe('alice@example.com');\n */\nexport function runWithEnsemble<\n AllMachines extends Machine<any>,\n C extends object,\n T\n>(\n flow: (ensemble: Ensemble<AllMachines, C>) => Generator<any, T, any>,\n ensemble: Ensemble<AllMachines, C>\n): T {\n const generator = flow(ensemble);\n let result = generator.next();\n while (!result.done) {\n result = generator.next();\n }\n return result.value;\n}\n\n// =============================================================================\n// SECTION 4: CLASS-BASED MULTI-MACHINE (OOP APPROACH)\n// =============================================================================\n\n/**\n * The base class for creating a class-based state machine (MultiMachine).\n * Extend this class to define your state machine's logic using instance methods\n * as transitions.\n *\n * This approach is ideal for developers who prefer class-based architectures\n * and want to manage a shared context directly through an external StateStore.\n * It provides a familiar OOP interface while maintaining the decoupling benefits\n * of the StateStore pattern.\n *\n * **Key features:**\n * - Extend this class and define transition methods as instance methods\n * - Protected `context` getter provides access to the current state\n * - Protected `setContext()` method updates the external store\n * - Works seamlessly with `createMultiMachine()`\n *\n * @template C - The shared context type. Should typically contain a discriminant\n * property (like `status`) that identifies the current state.\n *\n * @example\n * // Define your context type\n * type AppContext = { status: 'idle' | 'loading' | 'error'; data?: any; error?: string };\n *\n * // Extend MultiMachineBase and define transitions as methods\n * class AppMachine extends MultiMachineBase<AppContext> {\n * async fetch(url: string) {\n * // Notify subscribers we're loading\n * this.setContext({ ...this.context, status: 'loading' });\n *\n * try {\n * const data = await fetch(url).then(r => r.json());\n * // Update state when done\n * this.setContext({ ...this.context, status: 'idle', data });\n * } catch (error) {\n * // Handle errors\n * this.setContext({\n * ...this.context,\n * status: 'error',\n * error: error.message\n * });\n * }\n * }\n *\n * reset() {\n * this.setContext({ status: 'idle' });\n * }\n * }\n */\nexport abstract class MultiMachineBase<C extends object> {\n /**\n * The external state store that manages the machine's context.\n * @protected\n */\n protected store: StateStore<C>;\n\n /**\n * @param store - The StateStore that will manage this machine's context.\n */\n constructor(store: StateStore<C>) {\n this.store = store;\n }\n\n /**\n * Read-only access to the current context from the external store.\n * This getter always returns the latest context from the store.\n *\n * @protected\n *\n * @example\n * const currentStatus = this.context.status;\n * const currentData = this.context.data;\n */\n protected get context(): C {\n return this.store.getContext();\n }\n\n /**\n * Update the shared context in the external store.\n * Call this method in your transition methods to update the state.\n *\n * @protected\n * @param newContext - The new context object. Should typically be a shallow\n * copy with only the properties you're changing, merged with the current\n * context using spread operators.\n *\n * @example\n * // In a transition method:\n * this.setContext({ ...this.context, status: 'loading' });\n *\n * @example\n * // Updating nested properties:\n * this.setContext({\n * ...this.context,\n * user: { ...this.context.user, name: 'Alice' }\n * });\n */\n protected setContext(newContext: C): void {\n this.store.setContext(newContext);\n }\n}\n\n/**\n * Creates a live, type-safe instance of a class-based state machine (MultiMachine).\n *\n * This is the class-based alternative to the functional `createEnsemble` pattern,\n * designed for developers who prefer an OOP-style architecture. This function takes\n * your MultiMachine class blueprint and an external state store, and wires them\n * together. The returned object is a Proxy that dynamically exposes both context\n * properties and the available transition methods from your class.\n *\n * **Key features:**\n * - Directly access context properties as if they were on the machine object\n * - Call transition methods to update state through the store\n * - Type-safe integration with TypeScript\n * - Seamless Proxy-based API (no special method names or API quirks)\n *\n * **How it works:**\n * The returned Proxy intercepts property access. For context properties, it returns\n * values from the store. For methods, it calls them on the MultiMachine instance.\n * This creates the illusion of a single object that is both data and behavior.\n *\n * @template C - The shared context type.\n * @template T - The MultiMachine class type.\n *\n * @param MachineClass - The class you defined that extends `MultiMachineBase<C>`.\n * @param store - The `StateStore` that will manage the machine's context.\n * @returns A Proxy that merges context properties with class methods, allowing\n * direct access to both via a unified object interface.\n *\n * @example\n * // Define your context type\n * type CounterContext = { count: number };\n *\n * // Define your machine class\n * class CounterMachine extends MultiMachineBase<CounterContext> {\n * increment() {\n * this.setContext({ count: this.context.count + 1 });\n * }\n *\n * add(n: number) {\n * this.setContext({ count: this.context.count + n });\n * }\n *\n * reset() {\n * this.setContext({ count: 0 });\n * }\n * }\n *\n * // Create a store\n * let sharedContext = { count: 0 };\n * const store = {\n * getContext: () => sharedContext,\n * setContext: (ctx) => { sharedContext = ctx; }\n * };\n *\n * // Create the machine instance\n * const machine = createMultiMachine(CounterMachine, store);\n *\n * // Use it naturally - properties and methods seamlessly integrated\n * console.log(machine.count); // 0\n * machine.increment();\n * console.log(machine.count); // 1\n * machine.add(5);\n * console.log(machine.count); // 6\n * machine.reset();\n * console.log(machine.count); // 0\n *\n * @example\n * // Status-based state machine with type discrimination\n * type AppContext = {\n * status: 'idle' | 'loading' | 'success' | 'error';\n * data?: any;\n * error?: string;\n * };\n *\n * class AppMachine extends MultiMachineBase<AppContext> {\n * async fetch() {\n * this.setContext({ ...this.context, status: 'loading' });\n * try {\n * const data = await fetch('/api/data').then(r => r.json());\n * this.setContext({ status: 'success', data });\n * } catch (error) {\n * this.setContext({\n * status: 'error',\n * error: error instanceof Error ? error.message : 'Unknown error'\n * });\n * }\n * }\n *\n * reset() {\n * this.setContext({ status: 'idle' });\n * }\n * }\n *\n * // Set up\n * let context: AppContext = { status: 'idle' };\n * const store = {\n * getContext: () => context,\n * setContext: (ctx) => { context = ctx; }\n * };\n *\n * const app = createMultiMachine(AppMachine, store);\n *\n * // Use naturally with type discrimination\n * console.log(app.status); // 'idle'\n *\n * if (app.status === 'idle') {\n * app.fetch(); // Transition to loading\n * }\n *\n * // Later: app.status === 'success'\n * // console.log(app.data); // Access the data\n */\nexport function createMultiMachine<\n C extends object,\n T extends MultiMachineBase<C>\n>(\n MachineClass: new (store: StateStore<C>) => T,\n store: StateStore<C>\n): C & T {\n const instance = new MachineClass(store);\n\n return new Proxy({} as C & T, {\n get(_target, prop: string | symbol) {\n // 1. Prioritize properties from the context\n const context = store.getContext();\n if (prop in context) {\n return (context as any)[prop];\n }\n\n // 2. Then check for methods on the instance\n const method = (instance as any)[prop];\n if (typeof method === 'function') {\n return (...args: any[]) => {\n return method.apply(instance, args);\n };\n }\n\n return undefined;\n },\n\n set(_target, prop: string | symbol, value: any) {\n // Allow direct mutation of context properties\n const context = store.getContext();\n if (prop in context) {\n const newContext = { ...context, [prop]: value } as C;\n store.setContext(newContext);\n return true;\n }\n return false;\n },\n\n has(_target, prop: string | symbol) {\n // Support `in` operator checks\n const context = store.getContext();\n return prop in context || typeof (instance as any)[prop] === 'function';\n },\n\n ownKeys(_target) {\n // Support reflection APIs\n const context = store.getContext();\n const contextKeys = Object.keys(context);\n const methodKeys = Object.getOwnPropertyNames(\n Object.getPrototypeOf(instance)\n ).filter((key) => key !== 'constructor' && typeof (instance as any)[key] === 'function');\n return Array.from(new Set([...contextKeys, ...methodKeys]));\n },\n\n getOwnPropertyDescriptor(_target, prop) {\n // Support property descriptors\n const context = store.getContext();\n if (prop in context || typeof (instance as any)[prop] === 'function') {\n return {\n value: undefined,\n writable: true,\n enumerable: true,\n configurable: true,\n };\n }\n return undefined;\n },\n });\n}\n\n// =============================================================================\n// SECTION 5: THE MUTABLE MACHINE (EXPERIMENTAL)\n// =============================================================================\n\n/**\n * A mapped type that defines the shape of a Mutable Machine: an intersection\n * of the context `C` and all possible transitions.\n */\ntype MutableMachine<C extends object, AllMachines extends Machine<any>> = C &\n AllTransitions<AllMachines>;\n\n\n /**\n * Creates a Mutable Machine that uses a shared, mutable context. This primitive\n * provides a stable object reference whose properties are mutated in place,\n * offering a direct, imperative API.\n *\n * ---\n *\n * ### Key Characteristics & Trade-offs\n *\n * - **Stable Object Reference**: The machine is a single object. You can pass this\n * reference around, and it will always reflect the current state.\n * - **Direct Imperative API**: Transitions are called like methods directly on the\n * object (`machine.login('user')`), and the object's properties update immediately.\n * - **No State History**: Since the context is mutated, the history of previous\n * states is not preserved, which makes patterns like time-travel debugging impossible.\n * - **Not for Reactive UIs**: Most UI frameworks (React, Solid, Vue) rely on\n * immutable state changes to trigger updates. Mutating the context directly\n * will not cause components to re-render. Use the `Ensemble` primitive for UI integration.\n *\n * ---\n *\n * ### Best Suited For\n *\n * - **Backend Services & Game Logic**: Ideal for managing state in server-side\n * processes, game loops, or other non-UI environments where performance and a\n * stable state object are priorities.\n * - **Complex Synchronous Scripts**: Useful for orchestrating data processing\n * pipelines, command-line tools, or any script where state needs to be managed\n * imperatively without passing it through a function chain.\n *\n * @template C - The shared context type.\n * @template F - An object of functions that create machine instances for each state.\n * **Crucially, transitions inside these machines must be pure functions that\n * return the *next context object*, not a new machine instance.**\n * @param sharedContext - The initial context object. This object will be mutated.\n * @param factories - An object mapping state names to functions that create machine instances.\n * @param getDiscriminant - An accessor function that takes the context and returns the key\n * of the current state in the `factories` object. Provides refactoring safety.\n * @returns A Proxy that acts as a stable, mutable machine instance.\n *\n * @example\n * // ===== 1. Basic Authentication Example =====\n *\n * type AuthContext =\n * | { status: 'loggedOut'; error?: string }\n * | { status: 'loggedIn'; username: string };\n *\n * const authFactories = {\n * loggedOut: (ctx: AuthContext) => ({\n * context: ctx,\n * // This transition is a PURE function that returns the NEXT CONTEXT\n * login: (username: string) => ({ status: 'loggedIn', username }),\n * }),\n * loggedIn: (ctx: AuthContext) => ({\n * context: ctx,\n * logout: () => ({ status: 'loggedOut' }),\n * }),\n * };\n *\n * const authUser = createMutableMachine(\n * { status: 'loggedOut' } as AuthContext,\n * authFactories,\n * 'status'\n * );\n *\n * const userReference = authUser; // Store a reference to the object\n *\n * console.log(authUser.status); // 'loggedOut'\n *\n * authUser.login('alice'); // Mutates the object in place\n *\n * console.log(authUser.status); // 'loggedIn'\n * console.log(authUser.username); // 'alice'\n *\n * // The original reference points to the same, mutated object\n * console.log(userReference.status); // 'loggedIn'\n * console.log(userReference === authUser); // true\n *\n * // --- Type-safe transitions ---\n * // `authUser.login('bob')` would now throw a runtime error because `login`\n * // is not a valid action in the 'loggedIn' state.\n *\n * if (authUser.status === 'loggedIn') {\n * // TypeScript correctly narrows the type here, allowing a safe call.\n * authUser.logout();\n * }\n * console.log(authUser.status); // 'loggedOut'\n *\n * @example\n * // ===== 2. Game State Loop Example =====\n *\n * type PlayerContext = {\n * state: 'idle' | 'walking' | 'attacking';\n * hp: number;\n * position: { x: number; y: number };\n * };\n *\n * const playerFactories = {\n * idle: (ctx: PlayerContext) => ({\n * context: ctx,\n * walk: (dx: number, dy: number) => ({ ...ctx, state: 'walking', position: { x: ctx.position.x + dx, y: ctx.position.y + dy } }),\n * attack: () => ({ ...ctx, state: 'attacking' }),\n * }),\n * walking: (ctx: PlayerContext) => ({\n * context: ctx,\n * stop: () => ({ ...ctx, state: 'idle' }),\n * }),\n * attacking: (ctx: PlayerContext) => ({\n * context: ctx,\n * finishAttack: () => ({ ...ctx, state: 'idle' }),\n * }),\n * };\n *\n * const player = createMutableMachine(\n * { state: 'idle', hp: 100, position: { x: 0, y: 0 } },\n * playerFactories,\n * (ctx) => ctx.state\n * );\n *\n * // Simulate a game loop\n * function processInput(input: 'move_right' | 'attack') {\n * if (player.state === 'idle') {\n * if (input === 'move_right') player.walk(1, 0);\n * if (input === 'attack') player.attack();\n * }\n * console.log(`State: ${player.state}, Position: (${player.position.x}, ${player.position.y})`);\n * }\n *\n * processInput('move_right'); // State: walking, Position: (1, 0)\n * player.stop();\n * processInput('attack'); // State: attacking, Position: (1, 0)\n */\nexport function createMutableMachine<\n C extends object,\n F extends Record<string, (context: C) => Machine<C>>\n>(\n sharedContext: C,\n factories: F,\n getDiscriminant: (context: C) => keyof F\n): MutableMachine<C, ReturnType<F[keyof F]>> {\n const getCurrentMachine = (): ReturnType<F[keyof F]> => {\n const currentStateName = getDiscriminant(sharedContext);\n const factory = factories[currentStateName];\n if (!factory) {\n throw new Error(\n `[MutableMachine] Invalid state: No factory for state \"${String(currentStateName)}\".`\n );\n }\n return factory(sharedContext) as ReturnType<F[keyof F]>;\n };\n\n return new Proxy(sharedContext, {\n get(target, prop, _receiver) {\n // 1. Prioritize properties on the context object itself.\n if (prop in target) {\n return (target as any)[prop];\n }\n\n // 2. If not on context, check if it's a valid transition for the current state.\n const currentMachine = getCurrentMachine();\n const transition = (currentMachine as any)[prop];\n\n if (typeof transition === 'function') {\n return (...args: any[]) => {\n // This pattern requires transitions to be pure functions that return the next context.\n const nextContext = transition.apply(currentMachine.context, args);\n if (typeof nextContext !== 'object' || nextContext === null) {\n console.warn(`[MutableMachine] Transition \"${String(prop)}\" did not return a valid context object. State may be inconsistent.`);\n return;\n }\n // 3. Mutate the shared context with the result.\n // Clear existing keys before assigning to handle removed properties.\n Object.keys(target).forEach(key => delete (target as any)[key]);\n Object.assign(target, nextContext);\n };\n }\n\n return undefined;\n },\n set(target, prop, value, _receiver) {\n // Allow direct mutation of the context\n (target as any)[prop] = value;\n return true;\n },\n has(target, prop) {\n // Let checks like `if ('login' in machine)` work correctly.\n const currentMachine = getCurrentMachine();\n return prop in target || typeof (currentMachine as any)[prop] === 'function';\n }\n }) as MutableMachine<C, ReturnType<F[keyof F]>>;\n}"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["step", "metadata", "action", "metadata", "invoke", "invoke", "action"]
|
|
7
7
|
}
|
|
@@ -1 +1,5 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var b=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var J=Object.getOwnPropertyNames;var Y=Object.prototype.hasOwnProperty;var H=(t,e)=>{for(var r in e)b(t,r,{get:e[r],enumerable:!0})},Q=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of J(e))!Y.call(t,n)&&n!==r&&b(t,n,{get:()=>e[n],enumerable:!(o=q(e,n))||o.enumerable});return t};var X=t=>Q(b({},"__esModule",{value:!0}),t);var pe={};H(pe,{META_KEY:()=>K,MachineBase:()=>j,MultiMachineBase:()=>S,RUNTIME_META:()=>M,action:()=>_,createAsyncMachine:()=>se,createEnsemble:()=>ne,createFlow:()=>v,createMachine:()=>y,createMachineBuilder:()=>de,createMachineFactory:()=>ce,createMultiMachine:()=>ie,createMutableMachine:()=>ae,createRunner:()=>U,describe:()=>D,extendTransitions:()=>xe,extractFromInstance:()=>B,extractFunctionMetadata:()=>k,extractMachine:()=>C,extractMachines:()=>V,extractStateNode:()=>m,generateChart:()=>A,generateStatechart:()=>z,guarded:()=>L,hasState:()=>ye,invoke:()=>I,matchMachine:()=>fe,metadata:()=>W,next:()=>ge,overrideTransitions:()=>le,run:()=>E,runAsync:()=>O,runMachine:()=>Me,runSequence:()=>N,runWithDebug:()=>R,runWithEnsemble:()=>oe,runWithRunner:()=>re,setContext:()=>ue,step:()=>F,stepAsync:()=>P,transitionTo:()=>$,yieldMachine:()=>w});module.exports=X(pe);function E(t,e){let r=t(e),o=e;for(;;){let{value:n,done:i}=r.next(o);if(i)return n;o=n}}function F(t){return function*(){return yield t}()}function w(t){return t}function N(t,e){return e.reduce((r,o)=>E(o,r),t)}function v(t){return t}function R(t,e,r=(o,n)=>{console.log(`Step ${o}:`,n.context)}){let o=t(e),n=e,i=0;for(r(i,n);;){let{value:a,done:s}=o.next(n);if(s)return console.log("Final:",a),a;n=a,i++,r(i,n)}}async function O(t,e){let r=t(e),o=e;for(;;){let{value:n,done:i}=await r.next(o);if(i)return n;o=n}}async function*P(t){return yield t}var K=Symbol("MachineMeta"),M=Symbol("__machine_runtime_meta__");function g(t,e){let r=t[M]||{},o={...r,...e};e.guards&&r.guards?o.guards=[...r.guards,...e.guards]:e.guards&&(o.guards=[...e.guards]),e.actions&&r.actions?o.actions=[...r.actions,...e.actions]:e.actions&&(o.actions=[...e.actions]),Object.defineProperty(t,M,{value:o,enumerable:!1,writable:!1,configurable:!0})}function $(t,e){return g(e,{target:t.name||t.toString()}),e}function D(t,e){return g(e,{description:t}),e}function L(t,e){return g(e,{guards:[t]}),e}function I(t,e){return g(e,{invoke:{src:t.src,onDone:t.onDone.name||t.onDone.toString(),onError:t.onError.name||t.onError.toString(),description:t.description}}),e}function _(t,e){return g(e,{actions:[t]}),e}function W(t,e){return e}var c=require("ts-morph");function G(t){return c.Node.isIdentifier(t)?t.getText():c.Node.isTypeOfExpression(t)?t.getExpression().getText():"unknown"}function h(t){if(!c.Node.isObjectLiteralExpression(t))return{};let e={};for(let r of t.getProperties())if(c.Node.isPropertyAssignment(r)){let o=r.getName(),n=r.getInitializer();n&&(c.Node.isStringLiteral(n)||c.Node.isNumericLiteral(n)?e[o]=n.getLiteralValue():n.getText()==="true"||n.getText()==="false"?e[o]=n.getText()==="true":c.Node.isIdentifier(n)?e[o]=n.getText():c.Node.isObjectLiteralExpression(n)?e[o]=h(n):c.Node.isArrayLiteralExpression(n)&&(e[o]=n.getElements().map(i=>c.Node.isObjectLiteralExpression(i)?h(i):i.getText())))}return e}function Z(t){if(!c.Node.isObjectLiteralExpression(t))return{};let e={};for(let r of t.getProperties())if(c.Node.isPropertyAssignment(r)){let o=r.getName(),n=r.getInitializer();if(!n)continue;o==="onDone"||o==="onError"?e[o]=G(n):c.Node.isStringLiteral(n)?e[o]=n.getLiteralValue():c.Node.isIdentifier(n)&&(e[o]=n.getText())}return e}function p(t,e=!1){if(!c.Node.isCallExpression(t))return null;let r=t.getExpression(),o=c.Node.isIdentifier(r)?r.getText():null;if(!o)return null;let n={},i=t.getArguments();switch(o){case"transitionTo":i[0]&&(n.target=G(i[0]));break;case"describe":if(i[0]&&c.Node.isStringLiteral(i[0])&&(n.description=i[0].getLiteralValue()),i[1]&&c.Node.isCallExpression(i[1])){let a=p(i[1],e);a&&Object.assign(n,a)}break;case"guarded":if(i[0]){let a=h(i[0]);Object.keys(a).length>0&&(n.guards=[a])}if(i[1]&&c.Node.isCallExpression(i[1])){let a=p(i[1],e);a&&Object.assign(n,a)}break;case"invoke":if(i[0]){let a=Z(i[0]);Object.keys(a).length>0&&(n.invoke=a)}break;case"action":if(i[0]){let a=h(i[0]);Object.keys(a).length>0&&(n.actions=[a])}if(i[1]&&c.Node.isCallExpression(i[1])){let a=p(i[1],e);a&&Object.assign(n,a)}break;default:return null}return Object.keys(n).length>0?n:null}function ee(t,e=!1){if(!c.Node.isPropertyDeclaration(t))return e&&console.error(" ⚠️ Not a property declaration"),null;let r=t.getInitializer();if(!r)return e&&console.error(" ⚠️ No initializer"),null;if(!c.Node.isCallExpression(r))return e&&console.error(" ⚠️ Initializer is not a call expression"),null;let o=p(r,e);return o&&e&&console.error(" ✅ Extracted metadata:",JSON.stringify(o,null,2)),o}function te(t,e=!1){let r={on:{}},o=t.getDeclarations()[0];if(!o||!c.Node.isClassDeclaration(o))return e&&console.error(`⚠️ Warning: Could not get class declaration for ${t.getName()}`),r;let n=t.getName();e&&console.error(` Analyzing state: ${n}`);for(let i of o.getInstanceMembers()){let a=i.getName();e&&console.error(` Checking member: ${a}`);let s=ee(i,e);if(!s)continue;e&&console.error(` Found transition: ${a}`);let{invoke:u,actions:l,guards:f,...x}=s;if(u&&(r.invoke||(r.invoke=[]),r.invoke.push({src:u.src,onDone:{target:u.onDone},onError:{target:u.onError},description:u.description}),e&&console.error(` → Invoke: ${u.src}`)),x.target){let d={target:x.target};x.description&&(d.description=x.description),f&&(d.cond=f.map(T=>T.name).join(" && "),e&&console.error(` → Guard: ${d.cond}`)),l&&l.length>0&&(d.actions=l.map(T=>T.name),e&&console.error(` → Actions: ${d.actions.join(", ")}`)),r.on[a]=d,e&&console.error(` → Target: ${x.target}`)}}return r}function C(t,e,r=!1){r&&(console.error(`
|
|
2
|
+
🔍 Analyzing machine: ${t.id}`),console.error(` Source: ${t.input}`));let o=e.getSourceFile(t.input);if(!o)throw new Error(`Source file not found: ${t.input}`);let n={id:t.id,initial:t.initialState,states:{}};t.description&&(n.description=t.description);for(let i of t.classes){let a=o.getClass(i);if(!a){console.warn(`⚠️ Warning: Class '${i}' not found in '${t.input}'. Skipping.`);continue}let s=a.getSymbolOrThrow(),u=te(s,r);n.states[i]=u}return r&&console.error(` ✅ Extracted ${t.classes.length} states`),n}function V(t){var n;let e=(n=t.verbose)!=null?n:!1;e&&(console.error(`
|
|
3
|
+
📊 Starting statechart extraction`),console.error(` Machines to extract: ${t.machines.length}`));let r=new c.Project;r.addSourceFilesAtPaths("src/**/*.ts"),r.addSourceFilesAtPaths("examples/**/*.ts");let o=[];for(let i of t.machines)try{let a=C(i,r,e);o.push(a)}catch(a){console.error(`❌ Error extracting machine '${i.id}':`,a),e||console.error(" Run with --verbose for more details")}return e&&console.error(`
|
|
4
|
+
✅ Extraction complete: ${o.length}/${t.machines.length} machines extracted`),o}function A(){let t={input:"examples/authMachine.ts",classes:["LoggedOutMachine","LoggingInMachine","LoggedInMachine","SessionExpiredMachine","ErrorMachine"],id:"auth",initialState:"LoggedOutMachine",description:"Authentication state machine"};console.error("🔍 Using legacy generateChart function"),console.error(`⚠️ Consider using extractMachines() with a config file instead
|
|
5
|
+
`);let e=new c.Project;e.addSourceFilesAtPaths("src/**/*.ts"),e.addSourceFilesAtPaths("examples/**/*.ts");try{let r=C(t,e,!0);console.log(JSON.stringify(r,null,2))}catch(r){console.error("❌ Error:",r),process.exit(1)}}require.main===module&&A();function k(t){return typeof t!="function"?null:t[M]||null}function m(t){let e={on:{}},r=[];for(let o in t){let n=t[o];if(typeof n!="function")continue;let i=k(n);if(i&&(i.invoke&&r.push({src:i.invoke.src,onDone:{target:i.invoke.onDone},onError:{target:i.invoke.onError},description:i.invoke.description}),i.target)){let a={target:i.target};i.description&&(a.description=i.description),i.guards&&i.guards.length>0&&(a.cond=i.guards.map(s=>s.name).join(" && ")),i.actions&&i.actions.length>0&&(a.actions=i.actions.map(s=>s.name)),e.on[o]=a}}return r.length>0&&(e.invoke=r),e}function z(t,e){let r={id:e.id,initial:e.initial,states:{}};e.description&&(r.description=e.description);for(let[o,n]of Object.entries(t))r.states[o]=m(n);return r}function B(t,e){let r=e.stateName||t.constructor.name||"State";return{id:e.id,initial:r,states:{[r]:m(t)}}}function U(t,e){let r=t,o=s=>{r=s,e==null||e(s)},{context:n,...i}=t,a=new Proxy({},{get(s,u){let l=r[u];if(typeof l=="function")return(...f)=>{let x=l.apply(r.context,f),d=Object.assign({context:x.context},i);return o(d),d}}});return{get state(){return r},get context(){return r.context},actions:a,setState:o}}function ne(t,e,r){let o=()=>{let i=t.getContext(),a=r(i),s=e[a];if(!s)throw new Error(`[Ensemble] Invalid state: No factory found for state "${String(a)}".`);return s(i)},n=new Proxy({},{get(i,a){let s=o(),u=s[a];if(typeof u!="function")throw new Error(`[Ensemble] Transition "${a}" is not valid in the current state.`);return(...l)=>u.apply(s.context,l)}});return{get context(){return t.getContext()},get state(){return o()},actions:n}}function re(t,e){let r=U(e),o=t(r),n=o.next();for(;!n.done;)n=o.next();return n.value}function oe(t,e){let r=t(e),o=r.next();for(;!o.done;)o=r.next();return o.value}var S=class{constructor(e){this.store=e}get context(){return this.store.getContext()}setContext(e){this.store.setContext(e)}};function ie(t,e){let r=new t(e);return new Proxy({},{get(o,n){let i=e.getContext();if(n in i)return i[n];let a=r[n];if(typeof a=="function")return(...s)=>a.apply(r,s)},set(o,n,i){let a=e.getContext();if(n in a){let s={...a,[n]:i};return e.setContext(s),!0}return!1},has(o,n){let i=e.getContext();return n in i||typeof r[n]=="function"},ownKeys(o){let n=e.getContext(),i=Object.keys(n),a=Object.getOwnPropertyNames(Object.getPrototypeOf(r)).filter(s=>s!=="constructor"&&typeof r[s]=="function");return Array.from(new Set([...i,...a]))},getOwnPropertyDescriptor(o,n){let i=e.getContext();if(n in i||typeof r[n]=="function")return{value:void 0,writable:!0,enumerable:!0,configurable:!0}}})}function ae(t,e,r){let o=()=>{let n=r(t),i=e[n];if(!i)throw new Error(`[MutableMachine] Invalid state: No factory for state "${String(n)}".`);return i(t)};return new Proxy(t,{get(n,i,a){if(i in n)return n[i];let s=o(),u=s[i];if(typeof u=="function")return(...l)=>{let f=u.apply(s.context,l);if(typeof f!="object"||f===null){console.warn(`[MutableMachine] Transition "${String(i)}" did not return a valid context object. State may be inconsistent.`);return}Object.keys(n).forEach(x=>delete n[x]),Object.assign(n,f)}},set(n,i,a,s){return n[i]=a,!0},has(n,i){let a=o();return i in n||typeof a[i]=="function"}})}function y(t,e){return Object.assign({context:t},e)}function se(t,e){return Object.assign({context:t},e)}function ce(){return t=>{let e=Object.fromEntries(Object.entries(t).map(([r,o])=>[r,function(...n){let i=o(this,...n);return y(i,e)}]));return r=>y(r,e)}}function ue(t,e){let{context:r,...o}=t,n=typeof e=="function"?e(r):e;return y(n,o)}function le(t,e){let{context:r,...o}=t,n={...o,...e};return y(r,n)}function xe(t,e){let{context:r,...o}=t,n={...o,...e};return y(r,n)}function de(t){let{context:e,...r}=t;return o=>y(o,r)}function fe(t,e,r){let o=t.context[e],n=r[o];if(!n)throw new Error(`No handler found for state: ${String(o)}`);return n(t.context)}function ye(t,e,r){return t.context[e]===r}function Me(t,e){let r=t;async function o(n){let i=r[n.type];if(typeof i!="function")throw new Error(`[Machine] Unknown event type '${String(n.type)}' on current state.`);return r=await i.apply(r.context,n.args),e==null||e(r),r}return{get state(){return r.context},dispatch:o}}var j=class{constructor(e){this.context=e}};function ge(t,e){let{context:r,...o}=t;return y(e(r),o)}
|