import { Emitter } from '../lifecycle/event/event.js'; export type ISsmRuleMap = MapLike>; type MapLike = Pick, 'get' | 'has' | 'keys'>; export interface IStateChangeEvent { from: StateType; to: StateType; reason: EventType; } export class SimpleStateMachine { protected declare currentState: StateType; protected readonly rules: ISsmRuleMap; private readonly _onStateChange = new Emitter>(); public readonly onStateChange = this._onStateChange.register; constructor(rules: ISsmRuleMap, init_state: StateType) { this.rules = rules; this.moveTo(init_state); } protected moveTo(state: StateType) { if (!this.rules.has(state)) throw new Error(`missing state "${state}"`); this.currentState = state; } getName() { return this.currentState; } change(event: EventType) { const state = this.rules.get(this.currentState); if (!state) throw new Error(`no state "${this.currentState}"`); const next = state.get(event); if (typeof next === 'undefined') { throw new Error( `no event "${event} (${typeof event})" on state "${this.currentState} (${typeof this.currentState})" (has ${[...state.keys()].map((v) => `"${v} (${typeof v})"`).join(', ')})`, ); } const last = this.currentState; this.moveTo(next); this._onStateChange.fireNoError({ from: last, to: next, reason: event }); } }