@vsirotin/ts-stop 0.5.1 → 0.6.0

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 (87) hide show
  1. package/README.md +2 -164
  2. package/lib/FiniteStateMachine.d.ts +6 -1
  3. package/lib/FiniteStateMachine.d.ts.map +1 -1
  4. package/lib/FiniteStateMachine.js +114 -6
  5. package/lib/FiniteStateMachine.js.map +1 -1
  6. package/lib/esm/FiniteStateMachine.js +114 -6
  7. package/lib/esm/fa/DefaultState.js +10 -0
  8. package/lib/esm/fa/FiniteStateMachine.js +405 -0
  9. package/lib/esm/fa/IStateWithActions.js +1 -0
  10. package/lib/esm/fa/IStateWithOutputSignal.js +1 -0
  11. package/lib/esm/fa/MatrixBasedStateMachine.js +127 -0
  12. package/lib/esm/fa/TransitionMatrix.js +98 -0
  13. package/lib/esm/index.js +6 -6
  14. package/lib/esm/sfsm/ExternalWorldHub.js +80 -0
  15. package/lib/esm/sfsm/FaLoader.js +30 -0
  16. package/lib/esm/sfsm/FaReducer.js +36 -0
  17. package/lib/esm/sfsm/FaResolver.js +115 -0
  18. package/lib/esm/sfsm/FaUpdater.js +101 -0
  19. package/lib/esm/sfsm/Sfsm.js +225 -0
  20. package/lib/esm/sfsm/index.js +6 -0
  21. package/lib/esm/sfsm/interfaces.js +1 -0
  22. package/lib/esm/sfsm/types.js +1 -0
  23. package/lib/fa/DefaultState.d.ts +9 -0
  24. package/lib/fa/DefaultState.d.ts.map +1 -0
  25. package/lib/fa/DefaultState.js +15 -0
  26. package/lib/fa/DefaultState.js.map +1 -0
  27. package/lib/fa/FiniteStateMachine.d.ts +227 -0
  28. package/lib/fa/FiniteStateMachine.d.ts.map +1 -0
  29. package/lib/fa/FiniteStateMachine.js +410 -0
  30. package/lib/fa/FiniteStateMachine.js.map +1 -0
  31. package/lib/fa/IStateWithActions.d.ts +18 -0
  32. package/lib/fa/IStateWithActions.d.ts.map +1 -0
  33. package/lib/fa/IStateWithActions.js +3 -0
  34. package/lib/fa/IStateWithActions.js.map +1 -0
  35. package/lib/fa/IStateWithOutputSignal.d.ts +4 -0
  36. package/lib/fa/IStateWithOutputSignal.d.ts.map +1 -0
  37. package/lib/fa/IStateWithOutputSignal.js +3 -0
  38. package/lib/fa/IStateWithOutputSignal.js.map +1 -0
  39. package/lib/fa/MatrixBasedStateMachine.d.ts +108 -0
  40. package/lib/fa/MatrixBasedStateMachine.d.ts.map +1 -0
  41. package/lib/fa/MatrixBasedStateMachine.js +132 -0
  42. package/lib/fa/MatrixBasedStateMachine.js.map +1 -0
  43. package/lib/fa/TransitionMatrix.d.ts +61 -0
  44. package/lib/fa/TransitionMatrix.d.ts.map +1 -0
  45. package/lib/fa/TransitionMatrix.js +104 -0
  46. package/lib/fa/TransitionMatrix.js.map +1 -0
  47. package/lib/index.d.ts +6 -6
  48. package/lib/index.d.ts.map +1 -1
  49. package/lib/index.js +6 -6
  50. package/lib/index.js.map +1 -1
  51. package/lib/sfsm/ExternalWorldHub.d.ts +52 -0
  52. package/lib/sfsm/ExternalWorldHub.d.ts.map +1 -0
  53. package/lib/sfsm/ExternalWorldHub.js +85 -0
  54. package/lib/sfsm/ExternalWorldHub.js.map +1 -0
  55. package/lib/sfsm/FaLoader.d.ts +22 -0
  56. package/lib/sfsm/FaLoader.d.ts.map +1 -0
  57. package/lib/sfsm/FaLoader.js +68 -0
  58. package/lib/sfsm/FaLoader.js.map +1 -0
  59. package/lib/sfsm/FaReducer.d.ts +12 -0
  60. package/lib/sfsm/FaReducer.d.ts.map +1 -0
  61. package/lib/sfsm/FaReducer.js +40 -0
  62. package/lib/sfsm/FaReducer.js.map +1 -0
  63. package/lib/sfsm/FaResolver.d.ts +37 -0
  64. package/lib/sfsm/FaResolver.d.ts.map +1 -0
  65. package/lib/sfsm/FaResolver.js +120 -0
  66. package/lib/sfsm/FaResolver.js.map +1 -0
  67. package/lib/sfsm/FaUpdater.d.ts +25 -0
  68. package/lib/sfsm/FaUpdater.d.ts.map +1 -0
  69. package/lib/sfsm/FaUpdater.js +106 -0
  70. package/lib/sfsm/FaUpdater.js.map +1 -0
  71. package/lib/sfsm/Sfsm.d.ts +60 -0
  72. package/lib/sfsm/Sfsm.d.ts.map +1 -0
  73. package/lib/sfsm/Sfsm.js +230 -0
  74. package/lib/sfsm/Sfsm.js.map +1 -0
  75. package/lib/sfsm/index.d.ts +9 -0
  76. package/lib/sfsm/index.d.ts.map +1 -0
  77. package/lib/sfsm/index.js +18 -0
  78. package/lib/sfsm/index.js.map +1 -0
  79. package/lib/sfsm/interfaces.d.ts +22 -0
  80. package/lib/sfsm/interfaces.d.ts.map +1 -0
  81. package/lib/sfsm/interfaces.js +3 -0
  82. package/lib/sfsm/interfaces.js.map +1 -0
  83. package/lib/sfsm/types.d.ts +78 -0
  84. package/lib/sfsm/types.d.ts.map +1 -0
  85. package/lib/sfsm/types.js +3 -0
  86. package/lib/sfsm/types.js.map +1 -0
  87. package/package.json +12 -2
package/README.md CHANGED
@@ -2,171 +2,9 @@
2
2
 
3
3
  State Oriented Programming library for TypeScript.
4
4
 
5
- DEvelopment in progress.
5
+ See [DEVELOPMENT.md](./DEVELOPMENT.md) for development instructions.
6
6
 
7
- ## Installation
8
-
9
- ### From NPM (when published)
10
- ```bash
11
- npm install @vsirotin/ts-stop
12
- ```
13
-
14
- ### Local Installation for Another Project
15
-
16
- If you want to use this package in another project without publishing to NPM:
17
-
18
- #### Step 1: Build and Pack the Library
19
- ```bash
20
- # In the ts-stop directory
21
- cd /path/to/StOP/ts/ts-stop
22
- npm run build
23
- npm pack
24
- ```
25
-
26
- This creates a file `vsirotin-ts-stop-<version>.tgz` in the ts-stop directory.
27
-
28
- #### Step 2: Install in Your Project
29
-
30
- Choose one of these methods:
31
-
32
- **Method 1: Install from Tarball (Recommended)**
33
- ```bash
34
- # In your project directory
35
- npm install /Users/viktorsirotin/VSCodeProjects/StOP/ts/ts-stop/vsirotin-ts-stop-0.0.1.tgz
36
- ```
37
-
38
- **Method 2: Install from Directory**
39
- ```bash
40
- # In your project directory
41
- npm install /path/to/StOP/ts/ts-stop
42
- ```
43
-
44
- **Method 3: Add to package.json**
45
- ```json
46
- {
47
- "dependencies": {
48
- "@vsirotin/ts-stop": "file:/path/to/StOP/ts/ts-stop"
49
- }
50
- }
51
- ```
52
- Then run `npm install`.
53
-
54
- #### Step 3: Update After Changes
55
-
56
- When you make changes to the ts-stop library:
57
-
58
- ```bash
59
- # In the ts-stop directory
60
- npm run build
61
- npm pack
62
-
63
- # In your project directory
64
- npm install /path/to/StOP/ts/ts-stop/vsirotin-ts-stop-0.0.1.tgz --force
65
- ```
66
-
67
- Or if using Method 2 or 3:
68
- ```bash
69
- # In your project directory
70
- npm install --force
71
- ```
72
-
73
- ## Usage
74
-
75
- ```typescript
76
- import { FiniteStateMachine, DefaultState } from '@vsirotin/ts-stop';
77
-
78
- // Example: Simple State Machine
79
- const states = [/* your states */];
80
- const signals = [/* your signals */];
81
- const transitions = [/* your transitions */];
82
- const startState = states[0];
83
-
84
- const machine = new FiniteStateMachine(
85
- states,
86
- signals,
87
- transitions,
88
- startState
89
- );
90
-
91
- // Process signals
92
- machine.processSignal(someSignal);
93
- ```
94
-
95
- ## Development
96
-
97
- ### Build
98
- ```bash
99
- npm run build # Build both CommonJS and ESM versions
100
- npm run build:cjs # Build CommonJS version only
101
- npm run build:esm # Build ESM version only
102
- ```
103
-
104
- ### Test
105
- ```bash
106
- npm test # Run tests
107
- npm run test:coverage # Run tests with coverage
108
- ```
109
-
110
- ### Clean
111
- ```bash
112
- npm run clean # Remove build artifacts
113
- ```
114
-
115
- ### Package
116
- ```bash
117
- npm run pack # Build and create tarball for distribution
118
- ```
119
-
120
- ## Package Structure
121
-
122
- After building, the package contains:
123
-
124
- ```
125
- lib/
126
- ├── index.js # CommonJS entry point
127
- ├── index.d.ts # TypeScript declarations
128
- ├── index.d.ts.map # TypeScript declaration source map
129
- ├── index.js.map # JavaScript source map
130
- ├── esm/ # ES Modules
131
- │ └── index.js # ESM entry point
132
- └── [other modules with .js, .d.ts, and .map files]
133
- ```
134
-
135
- The package includes:
136
- - **CommonJS** modules in `lib/` for Node.js compatibility
137
- - **ESM** (ES Modules) in `lib/esm/` for modern JavaScript
138
- - **TypeScript declarations** (`.d.ts`) for type checking
139
- - **Source maps** for debugging
140
-
141
- ## Using the Package Locally
142
-
143
- To use this package in another project without publishing to NPM:
144
-
145
- ### Method 1: Direct Installation
146
- ```bash
147
- # From your target project directory
148
- npm install /path/to/StOP/ts/ts-stop
149
- ```
150
-
151
- ### Method 2: Using the Packed Tarball
152
- ```bash
153
- # In ts-stop directory
154
- npm run pack
155
-
156
- # In your target project directory
157
- npm install /path/to/StOP/ts/ts-stop/vsirotin-ts-stop-0.0.1.tgz
158
- ```
159
-
160
- ### Method 3: Using package.json
161
- In your target project's `package.json`:
162
- ```json
163
- {
164
- "dependencies": {
165
- "@vsirotin/ts-stop": "file:../StOP/ts/ts-stop"
166
- }
167
- }
168
- ```
169
- Then run `npm install`.
7
+ For usage and API documentation, see the [main StOP documentation](../../docs/Tutorial/01-StOP-Tutorial.md).
170
8
 
171
9
  ## License
172
10
 
@@ -102,8 +102,9 @@ export declare abstract class FiniteStateMachine<STATE, SIGNAL> implements IFini
102
102
  * @param signals - Array of all possible signals/events
103
103
  * @param transitions - Array of transition rules defining how signals move between states
104
104
  * @param startState - The initial state of the machine
105
+ * @param skipValidation - When true, all structural validations are skipped (default: false)
105
106
  */
106
- constructor(states: STATE[], signals: SIGNAL[], transitions: ITransition<STATE, SIGNAL>[], startState: STATE);
107
+ constructor(states: STATE[], signals: SIGNAL[], transitions: ITransition<STATE, SIGNAL>[], startState: STATE, skipValidation?: boolean);
107
108
  /**
108
109
  * Gets the current state of the state machine.
109
110
  *
@@ -126,6 +127,10 @@ export declare abstract class FiniteStateMachine<STATE, SIGNAL> implements IFini
126
127
  */
127
128
  protected sendSignal(signal: SIGNAL): STATE;
128
129
  private tryProcessStateWithOutputSignal;
130
+ private validateUnreachableStates;
131
+ private validateDanglingReferences;
132
+ private validateOutputSignalStates;
133
+ private validateOutputSignalCycles;
129
134
  private isStateWithOutputSignal;
130
135
  private executeStateTransition;
131
136
  private executeStateActions;
@@ -1 +1 @@
1
- {"version":3,"file":"FiniteStateMachine.d.ts","sourceRoot":"","sources":["../src/FiniteStateMachine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAG7F;;;;;GAKG;AACH,MAAM,WAAW,WAAW,CAAC,KAAK,EAAE,MAAM;IACtC,IAAI,EAAE,KAAK,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,KAAK,CAAC;CACb;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB,CAAC,KAAK;IACtC;;;;OAIG;IACH,eAAe,IAAI,KAAK,CAAC;CAE5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,8BAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAE,YAAW,mBAAmB,CAAC,KAAK,CAAC;IAsBrF,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE;IACzB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE;IAC3B,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE;IACnD,SAAS,CAAC,UAAU,EAAE,KAAK;IAxB/B;;;OAGG;IACH,SAAS,CAAC,YAAY,EAAE,KAAK,CAAC;IAE1B;;;GAGD;IACH,OAAO,CAAC,YAAY,CAA6B;IAEjD;;;;;;;OAOG;gBAEW,MAAM,EAAE,KAAK,EAAE,EACf,OAAO,EAAE,MAAM,EAAE,EACjB,WAAW,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,EACzC,UAAU,EAAE,KAAK;IA6B/B;;;;OAIG;IACH,eAAe,IAAI,KAAK;IAIxB;;;;;;;;;;;;;OAaG;IACH,SAAS,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK;IAqB3C,OAAO,CAAC,+BAA+B;IAcvC,OAAO,CAAC,uBAAuB;IAS/B,OAAO,CAAC,sBAAsB;IAiB9B,OAAO,CAAC,mBAAmB;IAK3B;;;;;OAKG;IACH,SAAS,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IAI/C;;;;;OAKG;IACH,SAAS,CAAC,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,IAAI,KAAK,GAAG,0BAA0B;IAOxF;;;;;OAKG;IACH,SAAS,CAAC,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,IAAI,KAAK,GAAG,0BAA0B;IAOxF;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAM1B;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAMzB;;;;OAIG;IACH,YAAY,IAAI,KAAK,EAAE;IAIvB;;;;OAIG;IACH,aAAa,IAAI,MAAM,EAAE;IAIzB;;;;;OAKG;IACH,6BAA6B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAMtD;;;;OAIG;IACH,+BAA+B,IAAI,MAAM,EAAE;IAM3C;;;;OAIG;IACH,cAAc,IAAI,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE;IAI9C;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIlC;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IAI3B;;;;GAID;IACH,eAAe,IAAI,YAAY,GAAG,IAAI;IAItC;;;;OAIG;IACH,eAAe,IAAI,OAAO;CAG7B"}
1
+ {"version":3,"file":"FiniteStateMachine.d.ts","sourceRoot":"","sources":["../src/FiniteStateMachine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,0BAA0B,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAG7F;;;;;GAKG;AACH,MAAM,WAAW,WAAW,CAAC,KAAK,EAAE,MAAM;IACtC,IAAI,EAAE,KAAK,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,KAAK,CAAC;CACb;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB,CAAC,KAAK;IACtC;;;;OAIG;IACH,eAAe,IAAI,KAAK,CAAC;CAE5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,8BAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAE,YAAW,mBAAmB,CAAC,KAAK,CAAC;IAuBrF,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE;IACzB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE;IAC3B,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE;IACnD,SAAS,CAAC,UAAU,EAAE,KAAK;IAzB/B;;;OAGG;IACH,SAAS,CAAC,YAAY,EAAE,KAAK,CAAC;IAE1B;;;GAGD;IACH,OAAO,CAAC,YAAY,CAA6B;IAEjD;;;;;;;;OAQG;gBAEW,MAAM,EAAE,KAAK,EAAE,EACf,OAAO,EAAE,MAAM,EAAE,EACjB,WAAW,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,EACzC,UAAU,EAAE,KAAK,EAC3B,cAAc,GAAE,OAAe;IA2CnC;;;;OAIG;IACH,eAAe,IAAI,KAAK;IAIxB;;;;;;;;;;;;;OAaG;IACH,SAAS,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK;IAqB3C,OAAO,CAAC,+BAA+B;IAcvC,OAAO,CAAC,yBAAyB;IA0BjC,OAAO,CAAC,0BAA0B;IAiClC,OAAO,CAAC,0BAA0B;IAelC,OAAO,CAAC,0BAA0B;IAmDlC,OAAO,CAAC,uBAAuB;IAS/B,OAAO,CAAC,sBAAsB;IAiB9B,OAAO,CAAC,mBAAmB;IAK3B;;;;;OAKG;IACH,SAAS,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IAI/C;;;;;OAKG;IACH,SAAS,CAAC,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,IAAI,KAAK,GAAG,0BAA0B;IAOxF;;;;;OAKG;IACH,SAAS,CAAC,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,IAAI,KAAK,GAAG,0BAA0B;IAOxF;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAM1B;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAMzB;;;;OAIG;IACH,YAAY,IAAI,KAAK,EAAE;IAIvB;;;;OAIG;IACH,aAAa,IAAI,MAAM,EAAE;IAIzB;;;;;OAKG;IACH,6BAA6B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAMtD;;;;OAIG;IACH,+BAA+B,IAAI,MAAM,EAAE;IAM3C;;;;OAIG;IACH,cAAc,IAAI,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE;IAI9C;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAIlC;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IAI3B;;;;GAID;IACH,eAAe,IAAI,YAAY,GAAG,IAAI;IAItC;;;;OAIG;IACH,eAAe,IAAI,OAAO;CAG7B"}
@@ -65,8 +65,9 @@ class FiniteStateMachine {
65
65
  * @param signals - Array of all possible signals/events
66
66
  * @param transitions - Array of transition rules defining how signals move between states
67
67
  * @param startState - The initial state of the machine
68
+ * @param skipValidation - When true, all structural validations are skipped (default: false)
68
69
  */
69
- constructor(states, signals, transitions, startState) {
70
+ constructor(states, signals, transitions, startState, skipValidation = false) {
70
71
  this.states = states;
71
72
  this.signals = signals;
72
73
  this.transitions = transitions;
@@ -78,11 +79,21 @@ class FiniteStateMachine {
78
79
  this.defaultState = null;
79
80
  // Find states that implement IDefaultState
80
81
  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.`);
82
+ if (!skipValidation) {
83
+ // Validate default state count
84
+ if (defaultStates.length > 1) {
85
+ throw new Error(`ERROR-STOP-01: Multiple states implement IDefaultState interface. ` +
86
+ `Only one state can handle invalid signals. ` +
87
+ `Found ${defaultStates.length} states with IDefaultState.`);
88
+ }
89
+ // Validate that all transition and start-state references are defined
90
+ this.validateDanglingReferences();
91
+ // Validate that all output signal states have at least one outgoing transition
92
+ this.validateOutputSignalStates();
93
+ // Validate that output-signal states do not form cycles
94
+ this.validateOutputSignalCycles();
95
+ // Validate that all states are reachable from the start state
96
+ this.validateUnreachableStates();
86
97
  }
87
98
  // Set default state if exactly one found
88
99
  if (defaultStates.length === 1) {
@@ -145,6 +156,103 @@ class FiniteStateMachine {
145
156
  }
146
157
  }
147
158
  }
159
+ validateUnreachableStates() {
160
+ const reachable = new Set();
161
+ const queue = [this.startState];
162
+ reachable.add(this.startState);
163
+ while (queue.length > 0) {
164
+ const current = queue.shift();
165
+ for (const t of this.transitions) {
166
+ if (t.from === current && !reachable.has(t.to)) {
167
+ reachable.add(t.to);
168
+ queue.push(t.to);
169
+ }
170
+ }
171
+ }
172
+ for (const state of this.states) {
173
+ if (this.isDefaultState(state))
174
+ continue; // DefaultState handles invalid signals — unreachable by design
175
+ if (!reachable.has(state)) {
176
+ throw new Error(`ERROR-STOP-08: State '${state}' is unreachable from start state '${this.startState}'. ` +
177
+ `All non-default states must be reachable from the start state via the transition graph.`);
178
+ }
179
+ }
180
+ }
181
+ validateDanglingReferences() {
182
+ const stateSet = new Set(this.states);
183
+ const signalSet = new Set(this.signals);
184
+ if (!stateSet.has(this.startState)) {
185
+ throw new Error(`ERROR-STOP-03: Start state '${this.startState}' is not in the states array. ` +
186
+ `The start state must be one of the provided states.`);
187
+ }
188
+ for (const t of this.transitions) {
189
+ if (!stateSet.has(t.from)) {
190
+ throw new Error(`ERROR-STOP-04: Transition references unknown state '${t.from}' as 'from'. ` +
191
+ `All transition states must be in the states array.`);
192
+ }
193
+ if (!stateSet.has(t.to)) {
194
+ throw new Error(`ERROR-STOP-05: Transition references unknown state '${t.to}' as 'to'. ` +
195
+ `All transition states must be in the states array.`);
196
+ }
197
+ if (!signalSet.has(t.signal)) {
198
+ throw new Error(`ERROR-STOP-06: Transition references unknown signal '${String(t.signal)}'. ` +
199
+ `All transition signals must be in the signals array.`);
200
+ }
201
+ }
202
+ }
203
+ validateOutputSignalStates() {
204
+ for (const state of this.states) {
205
+ if (this.isStateWithOutputSignal(state)) {
206
+ const hasOutgoing = this.transitions.some(t => t.from === state);
207
+ if (!hasOutgoing) {
208
+ throw new Error(`ERROR-STOP-02: Configuration error: State '${state}' implements IStateWithOutputSignal ` +
209
+ `but has no outgoing transitions. States with output signals must have ` +
210
+ `at least one outgoing transition.`);
211
+ }
212
+ }
213
+ }
214
+ }
215
+ validateOutputSignalCycles() {
216
+ const outputStateSet = new Set(this.states.filter(s => this.isStateWithOutputSignal(s)));
217
+ if (outputStateSet.size < 2)
218
+ return;
219
+ // Build adjacency: output state → output states reachable via one transition
220
+ const adj = new Map();
221
+ for (const state of outputStateSet) {
222
+ adj.set(state, this.transitions
223
+ .filter(t => t.from === state && outputStateSet.has(t.to))
224
+ .map(t => t.to));
225
+ }
226
+ // DFS-based cycle detection (colour: 0=unvisited, 1=in-stack, 2=done)
227
+ const visited = new Set();
228
+ const onStack = new Set();
229
+ const stackPath = [];
230
+ const dfs = (state) => {
231
+ var _a;
232
+ visited.add(state);
233
+ onStack.add(state);
234
+ stackPath.push(state);
235
+ for (const neighbor of ((_a = adj.get(state)) !== null && _a !== void 0 ? _a : [])) {
236
+ if (onStack.has(neighbor)) {
237
+ const cycleStart = stackPath.indexOf(neighbor);
238
+ const cyclePath = [...stackPath.slice(cycleStart), neighbor];
239
+ throw new Error(`ERROR-STOP-07: Circular dependency detected in output signals: ` +
240
+ `${cyclePath.map(s => String(s)).join(' -> ')}. ` +
241
+ `States with output signals cannot form cycles as this creates infinite loops.`);
242
+ }
243
+ if (!visited.has(neighbor)) {
244
+ dfs(neighbor);
245
+ }
246
+ }
247
+ onStack.delete(state);
248
+ stackPath.pop();
249
+ };
250
+ for (const state of outputStateSet) {
251
+ if (!visited.has(state)) {
252
+ dfs(state);
253
+ }
254
+ }
255
+ }
148
256
  isStateWithOutputSignal(state) {
149
257
  const obj = state;
150
258
  return (typeof obj === 'object' &&
@@ -1 +1 @@
1
- {"version":3,"file":"FiniteStateMachine.js","sourceRoot":"","sources":["../src/FiniteStateMachine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FiniteStateMachine.js","sourceRoot":"","sources":["../src/FiniteStateMachine.ts"],"names":[],"mappings":"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"}
@@ -62,8 +62,9 @@ export class FiniteStateMachine {
62
62
  * @param signals - Array of all possible signals/events
63
63
  * @param transitions - Array of transition rules defining how signals move between states
64
64
  * @param startState - The initial state of the machine
65
+ * @param skipValidation - When true, all structural validations are skipped (default: false)
65
66
  */
66
- constructor(states, signals, transitions, startState) {
67
+ constructor(states, signals, transitions, startState, skipValidation = false) {
67
68
  this.states = states;
68
69
  this.signals = signals;
69
70
  this.transitions = transitions;
@@ -75,11 +76,21 @@ export class FiniteStateMachine {
75
76
  this.defaultState = null;
76
77
  // Find states that implement IDefaultState
77
78
  const defaultStates = states.filter(state => this.isDefaultState(state));
78
- // Validate default state count
79
- if (defaultStates.length > 1) {
80
- throw new Error(`Multiple states implement IDefaultState interface. ` +
81
- `Only one state can handle invalid signals. ` +
82
- `Found ${defaultStates.length} states with IDefaultState.`);
79
+ if (!skipValidation) {
80
+ // Validate default state count
81
+ if (defaultStates.length > 1) {
82
+ throw new Error(`ERROR-STOP-01: Multiple states implement IDefaultState interface. ` +
83
+ `Only one state can handle invalid signals. ` +
84
+ `Found ${defaultStates.length} states with IDefaultState.`);
85
+ }
86
+ // Validate that all transition and start-state references are defined
87
+ this.validateDanglingReferences();
88
+ // Validate that all output signal states have at least one outgoing transition
89
+ this.validateOutputSignalStates();
90
+ // Validate that output-signal states do not form cycles
91
+ this.validateOutputSignalCycles();
92
+ // Validate that all states are reachable from the start state
93
+ this.validateUnreachableStates();
83
94
  }
84
95
  // Set default state if exactly one found
85
96
  if (defaultStates.length === 1) {
@@ -142,6 +153,103 @@ export class FiniteStateMachine {
142
153
  }
143
154
  }
144
155
  }
156
+ validateUnreachableStates() {
157
+ const reachable = new Set();
158
+ const queue = [this.startState];
159
+ reachable.add(this.startState);
160
+ while (queue.length > 0) {
161
+ const current = queue.shift();
162
+ for (const t of this.transitions) {
163
+ if (t.from === current && !reachable.has(t.to)) {
164
+ reachable.add(t.to);
165
+ queue.push(t.to);
166
+ }
167
+ }
168
+ }
169
+ for (const state of this.states) {
170
+ if (this.isDefaultState(state))
171
+ continue; // DefaultState handles invalid signals — unreachable by design
172
+ if (!reachable.has(state)) {
173
+ throw new Error(`ERROR-STOP-08: State '${state}' is unreachable from start state '${this.startState}'. ` +
174
+ `All non-default states must be reachable from the start state via the transition graph.`);
175
+ }
176
+ }
177
+ }
178
+ validateDanglingReferences() {
179
+ const stateSet = new Set(this.states);
180
+ const signalSet = new Set(this.signals);
181
+ if (!stateSet.has(this.startState)) {
182
+ throw new Error(`ERROR-STOP-03: Start state '${this.startState}' is not in the states array. ` +
183
+ `The start state must be one of the provided states.`);
184
+ }
185
+ for (const t of this.transitions) {
186
+ if (!stateSet.has(t.from)) {
187
+ throw new Error(`ERROR-STOP-04: Transition references unknown state '${t.from}' as 'from'. ` +
188
+ `All transition states must be in the states array.`);
189
+ }
190
+ if (!stateSet.has(t.to)) {
191
+ throw new Error(`ERROR-STOP-05: Transition references unknown state '${t.to}' as 'to'. ` +
192
+ `All transition states must be in the states array.`);
193
+ }
194
+ if (!signalSet.has(t.signal)) {
195
+ throw new Error(`ERROR-STOP-06: Transition references unknown signal '${String(t.signal)}'. ` +
196
+ `All transition signals must be in the signals array.`);
197
+ }
198
+ }
199
+ }
200
+ validateOutputSignalStates() {
201
+ for (const state of this.states) {
202
+ if (this.isStateWithOutputSignal(state)) {
203
+ const hasOutgoing = this.transitions.some(t => t.from === state);
204
+ if (!hasOutgoing) {
205
+ throw new Error(`ERROR-STOP-02: Configuration error: State '${state}' implements IStateWithOutputSignal ` +
206
+ `but has no outgoing transitions. States with output signals must have ` +
207
+ `at least one outgoing transition.`);
208
+ }
209
+ }
210
+ }
211
+ }
212
+ validateOutputSignalCycles() {
213
+ const outputStateSet = new Set(this.states.filter(s => this.isStateWithOutputSignal(s)));
214
+ if (outputStateSet.size < 2)
215
+ return;
216
+ // Build adjacency: output state → output states reachable via one transition
217
+ const adj = new Map();
218
+ for (const state of outputStateSet) {
219
+ adj.set(state, this.transitions
220
+ .filter(t => t.from === state && outputStateSet.has(t.to))
221
+ .map(t => t.to));
222
+ }
223
+ // DFS-based cycle detection (colour: 0=unvisited, 1=in-stack, 2=done)
224
+ const visited = new Set();
225
+ const onStack = new Set();
226
+ const stackPath = [];
227
+ const dfs = (state) => {
228
+ var _a;
229
+ visited.add(state);
230
+ onStack.add(state);
231
+ stackPath.push(state);
232
+ for (const neighbor of ((_a = adj.get(state)) !== null && _a !== void 0 ? _a : [])) {
233
+ if (onStack.has(neighbor)) {
234
+ const cycleStart = stackPath.indexOf(neighbor);
235
+ const cyclePath = [...stackPath.slice(cycleStart), neighbor];
236
+ throw new Error(`ERROR-STOP-07: Circular dependency detected in output signals: ` +
237
+ `${cyclePath.map(s => String(s)).join(' -> ')}. ` +
238
+ `States with output signals cannot form cycles as this creates infinite loops.`);
239
+ }
240
+ if (!visited.has(neighbor)) {
241
+ dfs(neighbor);
242
+ }
243
+ }
244
+ onStack.delete(state);
245
+ stackPath.pop();
246
+ };
247
+ for (const state of outputStateSet) {
248
+ if (!visited.has(state)) {
249
+ dfs(state);
250
+ }
251
+ }
252
+ }
145
253
  isStateWithOutputSignal(state) {
146
254
  const obj = state;
147
255
  return (typeof obj === 'object' &&
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Marker base class for states that should be used processed by invalid signals and
3
+ * in situation, then no transitions set for pair (current signal, current state).
4
+ * Only one state in a state machine can have this role.
5
+ */
6
+ export class DefaultState {
7
+ isDefaultState() {
8
+ return true;
9
+ }
10
+ }