Files
suaveplan/packages/foundation/flow/fsm/src/utils/definition-validator.md
2026-05-27 23:47:53 +01:00

3.1 KiB

definition-validator

Purpose

Validates an FSMDefinition object before the interpreter begins executing. Early structural validation prevents subtle runtime bugs such as transitions leading to undefined states or machines that can never leave their initial state due to a misconfigured initial key.

The validator is called automatically by FSMInterpreter's constructor and by createMachine(). It can also be called standalone to check definitions at authoring time, in build pipelines, or within test suites that assert that certain configurations are correct.

Features

  • Verifies the top-level initial state exists in states
  • Recursively collects all transition target references (including nested state trees) and confirms every target is a known state name
  • Ensures any state node that declares child states also provides an initial child key
  • Ensures that declared initial children actually exist within their parent's states map
  • Throws FSMError with code FSM.INVALID_DEFINITION and rich context metadata on any failure

Usage: Basic Example

import { validateDefinition } from '@suaveplan/fsm';

validateDefinition({
  initial: 'idle',
  context: {},
  states: {
    idle: { on: { START: { target: 'active' } } },
    active: { on: { STOP: { target: 'idle' } } },
  },
});
// No error — definition is valid

Usage: Advanced Example

import { validateDefinition } from '@suaveplan/fsm';
import { FSMError, FSM_CODES } from '@suaveplan/fsm/errors';

// Catch and inspect validation errors
try {
  validateDefinition({
    initial: 'ghost',   // "ghost" is not in states
    context: {},
    states: { idle: {} },
  });
} catch (err) {
  if (err instanceof FSMError && err.code === FSM_CODES.INVALID_DEFINITION) {
    // err.context?.initial === 'ghost'
    console.error('Bad definition:', err.message);
  }
}

// Hierarchical definition with nested initial
validateDefinition({
  initial: 'form',
  context: { step: 1 },
  states: {
    form: {
      initial: 'step1',
      states: {
        step1: { on: { NEXT: { target: 'step2' } } },
        step2: { on: { BACK: { target: 'step1' } } },
      },
    },
  },
});

API Reference

validateDefinition<TContext>(def: FSMDefinition<TContext>): void

Parameters:

  • def — the complete FSM definition to validate

Returns: void (pure side-effect: throws on invalid input)

Throws: FSMError with code FSM.INVALID_DEFINITION and a context object containing the offending state/target names.

Generic parameter:

  • TContext — the machine's extended context type; used only for correct typing of the definition shape.

Implementation Notes

State name collection is done with a recursive depth-first traversal of the states map. Both fully-qualified dotted names (e.g. "form.step1") and short names (e.g. "step1") are added to the lookup set so that authors can use either convention in their target strings.

The validator deliberately does not check guard function arity or action return types — those are runtime concerns enforced by TypeScript at compile time. The focus here is purely structural integrity of the state graph.