@statewalker/fsm 0.24.0 → 0.26.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 -1
- package/dist/index.js +29 -3
- package/package.json +1 -1
- package/src/FsmProcess.ts +3 -3
- package/src/index.ts +1 -0
- package/src/newFsmProcess.ts +45 -0
- package/src/utils/newFsmStateHandler.ts +28 -18
package/dist/index.d.ts
CHANGED
|
@@ -117,4 +117,9 @@ 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
|
+
declare function newFsmProcess(config: FsmStateConfig, handler: (state: string, event: undefined | string) => void | Promise<void> | ((event: undefined | string) => void | Promise<void>) | Promise<(event: undefined | string) => void | Promise<void>>): [
|
|
121
|
+
dispatch: (event: string) => Promise<boolean>,
|
|
122
|
+
shutdown: () => Promise<void>
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
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 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 };
|
package/dist/index.js
CHANGED
|
@@ -204,9 +204,9 @@ var FsmProcess = class extends FsmBaseClass {
|
|
|
204
204
|
} finally {
|
|
205
205
|
this.running = false;
|
|
206
206
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
return this.dispatch(
|
|
207
|
+
const nextEvent = this.nextEvent;
|
|
208
|
+
if (nextEvent !== void 0) {
|
|
209
|
+
return Promise.resolve().then(() => this.dispatch(nextEvent));
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
return !(this.status & STATUS_FINISHED);
|
|
@@ -408,6 +408,31 @@ function getTransitionsFromDescriptor(descriptor, prevStateKey, index = {}) {
|
|
|
408
408
|
}
|
|
409
409
|
return result;
|
|
410
410
|
}
|
|
411
|
+
|
|
412
|
+
// src/newFsmProcess.ts
|
|
413
|
+
function newFsmProcess(config, handler) {
|
|
414
|
+
let started = false;
|
|
415
|
+
let terminated = false;
|
|
416
|
+
const process = new FsmProcess(config);
|
|
417
|
+
process.onStateCreate((state) => {
|
|
418
|
+
started = true;
|
|
419
|
+
let cleanup;
|
|
420
|
+
state.onEnter(async () => {
|
|
421
|
+
cleanup = await handler(state.key, process.event);
|
|
422
|
+
});
|
|
423
|
+
state.onExit(async () => {
|
|
424
|
+
cleanup?.(process.event);
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
async function dispatch(event) {
|
|
428
|
+
return terminated || event !== void 0 ? process.dispatch(event) : false;
|
|
429
|
+
}
|
|
430
|
+
async function shutdown() {
|
|
431
|
+
await process.shutdown();
|
|
432
|
+
terminated = true;
|
|
433
|
+
}
|
|
434
|
+
return [dispatch, shutdown];
|
|
435
|
+
}
|
|
411
436
|
export {
|
|
412
437
|
EVENT_ANY,
|
|
413
438
|
EVENT_EMPTY,
|
|
@@ -430,6 +455,7 @@ export {
|
|
|
430
455
|
getProcessPrinter,
|
|
431
456
|
getStateTransitions,
|
|
432
457
|
isStateTransitionEnabled,
|
|
458
|
+
newFsmProcess,
|
|
433
459
|
newProcess,
|
|
434
460
|
preparePrinter,
|
|
435
461
|
setPrinter,
|
package/package.json
CHANGED
package/src/FsmProcess.ts
CHANGED
|
@@ -83,9 +83,9 @@ export class FsmProcess extends FsmBaseClass {
|
|
|
83
83
|
} finally {
|
|
84
84
|
this.running = false;
|
|
85
85
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return this.dispatch(
|
|
86
|
+
const nextEvent = this.nextEvent;
|
|
87
|
+
if (nextEvent !== undefined) {
|
|
88
|
+
return Promise.resolve().then(() => this.dispatch(nextEvent));
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
return !(this.status & STATUS_FINISHED);
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { FsmProcess } from "./FsmProcess.js";
|
|
2
|
+
import type { FsmStateConfig } from "./FsmStateConfig.js";
|
|
3
|
+
import { isStateTransitionEnabled } from "./utils/transitions.js";
|
|
4
|
+
|
|
5
|
+
export function newFsmProcess(
|
|
6
|
+
config: FsmStateConfig,
|
|
7
|
+
handler: (
|
|
8
|
+
state: string,
|
|
9
|
+
event: undefined | string,
|
|
10
|
+
) =>
|
|
11
|
+
| void
|
|
12
|
+
| Promise<void>
|
|
13
|
+
| ((event: undefined | string) => void | Promise<void>)
|
|
14
|
+
| Promise<(event: undefined | string) => void | Promise<void>>,
|
|
15
|
+
): [
|
|
16
|
+
dispatch: (event: string) => Promise<boolean>,
|
|
17
|
+
shutdown: () => Promise<void>,
|
|
18
|
+
] {
|
|
19
|
+
let started = false;
|
|
20
|
+
let terminated = false;
|
|
21
|
+
const process = new FsmProcess(config);
|
|
22
|
+
process.onStateCreate((state) => {
|
|
23
|
+
started = true;
|
|
24
|
+
let cleanup: Awaited<ReturnType<typeof handler>> | undefined;
|
|
25
|
+
state.onEnter(async () => {
|
|
26
|
+
cleanup = await handler(state.key, process.event);
|
|
27
|
+
});
|
|
28
|
+
state.onExit(async () => {
|
|
29
|
+
cleanup?.(process.event);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
async function dispatch(event: string): Promise<boolean> {
|
|
33
|
+
return terminated ||
|
|
34
|
+
(event !== undefined
|
|
35
|
+
// && (!started || isStateTransitionEnabled(process, event))
|
|
36
|
+
)
|
|
37
|
+
? process.dispatch(event)
|
|
38
|
+
: false;
|
|
39
|
+
}
|
|
40
|
+
async function shutdown(): Promise<void> {
|
|
41
|
+
await process.shutdown();
|
|
42
|
+
terminated = true;
|
|
43
|
+
}
|
|
44
|
+
return [dispatch, shutdown] as const;
|
|
45
|
+
}
|
|
@@ -72,16 +72,12 @@ export type FsmStateModule<
|
|
|
72
72
|
| ((...stack: FsmStateStore[]) => FsmStateContext)
|
|
73
73
|
| (new (...stack: FsmStateStore[]) => FsmStateContext);
|
|
74
74
|
// trigger?: (context: FsmStateContext) => AsyncGenerator<string>;
|
|
75
|
-
trigger?: (
|
|
76
|
-
context: FsmStateContext,
|
|
77
|
-
onEvent: (event: string) => void,
|
|
78
|
-
) => void | (() => void);
|
|
75
|
+
trigger?: (context: FsmStateContext) => AsyncIterator<string>;
|
|
79
76
|
handler?: (
|
|
80
77
|
context: FsmStateContext,
|
|
81
78
|
) => void | (() => void) | Promise<void | (() => void)>;
|
|
82
79
|
};
|
|
83
80
|
|
|
84
|
-
|
|
85
81
|
export function newModuleContext<
|
|
86
82
|
C = Record<string, unknown>,
|
|
87
83
|
S = Record<string, unknown>,
|
|
@@ -103,8 +99,6 @@ function isClass<T extends Array<unknown>, R = unknown>(
|
|
|
103
99
|
value: unknown,
|
|
104
100
|
): value is new (...args: T) => R {
|
|
105
101
|
if (!isFunction(value)) return false;
|
|
106
|
-
// console.log('============')
|
|
107
|
-
// console.log('???', value, value?.prototype, value?.prototype?.constructor);
|
|
108
102
|
return value?.prototype?.constructor?.toString().match(/^class/);
|
|
109
103
|
}
|
|
110
104
|
|
|
@@ -127,6 +121,7 @@ export function newStateHandlers<
|
|
|
127
121
|
FsmStateContext
|
|
128
122
|
>(),
|
|
129
123
|
) {
|
|
124
|
+
const triggers = new Map<unknown, () => void>();
|
|
130
125
|
return (state: FsmState) => {
|
|
131
126
|
const stack: FsmStateStore[] = [];
|
|
132
127
|
for (let s: FsmState | undefined = state.parent; !!s; s = s.parent) {
|
|
@@ -161,20 +156,35 @@ export function newStateHandlers<
|
|
|
161
156
|
}
|
|
162
157
|
|
|
163
158
|
// Initialize triggers
|
|
164
|
-
if (module.trigger) {
|
|
159
|
+
if (module.trigger && !triggers.has(module.trigger)) {
|
|
165
160
|
const process = state.process;
|
|
166
|
-
|
|
167
|
-
let
|
|
168
|
-
|
|
169
|
-
|
|
161
|
+
const iterator = module.trigger(stateContext);
|
|
162
|
+
let finalize: undefined | (() => void);
|
|
163
|
+
const end = new Promise<{ done: boolean; value?: string }>(
|
|
164
|
+
(r) => (finalize = () => r({ done: true })),
|
|
165
|
+
);
|
|
166
|
+
registrations.push(() => triggers.delete(module.trigger));
|
|
167
|
+
registrations.push(finalize);
|
|
168
|
+
registrations.push(() => iterator?.return?.(void 0));
|
|
169
|
+
(async () => {
|
|
170
|
+
try {
|
|
171
|
+
while (true) {
|
|
172
|
+
const { done, value: event } = await Promise.race([
|
|
173
|
+
iterator.next(),
|
|
174
|
+
end,
|
|
175
|
+
]);
|
|
176
|
+
if (done) break;
|
|
177
|
+
if (event && isStateTransitionEnabled(process, event)) {
|
|
178
|
+
process.dispatch(event);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
} finally {
|
|
182
|
+
finalize?.();
|
|
170
183
|
}
|
|
171
|
-
};
|
|
172
|
-
const cleanup = module.trigger(stateContext, notify);
|
|
173
|
-
registrations.push(() => {
|
|
174
|
-
notify = async () => {};
|
|
175
|
-
cleanup?.();
|
|
176
|
-
});
|
|
184
|
+
})();
|
|
177
185
|
}
|
|
186
|
+
|
|
187
|
+
// Run actions associated with this event
|
|
178
188
|
if (module.handler) {
|
|
179
189
|
const cleanup = module.handler(stateContext);
|
|
180
190
|
registrations.push(cleanup);
|