@doeixd/machine 0.0.12 → 0.0.17
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/README.md +90 -15
- package/dist/cjs/development/core.js +1852 -0
- package/dist/cjs/development/core.js.map +7 -0
- package/dist/cjs/development/index.js +1348 -1374
- package/dist/cjs/development/index.js.map +4 -4
- package/dist/cjs/production/core.js +1 -0
- package/dist/cjs/production/index.js +5 -5
- package/dist/esm/development/core.js +1829 -0
- package/dist/esm/development/core.js.map +7 -0
- package/dist/esm/development/index.js +1348 -1374
- package/dist/esm/development/index.js.map +4 -4
- package/dist/esm/production/core.js +1 -0
- package/dist/esm/production/index.js +5 -5
- package/dist/types/core.d.ts +18 -0
- package/dist/types/core.d.ts.map +1 -0
- package/dist/types/functional-combinators.d.ts +60 -5
- package/dist/types/functional-combinators.d.ts.map +1 -1
- package/dist/types/index.d.ts +242 -19
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/middleware/composition.d.ts +460 -0
- package/dist/types/middleware/composition.d.ts.map +1 -0
- package/dist/types/middleware/core.d.ts +196 -0
- package/dist/types/middleware/core.d.ts.map +1 -0
- package/dist/types/middleware/history.d.ts +54 -0
- package/dist/types/middleware/history.d.ts.map +1 -0
- package/dist/types/middleware/index.d.ts +10 -0
- package/dist/types/middleware/index.d.ts.map +1 -0
- package/dist/types/middleware/snapshot.d.ts +63 -0
- package/dist/types/middleware/snapshot.d.ts.map +1 -0
- package/dist/types/middleware/time-travel.d.ts +81 -0
- package/dist/types/middleware/time-travel.d.ts.map +1 -0
- package/package.json +19 -6
- package/src/core.ts +167 -0
- package/src/entry-react.ts +9 -0
- package/src/entry-solid.ts +9 -0
- package/src/functional-combinators.ts +76 -3
- package/src/index.ts +376 -102
- package/src/middleware/composition.ts +944 -0
- package/src/middleware/core.ts +573 -0
- package/src/middleware/history.ts +104 -0
- package/src/middleware/index.ts +13 -0
- package/src/middleware/snapshot.ts +153 -0
- package/src/middleware/time-travel.ts +236 -0
- package/src/middleware.ts +735 -1614
- package/src/prototype_functional.ts +46 -0
- package/src/reproduce_issue.ts +26 -0
- package/dist/types/middleware.d.ts +0 -1048
- package/dist/types/middleware.d.ts.map +0 -1
- package/dist/types/runtime-extract.d.ts +0 -53
- package/dist/types/runtime-extract.d.ts.map +0 -1
|
@@ -22,10 +22,11 @@ var src_exports = {};
|
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
ADVANCED_CONFIG_EXAMPLES: () => ADVANCED_CONFIG_EXAMPLES,
|
|
24
24
|
BoundMachine: () => BoundMachine,
|
|
25
|
+
CANCEL: () => CANCEL,
|
|
25
26
|
META_KEY: () => META_KEY,
|
|
26
27
|
MachineBase: () => MachineBase,
|
|
28
|
+
MiddlewareBuilder: () => MiddlewareBuilder,
|
|
27
29
|
MultiMachineBase: () => MultiMachineBase,
|
|
28
|
-
RUNTIME_META: () => RUNTIME_META,
|
|
29
30
|
action: () => action,
|
|
30
31
|
bindTransitions: () => bindTransitions,
|
|
31
32
|
branch: () => branch,
|
|
@@ -47,6 +48,7 @@ __export(src_exports, {
|
|
|
47
48
|
createMachineBuilder: () => createMachineBuilder,
|
|
48
49
|
createMachineFactory: () => createMachineFactory,
|
|
49
50
|
createMiddleware: () => createMiddleware,
|
|
51
|
+
createMiddlewareFactory: () => createMiddlewareFactory,
|
|
50
52
|
createMiddlewareRegistry: () => createMiddlewareRegistry,
|
|
51
53
|
createMultiMachine: () => createMultiMachine,
|
|
52
54
|
createMutableMachine: () => createMutableMachine,
|
|
@@ -59,13 +61,9 @@ __export(src_exports, {
|
|
|
59
61
|
delegateToChild: () => delegateToChild,
|
|
60
62
|
describe: () => describe,
|
|
61
63
|
extendTransitions: () => extendTransitions,
|
|
62
|
-
extractFromInstance: () => extractFromInstance,
|
|
63
|
-
extractFunctionMetadata: () => extractFunctionMetadata,
|
|
64
64
|
extractMachine: () => extractMachine,
|
|
65
65
|
extractMachines: () => extractMachines,
|
|
66
|
-
extractStateNode: () => extractStateNode,
|
|
67
66
|
generateChart: () => generateChart,
|
|
68
|
-
generateStatechart: () => generateStatechart,
|
|
69
67
|
guard: () => guard,
|
|
70
68
|
guardAsync: () => guardAsync,
|
|
71
69
|
guarded: () => guarded,
|
|
@@ -73,12 +71,20 @@ __export(src_exports, {
|
|
|
73
71
|
inDevelopment: () => inDevelopment,
|
|
74
72
|
invoke: () => invoke,
|
|
75
73
|
isConditionalMiddleware: () => isConditionalMiddleware,
|
|
74
|
+
isMiddlewareContext: () => isMiddlewareContext,
|
|
75
|
+
isMiddlewareError: () => isMiddlewareError,
|
|
76
76
|
isMiddlewareFn: () => isMiddlewareFn,
|
|
77
|
+
isMiddlewareHooks: () => isMiddlewareHooks,
|
|
78
|
+
isMiddlewareOptions: () => isMiddlewareOptions,
|
|
79
|
+
isMiddlewareResult: () => isMiddlewareResult,
|
|
80
|
+
isNamedMiddleware: () => isNamedMiddleware,
|
|
81
|
+
isPipelineConfig: () => isPipelineConfig,
|
|
77
82
|
isState: () => isState,
|
|
78
83
|
logState: () => logState,
|
|
79
84
|
matchMachine: () => matchMachine,
|
|
80
85
|
mergeContext: () => mergeContext,
|
|
81
86
|
metadata: () => metadata,
|
|
87
|
+
middlewareBuilder: () => middlewareBuilder,
|
|
82
88
|
next: () => next,
|
|
83
89
|
overrideTransitions: () => overrideTransitions,
|
|
84
90
|
pipeTransitions: () => pipeTransitions,
|
|
@@ -90,6 +96,7 @@ __export(src_exports, {
|
|
|
90
96
|
runWithEnsemble: () => runWithEnsemble,
|
|
91
97
|
runWithRunner: () => runWithRunner,
|
|
92
98
|
setContext: () => setContext,
|
|
99
|
+
state: () => state,
|
|
93
100
|
step: () => step,
|
|
94
101
|
stepAsync: () => stepAsync,
|
|
95
102
|
toggle: () => toggle,
|
|
@@ -351,1209 +358,1083 @@ function metadata(_meta, value) {
|
|
|
351
358
|
return value;
|
|
352
359
|
}
|
|
353
360
|
|
|
354
|
-
// src/
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
return {};
|
|
368
|
-
}
|
|
369
|
-
const result = {};
|
|
370
|
-
for (const prop of obj.getProperties()) {
|
|
371
|
-
if (import_ts_morph.Node.isPropertyAssignment(prop)) {
|
|
372
|
-
const name = prop.getName();
|
|
373
|
-
const init = prop.getInitializer();
|
|
374
|
-
if (init) {
|
|
375
|
-
if (import_ts_morph.Node.isStringLiteral(init)) {
|
|
376
|
-
result[name] = init.getLiteralValue();
|
|
377
|
-
} else if (import_ts_morph.Node.isNumericLiteral(init)) {
|
|
378
|
-
result[name] = init.getLiteralValue();
|
|
379
|
-
} else if (init.getText() === "true" || init.getText() === "false") {
|
|
380
|
-
result[name] = init.getText() === "true";
|
|
381
|
-
} else if (import_ts_morph.Node.isIdentifier(init)) {
|
|
382
|
-
result[name] = init.getText();
|
|
383
|
-
} else if (import_ts_morph.Node.isObjectLiteralExpression(init)) {
|
|
384
|
-
result[name] = parseObjectLiteral(init);
|
|
385
|
-
} else if (import_ts_morph.Node.isArrayLiteralExpression(init)) {
|
|
386
|
-
result[name] = init.getElements().map((el) => {
|
|
387
|
-
if (import_ts_morph.Node.isObjectLiteralExpression(el)) {
|
|
388
|
-
return parseObjectLiteral(el);
|
|
389
|
-
}
|
|
390
|
-
return el.getText();
|
|
391
|
-
});
|
|
392
|
-
}
|
|
361
|
+
// src/multi.ts
|
|
362
|
+
function createRunner(initialMachine, onChange) {
|
|
363
|
+
let currentMachine = initialMachine;
|
|
364
|
+
const setState = (newState) => {
|
|
365
|
+
currentMachine = newState;
|
|
366
|
+
onChange == null ? void 0 : onChange(newState);
|
|
367
|
+
};
|
|
368
|
+
const { context: _initialContext, ...originalTransitions } = initialMachine;
|
|
369
|
+
const actions = new Proxy({}, {
|
|
370
|
+
get(_target, prop) {
|
|
371
|
+
const transition = currentMachine[prop];
|
|
372
|
+
if (typeof transition !== "function") {
|
|
373
|
+
return void 0;
|
|
393
374
|
}
|
|
375
|
+
return (...args) => {
|
|
376
|
+
const nextState = transition.apply(currentMachine.context, args);
|
|
377
|
+
const nextStateWithTransitions = Object.assign(
|
|
378
|
+
{ context: nextState.context },
|
|
379
|
+
originalTransitions
|
|
380
|
+
);
|
|
381
|
+
setState(nextStateWithTransitions);
|
|
382
|
+
return nextStateWithTransitions;
|
|
383
|
+
};
|
|
394
384
|
}
|
|
395
|
-
}
|
|
396
|
-
return
|
|
385
|
+
});
|
|
386
|
+
return {
|
|
387
|
+
get state() {
|
|
388
|
+
return currentMachine;
|
|
389
|
+
},
|
|
390
|
+
get context() {
|
|
391
|
+
return currentMachine.context;
|
|
392
|
+
},
|
|
393
|
+
actions,
|
|
394
|
+
setState
|
|
395
|
+
};
|
|
397
396
|
}
|
|
398
|
-
function
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
397
|
+
function createEnsemble(store, factories, getDiscriminant) {
|
|
398
|
+
const getCurrentMachine = () => {
|
|
399
|
+
const context = store.getContext();
|
|
400
|
+
const currentStateName = getDiscriminant(context);
|
|
401
|
+
const factory = factories[currentStateName];
|
|
402
|
+
if (!factory) {
|
|
403
|
+
throw new Error(
|
|
404
|
+
`[Ensemble] Invalid state: No factory found for state "${String(currentStateName)}".`
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
return factory(context);
|
|
408
|
+
};
|
|
409
|
+
const actions = new Proxy({}, {
|
|
410
|
+
get(_target, prop) {
|
|
411
|
+
const currentMachine = getCurrentMachine();
|
|
412
|
+
const action2 = currentMachine[prop];
|
|
413
|
+
if (typeof action2 !== "function") {
|
|
414
|
+
throw new Error(
|
|
415
|
+
`[Ensemble] Transition "${prop}" is not valid in the current state.`
|
|
416
|
+
);
|
|
414
417
|
}
|
|
418
|
+
return (...args) => {
|
|
419
|
+
return action2.apply(currentMachine.context, args);
|
|
420
|
+
};
|
|
415
421
|
}
|
|
416
|
-
}
|
|
417
|
-
return
|
|
422
|
+
});
|
|
423
|
+
return {
|
|
424
|
+
get context() {
|
|
425
|
+
return store.getContext();
|
|
426
|
+
},
|
|
427
|
+
get state() {
|
|
428
|
+
return getCurrentMachine();
|
|
429
|
+
},
|
|
430
|
+
actions
|
|
431
|
+
};
|
|
418
432
|
}
|
|
419
|
-
function
|
|
420
|
-
|
|
421
|
-
return
|
|
422
|
-
}
|
|
423
|
-
const expression = call2.getExpression();
|
|
424
|
-
const fnName = import_ts_morph.Node.isIdentifier(expression) ? expression.getText() : null;
|
|
425
|
-
if (!fnName) {
|
|
426
|
-
return null;
|
|
427
|
-
}
|
|
428
|
-
const metadata2 = {};
|
|
429
|
-
const args = call2.getArguments();
|
|
430
|
-
switch (fnName) {
|
|
431
|
-
case "transitionTo":
|
|
432
|
-
if (args[0]) {
|
|
433
|
-
metadata2.target = resolveClassName(args[0]);
|
|
434
|
-
}
|
|
435
|
-
break;
|
|
436
|
-
case "describe":
|
|
437
|
-
if (args[0] && import_ts_morph.Node.isStringLiteral(args[0])) {
|
|
438
|
-
metadata2.description = args[0].getLiteralValue();
|
|
439
|
-
}
|
|
440
|
-
if (args[1] && import_ts_morph.Node.isCallExpression(args[1])) {
|
|
441
|
-
const nested = extractFromCallExpression(args[1], verbose);
|
|
442
|
-
if (nested) {
|
|
443
|
-
Object.assign(metadata2, nested);
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
break;
|
|
447
|
-
case "guarded":
|
|
448
|
-
if (args[0]) {
|
|
449
|
-
const guard2 = parseObjectLiteral(args[0]);
|
|
450
|
-
if (Object.keys(guard2).length > 0) {
|
|
451
|
-
metadata2.guards = [guard2];
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
if (args[1] && import_ts_morph.Node.isCallExpression(args[1])) {
|
|
455
|
-
const nested = extractFromCallExpression(args[1], verbose);
|
|
456
|
-
if (nested) {
|
|
457
|
-
Object.assign(metadata2, nested);
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
break;
|
|
461
|
-
case "invoke":
|
|
462
|
-
if (args[0]) {
|
|
463
|
-
const service = parseInvokeService(args[0]);
|
|
464
|
-
if (Object.keys(service).length > 0) {
|
|
465
|
-
metadata2.invoke = service;
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
break;
|
|
469
|
-
case "action":
|
|
470
|
-
if (args[0]) {
|
|
471
|
-
const actionMeta = parseObjectLiteral(args[0]);
|
|
472
|
-
if (Object.keys(actionMeta).length > 0) {
|
|
473
|
-
metadata2.actions = [actionMeta];
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
if (args[1] && import_ts_morph.Node.isCallExpression(args[1])) {
|
|
477
|
-
const nested = extractFromCallExpression(args[1], verbose);
|
|
478
|
-
if (nested) {
|
|
479
|
-
Object.assign(metadata2, nested);
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
break;
|
|
483
|
-
case "guard":
|
|
484
|
-
if (args[2]) {
|
|
485
|
-
const options = parseObjectLiteral(args[2]);
|
|
486
|
-
if (options.description) {
|
|
487
|
-
metadata2.description = options.description;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
metadata2.guards = [{ name: "runtime_guard", description: metadata2.description || "Synchronous condition check" }];
|
|
491
|
-
if (args[1] && import_ts_morph.Node.isCallExpression(args[1])) {
|
|
492
|
-
const nested = extractFromCallExpression(args[1], verbose);
|
|
493
|
-
if (nested) {
|
|
494
|
-
Object.assign(metadata2, nested);
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
break;
|
|
498
|
-
case "guardAsync":
|
|
499
|
-
if (args[2]) {
|
|
500
|
-
const options = parseObjectLiteral(args[2]);
|
|
501
|
-
if (options.description) {
|
|
502
|
-
metadata2.description = options.description;
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
metadata2.guards = [{ name: "runtime_guard_async", description: metadata2.description || "Asynchronous condition check" }];
|
|
506
|
-
if (args[1] && import_ts_morph.Node.isCallExpression(args[1])) {
|
|
507
|
-
const nested = extractFromCallExpression(args[1], verbose);
|
|
508
|
-
if (nested) {
|
|
509
|
-
Object.assign(metadata2, nested);
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
break;
|
|
513
|
-
default:
|
|
514
|
-
return null;
|
|
515
|
-
}
|
|
516
|
-
return Object.keys(metadata2).length > 0 ? metadata2 : null;
|
|
433
|
+
function createEnsembleFactory(store, getDiscriminant) {
|
|
434
|
+
return function withFactories(factories) {
|
|
435
|
+
return createEnsemble(store, factories, getDiscriminant);
|
|
436
|
+
};
|
|
517
437
|
}
|
|
518
|
-
function
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
if (!initializer) {
|
|
525
|
-
if (verbose) console.error(` ⚠️ No initializer`);
|
|
526
|
-
return null;
|
|
527
|
-
}
|
|
528
|
-
if (!import_ts_morph.Node.isCallExpression(initializer)) {
|
|
529
|
-
if (verbose) console.error(` ⚠️ Initializer is not a call expression`);
|
|
530
|
-
return null;
|
|
438
|
+
function runWithRunner(flow, initialMachine) {
|
|
439
|
+
const runner = createRunner(initialMachine);
|
|
440
|
+
const generator = flow(runner);
|
|
441
|
+
let result = generator.next();
|
|
442
|
+
while (!result.done) {
|
|
443
|
+
result = generator.next();
|
|
531
444
|
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
445
|
+
return result.value;
|
|
446
|
+
}
|
|
447
|
+
function runWithEnsemble(flow, ensemble) {
|
|
448
|
+
const generator = flow(ensemble);
|
|
449
|
+
let result = generator.next();
|
|
450
|
+
while (!result.done) {
|
|
451
|
+
result = generator.next();
|
|
535
452
|
}
|
|
536
|
-
return
|
|
453
|
+
return result.value;
|
|
537
454
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
}
|
|
545
|
-
return chartNode;
|
|
455
|
+
var MultiMachineBase = class {
|
|
456
|
+
/**
|
|
457
|
+
* @param store - The StateStore that will manage this machine's context.
|
|
458
|
+
*/
|
|
459
|
+
constructor(store) {
|
|
460
|
+
this.store = store;
|
|
546
461
|
}
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
462
|
+
/**
|
|
463
|
+
* Read-only access to the current context from the external store.
|
|
464
|
+
* This getter always returns the latest context from the store.
|
|
465
|
+
*
|
|
466
|
+
* @protected
|
|
467
|
+
*
|
|
468
|
+
* @example
|
|
469
|
+
* const currentStatus = this.context.status;
|
|
470
|
+
* const currentData = this.context.data;
|
|
471
|
+
*/
|
|
472
|
+
get context() {
|
|
473
|
+
return this.store.getContext();
|
|
550
474
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
475
|
+
/**
|
|
476
|
+
* Update the shared context in the external store.
|
|
477
|
+
* Call this method in your transition methods to update the state.
|
|
478
|
+
*
|
|
479
|
+
* @protected
|
|
480
|
+
* @param newContext - The new context object. Should typically be a shallow
|
|
481
|
+
* copy with only the properties you're changing, merged with the current
|
|
482
|
+
* context using spread operators.
|
|
483
|
+
*
|
|
484
|
+
* @example
|
|
485
|
+
* // In a transition method:
|
|
486
|
+
* this.setContext({ ...this.context, status: 'loading' });
|
|
487
|
+
*
|
|
488
|
+
* @example
|
|
489
|
+
* // Updating nested properties:
|
|
490
|
+
* this.setContext({
|
|
491
|
+
* ...this.context,
|
|
492
|
+
* user: { ...this.context.user, name: 'Alice' }
|
|
493
|
+
* });
|
|
494
|
+
*/
|
|
495
|
+
setContext(newContext) {
|
|
496
|
+
this.store.setContext(newContext);
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
function createMultiMachine(MachineClass, store) {
|
|
500
|
+
const instance = new MachineClass(store);
|
|
501
|
+
return new Proxy({}, {
|
|
502
|
+
get(_target, prop) {
|
|
503
|
+
const context = store.getContext();
|
|
504
|
+
if (prop in context) {
|
|
505
|
+
return context[prop];
|
|
578
506
|
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
}
|
|
507
|
+
const method = instance[prop];
|
|
508
|
+
if (typeof method === "function") {
|
|
509
|
+
return (...args) => {
|
|
510
|
+
return method.apply(instance, args);
|
|
511
|
+
};
|
|
584
512
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
513
|
+
return void 0;
|
|
514
|
+
},
|
|
515
|
+
set(_target, prop, value) {
|
|
516
|
+
const context = store.getContext();
|
|
517
|
+
if (prop in context) {
|
|
518
|
+
const newContext = { ...context, [prop]: value };
|
|
519
|
+
store.setContext(newContext);
|
|
520
|
+
return true;
|
|
590
521
|
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
522
|
+
return false;
|
|
523
|
+
},
|
|
524
|
+
has(_target, prop) {
|
|
525
|
+
const context = store.getContext();
|
|
526
|
+
return prop in context || typeof instance[prop] === "function";
|
|
527
|
+
},
|
|
528
|
+
ownKeys(_target) {
|
|
529
|
+
const context = store.getContext();
|
|
530
|
+
const contextKeys = Object.keys(context);
|
|
531
|
+
const methodKeys = Object.getOwnPropertyNames(
|
|
532
|
+
Object.getPrototypeOf(instance)
|
|
533
|
+
).filter((key) => key !== "constructor" && typeof instance[key] === "function");
|
|
534
|
+
return Array.from(/* @__PURE__ */ new Set([...contextKeys, ...methodKeys]));
|
|
535
|
+
},
|
|
536
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
537
|
+
const context = store.getContext();
|
|
538
|
+
if (prop in context || typeof instance[prop] === "function") {
|
|
539
|
+
return {
|
|
540
|
+
value: void 0,
|
|
541
|
+
writable: true,
|
|
542
|
+
enumerable: true,
|
|
543
|
+
configurable: true
|
|
544
|
+
};
|
|
594
545
|
}
|
|
546
|
+
return void 0;
|
|
595
547
|
}
|
|
596
|
-
}
|
|
597
|
-
return chartNode;
|
|
548
|
+
});
|
|
598
549
|
}
|
|
599
|
-
function
|
|
600
|
-
const
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
550
|
+
function createMutableMachine(sharedContext, factories, getDiscriminant) {
|
|
551
|
+
const getCurrentMachine = () => {
|
|
552
|
+
const currentStateName = getDiscriminant(sharedContext);
|
|
553
|
+
const factory = factories[currentStateName];
|
|
554
|
+
if (!factory) {
|
|
555
|
+
throw new Error(
|
|
556
|
+
`[MutableMachine] Invalid state: No factory for state "${String(currentStateName)}".`
|
|
557
|
+
);
|
|
604
558
|
}
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
if (
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
559
|
+
return factory(sharedContext);
|
|
560
|
+
};
|
|
561
|
+
return new Proxy(sharedContext, {
|
|
562
|
+
get(target, prop, _receiver) {
|
|
563
|
+
if (prop in target) {
|
|
564
|
+
return target[prop];
|
|
565
|
+
}
|
|
566
|
+
const currentMachine = getCurrentMachine();
|
|
567
|
+
const transition = currentMachine[prop];
|
|
568
|
+
if (typeof transition === "function") {
|
|
569
|
+
return (...args) => {
|
|
570
|
+
const nextContext = transition.apply(currentMachine.context, args);
|
|
571
|
+
if (typeof nextContext !== "object" || nextContext === null) {
|
|
572
|
+
console.warn(`[MutableMachine] Transition "${String(prop)}" did not return a valid context object. State may be inconsistent.`);
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
Object.keys(target).forEach((key) => delete target[key]);
|
|
576
|
+
Object.assign(target, nextContext);
|
|
577
|
+
};
|
|
614
578
|
}
|
|
579
|
+
return void 0;
|
|
580
|
+
},
|
|
581
|
+
set(target, prop, value, _receiver) {
|
|
582
|
+
target[prop] = value;
|
|
583
|
+
return true;
|
|
584
|
+
},
|
|
585
|
+
has(target, prop) {
|
|
586
|
+
const currentMachine = getCurrentMachine();
|
|
587
|
+
return prop in target || typeof currentMachine[prop] === "function";
|
|
615
588
|
}
|
|
616
|
-
}
|
|
617
|
-
return stateNode;
|
|
589
|
+
});
|
|
618
590
|
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
throw new Error(`Source file not found: ${config.input}`);
|
|
628
|
-
}
|
|
629
|
-
if (config.parallel) {
|
|
630
|
-
if (verbose) {
|
|
631
|
-
console.error(` ⏹️ Parallel machine detected. Analyzing regions.`);
|
|
591
|
+
|
|
592
|
+
// src/higher-order.ts
|
|
593
|
+
function delegateToChild(actionName) {
|
|
594
|
+
return function(...args) {
|
|
595
|
+
const child = this.context.child;
|
|
596
|
+
if (typeof child[actionName] === "function") {
|
|
597
|
+
const newChildState = child[actionName](...args);
|
|
598
|
+
return setContext(this, { ...this.context, child: newChildState });
|
|
632
599
|
}
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
if (
|
|
639
|
-
|
|
600
|
+
return this;
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
function toggle(prop) {
|
|
604
|
+
return function() {
|
|
605
|
+
if (typeof this.context[prop] !== "boolean") {
|
|
606
|
+
console.warn(`[toggle primitive] Property '${String(prop)}' is not a boolean. Toggling may have unexpected results.`);
|
|
640
607
|
}
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
608
|
+
return setContext(this, {
|
|
609
|
+
...this.context,
|
|
610
|
+
[prop]: !this.context[prop]
|
|
611
|
+
});
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
var IdleMachine = class extends MachineBase {
|
|
615
|
+
constructor(config) {
|
|
616
|
+
super({ status: "idle" });
|
|
617
|
+
this.config = config;
|
|
618
|
+
this.fetch = (params) => new LoadingMachine(this.config, params != null ? params : this.config.initialParams, 1);
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
var LoadingMachine = class extends MachineBase {
|
|
622
|
+
constructor(config, params, attempts) {
|
|
623
|
+
super({ status: "loading", abortController: new AbortController(), attempts });
|
|
624
|
+
this.config = config;
|
|
625
|
+
this.params = params;
|
|
626
|
+
this.succeed = (data) => {
|
|
627
|
+
var _a, _b;
|
|
628
|
+
(_b = (_a = this.config).onSuccess) == null ? void 0 : _b.call(_a, data);
|
|
629
|
+
return new SuccessMachine(this.config, { status: "success", data });
|
|
630
|
+
};
|
|
631
|
+
this.fail = (error) => {
|
|
632
|
+
var _a, _b, _c;
|
|
633
|
+
const maxRetries = (_a = this.config.maxRetries) != null ? _a : 3;
|
|
634
|
+
if (this.context.attempts < maxRetries) {
|
|
635
|
+
return new RetryingMachine(this.config, this.params, error, this.context.attempts);
|
|
654
636
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
637
|
+
(_c = (_b = this.config).onError) == null ? void 0 : _c.call(_b, error);
|
|
638
|
+
return new ErrorMachine(this.config, { status: "error", error });
|
|
639
|
+
};
|
|
640
|
+
this.cancel = () => {
|
|
641
|
+
this.context.abortController.abort();
|
|
642
|
+
return new CanceledMachine(this.config);
|
|
643
|
+
};
|
|
644
|
+
this.execute();
|
|
645
|
+
}
|
|
646
|
+
async execute() {
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
var RetryingMachine = class extends MachineBase {
|
|
650
|
+
constructor(config, params, error, attempts) {
|
|
651
|
+
super({ status: "retrying", error, attempts });
|
|
652
|
+
this.config = config;
|
|
653
|
+
this.params = params;
|
|
654
|
+
// This would be called after a delay.
|
|
655
|
+
this.retry = (params) => new LoadingMachine(this.config, params != null ? params : this.params, this.context.attempts + 1);
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
var SuccessMachine = class extends MachineBase {
|
|
659
|
+
constructor(config, context) {
|
|
660
|
+
super(context);
|
|
661
|
+
this.config = config;
|
|
662
|
+
this.refetch = (params) => new LoadingMachine(this.config, params != null ? params : this.config.initialParams, 1);
|
|
663
|
+
}
|
|
664
|
+
};
|
|
665
|
+
var ErrorMachine = class extends MachineBase {
|
|
666
|
+
constructor(config, context) {
|
|
667
|
+
super(context);
|
|
668
|
+
this.config = config;
|
|
669
|
+
this.retry = (params) => new LoadingMachine(this.config, params != null ? params : this.config.initialParams, 1);
|
|
670
|
+
}
|
|
671
|
+
};
|
|
672
|
+
var CanceledMachine = class extends MachineBase {
|
|
673
|
+
constructor(config) {
|
|
674
|
+
super({ status: "canceled" });
|
|
675
|
+
this.config = config;
|
|
676
|
+
this.refetch = (params) => new LoadingMachine(this.config, params != null ? params : this.config.initialParams, 1);
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
function createFetchMachine(config) {
|
|
680
|
+
return new IdleMachine(config);
|
|
681
|
+
}
|
|
682
|
+
function createParallelMachine(m1, m2) {
|
|
683
|
+
const combinedContext = { ...m1.context, ...m2.context };
|
|
684
|
+
const transitions1 = { ...m1 };
|
|
685
|
+
const transitions2 = { ...m2 };
|
|
686
|
+
delete transitions1.context;
|
|
687
|
+
delete transitions2.context;
|
|
688
|
+
const combinedTransitions = {};
|
|
689
|
+
for (const key in transitions1) {
|
|
690
|
+
const transitionFn = transitions1[key];
|
|
691
|
+
combinedTransitions[key] = (...args) => {
|
|
692
|
+
const nextM1 = transitionFn.apply(m1.context, args);
|
|
693
|
+
return createParallelMachine(nextM1, m2);
|
|
694
|
+
};
|
|
664
695
|
}
|
|
665
|
-
|
|
666
|
-
|
|
696
|
+
for (const key in transitions2) {
|
|
697
|
+
const transitionFn = transitions2[key];
|
|
698
|
+
combinedTransitions[key] = (...args) => {
|
|
699
|
+
const nextM2 = transitionFn.apply(m2.context, args);
|
|
700
|
+
return createParallelMachine(m1, nextM2);
|
|
701
|
+
};
|
|
667
702
|
}
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
states: {}
|
|
703
|
+
return {
|
|
704
|
+
context: combinedContext,
|
|
705
|
+
...combinedTransitions
|
|
672
706
|
};
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
continue;
|
|
681
|
-
}
|
|
682
|
-
const classSymbol = classDeclaration.getSymbolOrThrow();
|
|
683
|
-
const hasChildren = className === config.initialState && config.children;
|
|
684
|
-
const stateNode = analyzeStateNodeWithNesting(
|
|
685
|
-
className,
|
|
686
|
-
classSymbol,
|
|
687
|
-
sourceFile,
|
|
688
|
-
hasChildren ? config.children : void 0,
|
|
689
|
-
verbose
|
|
690
|
-
);
|
|
691
|
-
fullChart.states[className] = stateNode;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// src/extract.ts
|
|
710
|
+
var import_ts_morph = require("ts-morph");
|
|
711
|
+
function resolveClassName(node) {
|
|
712
|
+
if (import_ts_morph.Node.isIdentifier(node)) {
|
|
713
|
+
return node.getText();
|
|
692
714
|
}
|
|
693
|
-
if (
|
|
694
|
-
|
|
715
|
+
if (import_ts_morph.Node.isTypeOfExpression(node)) {
|
|
716
|
+
return node.getExpression().getText();
|
|
695
717
|
}
|
|
696
|
-
return
|
|
718
|
+
return "unknown";
|
|
697
719
|
}
|
|
698
|
-
function
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
if (verbose) {
|
|
702
|
-
console.error(`
|
|
703
|
-
📊 Starting statechart extraction`);
|
|
704
|
-
console.error(` Machines to extract: ${config.machines.length}`);
|
|
720
|
+
function parseObjectLiteral(obj) {
|
|
721
|
+
if (!import_ts_morph.Node.isObjectLiteralExpression(obj)) {
|
|
722
|
+
return {};
|
|
705
723
|
}
|
|
706
|
-
const
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
724
|
+
const result = {};
|
|
725
|
+
for (const prop of obj.getProperties()) {
|
|
726
|
+
if (import_ts_morph.Node.isPropertyAssignment(prop)) {
|
|
727
|
+
const name = prop.getName();
|
|
728
|
+
const init = prop.getInitializer();
|
|
729
|
+
if (init) {
|
|
730
|
+
if (import_ts_morph.Node.isStringLiteral(init)) {
|
|
731
|
+
result[name] = init.getLiteralValue();
|
|
732
|
+
} else if (import_ts_morph.Node.isNumericLiteral(init)) {
|
|
733
|
+
result[name] = init.getLiteralValue();
|
|
734
|
+
} else if (init.getText() === "true" || init.getText() === "false") {
|
|
735
|
+
result[name] = init.getText() === "true";
|
|
736
|
+
} else if (import_ts_morph.Node.isIdentifier(init)) {
|
|
737
|
+
result[name] = init.getText();
|
|
738
|
+
} else if (import_ts_morph.Node.isObjectLiteralExpression(init)) {
|
|
739
|
+
result[name] = parseObjectLiteral(init);
|
|
740
|
+
} else if (import_ts_morph.Node.isArrayLiteralExpression(init)) {
|
|
741
|
+
result[name] = init.getElements().map((el) => {
|
|
742
|
+
if (import_ts_morph.Node.isObjectLiteralExpression(el)) {
|
|
743
|
+
return parseObjectLiteral(el);
|
|
744
|
+
}
|
|
745
|
+
return el.getText();
|
|
746
|
+
});
|
|
747
|
+
}
|
|
718
748
|
}
|
|
719
749
|
}
|
|
720
750
|
}
|
|
721
|
-
|
|
722
|
-
console.error(`
|
|
723
|
-
✅ Extraction complete: ${results.length}/${config.machines.length} machines extracted`);
|
|
724
|
-
}
|
|
725
|
-
return results;
|
|
751
|
+
return result;
|
|
726
752
|
}
|
|
727
|
-
function
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
classes: [
|
|
731
|
-
"LoggedOutMachine",
|
|
732
|
-
"LoggingInMachine",
|
|
733
|
-
"LoggedInMachine",
|
|
734
|
-
"SessionExpiredMachine",
|
|
735
|
-
"ErrorMachine"
|
|
736
|
-
],
|
|
737
|
-
id: "auth",
|
|
738
|
-
initialState: "LoggedOutMachine",
|
|
739
|
-
description: "Authentication state machine"
|
|
740
|
-
};
|
|
741
|
-
console.error("🔍 Using legacy generateChart function");
|
|
742
|
-
console.error("⚠️ Consider using extractMachines() with a config file instead\n");
|
|
743
|
-
const project = new import_ts_morph.Project();
|
|
744
|
-
project.addSourceFilesAtPaths("src/**/*.ts");
|
|
745
|
-
project.addSourceFilesAtPaths("examples/**/*.ts");
|
|
746
|
-
try {
|
|
747
|
-
const chart = extractMachine(config, project, true);
|
|
748
|
-
console.log(JSON.stringify(chart, null, 2));
|
|
749
|
-
} catch (error) {
|
|
750
|
-
console.error(`❌ Error:`, error);
|
|
751
|
-
process.exit(1);
|
|
753
|
+
function parseInvokeService(obj) {
|
|
754
|
+
if (!import_ts_morph.Node.isObjectLiteralExpression(obj)) {
|
|
755
|
+
return {};
|
|
752
756
|
}
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
parallel: {
|
|
767
|
-
input: "examples/editorMachine.ts",
|
|
768
|
-
id: "editor",
|
|
769
|
-
parallel: {
|
|
770
|
-
regions: [
|
|
771
|
-
{
|
|
772
|
-
name: "fontWeight",
|
|
773
|
-
initialState: "NormalWeight",
|
|
774
|
-
classes: ["NormalWeight", "BoldWeight"]
|
|
775
|
-
},
|
|
776
|
-
{
|
|
777
|
-
name: "textDecoration",
|
|
778
|
-
initialState: "NoDecoration",
|
|
779
|
-
classes: ["NoDecoration", "UnderlineState"]
|
|
780
|
-
}
|
|
781
|
-
]
|
|
757
|
+
const service = {};
|
|
758
|
+
for (const prop of obj.getProperties()) {
|
|
759
|
+
if (import_ts_morph.Node.isPropertyAssignment(prop)) {
|
|
760
|
+
const name = prop.getName();
|
|
761
|
+
const init = prop.getInitializer();
|
|
762
|
+
if (!init) continue;
|
|
763
|
+
if (name === "onDone" || name === "onError") {
|
|
764
|
+
service[name] = resolveClassName(init);
|
|
765
|
+
} else if (import_ts_morph.Node.isStringLiteral(init)) {
|
|
766
|
+
service[name] = init.getLiteralValue();
|
|
767
|
+
} else if (import_ts_morph.Node.isIdentifier(init)) {
|
|
768
|
+
service[name] = init.getText();
|
|
769
|
+
}
|
|
782
770
|
}
|
|
783
771
|
}
|
|
784
|
-
|
|
785
|
-
if (require.main === module) {
|
|
786
|
-
generateChart();
|
|
772
|
+
return service;
|
|
787
773
|
}
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
function extractFunctionMetadata(fn) {
|
|
791
|
-
if (typeof fn !== "function") {
|
|
774
|
+
function extractFromCallExpression(call2, verbose = false) {
|
|
775
|
+
if (!import_ts_morph.Node.isCallExpression(call2)) {
|
|
792
776
|
return null;
|
|
793
777
|
}
|
|
794
|
-
const
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
const
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
if (
|
|
820
|
-
|
|
778
|
+
const expression = call2.getExpression();
|
|
779
|
+
const fnName = import_ts_morph.Node.isIdentifier(expression) ? expression.getText() : null;
|
|
780
|
+
if (!fnName) {
|
|
781
|
+
return null;
|
|
782
|
+
}
|
|
783
|
+
const metadata2 = {};
|
|
784
|
+
const args = call2.getArguments();
|
|
785
|
+
switch (fnName) {
|
|
786
|
+
case "transitionTo":
|
|
787
|
+
if (args[0]) {
|
|
788
|
+
metadata2.target = resolveClassName(args[0]);
|
|
789
|
+
}
|
|
790
|
+
break;
|
|
791
|
+
case "describe":
|
|
792
|
+
if (args[0] && import_ts_morph.Node.isStringLiteral(args[0])) {
|
|
793
|
+
metadata2.description = args[0].getLiteralValue();
|
|
794
|
+
}
|
|
795
|
+
if (args[1] && import_ts_morph.Node.isCallExpression(args[1])) {
|
|
796
|
+
const nested = extractFromCallExpression(args[1], verbose);
|
|
797
|
+
if (nested) {
|
|
798
|
+
Object.assign(metadata2, nested);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
break;
|
|
802
|
+
case "guarded":
|
|
803
|
+
if (args[0]) {
|
|
804
|
+
const guard2 = parseObjectLiteral(args[0]);
|
|
805
|
+
if (Object.keys(guard2).length > 0) {
|
|
806
|
+
metadata2.guards = [guard2];
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
if (args[1] && import_ts_morph.Node.isCallExpression(args[1])) {
|
|
810
|
+
const nested = extractFromCallExpression(args[1], verbose);
|
|
811
|
+
if (nested) {
|
|
812
|
+
Object.assign(metadata2, nested);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
break;
|
|
816
|
+
case "invoke":
|
|
817
|
+
if (args[0]) {
|
|
818
|
+
const service = parseInvokeService(args[0]);
|
|
819
|
+
if (Object.keys(service).length > 0) {
|
|
820
|
+
metadata2.invoke = service;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
break;
|
|
824
|
+
case "action":
|
|
825
|
+
if (args[0]) {
|
|
826
|
+
const actionMeta = parseObjectLiteral(args[0]);
|
|
827
|
+
if (Object.keys(actionMeta).length > 0) {
|
|
828
|
+
metadata2.actions = [actionMeta];
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
if (args[1] && import_ts_morph.Node.isCallExpression(args[1])) {
|
|
832
|
+
const nested = extractFromCallExpression(args[1], verbose);
|
|
833
|
+
if (nested) {
|
|
834
|
+
Object.assign(metadata2, nested);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
break;
|
|
838
|
+
case "guard":
|
|
839
|
+
if (args[2]) {
|
|
840
|
+
const options = parseObjectLiteral(args[2]);
|
|
841
|
+
if (options.description) {
|
|
842
|
+
metadata2.description = options.description;
|
|
843
|
+
}
|
|
821
844
|
}
|
|
822
|
-
|
|
823
|
-
|
|
845
|
+
metadata2.guards = [{ name: "runtime_guard", description: metadata2.description || "Synchronous condition check" }];
|
|
846
|
+
if (args[1] && import_ts_morph.Node.isCallExpression(args[1])) {
|
|
847
|
+
const nested = extractFromCallExpression(args[1], verbose);
|
|
848
|
+
if (nested) {
|
|
849
|
+
Object.assign(metadata2, nested);
|
|
850
|
+
}
|
|
824
851
|
}
|
|
825
|
-
|
|
826
|
-
|
|
852
|
+
break;
|
|
853
|
+
case "guardAsync":
|
|
854
|
+
if (args[2]) {
|
|
855
|
+
const options = parseObjectLiteral(args[2]);
|
|
856
|
+
if (options.description) {
|
|
857
|
+
metadata2.description = options.description;
|
|
858
|
+
}
|
|
827
859
|
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
};
|
|
835
|
-
if (meta.description) {
|
|
836
|
-
transition.description = meta.description;
|
|
860
|
+
metadata2.guards = [{ name: "runtime_guard_async", description: metadata2.description || "Asynchronous condition check" }];
|
|
861
|
+
if (args[1] && import_ts_morph.Node.isCallExpression(args[1])) {
|
|
862
|
+
const nested = extractFromCallExpression(args[1], verbose);
|
|
863
|
+
if (nested) {
|
|
864
|
+
Object.assign(metadata2, nested);
|
|
865
|
+
}
|
|
837
866
|
}
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
if (invoke2.length > 0) {
|
|
842
|
-
stateNode.invoke = invoke2;
|
|
867
|
+
break;
|
|
868
|
+
default:
|
|
869
|
+
return null;
|
|
843
870
|
}
|
|
844
|
-
return
|
|
871
|
+
return Object.keys(metadata2).length > 0 ? metadata2 : null;
|
|
845
872
|
}
|
|
846
|
-
function
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
states: {}
|
|
851
|
-
};
|
|
852
|
-
if (config.description) {
|
|
853
|
-
chart.description = config.description;
|
|
873
|
+
function extractMetaFromMember(member, verbose = false) {
|
|
874
|
+
if (!import_ts_morph.Node.isPropertyDeclaration(member)) {
|
|
875
|
+
if (verbose) console.error(` ⚠️ Not a property declaration`);
|
|
876
|
+
return null;
|
|
854
877
|
}
|
|
855
|
-
|
|
856
|
-
|
|
878
|
+
const initializer = member.getInitializer();
|
|
879
|
+
if (!initializer) {
|
|
880
|
+
if (verbose) console.error(` ⚠️ No initializer`);
|
|
881
|
+
return null;
|
|
857
882
|
}
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
const stateName = config.stateName || machineInstance.constructor.name || "State";
|
|
862
|
-
return {
|
|
863
|
-
id: config.id,
|
|
864
|
-
initial: stateName,
|
|
865
|
-
states: {
|
|
866
|
-
[stateName]: extractStateNode(machineInstance)
|
|
867
|
-
}
|
|
868
|
-
};
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
// src/multi.ts
|
|
872
|
-
function createRunner(initialMachine, onChange) {
|
|
873
|
-
let currentMachine = initialMachine;
|
|
874
|
-
const setState = (newState) => {
|
|
875
|
-
currentMachine = newState;
|
|
876
|
-
onChange == null ? void 0 : onChange(newState);
|
|
877
|
-
};
|
|
878
|
-
const { context: _initialContext, ...originalTransitions } = initialMachine;
|
|
879
|
-
const actions = new Proxy({}, {
|
|
880
|
-
get(_target, prop) {
|
|
881
|
-
const transition = currentMachine[prop];
|
|
882
|
-
if (typeof transition !== "function") {
|
|
883
|
-
return void 0;
|
|
884
|
-
}
|
|
885
|
-
return (...args) => {
|
|
886
|
-
const nextState = transition.apply(currentMachine.context, args);
|
|
887
|
-
const nextStateWithTransitions = Object.assign(
|
|
888
|
-
{ context: nextState.context },
|
|
889
|
-
originalTransitions
|
|
890
|
-
);
|
|
891
|
-
setState(nextStateWithTransitions);
|
|
892
|
-
return nextStateWithTransitions;
|
|
893
|
-
};
|
|
894
|
-
}
|
|
895
|
-
});
|
|
896
|
-
return {
|
|
897
|
-
get state() {
|
|
898
|
-
return currentMachine;
|
|
899
|
-
},
|
|
900
|
-
get context() {
|
|
901
|
-
return currentMachine.context;
|
|
902
|
-
},
|
|
903
|
-
actions,
|
|
904
|
-
setState
|
|
905
|
-
};
|
|
906
|
-
}
|
|
907
|
-
function createEnsemble(store, factories, getDiscriminant) {
|
|
908
|
-
const getCurrentMachine = () => {
|
|
909
|
-
const context = store.getContext();
|
|
910
|
-
const currentStateName = getDiscriminant(context);
|
|
911
|
-
const factory = factories[currentStateName];
|
|
912
|
-
if (!factory) {
|
|
913
|
-
throw new Error(
|
|
914
|
-
`[Ensemble] Invalid state: No factory found for state "${String(currentStateName)}".`
|
|
915
|
-
);
|
|
916
|
-
}
|
|
917
|
-
return factory(context);
|
|
918
|
-
};
|
|
919
|
-
const actions = new Proxy({}, {
|
|
920
|
-
get(_target, prop) {
|
|
921
|
-
const currentMachine = getCurrentMachine();
|
|
922
|
-
const action2 = currentMachine[prop];
|
|
923
|
-
if (typeof action2 !== "function") {
|
|
924
|
-
throw new Error(
|
|
925
|
-
`[Ensemble] Transition "${prop}" is not valid in the current state.`
|
|
926
|
-
);
|
|
927
|
-
}
|
|
928
|
-
return (...args) => {
|
|
929
|
-
return action2.apply(currentMachine.context, args);
|
|
930
|
-
};
|
|
931
|
-
}
|
|
932
|
-
});
|
|
933
|
-
return {
|
|
934
|
-
get context() {
|
|
935
|
-
return store.getContext();
|
|
936
|
-
},
|
|
937
|
-
get state() {
|
|
938
|
-
return getCurrentMachine();
|
|
939
|
-
},
|
|
940
|
-
actions
|
|
941
|
-
};
|
|
942
|
-
}
|
|
943
|
-
function createEnsembleFactory(store, getDiscriminant) {
|
|
944
|
-
return function withFactories(factories) {
|
|
945
|
-
return createEnsemble(store, factories, getDiscriminant);
|
|
946
|
-
};
|
|
947
|
-
}
|
|
948
|
-
function runWithRunner(flow, initialMachine) {
|
|
949
|
-
const runner = createRunner(initialMachine);
|
|
950
|
-
const generator = flow(runner);
|
|
951
|
-
let result = generator.next();
|
|
952
|
-
while (!result.done) {
|
|
953
|
-
result = generator.next();
|
|
883
|
+
if (!import_ts_morph.Node.isCallExpression(initializer)) {
|
|
884
|
+
if (verbose) console.error(` ⚠️ Initializer is not a call expression`);
|
|
885
|
+
return null;
|
|
954
886
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
const generator = flow(ensemble);
|
|
959
|
-
let result = generator.next();
|
|
960
|
-
while (!result.done) {
|
|
961
|
-
result = generator.next();
|
|
887
|
+
const metadata2 = extractFromCallExpression(initializer, verbose);
|
|
888
|
+
if (metadata2 && verbose) {
|
|
889
|
+
console.error(` ✅ Extracted metadata:`, JSON.stringify(metadata2, null, 2));
|
|
962
890
|
}
|
|
963
|
-
return
|
|
891
|
+
return metadata2;
|
|
964
892
|
}
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
* Read-only access to the current context from the external store.
|
|
974
|
-
* This getter always returns the latest context from the store.
|
|
975
|
-
*
|
|
976
|
-
* @protected
|
|
977
|
-
*
|
|
978
|
-
* @example
|
|
979
|
-
* const currentStatus = this.context.status;
|
|
980
|
-
* const currentData = this.context.data;
|
|
981
|
-
*/
|
|
982
|
-
get context() {
|
|
983
|
-
return this.store.getContext();
|
|
893
|
+
function analyzeStateNode(classSymbol, verbose = false) {
|
|
894
|
+
const chartNode = { on: {} };
|
|
895
|
+
const classDeclaration = classSymbol.getDeclarations()[0];
|
|
896
|
+
if (!classDeclaration || !import_ts_morph.Node.isClassDeclaration(classDeclaration)) {
|
|
897
|
+
if (verbose) {
|
|
898
|
+
console.error(`⚠️ Warning: Could not get class declaration for ${classSymbol.getName()}`);
|
|
899
|
+
}
|
|
900
|
+
return chartNode;
|
|
984
901
|
}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
*
|
|
989
|
-
* @protected
|
|
990
|
-
* @param newContext - The new context object. Should typically be a shallow
|
|
991
|
-
* copy with only the properties you're changing, merged with the current
|
|
992
|
-
* context using spread operators.
|
|
993
|
-
*
|
|
994
|
-
* @example
|
|
995
|
-
* // In a transition method:
|
|
996
|
-
* this.setContext({ ...this.context, status: 'loading' });
|
|
997
|
-
*
|
|
998
|
-
* @example
|
|
999
|
-
* // Updating nested properties:
|
|
1000
|
-
* this.setContext({
|
|
1001
|
-
* ...this.context,
|
|
1002
|
-
* user: { ...this.context.user, name: 'Alice' }
|
|
1003
|
-
* });
|
|
1004
|
-
*/
|
|
1005
|
-
setContext(newContext) {
|
|
1006
|
-
this.store.setContext(newContext);
|
|
902
|
+
const className = classSymbol.getName();
|
|
903
|
+
if (verbose) {
|
|
904
|
+
console.error(` Analyzing state: ${className}`);
|
|
1007
905
|
}
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
if (
|
|
1028
|
-
|
|
1029
|
-
store.setContext(newContext);
|
|
1030
|
-
return true;
|
|
1031
|
-
}
|
|
1032
|
-
return false;
|
|
1033
|
-
},
|
|
1034
|
-
has(_target, prop) {
|
|
1035
|
-
const context = store.getContext();
|
|
1036
|
-
return prop in context || typeof instance[prop] === "function";
|
|
1037
|
-
},
|
|
1038
|
-
ownKeys(_target) {
|
|
1039
|
-
const context = store.getContext();
|
|
1040
|
-
const contextKeys = Object.keys(context);
|
|
1041
|
-
const methodKeys = Object.getOwnPropertyNames(
|
|
1042
|
-
Object.getPrototypeOf(instance)
|
|
1043
|
-
).filter((key) => key !== "constructor" && typeof instance[key] === "function");
|
|
1044
|
-
return Array.from(/* @__PURE__ */ new Set([...contextKeys, ...methodKeys]));
|
|
1045
|
-
},
|
|
1046
|
-
getOwnPropertyDescriptor(_target, prop) {
|
|
1047
|
-
const context = store.getContext();
|
|
1048
|
-
if (prop in context || typeof instance[prop] === "function") {
|
|
1049
|
-
return {
|
|
1050
|
-
value: void 0,
|
|
1051
|
-
writable: true,
|
|
1052
|
-
enumerable: true,
|
|
1053
|
-
configurable: true
|
|
1054
|
-
};
|
|
906
|
+
for (const member of classDeclaration.getInstanceMembers()) {
|
|
907
|
+
const memberName = member.getName();
|
|
908
|
+
if (verbose) {
|
|
909
|
+
console.error(` Checking member: ${memberName}`);
|
|
910
|
+
}
|
|
911
|
+
const meta = extractMetaFromMember(member, verbose);
|
|
912
|
+
if (!meta) continue;
|
|
913
|
+
if (verbose) {
|
|
914
|
+
console.error(` Found transition: ${memberName}`);
|
|
915
|
+
}
|
|
916
|
+
const { invoke: invoke2, actions, guards, ...onEntry } = meta;
|
|
917
|
+
if (invoke2) {
|
|
918
|
+
if (!chartNode.invoke) chartNode.invoke = [];
|
|
919
|
+
chartNode.invoke.push({
|
|
920
|
+
src: invoke2.src,
|
|
921
|
+
onDone: { target: invoke2.onDone },
|
|
922
|
+
onError: { target: invoke2.onError },
|
|
923
|
+
description: invoke2.description
|
|
924
|
+
});
|
|
925
|
+
if (verbose) {
|
|
926
|
+
console.error(` → Invoke: ${invoke2.src}`);
|
|
1055
927
|
}
|
|
1056
|
-
return void 0;
|
|
1057
|
-
}
|
|
1058
|
-
});
|
|
1059
|
-
}
|
|
1060
|
-
function createMutableMachine(sharedContext, factories, getDiscriminant) {
|
|
1061
|
-
const getCurrentMachine = () => {
|
|
1062
|
-
const currentStateName = getDiscriminant(sharedContext);
|
|
1063
|
-
const factory = factories[currentStateName];
|
|
1064
|
-
if (!factory) {
|
|
1065
|
-
throw new Error(
|
|
1066
|
-
`[MutableMachine] Invalid state: No factory for state "${String(currentStateName)}".`
|
|
1067
|
-
);
|
|
1068
928
|
}
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
if (prop in target) {
|
|
1074
|
-
return target[prop];
|
|
929
|
+
if (onEntry.target) {
|
|
930
|
+
const transition = { target: onEntry.target };
|
|
931
|
+
if (onEntry.description) {
|
|
932
|
+
transition.description = onEntry.description;
|
|
1075
933
|
}
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
934
|
+
if (guards) {
|
|
935
|
+
transition.cond = guards.map((g) => g.name).join(" && ");
|
|
936
|
+
if (verbose) {
|
|
937
|
+
console.error(` → Guard: ${transition.cond}`);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
if (actions && actions.length > 0) {
|
|
941
|
+
transition.actions = actions.map((a) => a.name);
|
|
942
|
+
if (verbose) {
|
|
943
|
+
console.error(` → Actions: ${transition.actions.join(", ")}`);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
chartNode.on[memberName] = transition;
|
|
947
|
+
if (verbose) {
|
|
948
|
+
console.error(` → Target: ${onEntry.target}`);
|
|
1088
949
|
}
|
|
1089
|
-
return void 0;
|
|
1090
|
-
},
|
|
1091
|
-
set(target, prop, value, _receiver) {
|
|
1092
|
-
target[prop] = value;
|
|
1093
|
-
return true;
|
|
1094
|
-
},
|
|
1095
|
-
has(target, prop) {
|
|
1096
|
-
const currentMachine = getCurrentMachine();
|
|
1097
|
-
return prop in target || typeof currentMachine[prop] === "function";
|
|
1098
950
|
}
|
|
1099
|
-
}
|
|
951
|
+
}
|
|
952
|
+
return chartNode;
|
|
1100
953
|
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
if (typeof child[actionName] === "function") {
|
|
1107
|
-
const newChildState = child[actionName](...args);
|
|
1108
|
-
return setContext(this, { ...this.context, child: newChildState });
|
|
954
|
+
function analyzeStateNodeWithNesting(className, classSymbol, sourceFile, childConfig, verbose = false) {
|
|
955
|
+
const stateNode = analyzeStateNode(classSymbol, verbose);
|
|
956
|
+
if (childConfig) {
|
|
957
|
+
if (verbose) {
|
|
958
|
+
console.error(` 👪 Analyzing children for state: ${className}`);
|
|
1109
959
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
960
|
+
stateNode.initial = childConfig.initialState;
|
|
961
|
+
stateNode.states = {};
|
|
962
|
+
for (const childClassName of childConfig.classes) {
|
|
963
|
+
const childClassDeclaration = sourceFile.getClass(childClassName);
|
|
964
|
+
if (childClassDeclaration) {
|
|
965
|
+
const childSymbol = childClassDeclaration.getSymbolOrThrow();
|
|
966
|
+
stateNode.states[childClassName] = analyzeStateNode(childSymbol, verbose);
|
|
967
|
+
} else {
|
|
968
|
+
console.warn(`⚠️ Warning: Child class '${childClassName}' not found.`);
|
|
969
|
+
}
|
|
1117
970
|
}
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
[prop]: !this.context[prop]
|
|
1121
|
-
});
|
|
1122
|
-
};
|
|
971
|
+
}
|
|
972
|
+
return stateNode;
|
|
1123
973
|
}
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
974
|
+
function extractMachine(config, project, verbose = false) {
|
|
975
|
+
if (verbose) {
|
|
976
|
+
console.error(`
|
|
977
|
+
🔍 Analyzing machine: ${config.id}`);
|
|
978
|
+
console.error(` Source: ${config.input}`);
|
|
1129
979
|
}
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
980
|
+
const sourceFile = project.getSourceFile(config.input);
|
|
981
|
+
if (!sourceFile) {
|
|
982
|
+
throw new Error(`Source file not found: ${config.input}`);
|
|
983
|
+
}
|
|
984
|
+
if (config.parallel) {
|
|
985
|
+
if (verbose) {
|
|
986
|
+
console.error(` ⏹️ Parallel machine detected. Analyzing regions.`);
|
|
987
|
+
}
|
|
988
|
+
const parallelChart = {
|
|
989
|
+
id: config.id,
|
|
990
|
+
type: "parallel",
|
|
991
|
+
states: {}
|
|
1140
992
|
};
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
993
|
+
if (config.description) {
|
|
994
|
+
parallelChart.description = config.description;
|
|
995
|
+
}
|
|
996
|
+
for (const region of config.parallel.regions) {
|
|
997
|
+
if (verbose) {
|
|
998
|
+
console.error(` 📍 Analyzing region: ${region.name}`);
|
|
1146
999
|
}
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1000
|
+
const regionStates = {};
|
|
1001
|
+
for (const className of region.classes) {
|
|
1002
|
+
const classDeclaration = sourceFile.getClass(className);
|
|
1003
|
+
if (classDeclaration) {
|
|
1004
|
+
const classSymbol = classDeclaration.getSymbolOrThrow();
|
|
1005
|
+
regionStates[className] = analyzeStateNode(classSymbol, verbose);
|
|
1006
|
+
} else {
|
|
1007
|
+
console.warn(`⚠️ Warning: Class '${className}' not found for region '${region.name}'.`);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
parallelChart.states[region.name] = {
|
|
1011
|
+
initial: region.initialState,
|
|
1012
|
+
states: regionStates
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
if (verbose) {
|
|
1016
|
+
console.error(` ✅ Extracted ${config.parallel.regions.length} parallel regions`);
|
|
1017
|
+
}
|
|
1018
|
+
return parallelChart;
|
|
1155
1019
|
}
|
|
1156
|
-
|
|
1020
|
+
if (!config.initialState || !config.classes) {
|
|
1021
|
+
throw new Error(`Machine config for '${config.id}' must have either 'parallel' or 'initialState'/'classes'.`);
|
|
1157
1022
|
}
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
this.retry = (params) => new LoadingMachine(this.config, params != null ? params : this.params, this.context.attempts + 1);
|
|
1023
|
+
const fullChart = {
|
|
1024
|
+
id: config.id,
|
|
1025
|
+
initial: config.initialState,
|
|
1026
|
+
states: {}
|
|
1027
|
+
};
|
|
1028
|
+
if (config.description) {
|
|
1029
|
+
fullChart.description = config.description;
|
|
1166
1030
|
}
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1031
|
+
for (const className of config.classes) {
|
|
1032
|
+
const classDeclaration = sourceFile.getClass(className);
|
|
1033
|
+
if (!classDeclaration) {
|
|
1034
|
+
console.warn(`⚠️ Warning: Class '${className}' not found in '${config.input}'. Skipping.`);
|
|
1035
|
+
continue;
|
|
1036
|
+
}
|
|
1037
|
+
const classSymbol = classDeclaration.getSymbolOrThrow();
|
|
1038
|
+
const hasChildren = className === config.initialState && config.children;
|
|
1039
|
+
const stateNode = analyzeStateNodeWithNesting(
|
|
1040
|
+
className,
|
|
1041
|
+
classSymbol,
|
|
1042
|
+
sourceFile,
|
|
1043
|
+
hasChildren ? config.children : void 0,
|
|
1044
|
+
verbose
|
|
1045
|
+
);
|
|
1046
|
+
fullChart.states[className] = stateNode;
|
|
1173
1047
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
constructor(config, context) {
|
|
1177
|
-
super(context);
|
|
1178
|
-
this.config = config;
|
|
1179
|
-
this.retry = (params) => new LoadingMachine(this.config, params != null ? params : this.config.initialParams, 1);
|
|
1048
|
+
if (verbose) {
|
|
1049
|
+
console.error(` ✅ Extracted ${config.classes.length} states`);
|
|
1180
1050
|
}
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1051
|
+
return fullChart;
|
|
1052
|
+
}
|
|
1053
|
+
function extractMachines(config) {
|
|
1054
|
+
var _a;
|
|
1055
|
+
const verbose = (_a = config.verbose) != null ? _a : false;
|
|
1056
|
+
if (verbose) {
|
|
1057
|
+
console.error(`
|
|
1058
|
+
📊 Starting statechart extraction`);
|
|
1059
|
+
console.error(` Machines to extract: ${config.machines.length}`);
|
|
1060
|
+
}
|
|
1061
|
+
const project = new import_ts_morph.Project();
|
|
1062
|
+
project.addSourceFilesAtPaths("src/**/*.ts");
|
|
1063
|
+
project.addSourceFilesAtPaths("examples/**/*.ts");
|
|
1064
|
+
const results = [];
|
|
1065
|
+
for (const machineConfig of config.machines) {
|
|
1066
|
+
try {
|
|
1067
|
+
const chart = extractMachine(machineConfig, project, verbose);
|
|
1068
|
+
results.push(chart);
|
|
1069
|
+
} catch (error) {
|
|
1070
|
+
console.error(`❌ Error extracting machine '${machineConfig.id}':`, error);
|
|
1071
|
+
if (!verbose) {
|
|
1072
|
+
console.error(` Run with --verbose for more details`);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
if (verbose) {
|
|
1077
|
+
console.error(`
|
|
1078
|
+
✅ Extraction complete: ${results.length}/${config.machines.length} machines extracted`);
|
|
1187
1079
|
}
|
|
1188
|
-
|
|
1189
|
-
function createFetchMachine(config) {
|
|
1190
|
-
return new IdleMachine(config);
|
|
1080
|
+
return results;
|
|
1191
1081
|
}
|
|
1192
|
-
function
|
|
1193
|
-
const
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1082
|
+
function generateChart() {
|
|
1083
|
+
const config = {
|
|
1084
|
+
input: "examples/authMachine.ts",
|
|
1085
|
+
classes: [
|
|
1086
|
+
"LoggedOutMachine",
|
|
1087
|
+
"LoggingInMachine",
|
|
1088
|
+
"LoggedInMachine",
|
|
1089
|
+
"SessionExpiredMachine",
|
|
1090
|
+
"ErrorMachine"
|
|
1091
|
+
],
|
|
1092
|
+
id: "auth",
|
|
1093
|
+
initialState: "LoggedOutMachine",
|
|
1094
|
+
description: "Authentication state machine"
|
|
1095
|
+
};
|
|
1096
|
+
console.error("🔍 Using legacy generateChart function");
|
|
1097
|
+
console.error("⚠️ Consider using extractMachines() with a config file instead\n");
|
|
1098
|
+
const project = new import_ts_morph.Project();
|
|
1099
|
+
project.addSourceFilesAtPaths("src/**/*.ts");
|
|
1100
|
+
project.addSourceFilesAtPaths("examples/**/*.ts");
|
|
1101
|
+
try {
|
|
1102
|
+
const chart = extractMachine(config, project, true);
|
|
1103
|
+
console.log(JSON.stringify(chart, null, 2));
|
|
1104
|
+
} catch (error) {
|
|
1105
|
+
console.error(`❌ Error:`, error);
|
|
1106
|
+
process.exit(1);
|
|
1205
1107
|
}
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1108
|
+
}
|
|
1109
|
+
var ADVANCED_CONFIG_EXAMPLES = {
|
|
1110
|
+
hierarchical: {
|
|
1111
|
+
input: "examples/dashboardMachine.ts",
|
|
1112
|
+
id: "dashboard",
|
|
1113
|
+
classes: ["DashboardMachine", "LoggedOutMachine"],
|
|
1114
|
+
initialState: "DashboardMachine",
|
|
1115
|
+
children: {
|
|
1116
|
+
contextProperty: "child",
|
|
1117
|
+
initialState: "ViewingChildMachine",
|
|
1118
|
+
classes: ["ViewingChildMachine", "EditingChildMachine"]
|
|
1119
|
+
}
|
|
1120
|
+
},
|
|
1121
|
+
parallel: {
|
|
1122
|
+
input: "examples/editorMachine.ts",
|
|
1123
|
+
id: "editor",
|
|
1124
|
+
parallel: {
|
|
1125
|
+
regions: [
|
|
1126
|
+
{
|
|
1127
|
+
name: "fontWeight",
|
|
1128
|
+
initialState: "NormalWeight",
|
|
1129
|
+
classes: ["NormalWeight", "BoldWeight"]
|
|
1130
|
+
},
|
|
1131
|
+
{
|
|
1132
|
+
name: "textDecoration",
|
|
1133
|
+
initialState: "NoDecoration",
|
|
1134
|
+
classes: ["NoDecoration", "UnderlineState"]
|
|
1135
|
+
}
|
|
1136
|
+
]
|
|
1137
|
+
}
|
|
1212
1138
|
}
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
};
|
|
1139
|
+
};
|
|
1140
|
+
if (require.main === module) {
|
|
1141
|
+
generateChart();
|
|
1217
1142
|
}
|
|
1218
1143
|
|
|
1219
|
-
// src/middleware.ts
|
|
1144
|
+
// src/middleware/core.ts
|
|
1220
1145
|
var CANCEL = Symbol("CANCEL");
|
|
1221
1146
|
function createMiddleware(machine, hooks, options = {}) {
|
|
1222
|
-
const {
|
|
1223
|
-
const
|
|
1147
|
+
const { continueOnError = false, logErrors = true, onError } = options;
|
|
1148
|
+
const wrappedMachine = { ...machine };
|
|
1224
1149
|
for (const prop in machine) {
|
|
1225
1150
|
if (!Object.prototype.hasOwnProperty.call(machine, prop)) continue;
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
wrapped.context = value;
|
|
1229
|
-
continue;
|
|
1151
|
+
if (prop !== "context" && typeof machine[prop] !== "function") {
|
|
1152
|
+
wrappedMachine[prop] = machine[prop];
|
|
1230
1153
|
}
|
|
1231
|
-
if (exclude.includes(prop)) {
|
|
1232
|
-
wrapped[prop] = value;
|
|
1233
|
-
continue;
|
|
1234
|
-
}
|
|
1235
|
-
if (typeof value !== "function" || prop.startsWith("_")) {
|
|
1236
|
-
wrapped[prop] = value;
|
|
1237
|
-
continue;
|
|
1238
|
-
}
|
|
1239
|
-
wrapped[prop] = createTransitionWrapper(
|
|
1240
|
-
prop,
|
|
1241
|
-
value,
|
|
1242
|
-
machine,
|
|
1243
|
-
hooks,
|
|
1244
|
-
mode
|
|
1245
|
-
);
|
|
1246
1154
|
}
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
if (hooks.after) {
|
|
1275
|
-
const middlewareResult = {
|
|
1276
|
-
transitionName,
|
|
1277
|
-
prevContext: context,
|
|
1278
|
-
nextContext: result.context,
|
|
1279
|
-
args
|
|
1280
|
-
};
|
|
1281
|
-
const afterResult = hooks.after(middlewareResult);
|
|
1282
|
-
if (afterResult instanceof Promise) {
|
|
1283
|
-
throw new Error(
|
|
1284
|
-
`Middleware mode is 'sync' but after hook returned Promise for transition: ${transitionName}`
|
|
1285
|
-
);
|
|
1155
|
+
for (const prop in machine) {
|
|
1156
|
+
if (!Object.prototype.hasOwnProperty.call(machine, prop)) continue;
|
|
1157
|
+
const value = machine[prop];
|
|
1158
|
+
if (typeof value === "function" && prop !== "context") {
|
|
1159
|
+
wrappedMachine[prop] = function(...args) {
|
|
1160
|
+
const transitionName = prop;
|
|
1161
|
+
const context = wrappedMachine.context;
|
|
1162
|
+
const executeTransition = () => {
|
|
1163
|
+
let nextMachine;
|
|
1164
|
+
try {
|
|
1165
|
+
nextMachine = value.apply(this, args);
|
|
1166
|
+
} catch (error) {
|
|
1167
|
+
if (hooks.error) {
|
|
1168
|
+
try {
|
|
1169
|
+
hooks.error({
|
|
1170
|
+
transitionName,
|
|
1171
|
+
context,
|
|
1172
|
+
args: [...args],
|
|
1173
|
+
error
|
|
1174
|
+
});
|
|
1175
|
+
} catch (hookError) {
|
|
1176
|
+
if (!continueOnError) throw hookError;
|
|
1177
|
+
if (logErrors) console.error(`Middleware error hook error for ${transitionName}:`, hookError);
|
|
1178
|
+
onError == null ? void 0 : onError(hookError, "error", { transitionName, context, args, error });
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
throw error;
|
|
1286
1182
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1183
|
+
const ensureMiddlewareProperties = (machine2) => {
|
|
1184
|
+
if (machine2 && typeof machine2 === "object" && machine2.context) {
|
|
1185
|
+
for (const prop2 in wrappedMachine) {
|
|
1186
|
+
if (!Object.prototype.hasOwnProperty.call(wrappedMachine, prop2)) continue;
|
|
1187
|
+
if (prop2 !== "context" && !(prop2 in machine2)) {
|
|
1188
|
+
machine2[prop2] = wrappedMachine[prop2];
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
for (const prop2 in machine2) {
|
|
1192
|
+
if (!Object.prototype.hasOwnProperty.call(machine2, prop2)) continue;
|
|
1193
|
+
const value2 = machine2[prop2];
|
|
1194
|
+
if (typeof value2 === "function" && prop2 !== "context" && wrappedMachine[prop2]) {
|
|
1195
|
+
machine2[prop2] = wrappedMachine[prop2];
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
return machine2;
|
|
1296
1200
|
};
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1201
|
+
if (nextMachine && typeof nextMachine.then === "function") {
|
|
1202
|
+
const asyncResult = nextMachine.then((resolvedMachine) => {
|
|
1203
|
+
ensureMiddlewareProperties(resolvedMachine);
|
|
1204
|
+
if (hooks.after) {
|
|
1205
|
+
try {
|
|
1206
|
+
const result = hooks.after({
|
|
1207
|
+
transitionName,
|
|
1208
|
+
prevContext: context,
|
|
1209
|
+
nextContext: resolvedMachine.context,
|
|
1210
|
+
args: [...args]
|
|
1211
|
+
});
|
|
1212
|
+
if (result && typeof result.then === "function") {
|
|
1213
|
+
return result.then(() => resolvedMachine);
|
|
1214
|
+
}
|
|
1215
|
+
} catch (error) {
|
|
1216
|
+
if (!continueOnError) throw error;
|
|
1217
|
+
if (logErrors) console.error(`Middleware after hook error for ${transitionName}:`, error);
|
|
1218
|
+
onError == null ? void 0 : onError(error, "after", {
|
|
1219
|
+
transitionName,
|
|
1220
|
+
prevContext: context,
|
|
1221
|
+
nextContext: resolvedMachine.context,
|
|
1222
|
+
args
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
return resolvedMachine;
|
|
1300
1227
|
});
|
|
1301
|
-
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1228
|
+
return asyncResult;
|
|
1229
|
+
} else {
|
|
1230
|
+
ensureMiddlewareProperties(nextMachine);
|
|
1231
|
+
if (hooks.after) {
|
|
1232
|
+
try {
|
|
1233
|
+
const result = hooks.after({
|
|
1234
|
+
transitionName,
|
|
1235
|
+
prevContext: context,
|
|
1236
|
+
nextContext: nextMachine.context,
|
|
1237
|
+
args: [...args]
|
|
1238
|
+
});
|
|
1239
|
+
if (result && typeof result === "object" && result && "then" in result) {
|
|
1240
|
+
return result.then(() => nextMachine).catch((error) => {
|
|
1241
|
+
if (!continueOnError) throw error;
|
|
1242
|
+
if (logErrors) console.error(`Middleware after hook error for ${transitionName}:`, error);
|
|
1243
|
+
onError == null ? void 0 : onError(error, "after", {
|
|
1244
|
+
transitionName,
|
|
1245
|
+
prevContext: context,
|
|
1246
|
+
nextContext: nextMachine.context,
|
|
1247
|
+
args
|
|
1248
|
+
});
|
|
1249
|
+
return nextMachine;
|
|
1250
|
+
});
|
|
1251
|
+
}
|
|
1252
|
+
} catch (error) {
|
|
1253
|
+
if (!continueOnError) throw error;
|
|
1254
|
+
if (logErrors) console.error(`Middleware after hook error for ${transitionName}:`, error);
|
|
1255
|
+
onError == null ? void 0 : onError(error, "after", {
|
|
1256
|
+
transitionName,
|
|
1257
|
+
prevContext: context,
|
|
1258
|
+
nextContext: nextMachine.context,
|
|
1259
|
+
args
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
return nextMachine;
|
|
1334
1264
|
}
|
|
1335
|
-
}
|
|
1336
|
-
throw err;
|
|
1337
|
-
}
|
|
1338
|
-
};
|
|
1339
|
-
const executeAsyncTransition = async () => {
|
|
1340
|
-
try {
|
|
1265
|
+
};
|
|
1341
1266
|
if (hooks.before) {
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
return errorResult;
|
|
1267
|
+
try {
|
|
1268
|
+
const result = hooks.before({
|
|
1269
|
+
transitionName,
|
|
1270
|
+
context,
|
|
1271
|
+
args: [...args]
|
|
1272
|
+
});
|
|
1273
|
+
if (result && typeof result === "object" && result && "then" in result) {
|
|
1274
|
+
return result.then((hookResult) => {
|
|
1275
|
+
if (hookResult === CANCEL) {
|
|
1276
|
+
return wrappedMachine;
|
|
1277
|
+
}
|
|
1278
|
+
return executeTransition();
|
|
1279
|
+
}).catch((error) => {
|
|
1280
|
+
if (!continueOnError) throw error;
|
|
1281
|
+
if (logErrors) console.error(`Middleware before hook error for ${transitionName}:`, error);
|
|
1282
|
+
onError == null ? void 0 : onError(error, "before", { transitionName, context, args });
|
|
1283
|
+
return executeTransition();
|
|
1284
|
+
});
|
|
1285
|
+
}
|
|
1286
|
+
if (result === CANCEL) {
|
|
1287
|
+
return wrappedMachine;
|
|
1288
|
+
}
|
|
1289
|
+
} catch (error) {
|
|
1290
|
+
if (!continueOnError) throw error;
|
|
1291
|
+
if (logErrors) console.error(`Middleware before hook error for ${transitionName}:`, error);
|
|
1292
|
+
onError == null ? void 0 : onError(error, "before", { transitionName, context, args });
|
|
1369
1293
|
}
|
|
1370
1294
|
}
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
if (mode === "async") {
|
|
1375
|
-
return executeAsyncTransition();
|
|
1376
|
-
} else if (mode === "sync") {
|
|
1377
|
-
return executeSyncTransition();
|
|
1378
|
-
} else {
|
|
1379
|
-
return executeSyncTransition();
|
|
1295
|
+
;
|
|
1296
|
+
return executeTransition();
|
|
1297
|
+
};
|
|
1380
1298
|
}
|
|
1381
|
-
}
|
|
1299
|
+
}
|
|
1300
|
+
return wrappedMachine;
|
|
1382
1301
|
}
|
|
1383
1302
|
function withLogging(machine, options = {}) {
|
|
1384
|
-
const {
|
|
1385
|
-
logger = console.log,
|
|
1386
|
-
includeContext = true,
|
|
1387
|
-
includeArgs = true
|
|
1388
|
-
} = options;
|
|
1303
|
+
const { logger = console.log, includeArgs = false, includeContext = true } = options;
|
|
1389
1304
|
return createMiddleware(machine, {
|
|
1390
1305
|
before: ({ transitionName, args }) => {
|
|
1391
|
-
const
|
|
1392
|
-
logger(
|
|
1306
|
+
const message = includeArgs ? `→ ${transitionName} [${args.join(", ")}]` : `→ ${transitionName}`;
|
|
1307
|
+
logger(message);
|
|
1393
1308
|
},
|
|
1394
1309
|
after: ({ transitionName, nextContext }) => {
|
|
1395
1310
|
const contextStr = includeContext ? ` ${JSON.stringify(nextContext)}` : "";
|
|
1396
1311
|
logger(`✓ ${transitionName}${contextStr}`);
|
|
1312
|
+
},
|
|
1313
|
+
error: ({ transitionName, error }) => {
|
|
1314
|
+
console.error(`[Machine] ${transitionName} failed:`, error);
|
|
1397
1315
|
}
|
|
1398
1316
|
});
|
|
1399
1317
|
}
|
|
1400
1318
|
function withAnalytics(machine, track, options = {}) {
|
|
1401
|
-
const {
|
|
1402
|
-
eventPrefix = "state_transition",
|
|
1403
|
-
includePrevContext = false,
|
|
1404
|
-
includeArgs = true
|
|
1405
|
-
} = options;
|
|
1319
|
+
const { eventPrefix = "state_transition", includePrevContext = false, includeArgs = false } = options;
|
|
1406
1320
|
return createMiddleware(machine, {
|
|
1407
|
-
after:
|
|
1408
|
-
const
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
if (
|
|
1413
|
-
|
|
1414
|
-
}
|
|
1415
|
-
if (includeArgs && args.length > 0) {
|
|
1416
|
-
properties.args = args;
|
|
1417
|
-
}
|
|
1418
|
-
await track(`${eventPrefix}.${transitionName}`, properties);
|
|
1321
|
+
after: ({ transitionName, prevContext, nextContext, args }) => {
|
|
1322
|
+
const event = `${eventPrefix}.${transitionName}`;
|
|
1323
|
+
const data = { transition: transitionName };
|
|
1324
|
+
if (includePrevContext) data.from = prevContext;
|
|
1325
|
+
data.to = nextContext;
|
|
1326
|
+
if (includeArgs) data.args = args;
|
|
1327
|
+
track(event, data);
|
|
1419
1328
|
}
|
|
1420
|
-
}
|
|
1329
|
+
});
|
|
1421
1330
|
}
|
|
1422
|
-
function withValidation(machine,
|
|
1331
|
+
function withValidation(machine, validator) {
|
|
1423
1332
|
return createMiddleware(machine, {
|
|
1424
1333
|
before: (ctx) => {
|
|
1425
|
-
const result =
|
|
1426
|
-
if (result instanceof Promise) {
|
|
1427
|
-
return result.then((r) => {
|
|
1428
|
-
if (r === false) {
|
|
1429
|
-
throw new Error(`Validation failed for transition: ${ctx.transitionName}`);
|
|
1430
|
-
}
|
|
1431
|
-
return void 0;
|
|
1432
|
-
});
|
|
1433
|
-
}
|
|
1334
|
+
const result = validator(ctx);
|
|
1434
1335
|
if (result === false) {
|
|
1435
1336
|
throw new Error(`Validation failed for transition: ${ctx.transitionName}`);
|
|
1436
1337
|
}
|
|
1437
|
-
return void 0;
|
|
1438
1338
|
}
|
|
1439
|
-
}
|
|
1339
|
+
});
|
|
1440
1340
|
}
|
|
1441
|
-
function withPermissions(machine,
|
|
1341
|
+
function withPermissions(machine, checker) {
|
|
1442
1342
|
return createMiddleware(machine, {
|
|
1443
1343
|
before: (ctx) => {
|
|
1444
|
-
|
|
1445
|
-
if (result instanceof Promise) {
|
|
1446
|
-
return result.then((allowed) => {
|
|
1447
|
-
if (!allowed) {
|
|
1448
|
-
throw new Error(`Unauthorized transition: ${ctx.transitionName}`);
|
|
1449
|
-
}
|
|
1450
|
-
return void 0;
|
|
1451
|
-
});
|
|
1452
|
-
}
|
|
1453
|
-
if (!result) {
|
|
1344
|
+
if (!checker(ctx)) {
|
|
1454
1345
|
throw new Error(`Unauthorized transition: ${ctx.transitionName}`);
|
|
1455
1346
|
}
|
|
1456
|
-
return void 0;
|
|
1457
1347
|
}
|
|
1458
|
-
}
|
|
1348
|
+
});
|
|
1459
1349
|
}
|
|
1460
|
-
function withErrorReporting(machine,
|
|
1461
|
-
const {
|
|
1350
|
+
function withErrorReporting(machine, reporter, options = {}) {
|
|
1351
|
+
const { includeArgs = false } = options;
|
|
1462
1352
|
return createMiddleware(machine, {
|
|
1463
|
-
error:
|
|
1464
|
-
const
|
|
1465
|
-
transition: transitionName
|
|
1353
|
+
error: (errorCtx) => {
|
|
1354
|
+
const formattedCtx = {
|
|
1355
|
+
transition: errorCtx.transitionName,
|
|
1356
|
+
context: errorCtx.context,
|
|
1357
|
+
...includeArgs && { args: errorCtx.args }
|
|
1466
1358
|
};
|
|
1467
|
-
|
|
1468
|
-
errorContext.context = context;
|
|
1469
|
-
}
|
|
1470
|
-
if (includeArgs && args.length > 0) {
|
|
1471
|
-
errorContext.args = args;
|
|
1472
|
-
}
|
|
1473
|
-
await Promise.resolve(captureError(error, errorContext));
|
|
1359
|
+
reporter(errorCtx.error, formattedCtx);
|
|
1474
1360
|
}
|
|
1475
|
-
}
|
|
1361
|
+
});
|
|
1476
1362
|
}
|
|
1477
|
-
function withPerformanceMonitoring(machine,
|
|
1478
|
-
const
|
|
1363
|
+
function withPerformanceMonitoring(machine, tracker) {
|
|
1364
|
+
const startTimes = /* @__PURE__ */ new Map();
|
|
1479
1365
|
return createMiddleware(machine, {
|
|
1480
|
-
before: (
|
|
1481
|
-
|
|
1482
|
-
return void 0;
|
|
1366
|
+
before: (ctx) => {
|
|
1367
|
+
startTimes.set(ctx.transitionName, Date.now());
|
|
1483
1368
|
},
|
|
1484
|
-
after: (
|
|
1485
|
-
const startTime =
|
|
1369
|
+
after: (result) => {
|
|
1370
|
+
const startTime = startTimes.get(result.transitionName);
|
|
1486
1371
|
if (startTime) {
|
|
1487
|
-
const duration =
|
|
1488
|
-
|
|
1489
|
-
const
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1372
|
+
const duration = Date.now() - startTime;
|
|
1373
|
+
startTimes.delete(result.transitionName);
|
|
1374
|
+
const testResult = {
|
|
1375
|
+
transitionName: result.transitionName,
|
|
1376
|
+
duration,
|
|
1377
|
+
context: result.nextContext || result.prevContext
|
|
1378
|
+
};
|
|
1379
|
+
tracker(testResult);
|
|
1493
1380
|
}
|
|
1494
|
-
return void 0;
|
|
1495
1381
|
}
|
|
1496
|
-
}
|
|
1382
|
+
});
|
|
1497
1383
|
}
|
|
1498
1384
|
function withRetry(machine, options = {}) {
|
|
1385
|
+
var _a, _b;
|
|
1499
1386
|
const {
|
|
1500
|
-
|
|
1501
|
-
delay = 1e3,
|
|
1502
|
-
backoffMultiplier = 1,
|
|
1387
|
+
maxAttempts = (_a = options.maxRetries) != null ? _a : 3,
|
|
1503
1388
|
shouldRetry = () => true,
|
|
1389
|
+
backoffMs = (_b = options.delay) != null ? _b : 100,
|
|
1390
|
+
backoffMultiplier = 2,
|
|
1504
1391
|
onRetry
|
|
1505
1392
|
} = options;
|
|
1506
|
-
const
|
|
1393
|
+
const wrappedMachine = { ...machine };
|
|
1507
1394
|
for (const prop in machine) {
|
|
1508
1395
|
if (!Object.prototype.hasOwnProperty.call(machine, prop)) continue;
|
|
1509
1396
|
const value = machine[prop];
|
|
1510
|
-
if (
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1397
|
+
if (typeof value === "function" && prop !== "context") {
|
|
1398
|
+
wrappedMachine[prop] = async function(...args) {
|
|
1399
|
+
let lastError;
|
|
1400
|
+
let attempt = 0;
|
|
1401
|
+
while (attempt < maxAttempts) {
|
|
1402
|
+
try {
|
|
1403
|
+
return await value.apply(this, args);
|
|
1404
|
+
} catch (error) {
|
|
1405
|
+
lastError = error;
|
|
1406
|
+
attempt++;
|
|
1407
|
+
if (attempt < maxAttempts && shouldRetry(lastError, attempt)) {
|
|
1408
|
+
onRetry == null ? void 0 : onRetry(lastError, attempt);
|
|
1409
|
+
const baseDelay = typeof backoffMs === "function" ? backoffMs(attempt) : backoffMs;
|
|
1410
|
+
const delay = baseDelay * Math.pow(backoffMultiplier, attempt - 1);
|
|
1411
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1412
|
+
} else {
|
|
1413
|
+
throw lastError;
|
|
1414
|
+
}
|
|
1526
1415
|
}
|
|
1527
|
-
onRetry == null ? void 0 : onRetry(attempt + 1, lastError);
|
|
1528
|
-
const currentDelay = delay * Math.pow(backoffMultiplier, attempt);
|
|
1529
|
-
await new Promise((resolve) => setTimeout(resolve, currentDelay));
|
|
1530
1416
|
}
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
}
|
|
1417
|
+
throw lastError;
|
|
1418
|
+
};
|
|
1419
|
+
}
|
|
1534
1420
|
}
|
|
1535
|
-
return
|
|
1421
|
+
return wrappedMachine;
|
|
1422
|
+
}
|
|
1423
|
+
function createCustomMiddleware(hooks, options) {
|
|
1424
|
+
return (machine) => createMiddleware(machine, hooks, options);
|
|
1536
1425
|
}
|
|
1426
|
+
|
|
1427
|
+
// src/middleware/history.ts
|
|
1537
1428
|
function withHistory(machine, options = {}) {
|
|
1538
|
-
const {
|
|
1539
|
-
maxSize,
|
|
1540
|
-
serializer,
|
|
1541
|
-
filter,
|
|
1542
|
-
onEntry,
|
|
1543
|
-
_isRewrap = false
|
|
1544
|
-
} = options;
|
|
1429
|
+
const { maxSize, serializer, onEntry } = options;
|
|
1545
1430
|
const history = [];
|
|
1546
1431
|
let entryId = 0;
|
|
1547
1432
|
const instrumentedMachine = createMiddleware(machine, {
|
|
1548
1433
|
before: ({ transitionName, args }) => {
|
|
1549
|
-
if (filter && !filter(transitionName, args)) {
|
|
1550
|
-
return;
|
|
1551
|
-
}
|
|
1552
1434
|
const entry = {
|
|
1553
1435
|
id: `entry-${entryId++}`,
|
|
1554
1436
|
transitionName,
|
|
1555
1437
|
args: [...args],
|
|
1556
|
-
// Shallow clone args (fast, works with any type)
|
|
1557
1438
|
timestamp: Date.now()
|
|
1558
1439
|
};
|
|
1559
1440
|
if (serializer) {
|
|
@@ -1569,54 +1450,7 @@ function withHistory(machine, options = {}) {
|
|
|
1569
1450
|
}
|
|
1570
1451
|
onEntry == null ? void 0 : onEntry(entry);
|
|
1571
1452
|
}
|
|
1572
|
-
}
|
|
1573
|
-
if (!_isRewrap) {
|
|
1574
|
-
for (const prop in instrumentedMachine) {
|
|
1575
|
-
if (!Object.prototype.hasOwnProperty.call(instrumentedMachine, prop)) continue;
|
|
1576
|
-
const value = instrumentedMachine[prop];
|
|
1577
|
-
if (typeof value === "function" && !prop.startsWith("_") && prop !== "context" && !["history", "clearHistory"].includes(prop)) {
|
|
1578
|
-
const originalFn = value;
|
|
1579
|
-
instrumentedMachine[prop] = function(...args) {
|
|
1580
|
-
const result = originalFn.apply(this, args);
|
|
1581
|
-
if (result && typeof result === "object" && "context" in result && !("history" in result)) {
|
|
1582
|
-
const rewrappedResult = createMiddleware(result, {
|
|
1583
|
-
before: ({ transitionName, args: transArgs }) => {
|
|
1584
|
-
if (filter && !filter(transitionName, transArgs)) {
|
|
1585
|
-
return;
|
|
1586
|
-
}
|
|
1587
|
-
const entry = {
|
|
1588
|
-
id: `entry-${entryId++}`,
|
|
1589
|
-
transitionName,
|
|
1590
|
-
args: [...transArgs],
|
|
1591
|
-
timestamp: Date.now()
|
|
1592
|
-
};
|
|
1593
|
-
if (serializer) {
|
|
1594
|
-
try {
|
|
1595
|
-
entry.serializedArgs = serializer.serialize(transArgs);
|
|
1596
|
-
} catch (err) {
|
|
1597
|
-
console.error("Failed to serialize history args:", err);
|
|
1598
|
-
}
|
|
1599
|
-
}
|
|
1600
|
-
history.push(entry);
|
|
1601
|
-
if (maxSize && history.length > maxSize) {
|
|
1602
|
-
history.shift();
|
|
1603
|
-
}
|
|
1604
|
-
onEntry == null ? void 0 : onEntry(entry);
|
|
1605
|
-
}
|
|
1606
|
-
}, { exclude: ["context", "history", "clearHistory"] });
|
|
1607
|
-
return Object.assign(rewrappedResult, {
|
|
1608
|
-
history,
|
|
1609
|
-
clearHistory: () => {
|
|
1610
|
-
history.length = 0;
|
|
1611
|
-
entryId = 0;
|
|
1612
|
-
}
|
|
1613
|
-
});
|
|
1614
|
-
}
|
|
1615
|
-
return result;
|
|
1616
|
-
};
|
|
1617
|
-
}
|
|
1618
|
-
}
|
|
1619
|
-
}
|
|
1453
|
+
});
|
|
1620
1454
|
return Object.assign(instrumentedMachine, {
|
|
1621
1455
|
history,
|
|
1622
1456
|
clearHistory: () => {
|
|
@@ -1625,37 +1459,27 @@ function withHistory(machine, options = {}) {
|
|
|
1625
1459
|
}
|
|
1626
1460
|
});
|
|
1627
1461
|
}
|
|
1462
|
+
|
|
1463
|
+
// src/middleware/snapshot.ts
|
|
1628
1464
|
function withSnapshot(machine, options = {}) {
|
|
1629
1465
|
const {
|
|
1630
1466
|
maxSize,
|
|
1631
1467
|
serializer,
|
|
1632
1468
|
captureSnapshot,
|
|
1633
|
-
|
|
1634
|
-
filter,
|
|
1635
|
-
onSnapshot,
|
|
1636
|
-
_extraExclusions = [],
|
|
1637
|
-
_isRewrap = false
|
|
1469
|
+
onlyOnChange = false
|
|
1638
1470
|
} = options;
|
|
1639
1471
|
const snapshots = [];
|
|
1640
1472
|
let snapshotId = 0;
|
|
1641
1473
|
const instrumentedMachine = createMiddleware(machine, {
|
|
1642
1474
|
after: ({ transitionName, prevContext, nextContext }) => {
|
|
1643
|
-
if (
|
|
1475
|
+
if (onlyOnChange && JSON.stringify(prevContext) === JSON.stringify(nextContext)) {
|
|
1644
1476
|
return;
|
|
1645
1477
|
}
|
|
1646
|
-
if (onlyIfChanged) {
|
|
1647
|
-
const changed = JSON.stringify(prevContext) !== JSON.stringify(nextContext);
|
|
1648
|
-
if (!changed) {
|
|
1649
|
-
return;
|
|
1650
|
-
}
|
|
1651
|
-
}
|
|
1652
1478
|
const snapshot = {
|
|
1653
1479
|
id: `snapshot-${snapshotId++}`,
|
|
1654
1480
|
transitionName,
|
|
1655
1481
|
before: { ...prevContext },
|
|
1656
|
-
// Clone
|
|
1657
1482
|
after: { ...nextContext },
|
|
1658
|
-
// Clone
|
|
1659
1483
|
timestamp: Date.now()
|
|
1660
1484
|
};
|
|
1661
1485
|
if (serializer) {
|
|
@@ -1677,92 +1501,16 @@ function withSnapshot(machine, options = {}) {
|
|
|
1677
1501
|
if (maxSize && snapshots.length > maxSize) {
|
|
1678
1502
|
snapshots.shift();
|
|
1679
1503
|
}
|
|
1680
|
-
onSnapshot == null ? void 0 : onSnapshot(snapshot);
|
|
1681
1504
|
}
|
|
1682
|
-
}
|
|
1505
|
+
});
|
|
1683
1506
|
const restoreSnapshot = (context) => {
|
|
1684
|
-
const
|
|
1685
|
-
|
|
1507
|
+
const transitions = Object.fromEntries(
|
|
1508
|
+
Object.entries(machine).filter(
|
|
1509
|
+
([key]) => key !== "context" && key !== "snapshots" && key !== "clearSnapshots" && key !== "restoreSnapshot" && typeof machine[key] === "function"
|
|
1510
|
+
)
|
|
1511
|
+
);
|
|
1512
|
+
return Object.assign({ context }, transitions);
|
|
1686
1513
|
};
|
|
1687
|
-
if (!_isRewrap) {
|
|
1688
|
-
for (const prop in instrumentedMachine) {
|
|
1689
|
-
if (!Object.prototype.hasOwnProperty.call(instrumentedMachine, prop)) continue;
|
|
1690
|
-
const value = instrumentedMachine[prop];
|
|
1691
|
-
if (typeof value === "function" && !prop.startsWith("_") && prop !== "context" && !["snapshots", "clearSnapshots", "restoreSnapshot", "history", "clearHistory"].includes(prop)) {
|
|
1692
|
-
const originalWrappedFn = value;
|
|
1693
|
-
instrumentedMachine[prop] = function(...args) {
|
|
1694
|
-
const result = originalWrappedFn.apply(this, args);
|
|
1695
|
-
if (result && typeof result === "object" && "context" in result && !("snapshots" in result)) {
|
|
1696
|
-
for (const transProp in result) {
|
|
1697
|
-
if (!Object.prototype.hasOwnProperty.call(result, transProp)) continue;
|
|
1698
|
-
const transValue = result[transProp];
|
|
1699
|
-
if (typeof transValue === "function" && !transProp.startsWith("_") && transProp !== "context" && !["snapshots", "clearSnapshots", "restoreSnapshot", "history", "clearHistory"].includes(transProp)) {
|
|
1700
|
-
const origTransFn = transValue;
|
|
1701
|
-
result[transProp] = function(...transArgs) {
|
|
1702
|
-
const prevCtx = result.context;
|
|
1703
|
-
const transResult = origTransFn.apply(this, transArgs);
|
|
1704
|
-
if (transResult && typeof transResult === "object" && "context" in transResult) {
|
|
1705
|
-
const nextCtx = transResult.context;
|
|
1706
|
-
if (!(filter && !filter(transProp))) {
|
|
1707
|
-
let shouldRecord = true;
|
|
1708
|
-
if (onlyIfChanged) {
|
|
1709
|
-
const changed = JSON.stringify(prevCtx) !== JSON.stringify(nextCtx);
|
|
1710
|
-
shouldRecord = changed;
|
|
1711
|
-
}
|
|
1712
|
-
if (shouldRecord) {
|
|
1713
|
-
const snapshot = {
|
|
1714
|
-
id: `snapshot-${snapshotId++}`,
|
|
1715
|
-
transitionName: transProp,
|
|
1716
|
-
before: { ...prevCtx },
|
|
1717
|
-
after: { ...nextCtx },
|
|
1718
|
-
timestamp: Date.now()
|
|
1719
|
-
};
|
|
1720
|
-
if (serializer) {
|
|
1721
|
-
try {
|
|
1722
|
-
snapshot.serializedBefore = serializer.serialize(prevCtx);
|
|
1723
|
-
snapshot.serializedAfter = serializer.serialize(nextCtx);
|
|
1724
|
-
} catch (err) {
|
|
1725
|
-
console.error("Failed to serialize snapshot:", err);
|
|
1726
|
-
}
|
|
1727
|
-
}
|
|
1728
|
-
if (captureSnapshot) {
|
|
1729
|
-
try {
|
|
1730
|
-
snapshot.diff = captureSnapshot(prevCtx, nextCtx);
|
|
1731
|
-
} catch (err) {
|
|
1732
|
-
console.error("Failed to capture snapshot:", err);
|
|
1733
|
-
}
|
|
1734
|
-
}
|
|
1735
|
-
snapshots.push(snapshot);
|
|
1736
|
-
if (maxSize && snapshots.length > maxSize) {
|
|
1737
|
-
snapshots.shift();
|
|
1738
|
-
}
|
|
1739
|
-
onSnapshot == null ? void 0 : onSnapshot(snapshot);
|
|
1740
|
-
}
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
return transResult;
|
|
1744
|
-
};
|
|
1745
|
-
}
|
|
1746
|
-
}
|
|
1747
|
-
const resultWithTracking = Object.assign(result, {
|
|
1748
|
-
snapshots,
|
|
1749
|
-
clearSnapshots: () => {
|
|
1750
|
-
snapshots.length = 0;
|
|
1751
|
-
snapshotId = 0;
|
|
1752
|
-
},
|
|
1753
|
-
restoreSnapshot
|
|
1754
|
-
});
|
|
1755
|
-
if (machine.history) {
|
|
1756
|
-
resultWithTracking.history = machine.history;
|
|
1757
|
-
resultWithTracking.clearHistory = machine.clearHistory;
|
|
1758
|
-
}
|
|
1759
|
-
return resultWithTracking;
|
|
1760
|
-
}
|
|
1761
|
-
return result;
|
|
1762
|
-
};
|
|
1763
|
-
}
|
|
1764
|
-
}
|
|
1765
|
-
}
|
|
1766
1514
|
return Object.assign(instrumentedMachine, {
|
|
1767
1515
|
snapshots,
|
|
1768
1516
|
clearSnapshots: () => {
|
|
@@ -1772,139 +1520,122 @@ function withSnapshot(machine, options = {}) {
|
|
|
1772
1520
|
restoreSnapshot
|
|
1773
1521
|
});
|
|
1774
1522
|
}
|
|
1523
|
+
|
|
1524
|
+
// src/middleware/time-travel.ts
|
|
1775
1525
|
function withTimeTravel(machine, options = {}) {
|
|
1776
1526
|
const { maxSize, serializer, onRecord } = options;
|
|
1777
1527
|
const history = [];
|
|
1778
1528
|
const snapshots = [];
|
|
1779
|
-
let
|
|
1529
|
+
let historyId = 0;
|
|
1780
1530
|
let snapshotId = 0;
|
|
1781
|
-
const
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1531
|
+
const instrumentedMachine = createMiddleware(machine, {
|
|
1532
|
+
before: ({ transitionName, args }) => {
|
|
1533
|
+
const entry = {
|
|
1534
|
+
id: `entry-${historyId++}`,
|
|
1535
|
+
transitionName,
|
|
1536
|
+
args: [...args],
|
|
1537
|
+
timestamp: Date.now()
|
|
1538
|
+
};
|
|
1539
|
+
if (serializer) {
|
|
1540
|
+
try {
|
|
1541
|
+
entry.serializedArgs = serializer.serialize(args);
|
|
1542
|
+
} catch (err) {
|
|
1543
|
+
console.error("Failed to serialize history args:", err);
|
|
1544
|
+
}
|
|
1793
1545
|
}
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
history.shift();
|
|
1798
|
-
}
|
|
1799
|
-
onRecord == null ? void 0 : onRecord("history", entry);
|
|
1800
|
-
};
|
|
1801
|
-
const recordSnapshot = (transitionName, prevContext, nextContext) => {
|
|
1802
|
-
const snapshot = {
|
|
1803
|
-
id: `snapshot-${snapshotId++}`,
|
|
1804
|
-
transitionName,
|
|
1805
|
-
before: { ...prevContext },
|
|
1806
|
-
after: { ...nextContext },
|
|
1807
|
-
timestamp: Date.now()
|
|
1808
|
-
};
|
|
1809
|
-
if (serializer) {
|
|
1810
|
-
try {
|
|
1811
|
-
snapshot.serializedBefore = serializer.serialize(prevContext);
|
|
1812
|
-
snapshot.serializedAfter = serializer.serialize(nextContext);
|
|
1813
|
-
} catch (err) {
|
|
1814
|
-
console.error("Failed to serialize snapshot:", err);
|
|
1546
|
+
history.push(entry);
|
|
1547
|
+
if (maxSize && history.length > maxSize) {
|
|
1548
|
+
history.shift();
|
|
1815
1549
|
}
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
const replayFrom = (snapshotIndex = 0) => {
|
|
1828
|
-
if (snapshotIndex < 0 || snapshotIndex >= snapshots.length) {
|
|
1829
|
-
throw new Error(`Invalid snapshot index: ${snapshotIndex}`);
|
|
1830
|
-
}
|
|
1831
|
-
let current = restoreSnapshot(snapshots[snapshotIndex].before);
|
|
1832
|
-
const snapshot = snapshots[snapshotIndex];
|
|
1833
|
-
const historyStartIndex = history.findIndex(
|
|
1834
|
-
(entry) => entry.transitionName === snapshot.transitionName && entry.timestamp === snapshot.timestamp
|
|
1835
|
-
);
|
|
1836
|
-
if (historyStartIndex === -1) {
|
|
1837
|
-
throw new Error("Could not find matching history entry for snapshot");
|
|
1838
|
-
}
|
|
1839
|
-
for (let i = historyStartIndex; i < history.length; i++) {
|
|
1840
|
-
const entry = history[i];
|
|
1841
|
-
const transition = current[entry.transitionName];
|
|
1842
|
-
if (typeof transition === "function") {
|
|
1550
|
+
onRecord == null ? void 0 : onRecord("history", entry);
|
|
1551
|
+
},
|
|
1552
|
+
after: ({ transitionName, prevContext, nextContext }) => {
|
|
1553
|
+
const snapshot = {
|
|
1554
|
+
id: `snapshot-${snapshotId++}`,
|
|
1555
|
+
transitionName,
|
|
1556
|
+
before: { ...prevContext },
|
|
1557
|
+
after: { ...nextContext },
|
|
1558
|
+
timestamp: Date.now()
|
|
1559
|
+
};
|
|
1560
|
+
if (serializer) {
|
|
1843
1561
|
try {
|
|
1844
|
-
|
|
1562
|
+
snapshot.serializedBefore = serializer.serialize(prevContext);
|
|
1563
|
+
snapshot.serializedAfter = serializer.serialize(nextContext);
|
|
1845
1564
|
} catch (err) {
|
|
1846
|
-
console.error(
|
|
1847
|
-
throw err;
|
|
1565
|
+
console.error("Failed to serialize snapshot:", err);
|
|
1848
1566
|
}
|
|
1849
1567
|
}
|
|
1568
|
+
snapshots.push(snapshot);
|
|
1569
|
+
if (maxSize && snapshots.length > maxSize) {
|
|
1570
|
+
snapshots.shift();
|
|
1571
|
+
}
|
|
1572
|
+
onRecord == null ? void 0 : onRecord("snapshot", snapshot);
|
|
1850
1573
|
}
|
|
1851
|
-
|
|
1574
|
+
});
|
|
1575
|
+
const restoreSnapshot = (context) => {
|
|
1576
|
+
const transitions = Object.fromEntries(
|
|
1577
|
+
Object.entries(machine).filter(
|
|
1578
|
+
([key]) => key !== "context" && key !== "history" && key !== "snapshots" && key !== "clearHistory" && key !== "clearSnapshots" && key !== "restoreSnapshot" && key !== "clearTimeTravel" && key !== "replayFrom" && typeof machine[key] === "function"
|
|
1579
|
+
)
|
|
1580
|
+
);
|
|
1581
|
+
return Object.assign({ context }, transitions);
|
|
1852
1582
|
};
|
|
1853
|
-
const
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1583
|
+
const replayFrom = (startIndex) => {
|
|
1584
|
+
var _a;
|
|
1585
|
+
if (startIndex < 0 || startIndex >= history.length) {
|
|
1586
|
+
throw new Error(`Invalid replay start index: ${startIndex}`);
|
|
1587
|
+
}
|
|
1588
|
+
let currentContext = (_a = snapshots[startIndex]) == null ? void 0 : _a.before;
|
|
1589
|
+
if (!currentContext) {
|
|
1590
|
+
throw new Error(`No snapshot available for index ${startIndex}`);
|
|
1591
|
+
}
|
|
1592
|
+
const transitionsToReplay = history.slice(startIndex);
|
|
1593
|
+
const freshMachine = Object.assign(
|
|
1594
|
+
{ context: currentContext },
|
|
1595
|
+
Object.fromEntries(
|
|
1596
|
+
Object.entries(machine).filter(
|
|
1597
|
+
([key]) => key !== "context" && typeof machine[key] === "function"
|
|
1598
|
+
)
|
|
1599
|
+
)
|
|
1600
|
+
);
|
|
1601
|
+
let replayedMachine = freshMachine;
|
|
1602
|
+
for (const entry of transitionsToReplay) {
|
|
1603
|
+
const transitionFn = replayedMachine[entry.transitionName];
|
|
1604
|
+
if (transitionFn) {
|
|
1605
|
+
replayedMachine = transitionFn.apply(replayedMachine.context, entry.args);
|
|
1871
1606
|
}
|
|
1872
1607
|
}
|
|
1873
|
-
return
|
|
1874
|
-
history,
|
|
1875
|
-
snapshots,
|
|
1876
|
-
clearHistory: () => {
|
|
1877
|
-
history.length = 0;
|
|
1878
|
-
entryId = 0;
|
|
1879
|
-
},
|
|
1880
|
-
clearSnapshots: () => {
|
|
1881
|
-
snapshots.length = 0;
|
|
1882
|
-
snapshotId = 0;
|
|
1883
|
-
},
|
|
1884
|
-
clearTimeTravel: () => {
|
|
1885
|
-
history.length = 0;
|
|
1886
|
-
snapshots.length = 0;
|
|
1887
|
-
entryId = 0;
|
|
1888
|
-
snapshotId = 0;
|
|
1889
|
-
},
|
|
1890
|
-
restoreSnapshot,
|
|
1891
|
-
replayFrom
|
|
1892
|
-
});
|
|
1608
|
+
return replayedMachine;
|
|
1893
1609
|
};
|
|
1894
|
-
return
|
|
1610
|
+
return Object.assign(instrumentedMachine, {
|
|
1611
|
+
history,
|
|
1612
|
+
snapshots,
|
|
1613
|
+
clearHistory: () => {
|
|
1614
|
+
history.length = 0;
|
|
1615
|
+
historyId = 0;
|
|
1616
|
+
},
|
|
1617
|
+
clearSnapshots: () => {
|
|
1618
|
+
snapshots.length = 0;
|
|
1619
|
+
snapshotId = 0;
|
|
1620
|
+
},
|
|
1621
|
+
clearTimeTravel: () => {
|
|
1622
|
+
history.length = 0;
|
|
1623
|
+
snapshots.length = 0;
|
|
1624
|
+
historyId = 0;
|
|
1625
|
+
snapshotId = 0;
|
|
1626
|
+
},
|
|
1627
|
+
restoreSnapshot,
|
|
1628
|
+
replayFrom
|
|
1629
|
+
});
|
|
1895
1630
|
}
|
|
1631
|
+
|
|
1632
|
+
// src/middleware/composition.ts
|
|
1896
1633
|
function compose(machine, ...middlewares) {
|
|
1897
1634
|
return middlewares.reduce((acc, middleware) => middleware(acc), machine);
|
|
1898
1635
|
}
|
|
1899
|
-
function createCustomMiddleware(hooks, options) {
|
|
1900
|
-
return (machine) => createMiddleware(machine, hooks, options);
|
|
1901
|
-
}
|
|
1902
1636
|
function composeTyped(machine, ...middlewares) {
|
|
1903
1637
|
return middlewares.reduce((acc, middleware) => middleware(acc), machine);
|
|
1904
1638
|
}
|
|
1905
|
-
function chain(machine) {
|
|
1906
|
-
return new MiddlewareChainBuilder(machine);
|
|
1907
|
-
}
|
|
1908
1639
|
var MiddlewareChainBuilder = class _MiddlewareChainBuilder {
|
|
1909
1640
|
constructor(machine) {
|
|
1910
1641
|
this.machine = machine;
|
|
@@ -1925,53 +1656,30 @@ var MiddlewareChainBuilder = class _MiddlewareChainBuilder {
|
|
|
1925
1656
|
return this.machine;
|
|
1926
1657
|
}
|
|
1927
1658
|
};
|
|
1928
|
-
function
|
|
1929
|
-
return
|
|
1659
|
+
function chain(machine) {
|
|
1660
|
+
return new MiddlewareChainBuilder(machine);
|
|
1930
1661
|
}
|
|
1931
|
-
function
|
|
1932
|
-
const {
|
|
1933
|
-
|
|
1934
|
-
logErrors = true,
|
|
1935
|
-
onError
|
|
1936
|
-
} = config;
|
|
1937
|
-
return (machine, ...middlewares) => {
|
|
1938
|
-
let currentMachine = machine;
|
|
1939
|
-
const errors = [];
|
|
1940
|
-
for (let i = 0; i < middlewares.length; i++) {
|
|
1941
|
-
const middleware = middlewares[i];
|
|
1942
|
-
try {
|
|
1943
|
-
if ("middleware" in middleware && "when" in middleware) {
|
|
1944
|
-
if (!middleware.when(currentMachine)) {
|
|
1945
|
-
continue;
|
|
1946
|
-
}
|
|
1947
|
-
currentMachine = middleware.middleware(currentMachine);
|
|
1948
|
-
} else {
|
|
1949
|
-
currentMachine = middleware(currentMachine);
|
|
1950
|
-
}
|
|
1951
|
-
} catch (error) {
|
|
1952
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
1953
|
-
errors.push({ error: err, middlewareIndex: i });
|
|
1954
|
-
if (logErrors) {
|
|
1955
|
-
console.error(`Middleware pipeline error at index ${i}:`, err);
|
|
1956
|
-
}
|
|
1957
|
-
onError == null ? void 0 : onError(err, `middleware-${i}`);
|
|
1958
|
-
if (!continueOnError) {
|
|
1959
|
-
break;
|
|
1960
|
-
}
|
|
1961
|
-
}
|
|
1962
|
-
}
|
|
1963
|
-
return {
|
|
1964
|
-
machine: currentMachine,
|
|
1965
|
-
errors,
|
|
1966
|
-
success: errors.length === 0
|
|
1967
|
-
};
|
|
1662
|
+
function when(middleware, predicate) {
|
|
1663
|
+
const conditional = function(machine) {
|
|
1664
|
+
return predicate(machine) ? middleware(machine) : machine;
|
|
1968
1665
|
};
|
|
1666
|
+
conditional.middleware = middleware;
|
|
1667
|
+
conditional.when = predicate;
|
|
1668
|
+
return conditional;
|
|
1669
|
+
}
|
|
1670
|
+
function inDevelopment(middleware) {
|
|
1671
|
+
return when(middleware, () => {
|
|
1672
|
+
return typeof process !== "undefined" ? true : typeof window !== "undefined" ? !window.location.hostname.includes("production") : false;
|
|
1673
|
+
});
|
|
1674
|
+
}
|
|
1675
|
+
function whenContext(key, value, middleware) {
|
|
1676
|
+
return when(middleware, (machine) => machine.context[key] === value);
|
|
1969
1677
|
}
|
|
1970
1678
|
function createMiddlewareRegistry() {
|
|
1971
1679
|
const registry = /* @__PURE__ */ new Map();
|
|
1972
1680
|
return {
|
|
1973
1681
|
/**
|
|
1974
|
-
* Register a middleware
|
|
1682
|
+
* Register a middleware by name.
|
|
1975
1683
|
*/
|
|
1976
1684
|
register(name, middleware, description, priority) {
|
|
1977
1685
|
if (registry.has(name)) {
|
|
@@ -2033,21 +1741,45 @@ function createMiddlewareRegistry() {
|
|
|
2033
1741
|
}
|
|
2034
1742
|
};
|
|
2035
1743
|
}
|
|
2036
|
-
function
|
|
2037
|
-
const
|
|
2038
|
-
|
|
1744
|
+
function createPipeline(config = {}) {
|
|
1745
|
+
const {
|
|
1746
|
+
continueOnError = false,
|
|
1747
|
+
logErrors = true,
|
|
1748
|
+
onError
|
|
1749
|
+
} = config;
|
|
1750
|
+
return (machine, ...middlewares) => {
|
|
1751
|
+
let currentMachine = machine;
|
|
1752
|
+
const errors = [];
|
|
1753
|
+
let success = true;
|
|
1754
|
+
for (let i = 0; i < middlewares.length; i++) {
|
|
1755
|
+
const middleware = middlewares[i];
|
|
1756
|
+
try {
|
|
1757
|
+
if ("middleware" in middleware && "when" in middleware) {
|
|
1758
|
+
if (!middleware.when(currentMachine)) {
|
|
1759
|
+
continue;
|
|
1760
|
+
}
|
|
1761
|
+
currentMachine = middleware.middleware(currentMachine);
|
|
1762
|
+
} else {
|
|
1763
|
+
currentMachine = middleware(currentMachine);
|
|
1764
|
+
}
|
|
1765
|
+
} catch (error) {
|
|
1766
|
+
success = false;
|
|
1767
|
+
if (!continueOnError) {
|
|
1768
|
+
throw error;
|
|
1769
|
+
}
|
|
1770
|
+
errors.push({
|
|
1771
|
+
error,
|
|
1772
|
+
middlewareIndex: i,
|
|
1773
|
+
middlewareName: middleware.name
|
|
1774
|
+
});
|
|
1775
|
+
if (logErrors) {
|
|
1776
|
+
console.error(`Pipeline middleware error at index ${i}:`, error);
|
|
1777
|
+
}
|
|
1778
|
+
onError == null ? void 0 : onError(error, i, middleware.name);
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
return { machine: currentMachine, errors, success };
|
|
2039
1782
|
};
|
|
2040
|
-
conditional.middleware = middleware;
|
|
2041
|
-
conditional.when = predicate;
|
|
2042
|
-
return conditional;
|
|
2043
|
-
}
|
|
2044
|
-
function inDevelopment(middleware) {
|
|
2045
|
-
return when(middleware, () => {
|
|
2046
|
-
return typeof process !== "undefined" ? true : typeof window !== "undefined" ? !window.location.hostname.includes("production") : false;
|
|
2047
|
-
});
|
|
2048
|
-
}
|
|
2049
|
-
function whenContext(key, value, middleware) {
|
|
2050
|
-
return when(middleware, (machine) => machine.context[key] === value);
|
|
2051
1783
|
}
|
|
2052
1784
|
function combine(...middlewares) {
|
|
2053
1785
|
return (machine) => composeTyped(machine, ...middlewares);
|
|
@@ -2066,7 +1798,197 @@ function isMiddlewareFn(value) {
|
|
|
2066
1798
|
return typeof value === "function" && value.length === 1;
|
|
2067
1799
|
}
|
|
2068
1800
|
function isConditionalMiddleware(value) {
|
|
2069
|
-
return value !== null && "middleware" in value && "when" in value && isMiddlewareFn(value.middleware) && typeof value.when === "function";
|
|
1801
|
+
return value !== null && (typeof value === "object" || typeof value === "function") && "middleware" in value && "when" in value && isMiddlewareFn(value.middleware) && typeof value.when === "function";
|
|
1802
|
+
}
|
|
1803
|
+
function isMiddlewareResult(value, contextType) {
|
|
1804
|
+
return value !== null && typeof value === "object" && "transitionName" in value && "prevContext" in value && "nextContext" in value && "args" in value && typeof value.transitionName === "string" && Array.isArray(value.args) && (!contextType || isValidContext(value.prevContext, contextType) && isValidContext(value.nextContext, contextType));
|
|
1805
|
+
}
|
|
1806
|
+
function isMiddlewareContext(value, contextType) {
|
|
1807
|
+
return value !== null && typeof value === "object" && "transitionName" in value && "context" in value && "args" in value && typeof value.transitionName === "string" && Array.isArray(value.args) && (!contextType || isValidContext(value.context, contextType));
|
|
1808
|
+
}
|
|
1809
|
+
function isMiddlewareError(value, contextType) {
|
|
1810
|
+
return value !== null && typeof value === "object" && "transitionName" in value && "context" in value && "args" in value && "error" in value && typeof value.transitionName === "string" && Array.isArray(value.args) && value.error instanceof Error && (!contextType || isValidContext(value.context, contextType));
|
|
1811
|
+
}
|
|
1812
|
+
function isMiddlewareHooks(value, _contextType) {
|
|
1813
|
+
if (value === null || typeof value !== "object") return false;
|
|
1814
|
+
const hooks = value;
|
|
1815
|
+
if ("before" in hooks && hooks.before !== void 0) {
|
|
1816
|
+
if (typeof hooks.before !== "function") return false;
|
|
1817
|
+
}
|
|
1818
|
+
if ("after" in hooks && hooks.after !== void 0) {
|
|
1819
|
+
if (typeof hooks.after !== "function") return false;
|
|
1820
|
+
}
|
|
1821
|
+
if ("error" in hooks && hooks.error !== void 0) {
|
|
1822
|
+
if (typeof hooks.error !== "function") return false;
|
|
1823
|
+
}
|
|
1824
|
+
return true;
|
|
1825
|
+
}
|
|
1826
|
+
function isMiddlewareOptions(value) {
|
|
1827
|
+
return value === void 0 || value !== null && typeof value === "object" && ("continueOnError" in value ? typeof value.continueOnError === "boolean" : true) && ("logErrors" in value ? typeof value.logErrors === "boolean" : true) && ("onError" in value ? typeof value.onError === "function" || value.onError === void 0 : true);
|
|
1828
|
+
}
|
|
1829
|
+
function isValidContext(value, _contextType) {
|
|
1830
|
+
return value !== null && typeof value === "object";
|
|
1831
|
+
}
|
|
1832
|
+
function isNamedMiddleware(value) {
|
|
1833
|
+
return value !== null && typeof value === "object" && "name" in value && "middleware" in value && typeof value.name === "string" && isMiddlewareFn(value.middleware) && ("description" in value ? typeof value.description === "string" || value.description === void 0 : true) && ("priority" in value ? typeof value.priority === "number" || value.priority === void 0 : true);
|
|
1834
|
+
}
|
|
1835
|
+
function isPipelineConfig(value) {
|
|
1836
|
+
return value === void 0 || value !== null && typeof value === "object" && ("continueOnError" in value ? typeof value.continueOnError === "boolean" : true) && ("logErrors" in value ? typeof value.logErrors === "boolean" : true) && ("onError" in value ? typeof value.onError === "function" || value.onError === void 0 : true);
|
|
1837
|
+
}
|
|
1838
|
+
var MiddlewareBuilder = class {
|
|
1839
|
+
constructor(machine) {
|
|
1840
|
+
this.machine = machine;
|
|
1841
|
+
this.middlewares = [];
|
|
1842
|
+
}
|
|
1843
|
+
/**
|
|
1844
|
+
* Add logging middleware with type-safe configuration.
|
|
1845
|
+
*/
|
|
1846
|
+
withLogging(options) {
|
|
1847
|
+
this.middlewares.push((machine) => withLogging(machine, options));
|
|
1848
|
+
return this;
|
|
1849
|
+
}
|
|
1850
|
+
/**
|
|
1851
|
+
* Add analytics middleware with type-safe configuration.
|
|
1852
|
+
*/
|
|
1853
|
+
withAnalytics(track, options) {
|
|
1854
|
+
this.middlewares.push((machine) => withAnalytics(machine, track, options));
|
|
1855
|
+
return this;
|
|
1856
|
+
}
|
|
1857
|
+
/**
|
|
1858
|
+
* Add validation middleware with type-safe configuration.
|
|
1859
|
+
*/
|
|
1860
|
+
withValidation(validator, _options) {
|
|
1861
|
+
this.middlewares.push((machine) => withValidation(machine, validator));
|
|
1862
|
+
return this;
|
|
1863
|
+
}
|
|
1864
|
+
/**
|
|
1865
|
+
* Add permission checking middleware with type-safe configuration.
|
|
1866
|
+
*/
|
|
1867
|
+
withPermissions(checker) {
|
|
1868
|
+
this.middlewares.push((machine) => withPermissions(machine, checker));
|
|
1869
|
+
return this;
|
|
1870
|
+
}
|
|
1871
|
+
/**
|
|
1872
|
+
* Add error reporting middleware with type-safe configuration.
|
|
1873
|
+
*/
|
|
1874
|
+
withErrorReporting(reporter, options) {
|
|
1875
|
+
this.middlewares.push((machine) => withErrorReporting(machine, reporter, options));
|
|
1876
|
+
return this;
|
|
1877
|
+
}
|
|
1878
|
+
/**
|
|
1879
|
+
* Add performance monitoring middleware with type-safe configuration.
|
|
1880
|
+
*/
|
|
1881
|
+
withPerformanceMonitoring(tracker, _options) {
|
|
1882
|
+
this.middlewares.push((machine) => withPerformanceMonitoring(machine, tracker));
|
|
1883
|
+
return this;
|
|
1884
|
+
}
|
|
1885
|
+
/**
|
|
1886
|
+
* Add retry middleware with type-safe configuration.
|
|
1887
|
+
*/
|
|
1888
|
+
withRetry(options) {
|
|
1889
|
+
this.middlewares.push((machine) => withRetry(machine, options));
|
|
1890
|
+
return this;
|
|
1891
|
+
}
|
|
1892
|
+
/**
|
|
1893
|
+
* Add history tracking middleware with type-safe configuration.
|
|
1894
|
+
*/
|
|
1895
|
+
withHistory(options) {
|
|
1896
|
+
this.middlewares.push((machine) => withHistory(machine, options));
|
|
1897
|
+
return this;
|
|
1898
|
+
}
|
|
1899
|
+
/**
|
|
1900
|
+
* Add snapshot tracking middleware with type-safe configuration.
|
|
1901
|
+
*/
|
|
1902
|
+
withSnapshot(options) {
|
|
1903
|
+
this.middlewares.push((machine) => withSnapshot(machine, options));
|
|
1904
|
+
return this;
|
|
1905
|
+
}
|
|
1906
|
+
/**
|
|
1907
|
+
* Add time travel middleware with type-safe configuration.
|
|
1908
|
+
*/
|
|
1909
|
+
withTimeTravel(options) {
|
|
1910
|
+
this.middlewares.push((machine) => withTimeTravel(machine, options));
|
|
1911
|
+
return this;
|
|
1912
|
+
}
|
|
1913
|
+
/**
|
|
1914
|
+
* Add debugging middleware (combination of history, snapshot, and time travel).
|
|
1915
|
+
*/
|
|
1916
|
+
withDebugging() {
|
|
1917
|
+
this.middlewares.push((machine) => withDebugging(machine));
|
|
1918
|
+
return this;
|
|
1919
|
+
}
|
|
1920
|
+
/**
|
|
1921
|
+
* Add a custom middleware function.
|
|
1922
|
+
*/
|
|
1923
|
+
withCustom(middleware) {
|
|
1924
|
+
this.middlewares.push(middleware);
|
|
1925
|
+
return this;
|
|
1926
|
+
}
|
|
1927
|
+
/**
|
|
1928
|
+
* Add a conditional middleware.
|
|
1929
|
+
*/
|
|
1930
|
+
withConditional(middleware, predicate) {
|
|
1931
|
+
this.middlewares.push(when(middleware, predicate));
|
|
1932
|
+
return this;
|
|
1933
|
+
}
|
|
1934
|
+
/**
|
|
1935
|
+
* Build the final machine with all configured middleware applied.
|
|
1936
|
+
*/
|
|
1937
|
+
build() {
|
|
1938
|
+
let result = this.machine;
|
|
1939
|
+
for (const middleware of this.middlewares) {
|
|
1940
|
+
result = middleware(result);
|
|
1941
|
+
}
|
|
1942
|
+
return result;
|
|
1943
|
+
}
|
|
1944
|
+
/**
|
|
1945
|
+
* Get the middleware chain without building (for inspection or further composition).
|
|
1946
|
+
*/
|
|
1947
|
+
getChain() {
|
|
1948
|
+
return [...this.middlewares];
|
|
1949
|
+
}
|
|
1950
|
+
/**
|
|
1951
|
+
* Clear all configured middleware.
|
|
1952
|
+
*/
|
|
1953
|
+
clear() {
|
|
1954
|
+
this.middlewares = [];
|
|
1955
|
+
return this;
|
|
1956
|
+
}
|
|
1957
|
+
};
|
|
1958
|
+
function middlewareBuilder(machine) {
|
|
1959
|
+
return new MiddlewareBuilder(machine);
|
|
1960
|
+
}
|
|
1961
|
+
function createMiddlewareFactory(defaultOptions = {}) {
|
|
1962
|
+
return {
|
|
1963
|
+
create: (machine) => {
|
|
1964
|
+
const builder = middlewareBuilder(machine);
|
|
1965
|
+
if (defaultOptions.logging) {
|
|
1966
|
+
builder.withLogging(defaultOptions.logging);
|
|
1967
|
+
}
|
|
1968
|
+
if (defaultOptions.analytics) {
|
|
1969
|
+
builder.withAnalytics(
|
|
1970
|
+
defaultOptions.analytics.track,
|
|
1971
|
+
defaultOptions.analytics.options
|
|
1972
|
+
);
|
|
1973
|
+
}
|
|
1974
|
+
if (defaultOptions.history) {
|
|
1975
|
+
builder.withHistory(defaultOptions.history);
|
|
1976
|
+
}
|
|
1977
|
+
if (defaultOptions.snapshot) {
|
|
1978
|
+
builder.withSnapshot(defaultOptions.snapshot);
|
|
1979
|
+
}
|
|
1980
|
+
if (defaultOptions.timeTravel) {
|
|
1981
|
+
builder.withTimeTravel(defaultOptions.timeTravel);
|
|
1982
|
+
}
|
|
1983
|
+
if (defaultOptions.retry) {
|
|
1984
|
+
builder.withRetry(defaultOptions.retry);
|
|
1985
|
+
}
|
|
1986
|
+
return builder;
|
|
1987
|
+
}
|
|
1988
|
+
};
|
|
1989
|
+
}
|
|
1990
|
+
function withDebugging(machine) {
|
|
1991
|
+
return withTimeTravel(withSnapshot(withHistory(machine)));
|
|
2070
1992
|
}
|
|
2071
1993
|
|
|
2072
1994
|
// src/utils.ts
|
|
@@ -2185,17 +2107,69 @@ function createFunctionalMachine(initialContext) {
|
|
|
2185
2107
|
return createMachine(initialContext, transitions);
|
|
2186
2108
|
};
|
|
2187
2109
|
}
|
|
2110
|
+
function state(context, transitions) {
|
|
2111
|
+
if (transitions !== void 0) {
|
|
2112
|
+
return createMachine(context, transitions);
|
|
2113
|
+
}
|
|
2114
|
+
return createFunctionalMachine(context);
|
|
2115
|
+
}
|
|
2188
2116
|
|
|
2189
2117
|
// src/index.ts
|
|
2190
|
-
function createMachine(context,
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2118
|
+
function createMachine(context, fnsOrFactory) {
|
|
2119
|
+
if (typeof fnsOrFactory === "function") {
|
|
2120
|
+
let transitions2;
|
|
2121
|
+
const transition = (newContext) => {
|
|
2122
|
+
const machine2 = createMachine(newContext, transitions2);
|
|
2123
|
+
const boundTransitions2 = Object.fromEntries(
|
|
2124
|
+
Object.entries(transitions2).map(([key, fn]) => [
|
|
2125
|
+
key,
|
|
2126
|
+
fn.bind(newContext)
|
|
2127
|
+
])
|
|
2128
|
+
);
|
|
2129
|
+
return Object.assign(machine2, boundTransitions2);
|
|
2130
|
+
};
|
|
2131
|
+
transitions2 = fnsOrFactory(transition);
|
|
2132
|
+
const boundTransitions = Object.fromEntries(
|
|
2133
|
+
Object.entries(transitions2).map(([key, fn]) => [
|
|
2134
|
+
key,
|
|
2135
|
+
fn.bind(context)
|
|
2136
|
+
])
|
|
2137
|
+
);
|
|
2138
|
+
return Object.assign({ context }, boundTransitions);
|
|
2139
|
+
}
|
|
2140
|
+
const transitions = "context" in fnsOrFactory ? Object.fromEntries(
|
|
2141
|
+
Object.entries(fnsOrFactory).filter(([key]) => key !== "context")
|
|
2142
|
+
) : fnsOrFactory;
|
|
2194
2143
|
const machine = Object.assign({ context }, transitions);
|
|
2195
2144
|
return machine;
|
|
2196
2145
|
}
|
|
2197
|
-
function createAsyncMachine(context,
|
|
2198
|
-
|
|
2146
|
+
function createAsyncMachine(context, fnsOrFactory) {
|
|
2147
|
+
if (typeof fnsOrFactory === "function") {
|
|
2148
|
+
let transitions2;
|
|
2149
|
+
const transition = (newContext) => {
|
|
2150
|
+
const machine2 = createAsyncMachine(newContext, transitions2);
|
|
2151
|
+
const boundTransitions2 = Object.fromEntries(
|
|
2152
|
+
Object.entries(transitions2).map(([key, fn]) => [
|
|
2153
|
+
key,
|
|
2154
|
+
fn.bind(newContext)
|
|
2155
|
+
])
|
|
2156
|
+
);
|
|
2157
|
+
return Object.assign(machine2, boundTransitions2);
|
|
2158
|
+
};
|
|
2159
|
+
transitions2 = fnsOrFactory(transition);
|
|
2160
|
+
const boundTransitions = Object.fromEntries(
|
|
2161
|
+
Object.entries(transitions2).map(([key, fn]) => [
|
|
2162
|
+
key,
|
|
2163
|
+
fn.bind(context)
|
|
2164
|
+
])
|
|
2165
|
+
);
|
|
2166
|
+
return Object.assign({ context }, boundTransitions);
|
|
2167
|
+
}
|
|
2168
|
+
const transitions = "context" in fnsOrFactory ? Object.fromEntries(
|
|
2169
|
+
Object.entries(fnsOrFactory).filter(([key]) => key !== "context")
|
|
2170
|
+
) : fnsOrFactory;
|
|
2171
|
+
const machine = Object.assign({ context }, transitions);
|
|
2172
|
+
return machine;
|
|
2199
2173
|
}
|
|
2200
2174
|
function createMachineFactory() {
|
|
2201
2175
|
return (transformers) => {
|
|
@@ -2203,7 +2177,7 @@ function createMachineFactory() {
|
|
|
2203
2177
|
Object.entries(transformers).map(([key, transform]) => [
|
|
2204
2178
|
key,
|
|
2205
2179
|
function(...args) {
|
|
2206
|
-
const newContext = transform(this, ...args);
|
|
2180
|
+
const newContext = transform(this.context, ...args);
|
|
2207
2181
|
return createMachine(newContext, fns);
|
|
2208
2182
|
}
|
|
2209
2183
|
])
|