# context-helpers ## Purpose Provides ergonomic factory helpers for building context-update and side-effect actions that can be slotted directly into `TransitionDefinition.actions` arrays. Without these helpers, every action must be written as an explicit arrow function returning a new context, which becomes verbose for simple partial-update or logging scenarios. The two helpers mirror the `assign` and `pure` patterns popularised by XState, adapted to the `@suaveplan/fsm` action signature. ## Features - `assign(patch)` — shallow-merges a static partial object into the context - `assign(fn)` — delegates to a context-mapping function for complex derivations - `pure(fn)` — wraps a side-effect function ensuring its return value never corrupts the context - Both helpers are fully typed against the machine's `TContext` generic parameter ## Usage: Basic Example ```ts import { assign, pure, createMachine } from '@suaveplan/fsm'; interface Ctx { count: number; lastEvent: string } const machine = createMachine({ initial: 'idle', context: { count: 0, lastEvent: '' }, states: { idle: { on: { INCREMENT: { target: 'idle', actions: [ assign(ctx => ({ ...ctx, count: ctx.count + 1 })), pure((ctx, evt) => { console.log('incremented', ctx, evt); }), ], }, }, }, }, }); ``` ## Usage: Advanced Example ```ts import { assign } from '@suaveplan/fsm'; interface WizardCtx { step: number; formData: Record; completed: boolean; } // Static patch (shallow merge) const resetWizard = assign({ step: 1, completed: false }); // Functional update with derived logic const advanceStep = assign(ctx => ({ ...ctx, step: ctx.step + 1, completed: ctx.step + 1 >= 5, })); // Compose them in a transition const machine = createMachine({ initial: 'wizard', context: { step: 1, formData: {}, completed: false }, states: { wizard: { on: { NEXT: { target: 'wizard', actions: [advanceStep] }, RESET: { target: 'wizard', actions: [resetWizard] }, }, }, }, }); ``` ## API Reference ### `assign(updater): (context: TContext, event: FSMEvent) => TContext` **Parameters:** - `updater` — either a `Partial` patch object or a function `(ctx: TContext) => TContext` **Returns:** An action function compatible with `TransitionDefinition.actions`. **Behaviour:** - If `updater` is a plain object, it performs `{ ...context, ...updater }`. - If `updater` is a function, it calls `updater(context)` and returns the result. ### `pure(fn): (context: TContext, event: FSMEvent) => void` **Parameters:** - `fn` — a `(context: TContext, event: FSMEvent) => void` side-effect function **Returns:** A wrapped action function whose return value is always `void`. **Behaviour:** Calls `fn(context, event)` and discards any return value. This prevents accidental context mutations from side-effect functions that inadvertently return a value. ## Implementation Notes `assign` accepts both object and function forms by checking `typeof updater === 'function'`. The cast `updater as (ctx: TContext) => TContext` is required because TypeScript cannot narrow a union of `Partial` and `(ctx) => TContext` cleanly at the call site without the explicit cast. `pure` exists as a safety wrapper rather than a direct alias because some developers write side-effect actions as `(ctx, evt) => doSomething()` where `doSomething` returns a non-void value. Without `pure`, that non-void value would be treated as a context replacement by the interpreter.