@peter.naydenov/fsm 2.2.1 → 2.2.4
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/.nyc_output/86959cba-5ea6-46d1-a68b-aa782a39cf80.json +1 -0
- package/.nyc_output/processinfo/86959cba-5ea6-46d1-a68b-aa782a39cf80.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -1
- package/README.md +16 -1
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +88 -59
- package/coverage/lcov-report/index.js.html +63 -52
- package/coverage/lcov-report/src/index.html +111 -0
- package/coverage/lcov-report/src/index.js.html +206 -0
- package/coverage/lcov-report/src/methods/_getChain.js.html +113 -0
- package/coverage/lcov-report/src/methods/_onUpdateTask.js.html +149 -0
- package/coverage/lcov-report/src/methods/_setTransitions.js.html +212 -0
- package/coverage/lcov-report/src/methods/_transit.js.html +134 -0
- package/coverage/lcov-report/src/methods/_triggerCacheUpdate.js.html +137 -0
- package/coverage/lcov-report/src/methods/_updateStep.js.html +257 -0
- package/coverage/lcov-report/src/methods/_warn.js.html +122 -0
- package/coverage/lcov-report/src/methods/exportState.js.html +137 -0
- package/coverage/lcov-report/src/methods/getState.js.html +110 -0
- package/coverage/lcov-report/src/methods/ignoreCacheUpdates.js.html +119 -0
- package/coverage/lcov-report/src/methods/importState.js.html +128 -0
- package/coverage/lcov-report/src/methods/index.html +351 -0
- package/coverage/lcov-report/src/methods/index.js.html +224 -0
- package/coverage/lcov-report/src/methods/off.js.html +113 -0
- package/coverage/lcov-report/src/methods/on.js.html +116 -0
- package/coverage/lcov-report/src/methods/reset.js.html +116 -0
- package/coverage/lcov-report/src/methods/setDependencies.js.html +107 -0
- package/coverage/lcov-report/src/methods/update.js.html +140 -0
- package/coverage/lcov.info +476 -235
- package/package.json +10 -5
- package/src/index.js +17 -285
- package/src/methods/_getChain.js +11 -0
- package/src/methods/_onUpdateTask.js +23 -0
- package/src/methods/_setTransitions.js +44 -0
- package/src/methods/_transit.js +18 -0
- package/src/methods/_triggerCacheUpdate.js +19 -0
- package/src/methods/_updateStep.js +59 -0
- package/src/methods/_warn.js +14 -0
- package/src/methods/exportState.js +19 -0
- package/src/methods/getState.js +10 -0
- package/src/methods/ignoreCacheUpdates.js +13 -0
- package/src/methods/importState.js +16 -0
- package/src/methods/index.js +48 -0
- package/src/methods/off.js +11 -0
- package/src/methods/on.js +12 -0
- package/src/methods/reset.js +12 -0
- package/src/methods/setDependencies.js +9 -0
- package/src/methods/update.js +20 -0
- package/.nyc_output/51489dd3-db09-41c2-ba8f-51921b0f9c74.json +0 -1
- package/.nyc_output/683c9ca8-4bd1-4c2f-b532-d68517f8fae5.json +0 -1
- package/.nyc_output/processinfo/51489dd3-db09-41c2-ba8f-51921b0f9c74.json +0 -1
- package/.nyc_output/processinfo/683c9ca8-4bd1-4c2f-b532-d68517f8fae5.json +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peter.naydenov/fsm",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.4",
|
|
4
4
|
"description": "Simple Finite State Machine",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -10,13 +10,18 @@
|
|
|
10
10
|
"author": "Peter Naydenov",
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"
|
|
13
|
+
"@peter.naydenov/walk": "1.1.0",
|
|
14
|
+
"ask-for-promise": "1.3.1"
|
|
14
15
|
},
|
|
15
16
|
"devDependencies": {
|
|
16
|
-
"chai": "4.
|
|
17
|
+
"chai": "4.3.6",
|
|
17
18
|
"expect.js": "0.3.1",
|
|
18
|
-
"mocha": "
|
|
19
|
-
"nyc": "
|
|
19
|
+
"mocha": "10.0.0",
|
|
20
|
+
"nyc": "15.1.0"
|
|
21
|
+
},
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/PeterNaydenov/fsm.git"
|
|
20
25
|
},
|
|
21
26
|
"nyc": {
|
|
22
27
|
"include": [
|
package/src/index.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
|
|
2
2
|
const
|
|
3
3
|
MISSING_STATE = 'N/A'
|
|
4
|
-
, askForPromise
|
|
4
|
+
, askForPromise = require ( 'ask-for-promise' )
|
|
5
|
+
, methods = require ( './methods/index' )
|
|
6
|
+
, walk = require ( '@peter.naydenov/walk' )
|
|
5
7
|
;
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
fsm = this
|
|
11
|
-
, sData = Object.assign ( {}, stateData )
|
|
12
|
-
;
|
|
9
|
+
function Fsm ({init, table, stateData, debug }, lib={} ) {
|
|
10
|
+
const fsm = this;
|
|
11
|
+
|
|
13
12
|
fsm.state = init || MISSING_STATE
|
|
14
13
|
fsm.initialState = init || MISSING_STATE
|
|
15
14
|
fsm.lock = false // switch 'ON' during transition in progress. Write other updates in cache.
|
|
16
15
|
fsm.cache = [] // cached 'update' commands
|
|
16
|
+
fsm.askForPromise = askForPromise
|
|
17
17
|
|
|
18
|
-
fsm.stateData =
|
|
19
|
-
fsm.initialStateData =
|
|
20
|
-
fsm.dependencies = {}
|
|
18
|
+
fsm.stateData = walk ( stateData )
|
|
19
|
+
fsm.initialStateData = walk ( stateData )
|
|
20
|
+
fsm.dependencies = { walk, askForPromise }
|
|
21
21
|
fsm.callback = {
|
|
22
22
|
update : []
|
|
23
23
|
, transition : []
|
|
@@ -25,286 +25,18 @@ class Fsm {
|
|
|
25
25
|
, negative : []
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
if ( debug ) fsm._warn ( result.transitions )
|
|
30
|
-
fsm.transitions = result.transitions
|
|
31
|
-
fsm.nextState = result.nextState
|
|
32
|
-
fsm.chainActions = result.chainActions
|
|
33
|
-
} // constructor func.
|
|
28
|
+
walk ( methods, (v,k) => fsm[k] = methods[k](fsm) ) // Attach methods to fsm
|
|
34
29
|
|
|
30
|
+
const {transitions, nextState, chainActions } = fsm._setTransitions ( table, lib );
|
|
31
|
+
if ( debug ) fsm._warn ( transitions )
|
|
32
|
+
fsm.transitions = transitions
|
|
33
|
+
fsm.nextState = nextState
|
|
34
|
+
fsm.chainActions = chainActions
|
|
35
|
+
} // Fsm func.
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
|
|
38
39
|
|
|
39
|
-
_warn ( data ) {
|
|
40
|
-
// *** Warn if transition function used in description table is not defined.
|
|
41
|
-
Object.keys(data).forEach ( k => {
|
|
42
|
-
if (data[k] == null) console.log ( `Warning: Transition for ${k} is not defined` )
|
|
43
|
-
})
|
|
44
|
-
} // _warn func.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
_setTransitions ( data, lib ) { // ( machineTable, transitionLib ) --> {transitions, nextState, chainActions}
|
|
51
|
-
// *** Converts initial FSM data to useful fsm objects.
|
|
52
|
-
let
|
|
53
|
-
fsm = this
|
|
54
|
-
, transitions = {}
|
|
55
|
-
, nextState = {}
|
|
56
|
-
, chainActions = {}
|
|
57
|
-
;
|
|
58
|
-
data.forEach ( el => {
|
|
59
|
-
const
|
|
60
|
-
[ from, action, next, transitionName, alt ] = el
|
|
61
|
-
, transition = lib [ transitionName ]
|
|
62
|
-
, key = `${from}/${action}`
|
|
63
|
-
;
|
|
64
|
-
transitions[key] = transition || null
|
|
65
|
-
nextState [key] = next
|
|
66
|
-
if ( fsm._isAltValid(alt) ) {
|
|
67
|
-
chainActions [key] = []
|
|
68
|
-
chainActions [key][0] = alt[0]
|
|
69
|
-
chainActions [key][1] = alt[1]
|
|
70
|
-
}
|
|
71
|
-
})
|
|
72
|
-
return { transitions, nextState, chainActions }
|
|
73
|
-
} // setTransitions
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
_isAltValid ( alt ) { // (altAction) -> boolean
|
|
80
|
-
// *** Check if alt is valid altAction.
|
|
81
|
-
if ( !(alt instanceof Array) ) return false
|
|
82
|
-
if ( alt.length != 2 ) return false
|
|
83
|
-
alt.forEach ( m => {
|
|
84
|
-
if ( m !== false || typeof m != 'string' ) return false
|
|
85
|
-
})
|
|
86
|
-
return true
|
|
87
|
-
} // _isAltValid func.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
setDependencies ( deps ) {
|
|
94
|
-
this.dependencies = Object.assign ( {}, this.dependencies, deps )
|
|
95
|
-
} // setDependencies func.
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
on ( eName, fn) {
|
|
102
|
-
// *** Register callback functions on: 'update', 'transition', 'negative', 'positive'
|
|
103
|
-
const
|
|
104
|
-
fsm = this
|
|
105
|
-
, cb = fsm.callback;
|
|
106
|
-
if ( cb[eName] ) cb[eName].push ( fn )
|
|
107
|
-
} // on func.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
off ( eName ) {
|
|
113
|
-
if ( !fsm.callback[eName] ) return
|
|
114
|
-
fsm.callback[eName] = []
|
|
115
|
-
} // off func.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
getState () { return this.state }
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
importState ( {state, stateData} ) {
|
|
128
|
-
// *** Import existing state to fsm
|
|
129
|
-
const fsm = this;
|
|
130
|
-
if ( state ) {
|
|
131
|
-
fsm.state = state
|
|
132
|
-
fsm.stateData = Object.assign ( {}, stateData )
|
|
133
|
-
}
|
|
134
|
-
} // importState func.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
exportState () {
|
|
141
|
-
// *** Export internal flags and state as an object
|
|
142
|
-
const
|
|
143
|
-
fsm = this
|
|
144
|
-
, state = fsm.state
|
|
145
|
-
, stateData = Object.assign ( {}, fsm.stateData )
|
|
146
|
-
;
|
|
147
|
-
return {
|
|
148
|
-
state
|
|
149
|
-
, stateData
|
|
150
|
-
}
|
|
151
|
-
} // exportState func.
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
transit ( task, key, dt ) { // ( promiseObj, transitionKey, additionalData ) -> void
|
|
158
|
-
// *** Execute transition if exists. Ignore all non-predefined cases
|
|
159
|
-
const
|
|
160
|
-
fsm = this
|
|
161
|
-
, dependencies = Object.assign ( {}, fsm.dependencies )
|
|
162
|
-
, stateData = Object.assign ( {}, fsm.stateData )
|
|
163
|
-
, transition = fsm.transitions [ key ]
|
|
164
|
-
;
|
|
165
|
-
if ( typeof transition === 'function' ) transition ( task, dependencies, stateData, dt )
|
|
166
|
-
else task.done ({ success : false }) // ignore all non-predefined cases
|
|
167
|
-
} // transit func.
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
update ( action, dt ) { // () -> Promise<transitionResponse>
|
|
174
|
-
// *** Executes transition-functions and transition-chains.
|
|
175
|
-
const
|
|
176
|
-
fsm = this
|
|
177
|
-
, theUpdate = askForPromise ()
|
|
178
|
-
;
|
|
179
|
-
if ( fsm.lock ) {
|
|
180
|
-
fsm.cache.push ( { theUpdate, action, dt })
|
|
181
|
-
return theUpdate.promise
|
|
182
|
-
}
|
|
183
|
-
fsm._updateStep ( theUpdate, action, dt )
|
|
184
|
-
return theUpdate.promise
|
|
185
|
-
} // update func.
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
_updateStep ( theUpdate, action, dt ) {
|
|
192
|
-
const
|
|
193
|
-
fsm = this
|
|
194
|
-
, task = askForPromise ()
|
|
195
|
-
, key = `${fsm.state}/${action}`
|
|
196
|
-
, cb = fsm.callback
|
|
197
|
-
;
|
|
198
|
-
fsm.lock = true
|
|
199
|
-
fsm.transit ( task, key, dt )
|
|
200
|
-
task.onComplete (
|
|
201
|
-
result => {
|
|
202
|
-
/**
|
|
203
|
-
* Result description:
|
|
204
|
-
* {
|
|
205
|
-
* success - boolean. Is it transition successful.
|
|
206
|
-
* ? stateData - object. Flat object with fsm state values.
|
|
207
|
-
* ? response - object. External data as response of transition if needed.
|
|
208
|
-
* ? command - string. Next action if function-chaining.
|
|
209
|
-
* }
|
|
210
|
-
*/
|
|
211
|
-
|
|
212
|
-
let
|
|
213
|
-
chainActions = fsm._getChain ( fsm.chainActions, key)
|
|
214
|
-
, data = result.response
|
|
215
|
-
;
|
|
216
|
-
|
|
217
|
-
if ( result.success ) {
|
|
218
|
-
fsm.state = fsm.nextState [ key ]
|
|
219
|
-
if ( result.stateData ) fsm.stateData = result.stateData
|
|
220
|
-
cb [ 'positive' ].forEach ( fn => fn ( fsm.state, data) )
|
|
221
|
-
cb [ 'transition' ].forEach ( fn => fn ( fsm.state, data) )
|
|
222
|
-
if ( chainActions && chainActions[0] ) {
|
|
223
|
-
fsm._updateStep ( theUpdate, chainActions[0], data ) // Positive altAction index
|
|
224
|
-
return
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
cb [ 'negative' ].forEach ( fn => fn ( fsm.state, data) )
|
|
229
|
-
cb [ 'transition' ].forEach ( fn => fn ( fsm.state, data) )
|
|
230
|
-
if ( chainActions && chainActions[1] ) {
|
|
231
|
-
fsm._updateStep ( theUpdate, chainActions[1], data ) // Negative altAction index
|
|
232
|
-
return
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
if ( result.command ) {
|
|
236
|
-
fsm._updateStep ( theUpdate, result.command, data )
|
|
237
|
-
return
|
|
238
|
-
}
|
|
239
|
-
theUpdate.done ( data )
|
|
240
|
-
}) // task onComplete
|
|
241
|
-
|
|
242
|
-
theUpdate.onComplete ( data => {
|
|
243
|
-
const updateCallbacks = askForPromise ( cb['update'] );
|
|
244
|
-
cb [ 'update' ].forEach ( (fn,i) => {
|
|
245
|
-
fn ( fsm.state, data )
|
|
246
|
-
updateCallbacks[i].done ()
|
|
247
|
-
})
|
|
248
|
-
updateCallbacks.onComplete ( x => {
|
|
249
|
-
fsm.lock = false
|
|
250
|
-
fsm._triggerCacheUpdate ()
|
|
251
|
-
})
|
|
252
|
-
})
|
|
253
|
-
task.promise.catch ( () => console.log ( `Failed in step ${key}`) )
|
|
254
|
-
} // updateStep func.
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
ignoreCachedUpdates () {
|
|
261
|
-
// *** Ignore all cached updates
|
|
262
|
-
const
|
|
263
|
-
fsm = this
|
|
264
|
-
, cache = fsm.cache
|
|
265
|
-
;
|
|
266
|
-
cache.forEach ( ({theUpdate, action, dt} ) => theUpdate.cancel ( `Action '${action}' was ignored` ))
|
|
267
|
-
fsm.cache = []
|
|
268
|
-
} // ignoreCache func.
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
_triggerCacheUpdate () {
|
|
274
|
-
const fsm = this;
|
|
275
|
-
if ( fsm.cache.length !== 0 ) {
|
|
276
|
-
const { theUpdate, action, dt } = fsm.cache [0]
|
|
277
|
-
fsm.cache = fsm.cache.reduce ( (res,el,i) => {
|
|
278
|
-
if ( i != 0 ) res.push(el)
|
|
279
|
-
return res
|
|
280
|
-
},[] )
|
|
281
|
-
fsm._updateStep ( theUpdate, action, dt )
|
|
282
|
-
}
|
|
283
|
-
} // _triggerCachceUpdate func.
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
_getChain ( chainActions, key ) {
|
|
290
|
-
if ( !chainActions[key] ) return false
|
|
291
|
-
return chainActions [key]
|
|
292
|
-
} // getAlt func.
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
reset () {
|
|
299
|
-
const fsm = this;
|
|
300
|
-
fsm.state = fsm.initialState
|
|
301
|
-
fsm.stateData = fsm.initialStateData
|
|
302
|
-
} // reset func.
|
|
303
|
-
|
|
304
|
-
} // class Fsm
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
40
|
module.exports = Fsm
|
|
309
41
|
|
|
310
42
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
function _onUpdateTask ( fsm ) {
|
|
2
|
+
return function _onUpdateTask ( data ) {
|
|
3
|
+
const
|
|
4
|
+
cb = fsm.callback
|
|
5
|
+
, updateCallbacks = fsm.askForPromise ( cb['update'] )
|
|
6
|
+
;
|
|
7
|
+
|
|
8
|
+
cb [ 'update' ].forEach ( (fn,i) => {
|
|
9
|
+
fn ( fsm.state, data )
|
|
10
|
+
updateCallbacks[i].done ()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
updateCallbacks.onComplete ( x => {
|
|
14
|
+
fsm.lock = false
|
|
15
|
+
fsm._triggerCacheUpdate ()
|
|
16
|
+
})
|
|
17
|
+
}} // _onUpdateTask func.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
module.exports = _onUpdateTask
|
|
22
|
+
|
|
23
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
function _setTransitions () {
|
|
2
|
+
return function ( table, lib ) { // ( machineTable, transitionLib ) --> {transitions, nextState, chainActions}
|
|
3
|
+
// *** Converts initial FSM data to useful fsm objects.
|
|
4
|
+
let
|
|
5
|
+
transitions = {}
|
|
6
|
+
, nextState = {}
|
|
7
|
+
, chainActions = {}
|
|
8
|
+
;
|
|
9
|
+
table.forEach ( el => {
|
|
10
|
+
const
|
|
11
|
+
[ from, action, next, transitionName, alt ] = el
|
|
12
|
+
, transition = lib [ transitionName ]
|
|
13
|
+
, key = `${from}/${action}`
|
|
14
|
+
;
|
|
15
|
+
transitions[key] = transition || null
|
|
16
|
+
nextState [key] = next
|
|
17
|
+
if ( _isAltValid(alt) ) {
|
|
18
|
+
chainActions [key] = []
|
|
19
|
+
chainActions [key][0] = alt[0]
|
|
20
|
+
chainActions [key][1] = alt[1]
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
return { transitions, nextState, chainActions }
|
|
24
|
+
}} // _setTransitions func.
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
function _isAltValid ( alt ) { // (altAction) -> boolean
|
|
31
|
+
// *** Check if alt is valid altAction.
|
|
32
|
+
if ( !(alt instanceof Array) ) return false
|
|
33
|
+
if ( alt.length != 2 ) return false
|
|
34
|
+
alt.forEach ( m => {
|
|
35
|
+
if ( m !== false || typeof m != 'string' ) return false
|
|
36
|
+
})
|
|
37
|
+
return true
|
|
38
|
+
} // _isAltValid func.
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
module.exports = _setTransitions
|
|
43
|
+
|
|
44
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function _transit (fsm ) {
|
|
2
|
+
return function ( task, key, dt ) { // ( promiseObj, transitionKey, additionalData ) -> void
|
|
3
|
+
// *** Execute transition if exists. Ignore all non-predefined cases
|
|
4
|
+
const
|
|
5
|
+
dependencies = fsm.dependencies
|
|
6
|
+
, { walk } = dependencies
|
|
7
|
+
, stateData = walk ( fsm.stateData )
|
|
8
|
+
, transition = fsm.transitions [ key ]
|
|
9
|
+
;
|
|
10
|
+
if ( typeof transition === 'function' ) transition ( task, dependencies, stateData, dt )
|
|
11
|
+
else task.done ({ success : false }) // ignore all non-predefined cases
|
|
12
|
+
}} // _transit func.
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
module.exports = _transit
|
|
17
|
+
|
|
18
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
function _triggerCacheUpdate ( fsm ) {
|
|
2
|
+
return function () {
|
|
3
|
+
if ( fsm.cache.length !== 0 ) {
|
|
4
|
+
const { updateTask, action, dt } = fsm.cache [0]
|
|
5
|
+
fsm.cache = fsm.cache.reduce ( (res,el,i) => {
|
|
6
|
+
if ( i != 0 ) res.push(el)
|
|
7
|
+
return res
|
|
8
|
+
},[] )
|
|
9
|
+
|
|
10
|
+
fsm._updateStep ( updateTask, action, dt )
|
|
11
|
+
updateTask.onComplete ( data => fsm._onUpdateTask ( data ) )
|
|
12
|
+
}
|
|
13
|
+
}} // _triggerCacheUpdate func.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
module.exports = _triggerCacheUpdate
|
|
18
|
+
|
|
19
|
+
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
function _updateStep ( fsm ) {
|
|
2
|
+
return function ( updateTask, action, dt ) {
|
|
3
|
+
const
|
|
4
|
+
task = fsm.askForPromise ()
|
|
5
|
+
, key = `${fsm.state}/${action}`
|
|
6
|
+
, cb = fsm.callback
|
|
7
|
+
;
|
|
8
|
+
fsm.lock = true
|
|
9
|
+
fsm._transit ( task, key, dt )
|
|
10
|
+
task.onComplete (
|
|
11
|
+
result => {
|
|
12
|
+
/**
|
|
13
|
+
* Result description:
|
|
14
|
+
* {
|
|
15
|
+
* success - boolean. Is it transition successful.
|
|
16
|
+
* ? stateData - object. Flat object with fsm state values.
|
|
17
|
+
* ? response - object. External data as response of transition if needed.
|
|
18
|
+
* ? command - string. Next action if function-chaining. (depricated!) Use a chainAction inside the logic table
|
|
19
|
+
* }
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
let
|
|
23
|
+
chainActions = fsm._getChain ( fsm.chainActions, key)
|
|
24
|
+
, data = result.response
|
|
25
|
+
;
|
|
26
|
+
|
|
27
|
+
if ( result.success ) {
|
|
28
|
+
fsm.state = fsm.nextState [ key ]
|
|
29
|
+
if ( result.stateData ) fsm.stateData = result.stateData
|
|
30
|
+
cb [ 'positive' ].forEach ( fn => fn ( fsm.state, data) )
|
|
31
|
+
cb [ 'transition' ].forEach ( fn => fn ( fsm.state, data) )
|
|
32
|
+
if ( chainActions && chainActions[0] ) {
|
|
33
|
+
fsm._updateStep ( updateTask, chainActions[0], data ) // Positive altAction index
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
cb [ 'negative' ].forEach ( fn => fn ( fsm.state, data) )
|
|
39
|
+
cb [ 'transition' ].forEach ( fn => fn ( fsm.state, data) )
|
|
40
|
+
if ( chainActions && chainActions[1] ) {
|
|
41
|
+
fsm._updateStep ( updateTask, chainActions[1], data ) // Negative altAction index
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if ( result.command ) {
|
|
46
|
+
fsm._updateStep ( updateTask, result.command, data )
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
updateTask.done ( data )
|
|
50
|
+
}) // task onComplete
|
|
51
|
+
|
|
52
|
+
task.promise.catch ( () => console.log ( `Failed in step ${key}`) )
|
|
53
|
+
}} // updateStep func.
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
module.exports = _updateStep
|
|
58
|
+
|
|
59
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
function _warn ( fsm ) {
|
|
2
|
+
return function ( transitions ) {
|
|
3
|
+
// *** Warn if transition function used in description table is not defined.
|
|
4
|
+
const { walk } = fsm.dependencies;
|
|
5
|
+
walk ( transitions, (v,k) => {
|
|
6
|
+
if (v == null) console.log ( `Warning: Transition for ${k} is not defined` )
|
|
7
|
+
})
|
|
8
|
+
}} // warn func.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
module.exports = _warn
|
|
13
|
+
|
|
14
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
function exportState (fsm) {
|
|
2
|
+
return function () {
|
|
3
|
+
// *** Export internal flags and state as an object
|
|
4
|
+
const
|
|
5
|
+
state = fsm.state
|
|
6
|
+
, { walk } = fsm.dependencies
|
|
7
|
+
, stateData = walk ( fsm.stateData )
|
|
8
|
+
;
|
|
9
|
+
return {
|
|
10
|
+
state
|
|
11
|
+
, stateData
|
|
12
|
+
}
|
|
13
|
+
}} // exportState func.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
module.exports = exportState
|
|
18
|
+
|
|
19
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function ignoreCachedUpdates ( fsm ) {
|
|
2
|
+
return function () {
|
|
3
|
+
// *** Ignore all cached updates
|
|
4
|
+
const cache = fsm.cache;
|
|
5
|
+
cache.forEach ( ({updateTask, action, dt} ) => updateTask.cancel ( `Action '${action}' was ignored` ))
|
|
6
|
+
fsm.cache = []
|
|
7
|
+
}} // ignoreCache func.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
module.exports = ignoreCachedUpdates
|
|
12
|
+
|
|
13
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function importState (fsm) {
|
|
2
|
+
return function ( {state, stateData} ) {
|
|
3
|
+
// *** Import existing state to fsm
|
|
4
|
+
const { walk } = fsm.dependencies;
|
|
5
|
+
if ( state ) {
|
|
6
|
+
fsm.state = state
|
|
7
|
+
fsm.stateData = walk ( stateData )
|
|
8
|
+
// TODO: test if stateData exist ??!
|
|
9
|
+
}
|
|
10
|
+
}} // importState func.
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
module.exports = importState
|
|
15
|
+
|
|
16
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const
|
|
2
|
+
_setTransitions = require ( './_setTransitions' )
|
|
3
|
+
, _updateStep = require ( './_updateStep' )
|
|
4
|
+
, _warn = require ( './_warn' )
|
|
5
|
+
, _transit = require ( './_transit' )
|
|
6
|
+
, _getChain = require ( './_getChain' )
|
|
7
|
+
, _triggerCacheUpdate = require ( './_triggerCacheUpdate' )
|
|
8
|
+
, _onUpdateTask = require ( './_onUpdateTask' )
|
|
9
|
+
|
|
10
|
+
, setDependencies = require ( './setDependencies' )
|
|
11
|
+
, on = require ( './on' )
|
|
12
|
+
, off = require ( './off' )
|
|
13
|
+
, importState = require ( './importState' )
|
|
14
|
+
, exportState = require ( './exportState' )
|
|
15
|
+
, update = require ( './update' )
|
|
16
|
+
, reset = require ( './reset' )
|
|
17
|
+
, ignoreCachedUpdates = require ( './ignoreCacheUpdates' )
|
|
18
|
+
, getState = require ( './getState' )
|
|
19
|
+
;
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
const fn = {
|
|
24
|
+
// *** "Private" methods
|
|
25
|
+
_setTransitions // Convert machine configuration and transition library in a internal fsm structures
|
|
26
|
+
, _updateStep // Process results of transitions
|
|
27
|
+
, _warn // Warn on issues if "debug:true" in machine configuration
|
|
28
|
+
, _transit // Executes a transition if it is defined
|
|
29
|
+
, _getChain // Returns chainAction for the key if available
|
|
30
|
+
, _triggerCacheUpdate // Call next transition from the cache
|
|
31
|
+
, _onUpdateTask // Executes on update success. Used in "update" and "_triggerCacheUpdate"
|
|
32
|
+
// *** Public methods
|
|
33
|
+
, setDependencies // Add objects in dependencies
|
|
34
|
+
, on // Register callback functions on: 'update', 'transition', 'negative', 'positive'
|
|
35
|
+
, off // Remove callbacks
|
|
36
|
+
, importState // Get state and data from outside
|
|
37
|
+
, exportState // Extract state from fsm
|
|
38
|
+
, update // Trigger an action on fsm
|
|
39
|
+
, reset // Change state and stateData to initial values
|
|
40
|
+
, ignoreCachedUpdates // Disable update records in the cache
|
|
41
|
+
, getState // Return a state value
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
module.exports = fn
|
|
47
|
+
|
|
48
|
+
|