@statewalker/fsm 0.26.0 → 0.28.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.d.ts +6 -2
- package/dist/index.js +53 -8
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/newFsmProcess.ts +23 -14
- package/src/startFsmProcess copy 2.ts +74 -0
- package/src/startFsmProcess copy.ts +77 -0
- package/src/startFsmProcess.ts +78 -0
package/dist/index.d.ts
CHANGED
|
@@ -117,9 +117,13 @@ declare function setStateTracer(state: FsmState, print?: Printer): void;
|
|
|
117
117
|
declare function isStateTransitionEnabled(process: FsmProcess, event: string): boolean;
|
|
118
118
|
declare function getStateTransitions(state?: FsmState): [from: string, event: string, to: string][];
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
type Module<C = unknown> = (context: C) => void | (() => void | Promise<void>) | Promise<void | (() => void | Promise<void>)>;
|
|
121
|
+
declare function newFsmProcess<C>(context: C, config: FsmStateConfig, load: (state: string, event: undefined | string) => undefined | Module<C> | Module<C>[] | Promise<undefined | Module<C> | Module<C>[]>): [
|
|
121
122
|
dispatch: (event: string) => Promise<boolean>,
|
|
122
123
|
shutdown: () => Promise<void>
|
|
123
124
|
];
|
|
124
125
|
|
|
125
|
-
|
|
126
|
+
type ModuleOrTrigger<C = unknown> = (context: C) => void | (() => void | Promise<void>) | Promise<void | (() => void | Promise<void>)> | AsyncGenerator<string, void, unknown> | Generator<string, void, unknown>;
|
|
127
|
+
declare function startFsmProcess<C>(context: C, config: FsmStateConfig, load: (state: string, event: undefined | string) => undefined | ModuleOrTrigger<C> | ModuleOrTrigger<C>[] | Promise<undefined | ModuleOrTrigger<C> | ModuleOrTrigger<C>[]>, startEvent?: string): () => Promise<void>;
|
|
128
|
+
|
|
129
|
+
export { EVENT_ANY, EVENT_EMPTY, type FsmEventKey, FsmProcess, type FsmProcessDump, type FsmProcessDumpHandler, type FsmProcessHandler, FsmState, type FsmStateConfig, FsmStateDescriptor, type FsmStateDump, type FsmStateDumpHandler, type FsmStateErrorHandler, type FsmStateHandler, type FsmStateKey, KEY_PRINTER, type Module, type ModuleOrTrigger, type Printer, type PrinterConfig, STATE_ANY, STATE_FINAL, STATE_INITIAL, STATUS_ENTER, STATUS_EXIT, STATUS_FINISHED, STATUS_FIRST, STATUS_LAST, STATUS_LEAF, STATUS_NEXT, STATUS_NONE, getPrinter, getProcessPrinter, getStateTransitions, isStateTransitionEnabled, newFsmProcess, newProcess, preparePrinter, setPrinter, setProcessPrinter, setProcessTracer, setStateTracer, startFsmProcess };
|
package/dist/index.js
CHANGED
|
@@ -410,22 +410,24 @@ function getTransitionsFromDescriptor(descriptor, prevStateKey, index = {}) {
|
|
|
410
410
|
}
|
|
411
411
|
|
|
412
412
|
// src/newFsmProcess.ts
|
|
413
|
-
function newFsmProcess(config,
|
|
413
|
+
function newFsmProcess(context, config, load) {
|
|
414
414
|
let started = false;
|
|
415
415
|
let terminated = false;
|
|
416
416
|
const process = new FsmProcess(config);
|
|
417
417
|
process.onStateCreate((state) => {
|
|
418
418
|
started = true;
|
|
419
|
-
let cleanup;
|
|
420
419
|
state.onEnter(async () => {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
420
|
+
const modules = await load(state.key, process.event) ?? [];
|
|
421
|
+
for (const module of Array.isArray(modules) ? modules : [modules]) {
|
|
422
|
+
const handler = await module(context);
|
|
423
|
+
if (typeof handler === "function") {
|
|
424
|
+
state.onExit(handler);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
425
427
|
});
|
|
426
428
|
});
|
|
427
429
|
async function dispatch(event) {
|
|
428
|
-
return terminated || event !== void 0 ? process.dispatch(event) : false;
|
|
430
|
+
return terminated || event !== void 0 && (!started || isStateTransitionEnabled(process, event)) ? process.dispatch(event) : false;
|
|
429
431
|
}
|
|
430
432
|
async function shutdown() {
|
|
431
433
|
await process.shutdown();
|
|
@@ -433,6 +435,48 @@ function newFsmProcess(config, handler) {
|
|
|
433
435
|
}
|
|
434
436
|
return [dispatch, shutdown];
|
|
435
437
|
}
|
|
438
|
+
|
|
439
|
+
// src/startFsmProcess.ts
|
|
440
|
+
function startFsmProcess(context, config, load, startEvent = "") {
|
|
441
|
+
let started = false;
|
|
442
|
+
let terminated = false;
|
|
443
|
+
const process = new FsmProcess(config);
|
|
444
|
+
process.onStateCreate((state) => {
|
|
445
|
+
started = true;
|
|
446
|
+
state.onEnter(async () => {
|
|
447
|
+
const ModuleOrTriggers = await load(state.key, process.event) ?? [];
|
|
448
|
+
for (const ModuleOrTrigger of Array.isArray(ModuleOrTriggers) ? ModuleOrTriggers : [ModuleOrTriggers]) {
|
|
449
|
+
const result = await ModuleOrTrigger?.(context);
|
|
450
|
+
if (isGenerator(result)) {
|
|
451
|
+
state.onExit(() => {
|
|
452
|
+
result.return?.(void 0);
|
|
453
|
+
});
|
|
454
|
+
(async () => {
|
|
455
|
+
for await (const event of result) {
|
|
456
|
+
if (terminated) {
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
if (event !== void 0 && isStateTransitionEnabled(process, event)) {
|
|
460
|
+
await process.dispatch(event);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
})();
|
|
464
|
+
} else if (typeof result === "function") {
|
|
465
|
+
state.onExit(result);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
});
|
|
470
|
+
function isGenerator(value) {
|
|
471
|
+
return typeof value === "object" && value !== null && "next" in value && typeof value.next === "function";
|
|
472
|
+
}
|
|
473
|
+
async function shutdown() {
|
|
474
|
+
await process.shutdown();
|
|
475
|
+
terminated = true;
|
|
476
|
+
}
|
|
477
|
+
process.dispatch(startEvent);
|
|
478
|
+
return shutdown;
|
|
479
|
+
}
|
|
436
480
|
export {
|
|
437
481
|
EVENT_ANY,
|
|
438
482
|
EVENT_EMPTY,
|
|
@@ -461,5 +505,6 @@ export {
|
|
|
461
505
|
setPrinter,
|
|
462
506
|
setProcessPrinter,
|
|
463
507
|
setProcessTracer,
|
|
464
|
-
setStateTracer
|
|
508
|
+
setStateTracer,
|
|
509
|
+
startFsmProcess
|
|
465
510
|
};
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
package/src/newFsmProcess.ts
CHANGED
|
@@ -2,16 +2,24 @@ import { FsmProcess } from "./FsmProcess.js";
|
|
|
2
2
|
import type { FsmStateConfig } from "./FsmStateConfig.js";
|
|
3
3
|
import { isStateTransitionEnabled } from "./utils/transitions.js";
|
|
4
4
|
|
|
5
|
-
export
|
|
5
|
+
export type Module<C = unknown> = (
|
|
6
|
+
context: C,
|
|
7
|
+
) =>
|
|
8
|
+
| void
|
|
9
|
+
| (() => void | Promise<void>)
|
|
10
|
+
| Promise<void | (() => void | Promise<void>)>;
|
|
11
|
+
|
|
12
|
+
export function newFsmProcess<C>(
|
|
13
|
+
context: C,
|
|
6
14
|
config: FsmStateConfig,
|
|
7
|
-
|
|
15
|
+
load: (
|
|
8
16
|
state: string,
|
|
9
17
|
event: undefined | string,
|
|
10
18
|
) =>
|
|
11
|
-
|
|
|
12
|
-
|
|
|
13
|
-
|
|
|
14
|
-
| Promise<
|
|
19
|
+
| undefined
|
|
20
|
+
| Module<C>
|
|
21
|
+
| Module<C>[]
|
|
22
|
+
| Promise<undefined | Module<C> | Module<C>[]>,
|
|
15
23
|
): [
|
|
16
24
|
dispatch: (event: string) => Promise<boolean>,
|
|
17
25
|
shutdown: () => Promise<void>,
|
|
@@ -21,19 +29,20 @@ export function newFsmProcess(
|
|
|
21
29
|
const process = new FsmProcess(config);
|
|
22
30
|
process.onStateCreate((state) => {
|
|
23
31
|
started = true;
|
|
24
|
-
let cleanup: Awaited<ReturnType<typeof handler>> | undefined;
|
|
25
32
|
state.onEnter(async () => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
const modules = (await load(state.key, process.event)) ?? [];
|
|
34
|
+
for (const module of Array.isArray(modules) ? modules : [modules]) {
|
|
35
|
+
const handler = await module(context);
|
|
36
|
+
if (typeof handler === "function") {
|
|
37
|
+
state.onExit(handler);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
30
40
|
});
|
|
31
41
|
});
|
|
32
42
|
async function dispatch(event: string): Promise<boolean> {
|
|
33
43
|
return terminated ||
|
|
34
|
-
(event !== undefined
|
|
35
|
-
|
|
36
|
-
)
|
|
44
|
+
(event !== undefined &&
|
|
45
|
+
(!started || isStateTransitionEnabled(process, event)))
|
|
37
46
|
? process.dispatch(event)
|
|
38
47
|
: false;
|
|
39
48
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { FsmStateConfig } from "./FsmStateConfig.js";
|
|
2
|
+
import { type Module, newFsmProcess } from "./newFsmProcess.js";
|
|
3
|
+
|
|
4
|
+
export type ModuleOrTrigger<C = unknown> =
|
|
5
|
+
| Module<C>
|
|
6
|
+
| AsyncGenerator<string, void, unknown>
|
|
7
|
+
| Generator<string, void, unknown>;
|
|
8
|
+
export function startFsmProcess<C>(
|
|
9
|
+
context: C,
|
|
10
|
+
config: FsmStateConfig,
|
|
11
|
+
load: (
|
|
12
|
+
state: string,
|
|
13
|
+
event: undefined | string,
|
|
14
|
+
) =>
|
|
15
|
+
| undefined
|
|
16
|
+
| ModuleOrTrigger<C>
|
|
17
|
+
| ModuleOrTrigger<C>[]
|
|
18
|
+
| Promise<undefined | ModuleOrTrigger<C> | ModuleOrTrigger<C>[]>,
|
|
19
|
+
startEvent = "",
|
|
20
|
+
) {
|
|
21
|
+
function validateModule(
|
|
22
|
+
module: ModuleOrTrigger<C> | undefined,
|
|
23
|
+
): Module<C> | undefined {
|
|
24
|
+
if (module === undefined) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
if (isGeneratorFunction<string, [C]>(module)) {
|
|
28
|
+
const generator = module as (context: C) => AsyncGenerator<string>;
|
|
29
|
+
return async (context: C) => {
|
|
30
|
+
const iterator = generator(context);
|
|
31
|
+
console.warn('INIT', module, iterator);
|
|
32
|
+
(async () => {
|
|
33
|
+
for await (const event of iterator) {
|
|
34
|
+
await dispatch(event);
|
|
35
|
+
}
|
|
36
|
+
})();
|
|
37
|
+
return () => {
|
|
38
|
+
console.warn('DONE', module, iterator);
|
|
39
|
+
iterator.return?.(void 0);
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return module as Module<C>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const [dispatch, terminate] = newFsmProcess(
|
|
47
|
+
context,
|
|
48
|
+
config,
|
|
49
|
+
async (state, event) => {
|
|
50
|
+
const modules = (await load(state, event)) ?? [];
|
|
51
|
+
const modulesList = Array.isArray(modules) ? modules : [modules];
|
|
52
|
+
return modulesList
|
|
53
|
+
.map(validateModule)
|
|
54
|
+
.flat()
|
|
55
|
+
.filter(Boolean) as Module<C>[];
|
|
56
|
+
},
|
|
57
|
+
);
|
|
58
|
+
dispatch(startEvent);
|
|
59
|
+
return terminate;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const AsyncGeneratorFunction = async function* () {}.constructor;
|
|
63
|
+
const GeneratorFunction = function* () {}.constructor;
|
|
64
|
+
|
|
65
|
+
function isGeneratorFunction<T, P extends unknown[] = []>(
|
|
66
|
+
value: unknown,
|
|
67
|
+
): value is
|
|
68
|
+
| ((...args: P) => AsyncGenerator<T>)
|
|
69
|
+
| ((...args: P) => Generator<T>) {
|
|
70
|
+
return (
|
|
71
|
+
value instanceof AsyncGeneratorFunction ||
|
|
72
|
+
value instanceof GeneratorFunction
|
|
73
|
+
);
|
|
74
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { FsmProcess } from "./FsmProcess.js";
|
|
2
|
+
import type { FsmStateConfig } from "./FsmStateConfig.js";
|
|
3
|
+
import { isStateTransitionEnabled } from "./utils/transitions.js";
|
|
4
|
+
|
|
5
|
+
export type Module<C = unknown> = (
|
|
6
|
+
context: C,
|
|
7
|
+
) =>
|
|
8
|
+
| void
|
|
9
|
+
| (() => void | Promise<void>)
|
|
10
|
+
| Promise<void | (() => void | Promise<void>)>
|
|
11
|
+
| AsyncGenerator<string, void, unknown>
|
|
12
|
+
| Generator<string, void, unknown>;
|
|
13
|
+
|
|
14
|
+
export function startFsmProcess<C>(
|
|
15
|
+
context: C,
|
|
16
|
+
config: FsmStateConfig,
|
|
17
|
+
load: (
|
|
18
|
+
state: string,
|
|
19
|
+
event: undefined | string,
|
|
20
|
+
) =>
|
|
21
|
+
| undefined
|
|
22
|
+
| Module<C>
|
|
23
|
+
| Module<C>[]
|
|
24
|
+
| Promise<undefined | Module<C> | Module<C>[]>,
|
|
25
|
+
startEvent = ""
|
|
26
|
+
): () => Promise<void> {
|
|
27
|
+
let started = false;
|
|
28
|
+
let terminated = false;
|
|
29
|
+
const process = new FsmProcess(config);
|
|
30
|
+
process.onStateCreate((state) => {
|
|
31
|
+
started = true;
|
|
32
|
+
state.onEnter(async () => {
|
|
33
|
+
const modules = (await load(state.key, process.event)) ?? [];
|
|
34
|
+
for (const module of Array.isArray(modules) ? modules : [modules]) {
|
|
35
|
+
const result = await module(context);
|
|
36
|
+
if (isGenerator(result)) {
|
|
37
|
+
state.onExit(() => {
|
|
38
|
+
result.return?.(void 0);
|
|
39
|
+
});
|
|
40
|
+
(async () => {
|
|
41
|
+
for await (const event of result) {
|
|
42
|
+
await dispatch(event);
|
|
43
|
+
}
|
|
44
|
+
})();
|
|
45
|
+
} else if (typeof result === "function") {
|
|
46
|
+
state.onExit(result);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
function isGenerator(
|
|
53
|
+
value: unknown,
|
|
54
|
+
): value is
|
|
55
|
+
| Generator<string, void, unknown>
|
|
56
|
+
| AsyncGenerator<string, void, unknown> {
|
|
57
|
+
return (
|
|
58
|
+
typeof value === "object" &&
|
|
59
|
+
value !== null &&
|
|
60
|
+
"next" in value &&
|
|
61
|
+
typeof (value as Generator<string, void, unknown>).next === "function"
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
async function dispatch(event: string): Promise<boolean> {
|
|
65
|
+
return terminated ||
|
|
66
|
+
(event !== undefined &&
|
|
67
|
+
(!started || isStateTransitionEnabled(process, event)))
|
|
68
|
+
? process.dispatch(event)
|
|
69
|
+
: false;
|
|
70
|
+
}
|
|
71
|
+
async function shutdown(): Promise<void> {
|
|
72
|
+
await process.shutdown();
|
|
73
|
+
terminated = true;
|
|
74
|
+
}
|
|
75
|
+
dispatch(startEvent);
|
|
76
|
+
return shutdown;
|
|
77
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { FsmProcess } from "./FsmProcess.js";
|
|
2
|
+
import type { FsmStateConfig } from "./FsmStateConfig.js";
|
|
3
|
+
import { isStateTransitionEnabled } from "./utils/transitions.js";
|
|
4
|
+
|
|
5
|
+
export type ModuleOrTrigger<C = unknown> = (
|
|
6
|
+
context: C,
|
|
7
|
+
) =>
|
|
8
|
+
| void
|
|
9
|
+
| (() => void | Promise<void>)
|
|
10
|
+
| Promise<void | (() => void | Promise<void>)>
|
|
11
|
+
| AsyncGenerator<string, void, unknown>
|
|
12
|
+
| Generator<string, void, unknown>;
|
|
13
|
+
|
|
14
|
+
export function startFsmProcess<C>(
|
|
15
|
+
context: C,
|
|
16
|
+
config: FsmStateConfig,
|
|
17
|
+
load: (
|
|
18
|
+
state: string,
|
|
19
|
+
event: undefined | string,
|
|
20
|
+
) =>
|
|
21
|
+
| undefined
|
|
22
|
+
| ModuleOrTrigger<C>
|
|
23
|
+
| ModuleOrTrigger<C>[]
|
|
24
|
+
| Promise<undefined | ModuleOrTrigger<C> | ModuleOrTrigger<C>[]>,
|
|
25
|
+
startEvent = "",
|
|
26
|
+
): () => Promise<void> {
|
|
27
|
+
let started = false;
|
|
28
|
+
let terminated = false;
|
|
29
|
+
const process = new FsmProcess(config);
|
|
30
|
+
process.onStateCreate((state) => {
|
|
31
|
+
started = true;
|
|
32
|
+
state.onEnter(async () => {
|
|
33
|
+
const ModuleOrTriggers = (await load(state.key, process.event)) ?? [];
|
|
34
|
+
for (const ModuleOrTrigger of Array.isArray(ModuleOrTriggers) ? ModuleOrTriggers : [ModuleOrTriggers]) {
|
|
35
|
+
const result = await ModuleOrTrigger?.(context);
|
|
36
|
+
if (isGenerator(result)) {
|
|
37
|
+
state.onExit(() => {
|
|
38
|
+
result.return?.(void 0);
|
|
39
|
+
});
|
|
40
|
+
(async () => {
|
|
41
|
+
for await (const event of result) {
|
|
42
|
+
if (terminated) {
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
if (
|
|
46
|
+
event !== undefined &&
|
|
47
|
+
isStateTransitionEnabled(process, event)
|
|
48
|
+
) {
|
|
49
|
+
await process.dispatch(event);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
})();
|
|
53
|
+
} else if (typeof result === "function") {
|
|
54
|
+
state.onExit(result);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
function isGenerator(
|
|
61
|
+
value: unknown,
|
|
62
|
+
): value is
|
|
63
|
+
| Generator<string, void, unknown>
|
|
64
|
+
| AsyncGenerator<string, void, unknown> {
|
|
65
|
+
return (
|
|
66
|
+
typeof value === "object" &&
|
|
67
|
+
value !== null &&
|
|
68
|
+
"next" in value &&
|
|
69
|
+
typeof (value as Generator<string, void, unknown>).next === "function"
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
async function shutdown(): Promise<void> {
|
|
73
|
+
await process.shutdown();
|
|
74
|
+
terminated = true;
|
|
75
|
+
}
|
|
76
|
+
process.dispatch(startEvent);
|
|
77
|
+
return shutdown;
|
|
78
|
+
}
|