@statewalker/fsm 0.10.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index-umd.js +94 -40
- package/dist/index-umd.min.js +2 -2
- package/dist/index.js +94 -35
- package/dist/index.min.js +2 -2
- package/package.json +1 -1
- package/src/index.js +2 -3
- package/src/initAsyncProcess.js +61 -0
package/dist/index-umd.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @statewalker/fsm v0.
|
|
1
|
+
// @statewalker/fsm v0.13.0 https://github.com/statewalker/statewalker-tree Copyright 2022 Mikhail Kotelnikov
|
|
2
2
|
(function (global, factory) {
|
|
3
3
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@statewalker/tree')) :
|
|
4
4
|
typeof define === 'function' && define.amd ? define(['exports', '@statewalker/tree'], factory) :
|
|
@@ -138,38 +138,6 @@ function getAllStateKeys(descriptor) {
|
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
/**
|
|
142
|
-
* Returns all possible transitions from the current state of the process.
|
|
143
|
-
* @param {Object} options - method parameters
|
|
144
|
-
* @param {Process} options.process - the current process for which
|
|
145
|
-
* all transitions should be returned
|
|
146
|
-
* @returns {Array<Object>} - an array of all transitions;
|
|
147
|
-
* each entry in this returned array contains the following keys:
|
|
148
|
-
* 1) parentStateKey - key of the state where the transition can be activated
|
|
149
|
-
* 2) sourceStateKey - the initial transition state
|
|
150
|
-
* 3) eventKey - key of the event activating transition
|
|
151
|
-
* 4) targetStateKey - the resulting state for this transition
|
|
152
|
-
*
|
|
153
|
-
*/
|
|
154
|
-
function getAllTransitions(process) {
|
|
155
|
-
const list = [];
|
|
156
|
-
let stateKey = process.current ? process.current.key : KEYS.STATE_INITIAL;
|
|
157
|
-
for (let i = process.stack.length - 1; i >= 0; i--) {
|
|
158
|
-
const parentState = process.stack[i];
|
|
159
|
-
const parentStateKey = parentState.key;
|
|
160
|
-
const descriptor = parentState.descriptor;
|
|
161
|
-
for (const sKey of [stateKey, KEYS.STATE_ANY]) {
|
|
162
|
-
const stateTransitions = descriptor.transitions[sKey];
|
|
163
|
-
if (!stateTransitions) continue;
|
|
164
|
-
for (const[eventKey, targetKey] of Object.entries(stateTransitions)) {
|
|
165
|
-
list.push([parentStateKey, sKey, eventKey, targetKey]);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
stateKey = parentStateKey;
|
|
169
|
-
}
|
|
170
|
-
return list;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
141
|
function getTargetStateKey(descriptor, stateKey, eventKey) {
|
|
174
142
|
const pairs = [
|
|
175
143
|
[stateKey, eventKey],
|
|
@@ -272,6 +240,98 @@ function newAsyncProcess({
|
|
|
272
240
|
return process;
|
|
273
241
|
}
|
|
274
242
|
|
|
243
|
+
function initProcess({ config, handler, handleError = console.error }) {
|
|
244
|
+
let process;
|
|
245
|
+
const before = async (process) => {
|
|
246
|
+
process._started = true;
|
|
247
|
+
const state = process.current;
|
|
248
|
+
handler(state);
|
|
249
|
+
await state.init.run();
|
|
250
|
+
};
|
|
251
|
+
const after = async (process) => {
|
|
252
|
+
const state = process.current;
|
|
253
|
+
await state.done.run();
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
process = newAsyncProcess({
|
|
257
|
+
config,
|
|
258
|
+
before,
|
|
259
|
+
after,
|
|
260
|
+
newProcess: (descriptor) => {
|
|
261
|
+
return {
|
|
262
|
+
descriptor,
|
|
263
|
+
config,
|
|
264
|
+
status: 0,
|
|
265
|
+
stack: [],
|
|
266
|
+
event: undefined,
|
|
267
|
+
current: undefined
|
|
268
|
+
};
|
|
269
|
+
},
|
|
270
|
+
newState: (state) => {
|
|
271
|
+
state.init = newStateMethod();
|
|
272
|
+
state.done = newStateMethod();
|
|
273
|
+
state.dispatch = (...args) => state.process.dispatch(...args);
|
|
274
|
+
state.getEvent = () => state.process.event || {};
|
|
275
|
+
state.getEventKey = () => state.getEvent().key;
|
|
276
|
+
return state;
|
|
277
|
+
},
|
|
278
|
+
handleError
|
|
279
|
+
});
|
|
280
|
+
process.dispatch = (key, params = {}) => {
|
|
281
|
+
process.next({ key, params });
|
|
282
|
+
};
|
|
283
|
+
return process;
|
|
284
|
+
|
|
285
|
+
function newStateMethod() {
|
|
286
|
+
const list = [];
|
|
287
|
+
return Object.assign((m) => list.push(m), {
|
|
288
|
+
run: async (...args) => {
|
|
289
|
+
// We use the index to iterate over the list: the list can be updated by called methods
|
|
290
|
+
for (let i = 0; i < list.length; i++) {
|
|
291
|
+
try {
|
|
292
|
+
list[i] && (await list[i](...args));
|
|
293
|
+
} catch (error) {
|
|
294
|
+
console.error(error);
|
|
295
|
+
await handleError(error);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Returns all possible transitions from the current state of the process.
|
|
305
|
+
* @param {Object} options - method parameters
|
|
306
|
+
* @param {Process} options.process - the current process for which
|
|
307
|
+
* all transitions should be returned
|
|
308
|
+
* @returns {Array<Object>} - an array of all transitions;
|
|
309
|
+
* each entry in this returned array contains the following keys:
|
|
310
|
+
* 1) parentStateKey - key of the state where the transition can be activated
|
|
311
|
+
* 2) sourceStateKey - the initial transition state
|
|
312
|
+
* 3) eventKey - key of the event activating transition
|
|
313
|
+
* 4) targetStateKey - the resulting state for this transition
|
|
314
|
+
*
|
|
315
|
+
*/
|
|
316
|
+
function getAllTransitions(process) {
|
|
317
|
+
const list = [];
|
|
318
|
+
let stateKey = process.current ? process.current.key : KEYS.STATE_INITIAL;
|
|
319
|
+
for (let i = process.stack.length - 1; i >= 0; i--) {
|
|
320
|
+
const parentState = process.stack[i];
|
|
321
|
+
const parentStateKey = parentState.key;
|
|
322
|
+
const descriptor = parentState.descriptor;
|
|
323
|
+
for (const sKey of [stateKey, KEYS.STATE_ANY]) {
|
|
324
|
+
const stateTransitions = descriptor.transitions[sKey];
|
|
325
|
+
if (!stateTransitions) continue;
|
|
326
|
+
for (const[eventKey, targetKey] of Object.entries(stateTransitions)) {
|
|
327
|
+
list.push([parentStateKey, sKey, eventKey, targetKey]);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
stateKey = parentStateKey;
|
|
331
|
+
}
|
|
332
|
+
return list;
|
|
333
|
+
}
|
|
334
|
+
|
|
275
335
|
function newSyncProcess({
|
|
276
336
|
config,
|
|
277
337
|
descriptor,
|
|
@@ -304,15 +364,9 @@ exports.getAllStateKeys = getAllStateKeys;
|
|
|
304
364
|
exports.getAllTransitions = getAllTransitions;
|
|
305
365
|
exports.getStateDescriptor = getStateDescriptor;
|
|
306
366
|
exports.getTargetStateKey = getTargetStateKey;
|
|
307
|
-
exports.
|
|
367
|
+
exports.initAsyncProcess = initProcess;
|
|
308
368
|
exports.newProcessInstance = newProcessInstance;
|
|
309
369
|
exports.newSyncProcess = newSyncProcess;
|
|
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
|
-
});
|
|
316
370
|
|
|
317
371
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
318
372
|
|
package/dist/index-umd.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
// @statewalker/fsm v0.
|
|
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,
|
|
1
|
+
// @statewalker/fsm v0.13.0 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,a={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}(a.transitions[t]=a.transitions[t]||{})[n]=s}if(Array.isArray(r))for(const e of r)a.states[e.key]=n(e);else if(r)for(const e of Object.keys(r))a.states[e]=n(r[e]);return a}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],a=e.transitions[n];a&&(o=a[c],void 0===o&&(o=a[s.EVENT_ANY]))}return void 0!==o?o:s.STATE_FINAL}function c({config:e,descriptor:c,newState:a=(e=>e),newProcess:i=(e=>({descriptor:e,status:0,stack:[],event:void 0,current:void 0}))}){const f=i(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?a({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,a=o.descriptor;for(const e of[n,s.STATE_ANY]){const n=a.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.initAsyncProcess=function({config:e,handler:n,handleError:s=console.error}){let r;return r=function({config:e,descriptor:n,before:s,after:r,newProcess:o,newState:a,handleError:i=console.error}){const[f,u]=c({config:e,descriptor:n,newProcess:o,newState:a}),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){i(e)}})).finally((()=>f.running=void 0)).then((()=>!f.finished))),f}({config:e,before:async e=>{e._started=!0;const t=e.current;n(t),await t.init.run()},after:async e=>{const t=e.current;await t.done.run()},newProcess:t=>({descriptor:t,config:e,status:0,stack:[],event:void 0,current:void 0}),newState:e=>(e.init=o(),e.done=o(),e.dispatch=(...t)=>e.process.dispatch(...t),e.getEvent=()=>e.process.event||{},e.getEventKey=()=>e.getEvent().key,e),handleError:s}),r.dispatch=(e,t={})=>{r.next({key:e,params:t})},r;function o(){const e=[];return Object.assign((t=>e.push(t)),{run:async(...t)=>{for(let n=0;n<e.length;n++)try{e[n]&&await e[n](...t)}catch(e){console.error(e),await s(e)}}})}},e.newProcessInstance=c,e.newSyncProcess=function({config:e,descriptor:n,before:s,after:r,newProcess:o,newState:a}){const[i,f]=c({config:e,descriptor:n,newProcess:o,newState:a}),u=t.newTreeWalker(s,r,i);return i.dispatch=i.next=e=>{for("string"==typeof e&&(e={key:e}),i.event=e;i.event;){if(!u(f))return!1;if(i.status&t.MODE.LEAF)return!0}},i},Object.defineProperty(e,"__esModule",{value:!0})}));
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
// @statewalker/fsm v0.
|
|
1
|
+
// @statewalker/fsm v0.13.0 https://github.com/statewalker/statewalker-tree Copyright 2022 Mikhail Kotelnikov
|
|
2
2
|
import { MODE, newAsyncTreeWalker, newTreeWalker } from '@statewalker/tree';
|
|
3
|
-
export * from '@statewalker/tree';
|
|
4
3
|
|
|
5
4
|
function buildStateDescriptor(config = {}) {
|
|
6
5
|
const { key, transitions = [], states = {}, options, ...params } = config;
|
|
@@ -135,38 +134,6 @@ function getAllStateKeys(descriptor) {
|
|
|
135
134
|
}
|
|
136
135
|
}
|
|
137
136
|
|
|
138
|
-
/**
|
|
139
|
-
* Returns all possible transitions from the current state of the process.
|
|
140
|
-
* @param {Object} options - method parameters
|
|
141
|
-
* @param {Process} options.process - the current process for which
|
|
142
|
-
* all transitions should be returned
|
|
143
|
-
* @returns {Array<Object>} - an array of all transitions;
|
|
144
|
-
* each entry in this returned array contains the following keys:
|
|
145
|
-
* 1) parentStateKey - key of the state where the transition can be activated
|
|
146
|
-
* 2) sourceStateKey - the initial transition state
|
|
147
|
-
* 3) eventKey - key of the event activating transition
|
|
148
|
-
* 4) targetStateKey - the resulting state for this transition
|
|
149
|
-
*
|
|
150
|
-
*/
|
|
151
|
-
function getAllTransitions(process) {
|
|
152
|
-
const list = [];
|
|
153
|
-
let stateKey = process.current ? process.current.key : KEYS.STATE_INITIAL;
|
|
154
|
-
for (let i = process.stack.length - 1; i >= 0; i--) {
|
|
155
|
-
const parentState = process.stack[i];
|
|
156
|
-
const parentStateKey = parentState.key;
|
|
157
|
-
const descriptor = parentState.descriptor;
|
|
158
|
-
for (const sKey of [stateKey, KEYS.STATE_ANY]) {
|
|
159
|
-
const stateTransitions = descriptor.transitions[sKey];
|
|
160
|
-
if (!stateTransitions) continue;
|
|
161
|
-
for (const[eventKey, targetKey] of Object.entries(stateTransitions)) {
|
|
162
|
-
list.push([parentStateKey, sKey, eventKey, targetKey]);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
stateKey = parentStateKey;
|
|
166
|
-
}
|
|
167
|
-
return list;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
137
|
function getTargetStateKey(descriptor, stateKey, eventKey) {
|
|
171
138
|
const pairs = [
|
|
172
139
|
[stateKey, eventKey],
|
|
@@ -269,6 +236,98 @@ function newAsyncProcess({
|
|
|
269
236
|
return process;
|
|
270
237
|
}
|
|
271
238
|
|
|
239
|
+
function initProcess({ config, handler, handleError = console.error }) {
|
|
240
|
+
let process;
|
|
241
|
+
const before = async (process) => {
|
|
242
|
+
process._started = true;
|
|
243
|
+
const state = process.current;
|
|
244
|
+
handler(state);
|
|
245
|
+
await state.init.run();
|
|
246
|
+
};
|
|
247
|
+
const after = async (process) => {
|
|
248
|
+
const state = process.current;
|
|
249
|
+
await state.done.run();
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
process = newAsyncProcess({
|
|
253
|
+
config,
|
|
254
|
+
before,
|
|
255
|
+
after,
|
|
256
|
+
newProcess: (descriptor) => {
|
|
257
|
+
return {
|
|
258
|
+
descriptor,
|
|
259
|
+
config,
|
|
260
|
+
status: 0,
|
|
261
|
+
stack: [],
|
|
262
|
+
event: undefined,
|
|
263
|
+
current: undefined
|
|
264
|
+
};
|
|
265
|
+
},
|
|
266
|
+
newState: (state) => {
|
|
267
|
+
state.init = newStateMethod();
|
|
268
|
+
state.done = newStateMethod();
|
|
269
|
+
state.dispatch = (...args) => state.process.dispatch(...args);
|
|
270
|
+
state.getEvent = () => state.process.event || {};
|
|
271
|
+
state.getEventKey = () => state.getEvent().key;
|
|
272
|
+
return state;
|
|
273
|
+
},
|
|
274
|
+
handleError
|
|
275
|
+
});
|
|
276
|
+
process.dispatch = (key, params = {}) => {
|
|
277
|
+
process.next({ key, params });
|
|
278
|
+
};
|
|
279
|
+
return process;
|
|
280
|
+
|
|
281
|
+
function newStateMethod() {
|
|
282
|
+
const list = [];
|
|
283
|
+
return Object.assign((m) => list.push(m), {
|
|
284
|
+
run: async (...args) => {
|
|
285
|
+
// We use the index to iterate over the list: the list can be updated by called methods
|
|
286
|
+
for (let i = 0; i < list.length; i++) {
|
|
287
|
+
try {
|
|
288
|
+
list[i] && (await list[i](...args));
|
|
289
|
+
} catch (error) {
|
|
290
|
+
console.error(error);
|
|
291
|
+
await handleError(error);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Returns all possible transitions from the current state of the process.
|
|
301
|
+
* @param {Object} options - method parameters
|
|
302
|
+
* @param {Process} options.process - the current process for which
|
|
303
|
+
* all transitions should be returned
|
|
304
|
+
* @returns {Array<Object>} - an array of all transitions;
|
|
305
|
+
* each entry in this returned array contains the following keys:
|
|
306
|
+
* 1) parentStateKey - key of the state where the transition can be activated
|
|
307
|
+
* 2) sourceStateKey - the initial transition state
|
|
308
|
+
* 3) eventKey - key of the event activating transition
|
|
309
|
+
* 4) targetStateKey - the resulting state for this transition
|
|
310
|
+
*
|
|
311
|
+
*/
|
|
312
|
+
function getAllTransitions(process) {
|
|
313
|
+
const list = [];
|
|
314
|
+
let stateKey = process.current ? process.current.key : KEYS.STATE_INITIAL;
|
|
315
|
+
for (let i = process.stack.length - 1; i >= 0; i--) {
|
|
316
|
+
const parentState = process.stack[i];
|
|
317
|
+
const parentStateKey = parentState.key;
|
|
318
|
+
const descriptor = parentState.descriptor;
|
|
319
|
+
for (const sKey of [stateKey, KEYS.STATE_ANY]) {
|
|
320
|
+
const stateTransitions = descriptor.transitions[sKey];
|
|
321
|
+
if (!stateTransitions) continue;
|
|
322
|
+
for (const[eventKey, targetKey] of Object.entries(stateTransitions)) {
|
|
323
|
+
list.push([parentStateKey, sKey, eventKey, targetKey]);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
stateKey = parentStateKey;
|
|
327
|
+
}
|
|
328
|
+
return list;
|
|
329
|
+
}
|
|
330
|
+
|
|
272
331
|
function newSyncProcess({
|
|
273
332
|
config,
|
|
274
333
|
descriptor,
|
|
@@ -294,4 +353,4 @@ function newSyncProcess({
|
|
|
294
353
|
return process;
|
|
295
354
|
}
|
|
296
355
|
|
|
297
|
-
export { KEYS, buildStateDescriptor, checkProcessDescriptor, getAllStateKeys, getAllTransitions, getStateDescriptor, getTargetStateKey,
|
|
356
|
+
export { KEYS, buildStateDescriptor, checkProcessDescriptor, getAllStateKeys, getAllTransitions, getStateDescriptor, getTargetStateKey, initProcess as initAsyncProcess, newProcessInstance, newSyncProcess };
|
package/dist/index.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
// @statewalker/fsm v0.
|
|
2
|
-
import{MODE as t,newAsyncTreeWalker as e,newTreeWalker as n}from"@statewalker/tree";
|
|
1
|
+
// @statewalker/fsm v0.13.0 https://github.com/statewalker/statewalker-tree Copyright 2022 Mikhail Kotelnikov
|
|
2
|
+
import{MODE as t,newAsyncTreeWalker as e,newTreeWalker as n}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,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 f({config:e,descriptor:n,newState:o=(t=>t),newProcess:i=(t=>({descriptor:t,status:0,stack:[],event:void 0,current:void 0}))}){const f=i(n=n||s(e));return[f,()=>{let e,n;if(f.status)if(f.stack.length){const s=f.event.key||r.EVENT_EMPTY;e=a(f.stack[f.stack.length-1].descriptor,f.status&t.ENTER?r.STATE_INITIAL:f.current?f.current.key:r.STATE_FINAL,s),e&&(n=c(f,e))}else e=r.STATE_FINAL;else n=f.descriptor,e=n.key;return e?o({process:f,key:e,descriptor:n}):null}]}function u({config:n,handler:s,handleError:r=console.error}){let o;return o=function({config:n,descriptor:s,before:r,after:o,newProcess:c,newState:i,handleError:a=console.error}){const[u,d]=f({config:n,descriptor:s,newProcess:c,newState:i}),l=e(r,o,u);return u.finished=!1,u.next=e=>(u.nextEvent=e,u.running=u.running||Promise.resolve().then((async()=>{try{for(u.event=u.nextEvent,u.nextEvent=void 0;!u.finished&&u.event;)if(u.finished=!await l(d),u.status&t.EXIT&&u.nextEvent)u.event=u.nextEvent,u.nextEvent=void 0;else if(u.status&t.LEAF)break}catch(t){a(t)}})).finally((()=>u.running=void 0)).then((()=>!u.finished))),u}({config:n,before:async t=>{t._started=!0;const e=t.current;s(e),await e.init.run()},after:async t=>{const e=t.current;await e.done.run()},newProcess:t=>({descriptor:t,config:n,status:0,stack:[],event:void 0,current:void 0}),newState:t=>(t.init=c(),t.done=c(),t.dispatch=(...e)=>t.process.dispatch(...e),t.getEvent=()=>t.process.event||{},t.getEventKey=()=>t.getEvent().key,t),handleError:r}),o.dispatch=(t,e={})=>{o.next({key:t,params:e})},o;function c(){const t=[];return Object.assign((e=>t.push(e)),{run:async(...e)=>{for(let n=0;n<t.length;n++)try{t[n]&&await t[n](...e)}catch(t){console.error(t),await r(t)}}})}}function d(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 l({config:e,descriptor:s,before:r,after:o,newProcess:c,newState:i}){const[a,u]=f({config:e,descriptor:s,newProcess:c,newState:i}),d=n(r,o,a);return a.dispatch=a.next=e=>{for("string"==typeof e&&(e={key:e}),a.event=e;a.event;){if(!d(u))return!1;if(a.status&t.LEAF)return!0}},a}export{r as KEYS,s as buildStateDescriptor,o as checkProcessDescriptor,i as getAllStateKeys,d as getAllTransitions,c as getStateDescriptor,a as getTargetStateKey,u as initAsyncProcess,f as newProcessInstance,l as newSyncProcess};
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
export * from "@statewalker/tree";
|
|
2
1
|
export { default as buildStateDescriptor } from "./buildStateDescriptor.js";
|
|
3
2
|
export { default as checkProcessDescriptor } from "./checkProcessDescriptor.js";
|
|
4
3
|
export { default as getStateDescriptor } from "./getStateDescriptor.js";
|
|
5
4
|
export { default as getAllStateKeys } from "./getAllStateKeys.js";
|
|
6
|
-
export { default as getAllTransitions } from "./getAllTransitions.js";
|
|
7
5
|
export { default as getTargetStateKey } from "./getTargetStateKey.js";
|
|
8
6
|
export { default as KEYS } from "./KEYS.js";
|
|
9
|
-
export { default as
|
|
7
|
+
export { default as initAsyncProcess } from "./initAsyncProcess.js";
|
|
8
|
+
export { default as getAllTransitions } from "./getAllTransitions.js";
|
|
10
9
|
export { default as newProcessInstance } from "./newProcessInstance.js";
|
|
11
10
|
export { default as newSyncProcess } from "./newSyncProcess.js";
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import newAsyncProcess from "./newAsyncProcess.js";
|
|
2
|
+
|
|
3
|
+
export default function initProcess({ config, handler, handleError = console.error }) {
|
|
4
|
+
let process;
|
|
5
|
+
const before = async (process) => {
|
|
6
|
+
process._started = true;
|
|
7
|
+
const state = process.current;
|
|
8
|
+
handler(state);
|
|
9
|
+
await state.init.run();
|
|
10
|
+
};
|
|
11
|
+
const after = async (process) => {
|
|
12
|
+
const state = process.current;
|
|
13
|
+
await state.done.run();
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
process = newAsyncProcess({
|
|
17
|
+
config,
|
|
18
|
+
before,
|
|
19
|
+
after,
|
|
20
|
+
newProcess: (descriptor) => {
|
|
21
|
+
return {
|
|
22
|
+
descriptor,
|
|
23
|
+
config,
|
|
24
|
+
status: 0,
|
|
25
|
+
stack: [],
|
|
26
|
+
event: undefined,
|
|
27
|
+
current: undefined
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
newState: (state) => {
|
|
31
|
+
state.init = newStateMethod();
|
|
32
|
+
state.done = newStateMethod();
|
|
33
|
+
state.dispatch = (...args) => state.process.dispatch(...args);
|
|
34
|
+
state.getEvent = () => state.process.event || {};
|
|
35
|
+
state.getEventKey = () => state.getEvent().key;
|
|
36
|
+
return state;
|
|
37
|
+
},
|
|
38
|
+
handleError
|
|
39
|
+
});
|
|
40
|
+
process.dispatch = (key, params = {}) => {
|
|
41
|
+
process.next({ key, params });
|
|
42
|
+
};
|
|
43
|
+
return process;
|
|
44
|
+
|
|
45
|
+
function newStateMethod() {
|
|
46
|
+
const list = [];
|
|
47
|
+
return Object.assign((m) => list.push(m), {
|
|
48
|
+
run: async (...args) => {
|
|
49
|
+
// We use the index to iterate over the list: the list can be updated by called methods
|
|
50
|
+
for (let i = 0; i < list.length; i++) {
|
|
51
|
+
try {
|
|
52
|
+
list[i] && (await list[i](...args));
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error(error);
|
|
55
|
+
await handleError(error);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|