@statewalker/fsm 0.9.2 → 0.10.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.
- package/LICENSE +21 -0
- package/README.md +1 -1
- package/dist/{cjs/statewalker-fsm.js → index-umd.js} +40 -94
- package/dist/index-umd.min.js +2 -0
- package/dist/{esm/statewalker-fsm-esm.js → index.js} +31 -85
- package/dist/index.min.js +2 -0
- package/package.json +21 -21
- package/src/newAsyncProcess.js +22 -24
- package/src/newSyncProcess.js +3 -2
- package/dist/cjs/package.json +0 -3
- package/dist/cjs/statewalker-fsm.min.js +0 -2
- package/dist/esm/statewalker-fsm-esm.min.js +0 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 statewalker
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
# Hierarchical Finite State Machine
|
|
1
|
+
# @statewalker/fsm: Hierarchical Finite State Machine
|
|
@@ -1,65 +1,9 @@
|
|
|
1
|
-
// @statewalker/fsm v0.
|
|
1
|
+
// @statewalker/fsm v0.10.1 https://github.com/statewalker/statewalker-tree Copyright 2022 Mikhail Kotelnikov
|
|
2
2
|
(function (global, factory) {
|
|
3
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
4
|
-
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
5
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.statewalker = global.statewalker || {}, global.statewalker.fsm = global.statewalker.fsm || {})));
|
|
6
|
-
})(this, (function (exports) { 'use strict';
|
|
7
|
-
|
|
8
|
-
const MODE = {
|
|
9
|
-
NONE : 0,
|
|
10
|
-
FIRST: 1, // old=true; new=true => ENTER + ENTER
|
|
11
|
-
NEXT: 2, // old=false; new=true => EXIT + ENTER
|
|
12
|
-
LEAF : 4, // old=true; new=false => ENTER + EXIT
|
|
13
|
-
LAST : 8, // old=false; new=false => EXIT + EXIT
|
|
14
|
-
|
|
15
|
-
ENTER: 1 | 2, // MODE.FIRST | MODE.NEXT
|
|
16
|
-
EXIT : 4 | 8 // MODE.LEAF | MODE.LAST
|
|
17
|
-
};
|
|
18
|
-
var MODE$1 = MODE;
|
|
19
|
-
|
|
20
|
-
function newTreeWalker(
|
|
21
|
-
before, after,
|
|
22
|
-
context = { stack: [], status: MODE$1.NONE }
|
|
23
|
-
) {
|
|
24
|
-
return (getNode) => {
|
|
25
|
-
let status = context.status;
|
|
26
|
-
const prev = status & MODE$1.EXIT;
|
|
27
|
-
if (prev) after(context);
|
|
28
|
-
if (status & MODE$1.ENTER) context.stack.push(context.current);
|
|
29
|
-
let node = getNode(context);
|
|
30
|
-
if (node) {
|
|
31
|
-
context.current = node;
|
|
32
|
-
status = context.status = prev ? MODE$1.NEXT : MODE$1.FIRST;
|
|
33
|
-
before(context);
|
|
34
|
-
} else {
|
|
35
|
-
node = context.current = context.stack.pop();
|
|
36
|
-
status = context.status = node ? prev ? MODE$1.LAST : MODE$1.LEAF : MODE$1.NONE;
|
|
37
|
-
}
|
|
38
|
-
return status !== MODE$1.NONE;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function newAsyncTreeWalker(
|
|
43
|
-
before, after,
|
|
44
|
-
context = { stack: [], status: MODE$1.NONE }
|
|
45
|
-
) {
|
|
46
|
-
return async (getNode) => {
|
|
47
|
-
let status = context.status;
|
|
48
|
-
const prev = status & MODE$1.EXIT;
|
|
49
|
-
if (prev) await after(context);
|
|
50
|
-
if (status & MODE$1.ENTER) await context.stack.push(context.current);
|
|
51
|
-
let node = await getNode(context);
|
|
52
|
-
if (node) {
|
|
53
|
-
context.current = node;
|
|
54
|
-
status = context.status = prev ? MODE$1.NEXT : MODE$1.FIRST;
|
|
55
|
-
await before(context);
|
|
56
|
-
} else {
|
|
57
|
-
node = context.current = await context.stack.pop();
|
|
58
|
-
status = context.status = node ? prev ? MODE$1.LAST : MODE$1.LEAF : MODE$1.NONE;
|
|
59
|
-
}
|
|
60
|
-
return status !== MODE$1.NONE;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
3
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@statewalker/tree')) :
|
|
4
|
+
typeof define === 'function' && define.amd ? define(['exports', '@statewalker/tree'], factory) :
|
|
5
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.statewalker = global.statewalker || {}, global.statewalker.fsm = global.statewalker.fsm || {}), global.statewalker.tree));
|
|
6
|
+
})(this, (function (exports, tree) { 'use strict';
|
|
63
7
|
|
|
64
8
|
function buildStateDescriptor(config = {}) {
|
|
65
9
|
const { key, transitions = [], states = {}, options, ...params } = config;
|
|
@@ -269,7 +213,7 @@ function newProcessInstance({
|
|
|
269
213
|
} else {
|
|
270
214
|
const eventKey = process.event.key || KEYS.EVENT_EMPTY;
|
|
271
215
|
const parentDescriptor = process.stack[process.stack.length - 1].descriptor;
|
|
272
|
-
const stateKey = process.status & MODE
|
|
216
|
+
const stateKey = process.status & tree.MODE.ENTER
|
|
273
217
|
? KEYS.STATE_INITIAL
|
|
274
218
|
: process.current ? process.current.key : KEYS.STATE_FINAL;
|
|
275
219
|
key = getTargetStateKey(parentDescriptor, stateKey, eventKey);
|
|
@@ -297,40 +241,38 @@ function newAsyncProcess({
|
|
|
297
241
|
newProcess,
|
|
298
242
|
newState
|
|
299
243
|
});
|
|
300
|
-
const shift = newAsyncTreeWalker(before, after, process);
|
|
244
|
+
const shift = tree.newAsyncTreeWalker(before, after, process);
|
|
301
245
|
process.finished = false;
|
|
302
|
-
process.
|
|
246
|
+
process.next = (event) => {
|
|
303
247
|
process.nextEvent = event;
|
|
304
|
-
process.running = process.running || Promise
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
process.
|
|
312
|
-
process.nextEvent
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
248
|
+
return process.running = process.running || Promise
|
|
249
|
+
.resolve()
|
|
250
|
+
.then(async () => {
|
|
251
|
+
try {
|
|
252
|
+
process.event = process.nextEvent;
|
|
253
|
+
process.nextEvent = undefined;
|
|
254
|
+
while (!process.finished && process.event) {
|
|
255
|
+
process.finished = !await shift(loadNextState);
|
|
256
|
+
if ((process.status & tree.MODE.EXIT) && process.nextEvent) {
|
|
257
|
+
// Consume the next event if it exists.
|
|
258
|
+
process.event = process.nextEvent;
|
|
259
|
+
process.nextEvent = undefined;
|
|
260
|
+
} else if (process.status & tree.MODE.LEAF) {
|
|
261
|
+
// Returns control when the process is in a "leaf" state (a state without children)
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
316
264
|
}
|
|
317
|
-
|
|
265
|
+
} catch (error) {
|
|
266
|
+
handleError(error);
|
|
318
267
|
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}).finally(() => process.running = undefined);
|
|
323
|
-
};
|
|
324
|
-
|
|
325
|
-
process.next = async (event) => {
|
|
326
|
-
process.dispatch(event);
|
|
327
|
-
await process.running;
|
|
328
|
-
return !process.finished;
|
|
268
|
+
})
|
|
269
|
+
.finally(() => process.running = undefined)
|
|
270
|
+
.then(() => !process.finished);
|
|
329
271
|
};
|
|
330
272
|
return process;
|
|
331
273
|
}
|
|
332
274
|
|
|
333
|
-
function newSyncProcess({
|
|
275
|
+
function newSyncProcess({
|
|
334
276
|
config,
|
|
335
277
|
descriptor,
|
|
336
278
|
before, after,
|
|
@@ -343,19 +285,19 @@ function newSyncProcess({
|
|
|
343
285
|
newProcess,
|
|
344
286
|
newState,
|
|
345
287
|
});
|
|
346
|
-
const shift = newTreeWalker(before, after, process);
|
|
347
|
-
process.dispatch = process.next =(event) => {
|
|
288
|
+
const shift = tree.newTreeWalker(before, after, process);
|
|
289
|
+
process.dispatch = process.next = (event) => {
|
|
290
|
+
if (typeof event === 'string') event = { key : event };
|
|
348
291
|
process.event = event;
|
|
349
292
|
while (process.event) {
|
|
350
293
|
if (!shift(loadNextState)) return false;
|
|
351
|
-
if (process.status & MODE
|
|
294
|
+
if (process.status & tree.MODE.LEAF) return true;
|
|
352
295
|
}
|
|
353
296
|
};
|
|
354
297
|
return process;
|
|
355
298
|
}
|
|
356
299
|
|
|
357
300
|
exports.KEYS = KEYS;
|
|
358
|
-
exports.MODE = MODE$1;
|
|
359
301
|
exports.buildStateDescriptor = buildStateDescriptor;
|
|
360
302
|
exports.checkProcessDescriptor = checkProcessDescriptor;
|
|
361
303
|
exports.getAllStateKeys = getAllStateKeys;
|
|
@@ -363,10 +305,14 @@ exports.getAllTransitions = getAllTransitions;
|
|
|
363
305
|
exports.getStateDescriptor = getStateDescriptor;
|
|
364
306
|
exports.getTargetStateKey = getTargetStateKey;
|
|
365
307
|
exports.newAsyncProcess = newAsyncProcess;
|
|
366
|
-
exports.newAsyncTreeWalker = newAsyncTreeWalker;
|
|
367
308
|
exports.newProcessInstance = newProcessInstance;
|
|
368
309
|
exports.newSyncProcess = newSyncProcess;
|
|
369
|
-
|
|
310
|
+
Object.keys(tree).forEach(function (k) {
|
|
311
|
+
if (k !== 'default' && !exports.hasOwnProperty(k)) Object.defineProperty(exports, k, {
|
|
312
|
+
enumerable: true,
|
|
313
|
+
get: function () { return tree[k]; }
|
|
314
|
+
});
|
|
315
|
+
});
|
|
370
316
|
|
|
371
317
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
372
318
|
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @statewalker/fsm v0.10.1 https://github.com/statewalker/statewalker-tree Copyright 2022 Mikhail Kotelnikov
|
|
2
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@statewalker/tree")):"function"==typeof define&&define.amd?define(["exports","@statewalker/tree"],t):t(((e="undefined"!=typeof globalThis?globalThis:e||self).statewalker=e.statewalker||{},e.statewalker.fsm=e.statewalker.fsm||{}),e.statewalker.tree)}(this,(function(e,t){"use strict";function n(e={}){const{key:t,transitions:s=[],states:r={},options:o,...c}=e,i={key:t,transitions:{},states:{},options:Object.assign(o||{},c)};for(const e of s){let t,n,s;if(Array.isArray(e))t=e[0],n=e[1],s=e[2];else{const{from:r,event:o,to:c}=e;t=r,n=o,s=c}(i.transitions[t]=i.transitions[t]||{})[n]=s}if(Array.isArray(r))for(const e of r)i.states[e.key]=n(e);else if(r)for(const e of Object.keys(r))i.states[e]=n(r[e]);return i}var s={STATE_ANY:"*",STATE_INITIAL:"",STATE_FINAL:"",EVENT_ANY:"*",EVENT_EMPTY:""};function r(e,t){let n;for(let s=e.stack.length-1;!n&&s>=0;s--){n=(e.stack[s].descriptor.states||{})[t]}return n||{transitions:{},states:{}}}function o(e,t,n){const r=[[t,n],[s.STATE_ANY,n],[t,s.EVENT_ANY],[s.STATE_ANY,s.EVENT_ANY]];let o;for(let t=0,n=r.length;void 0===o&&t<n;t++){const[n,c]=r[t],i=e.transitions[n];i&&(o=i[c],void 0===o&&(o=i[s.EVENT_ANY]))}return void 0!==o?o:s.STATE_FINAL}function c({config:e,descriptor:c,newState:i=(e=>e),newProcess:a=(e=>({descriptor:e,status:0,stack:[],event:void 0,current:void 0}))}){const f=a(c=c||n(e));return[f,()=>{let e,n;if(f.status)if(f.stack.length){const c=f.event.key||s.EVENT_EMPTY;e=o(f.stack[f.stack.length-1].descriptor,f.status&t.MODE.ENTER?s.STATE_INITIAL:f.current?f.current.key:s.STATE_FINAL,c),e&&(n=r(f,e))}else e=s.STATE_FINAL;else n=f.descriptor,e=n.key;return e?i({process:f,key:e,descriptor:n}):null}]}e.KEYS=s,e.buildStateDescriptor=n,e.checkProcessDescriptor=function(e){return function e(t,n=[],r=[]){r=[...r,t.key];const o=Object.assign({key:t.key},function(e){const t={},n={};for(const[s,r]of Object.entries(e.transitions)){t[s]=(t[s]||0)+1;for(const e of Object.values(r))n[e]=(n[e]||0)+1}const r=[],o=[];for(const e of Object.keys(t))e===s.STATE_ANY||e===s.STATE_FINAL||e===s.STATE_INITIAL||e in n||r.push(e);for(const e of Object.keys(n))e===s.STATE_FINAL||e in t||o.push(e);return{unreachableStates:r,deadendStates:o}}(t));if(o.deadendStates.length||o.unreachableStates.length){const e={path:r};n.push(e),o.deadendStates.length&&(e.deadendStates=o.deadendStates),o.unreachableStates.length&&(e.unreachableStates=o.unreachableStates)}for(const s of Object.values(t.states))e(s,n,r);return n}(e)},e.getAllStateKeys=function(e){const t={},n=e=>t[e]=(t[e]||0)+1;return function e(t){n(t.key);for(const[e,s]of Object.entries(t.transitions)){n(e);for(const e of Object.values(s))n(e)}for(const[s,r]of Object.entries(t.states))n(s),e(r)}(e),Object.keys(t).sort()},e.getAllTransitions=function(e){const t=[];let n=e.current?e.current.key:s.STATE_INITIAL;for(let r=e.stack.length-1;r>=0;r--){const o=e.stack[r],c=o.key,i=o.descriptor;for(const e of[n,s.STATE_ANY]){const n=i.transitions[e];if(n)for(const[s,r]of Object.entries(n))t.push([c,e,s,r])}n=c}return t},e.getStateDescriptor=r,e.getTargetStateKey=o,e.newAsyncProcess=function({config:e,descriptor:n,before:s,after:r,newProcess:o,newState:i,handleError:a=console.error}){const[f,u]=c({config:e,descriptor:n,newProcess:o,newState:i}),l=t.newAsyncTreeWalker(s,r,f);return f.finished=!1,f.next=e=>(f.nextEvent=e,f.running=f.running||Promise.resolve().then((async()=>{try{for(f.event=f.nextEvent,f.nextEvent=void 0;!f.finished&&f.event;)if(f.finished=!await l(u),f.status&t.MODE.EXIT&&f.nextEvent)f.event=f.nextEvent,f.nextEvent=void 0;else if(f.status&t.MODE.LEAF)break}catch(e){a(e)}})).finally((()=>f.running=void 0)).then((()=>!f.finished))),f},e.newProcessInstance=c,e.newSyncProcess=function({config:e,descriptor:n,before:s,after:r,newProcess:o,newState:i}){const[a,f]=c({config:e,descriptor:n,newProcess:o,newState:i}),u=t.newTreeWalker(s,r,a);return a.dispatch=a.next=e=>{for("string"==typeof e&&(e={key:e}),a.event=e;a.event;){if(!u(f))return!1;if(a.status&t.MODE.LEAF)return!0}},a},Object.keys(t).forEach((function(n){"default"===n||e.hasOwnProperty(n)||Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[n]}})})),Object.defineProperty(e,"__esModule",{value:!0})}));
|
|
@@ -1,59 +1,6 @@
|
|
|
1
|
-
// @statewalker/fsm v0.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
FIRST: 1, // old=true; new=true => ENTER + ENTER
|
|
5
|
-
NEXT: 2, // old=false; new=true => EXIT + ENTER
|
|
6
|
-
LEAF : 4, // old=true; new=false => ENTER + EXIT
|
|
7
|
-
LAST : 8, // old=false; new=false => EXIT + EXIT
|
|
8
|
-
|
|
9
|
-
ENTER: 1 | 2, // MODE.FIRST | MODE.NEXT
|
|
10
|
-
EXIT : 4 | 8 // MODE.LEAF | MODE.LAST
|
|
11
|
-
};
|
|
12
|
-
var MODE$1 = MODE;
|
|
13
|
-
|
|
14
|
-
function newTreeWalker(
|
|
15
|
-
before, after,
|
|
16
|
-
context = { stack: [], status: MODE$1.NONE }
|
|
17
|
-
) {
|
|
18
|
-
return (getNode) => {
|
|
19
|
-
let status = context.status;
|
|
20
|
-
const prev = status & MODE$1.EXIT;
|
|
21
|
-
if (prev) after(context);
|
|
22
|
-
if (status & MODE$1.ENTER) context.stack.push(context.current);
|
|
23
|
-
let node = getNode(context);
|
|
24
|
-
if (node) {
|
|
25
|
-
context.current = node;
|
|
26
|
-
status = context.status = prev ? MODE$1.NEXT : MODE$1.FIRST;
|
|
27
|
-
before(context);
|
|
28
|
-
} else {
|
|
29
|
-
node = context.current = context.stack.pop();
|
|
30
|
-
status = context.status = node ? prev ? MODE$1.LAST : MODE$1.LEAF : MODE$1.NONE;
|
|
31
|
-
}
|
|
32
|
-
return status !== MODE$1.NONE;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function newAsyncTreeWalker(
|
|
37
|
-
before, after,
|
|
38
|
-
context = { stack: [], status: MODE$1.NONE }
|
|
39
|
-
) {
|
|
40
|
-
return async (getNode) => {
|
|
41
|
-
let status = context.status;
|
|
42
|
-
const prev = status & MODE$1.EXIT;
|
|
43
|
-
if (prev) await after(context);
|
|
44
|
-
if (status & MODE$1.ENTER) await context.stack.push(context.current);
|
|
45
|
-
let node = await getNode(context);
|
|
46
|
-
if (node) {
|
|
47
|
-
context.current = node;
|
|
48
|
-
status = context.status = prev ? MODE$1.NEXT : MODE$1.FIRST;
|
|
49
|
-
await before(context);
|
|
50
|
-
} else {
|
|
51
|
-
node = context.current = await context.stack.pop();
|
|
52
|
-
status = context.status = node ? prev ? MODE$1.LAST : MODE$1.LEAF : MODE$1.NONE;
|
|
53
|
-
}
|
|
54
|
-
return status !== MODE$1.NONE;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
1
|
+
// @statewalker/fsm v0.10.1 https://github.com/statewalker/statewalker-tree Copyright 2022 Mikhail Kotelnikov
|
|
2
|
+
import { MODE, newAsyncTreeWalker, newTreeWalker } from '@statewalker/tree';
|
|
3
|
+
export * from '@statewalker/tree';
|
|
57
4
|
|
|
58
5
|
function buildStateDescriptor(config = {}) {
|
|
59
6
|
const { key, transitions = [], states = {}, options, ...params } = config;
|
|
@@ -263,7 +210,7 @@ function newProcessInstance({
|
|
|
263
210
|
} else {
|
|
264
211
|
const eventKey = process.event.key || KEYS.EVENT_EMPTY;
|
|
265
212
|
const parentDescriptor = process.stack[process.stack.length - 1].descriptor;
|
|
266
|
-
const stateKey = process.status & MODE
|
|
213
|
+
const stateKey = process.status & MODE.ENTER
|
|
267
214
|
? KEYS.STATE_INITIAL
|
|
268
215
|
: process.current ? process.current.key : KEYS.STATE_FINAL;
|
|
269
216
|
key = getTargetStateKey(parentDescriptor, stateKey, eventKey);
|
|
@@ -293,38 +240,36 @@ function newAsyncProcess({
|
|
|
293
240
|
});
|
|
294
241
|
const shift = newAsyncTreeWalker(before, after, process);
|
|
295
242
|
process.finished = false;
|
|
296
|
-
process.
|
|
243
|
+
process.next = (event) => {
|
|
297
244
|
process.nextEvent = event;
|
|
298
|
-
process.running = process.running || Promise
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
process.
|
|
306
|
-
process.nextEvent
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
245
|
+
return process.running = process.running || Promise
|
|
246
|
+
.resolve()
|
|
247
|
+
.then(async () => {
|
|
248
|
+
try {
|
|
249
|
+
process.event = process.nextEvent;
|
|
250
|
+
process.nextEvent = undefined;
|
|
251
|
+
while (!process.finished && process.event) {
|
|
252
|
+
process.finished = !await shift(loadNextState);
|
|
253
|
+
if ((process.status & MODE.EXIT) && process.nextEvent) {
|
|
254
|
+
// Consume the next event if it exists.
|
|
255
|
+
process.event = process.nextEvent;
|
|
256
|
+
process.nextEvent = undefined;
|
|
257
|
+
} else if (process.status & MODE.LEAF) {
|
|
258
|
+
// Returns control when the process is in a "leaf" state (a state without children)
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
310
261
|
}
|
|
311
|
-
|
|
262
|
+
} catch (error) {
|
|
263
|
+
handleError(error);
|
|
312
264
|
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
}).finally(() => process.running = undefined);
|
|
317
|
-
};
|
|
318
|
-
|
|
319
|
-
process.next = async (event) => {
|
|
320
|
-
process.dispatch(event);
|
|
321
|
-
await process.running;
|
|
322
|
-
return !process.finished;
|
|
265
|
+
})
|
|
266
|
+
.finally(() => process.running = undefined)
|
|
267
|
+
.then(() => !process.finished);
|
|
323
268
|
};
|
|
324
269
|
return process;
|
|
325
270
|
}
|
|
326
271
|
|
|
327
|
-
function newSyncProcess({
|
|
272
|
+
function newSyncProcess({
|
|
328
273
|
config,
|
|
329
274
|
descriptor,
|
|
330
275
|
before, after,
|
|
@@ -338,14 +283,15 @@ function newSyncProcess({
|
|
|
338
283
|
newState,
|
|
339
284
|
});
|
|
340
285
|
const shift = newTreeWalker(before, after, process);
|
|
341
|
-
process.dispatch = process.next =(event) => {
|
|
286
|
+
process.dispatch = process.next = (event) => {
|
|
287
|
+
if (typeof event === 'string') event = { key : event };
|
|
342
288
|
process.event = event;
|
|
343
289
|
while (process.event) {
|
|
344
290
|
if (!shift(loadNextState)) return false;
|
|
345
|
-
if (process.status & MODE
|
|
291
|
+
if (process.status & MODE.LEAF) return true;
|
|
346
292
|
}
|
|
347
293
|
};
|
|
348
294
|
return process;
|
|
349
295
|
}
|
|
350
296
|
|
|
351
|
-
export { KEYS,
|
|
297
|
+
export { KEYS, buildStateDescriptor, checkProcessDescriptor, getAllStateKeys, getAllTransitions, getStateDescriptor, getTargetStateKey, newAsyncProcess, newProcessInstance, newSyncProcess };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @statewalker/fsm v0.10.1 https://github.com/statewalker/statewalker-tree Copyright 2022 Mikhail Kotelnikov
|
|
2
|
+
import{MODE as t,newAsyncTreeWalker as e,newTreeWalker as n}from"@statewalker/tree";export*from"@statewalker/tree";function s(t={}){const{key:e,transitions:n=[],states:r={},options:o,...c}=t,i={key:e,transitions:{},states:{},options:Object.assign(o||{},c)};for(const t of n){let e,n,s;if(Array.isArray(t))e=t[0],n=t[1],s=t[2];else{const{from:r,event:o,to:c}=t;e=r,n=o,s=c}(i.transitions[e]=i.transitions[e]||{})[n]=s}if(Array.isArray(r))for(const t of r)i.states[t.key]=s(t);else if(r)for(const t of Object.keys(r))i.states[t]=s(r[t]);return i}var r={STATE_ANY:"*",STATE_INITIAL:"",STATE_FINAL:"",EVENT_ANY:"*",EVENT_EMPTY:""};function o(t){return function t(e,n=[],s=[]){s=[...s,e.key];const o=Object.assign({key:e.key},function(t){const e={},n={};for(const[s,r]of Object.entries(t.transitions)){e[s]=(e[s]||0)+1;for(const t of Object.values(r))n[t]=(n[t]||0)+1}const s=[],o=[];for(const t of Object.keys(e))t===r.STATE_ANY||t===r.STATE_FINAL||t===r.STATE_INITIAL||t in n||s.push(t);for(const t of Object.keys(n))t===r.STATE_FINAL||t in e||o.push(t);return{unreachableStates:s,deadendStates:o}}(e));if(o.deadendStates.length||o.unreachableStates.length){const t={path:s};n.push(t),o.deadendStates.length&&(t.deadendStates=o.deadendStates),o.unreachableStates.length&&(t.unreachableStates=o.unreachableStates)}for(const r of Object.values(e.states))t(r,n,s);return n}(t)}function c(t,e){let n;for(let s=t.stack.length-1;!n&&s>=0;s--){n=(t.stack[s].descriptor.states||{})[e]}return n||{transitions:{},states:{}}}function i(t){const e={},n=t=>e[t]=(e[t]||0)+1;return function t(e){n(e.key);for(const[t,s]of Object.entries(e.transitions)){n(t);for(const t of Object.values(s))n(t)}for(const[s,r]of Object.entries(e.states))n(s),t(r)}(t),Object.keys(e).sort()}function a(t){const e=[];let n=t.current?t.current.key:r.STATE_INITIAL;for(let s=t.stack.length-1;s>=0;s--){const o=t.stack[s],c=o.key,i=o.descriptor;for(const t of[n,r.STATE_ANY]){const n=i.transitions[t];if(n)for(const[s,r]of Object.entries(n))e.push([c,t,s,r])}n=c}return e}function f(t,e,n){const s=[[e,n],[r.STATE_ANY,n],[e,r.EVENT_ANY],[r.STATE_ANY,r.EVENT_ANY]];let o;for(let e=0,n=s.length;void 0===o&&e<n;e++){const[n,c]=s[e],i=t.transitions[n];i&&(o=i[c],void 0===o&&(o=i[r.EVENT_ANY]))}return void 0!==o?o:r.STATE_FINAL}function u({config:e,descriptor:n,newState:o=(t=>t),newProcess:i=(t=>({descriptor:t,status:0,stack:[],event:void 0,current:void 0}))}){const a=i(n=n||s(e));return[a,()=>{let e,n;if(a.status)if(a.stack.length){const s=a.event.key||r.EVENT_EMPTY;e=f(a.stack[a.stack.length-1].descriptor,a.status&t.ENTER?r.STATE_INITIAL:a.current?a.current.key:r.STATE_FINAL,s),e&&(n=c(a,e))}else e=r.STATE_FINAL;else n=a.descriptor,e=n.key;return e?o({process:a,key:e,descriptor:n}):null}]}function T({config:n,descriptor:s,before:r,after:o,newProcess:c,newState:i,handleError:a=console.error}){const[f,T]=u({config:n,descriptor:s,newProcess:c,newState:i}),E=e(r,o,f);return f.finished=!1,f.next=e=>(f.nextEvent=e,f.running=f.running||Promise.resolve().then((async()=>{try{for(f.event=f.nextEvent,f.nextEvent=void 0;!f.finished&&f.event;)if(f.finished=!await E(T),f.status&t.EXIT&&f.nextEvent)f.event=f.nextEvent,f.nextEvent=void 0;else if(f.status&t.LEAF)break}catch(t){a(t)}})).finally((()=>f.running=void 0)).then((()=>!f.finished))),f}function E({config:e,descriptor:s,before:r,after:o,newProcess:c,newState:i}){const[a,f]=u({config:e,descriptor:s,newProcess:c,newState:i}),T=n(r,o,a);return a.dispatch=a.next=e=>{for("string"==typeof e&&(e={key:e}),a.event=e;a.event;){if(!T(f))return!1;if(a.status&t.LEAF)return!0}},a}export{r as KEYS,s as buildStateDescriptor,o as checkProcessDescriptor,i as getAllStateKeys,a as getAllTransitions,c as getStateDescriptor,f as getTargetStateKey,T as newAsyncProcess,u as newProcessInstance,E as newSyncProcess};
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statewalker/fsm",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.10.1",
|
|
4
|
+
"description": "HFSM Implementation",
|
|
5
5
|
"keywords": [],
|
|
6
|
-
"homepage": "https://github.com/statewalker/statewalker",
|
|
6
|
+
"homepage": "https://github.com/statewalker/statewalker-tree",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Mikhail Kotelnikov",
|
|
9
9
|
"email": "mikhail.kotelnikov@gmail.com"
|
|
@@ -15,31 +15,31 @@
|
|
|
15
15
|
"src/**/*.js",
|
|
16
16
|
"index.js"
|
|
17
17
|
],
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@statewalker/tree": "0.10.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@statewalker/rollup": "^0.1.4",
|
|
23
|
+
"eslint": "^8",
|
|
24
|
+
"expect.js": "^0.3",
|
|
25
|
+
"mocha": "^10",
|
|
26
|
+
"rollup": "^2"
|
|
27
|
+
},
|
|
28
|
+
"module": "src/index.js",
|
|
22
29
|
"exports": {
|
|
23
|
-
"package.json": "./package.json",
|
|
24
|
-
"umd": "./dist/cjs/statewalker-fsm.min.js",
|
|
25
|
-
"require": "./dist/cjs/statewalker-fsm.js",
|
|
26
30
|
"import": "./src/index.js",
|
|
27
|
-
"
|
|
31
|
+
"umd": "./dist/index-umd.min.js",
|
|
32
|
+
"default": "./dist/index.js"
|
|
28
33
|
},
|
|
29
34
|
"repository": {
|
|
30
35
|
"type": "git",
|
|
31
|
-
"url": "
|
|
32
|
-
},
|
|
33
|
-
"devDependencies": {
|
|
34
|
-
"@statewalker/tree": "^0.9.1"
|
|
36
|
+
"url": "git@github.com:statewalker/statewalker-fsm.git"
|
|
35
37
|
},
|
|
36
38
|
"scripts": {
|
|
37
|
-
"eslint": "
|
|
38
|
-
"rollup": "
|
|
39
|
-
"test": "
|
|
40
|
-
"
|
|
41
|
-
"prepublishOnly": "rm -rf dist && yarn test && yarn rollup",
|
|
42
|
-
"postpublish": "zip -j dist/statewalker-fsm.zip -- ../../LICENSE README.md dist/*.js"
|
|
39
|
+
"eslint": "eslint src",
|
|
40
|
+
"rollup": "rollup -c",
|
|
41
|
+
"test": "mocha -R spec ./test/index.js && yarn eslint",
|
|
42
|
+
"prepublishOnly": "rm -rf dist && yarn test && yarn rollup"
|
|
43
43
|
},
|
|
44
44
|
"license": "MIT",
|
|
45
45
|
"sideEffects": false,
|
package/src/newAsyncProcess.js
CHANGED
|
@@ -17,33 +17,31 @@ export default function newAsyncProcess({
|
|
|
17
17
|
});
|
|
18
18
|
const shift = newAsyncTreeWalker(before, after, process);
|
|
19
19
|
process.finished = false;
|
|
20
|
-
process.
|
|
20
|
+
process.next = (event) => {
|
|
21
21
|
process.nextEvent = event;
|
|
22
|
-
process.running = process.running || Promise
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
process.
|
|
30
|
-
process.nextEvent
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
22
|
+
return process.running = process.running || Promise
|
|
23
|
+
.resolve()
|
|
24
|
+
.then(async () => {
|
|
25
|
+
try {
|
|
26
|
+
process.event = process.nextEvent;
|
|
27
|
+
process.nextEvent = undefined;
|
|
28
|
+
while (!process.finished && process.event) {
|
|
29
|
+
process.finished = !await shift(loadNextState);
|
|
30
|
+
if ((process.status & MODE.EXIT) && process.nextEvent) {
|
|
31
|
+
// Consume the next event if it exists.
|
|
32
|
+
process.event = process.nextEvent;
|
|
33
|
+
process.nextEvent = undefined;
|
|
34
|
+
} else if (process.status & MODE.LEAF) {
|
|
35
|
+
// Returns control when the process is in a "leaf" state (a state without children)
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
34
38
|
}
|
|
35
|
-
|
|
39
|
+
} catch (error) {
|
|
40
|
+
handleError(error);
|
|
36
41
|
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}).finally(() => process.running = undefined);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
process.next = async (event) => {
|
|
44
|
-
process.dispatch(event);
|
|
45
|
-
await process.running;
|
|
46
|
-
return !process.finished;
|
|
42
|
+
})
|
|
43
|
+
.finally(() => process.running = undefined)
|
|
44
|
+
.then(() => !process.finished);
|
|
47
45
|
}
|
|
48
46
|
return process;
|
|
49
47
|
}
|
package/src/newSyncProcess.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MODE, newTreeWalker } from "@statewalker/tree";
|
|
2
2
|
import newProcessInstance from "./newProcessInstance.js";
|
|
3
3
|
|
|
4
|
-
export default function newSyncProcess({
|
|
4
|
+
export default function newSyncProcess({
|
|
5
5
|
config,
|
|
6
6
|
descriptor,
|
|
7
7
|
before, after,
|
|
@@ -15,7 +15,8 @@ export default function newSyncProcess({
|
|
|
15
15
|
newState,
|
|
16
16
|
});
|
|
17
17
|
const shift = newTreeWalker(before, after, process);
|
|
18
|
-
process.dispatch = process.next =(event) => {
|
|
18
|
+
process.dispatch = process.next = (event) => {
|
|
19
|
+
if (typeof event === 'string') event = { key : event };
|
|
19
20
|
process.event = event;
|
|
20
21
|
while (process.event) {
|
|
21
22
|
if (!shift(loadNextState)) return false;
|
package/dist/cjs/package.json
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @statewalker/fsm v0.9.2 https://github.com/statewalker/statewalker Copyright 2022 Mikhail Kotelnikov
|
|
2
|
-
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(((t="undefined"!=typeof globalThis?globalThis:t||self).statewalker=t.statewalker||{},t.statewalker.fsm=t.statewalker.fsm||{}))}(this,(function(t){"use strict";var e={NONE:0,FIRST:1,NEXT:2,LEAF:4,LAST:8,ENTER:3,EXIT:12};function n(t,n,s={stack:[],status:e.NONE}){return r=>{let o=s.status;const c=o&e.EXIT;c&&n(s),o&e.ENTER&&s.stack.push(s.current);let a=r(s);return a?(s.current=a,o=s.status=c?e.NEXT:e.FIRST,t(s)):(a=s.current=s.stack.pop(),o=s.status=a?c?e.LAST:e.LEAF:e.NONE),o!==e.NONE}}function s(t,n,s={stack:[],status:e.NONE}){return async r=>{let o=s.status;const c=o&e.EXIT;c&&await n(s),o&e.ENTER&&await s.stack.push(s.current);let a=await r(s);return a?(s.current=a,o=s.status=c?e.NEXT:e.FIRST,await t(s)):(a=s.current=await s.stack.pop(),o=s.status=a?c?e.LAST:e.LEAF:e.NONE),o!==e.NONE}}function r(t={}){const{key:e,transitions:n=[],states:s={},options:o,...c}=t,a={key:e,transitions:{},states:{},options:Object.assign(o||{},c)};for(const t of n){let e,n,s;if(Array.isArray(t))e=t[0],n=t[1],s=t[2];else{const{from:r,event:o,to:c}=t;e=r,n=o,s=c}(a.transitions[e]=a.transitions[e]||{})[n]=s}if(Array.isArray(s))for(const t of s)a.states[t.key]=r(t);else if(s)for(const t of Object.keys(s))a.states[t]=r(s[t]);return a}var o={STATE_ANY:"*",STATE_INITIAL:"",STATE_FINAL:"",EVENT_ANY:"*",EVENT_EMPTY:""};function c(t,e){let n;for(let s=t.stack.length-1;!n&&s>=0;s--){n=(t.stack[s].descriptor.states||{})[e]}return n||{transitions:{},states:{}}}function a(t,e,n){const s=[[e,n],[o.STATE_ANY,n],[e,o.EVENT_ANY],[o.STATE_ANY,o.EVENT_ANY]];let r;for(let e=0,n=s.length;void 0===r&&e<n;e++){const[n,c]=s[e],a=t.transitions[n];a&&(r=a[c],void 0===r&&(r=a[o.EVENT_ANY]))}return void 0!==r?r:o.STATE_FINAL}function i({config:t,descriptor:n,newState:s=(t=>t),newProcess:i=(t=>({descriptor:t,status:0,stack:[],event:void 0,current:void 0}))}){const f=i(n=n||r(t));return[f,()=>{let t,n;if(f.status)if(f.stack.length){const s=f.event.key||o.EVENT_EMPTY;t=a(f.stack[f.stack.length-1].descriptor,f.status&e.ENTER?o.STATE_INITIAL:f.current?f.current.key:o.STATE_FINAL,s),t&&(n=c(f,t))}else t=o.STATE_FINAL;else n=f.descriptor,t=n.key;return t?s({process:f,key:t,descriptor:n}):null}]}t.KEYS=o,t.MODE=e,t.buildStateDescriptor=r,t.checkProcessDescriptor=function(t){return function t(e,n=[],s=[]){s=[...s,e.key];const r=Object.assign({key:e.key},function(t){const e={},n={};for(const[s,r]of Object.entries(t.transitions)){e[s]=(e[s]||0)+1;for(const t of Object.values(r))n[t]=(n[t]||0)+1}const s=[],r=[];for(const t of Object.keys(e))t===o.STATE_ANY||t===o.STATE_FINAL||t===o.STATE_INITIAL||t in n||s.push(t);for(const t of Object.keys(n))t===o.STATE_FINAL||t in e||r.push(t);return{unreachableStates:s,deadendStates:r}}(e));if(r.deadendStates.length||r.unreachableStates.length){const t={path:s};n.push(t),r.deadendStates.length&&(t.deadendStates=r.deadendStates),r.unreachableStates.length&&(t.unreachableStates=r.unreachableStates)}for(const r of Object.values(e.states))t(r,n,s);return n}(t)},t.getAllStateKeys=function(t){const e={},n=t=>e[t]=(e[t]||0)+1;return function t(e){n(e.key);for(const[t,s]of Object.entries(e.transitions)){n(t);for(const t of Object.values(s))n(t)}for(const[s,r]of Object.entries(e.states))n(s),t(r)}(t),Object.keys(e).sort()},t.getAllTransitions=function(t){const e=[];let n=t.current?t.current.key:o.STATE_INITIAL;for(let s=t.stack.length-1;s>=0;s--){const r=t.stack[s],c=r.key,a=r.descriptor;for(const t of[n,o.STATE_ANY]){const n=a.transitions[t];if(n)for(const[s,r]of Object.entries(n))e.push([c,t,s,r])}n=c}return e},t.getStateDescriptor=c,t.getTargetStateKey=a,t.newAsyncProcess=function({config:t,descriptor:n,before:r,after:o,newProcess:c,newState:a,handleError:f=console.error}){const[u,T]=i({config:t,descriptor:n,newProcess:c,newState:a}),E=s(r,o,u);return u.finished=!1,u.dispatch=t=>{u.nextEvent=t,u.running=u.running||Promise.resolve().then((async()=>{try{for(;!u.finished;){if(u.nextEvent)u.event=u.nextEvent,u.nextEvent=void 0;else if(u.status&e.LEAF)break;u.finished=!await E(T)}}catch(t){f(t)}})).finally((()=>u.running=void 0))},u.next=async t=>(u.dispatch(t),await u.running,!u.finished),u},t.newAsyncTreeWalker=s,t.newProcessInstance=i,t.newSyncProcess=function({config:t,descriptor:s,before:r,after:o,newProcess:c,newState:a}){const[f,u]=i({config:t,descriptor:s,newProcess:c,newState:a}),T=n(r,o,f);return f.dispatch=f.next=t=>{for(f.event=t;f.event;){if(!T(u))return!1;if(f.status&e.LEAF)return!0}},f},t.newTreeWalker=n,Object.defineProperty(t,"__esModule",{value:!0})}));
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
// @statewalker/fsm v0.9.2 https://github.com/statewalker/statewalker Copyright 2022 Mikhail Kotelnikov
|
|
2
|
-
var t={NONE:0,FIRST:1,NEXT:2,LEAF:4,LAST:8,ENTER:3,EXIT:12};function e(e,n,s={stack:[],status:t.NONE}){return r=>{let o=s.status;const c=o&t.EXIT;c&&n(s),o&t.ENTER&&s.stack.push(s.current);let a=r(s);return a?(s.current=a,o=s.status=c?t.NEXT:t.FIRST,e(s)):(a=s.current=s.stack.pop(),o=s.status=a?c?t.LAST:t.LEAF:t.NONE),o!==t.NONE}}function n(e,n,s={stack:[],status:t.NONE}){return async r=>{let o=s.status;const c=o&t.EXIT;c&&await n(s),o&t.ENTER&&await s.stack.push(s.current);let a=await r(s);return a?(s.current=a,o=s.status=c?t.NEXT:t.FIRST,await e(s)):(a=s.current=await s.stack.pop(),o=s.status=a?c?t.LAST:t.LEAF:t.NONE),o!==t.NONE}}function s(t={}){const{key:e,transitions:n=[],states:r={},options:o,...c}=t,a={key:e,transitions:{},states:{},options:Object.assign(o||{},c)};for(const t of n){let e,n,s;if(Array.isArray(t))e=t[0],n=t[1],s=t[2];else{const{from:r,event:o,to:c}=t;e=r,n=o,s=c}(a.transitions[e]=a.transitions[e]||{})[n]=s}if(Array.isArray(r))for(const t of r)a.states[t.key]=s(t);else if(r)for(const t of Object.keys(r))a.states[t]=s(r[t]);return a}var r={STATE_ANY:"*",STATE_INITIAL:"",STATE_FINAL:"",EVENT_ANY:"*",EVENT_EMPTY:""};function o(t){return function t(e,n=[],s=[]){s=[...s,e.key];const o=Object.assign({key:e.key},function(t){const e={},n={};for(const[s,r]of Object.entries(t.transitions)){e[s]=(e[s]||0)+1;for(const t of Object.values(r))n[t]=(n[t]||0)+1}const s=[],o=[];for(const t of Object.keys(e))t===r.STATE_ANY||t===r.STATE_FINAL||t===r.STATE_INITIAL||t in n||s.push(t);for(const t of Object.keys(n))t===r.STATE_FINAL||t in e||o.push(t);return{unreachableStates:s,deadendStates:o}}(e));if(o.deadendStates.length||o.unreachableStates.length){const t={path:s};n.push(t),o.deadendStates.length&&(t.deadendStates=o.deadendStates),o.unreachableStates.length&&(t.unreachableStates=o.unreachableStates)}for(const r of Object.values(e.states))t(r,n,s);return n}(t)}function c(t,e){let n;for(let s=t.stack.length-1;!n&&s>=0;s--){n=(t.stack[s].descriptor.states||{})[e]}return n||{transitions:{},states:{}}}function a(t){const e={},n=t=>e[t]=(e[t]||0)+1;return function t(e){n(e.key);for(const[t,s]of Object.entries(e.transitions)){n(t);for(const t of Object.values(s))n(t)}for(const[s,r]of Object.entries(e.states))n(s),t(r)}(t),Object.keys(e).sort()}function i(t){const e=[];let n=t.current?t.current.key:r.STATE_INITIAL;for(let s=t.stack.length-1;s>=0;s--){const o=t.stack[s],c=o.key,a=o.descriptor;for(const t of[n,r.STATE_ANY]){const n=a.transitions[t];if(n)for(const[s,r]of Object.entries(n))e.push([c,t,s,r])}n=c}return e}function u(t,e,n){const s=[[e,n],[r.STATE_ANY,n],[e,r.EVENT_ANY],[r.STATE_ANY,r.EVENT_ANY]];let o;for(let e=0,n=s.length;void 0===o&&e<n;e++){const[n,c]=s[e],a=t.transitions[n];a&&(o=a[c],void 0===o&&(o=a[r.EVENT_ANY]))}return void 0!==o?o:r.STATE_FINAL}function f({config:e,descriptor:n,newState:o=(t=>t),newProcess:a=(t=>({descriptor:t,status:0,stack:[],event:void 0,current:void 0}))}){const i=a(n=n||s(e));return[i,()=>{let e,n;if(i.status)if(i.stack.length){const s=i.event.key||r.EVENT_EMPTY;e=u(i.stack[i.stack.length-1].descriptor,i.status&t.ENTER?r.STATE_INITIAL:i.current?i.current.key:r.STATE_FINAL,s),e&&(n=c(i,e))}else e=r.STATE_FINAL;else n=i.descriptor,e=n.key;return e?o({process:i,key:e,descriptor:n}):null}]}function E({config:e,descriptor:s,before:r,after:o,newProcess:c,newState:a,handleError:i=console.error}){const[u,E]=f({config:e,descriptor:s,newProcess:c,newState:a}),T=n(r,o,u);return u.finished=!1,u.dispatch=e=>{u.nextEvent=e,u.running=u.running||Promise.resolve().then((async()=>{try{for(;!u.finished;){if(u.nextEvent)u.event=u.nextEvent,u.nextEvent=void 0;else if(u.status&t.LEAF)break;u.finished=!await T(E)}}catch(t){i(t)}})).finally((()=>u.running=void 0))},u.next=async t=>(u.dispatch(t),await u.running,!u.finished),u}function T({config:n,descriptor:s,before:r,after:o,newProcess:c,newState:a}){const[i,u]=f({config:n,descriptor:s,newProcess:c,newState:a}),E=e(r,o,i);return i.dispatch=i.next=e=>{for(i.event=e;i.event;){if(!E(u))return!1;if(i.status&t.LEAF)return!0}},i}export{r as KEYS,t as MODE,s as buildStateDescriptor,o as checkProcessDescriptor,a as getAllStateKeys,i as getAllTransitions,c as getStateDescriptor,u as getTargetStateKey,E as newAsyncProcess,n as newAsyncTreeWalker,f as newProcessInstance,T as newSyncProcess,e as newTreeWalker};
|