@vsirotin/ts-stop 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +173 -0
  2. package/lib/DefaultState.d.ts +9 -0
  3. package/lib/DefaultState.d.ts.map +1 -0
  4. package/lib/DefaultState.js +15 -0
  5. package/lib/DefaultState.js.map +1 -0
  6. package/lib/FiniteStateMachine.d.ts +222 -0
  7. package/lib/FiniteStateMachine.d.ts.map +1 -0
  8. package/lib/FiniteStateMachine.js +302 -0
  9. package/lib/FiniteStateMachine.js.map +1 -0
  10. package/lib/IStateWithActions.d.ts +18 -0
  11. package/lib/IStateWithActions.d.ts.map +1 -0
  12. package/lib/IStateWithActions.js +3 -0
  13. package/lib/IStateWithActions.js.map +1 -0
  14. package/lib/IStateWithOutputSignal.d.ts +4 -0
  15. package/lib/IStateWithOutputSignal.d.ts.map +1 -0
  16. package/lib/IStateWithOutputSignal.js +3 -0
  17. package/lib/IStateWithOutputSignal.js.map +1 -0
  18. package/lib/MatrixBasedStateMachine.d.ts +108 -0
  19. package/lib/MatrixBasedStateMachine.d.ts.map +1 -0
  20. package/lib/MatrixBasedStateMachine.js +132 -0
  21. package/lib/MatrixBasedStateMachine.js.map +1 -0
  22. package/lib/TransitionMatrix.d.ts +61 -0
  23. package/lib/TransitionMatrix.d.ts.map +1 -0
  24. package/lib/TransitionMatrix.js +104 -0
  25. package/lib/TransitionMatrix.js.map +1 -0
  26. package/lib/esm/DefaultState.js +10 -0
  27. package/lib/esm/FiniteStateMachine.js +297 -0
  28. package/lib/esm/IStateWithActions.js +1 -0
  29. package/lib/esm/IStateWithOutputSignal.js +1 -0
  30. package/lib/esm/MatrixBasedStateMachine.js +127 -0
  31. package/lib/esm/TransitionMatrix.js +98 -0
  32. package/lib/esm/index.js +9 -0
  33. package/lib/index.d.ts +10 -0
  34. package/lib/index.d.ts.map +1 -0
  35. package/lib/index.js +26 -0
  36. package/lib/index.js.map +1 -0
  37. package/package.json +45 -0
