first commit
This commit is contained in:
89
docs/foundation/flow/fsm/src/utils/definition-validator.md
Normal file
89
docs/foundation/flow/fsm/src/utils/definition-validator.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# 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
|
||||
|
||||
```ts
|
||||
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
|
||||
|
||||
```ts
|
||||
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.
|
||||
Reference in New Issue
Block a user