jssm 5.162.4 → 5.162.6
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 +7 -7
- package/dist/cdn/instance.js +1 -1
- package/dist/cdn/viz.js +1 -1
- package/dist/cli/fsl-export-system-prompt.cjs +1 -1
- package/dist/cli/fsl-render.cjs +1 -1
- package/dist/cli/fsl.cjs +1 -1
- package/dist/cli/lib.cjs +1 -1
- package/dist/cli/lib.mjs +1 -1
- package/dist/deno/README.md +7 -7
- package/dist/deno/jssm.d.ts +87 -2
- package/dist/deno/jssm.js +1 -1
- package/dist/deno/jssm_types.d.ts +11 -5
- package/dist/fence/fence.js +141 -15
- package/dist/jssm.es5.cjs +1 -1
- package/dist/jssm.es5.iife.js +1 -1
- package/dist/jssm.es6.mjs +1 -1
- package/dist/jssm_viz.cjs +1 -1
- package/dist/jssm_viz.iife.cjs +1 -1
- package/dist/jssm_viz.mjs +1 -1
- package/jssm.es5.d.cts +98 -7
- package/jssm.es6.d.ts +98 -7
- package/jssm.fence.d.ts +98 -7
- package/jssm_viz.es5.d.cts +98 -7
- package/jssm_viz.es6.d.ts +98 -7
- package/package.json +1 -1
|
@@ -883,6 +883,10 @@ type AfterHook<mDT> = {
|
|
|
883
883
|
from: string;
|
|
884
884
|
handler: HookHandler<mDT>;
|
|
885
885
|
};
|
|
886
|
+
type AfterAnyHook<mDT> = {
|
|
887
|
+
kind: 'after any';
|
|
888
|
+
handler: HookHandler<mDT>;
|
|
889
|
+
};
|
|
886
890
|
type PostBasicHookDescription<mDT> = {
|
|
887
891
|
kind: 'post hook';
|
|
888
892
|
from: string;
|
|
@@ -956,12 +960,12 @@ type PostEverythingHook<mDT> = {
|
|
|
956
960
|
*
|
|
957
961
|
* Pre-transition variants (`'hook'`, `'named'`, `'standard transition'`,
|
|
958
962
|
* `'main transition'`, `'forced transition'`, `'any transition'`,
|
|
959
|
-
* `'global action'`, `'any action'`, `'entry'`, `'exit'`, `'after'
|
|
960
|
-
* may return a falsy value to veto a transition. Post-transition
|
|
963
|
+
* `'global action'`, `'any action'`, `'entry'`, `'exit'`, `'after'`,
|
|
964
|
+
* `'after any'`) may return a falsy value to veto a transition. Post-transition
|
|
961
965
|
* variants (`'post *'`) cannot veto and are invoked only after a
|
|
962
966
|
* successful transition.
|
|
963
967
|
*/
|
|
964
|
-
type HookDescription<mDT> = BasicHookDescription<mDT> | HookDescriptionWithAction<mDT> | GlobalActionHook<mDT> | AnyActionHook<mDT> | StandardTransitionHook<mDT> | MainTransitionHook<mDT> | ForcedTransitionHook<mDT> | AnyTransitionHook<mDT> | EntryHook<mDT> | ExitHook<mDT> | AfterHook<mDT> | PostBasicHookDescription<mDT> | PostHookDescriptionWithAction<mDT> | PostGlobalActionHook<mDT> | PostAnyActionHook<mDT> | PostStandardTransitionHook<mDT> | PostMainTransitionHook<mDT> | PostForcedTransitionHook<mDT> | PostAnyTransitionHook<mDT> | PostEntryHook<mDT> | PostExitHook<mDT> | PreEverythingHook<mDT> | EverythingHook<mDT> | PrePostEverythingHook<mDT> | PostEverythingHook<mDT>;
|
|
968
|
+
type HookDescription<mDT> = BasicHookDescription<mDT> | HookDescriptionWithAction<mDT> | GlobalActionHook<mDT> | AnyActionHook<mDT> | StandardTransitionHook<mDT> | MainTransitionHook<mDT> | ForcedTransitionHook<mDT> | AnyTransitionHook<mDT> | EntryHook<mDT> | ExitHook<mDT> | AfterHook<mDT> | AfterAnyHook<mDT> | PostBasicHookDescription<mDT> | PostHookDescriptionWithAction<mDT> | PostGlobalActionHook<mDT> | PostAnyActionHook<mDT> | PostStandardTransitionHook<mDT> | PostMainTransitionHook<mDT> | PostForcedTransitionHook<mDT> | PostAnyTransitionHook<mDT> | PostEntryHook<mDT> | PostExitHook<mDT> | PreEverythingHook<mDT> | EverythingHook<mDT> | PrePostEverythingHook<mDT> | PostEverythingHook<mDT>;
|
|
965
969
|
/**
|
|
966
970
|
* Whether an observational hook runs in the pre-transition phase (where it
|
|
967
971
|
* may veto/mutate the transition) or the post-transition phase (a pure
|
|
@@ -1235,7 +1239,9 @@ type JssmErrorEventDetail = {
|
|
|
1235
1239
|
/**
|
|
1236
1240
|
* Detail payload fired with a `data-change` event. Fires whenever the
|
|
1237
1241
|
* machine's data payload is replaced. `old_data` is the value before the
|
|
1238
|
-
* change; `new_data` is the value after.
|
|
1242
|
+
* change; `new_data` is the value after. `cause` names the API family that
|
|
1243
|
+
* performed the replacement: a data-bearing `transition`, an `override`, or
|
|
1244
|
+
* a direct `set_data` call.
|
|
1239
1245
|
*/
|
|
1240
1246
|
type JssmDataChangeEventDetail<mDT> = {
|
|
1241
1247
|
from?: StateType;
|
|
@@ -1243,7 +1249,7 @@ type JssmDataChangeEventDetail<mDT> = {
|
|
|
1243
1249
|
action?: StateType;
|
|
1244
1250
|
old_data: mDT;
|
|
1245
1251
|
new_data: mDT;
|
|
1246
|
-
cause: 'transition' | 'override';
|
|
1252
|
+
cause: 'transition' | 'override' | 'set_data';
|
|
1247
1253
|
};
|
|
1248
1254
|
/**
|
|
1249
1255
|
* Detail payload fired with an `override` event. Distinguishes a forced
|
package/dist/fence/fence.js
CHANGED
|
@@ -23790,7 +23790,7 @@ function fslSemanticSpans(text) {
|
|
|
23790
23790
|
* Useful for runtime diagnostics and for embedding in serialized machine
|
|
23791
23791
|
* snapshots so that deserializers can detect version-skew.
|
|
23792
23792
|
*/
|
|
23793
|
-
const version = "5.162.
|
|
23793
|
+
const version = "5.162.6";
|
|
23794
23794
|
|
|
23795
23795
|
/**
|
|
23796
23796
|
* The FSL Markdown fence convention parser — pure, host-agnostic logic that
|
|
@@ -23970,6 +23970,7 @@ const hook_required_fields = {
|
|
|
23970
23970
|
'entry': ['to'],
|
|
23971
23971
|
'exit': ['from'],
|
|
23972
23972
|
'after': ['from'],
|
|
23973
|
+
'after any': [],
|
|
23973
23974
|
'post hook': ['from', 'to'],
|
|
23974
23975
|
'post named': ['from', 'to', 'action'],
|
|
23975
23976
|
'post global action': ['action'],
|
|
@@ -24338,6 +24339,7 @@ class Machine {
|
|
|
24338
24339
|
this._entry_hooks = new Map();
|
|
24339
24340
|
this._exit_hooks = new Map();
|
|
24340
24341
|
this._after_hooks = new Map();
|
|
24342
|
+
this._after_any_hook = undefined;
|
|
24341
24343
|
this._global_action_hooks = new Map();
|
|
24342
24344
|
this._any_action_hook = undefined;
|
|
24343
24345
|
this._standard_transition_hook = undefined;
|
|
@@ -24852,6 +24854,53 @@ class Machine {
|
|
|
24852
24854
|
data() {
|
|
24853
24855
|
return structuredClone(this._data);
|
|
24854
24856
|
}
|
|
24857
|
+
/*********
|
|
24858
|
+
*
|
|
24859
|
+
* Replace the machine's data in place, without a transition. This is the
|
|
24860
|
+
* practical way to assign any value — including `undefined`, `null`, or
|
|
24861
|
+
* `false` — outside a hook's complex return, closing the gap where an
|
|
24862
|
+
* `undefined` assignment had no direct API (StoneCypher/fsl#1264). Fires
|
|
24863
|
+
* a `data-change` event with cause `'set_data'` when the value actually
|
|
24864
|
+
* changes; unlike {@link override} it requires no `allows_override`
|
|
24865
|
+
* config, because it never moves the state.
|
|
24866
|
+
*
|
|
24867
|
+
* ```typescript
|
|
24868
|
+
* import * as jssm from 'jssm';
|
|
24869
|
+
*
|
|
24870
|
+
* const lswitch = jssm.from('on <=> off;', {data: 1});
|
|
24871
|
+
* console.log( lswitch.data() ); // 1
|
|
24872
|
+
*
|
|
24873
|
+
* lswitch.set_data(2);
|
|
24874
|
+
* console.log( lswitch.data() ); // 2
|
|
24875
|
+
*
|
|
24876
|
+
* lswitch.set_data(undefined);
|
|
24877
|
+
* console.log( lswitch.data() ); // undefined
|
|
24878
|
+
* ```
|
|
24879
|
+
*
|
|
24880
|
+
* @typeParam mDT The type of the machine data member; usually omitted
|
|
24881
|
+
*
|
|
24882
|
+
* @param newData The value to install as the machine's data.
|
|
24883
|
+
*
|
|
24884
|
+
* @returns The machine, for chaining.
|
|
24885
|
+
*
|
|
24886
|
+
* @see Machine.data
|
|
24887
|
+
* @see override
|
|
24888
|
+
*
|
|
24889
|
+
*/
|
|
24890
|
+
set_data(newData) {
|
|
24891
|
+
const oldData = this._data;
|
|
24892
|
+
this._data = newData;
|
|
24893
|
+
if (oldData !== newData) {
|
|
24894
|
+
this._fire('data-change', {
|
|
24895
|
+
from: this._state,
|
|
24896
|
+
to: this._state,
|
|
24897
|
+
old_data: oldData,
|
|
24898
|
+
new_data: newData,
|
|
24899
|
+
cause: 'set_data'
|
|
24900
|
+
});
|
|
24901
|
+
}
|
|
24902
|
+
return this;
|
|
24903
|
+
}
|
|
24855
24904
|
/**
|
|
24856
24905
|
* The machine's current data by REFERENCE — no clone. The public
|
|
24857
24906
|
* {@link Machine.data} contract is a deep clone per call (a mutation
|
|
@@ -26629,6 +26678,11 @@ class Machine {
|
|
|
26629
26678
|
this._has_hooks = true;
|
|
26630
26679
|
this._has_after_hooks = true;
|
|
26631
26680
|
break;
|
|
26681
|
+
case 'after any':
|
|
26682
|
+
this._after_any_hook = HookDesc.handler;
|
|
26683
|
+
this._has_hooks = true;
|
|
26684
|
+
this._has_after_hooks = true;
|
|
26685
|
+
break;
|
|
26632
26686
|
case 'post hook': {
|
|
26633
26687
|
// Numeric pair key; same rationale as 'hook' (#729).
|
|
26634
26688
|
this._post_hooks.set(pair_key(this._state_interner.intern(HookDesc.from), this._state_interner.intern(HookDesc.to)), HookDesc.handler);
|
|
@@ -26800,6 +26854,12 @@ class Machine {
|
|
|
26800
26854
|
case 'after':
|
|
26801
26855
|
removed = this._after_hooks.delete(HookDesc.from);
|
|
26802
26856
|
break;
|
|
26857
|
+
case 'after any':
|
|
26858
|
+
if (this._after_any_hook !== undefined) {
|
|
26859
|
+
this._after_any_hook = undefined;
|
|
26860
|
+
removed = true;
|
|
26861
|
+
}
|
|
26862
|
+
break;
|
|
26803
26863
|
case 'post hook': {
|
|
26804
26864
|
const fid = this._state_interner.id_of(HookDesc.from), tid = this._state_interner.id_of(HookDesc.to);
|
|
26805
26865
|
removed = (fid !== undefined) && (tid !== undefined) && this._post_hooks.delete(pair_key(fid, tid));
|
|
@@ -27017,6 +27077,36 @@ class Machine {
|
|
|
27017
27077
|
this.set_hook({ kind: 'after', from, handler });
|
|
27018
27078
|
return this;
|
|
27019
27079
|
}
|
|
27080
|
+
/** Register a hook that fires when ANY state's `after` timer elapses — the
|
|
27081
|
+
* whole-machine companion to {@link hook_after}, mirroring how
|
|
27082
|
+
* {@link hook_any_transition} companions {@link hook}. When the elapsing
|
|
27083
|
+
* state also has a specific {@link hook_after}, the specific hook fires
|
|
27084
|
+
* first and this one fires second; a specific after hook firing always
|
|
27085
|
+
* implies the any-after hook fires too (StoneCypher/fsl#1299). Like
|
|
27086
|
+
* `hook_after` it is informational — its outcome cannot reject the timed
|
|
27087
|
+
* transition — and it does NOT fire on ordinary dispatch.
|
|
27088
|
+
* @param handler - Callback invoked whenever any `after` timer fires, just
|
|
27089
|
+
* before the timed transition is taken.
|
|
27090
|
+
* @returns `this` for chaining.
|
|
27091
|
+
*
|
|
27092
|
+
* @example
|
|
27093
|
+
* const m = sm`a after 1000 -> b; a -> c; c -> a;`;
|
|
27094
|
+
* let calls = 0;
|
|
27095
|
+
* m.hook_after_any(() => { calls += 1; });
|
|
27096
|
+
* m.go('c');
|
|
27097
|
+
* m.go('a');
|
|
27098
|
+
* // ordinary dispatch never fires it; only a timer elapsing does:
|
|
27099
|
+
* calls; // => 0
|
|
27100
|
+
* m.clear_state_timeout();
|
|
27101
|
+
*
|
|
27102
|
+
* @see hook_after
|
|
27103
|
+
* @see hook_any_transition
|
|
27104
|
+
* @see set_state_timeout
|
|
27105
|
+
*/
|
|
27106
|
+
hook_after_any(handler) {
|
|
27107
|
+
this.set_hook({ kind: 'after any', handler });
|
|
27108
|
+
return this;
|
|
27109
|
+
}
|
|
27020
27110
|
/** Post-transition hook on a specific edge. Fires after the transition
|
|
27021
27111
|
* from `from` to `to` has completed. Cannot block the transition.
|
|
27022
27112
|
* @param from - Source state name.
|
|
@@ -27243,7 +27333,13 @@ class Machine {
|
|
|
27243
27333
|
}
|
|
27244
27334
|
/*********
|
|
27245
27335
|
*
|
|
27246
|
-
* Replace the current state and data
|
|
27336
|
+
* Replace the current state — and, when a data argument is provided, the
|
|
27337
|
+
* data — with no regard to the graph.
|
|
27338
|
+
*
|
|
27339
|
+
* The data argument is arity-detected: omitting it preserves the current
|
|
27340
|
+
* data, while explicitly passing `undefined` really sets the data to
|
|
27341
|
+
* `undefined` (StoneCypher/fsl#1264). Before 5.163 an omitted data
|
|
27342
|
+
* argument silently cleared the data.
|
|
27247
27343
|
*
|
|
27248
27344
|
* ```typescript
|
|
27249
27345
|
* import { sm } from 'jssm';
|
|
@@ -27259,22 +27355,37 @@ class Machine {
|
|
|
27259
27355
|
* console.log( machine.state() ); // 'a'
|
|
27260
27356
|
* ```
|
|
27261
27357
|
*
|
|
27358
|
+
* @param newState The state to teleport to; must exist in the graph.
|
|
27359
|
+
*
|
|
27360
|
+
* @param newData Replacement data. Omit to keep the current data; pass
|
|
27361
|
+
* `undefined` explicitly to clear it.
|
|
27362
|
+
*
|
|
27363
|
+
* @throws {JssmError} If the machine's config does not set
|
|
27364
|
+
* `allows_override: true`, or if `newState` does not exist.
|
|
27365
|
+
*
|
|
27366
|
+
* @see set_data
|
|
27367
|
+
*
|
|
27262
27368
|
*/
|
|
27263
27369
|
override(newState, newData) {
|
|
27370
|
+
// arity, not undefined-comparison: an omitted argument preserves the
|
|
27371
|
+
// data, an explicit `undefined` clears it (StoneCypher/fsl#1264)
|
|
27372
|
+
const dataProvided = arguments.length >= 2;
|
|
27264
27373
|
if (this.allows_override) {
|
|
27265
27374
|
if (this._states.has(newState)) {
|
|
27266
27375
|
const fromState = this._state;
|
|
27267
27376
|
const oldData = this._data;
|
|
27268
27377
|
this._state = newState;
|
|
27269
27378
|
this._state_id = this._state_interner.intern(newState);
|
|
27270
|
-
|
|
27379
|
+
if (dataProvided) {
|
|
27380
|
+
this._data = newData;
|
|
27381
|
+
}
|
|
27271
27382
|
this._fire('override', {
|
|
27272
27383
|
from: fromState,
|
|
27273
27384
|
to: newState,
|
|
27274
27385
|
old_data: oldData,
|
|
27275
|
-
new_data:
|
|
27386
|
+
new_data: this._data
|
|
27276
27387
|
});
|
|
27277
|
-
if (oldData !== newData) {
|
|
27388
|
+
if (dataProvided && (oldData !== newData)) {
|
|
27278
27389
|
this._fire('data-change', {
|
|
27279
27390
|
from: fromState,
|
|
27280
27391
|
to: newState,
|
|
@@ -27482,13 +27593,20 @@ class Machine {
|
|
|
27482
27593
|
* `newStateOrAction` is an action name and the target state is looked up
|
|
27483
27594
|
* via the current action edge.
|
|
27484
27595
|
*
|
|
27596
|
+
* @param dataProvided `true` when the caller explicitly supplied a data
|
|
27597
|
+
* argument — even an explicitly-`undefined` one, which commits `undefined`
|
|
27598
|
+
* as the new data (StoneCypher/fsl#1264). When `false` the current data
|
|
27599
|
+
* is preserved. The public wrappers derive this from call arity; the
|
|
27600
|
+
* default reproduces the old `!== undefined` inference for any direct
|
|
27601
|
+
* callers.
|
|
27602
|
+
*
|
|
27485
27603
|
* @returns `true` if the transition was valid and every hook passed;
|
|
27486
27604
|
* `false` if the transition was invalid or any hook rejected.
|
|
27487
27605
|
*
|
|
27488
27606
|
* @internal
|
|
27489
27607
|
*
|
|
27490
27608
|
*/
|
|
27491
|
-
transition_impl(newStateOrAction, newData, wasForced, wasAction) {
|
|
27609
|
+
transition_impl(newStateOrAction, newData, wasForced, wasAction, dataProvided = newData !== undefined) {
|
|
27492
27610
|
let valid = false, trans_type, newState, newStateId = NaN, actionId = NaN, fromAction = undefined;
|
|
27493
27611
|
if (wasForced) {
|
|
27494
27612
|
// numeric inline of valid_force_transition: any existing edge
|
|
@@ -27753,7 +27871,7 @@ class Machine {
|
|
|
27753
27871
|
if (data_changed) {
|
|
27754
27872
|
this._data = hook_args.data;
|
|
27755
27873
|
}
|
|
27756
|
-
else if (
|
|
27874
|
+
else if (dataProvided) {
|
|
27757
27875
|
this._data = newData;
|
|
27758
27876
|
}
|
|
27759
27877
|
// success fallthrough to posthooks; intentionally no return here
|
|
@@ -27766,9 +27884,9 @@ class Machine {
|
|
|
27766
27884
|
}
|
|
27767
27885
|
this._state = newState;
|
|
27768
27886
|
this._state_id = newStateId;
|
|
27769
|
-
//
|
|
27770
|
-
//
|
|
27771
|
-
if (
|
|
27887
|
+
// provision is detected by caller arity, so an explicit `undefined`
|
|
27888
|
+
// commits while an omitted argument preserves (StoneCypher/fsl#1264)
|
|
27889
|
+
if (dataProvided) {
|
|
27772
27890
|
this._data = newData;
|
|
27773
27891
|
}
|
|
27774
27892
|
// success fallthrough to posthooks; intentionally no return here
|
|
@@ -28081,7 +28199,9 @@ class Machine {
|
|
|
28081
28199
|
*
|
|
28082
28200
|
*/
|
|
28083
28201
|
action(actionName, newData) {
|
|
28084
|
-
|
|
28202
|
+
// arity, not undefined-comparison: an explicit `undefined` is a real
|
|
28203
|
+
// data assignment (StoneCypher/fsl#1264)
|
|
28204
|
+
return this.transition_impl(actionName, newData, false, true, arguments.length >= 2);
|
|
28085
28205
|
}
|
|
28086
28206
|
/********
|
|
28087
28207
|
*
|
|
@@ -28345,6 +28465,7 @@ class Machine {
|
|
|
28345
28465
|
push_global(this._main_transition_hook, 'main transition', 'pre');
|
|
28346
28466
|
push_global(this._forced_transition_hook, 'forced transition', 'pre');
|
|
28347
28467
|
push_global(this._any_transition_hook, 'any transition', 'pre');
|
|
28468
|
+
push_global(this._after_any_hook, 'after any', 'pre');
|
|
28348
28469
|
push_global(this._pre_everything_hook, 'pre everything', 'pre');
|
|
28349
28470
|
push_global(this._everything_hook, 'everything', 'pre');
|
|
28350
28471
|
// post-phase, edge- and state-keyed tables
|
|
@@ -28859,7 +28980,7 @@ class Machine {
|
|
|
28859
28980
|
*
|
|
28860
28981
|
*/
|
|
28861
28982
|
do(actionName, newData) {
|
|
28862
|
-
return this.transition_impl(actionName, newData, false, true);
|
|
28983
|
+
return this.transition_impl(actionName, newData, false, true, arguments.length >= 2);
|
|
28863
28984
|
}
|
|
28864
28985
|
/********
|
|
28865
28986
|
*
|
|
@@ -28893,7 +29014,7 @@ class Machine {
|
|
|
28893
29014
|
*
|
|
28894
29015
|
*/
|
|
28895
29016
|
transition(newState, newData) {
|
|
28896
|
-
return this.transition_impl(newState, newData, false, false);
|
|
29017
|
+
return this.transition_impl(newState, newData, false, false, arguments.length >= 2);
|
|
28897
29018
|
}
|
|
28898
29019
|
/********
|
|
28899
29020
|
*
|
|
@@ -28917,7 +29038,7 @@ class Machine {
|
|
|
28917
29038
|
*
|
|
28918
29039
|
*/
|
|
28919
29040
|
go(newState, newData) {
|
|
28920
|
-
return this.transition_impl(newState, newData, false, false);
|
|
29041
|
+
return this.transition_impl(newState, newData, false, false, arguments.length >= 2);
|
|
28921
29042
|
}
|
|
28922
29043
|
/********
|
|
28923
29044
|
*
|
|
@@ -28945,7 +29066,7 @@ class Machine {
|
|
|
28945
29066
|
*
|
|
28946
29067
|
*/
|
|
28947
29068
|
force_transition(newState, newData) {
|
|
28948
|
-
return this.transition_impl(newState, newData, true, false);
|
|
29069
|
+
return this.transition_impl(newState, newData, true, false, arguments.length >= 2);
|
|
28949
29070
|
}
|
|
28950
29071
|
/** Get the edge index for an action from the current state.
|
|
28951
29072
|
* Interned dispatch: resolves via the numeric (action, from) index —
|
|
@@ -29058,6 +29179,11 @@ class Machine {
|
|
|
29058
29179
|
if (ah !== undefined) {
|
|
29059
29180
|
ah({ data: this._data, next_data: this._data });
|
|
29060
29181
|
}
|
|
29182
|
+
// a specific after hook firing implies the any-after hook fires too,
|
|
29183
|
+
// afterward; and it also fires alone (StoneCypher/fsl#1299)
|
|
29184
|
+
if (this._after_any_hook !== undefined) {
|
|
29185
|
+
this._after_any_hook({ data: this._data, next_data: this._data });
|
|
29186
|
+
}
|
|
29061
29187
|
}
|
|
29062
29188
|
this._fire('timeout', { from: from_state, to: next_state, after_time });
|
|
29063
29189
|
this.go(next_state);
|