@@ -0,0 +1,302 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FiniteStateMachine = void 0;
4
+ const DefaultState_1 = require("./DefaultState");
5
+ /**
6
+ * Concrete implementation of a finite state machine with optional state actions.
7
+ *
8
+ * This class supports states that can optionally implement action interfaces:
9
+ * - IStateWithAfterEntryAction: Execute action when entering the state
10
+ * - IStateWithBeforeExitAction: Execute action when exiting the state
11
+ * - Both interfaces: Execute both entry and exit actions
12
+ * - Neither interface: Traditional state machine behavior (no actions)
13
+ *
14
+ * @template STATE - The type representing possible states
15
+ * @template SIGNAL - The type representing signals/events
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * // Basic string-based turnstile (traditional approach)
20
+ * class Turnstile extends FiniteStateMachine<string, string> {
21
+ * constructor() {
22
+ * super(
23
+ * ['locked', 'unlocked'],
24
+ * ['coin', 'push'],
25
+ * [
26
+ * { from: 'locked', signal: 'coin', to: 'unlocked' },
27
+ * { from: 'unlocked', signal: 'push', to: 'locked' }
28
+ * ],
29
+ * 'locked'
30
+ * );
31
+ * }
32
+ *
33
+ * ...
34
+ * }
35
+ *
36
+
37
+ *
38
+ * class TurnstileWithActions extends FiniteStateMachine<ActionState, string> {
39
+ * private locked = new ActionState('locked', 'Payment required');
40
+ * private unlocked = new ActionState('unlocked', 'Please proceed');
41
+ *
42
+ * constructor() {
43
+ * super(
44
+ * [this.locked, this.unlocked],
45
+ * ['coin', 'push'],
46
+ * [
47
+ * { from: this.locked, signal: 'coin', to: this.unlocked },
48
+ * { from: this.unlocked, signal: 'push', to: this.locked }
49
+ * ],
50
+ * this.locked
51
+ * );
52
+ * }
53
+ *
54
+ * insertCoin(): ActionState { return this.sendSignal('coin'); }
55
+ * pushThrough(): ActionState { return this.sendSignal('push'); }
56
+ * }
57
+ *
58
+ * ```
59
+ */
60
+ class FiniteStateMachine {
61
+ /**
62
+ * Creates a new finite state machine.
63
+ *
64
+ * @param states - Array of all possible states
65
+ * @param signals - Array of all possible signals/events
66
+ * @param transitions - Array of transition rules defining how signals move between states
67
+ * @param startState - The initial state of the machine
68
+ */
69
+ constructor(states, signals, transitions, startState) {
70
+ this.states = states;
71
+ this.signals = signals;
72
+ this.transitions = transitions;
73
+ this.startState = startState;
74
+ /**
75
+ * The default state that handles invalid signals.
76
+ * Set to null if no state implements IDefaultState.
77
+ */
78
+ this.defaultState = null;
79
+ // Find states that implement IDefaultState
80
+ const defaultStates = states.filter(state => this.isDefaultState(state));
81
+ // Validate default state count
82
+ if (defaultStates.length > 1) {
83
+ throw new Error(`Multiple states implement IDefaultState interface. ` +
84
+ `Only one state can handle invalid signals. ` +
85
+ `Found ${defaultStates.length} states with IDefaultState.`);
86
+ }
87
+ // Set default state if exactly one found
88
+ if (defaultStates.length === 1) {
89
+ this.defaultState = defaultStates[0];
90
+ }
91
+ // Initialize the machine to its starting state
92
+ this.currentState = startState;
93
+ // Check if a current state has output signal and process it
94
+ this.tryProcessStateWithOutputSignal();
95
+ // Execute initial state entry action if supported
96
+ this.executeEntryAction(this.currentState);
97
+ }
98
+ /**
99
+ * Gets the current state of the state machine.
100
+ *
101
+ * @returns The current state
102
+ */
103
+ getCurrentState() {
104
+ return this.currentState;
105
+ }
106
+ /**
107
+ * Processes a signal and potentially transitions to a new state with action execution.
108
+ *
109
+ * This method:
110
+ * 1. Finds a matching transition for the current state and signal
111
+ * 2. If found and the target state is different:
112
+ * a. Executes beforeExitAction on current state (if implemented)
113
+ * b. Changes to the new state
114
+ * c. Executes afterEntryAction on new state (if implemented)
115
+ * 3. Returns the resulting state
116
+ *
117
+ * @param signal - The signal/event to process
118
+ * @returns The resulting state after processing the signal
119
+ */
120
+ sendSignal(signal) {
121
+ // Find a transition that matches current state and signal
122
+ const transition = this.transitions.find(t => t.from === this.currentState && t.signal === signal);
123
+ // If valid transition found, handle state change with actions
124
+ if (transition) {
125
+ this.executeStateTransition(transition);
126
+ }
127
+ else if (this.defaultState) {
128
+ // No valid transition found, but default state exists
129
+ // Execute default state's actions (entry/exit if implemented)
130
+ this.executeStateActions(this.defaultState);
131
+ // Current state remains unchanged
132
+ }
133
+ this.tryProcessStateWithOutputSignal();
134
+ return this.currentState;
135
+ }
136
+ tryProcessStateWithOutputSignal() {
137
+ if (this.isStateWithOutputSignal(this.currentState)) {
138
+ // Processing of behaviour for state with inside calculated output signal
139
+ this.executeStateActions(this.currentState);
140
+ const stateWithOutputSignal = this.currentState;
141
+ const outputSignal = stateWithOutputSignal.getOutputSignal();
142
+ // Add null/undefined check to prevent errors
143
+ if (outputSignal !== null && outputSignal !== undefined) {
144
+ this.sendSignal(outputSignal);
145
+ }
146
+ }
147
+ }
148
+ isStateWithOutputSignal(state) {
149
+ const obj = state;
150
+ return (typeof obj === 'object' &&
151
+ obj !== null &&
152
+ typeof obj.getOutputSignal === 'function');
153
+ }
154
+ executeStateTransition(transition) {
155
+ const oldState = this.currentState;
156
+ const newState = transition.to;
157
+ // Only execute actions if there's an actual state change
158
+ if (oldState !== newState) {
159
+ // Execute before exit action on current state
160
+ this.executeExitAction(oldState);
161
+ // Change state
162
+ this.currentState = newState;
163
+ // Execute after entry action on new state
164
+ this.executeEntryAction(newState);
165
+ }
166
+ }
167
+ executeStateActions(state) {
168
+ this.executeEntryAction(state);
169
+ this.executeExitAction(state);
170
+ }
171
+ /**
172
+ * Type guard to check if a state is an instance of DefaultState class.
173
+ *
174
+ * @param state - The state to check
175
+ * @returns true if the state is an instance of DefaultState
176
+ */
177
+ isDefaultState(state) {
178
+ return state instanceof DefaultState_1.DefaultState;
179
+ }
180
+ /**
181
+ * Type guard to check if a state implements IStateWithAfterEntryAction.
182
+ *
183
+ * @param state - The state to check
184
+ * @returns true if the state implements afterEntryAction method
185
+ */
186
+ hasAfterEntryAction(state) {
187
+ return typeof state === 'object' &&
188
+ state !== null &&
189
+ 'afterEntryAction' in state &&
190
+ typeof state.afterEntryAction === 'function';
191
+ }
192
+ /**
193
+ * Type guard to check if a state implements IStateWithBeforeExitAction.
194
+ *
195
+ * @param state - The state to check
196
+ * @returns true if the state implements beforeExitAction method
197
+ */
198
+ hasBeforeExitAction(state) {
199
+ return typeof state === 'object' &&
200
+ state !== null &&
201
+ 'beforeExitAction' in state &&
202
+ typeof state.beforeExitAction === 'function';
203
+ }
204
+ /**
205
+ * Executes the afterEntryAction on a state if it implements IStateWithAfterEntryAction.
206
+ *
207
+ * @param state - The state to execute the entry action on
208
+ */
209
+ executeEntryAction(state) {
210
+ if (this.hasAfterEntryAction(state)) {
211
+ state.afterEntryAction();
212
+ }
213
+ }
214
+ /**
215
+ * Executes the beforeExitAction on a state if it implements IStateWithBeforeExitAction.
216
+ *
217
+ * @param state - The state to execute the exit action on
218
+ */
219
+ executeExitAction(state) {
220
+ if (this.hasBeforeExitAction(state)) {
221
+ state.beforeExitAction();
222
+ }
223
+ }
224
+ /**
225
+ * Gets all possible states.
226
+ *
227
+ * @returns Array of all states
228
+ */
229
+ getAllStates() {
230
+ return [...this.states];
231
+ }
232
+ /**
233
+ * Gets all possible signals.
234
+ *
235
+ * @returns Array of all signals
236
+ */
237
+ getAllSignals() {
238
+ return [...this.signals];
239
+ }
240
+ /**
241
+ * Checks if a given signal is valid from the current state.
242
+ *
243
+ * @param signal - The signal to check
244
+ * @returns true if the signal can trigger a transition from the current state
245
+ */
246
+ isValidSignalFromCurrentState(signal) {
247
+ return this.transitions.some(t => t.from === this.currentState && t.signal === signal);
248
+ }
249
+ /**
250
+ * Gets all valid signals from the current state.
251
+ *
252
+ * @returns Array of signals that can trigger transitions from the current state
253
+ */
254
+ getValidSignalsFromCurrentState() {
255
+ return this.transitions
256
+ .filter(t => t.from === this.currentState)
257
+ .map(t => t.signal);
258
+ }
259
+ /**
260
+ * Gets all transitions.
261
+ *
262
+ * @returns Array of all transitions
263
+ */
264
+ getTransitions() {
265
+ return [...this.transitions];
266
+ }
267
+ /**
268
+ * Checks if a signal is valid in the state machine.
269
+ * @param signal - The signal to check
270
+ * @returns True if the signal is valid, false otherwise.
271
+ */
272
+ hasSignal(signal) {
273
+ return this.getAllSignals().includes(signal);
274
+ }
275
+ /**
276
+ * Checks if a given state exists in the state machine.
277
+ *
278
+ * @param state - The state to check
279
+ * @returns true if the state exists, false otherwise
280
+ */
281
+ hasState(state) {
282
+ return this.getAllStates().includes(state);
283
+ }
284
+ /**
285
+ * Gets the default state that handles invalid signals.
286
+ *
287
+ * @returns The default state or null if none exists
288
+ */
289
+ getDefaultState() {
290
+ return this.defaultState;
291
+ }
292
+ /**
293
+ * Checks if the state machine has a default state.
294
+ *
295
+ * @returns true if a default state exists
296
+ */
297
+ hasDefaultState() {
298
+ return this.defaultState !== null;
299
+ }
300
+ }
301
+ exports.FiniteStateMachine = FiniteStateMachine;
302
+ //# sourceMappingURL=FiniteStateMachine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FiniteStateMachine.js","sourceRoot":"","sources":["../src/FiniteStateMachine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Interface for states that have an action after entry.
3
+ */
4
+ export interface IStateWithAfterEntryAction {
5
+ afterEntryAction: () => void;
6
+ }
7
+ /**
8
+ * Interface for states that have an action before exit.
9
+ */
10
+ export interface IStateWithBeforeExitAction {
11
+ beforeExitAction: () => void;
12
+ }
13
+ /**
14
+ * Interface combining both entry and exit actions.
15
+ */
16
+ export interface IStateWithActions extends IStateWithAfterEntryAction, IStateWithBeforeExitAction {
17
+ }
18
+ //# sourceMappingURL=IStateWithActions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IStateWithActions.d.ts","sourceRoot":"","sources":["../src/IStateWithActions.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC,gBAAgB,EAAE,MAAM,IAAI,CAAC;CAChC;AACD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC,gBAAgB,EAAE,MAAM,IAAI,CAAC;CAChC;AACD;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,0BAA0B,EAAE,0BAA0B;CAAI"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=IStateWithActions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IStateWithActions.js","sourceRoot":"","sources":["../src/IStateWithActions.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ export interface IStateWithOutputSignal<SIGNAL> {
2
+ getOutputSignal(): SIGNAL;
3
+ }
4
+ //# sourceMappingURL=IStateWithOutputSignal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IStateWithOutputSignal.d.ts","sourceRoot":"","sources":["../src/IStateWithOutputSignal.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,sBAAsB,CAAC,MAAM;IAC1C,eAAe,IAAI,MAAM,CAAC;CAC7B"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=IStateWithOutputSignal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IStateWithOutputSignal.js","sourceRoot":"","sources":["../src/IStateWithOutputSignal.ts"],"names":[],"mappings":""}
@@ -0,0 +1,108 @@
1
+ import { FiniteStateMachine } from './FiniteStateMachine';
2
+ import { TransitionMatrix } from './TransitionMatrix';
3
+ /**
4
+ * Abstract base class for finite state machines that use transition matrices.
5
+ *
6
+ * This class extends FiniteStateMachine to provide a more intuitive way to define
7
+ * state transitions using a 2D matrix representation instead of explicit transition arrays.
8
+ *
9
+ * The matrix format allows for visual representation of state transitions:
10
+ * - Columns represent states
11
+ * - Rows represent signals
12
+ * - Cell values represent target states
13
+ * - Empty cells represent invalid/ignored transitions
14
+ *
15
+ * @template STATE - The type representing possible states
16
+ * @template SIGNAL - The type representing signals/events
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * // Example 1: Using explicit start state
21
+ * class TurnstileMatrix extends MatrixBasedStateMachine<string, string> {
22
+ * constructor() {
23
+ * const matrix = transitionMatrix([
24
+ * [ , "locked" , "unlocked" ],
25
+ * [ "coin" , "unlocked" , ],
26
+ * [ "push" , , "locked" ]
27
+ * ]);
28
+ * super(matrix, "locked"); // Explicit start state
29
+ * }
30
+ * }
31
+ *
32
+ * // Example 2: Using first state as start state (auto)
33
+ * class TurnstileMatrixAuto extends MatrixBasedStateMachine<string, string> {
34
+ * constructor() {
35
+ * const matrix = transitionMatrix([
36
+ * [ , "locked" , "unlocked" ], // "locked" becomes start state
37
+ * [ "coin" , "unlocked" , ],
38
+ * [ "push" , , "locked" ]
39
+ * ]);
40
+ * super(matrix); // Uses first state ("locked") as start state
41
+ * }
42
+ * }
43
+ * ```
44
+ */
45
+ export declare abstract class MatrixBasedStateMachine<STATE, SIGNAL> extends FiniteStateMachine<STATE, SIGNAL> {
46
+ /**
47
+ * The transition matrix used to define state transitions.
48
+ * Stored for potential debugging or inspection purposes.
49
+ */
50
+ protected readonly matrix: TransitionMatrix<STATE, SIGNAL>;
51
+ /**
52
+ * Creates a new matrix-based finite state machine.
53
+ *
54
+ * @param matrix - The transition matrix defining all states, signals, and transitions
55
+ * @param startState - Optional. The initial state of the machine. If not provided,
56
+ * the first state from the matrix (first column in header row) will be used.
57
+ * If provided, must be one of the states in the matrix.
58
+ *
59
+ * @throws {Error} If matrix has no states
60
+ * @throws {Error} If startState is provided but not found in the matrix states
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * // Constructor with explicit start state
65
+ * const matrix = transitionMatrix([
66
+ * [ , "locked" , "unlocked" ],
67
+ * [ "coin" , "unlocked" , ],
68
+ * [ "push" , , "locked" ]
69
+ * ]);
70
+ * super(matrix, "unlocked"); // Start in unlocked state
71
+ *
72
+ * // Constructor with auto start state (uses first state)
73
+ * super(matrix); // Automatically starts in "locked" state
74
+ * ```
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * // TurnstileMatrix implementation from test/Turnstile/TurnstileMatrix.ts
79
+ * class TurnstileMatrix extends MatrixBasedStateMachine<string, string> {
80
+ * constructor() {
81
+ * const matrix = transitionMatrix([
82
+ * [ , "locked" , "unlocked" ],
83
+ * [ "coin" , "unlocked" , ],
84
+ * [ "push" , , "locked" ]
85
+ * ]);
86
+ *
87
+ * // Two ways to call the constructor:
88
+ * super(matrix, "locked"); // Option 1: Explicit start state
89
+ * // OR
90
+ * super(matrix); // Option 2: Auto start state (uses "locked")
91
+ * }
92
+ *
93
+ * insertCoin(): string { return this.sendSignal('coin'); }
94
+ * pushThrough(): string { return this.sendSignal('push'); }
95
+ * isLocked(): boolean { return this.getCurrentState() === 'locked'; }
96
+ * isUnlocked(): boolean { return this.getCurrentState() === 'unlocked'; }
97
+ * }
98
+ * ```
99
+ */
100
+ constructor(matrix: TransitionMatrix<STATE, SIGNAL>, startState?: STATE);
101
+ /**
102
+ * Gets the transition matrix used by this state machine.
103
+ *
104
+ * @returns The transition matrix
105
+ */
106
+ getMatrix(): TransitionMatrix<STATE, SIGNAL>;
107
+ }
108
+ //# sourceMappingURL=MatrixBasedStateMachine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MatrixBasedStateMachine.d.ts","sourceRoot":"","sources":["../src/MatrixBasedStateMachine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAuB,MAAM,sBAAsB,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,8BAAsB,uBAAuB,CAAC,KAAK,EAAE,MAAM,CAAE,SAAQ,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC;IAClG;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAE3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgDG;gBACS,MAAM,EAAE,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC,EAAE,KAAK;IAqCvE;;;;OAIG;IACH,SAAS,IAAI,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC;CAI/C"}
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MatrixBasedStateMachine = void 0;
4
+ const FiniteStateMachine_1 = require("./FiniteStateMachine");
5
+ /**
6
+ * Abstract base class for finite state machines that use transition matrices.
7
+ *
8
+ * This class extends FiniteStateMachine to provide a more intuitive way to define
9
+ * state transitions using a 2D matrix representation instead of explicit transition arrays.
10
+ *
11
+ * The matrix format allows for visual representation of state transitions:
12
+ * - Columns represent states
13
+ * - Rows represent signals
14
+ * - Cell values represent target states
15
+ * - Empty cells represent invalid/ignored transitions
16
+ *
17
+ * @template STATE - The type representing possible states
18
+ * @template SIGNAL - The type representing signals/events
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * // Example 1: Using explicit start state
23
+ * class TurnstileMatrix extends MatrixBasedStateMachine<string, string> {
24
+ * constructor() {
25
+ * const matrix = transitionMatrix([
26
+ * [ , "locked" , "unlocked" ],
27
+ * [ "coin" , "unlocked" , ],
28
+ * [ "push" , , "locked" ]
29
+ * ]);
30
+ * super(matrix, "locked"); // Explicit start state
31
+ * }
32
+ * }
33
+ *
34
+ * // Example 2: Using first state as start state (auto)
35
+ * class TurnstileMatrixAuto extends MatrixBasedStateMachine<string, string> {
36
+ * constructor() {
37
+ * const matrix = transitionMatrix([
38
+ * [ , "locked" , "unlocked" ], // "locked" becomes start state
39
+ * [ "coin" , "unlocked" , ],
40
+ * [ "push" , , "locked" ]
41
+ * ]);
42
+ * super(matrix); // Uses first state ("locked") as start state
43
+ * }
44
+ * }
45
+ * ```
46
+ */
47
+ class MatrixBasedStateMachine extends FiniteStateMachine_1.FiniteStateMachine {
48
+ /**
49
+ * Creates a new matrix-based finite state machine.
50
+ *
51
+ * @param matrix - The transition matrix defining all states, signals, and transitions
52
+ * @param startState - Optional. The initial state of the machine. If not provided,
53
+ * the first state from the matrix (first column in header row) will be used.
54
+ * If provided, must be one of the states in the matrix.
55
+ *
56
+ * @throws {Error} If matrix has no states
57
+ * @throws {Error} If startState is provided but not found in the matrix states
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * // Constructor with explicit start state
62
+ * const matrix = transitionMatrix([
63
+ * [ , "locked" , "unlocked" ],
64
+ * [ "coin" , "unlocked" , ],
65
+ * [ "push" , , "locked" ]
66
+ * ]);
67
+ * super(matrix, "unlocked"); // Start in unlocked state
68
+ *
69
+ * // Constructor with auto start state (uses first state)
70
+ * super(matrix); // Automatically starts in "locked" state
71
+ * ```
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * // TurnstileMatrix implementation from test/Turnstile/TurnstileMatrix.ts
76
+ * class TurnstileMatrix extends MatrixBasedStateMachine<string, string> {
77
+ * constructor() {
78
+ * const matrix = transitionMatrix([
79
+ * [ , "locked" , "unlocked" ],
80
+ * [ "coin" , "unlocked" , ],
81
+ * [ "push" , , "locked" ]
82
+ * ]);
83
+ *
84
+ * // Two ways to call the constructor:
85
+ * super(matrix, "locked"); // Option 1: Explicit start state
86
+ * // OR
87
+ * super(matrix); // Option 2: Auto start state (uses "locked")
88
+ * }
89
+ *
90
+ * insertCoin(): string { return this.sendSignal('coin'); }
91
+ * pushThrough(): string { return this.sendSignal('push'); }
92
+ * isLocked(): boolean { return this.getCurrentState() === 'locked'; }
93
+ * isUnlocked(): boolean { return this.getCurrentState() === 'unlocked'; }
94
+ * }
95
+ * ```
96
+ */
97
+ constructor(matrix, startState) {
98
+ // Get states from matrix
99
+ const states = matrix.getStates();
100
+ // Validate matrix has states
101
+ if (states.length === 0) {
102
+ throw new Error('Matrix must contain at least one state');
103
+ }
104
+ // Determine the actual start state
105
+ let actualStartState;
106
+ if (startState !== undefined) {
107
+ // Explicit start state provided - validate it exists
108
+ if (!states.includes(startState)) {
109
+ throw new Error(`Start state '${String(startState)}' not found in matrix states: [${states.map(s => String(s)).join(', ')}]`);
110
+ }
111
+ actualStartState = startState;
112
+ }
113
+ else {
114
+ // No start state provided - use first state from matrix
115
+ actualStartState = states[0];
116
+ }
117
+ // Call parent constructor with matrix-derived data
118
+ super(matrix.getStates(), matrix.getSignals(), matrix.getTransitions(), actualStartState);
119
+ // Store the matrix for potential future use
120
+ this.matrix = matrix;
121
+ }
122
+ /**
123
+ * Gets the transition matrix used by this state machine.
124
+ *
125
+ * @returns The transition matrix
126
+ */
127
+ getMatrix() {
128
+ return this.matrix;
129
+ }
130
+ }
131
+ exports.MatrixBasedStateMachine = MatrixBasedStateMachine;
132
+ //# sourceMappingURL=MatrixBasedStateMachine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MatrixBasedStateMachine.js","sourceRoot":"","sources":["../src/MatrixBasedStateMachine.ts"],"names":[],"mappings":";;;AAAA,6DAA+E;AAG/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,MAAsB,uBAAuC,SAAQ,uCAAiC;IAOlG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgDG;IACH,YAAY,MAAuC,EAAE,UAAkB;QACnE,yBAAyB;QACzB,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QAElC,6BAA6B;QAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC9D,CAAC;QAED,mCAAmC;QACnC,IAAI,gBAAuB,CAAC;QAE5B,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC3B,qDAAqD;YACrD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CACX,gBAAgB,MAAM,CAAC,UAAU,CAAC,kCAAkC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC/G,CAAC;YACN,CAAC;YACD,gBAAgB,GAAG,UAAU,CAAC;QAClC,CAAC;aAAM,CAAC;YACJ,wDAAwD;YACxD,gBAAgB,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACjC,CAAC;QAED,mDAAmD;QACnD,KAAK,CACD,MAAM,CAAC,SAAS,EAAE,EAClB,MAAM,CAAC,UAAU,EAAE,EACnB,MAAM,CAAC,cAAc,EAAE,EACvB,gBAAgB,CACnB,CAAC;QAEF,4CAA4C;QAC5C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;IAED;;;;OAIG;IACH,SAAS;QACL,OAAO,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;CAEJ;AAtGD,0DAsGC"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Utility type to extract non-empty values from transition matrix
3
+ */
4
+ export type NonEmpty<T> = T extends "" | undefined | null ? never : T;
5
+ /**
6
+ * Creates transitions from a 2D matrix representation.
7
+ *
8
+ * Matrix format:
9
+ * - First row: [undefined, ...states] - column headers
10
+ * - Subsequent rows: [signal, ...transitions] - signal + target states
11
+ * - Empty cells: undefined, null, "", or omitted
12
+ *
13
+ * @template STATE - Type for states
14
+ * @template SIGNAL - Type for signals
15
+ */
16
+ export declare class TransitionMatrix<STATE, SIGNAL> {
17
+ private states;
18
+ private signals;
19
+ private transitions;
20
+ /**
21
+ * Creates a transition matrix from a 2D array.
22
+ *
23
+ * @param matrix - 2D array where:
24
+ * - matrix[0] = [undefined, ...states] (header row)
25
+ * - matrix[i] = [signal, target1, target2, ...] (transition rows)
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * const matrix = [
30
+ * [ , "locked" , "unlocked" ], // States header
31
+ * [ "coin" , "unlocked" , ], // coin transitions
32
+ * [ "push" , , "locked" ] // push transitions
33
+ * ];
34
+ * ```
35
+ */
36
+ static fromArray<S, G>(matrix: Array<Array<S | G | undefined | null | "">>): TransitionMatrix<NonEmpty<S>, NonEmpty<G>>;
37
+ /**
38
+ * Get all states from the matrix.
39
+ */
40
+ getStates(): STATE[];
41
+ /**
42
+ * Get all signals from the matrix.
43
+ */
44
+ getSignals(): SIGNAL[];
45
+ /**
46
+ * Get all transitions from the matrix.
47
+ */
48
+ getTransitions(): {
49
+ from: STATE;
50
+ to: STATE;
51
+ signal: SIGNAL;
52
+ }[];
53
+ }
54
+ /**
55
+ * Helper function to create transition matrix from 2D array.
56
+ *
57
+ * @template S - State type
58
+ * @template G - Signal type
59
+ */
60
+ export declare function transitionMatrix<S, G>(matrix: Array<Array<S | G | undefined | null | "">>): TransitionMatrix<NonEmpty<S>, NonEmpty<G>>;
61
+ //# sourceMappingURL=TransitionMatrix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TransitionMatrix.d.ts","sourceRoot":"","sources":["../src/TransitionMatrix.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,SAAS,GAAG,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC;AAEtE;;;;;;;;;;GAUG;AACH,qBAAa,gBAAgB,CAAC,KAAK,EAAE,MAAM;IACvC,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,WAAW,CAAoD;IAEvE;;;;;;;;;;;;;;;OAeG;IACH,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EACjB,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,GACpD,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAiD7C;;OAEG;IACH,SAAS,IAAI,KAAK,EAAE;IAIpB;;OAEG;IACH,UAAU,IAAI,MAAM,EAAE;IAItB;;OAEG;IACH,cAAc,IAAI;QAAE,IAAI,EAAE,KAAK,CAAC;QAAC,EAAE,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE;CAGjE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,CAAC,EACjC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,GACpD,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAE5C"}