@statewalker/fsm 0.8.0 → 0.9.2
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/dist/cjs/statewalker-fsm.js +113 -85
- package/dist/cjs/statewalker-fsm.min.js +2 -2
- package/dist/esm/statewalker-fsm-esm.js +108 -84
- package/dist/esm/statewalker-fsm-esm.min.js +2 -2
- package/package.json +4 -6
- package/src/KEYS.js +5 -5
- package/src/checkProcessDescriptor.js +1 -1
- package/src/getAllTransitions.js +1 -1
- package/src/getStateDescriptor.js +8 -0
- package/src/getTargetStateKey.js +1 -1
- package/src/index.js +11 -9
- package/src/newAsyncProcess.js +31 -14
- package/src/newProcessInstance.js +9 -12
- package/src/newSyncProcess.js +3 -3
- package/LICENSE +0 -27
|
@@ -1,9 +1,65 @@
|
|
|
1
|
-
// @statewalker/fsm v0.
|
|
1
|
+
// @statewalker/fsm v0.9.2 https://github.com/statewalker/statewalker Copyright 2022 Mikhail Kotelnikov
|
|
2
2
|
(function (global, factory) {
|
|
3
3
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
4
4
|
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
5
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';
|
|
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
|
+
}
|
|
7
63
|
|
|
8
64
|
function buildStateDescriptor(config = {}) {
|
|
9
65
|
const { key, transitions = [], states = {}, options, ...params } = config;
|
|
@@ -41,11 +97,11 @@ function buildStateDescriptor(config = {}) {
|
|
|
41
97
|
}
|
|
42
98
|
|
|
43
99
|
var KEYS = {
|
|
44
|
-
STATE_ANY :
|
|
45
|
-
STATE_INITIAL :
|
|
46
|
-
STATE_FINAL :
|
|
47
|
-
EVENT_ANY :
|
|
48
|
-
EVENT_EMPTY :
|
|
100
|
+
STATE_ANY : "*",
|
|
101
|
+
STATE_INITIAL : "",
|
|
102
|
+
STATE_FINAL : "",
|
|
103
|
+
EVENT_ANY : "*",
|
|
104
|
+
EVENT_EMPTY : "",
|
|
49
105
|
};
|
|
50
106
|
|
|
51
107
|
function checkProcessDescriptor(descriptor) {
|
|
@@ -101,6 +157,15 @@ function checkProcessDescriptor(descriptor) {
|
|
|
101
157
|
}
|
|
102
158
|
}
|
|
103
159
|
|
|
160
|
+
function getStateDescriptor(process, stateKey) {
|
|
161
|
+
let descriptor;
|
|
162
|
+
for (let i = process.stack.length - 1; !descriptor && i >= 0; i--) {
|
|
163
|
+
const states = process.stack[i].descriptor.states || {};
|
|
164
|
+
descriptor = states[stateKey];
|
|
165
|
+
}
|
|
166
|
+
return descriptor || { transitions: {}, states: {} };
|
|
167
|
+
}
|
|
168
|
+
|
|
104
169
|
/**
|
|
105
170
|
* This method returns a list of all states used in
|
|
106
171
|
* the specified state descriptor.
|
|
@@ -179,60 +244,6 @@ function getTargetStateKey(descriptor, stateKey, eventKey) {
|
|
|
179
244
|
return (targetKey !== undefined) ? targetKey : KEYS.STATE_FINAL;
|
|
180
245
|
}
|
|
181
246
|
|
|
182
|
-
const MODE = {
|
|
183
|
-
NONE : 0,
|
|
184
|
-
LEAF : 1,
|
|
185
|
-
LAST : 2,
|
|
186
|
-
FIRST : 4,
|
|
187
|
-
NEXT : 8,
|
|
188
|
-
};
|
|
189
|
-
MODE.ENTER = MODE.FIRST | MODE.NEXT;
|
|
190
|
-
MODE.EXIT = MODE.LAST | MODE.LEAF;
|
|
191
|
-
|
|
192
|
-
function newTreeWalker(
|
|
193
|
-
before, after,
|
|
194
|
-
context = { stack: [], status: MODE.NONE }
|
|
195
|
-
) {
|
|
196
|
-
return (getNode) => {
|
|
197
|
-
let status = context.status;
|
|
198
|
-
const prev = status & MODE.EXIT;
|
|
199
|
-
if (prev) after(context);
|
|
200
|
-
if (status & MODE.ENTER) context.stack.push(context.current);
|
|
201
|
-
let node = getNode(context);
|
|
202
|
-
if (node) {
|
|
203
|
-
context.current = node;
|
|
204
|
-
status = context.status = prev ? MODE.NEXT : MODE.FIRST;
|
|
205
|
-
before(context);
|
|
206
|
-
} else {
|
|
207
|
-
node = context.current = context.stack.pop();
|
|
208
|
-
status = context.status = node ? prev ? MODE.LAST : MODE.LEAF : MODE.NONE;
|
|
209
|
-
}
|
|
210
|
-
return status !== MODE.NONE;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
function newAsyncTreeWalker(
|
|
215
|
-
before, after,
|
|
216
|
-
context = { stack: [], status: MODE.NONE }
|
|
217
|
-
) {
|
|
218
|
-
return async (getNode) => {
|
|
219
|
-
let status = context.status;
|
|
220
|
-
const prev = status & MODE.EXIT;
|
|
221
|
-
if (prev) await after(context);
|
|
222
|
-
if (status & MODE.ENTER) await context.stack.push(context.current);
|
|
223
|
-
let node = await getNode(context);
|
|
224
|
-
if (node) {
|
|
225
|
-
context.current = node;
|
|
226
|
-
status = context.status = prev ? MODE.NEXT : MODE.FIRST;
|
|
227
|
-
await before(context);
|
|
228
|
-
} else {
|
|
229
|
-
node = context.current = await context.stack.pop();
|
|
230
|
-
status = context.status = node ? prev ? MODE.LAST : MODE.LEAF : MODE.NONE;
|
|
231
|
-
}
|
|
232
|
-
return status !== MODE.NONE;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
247
|
function newProcessInstance({
|
|
237
248
|
config,
|
|
238
249
|
descriptor,
|
|
@@ -257,20 +268,16 @@ function newProcessInstance({
|
|
|
257
268
|
key = KEYS.STATE_FINAL;
|
|
258
269
|
} else {
|
|
259
270
|
const eventKey = process.event.key || KEYS.EVENT_EMPTY;
|
|
260
|
-
const
|
|
261
|
-
const stateKey = process.status & MODE.ENTER
|
|
271
|
+
const parentDescriptor = process.stack[process.stack.length - 1].descriptor;
|
|
272
|
+
const stateKey = process.status & MODE$1.ENTER
|
|
262
273
|
? KEYS.STATE_INITIAL
|
|
263
274
|
: process.current ? process.current.key : KEYS.STATE_FINAL;
|
|
264
|
-
key = getTargetStateKey(
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
for (let i = process.stack.length - 1; !descriptor && i >= 0; i--) {
|
|
268
|
-
const states = process.stack[i].descriptor.states || {};
|
|
269
|
-
descriptor = states[key];
|
|
275
|
+
key = getTargetStateKey(parentDescriptor, stateKey, eventKey);
|
|
276
|
+
if (key) {
|
|
277
|
+
descriptor = getStateDescriptor(process, key);
|
|
270
278
|
}
|
|
271
279
|
}
|
|
272
280
|
}
|
|
273
|
-
descriptor = descriptor || { transitions: {}, states: {} };
|
|
274
281
|
return key ? newState({ process, key, descriptor }) : null;
|
|
275
282
|
};
|
|
276
283
|
return [process, loadNextState];
|
|
@@ -282,26 +289,43 @@ function newAsyncProcess({
|
|
|
282
289
|
before, after,
|
|
283
290
|
newProcess,
|
|
284
291
|
newState,
|
|
292
|
+
handleError = console.error
|
|
285
293
|
}) {
|
|
286
294
|
const [process, loadNextState] = newProcessInstance({
|
|
287
295
|
config,
|
|
288
296
|
descriptor,
|
|
289
297
|
newProcess,
|
|
290
|
-
newState
|
|
298
|
+
newState
|
|
291
299
|
});
|
|
292
300
|
const shift = newAsyncTreeWalker(before, after, process);
|
|
301
|
+
process.finished = false;
|
|
302
|
+
process.dispatch = (event) => {
|
|
303
|
+
process.nextEvent = event;
|
|
304
|
+
process.running = process.running || Promise.resolve().then(async () => {
|
|
305
|
+
try {
|
|
306
|
+
while (!process.finished) {
|
|
307
|
+
// await Promise.resolve();
|
|
308
|
+
// console.log('XXX', process.nextEvent, process.running)
|
|
309
|
+
if (process.nextEvent) {
|
|
310
|
+
// Consume the next event if exists.
|
|
311
|
+
process.event = process.nextEvent;
|
|
312
|
+
process.nextEvent = undefined;
|
|
313
|
+
} else if (process.status & MODE$1.LEAF) {
|
|
314
|
+
// Returns control when the process is in a "leaf" state (a state without children)
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
process.finished = !await shift(loadNextState);
|
|
318
|
+
}
|
|
319
|
+
} catch (error) {
|
|
320
|
+
handleError(error);
|
|
321
|
+
}
|
|
322
|
+
}).finally(() => process.running = undefined);
|
|
323
|
+
};
|
|
324
|
+
|
|
293
325
|
process.next = async (event) => {
|
|
294
|
-
process.event
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
process.running = true;
|
|
298
|
-
while (process.event) {
|
|
299
|
-
if (!await shift(loadNextState)) return false;
|
|
300
|
-
if (process.status & MODE.LEAF) return true;
|
|
301
|
-
}
|
|
302
|
-
} finally {
|
|
303
|
-
process.running = false;
|
|
304
|
-
}
|
|
326
|
+
process.dispatch(event);
|
|
327
|
+
await process.running;
|
|
328
|
+
return !process.finished;
|
|
305
329
|
};
|
|
306
330
|
return process;
|
|
307
331
|
}
|
|
@@ -320,26 +344,30 @@ function newSyncProcess({
|
|
|
320
344
|
newState,
|
|
321
345
|
});
|
|
322
346
|
const shift = newTreeWalker(before, after, process);
|
|
323
|
-
process.next =
|
|
347
|
+
process.dispatch = process.next =(event) => {
|
|
324
348
|
process.event = event;
|
|
325
349
|
while (process.event) {
|
|
326
350
|
if (!shift(loadNextState)) return false;
|
|
327
|
-
if (process.status & MODE.LEAF) return true;
|
|
351
|
+
if (process.status & MODE$1.LEAF) return true;
|
|
328
352
|
}
|
|
329
353
|
};
|
|
330
354
|
return process;
|
|
331
355
|
}
|
|
332
356
|
|
|
333
357
|
exports.KEYS = KEYS;
|
|
358
|
+
exports.MODE = MODE$1;
|
|
334
359
|
exports.buildStateDescriptor = buildStateDescriptor;
|
|
335
360
|
exports.checkProcessDescriptor = checkProcessDescriptor;
|
|
336
361
|
exports.getAllStateKeys = getAllStateKeys;
|
|
337
362
|
exports.getAllTransitions = getAllTransitions;
|
|
363
|
+
exports.getStateDescriptor = getStateDescriptor;
|
|
338
364
|
exports.getTargetStateKey = getTargetStateKey;
|
|
339
365
|
exports.newAsyncProcess = newAsyncProcess;
|
|
366
|
+
exports.newAsyncTreeWalker = newAsyncTreeWalker;
|
|
340
367
|
exports.newProcessInstance = newProcessInstance;
|
|
341
368
|
exports.newSyncProcess = newSyncProcess;
|
|
369
|
+
exports.newTreeWalker = newTreeWalker;
|
|
342
370
|
|
|
343
371
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
344
372
|
|
|
345
|
-
}))
|
|
373
|
+
}));
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
// @statewalker/fsm v0.
|
|
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";function e(t={}){const{key:
|
|
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,4 +1,60 @@
|
|
|
1
|
-
// @statewalker/fsm v0.
|
|
1
|
+
// @statewalker/fsm v0.9.2 https://github.com/statewalker/statewalker Copyright 2022 Mikhail Kotelnikov
|
|
2
|
+
const MODE = {
|
|
3
|
+
NONE : 0,
|
|
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
|
+
}
|
|
57
|
+
|
|
2
58
|
function buildStateDescriptor(config = {}) {
|
|
3
59
|
const { key, transitions = [], states = {}, options, ...params } = config;
|
|
4
60
|
const result = {
|
|
@@ -35,11 +91,11 @@ function buildStateDescriptor(config = {}) {
|
|
|
35
91
|
}
|
|
36
92
|
|
|
37
93
|
var KEYS = {
|
|
38
|
-
STATE_ANY :
|
|
39
|
-
STATE_INITIAL :
|
|
40
|
-
STATE_FINAL :
|
|
41
|
-
EVENT_ANY :
|
|
42
|
-
EVENT_EMPTY :
|
|
94
|
+
STATE_ANY : "*",
|
|
95
|
+
STATE_INITIAL : "",
|
|
96
|
+
STATE_FINAL : "",
|
|
97
|
+
EVENT_ANY : "*",
|
|
98
|
+
EVENT_EMPTY : "",
|
|
43
99
|
};
|
|
44
100
|
|
|
45
101
|
function checkProcessDescriptor(descriptor) {
|
|
@@ -95,6 +151,15 @@ function checkProcessDescriptor(descriptor) {
|
|
|
95
151
|
}
|
|
96
152
|
}
|
|
97
153
|
|
|
154
|
+
function getStateDescriptor(process, stateKey) {
|
|
155
|
+
let descriptor;
|
|
156
|
+
for (let i = process.stack.length - 1; !descriptor && i >= 0; i--) {
|
|
157
|
+
const states = process.stack[i].descriptor.states || {};
|
|
158
|
+
descriptor = states[stateKey];
|
|
159
|
+
}
|
|
160
|
+
return descriptor || { transitions: {}, states: {} };
|
|
161
|
+
}
|
|
162
|
+
|
|
98
163
|
/**
|
|
99
164
|
* This method returns a list of all states used in
|
|
100
165
|
* the specified state descriptor.
|
|
@@ -173,60 +238,6 @@ function getTargetStateKey(descriptor, stateKey, eventKey) {
|
|
|
173
238
|
return (targetKey !== undefined) ? targetKey : KEYS.STATE_FINAL;
|
|
174
239
|
}
|
|
175
240
|
|
|
176
|
-
const MODE = {
|
|
177
|
-
NONE : 0,
|
|
178
|
-
LEAF : 1,
|
|
179
|
-
LAST : 2,
|
|
180
|
-
FIRST : 4,
|
|
181
|
-
NEXT : 8,
|
|
182
|
-
};
|
|
183
|
-
MODE.ENTER = MODE.FIRST | MODE.NEXT;
|
|
184
|
-
MODE.EXIT = MODE.LAST | MODE.LEAF;
|
|
185
|
-
|
|
186
|
-
function newTreeWalker(
|
|
187
|
-
before, after,
|
|
188
|
-
context = { stack: [], status: MODE.NONE }
|
|
189
|
-
) {
|
|
190
|
-
return (getNode) => {
|
|
191
|
-
let status = context.status;
|
|
192
|
-
const prev = status & MODE.EXIT;
|
|
193
|
-
if (prev) after(context);
|
|
194
|
-
if (status & MODE.ENTER) context.stack.push(context.current);
|
|
195
|
-
let node = getNode(context);
|
|
196
|
-
if (node) {
|
|
197
|
-
context.current = node;
|
|
198
|
-
status = context.status = prev ? MODE.NEXT : MODE.FIRST;
|
|
199
|
-
before(context);
|
|
200
|
-
} else {
|
|
201
|
-
node = context.current = context.stack.pop();
|
|
202
|
-
status = context.status = node ? prev ? MODE.LAST : MODE.LEAF : MODE.NONE;
|
|
203
|
-
}
|
|
204
|
-
return status !== MODE.NONE;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function newAsyncTreeWalker(
|
|
209
|
-
before, after,
|
|
210
|
-
context = { stack: [], status: MODE.NONE }
|
|
211
|
-
) {
|
|
212
|
-
return async (getNode) => {
|
|
213
|
-
let status = context.status;
|
|
214
|
-
const prev = status & MODE.EXIT;
|
|
215
|
-
if (prev) await after(context);
|
|
216
|
-
if (status & MODE.ENTER) await context.stack.push(context.current);
|
|
217
|
-
let node = await getNode(context);
|
|
218
|
-
if (node) {
|
|
219
|
-
context.current = node;
|
|
220
|
-
status = context.status = prev ? MODE.NEXT : MODE.FIRST;
|
|
221
|
-
await before(context);
|
|
222
|
-
} else {
|
|
223
|
-
node = context.current = await context.stack.pop();
|
|
224
|
-
status = context.status = node ? prev ? MODE.LAST : MODE.LEAF : MODE.NONE;
|
|
225
|
-
}
|
|
226
|
-
return status !== MODE.NONE;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
241
|
function newProcessInstance({
|
|
231
242
|
config,
|
|
232
243
|
descriptor,
|
|
@@ -251,20 +262,16 @@ function newProcessInstance({
|
|
|
251
262
|
key = KEYS.STATE_FINAL;
|
|
252
263
|
} else {
|
|
253
264
|
const eventKey = process.event.key || KEYS.EVENT_EMPTY;
|
|
254
|
-
const
|
|
255
|
-
const stateKey = process.status & MODE.ENTER
|
|
265
|
+
const parentDescriptor = process.stack[process.stack.length - 1].descriptor;
|
|
266
|
+
const stateKey = process.status & MODE$1.ENTER
|
|
256
267
|
? KEYS.STATE_INITIAL
|
|
257
268
|
: process.current ? process.current.key : KEYS.STATE_FINAL;
|
|
258
|
-
key = getTargetStateKey(
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
for (let i = process.stack.length - 1; !descriptor && i >= 0; i--) {
|
|
262
|
-
const states = process.stack[i].descriptor.states || {};
|
|
263
|
-
descriptor = states[key];
|
|
269
|
+
key = getTargetStateKey(parentDescriptor, stateKey, eventKey);
|
|
270
|
+
if (key) {
|
|
271
|
+
descriptor = getStateDescriptor(process, key);
|
|
264
272
|
}
|
|
265
273
|
}
|
|
266
274
|
}
|
|
267
|
-
descriptor = descriptor || { transitions: {}, states: {} };
|
|
268
275
|
return key ? newState({ process, key, descriptor }) : null;
|
|
269
276
|
};
|
|
270
277
|
return [process, loadNextState];
|
|
@@ -276,26 +283,43 @@ function newAsyncProcess({
|
|
|
276
283
|
before, after,
|
|
277
284
|
newProcess,
|
|
278
285
|
newState,
|
|
286
|
+
handleError = console.error
|
|
279
287
|
}) {
|
|
280
288
|
const [process, loadNextState] = newProcessInstance({
|
|
281
289
|
config,
|
|
282
290
|
descriptor,
|
|
283
291
|
newProcess,
|
|
284
|
-
newState
|
|
292
|
+
newState
|
|
285
293
|
});
|
|
286
294
|
const shift = newAsyncTreeWalker(before, after, process);
|
|
295
|
+
process.finished = false;
|
|
296
|
+
process.dispatch = (event) => {
|
|
297
|
+
process.nextEvent = event;
|
|
298
|
+
process.running = process.running || Promise.resolve().then(async () => {
|
|
299
|
+
try {
|
|
300
|
+
while (!process.finished) {
|
|
301
|
+
// await Promise.resolve();
|
|
302
|
+
// console.log('XXX', process.nextEvent, process.running)
|
|
303
|
+
if (process.nextEvent) {
|
|
304
|
+
// Consume the next event if exists.
|
|
305
|
+
process.event = process.nextEvent;
|
|
306
|
+
process.nextEvent = undefined;
|
|
307
|
+
} else if (process.status & MODE$1.LEAF) {
|
|
308
|
+
// Returns control when the process is in a "leaf" state (a state without children)
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
process.finished = !await shift(loadNextState);
|
|
312
|
+
}
|
|
313
|
+
} catch (error) {
|
|
314
|
+
handleError(error);
|
|
315
|
+
}
|
|
316
|
+
}).finally(() => process.running = undefined);
|
|
317
|
+
};
|
|
318
|
+
|
|
287
319
|
process.next = async (event) => {
|
|
288
|
-
process.event
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
process.running = true;
|
|
292
|
-
while (process.event) {
|
|
293
|
-
if (!await shift(loadNextState)) return false;
|
|
294
|
-
if (process.status & MODE.LEAF) return true;
|
|
295
|
-
}
|
|
296
|
-
} finally {
|
|
297
|
-
process.running = false;
|
|
298
|
-
}
|
|
320
|
+
process.dispatch(event);
|
|
321
|
+
await process.running;
|
|
322
|
+
return !process.finished;
|
|
299
323
|
};
|
|
300
324
|
return process;
|
|
301
325
|
}
|
|
@@ -314,14 +338,14 @@ function newSyncProcess({
|
|
|
314
338
|
newState,
|
|
315
339
|
});
|
|
316
340
|
const shift = newTreeWalker(before, after, process);
|
|
317
|
-
process.next =
|
|
341
|
+
process.dispatch = process.next =(event) => {
|
|
318
342
|
process.event = event;
|
|
319
343
|
while (process.event) {
|
|
320
344
|
if (!shift(loadNextState)) return false;
|
|
321
|
-
if (process.status & MODE.LEAF) return true;
|
|
345
|
+
if (process.status & MODE$1.LEAF) return true;
|
|
322
346
|
}
|
|
323
347
|
};
|
|
324
348
|
return process;
|
|
325
349
|
}
|
|
326
350
|
|
|
327
|
-
export { KEYS, buildStateDescriptor, checkProcessDescriptor, getAllStateKeys, getAllTransitions, getTargetStateKey, newAsyncProcess, newProcessInstance, newSyncProcess };
|
|
351
|
+
export { KEYS, MODE$1 as MODE, buildStateDescriptor, checkProcessDescriptor, getAllStateKeys, getAllTransitions, getStateDescriptor, getTargetStateKey, newAsyncProcess, newAsyncTreeWalker, newProcessInstance, newSyncProcess, newTreeWalker };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
// @statewalker/fsm v0.
|
|
2
|
-
function t(e={}){const{key:
|
|
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};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statewalker/fsm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "Utility graph methods (iterators, tree builders etc)",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"homepage": "https://github.com/statewalker/statewalker",
|
|
@@ -31,21 +31,19 @@
|
|
|
31
31
|
"url": "https://github.com/statewalker/statewalker.git"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@statewalker/tree": "^0.
|
|
34
|
+
"@statewalker/tree": "^0.9.1"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"eslint": "../../node_modules/eslint/bin/eslint.js src",
|
|
38
38
|
"rollup": "../../node_modules/rollup/dist/bin/rollup -c",
|
|
39
39
|
"test": "../../node_modules/mocha/bin/mocha -R spec ./test/index.js && yarn eslint",
|
|
40
|
-
"pretest": "yarn rollup",
|
|
41
40
|
"prepare": "yarn rollup",
|
|
42
|
-
"prepublishOnly": "rm -rf dist && yarn test",
|
|
41
|
+
"prepublishOnly": "rm -rf dist && yarn test && yarn rollup",
|
|
43
42
|
"postpublish": "zip -j dist/statewalker-fsm.zip -- ../../LICENSE README.md dist/*.js"
|
|
44
43
|
},
|
|
45
44
|
"license": "MIT",
|
|
46
45
|
"sideEffects": false,
|
|
47
46
|
"publishConfig": {
|
|
48
47
|
"access": "public"
|
|
49
|
-
}
|
|
50
|
-
"gitHead": "bd8ef5bbb5f0d6b7fc06941ec737a36fa85d69c0"
|
|
48
|
+
}
|
|
51
49
|
}
|
package/src/KEYS.js
CHANGED
package/src/getAllTransitions.js
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export default function getStateDescriptor(process, stateKey) {
|
|
2
|
+
let descriptor;
|
|
3
|
+
for (let i = process.stack.length - 1; !descriptor && i >= 0; i--) {
|
|
4
|
+
const states = process.stack[i].descriptor.states || {};
|
|
5
|
+
descriptor = states[stateKey];
|
|
6
|
+
}
|
|
7
|
+
return descriptor || { transitions: {}, states: {} };
|
|
8
|
+
}
|
package/src/getTargetStateKey.js
CHANGED
package/src/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
export
|
|
2
|
-
export { default as
|
|
3
|
-
export { default as
|
|
4
|
-
export { default as
|
|
5
|
-
export { default as
|
|
6
|
-
export { default as
|
|
7
|
-
export { default as
|
|
8
|
-
export { default as
|
|
9
|
-
export { default as
|
|
1
|
+
export * from "@statewalker/tree";
|
|
2
|
+
export { default as buildStateDescriptor } from "./buildStateDescriptor.js";
|
|
3
|
+
export { default as checkProcessDescriptor } from "./checkProcessDescriptor.js";
|
|
4
|
+
export { default as getStateDescriptor } from "./getStateDescriptor.js";
|
|
5
|
+
export { default as getAllStateKeys } from "./getAllStateKeys.js";
|
|
6
|
+
export { default as getAllTransitions } from "./getAllTransitions.js";
|
|
7
|
+
export { default as getTargetStateKey } from "./getTargetStateKey.js";
|
|
8
|
+
export { default as KEYS } from "./KEYS.js";
|
|
9
|
+
export { default as newAsyncProcess } from "./newAsyncProcess.js";
|
|
10
|
+
export { default as newProcessInstance } from "./newProcessInstance.js";
|
|
11
|
+
export { default as newSyncProcess } from "./newSyncProcess.js";
|
package/src/newAsyncProcess.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { MODE, newAsyncTreeWalker } from
|
|
2
|
-
import newProcessInstance from
|
|
1
|
+
import { MODE, newAsyncTreeWalker } from "@statewalker/tree";
|
|
2
|
+
import newProcessInstance from "./newProcessInstance.js";
|
|
3
3
|
|
|
4
4
|
export default function newAsyncProcess({
|
|
5
5
|
config,
|
|
@@ -7,26 +7,43 @@ export default function newAsyncProcess({
|
|
|
7
7
|
before, after,
|
|
8
8
|
newProcess,
|
|
9
9
|
newState,
|
|
10
|
+
handleError = console.error
|
|
10
11
|
}) {
|
|
11
12
|
const [process, loadNextState] = newProcessInstance({
|
|
12
13
|
config,
|
|
13
14
|
descriptor,
|
|
14
15
|
newProcess,
|
|
15
|
-
newState
|
|
16
|
+
newState
|
|
16
17
|
});
|
|
17
18
|
const shift = newAsyncTreeWalker(before, after, process);
|
|
19
|
+
process.finished = false;
|
|
20
|
+
process.dispatch = (event) => {
|
|
21
|
+
process.nextEvent = event;
|
|
22
|
+
process.running = process.running || Promise.resolve().then(async () => {
|
|
23
|
+
try {
|
|
24
|
+
while (!process.finished) {
|
|
25
|
+
// await Promise.resolve();
|
|
26
|
+
// console.log('XXX', process.nextEvent, process.running)
|
|
27
|
+
if (process.nextEvent) {
|
|
28
|
+
// Consume the next event if exists.
|
|
29
|
+
process.event = process.nextEvent;
|
|
30
|
+
process.nextEvent = undefined;
|
|
31
|
+
} else if (process.status & MODE.LEAF) {
|
|
32
|
+
// Returns control when the process is in a "leaf" state (a state without children)
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
process.finished = !await shift(loadNextState);
|
|
36
|
+
}
|
|
37
|
+
} catch (error) {
|
|
38
|
+
handleError(error);
|
|
39
|
+
}
|
|
40
|
+
}).finally(() => process.running = undefined);
|
|
41
|
+
}
|
|
42
|
+
|
|
18
43
|
process.next = async (event) => {
|
|
19
|
-
process.event
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
process.running = true;
|
|
23
|
-
while (process.event) {
|
|
24
|
-
if (!await shift(loadNextState)) return false;
|
|
25
|
-
if (process.status & MODE.LEAF) return true;
|
|
26
|
-
}
|
|
27
|
-
} finally {
|
|
28
|
-
process.running = false;
|
|
29
|
-
}
|
|
44
|
+
process.dispatch(event);
|
|
45
|
+
await process.running;
|
|
46
|
+
return !process.finished;
|
|
30
47
|
}
|
|
31
48
|
return process;
|
|
32
49
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { MODE } from
|
|
2
|
-
import buildStateDescriptor from
|
|
3
|
-
import getTargetStateKey from
|
|
4
|
-
import
|
|
1
|
+
import { MODE } from "@statewalker/tree";
|
|
2
|
+
import buildStateDescriptor from "./buildStateDescriptor.js";
|
|
3
|
+
import getTargetStateKey from "./getTargetStateKey.js";
|
|
4
|
+
import getStateDescriptor from "./getStateDescriptor.js";
|
|
5
|
+
import KEYS from "./KEYS.js";
|
|
5
6
|
|
|
6
7
|
export default function newProcessInstance({
|
|
7
8
|
config,
|
|
@@ -27,20 +28,16 @@ export default function newProcessInstance({
|
|
|
27
28
|
key = KEYS.STATE_FINAL;
|
|
28
29
|
} else {
|
|
29
30
|
const eventKey = process.event.key || KEYS.EVENT_EMPTY;
|
|
30
|
-
const
|
|
31
|
+
const parentDescriptor = process.stack[process.stack.length - 1].descriptor;
|
|
31
32
|
const stateKey = process.status & MODE.ENTER
|
|
32
33
|
? KEYS.STATE_INITIAL
|
|
33
34
|
: process.current ? process.current.key : KEYS.STATE_FINAL;
|
|
34
|
-
key = getTargetStateKey(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
for (let i = process.stack.length - 1; !descriptor && i >= 0; i--) {
|
|
38
|
-
const states = process.stack[i].descriptor.states || {};
|
|
39
|
-
descriptor = states[key];
|
|
35
|
+
key = getTargetStateKey(parentDescriptor, stateKey, eventKey);
|
|
36
|
+
if (key) {
|
|
37
|
+
descriptor = getStateDescriptor(process, key);
|
|
40
38
|
}
|
|
41
39
|
}
|
|
42
40
|
}
|
|
43
|
-
descriptor = descriptor || { transitions: {}, states: {} };
|
|
44
41
|
return key ? newState({ process, key, descriptor }) : null;
|
|
45
42
|
};
|
|
46
43
|
return [process, loadNextState];
|
package/src/newSyncProcess.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { MODE, newTreeWalker } from
|
|
2
|
-
import newProcessInstance from
|
|
1
|
+
import { MODE, newTreeWalker } from "@statewalker/tree";
|
|
2
|
+
import newProcessInstance from "./newProcessInstance.js";
|
|
3
3
|
|
|
4
4
|
export default function newSyncProcess({
|
|
5
5
|
config,
|
|
@@ -15,7 +15,7 @@ export default function newSyncProcess({
|
|
|
15
15
|
newState,
|
|
16
16
|
});
|
|
17
17
|
const shift = newTreeWalker(before, after, process);
|
|
18
|
-
process.next =
|
|
18
|
+
process.dispatch = process.next =(event) => {
|
|
19
19
|
process.event = event;
|
|
20
20
|
while (process.event) {
|
|
21
21
|
if (!shift(loadNextState)) return false;
|
package/LICENSE
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
Copyright 2010-2020 Mikhail Kotelnikov
|
|
2
|
-
All rights reserved.
|
|
3
|
-
|
|
4
|
-
Redistribution and use in source and binary forms, with or without modification,
|
|
5
|
-
are permitted provided that the following conditions are met:
|
|
6
|
-
|
|
7
|
-
* Redistributions of source code must retain the above copyright notice, this
|
|
8
|
-
list of conditions and the following disclaimer.
|
|
9
|
-
|
|
10
|
-
* Redistributions in binary form must reproduce the above copyright notice,
|
|
11
|
-
this list of conditions and the following disclaimer in the documentation
|
|
12
|
-
and/or other materials provided with the distribution.
|
|
13
|
-
|
|
14
|
-
* Neither the name of the author nor the names of contributors may be used to
|
|
15
|
-
endorse or promote products derived from this software without specific prior
|
|
16
|
-
written permission.
|
|
17
|
-
|
|
18
|
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
19
|
-
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
20
|
-
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
21
|
-
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
22
|
-
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
23
|
-
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
24
|
-
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
25
|
-
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
26
|
-
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
27
|
-
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|