• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

excaliburjs / Excalibur / 14804036802

02 May 2025 09:58PM UTC coverage: 5.927% (-83.4%) from 89.28%
14804036802

Pull #3404

github

web-flow
Merge 5c103d7f8 into 0f2ccaeb2
Pull Request #3404: feat: added Graph module to Math

234 of 8383 branches covered (2.79%)

229 of 246 new or added lines in 1 file covered. (93.09%)

13145 existing lines in 208 files now uncovered.

934 of 15759 relevant lines covered (5.93%)

4.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/engine/Util/StateMachine.ts
1
export interface State<TData> {
2
  name?: string;
3
  transitions: string[];
4
  onEnter?: (context: { from: string; eventData?: any; data: TData }) => boolean | void;
5
  onState?: () => any;
6
  onExit?: (context: { to: string; data: TData }) => boolean | void;
7
  onUpdate?: (data: TData, elapsed: number) => any;
8
}
9

10
export interface StateMachineDescription<TData = any> {
11
  start: string;
12
  states: { [name: string]: State<TData> };
13
}
14

15
export type PossibleStates<TMachine> = TMachine extends StateMachineDescription ? Extract<keyof TMachine['states'], string> : never;
16

17
export interface StateMachineState<TData> {
18
  data: TData;
19
  currentState: string;
20
}
21

22
export class StateMachine<TPossibleStates extends string, TData> {
23
  public startState: State<TData>;
24
  private _currentState: State<TData>;
25
  public get currentState(): State<TData> {
UNCOV
26
    return this._currentState;
×
27
  }
28
  public set currentState(state: State<TData>) {
UNCOV
29
    this._currentState = state;
×
30
  }
UNCOV
31
  public states = new Map<string, State<TData>>();
×
32
  public data: TData;
33

34
  static create<TMachine extends StateMachineDescription<TData>, TData>(
35
    machineDescription: TMachine,
36
    data?: TData
37
  ): StateMachine<PossibleStates<TMachine>, TData> {
UNCOV
38
    const machine = new StateMachine<PossibleStates<TMachine>, TData>();
×
UNCOV
39
    machine.data = data;
×
UNCOV
40
    for (const stateName in machineDescription.states) {
×
UNCOV
41
      machine.states.set(stateName as PossibleStates<TMachine>, {
×
42
        name: stateName,
43
        ...machineDescription.states[stateName]
44
      });
45
    }
46

47
    // validate transitions are states
UNCOV
48
    for (const state of machine.states.values()) {
×
UNCOV
49
      for (const transitionState of state.transitions) {
×
UNCOV
50
        if (transitionState === '*') {
×
UNCOV
51
          continue;
×
52
        }
UNCOV
53
        if (!machine.states.has(transitionState)) {
×
UNCOV
54
          throw Error(
×
55
            `Invalid state machine, state [${state.name}] has a transition to another state that doesn't exist [${transitionState}]`
56
          );
57
        }
58
      }
59
    }
UNCOV
60
    machine.currentState = machine.startState = machine.states.get(machineDescription.start);
×
UNCOV
61
    return machine;
×
62
  }
63

64
  in(state: TPossibleStates): boolean {
UNCOV
65
    return this.currentState.name === state;
×
66
  }
67

68
  go(stateName: TPossibleStates, eventData?: any): boolean {
UNCOV
69
    if (this.currentState.transitions.includes(stateName) || this.currentState.transitions.includes('*')) {
×
UNCOV
70
      const potentialNewState = this.states.get(stateName);
×
UNCOV
71
      if (this.currentState.onExit) {
×
UNCOV
72
        const canExit = this.currentState?.onExit({ to: potentialNewState.name, data: this.data });
×
UNCOV
73
        if (canExit === false) {
×
UNCOV
74
          return false;
×
75
        }
76
      }
77

UNCOV
78
      if (potentialNewState?.onEnter) {
×
UNCOV
79
        const canEnter = potentialNewState?.onEnter({ from: this.currentState.name, eventData, data: this.data });
×
UNCOV
80
        if (canEnter === false) {
×
UNCOV
81
          return false;
×
82
        }
83
      }
UNCOV
84
      this.currentState = potentialNewState;
×
UNCOV
85
      if (this.currentState?.onState) {
×
UNCOV
86
        this.currentState.onState();
×
87
      }
UNCOV
88
      return true;
×
89
    }
UNCOV
90
    return false;
×
91
  }
92

93
  update(elapsed: number) {
UNCOV
94
    if (this.currentState.onUpdate) {
×
UNCOV
95
      this.currentState.onUpdate(this.data, elapsed);
×
96
    }
97
  }
98

99
  save(saveKey: string) {
UNCOV
100
    localStorage.setItem(
×
101
      saveKey,
102
      JSON.stringify({
103
        currentState: this.currentState.name,
104
        data: this.data
105
      })
106
    );
107
  }
108

109
  restore(saveKey: string) {
UNCOV
110
    const state: StateMachineState<TData> = JSON.parse(localStorage.getItem(saveKey));
×
UNCOV
111
    this.currentState = this.states.get(state.currentState);
×
UNCOV
112
    this.data = state.data;
×
113
  }
114
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc