@peter.naydenov/fsm 4.0.1 → 5.0.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.
- package/Changelog.md +90 -0
- package/LICENSE +21 -0
- package/Migration.guide.md +86 -0
- package/README.md +96 -173
- package/README_v.4.x.x.md +491 -0
- package/blueprint.md +22 -0
- package/coverage/lcov-report/index.html +1 -1
- package/coverage/lcov-report/src/index.html +1 -1
- package/coverage/lcov-report/src/index.js.html +1 -1
- package/coverage/lcov-report/src/methods/_getChain.js.html +1 -1
- package/coverage/lcov-report/src/methods/_onUpdateTask.js.html +1 -1
- package/coverage/lcov-report/src/methods/_setTransitions.js.html +1 -1
- package/coverage/lcov-report/src/methods/_transit.js.html +1 -1
- package/coverage/lcov-report/src/methods/_triggerCacheUpdate.js.html +1 -1
- package/coverage/lcov-report/src/methods/_updateStep.js.html +1 -1
- package/coverage/lcov-report/src/methods/_warn.js.html +1 -1
- package/coverage/lcov-report/src/methods/exportState.js.html +1 -1
- package/coverage/lcov-report/src/methods/getState.js.html +1 -1
- package/coverage/lcov-report/src/methods/ignoreCacheUpdates.js.html +1 -1
- package/coverage/lcov-report/src/methods/importState.js.html +1 -1
- package/coverage/lcov-report/src/methods/index.html +1 -1
- package/coverage/lcov-report/src/methods/index.js.html +1 -1
- package/coverage/lcov-report/src/methods/off.js.html +1 -1
- package/coverage/lcov-report/src/methods/on.js.html +1 -1
- package/coverage/lcov-report/src/methods/reset.js.html +1 -1
- package/coverage/lcov-report/src/methods/setDependencies.js.html +1 -1
- package/coverage/lcov-report/src/methods/update.js.html +1 -1
- package/coverage/tmp/coverage-51040-1691437648869-0.json +1 -0
- package/package.json +8 -7
- package/src/main.js +75 -0
- package/src/methods/_getChain.js +3 -2
- package/src/methods/_onUpdateTask.js +1 -1
- package/src/methods/_setTransitions.js +3 -3
- package/src/methods/_transit.js +7 -4
- package/src/methods/_triggerCacheUpdate.js +2 -0
- package/src/methods/_updateStateData.js +43 -0
- package/src/methods/_updateStep.js +10 -13
- package/src/methods/_warn.js +1 -1
- package/src/methods/exportState.js +5 -8
- package/src/methods/extractList.js +26 -0
- package/src/methods/getDependencies.js +10 -0
- package/src/methods/importState.js +3 -1
- package/src/methods/index.js +23 -15
- package/src/methods/reset.js +3 -2
- package/src/methods/setDependencies.js +1 -1
- package/src/methods/update.js +14 -4
- package/src/queryStateUpdate.js +38 -0
- package/coverage/tmp/coverage-29775-1668580484020-0.json +0 -1
- package/src/index.js +0 -41
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
# FSM (@peter.naydenov/fsm)
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Finite state machine(FSM) is an abstract machine that can be in exactly one of a finite number of **states** at any given time. The FSM can change from one state to another in response to some external inputs(**actions**). The change from state to another is called a **transition**. An FSM is defined by a list of its states, its initial state, and the conditions for each transition.
|
|
9
|
+
```js
|
|
10
|
+
const myFsm = {
|
|
11
|
+
init : 'none' // initial fsm state
|
|
12
|
+
, table : [
|
|
13
|
+
// [ fromState, action , nextState, transitionFx ]
|
|
14
|
+
[ 'none' , 'activate', 'active' , 'switchON' ] // transition condition
|
|
15
|
+
, [ 'active' , 'stop' , 'none' , 'switchOFF' ] // transition condition
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
- **init**: string. Initial state for the FSM;
|
|
20
|
+
- **table**: array of transitionConditions. Describe relation among fsm state, action and transition;
|
|
21
|
+
- **transitionCondition**: Array [fromState action nextState transitionFx];
|
|
22
|
+
- **fromState**: string. State as starting point for transition;
|
|
23
|
+
- **action**: string. External input signal. Transition could happen only when fromState and action are described in transitionCondition record;
|
|
24
|
+
- **nextState**: string. The FSM state if transition is successful;
|
|
25
|
+
- **transitionFx**: string. The function name that will be executed on 'state/action' conditions. Transition should return **transitionResult** object where parameter "**success**" will represent transition success. Result of transition will be evaluated by FSM. Positive response will change actual state to 'nextState' from transitionCondition record. Negative result will keep actual state;
|
|
26
|
+
|
|
27
|
+
**Transitions** are functions and they are provided to FSM as functional library - javascript object with functions.
|
|
28
|
+
```js
|
|
29
|
+
const transitionLibrary = {
|
|
30
|
+
switchOn : function () {
|
|
31
|
+
// ...code
|
|
32
|
+
}
|
|
33
|
+
, switchOff : function () {
|
|
34
|
+
// ...code
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
It's simple and clean way to represent system behaviour but practice shows that is not enough. This implementation was extended to cover some aditional program needs like:
|
|
40
|
+
- Transition function could contain asynchronous code(Available after version 2.0);
|
|
41
|
+
- Chain-actions in **transaction conditions** (Optional after version 2.0);
|
|
42
|
+
- Chain-actions are possible on **positive** and *negative* transition-end (After version 2.0);
|
|
43
|
+
- Export fsm state as an object: externalState. (Available after version 2.1);
|
|
44
|
+
- Import externalState (Available after version 2.1);
|
|
45
|
+
- Prevent simultaneous updates (Available after version 2.1);
|
|
46
|
+
- Cache stack for fsm-updates and postponed execution (Available after version 2.1);
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
## Implement Fsm
|
|
53
|
+
|
|
54
|
+
Install module by:
|
|
55
|
+
```
|
|
56
|
+
npm i @peter.naydenov/fsm
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Add in your script:
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
import Fsm from '@peter.naydenov/fsm'
|
|
63
|
+
// init new fsm:
|
|
64
|
+
const fsm = new Fsm ( machine, lib )
|
|
65
|
+
```
|
|
66
|
+
... where **machine** is fsm-description and **lib** is a transition-library.
|
|
67
|
+
|
|
68
|
+
If your project is commonJS, use a dynamic `import` function or use version v.3.0.0 or older.
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
## Fsm Description
|
|
73
|
+
Fsm description is an object that define fsm business logic. Every fsm description should contain **init** and **table** properties.:
|
|
74
|
+
```js
|
|
75
|
+
const machine = {
|
|
76
|
+
init : 'stopped'
|
|
77
|
+
, table: [
|
|
78
|
+
// [ state , action , nextState, functionName, chainAction(optional) ]
|
|
79
|
+
[ 'stopped', 'activate', 'active', 'fnActivate' ]
|
|
80
|
+
, [ 'stopped', 'activate', 'active', 'fnActivate' ]
|
|
81
|
+
]
|
|
82
|
+
, stateData : { greeting: 'hi' }
|
|
83
|
+
/** Parameter 'stateData' is optional parameter. Data will be
|
|
84
|
+
* provided to each transition function. You can read and modify
|
|
85
|
+
* stateData values.
|
|
86
|
+
* /
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Property '**init**' is the initial state of the system. Property '**table**' describes how system reacts. Every row contain 5 elements:
|
|
91
|
+
1. Current active state;
|
|
92
|
+
2. Action;
|
|
93
|
+
3. Next state;
|
|
94
|
+
4. Transition function that should be applied;
|
|
95
|
+
5. Chain action
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
[ 'stopped', 'activate', 'active', 'fnActivate' ]
|
|
99
|
+
// Read this transition condition like:
|
|
100
|
+
/**
|
|
101
|
+
* When state is 'stopped' and external input 'activate' comes, transition 'fnActivate' will be executed. On success state will become 'active'. No chain-actions are defined.
|
|
102
|
+
*/
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Fsm Transition Library
|
|
106
|
+
|
|
107
|
+
Object that will contain all transition functions:
|
|
108
|
+
```js
|
|
109
|
+
const lib = {
|
|
110
|
+
fnActicate () {
|
|
111
|
+
// ... code to activate
|
|
112
|
+
}
|
|
113
|
+
, fnStop () {
|
|
114
|
+
// ... code to stop
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
## Fsm Transition Function
|
|
124
|
+
|
|
125
|
+
Fsm transition function is a function, member of transition library. Transition functions is kind of middleware. Every function receives 4 arguments:
|
|
126
|
+
```js
|
|
127
|
+
const lib = {
|
|
128
|
+
fnActivate ( task, dependencies, stateObject, dt ) {
|
|
129
|
+
// function code is here...
|
|
130
|
+
task.done ( end ) // end is a transitionResult {}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
- task - askForPromise object; [AskForPromise documentation](https://github.com/PeterNaydenov/ask-for-promise). Represents asynchronous transition execution. Finish by providing to task object, the transition result object. `task.done( transitionResult )`;
|
|
135
|
+
- dependencies - object. Contain all external dependencies. Set fsm dependencies by fsm.setDependencies();
|
|
136
|
+
- stateObject - object. Contains all helper params needed to support the FSM state;
|
|
137
|
+
- dt - object. External data provided from fsm.update( action, **dt**);
|
|
138
|
+
|
|
139
|
+
Execution of transition function will end on `task.done(end)` where **end** is an **transitionResult** object.
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
## transitionResult
|
|
146
|
+
Only one of the params in this object is required:
|
|
147
|
+
|
|
148
|
+
```js
|
|
149
|
+
{
|
|
150
|
+
success : true // Required. Boolean. Transition success;
|
|
151
|
+
, response : {} // Optional. Object. update answer response;
|
|
152
|
+
, stateData : {} // Optional. Object. 'stateData' if there is stateData changes;
|
|
153
|
+
, command : null // Optional. String|null|undefined. Next action if chaining is required (depricated). Use "chainActions" in table instead;
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
## FSM Methods
|
|
160
|
+
|
|
161
|
+
```js
|
|
162
|
+
setDependencies : 'Insert all external dependencies'
|
|
163
|
+
, getState : 'Returns actual state'
|
|
164
|
+
, update : 'Trigger an action'
|
|
165
|
+
, exportState : 'Export state and stateData as a single object (externalState)'
|
|
166
|
+
, importState : 'Import externalState object.'
|
|
167
|
+
, reset : 'Revert state and stateData to initial values described during initialization'
|
|
168
|
+
, ignoreCachedUpdates : 'Ignore all cached updates'
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
### fsm.setDependencies ()
|
|
173
|
+
Set dependencies for FSM. Dependency object will be provided to every transition function. With **dependency injection** code will stay testable. Don't forget to add here all **window** based objects and functions that are available only in the browser environment.
|
|
174
|
+
|
|
175
|
+
```js
|
|
176
|
+
const
|
|
177
|
+
moment = require ( 'moment' )
|
|
178
|
+
, fsm = new Fsm ()
|
|
179
|
+
, deps = {
|
|
180
|
+
scrollTo : window.scrollTo
|
|
181
|
+
, moment
|
|
182
|
+
}
|
|
183
|
+
;
|
|
184
|
+
|
|
185
|
+
fsm.setDependencies ( deps )
|
|
186
|
+
```
|
|
187
|
+
- **Method returns**: void;
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
### fsm.getState ()
|
|
192
|
+
Will return current current FSM state.
|
|
193
|
+
|
|
194
|
+
```js
|
|
195
|
+
let currentState = fsm.getState ()
|
|
196
|
+
```
|
|
197
|
+
- **Method returns**: string. Current FSM state;
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
### fsm.update ()
|
|
202
|
+
Provide actions to FSM. If conditions 'state/action' exist in description table, FSM will react.
|
|
203
|
+
```js
|
|
204
|
+
fsm.update ( action, altData)
|
|
205
|
+
.then ( r => {
|
|
206
|
+
// ...do something with the response
|
|
207
|
+
})
|
|
208
|
+
```
|
|
209
|
+
- **action**(required): string. The action.
|
|
210
|
+
- **altData**(optional): any. Additional data provided to the transition;
|
|
211
|
+
- **Method returns**: Promise of any. Returned value is equal to transitionResult.response;
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
### fsm.exportState ()
|
|
218
|
+
Export state and stateData as a single object (**externalState**). Export state to:
|
|
219
|
+
- Keep fsm history record;
|
|
220
|
+
- Possible point of recovery;
|
|
221
|
+
- Synchronize fsm states accross the network in large distributed systems;
|
|
222
|
+
- Debuging purposes;
|
|
223
|
+
|
|
224
|
+
```js
|
|
225
|
+
const externalState = fsm.exportState ();
|
|
226
|
+
/**
|
|
227
|
+
* externalState = {
|
|
228
|
+
* state : 'actualState'
|
|
229
|
+
* , stateData : {
|
|
230
|
+
* ... all stateData flags are here
|
|
231
|
+
* }
|
|
232
|
+
* }
|
|
233
|
+
* */
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
- **Method returns**: externalState object
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
### fsm.importState ()
|
|
243
|
+
Put fsm in specific state by importing **externalState** object described in 'exportState()' method. Use method to:
|
|
244
|
+
- Recover previous state of the fsm;
|
|
245
|
+
- Testing specific situations by moving fsm directly in required state;
|
|
246
|
+
- Synchronize fsm states accross the network;
|
|
247
|
+
|
|
248
|
+
- **externalState**: externalState object
|
|
249
|
+
- **Method returns**: void
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
### fsm.reset ()
|
|
256
|
+
Returns initial values for state and stateData.
|
|
257
|
+
|
|
258
|
+
```js
|
|
259
|
+
fsm.reset ()
|
|
260
|
+
```
|
|
261
|
+
- **Method returns**: void;
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
### fsm.ignoreCachedUpdates ()
|
|
268
|
+
Ignore all cached updates.
|
|
269
|
+
|
|
270
|
+
```js
|
|
271
|
+
const fsm = new Fsm ( description, transitions );
|
|
272
|
+
fsm.update ( 'start' ).then ( x => fsm.ignoreCachedUpdates () )
|
|
273
|
+
/**
|
|
274
|
+
* Update with action 'start' will block all upcoming updates. Subsequent updates
|
|
275
|
+
* will wait by using cache mechanism.
|
|
276
|
+
* Method 'ignoreCachedUpdates' will remove updates from cache and will close their promises with 'reject' and
|
|
277
|
+
* error message.
|
|
278
|
+
* Use reject function to customize 'canceled updates' behaviour
|
|
279
|
+
*/
|
|
280
|
+
fsm.update ( 'move' )
|
|
281
|
+
.then ( r => { // resolve function
|
|
282
|
+
result = fsm.exportState ()
|
|
283
|
+
expect ( result.state ).to.be.equal ( 'initial' )
|
|
284
|
+
}
|
|
285
|
+
, r => { // reject function
|
|
286
|
+
//---> 'r' will contain error message produced by fsm.
|
|
287
|
+
// r == "Action 'move' was ignored"
|
|
288
|
+
})
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
- **Method returns**: void;
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
## Example
|
|
298
|
+
|
|
299
|
+
Example represents controller for system that require electricity. On `fsm.update('start')` controller will try to activate standard electricity source. On fail will trigger chain-action `generator` and will try to activate alternative energy source. On success state will become `altSrc`(alternativeSource). When standart electricity source is available we can inform the system by calling `fsm.update('electricity')` and on success state will become `active`. Switch off the system any time by calling `fsm.update('stop')`.
|
|
300
|
+
|
|
301
|
+
```js
|
|
302
|
+
const
|
|
303
|
+
lib = {
|
|
304
|
+
switchON ( task, dependencies, stateData, dt ) {
|
|
305
|
+
task.done ({ success : false })
|
|
306
|
+
}
|
|
307
|
+
, altOn ( task ) {
|
|
308
|
+
task.done ({ success: true })
|
|
309
|
+
}
|
|
310
|
+
, switchOFF ( task ) {
|
|
311
|
+
task.done ({ success: true })
|
|
312
|
+
}
|
|
313
|
+
, primarySource ( task ) {
|
|
314
|
+
task.done ({ success: true })
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
, machine = {
|
|
318
|
+
init : 'none'
|
|
319
|
+
, table : [
|
|
320
|
+
[ 'none' , 'start' , 'active' , 'switchON', [ false, 'generator'] ]
|
|
321
|
+
, [ 'none' , 'generator' , 'altSrc' , 'altOn' ]
|
|
322
|
+
, [ 'active' , 'stop' , 'none' , 'switchOFF' ]
|
|
323
|
+
, [ 'altSrc' , 'stop' , 'none' , 'switchOFF' ]
|
|
324
|
+
, [ 'altSrc' , 'electricity' , 'active', 'primarySource' ]
|
|
325
|
+
]
|
|
326
|
+
}
|
|
327
|
+
;
|
|
328
|
+
const fsm = new Fsm ( machine, lib );
|
|
329
|
+
fsm.update ( 'activate' )
|
|
330
|
+
.then ( () => {
|
|
331
|
+
const r = fsm.getState ();
|
|
332
|
+
expect ( r ).to.be.equal ( 'altSrc' )
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
## Migration from v.1 to v.2
|
|
342
|
+
Project was started with simplest posible implementation. I like the approach and want to extend it. Reasons:
|
|
343
|
+
- Some of my transition function contain asynchronous events;
|
|
344
|
+
- Describe chain of actions inside the transition condition records;
|
|
345
|
+
- Chain of action on positive and negative transition end;
|
|
346
|
+
|
|
347
|
+
So... about changes:
|
|
348
|
+
### Transition complete
|
|
349
|
+
- **Version 1**: Transition function should return **transitionResult** object.
|
|
350
|
+
- **Version 2**: Transition function receives as first param **task**. Task is askForPromise object. Transition is complete on `task.done(transitionResult)`.
|
|
351
|
+
- **Changes**: Find return statement and convert it to task.done:
|
|
352
|
+
|
|
353
|
+
```js
|
|
354
|
+
// ver. 1 ->
|
|
355
|
+
...
|
|
356
|
+
return { success : true }
|
|
357
|
+
// ver. 2 ->
|
|
358
|
+
...
|
|
359
|
+
task.done ({ success : true })
|
|
360
|
+
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
### Transition params
|
|
366
|
+
|
|
367
|
+
```js
|
|
368
|
+
// ver. 1 ->
|
|
369
|
+
transition ( dependencies, stateData, dt )
|
|
370
|
+
|
|
371
|
+
// ver. 2 ->
|
|
372
|
+
transition ( task, dependencies, stateData, dt )
|
|
373
|
+
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
- **Change**: Open transition library and add 'task' argument to all transitioin functions.
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
### Description table
|
|
381
|
+
- **Version 1**: Transition condition in description table:
|
|
382
|
+
```js
|
|
383
|
+
[ 'state', 'action', 'nextState', 'transitionFx' ]
|
|
384
|
+
```
|
|
385
|
+
All fields are string and are required.
|
|
386
|
+
|
|
387
|
+
- **Version 2**: Fields in description table record:
|
|
388
|
+
```js
|
|
389
|
+
[ 'state', 'action', 'nextState', 'transitionFx', 'chainActions' ]
|
|
390
|
+
// chainAction is array [ nextAction, nextAction ]
|
|
391
|
+
// If we need chaining only on positive/negative result of transition we can use "false"
|
|
392
|
+
// Example:
|
|
393
|
+
// We need chain transition only if transition failed:
|
|
394
|
+
// [ false, nextAction ]
|
|
395
|
+
// This chainAction will trigger nextAction only if transition failed.
|
|
396
|
+
|
|
397
|
+
```
|
|
398
|
+
ChainActions is an array with two values. First value represents next action on success transition.
|
|
399
|
+
Second on failed transition. ChainAction is optional.
|
|
400
|
+
|
|
401
|
+
- **Changes**: As ChainActions is an optional parameter, no changes needed.
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
### Chaining
|
|
406
|
+
- Version 1:
|
|
407
|
+
TransitionResult should contain property "command", that will link to next transition.
|
|
408
|
+
- Version 2:
|
|
409
|
+
TransitionResult with property 'command' still works. Chaining in description-table is more powerfull and will overwrite transitionResult's "command" property.
|
|
410
|
+
- Changes: No changes needed but is much better to describe chains in description table instead in transition functions. Keep all logic flows on one place for easy reading and manipulating.
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
## Release History
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
### 4.0.1 ( 2022-11-16)
|
|
420
|
+
- [x] Walk was removed. Generates a lot of problems with objects in stateData(HTMLElement, Date, URL). StateData is using a shallow copy. Developer should take care of immutability himself;
|
|
421
|
+
|
|
422
|
+
### 4.0.0 (2022-11-15)
|
|
423
|
+
- [x] The library become a ES module;
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
### 3.0.0 (2022-10-14)
|
|
428
|
+
- [x] Dependency "@peter.naydenov/walk" was upgraded to version 3.0.0;
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
### 2.2.4 ( 2022-05-27 )
|
|
433
|
+
- [x] New dependency was added - walk ("@peter.naydenov/walk");
|
|
434
|
+
- [x] "Walk" is loaded by default in fsm dependency object;
|
|
435
|
+
- [x] "Ask-for-promise" is loaded by default in fsm dependency object;
|
|
436
|
+
- [x] Deep copy for stateData on each update with "walk" library;
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
### 2.2.3 ( 2021-04-02 )
|
|
441
|
+
- [x] Fix: Duplicated update callback if logic contain a chainAction;
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
### 2.2.2 ( 2021-03-26 )
|
|
447
|
+
- [x] Internal code refactoring;
|
|
448
|
+
- [ ] Bug: Duplicated update callback if logic contain a chainAction;
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
### 2.2.0 (2019-01-20)
|
|
453
|
+
- [x] Fix: Cached transitions are starting before callback functions for already executed transitions;
|
|
454
|
+
- [x] New method 'ignoreCachedUpdates()'. Ignore all cached updates;
|
|
455
|
+
|
|
456
|
+
### 2.1.0 (2019-01-19)
|
|
457
|
+
- [x] Export fsm state as an object - externalState;
|
|
458
|
+
- [x] Import externalState;
|
|
459
|
+
- [x] Lock updates during update process execution;
|
|
460
|
+
- [x] Prevent simultaneous updates;
|
|
461
|
+
- [x] Cache new updates during update process execution;
|
|
462
|
+
- [x] Execute cached updates in a row;
|
|
463
|
+
- [ ] Error: Cached transitions are starting before callback functions for already executed transitions;
|
|
464
|
+
|
|
465
|
+
### 2.0.0 (2018-12-01)
|
|
466
|
+
- [x] Transition function could contain asynchronous code;
|
|
467
|
+
- [x] Chain-actions in **transaction conditions** (Optional);
|
|
468
|
+
- [x] Chain-actions are possible on **positive** and *negative* transition-end;
|
|
469
|
+
|
|
470
|
+
### 1.0.0 (2018-11-21)
|
|
471
|
+
- [x] FSM;
|
|
472
|
+
- [x] Set FSM external dependencies;
|
|
473
|
+
- [x] Chain-actions by using `command` in transition response object;
|
|
474
|
+
- [x] Internal state flags and values with stateData;
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
## Credits
|
|
481
|
+
'@peter.naydenov/fsm' was created by Peter Naydenov.
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
## License
|
|
489
|
+
'@peter.naydenov/fsm' is released under the MIT License.
|
|
490
|
+
|
|
491
|
+
|
package/blueprint.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Plans for the future
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
## Data validator
|
|
6
|
+
Simple data validator as an optional testing instrument. DT based as the stateData.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## Method 'explore'
|
|
13
|
+
- Question FSM for available states, actions, transitions, state/action pairs;
|
|
14
|
+
-> list -> returns list of what is provided as second argument[ 'states', 'actions', 'state/action' ]
|
|
15
|
+
-> states: List of available states
|
|
16
|
+
-> transitions: Returns a function name for state/action name. If is not provided will return full list of possible action/ transition function
|
|
17
|
+
-> actions: List of available actions from provided state. If is not provided will return full list of possible actions from current state;
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
-> provide table of state/action -> transition -> resultState [ chainPositive, chainNegative]
|
|
21
|
+
-> ask for specific state -> provide list of possible actions;
|
|
22
|
+
-> ask for specific action -> provide list of possible states;
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
117
117
|
Code coverage generated by
|
|
118
118
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
119
|
-
at
|
|
119
|
+
at 2023-08-07T19:47:29.021Z
|
|
120
120
|
</div>
|
|
121
121
|
<script src="prettify.js"></script>
|
|
122
122
|
<script>
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
102
102
|
Code coverage generated by
|
|
103
103
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
104
|
-
at
|
|
104
|
+
at 2023-08-07T19:47:29.021Z
|
|
105
105
|
</div>
|
|
106
106
|
<script src="../prettify.js"></script>
|
|
107
107
|
<script>
|
|
@@ -193,7 +193,7 @@ export default Fsm
|
|
|
193
193
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
194
194
|
Code coverage generated by
|
|
195
195
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
196
|
-
at
|
|
196
|
+
at 2023-08-07T19:47:29.021Z
|
|
197
197
|
</div>
|
|
198
198
|
<script src="../prettify.js"></script>
|
|
199
199
|
<script>
|
|
@@ -103,7 +103,7 @@ export default _getChain
|
|
|
103
103
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
104
104
|
Code coverage generated by
|
|
105
105
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
106
|
-
at
|
|
106
|
+
at 2023-08-07T19:47:29.021Z
|
|
107
107
|
</div>
|
|
108
108
|
<script src="../../prettify.js"></script>
|
|
109
109
|
<script>
|
|
@@ -139,7 +139,7 @@ export default _onUpdateTask
|
|
|
139
139
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
140
140
|
Code coverage generated by
|
|
141
141
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
142
|
-
at
|
|
142
|
+
at 2023-08-07T19:47:29.021Z
|
|
143
143
|
</div>
|
|
144
144
|
<script src="../../prettify.js"></script>
|
|
145
145
|
<script>
|
|
@@ -202,7 +202,7 @@ export default _setTransitions
|
|
|
202
202
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
203
203
|
Code coverage generated by
|
|
204
204
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
205
|
-
at
|
|
205
|
+
at 2023-08-07T19:47:29.021Z
|
|
206
206
|
</div>
|
|
207
207
|
<script src="../../prettify.js"></script>
|
|
208
208
|
<script>
|
|
@@ -121,7 +121,7 @@ export default _transit
|
|
|
121
121
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
122
122
|
Code coverage generated by
|
|
123
123
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
124
|
-
at
|
|
124
|
+
at 2023-08-07T19:47:29.021Z
|
|
125
125
|
</div>
|
|
126
126
|
<script src="../../prettify.js"></script>
|
|
127
127
|
<script>
|
|
@@ -127,7 +127,7 @@ export default _triggerCacheUpdate
|
|
|
127
127
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
128
128
|
Code coverage generated by
|
|
129
129
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
130
|
-
at
|
|
130
|
+
at 2023-08-07T19:47:29.021Z
|
|
131
131
|
</div>
|
|
132
132
|
<script src="../../prettify.js"></script>
|
|
133
133
|
<script>
|
|
@@ -247,7 +247,7 @@ export default _updateStep
|
|
|
247
247
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
248
248
|
Code coverage generated by
|
|
249
249
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
250
|
-
at
|
|
250
|
+
at 2023-08-07T19:47:29.021Z
|
|
251
251
|
</div>
|
|
252
252
|
<script src="../../prettify.js"></script>
|
|
253
253
|
<script>
|
|
@@ -109,7 +109,7 @@ export default _warn
|
|
|
109
109
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
110
110
|
Code coverage generated by
|
|
111
111
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
112
|
-
at
|
|
112
|
+
at 2023-08-07T19:47:29.021Z
|
|
113
113
|
</div>
|
|
114
114
|
<script src="../../prettify.js"></script>
|
|
115
115
|
<script>
|
|
@@ -124,7 +124,7 @@ export default exportState
|
|
|
124
124
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
125
125
|
Code coverage generated by
|
|
126
126
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
127
|
-
at
|
|
127
|
+
at 2023-08-07T19:47:29.021Z
|
|
128
128
|
</div>
|
|
129
129
|
<script src="../../prettify.js"></script>
|
|
130
130
|
<script>
|
|
@@ -100,7 +100,7 @@ export default getState
|
|
|
100
100
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
101
101
|
Code coverage generated by
|
|
102
102
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
103
|
-
at
|
|
103
|
+
at 2023-08-07T19:47:29.021Z
|
|
104
104
|
</div>
|
|
105
105
|
<script src="../../prettify.js"></script>
|
|
106
106
|
<script>
|
|
@@ -109,7 +109,7 @@ export default ignoreCachedUpdates
|
|
|
109
109
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
110
110
|
Code coverage generated by
|
|
111
111
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
112
|
-
at
|
|
112
|
+
at 2023-08-07T19:47:29.021Z
|
|
113
113
|
</div>
|
|
114
114
|
<script src="../../prettify.js"></script>
|
|
115
115
|
<script>
|
|
@@ -118,7 +118,7 @@ export default importState
|
|
|
118
118
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
119
119
|
Code coverage generated by
|
|
120
120
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
121
|
-
at
|
|
121
|
+
at 2023-08-07T19:47:29.021Z
|
|
122
122
|
</div>
|
|
123
123
|
<script src="../../prettify.js"></script>
|
|
124
124
|
<script>
|
|
@@ -341,7 +341,7 @@
|
|
|
341
341
|
<div class='footer quiet pad2 space-top1 center small'>
|
|
342
342
|
Code coverage generated by
|
|
343
343
|
<a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
|
|
344
|
-
at
|
|
344
|
+
at 2023-08-07T19:47:29.021Z
|
|
345
345
|
</div>
|
|
346
346
|
<script src="../../prettify.js"></script>
|
|
347
347
|
<script>
|