Skip to content

Core Concepts

The FSM class

FSM is the base class for all state machines, extending eventemitter3’s EventEmitter.

import { FSM } from 'afsm'
class MyFSM extends FSM {
// your states and methods
}
const obj = new MyFSM('my-fsm') // optional name

Key members

MemberDescription
obj.stateCurrent state, type State (string or MiddleState)
obj.stateDiagramAuto-generated mermaid state diagram lines
obj.nameInstance name (shown in DevTools)
obj.groupNameGroup name (defaults to class name)
obj.on/off/emitInherited from EventEmitter
FSM.STATECHANGEDState change event name, constant 'stateChanged'
FSM.INITInitial state, constant '[*]'
FSM.ON / FSM.OFFGeneric state constants 'on' / 'off'

The State type

export type State = string | MiddleState

There are two kinds of state:

  1. Stable states (strings) — e.g. 'idle', 'connected', FSM.INIT
  2. Intermediate states (MiddleState instances) — transient during async execution, toString() returns ${action}ing

For example, calling @ChangeState('idle', 'done') async fetch():

  • Enters intermediate state fetching (a MiddleState instance)
  • On success becomes stable state done
  • On failure rolls back to idle

MiddleState

export class MiddleState {
oldState: State
newState: string
action: string
aborted: boolean
toString() { return `${this.action}ing` }
abort(fsm: IFSM): void
}

An intermediate state describes the transition “from oldState via action toward newState”. It can be aborted via abort() (see Abort & Interruption).

stateDiagram

stateDiagram is a getter that auto-generates mermaid syntax from decorator metadata. It’s memoized on the prototype after first access.

const obj = new MyFSM()
console.log(obj.stateDiagram)
// [
// "[*] --> gotoState1ing : gotoState1",
// "gotoState1ing --> state1 : gotoState1 🟢",
// "gotoState1ing --> [*] : gotoState1 🔴",
// ...
// ]

Drop this into a mermaid stateDiagram-v2 block to render. See Visualizing the Diagram.

Instance registries

FSM has two static registries used by the context composition pattern (see Composing FSMs):

  • FSM.instances: Map<string, IFSM> — string-keyed registry
  • FSM.instances2: WeakMap<object, IFSM> — object-keyed registry
  • FSM.get(context) — get or create the FSM associated with a context
  • FSM.getState(context) — directly fetch a context’s state

The IFSM interface

export interface IFSM extends FSM {}

A self-referential interface for FSM, mainly used in decorator type signatures. In everyday use you just extends FSM.

Next steps