jssm 5.141.4 → 5.141.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 +3 -3
- package/dist/cdn/instance.js +203 -93
- package/dist/cdn/viz.js +203 -93
- package/dist/cli/fsl-render.cjs +1 -1
- package/dist/cli/fsl.cjs +1 -1
- package/dist/deno/README.md +3 -3
- package/dist/deno/jssm.d.ts +46 -0
- package/dist/deno/jssm.js +1 -1
- 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 +46 -0
- package/jssm.es6.d.ts +46 -0
- package/jssm_viz.es5.d.cts +46 -0
- package/jssm_viz.es6.d.ts +46 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,10 +18,10 @@ Please edit the file it's derived from, instead: `./src/md/readme_base.md`
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
* Generated for version 5.141.
|
|
21
|
+
* Generated for version 5.141.6 at 6/4/2026, 4:19:34 PM
|
|
22
22
|
|
|
23
23
|
-->
|
|
24
|
-
# jssm 5.141.
|
|
24
|
+
# jssm 5.141.6
|
|
25
25
|
|
|
26
26
|
[**Try the live editor**](https://stonecypher.github.io/jssm-viz-demo/graph_explorer.html) ·
|
|
27
27
|
[Documentation](https://stonecypher.github.io/jssm/docs/) ·
|
|
@@ -418,7 +418,7 @@ If your contribution is missing here, please open an issue.
|
|
|
418
418
|
|
|
419
419
|
- 5,971 specs with 100.0% coverage
|
|
420
420
|
- 513 fuzz tests with 3.4% coverage
|
|
421
|
-
- 5,
|
|
421
|
+
- 5,590 TypeScript lines - 1.2 tests per line, 10.2 generated tests per line
|
|
422
422
|
|
|
423
423
|
[](https://github.com/StoneCypher/jssm/actions)
|
|
424
424
|
[](https://www.npmjs.com/package/jssm)
|
package/dist/cdn/instance.js
CHANGED
|
@@ -21327,7 +21327,7 @@ var constants = /*#__PURE__*/Object.freeze({
|
|
|
21327
21327
|
* Useful for runtime diagnostics and for embedding in serialized machine
|
|
21328
21328
|
* snapshots so that deserializers can detect version-skew.
|
|
21329
21329
|
*/
|
|
21330
|
-
const version = "5.141.
|
|
21330
|
+
const version = "5.141.6";
|
|
21331
21331
|
|
|
21332
21332
|
// whargarbl lots of these return arrays could/should be sets
|
|
21333
21333
|
const { state_name_chars, state_name_first_chars, action_label_chars } = constants;
|
|
@@ -23046,6 +23046,62 @@ class Machine {
|
|
|
23046
23046
|
this._event_listener_count++;
|
|
23047
23047
|
return () => { this._unsubscribe_entry(set, entry); };
|
|
23048
23048
|
}
|
|
23049
|
+
/**
|
|
23050
|
+
* Invoke a single event-handler entry, respecting its filter, once-removal
|
|
23051
|
+
* semantics, and the error re-fire / recursion-guard logic. Extracted so
|
|
23052
|
+
* {@link _fire} can share identical behavior between the size-1 fast-path
|
|
23053
|
+
* and the general snapshotted loop.
|
|
23054
|
+
*
|
|
23055
|
+
* @param entry - The subscriber descriptor to invoke.
|
|
23056
|
+
* @param set - The live Set that owns `entry`; needed for once-removal.
|
|
23057
|
+
* @param name - The event name being dispatched (used in error re-fires).
|
|
23058
|
+
* @param detail - The event payload forwarded to the handler.
|
|
23059
|
+
*
|
|
23060
|
+
* @internal
|
|
23061
|
+
*/
|
|
23062
|
+
_fire_one(entry, set, name, detail) {
|
|
23063
|
+
// filter check
|
|
23064
|
+
if (entry.filter !== undefined) {
|
|
23065
|
+
for (const k of Object.keys(entry.filter)) {
|
|
23066
|
+
if (entry.filter[k] !== detail[k]) {
|
|
23067
|
+
return;
|
|
23068
|
+
}
|
|
23069
|
+
}
|
|
23070
|
+
}
|
|
23071
|
+
// once removal happens BEFORE invocation so a throwing handler still
|
|
23072
|
+
// gets removed and so re-entrant `on` calls during the handler see
|
|
23073
|
+
// the post-removal state.
|
|
23074
|
+
if (entry.once) {
|
|
23075
|
+
this._unsubscribe_entry(set, entry);
|
|
23076
|
+
}
|
|
23077
|
+
try {
|
|
23078
|
+
entry.handler(detail);
|
|
23079
|
+
}
|
|
23080
|
+
catch (err) {
|
|
23081
|
+
if (name === 'error' || this._firing_error) {
|
|
23082
|
+
// surface to stderr as a last resort but never recurse;
|
|
23083
|
+
// `console` is in the JS standard library and present in every
|
|
23084
|
+
// supported runtime, so guarding it would just add an untestable
|
|
23085
|
+
// branch. See #638.
|
|
23086
|
+
// eslint-disable-next-line no-console
|
|
23087
|
+
console.error(err);
|
|
23088
|
+
}
|
|
23089
|
+
else {
|
|
23090
|
+
this._firing_error = true;
|
|
23091
|
+
try {
|
|
23092
|
+
this._fire('error', {
|
|
23093
|
+
error: err,
|
|
23094
|
+
source_event: name,
|
|
23095
|
+
source_detail: detail,
|
|
23096
|
+
handler: entry.handler
|
|
23097
|
+
});
|
|
23098
|
+
}
|
|
23099
|
+
finally {
|
|
23100
|
+
this._firing_error = false;
|
|
23101
|
+
}
|
|
23102
|
+
}
|
|
23103
|
+
}
|
|
23104
|
+
}
|
|
23049
23105
|
/**
|
|
23050
23106
|
* Dispatch an event to every registered subscriber in registration
|
|
23051
23107
|
* order. Filters are checked first; non-matching handlers are skipped
|
|
@@ -23057,6 +23113,11 @@ class Machine {
|
|
|
23057
23113
|
* handler throws, the new exception is swallowed rather than rebroadcast
|
|
23058
23114
|
* to avoid an infinite loop.
|
|
23059
23115
|
*
|
|
23116
|
+
* When exactly one subscriber is registered the common case avoids the
|
|
23117
|
+
* `Array.from(set)` snapshot allocation by capturing the lone entry into a
|
|
23118
|
+
* local first — equivalent to a 1-element snapshot but allocation-free.
|
|
23119
|
+
* The general path still snapshots for re-entrancy safety.
|
|
23120
|
+
*
|
|
23060
23121
|
* @internal
|
|
23061
23122
|
*/
|
|
23062
23123
|
_fire(name, detail) {
|
|
@@ -23064,55 +23125,19 @@ class Machine {
|
|
|
23064
23125
|
if (set === undefined || set.size === 0) {
|
|
23065
23126
|
return;
|
|
23066
23127
|
}
|
|
23067
|
-
//
|
|
23128
|
+
// Fast-path: single subscriber — capture entry before invoking so that
|
|
23129
|
+
// even if the handler mutates `set` (via off/once auto-removal) we hold a
|
|
23130
|
+
// stable reference. Behaviorally identical to a 1-element snapshot.
|
|
23131
|
+
if (set.size === 1) {
|
|
23132
|
+
const only = set.values().next().value;
|
|
23133
|
+
this._fire_one(only, set, name, detail);
|
|
23134
|
+
return;
|
|
23135
|
+
}
|
|
23136
|
+
// General path: snapshot so handlers can `off()` mid-loop without
|
|
23137
|
+
// disturbing iteration.
|
|
23068
23138
|
const entries = Array.from(set);
|
|
23069
23139
|
for (const entry of entries) {
|
|
23070
|
-
|
|
23071
|
-
if (entry.filter !== undefined) {
|
|
23072
|
-
let matched = true;
|
|
23073
|
-
for (const k of Object.keys(entry.filter)) {
|
|
23074
|
-
if (entry.filter[k] !== detail[k]) {
|
|
23075
|
-
matched = false;
|
|
23076
|
-
break;
|
|
23077
|
-
}
|
|
23078
|
-
}
|
|
23079
|
-
if (!matched) {
|
|
23080
|
-
continue;
|
|
23081
|
-
}
|
|
23082
|
-
}
|
|
23083
|
-
// once removal happens BEFORE invocation so a throwing handler still
|
|
23084
|
-
// gets removed and so re-entrant `on` calls during the handler see
|
|
23085
|
-
// the post-removal state.
|
|
23086
|
-
if (entry.once) {
|
|
23087
|
-
this._unsubscribe_entry(set, entry);
|
|
23088
|
-
}
|
|
23089
|
-
try {
|
|
23090
|
-
entry.handler(detail);
|
|
23091
|
-
}
|
|
23092
|
-
catch (err) {
|
|
23093
|
-
if (name === 'error' || this._firing_error) {
|
|
23094
|
-
// surface to stderr as a last resort but never recurse;
|
|
23095
|
-
// `console` is in the JS standard library and present in every
|
|
23096
|
-
// supported runtime, so guarding it would just add an untestable
|
|
23097
|
-
// branch. See #638.
|
|
23098
|
-
// eslint-disable-next-line no-console
|
|
23099
|
-
console.error(err);
|
|
23100
|
-
}
|
|
23101
|
-
else {
|
|
23102
|
-
this._firing_error = true;
|
|
23103
|
-
try {
|
|
23104
|
-
this._fire('error', {
|
|
23105
|
-
error: err,
|
|
23106
|
-
source_event: name,
|
|
23107
|
-
source_detail: detail,
|
|
23108
|
-
handler: entry.handler
|
|
23109
|
-
});
|
|
23110
|
-
}
|
|
23111
|
-
finally {
|
|
23112
|
-
this._firing_error = false;
|
|
23113
|
-
}
|
|
23114
|
-
}
|
|
23115
|
-
}
|
|
23140
|
+
this._fire_one(entry, set, name, detail);
|
|
23116
23141
|
}
|
|
23117
23142
|
}
|
|
23118
23143
|
/** Low-level hook registration. Installs a handler described by a
|
|
@@ -23823,6 +23848,44 @@ class Machine {
|
|
|
23823
23848
|
throw new JssmError(this, "Code specifies no override, but config tries to permit; config may not be less strict than code");
|
|
23824
23849
|
}
|
|
23825
23850
|
}
|
|
23851
|
+
/*********
|
|
23852
|
+
*
|
|
23853
|
+
* Fire a `'rejection'` event caused by a hook vetoing a pending transition.
|
|
23854
|
+
* Extracted from the per-call closures inside {@link transition_impl} so
|
|
23855
|
+
* that it is allocated once at class-definition time rather than on every
|
|
23856
|
+
* hooked transition.
|
|
23857
|
+
*
|
|
23858
|
+
* @param hook_name Name of the hook that rejected (e.g. `'exit'`).
|
|
23859
|
+
* @param fromState State the machine was in when the transition was
|
|
23860
|
+
* attempted; used as the `from` field of the rejection event.
|
|
23861
|
+
* @param newState State that would have been entered had the hook
|
|
23862
|
+
* passed; used as the `to` field of the rejection event.
|
|
23863
|
+
* @param fromAction Action name when the transition was initiated by an
|
|
23864
|
+
* action call; `undefined` for plain state transitions.
|
|
23865
|
+
* @param oldData Machine data at the moment the transition was
|
|
23866
|
+
* attempted, before any hook mutations.
|
|
23867
|
+
* @param newData The `next_data` value passed to the transition call.
|
|
23868
|
+
* @param wasForced Whether the transition was attempted via
|
|
23869
|
+
* `force_transition`.
|
|
23870
|
+
*
|
|
23871
|
+
* @see transition_impl
|
|
23872
|
+
* @see _fire
|
|
23873
|
+
*
|
|
23874
|
+
* @internal
|
|
23875
|
+
*
|
|
23876
|
+
*/
|
|
23877
|
+
_fire_hook_rejection(hook_name, fromState, newState, fromAction, oldData, newData, wasForced) {
|
|
23878
|
+
this._fire('rejection', {
|
|
23879
|
+
from: fromState,
|
|
23880
|
+
to: newState,
|
|
23881
|
+
action: fromAction,
|
|
23882
|
+
data: oldData,
|
|
23883
|
+
next_data: newData,
|
|
23884
|
+
reason: 'hook',
|
|
23885
|
+
hook_name,
|
|
23886
|
+
forced: wasForced
|
|
23887
|
+
});
|
|
23888
|
+
}
|
|
23826
23889
|
/*********
|
|
23827
23890
|
*
|
|
23828
23891
|
* Shared transition core used by {@link transition}, {@link force_transition},
|
|
@@ -23931,75 +23994,68 @@ class Machine {
|
|
|
23931
23994
|
if (this._has_hooks) {
|
|
23932
23995
|
// once validity is known, clear old 'after' timeout clause
|
|
23933
23996
|
this.clear_state_timeout();
|
|
23934
|
-
function update_fields(res) {
|
|
23935
|
-
if (res.hasOwnProperty('data')) {
|
|
23936
|
-
hook_args.data = res.data;
|
|
23937
|
-
hook_args.next_data = res.next_data;
|
|
23938
|
-
data_changed = true;
|
|
23939
|
-
}
|
|
23940
|
-
}
|
|
23941
23997
|
let data_changed = false;
|
|
23942
|
-
const fire_rejection = (hook_name) => {
|
|
23943
|
-
this._fire('rejection', {
|
|
23944
|
-
from: fromState,
|
|
23945
|
-
to: newState,
|
|
23946
|
-
action: fromAction,
|
|
23947
|
-
data: oldData,
|
|
23948
|
-
next_data: newData,
|
|
23949
|
-
reason: 'hook',
|
|
23950
|
-
hook_name,
|
|
23951
|
-
forced: wasForced
|
|
23952
|
-
});
|
|
23953
|
-
};
|
|
23954
23998
|
// 0. pre everything hook (fires before all other pre-hooks)
|
|
23955
23999
|
if (this._pre_everything_hook !== undefined) {
|
|
23956
24000
|
const outcome = abstract_everything_hook_step(this._pre_everything_hook, Object.assign(Object.assign({}, hook_args), { hook_name: 'pre everything' }));
|
|
23957
24001
|
if (outcome.pass === false) {
|
|
23958
|
-
|
|
24002
|
+
this._fire_hook_rejection('pre everything', fromState, newState, fromAction, oldData, newData, wasForced);
|
|
23959
24003
|
return false;
|
|
23960
24004
|
}
|
|
23961
|
-
|
|
24005
|
+
if (_update_hook_fields(hook_args, outcome)) {
|
|
24006
|
+
data_changed = true;
|
|
24007
|
+
}
|
|
23962
24008
|
}
|
|
23963
24009
|
if (wasAction) {
|
|
23964
24010
|
// 1a. any action hook
|
|
23965
24011
|
const outcome = abstract_hook_step(this._any_action_hook, hook_args);
|
|
23966
24012
|
if (outcome.pass === false) {
|
|
23967
|
-
|
|
24013
|
+
this._fire_hook_rejection('any action', fromState, newState, fromAction, oldData, newData, wasForced);
|
|
23968
24014
|
return false;
|
|
23969
24015
|
}
|
|
23970
|
-
|
|
24016
|
+
if (_update_hook_fields(hook_args, outcome)) {
|
|
24017
|
+
data_changed = true;
|
|
24018
|
+
}
|
|
23971
24019
|
// 1b. global specific action hook
|
|
23972
24020
|
const outcome2 = abstract_hook_step(this._global_action_hooks.get(newStateOrAction), hook_args);
|
|
23973
24021
|
if (outcome2.pass === false) {
|
|
23974
|
-
|
|
24022
|
+
this._fire_hook_rejection('global action', fromState, newState, fromAction, oldData, newData, wasForced);
|
|
23975
24023
|
return false;
|
|
23976
24024
|
}
|
|
23977
|
-
|
|
24025
|
+
if (_update_hook_fields(hook_args, outcome2)) {
|
|
24026
|
+
data_changed = true;
|
|
24027
|
+
}
|
|
23978
24028
|
}
|
|
23979
24029
|
// 2. after hook
|
|
23980
24030
|
if (this._has_after_hooks) {
|
|
23981
24031
|
const ah = this._after_hooks.get(newStateOrAction);
|
|
23982
24032
|
const outcome = abstract_hook_step(ah, hook_args);
|
|
23983
|
-
// there's no such thing as after not passing, so, omit the result pass check
|
|
23984
|
-
|
|
24033
|
+
// there's no such thing as after not passing, so, omit the result pass check.
|
|
24034
|
+
// after hooks are post-exit and informational — their outcome never changes
|
|
24035
|
+
// data, so there's no data_changed branch here (it would be unreachable).
|
|
24036
|
+
_update_hook_fields(hook_args, outcome);
|
|
23985
24037
|
}
|
|
23986
24038
|
// 3. any transition hook
|
|
23987
24039
|
if (this._any_transition_hook !== undefined) {
|
|
23988
24040
|
const outcome = abstract_hook_step(this._any_transition_hook, hook_args);
|
|
23989
24041
|
if (outcome.pass === false) {
|
|
23990
|
-
|
|
24042
|
+
this._fire_hook_rejection('any transition', fromState, newState, fromAction, oldData, newData, wasForced);
|
|
23991
24043
|
return false;
|
|
23992
24044
|
}
|
|
23993
|
-
|
|
24045
|
+
if (_update_hook_fields(hook_args, outcome)) {
|
|
24046
|
+
data_changed = true;
|
|
24047
|
+
}
|
|
23994
24048
|
}
|
|
23995
24049
|
// 4. exit hook
|
|
23996
24050
|
if (this._has_exit_hooks) {
|
|
23997
24051
|
const outcome = abstract_hook_step(this._exit_hooks.get(this._state), hook_args);
|
|
23998
24052
|
if (outcome.pass === false) {
|
|
23999
|
-
|
|
24053
|
+
this._fire_hook_rejection('exit', fromState, newState, fromAction, oldData, newData, wasForced);
|
|
24000
24054
|
return false;
|
|
24001
24055
|
}
|
|
24002
|
-
|
|
24056
|
+
if (_update_hook_fields(hook_args, outcome)) {
|
|
24057
|
+
data_changed = true;
|
|
24058
|
+
}
|
|
24003
24059
|
}
|
|
24004
24060
|
// 5. named transition / action hook
|
|
24005
24061
|
if (this._has_named_hooks) {
|
|
@@ -24011,10 +24067,12 @@ class Machine {
|
|
|
24011
24067
|
const nh = byAct === undefined ? undefined : byAct.get(newStateOrAction);
|
|
24012
24068
|
const outcome = abstract_hook_step(nh, hook_args);
|
|
24013
24069
|
if (outcome.pass === false) {
|
|
24014
|
-
|
|
24070
|
+
this._fire_hook_rejection('named', fromState, newState, fromAction, oldData, newData, wasForced);
|
|
24015
24071
|
return false;
|
|
24016
24072
|
}
|
|
24017
|
-
|
|
24073
|
+
if (_update_hook_fields(hook_args, outcome)) {
|
|
24074
|
+
data_changed = true;
|
|
24075
|
+
}
|
|
24018
24076
|
}
|
|
24019
24077
|
}
|
|
24020
24078
|
// 6. regular hook
|
|
@@ -24024,56 +24082,68 @@ class Machine {
|
|
|
24024
24082
|
const h = byTo === undefined ? undefined : byTo.get(newState);
|
|
24025
24083
|
const outcome = abstract_hook_step(h, hook_args);
|
|
24026
24084
|
if (outcome.pass === false) {
|
|
24027
|
-
|
|
24085
|
+
this._fire_hook_rejection('hook', fromState, newState, fromAction, oldData, newData, wasForced);
|
|
24028
24086
|
return false;
|
|
24029
24087
|
}
|
|
24030
|
-
|
|
24088
|
+
if (_update_hook_fields(hook_args, outcome)) {
|
|
24089
|
+
data_changed = true;
|
|
24090
|
+
}
|
|
24031
24091
|
}
|
|
24032
24092
|
// 7. edge type hook
|
|
24033
24093
|
// 7a. standard transition hook
|
|
24034
24094
|
if (trans_type === 'legal') {
|
|
24035
24095
|
const outcome = abstract_hook_step(this._standard_transition_hook, hook_args);
|
|
24036
24096
|
if (outcome.pass === false) {
|
|
24037
|
-
|
|
24097
|
+
this._fire_hook_rejection('standard transition', fromState, newState, fromAction, oldData, newData, wasForced);
|
|
24038
24098
|
return false;
|
|
24039
24099
|
}
|
|
24040
|
-
|
|
24100
|
+
if (_update_hook_fields(hook_args, outcome)) {
|
|
24101
|
+
data_changed = true;
|
|
24102
|
+
}
|
|
24041
24103
|
}
|
|
24042
24104
|
// 7b. main type hook
|
|
24043
24105
|
if (trans_type === 'main') {
|
|
24044
24106
|
const outcome = abstract_hook_step(this._main_transition_hook, hook_args);
|
|
24045
24107
|
if (outcome.pass === false) {
|
|
24046
|
-
|
|
24108
|
+
this._fire_hook_rejection('main transition', fromState, newState, fromAction, oldData, newData, wasForced);
|
|
24047
24109
|
return false;
|
|
24048
24110
|
}
|
|
24049
|
-
|
|
24111
|
+
if (_update_hook_fields(hook_args, outcome)) {
|
|
24112
|
+
data_changed = true;
|
|
24113
|
+
}
|
|
24050
24114
|
}
|
|
24051
24115
|
// 7c. forced transition hook
|
|
24052
24116
|
if (trans_type === 'forced') {
|
|
24053
24117
|
const outcome = abstract_hook_step(this._forced_transition_hook, hook_args);
|
|
24054
24118
|
if (outcome.pass === false) {
|
|
24055
|
-
|
|
24119
|
+
this._fire_hook_rejection('forced transition', fromState, newState, fromAction, oldData, newData, wasForced);
|
|
24056
24120
|
return false;
|
|
24057
24121
|
}
|
|
24058
|
-
|
|
24122
|
+
if (_update_hook_fields(hook_args, outcome)) {
|
|
24123
|
+
data_changed = true;
|
|
24124
|
+
}
|
|
24059
24125
|
}
|
|
24060
24126
|
// 8. entry hook
|
|
24061
24127
|
if (this._has_entry_hooks) {
|
|
24062
24128
|
const outcome = abstract_hook_step(this._entry_hooks.get(newState), hook_args);
|
|
24063
24129
|
if (outcome.pass === false) {
|
|
24064
|
-
|
|
24130
|
+
this._fire_hook_rejection('entry', fromState, newState, fromAction, oldData, newData, wasForced);
|
|
24065
24131
|
return false;
|
|
24066
24132
|
}
|
|
24067
|
-
|
|
24133
|
+
if (_update_hook_fields(hook_args, outcome)) {
|
|
24134
|
+
data_changed = true;
|
|
24135
|
+
}
|
|
24068
24136
|
}
|
|
24069
24137
|
// 9. everything hook (fires after all other pre-hooks)
|
|
24070
24138
|
if (this._everything_hook !== undefined) {
|
|
24071
24139
|
const outcome = abstract_everything_hook_step(this._everything_hook, Object.assign(Object.assign({}, hook_args), { hook_name: 'everything' }));
|
|
24072
24140
|
if (outcome.pass === false) {
|
|
24073
|
-
|
|
24141
|
+
this._fire_hook_rejection('everything', fromState, newState, fromAction, oldData, newData, wasForced);
|
|
24074
24142
|
return false;
|
|
24075
24143
|
}
|
|
24076
|
-
|
|
24144
|
+
if (_update_hook_fields(hook_args, outcome)) {
|
|
24145
|
+
data_changed = true;
|
|
24146
|
+
}
|
|
24077
24147
|
}
|
|
24078
24148
|
// all hooks passed! let's now establish the result
|
|
24079
24149
|
if (this._history_length) {
|
|
@@ -24999,6 +25069,46 @@ function is_hook_complex_result(hr) {
|
|
|
24999
25069
|
}
|
|
25000
25070
|
return false;
|
|
25001
25071
|
}
|
|
25072
|
+
/**
|
|
25073
|
+
*
|
|
25074
|
+
* Apply any data-field updates from a hook's complex result into `hook_args`,
|
|
25075
|
+
* and return whether data actually changed.
|
|
25076
|
+
*
|
|
25077
|
+
* This is the hoisted, allocation-free replacement for the `update_fields`
|
|
25078
|
+
* inner function that used to be re-created on every hooked transition inside
|
|
25079
|
+
* {@link Machine.transition_impl}. By moving it to module scope the function
|
|
25080
|
+
* object is allocated once at module load time.
|
|
25081
|
+
*
|
|
25082
|
+
* When the result does not carry a `data` property (the common case —
|
|
25083
|
+
* most hooks return `true` or `undefined`) the function returns `false`
|
|
25084
|
+
* immediately without touching `hook_args`.
|
|
25085
|
+
*
|
|
25086
|
+
* ```typescript
|
|
25087
|
+
* const args = { data: 'old', next_data: undefined, ... };
|
|
25088
|
+
* const changed = _update_hook_fields(args, { pass: true, data: 'new', next_data: undefined });
|
|
25089
|
+
* // changed === true, args.data === 'new'
|
|
25090
|
+
* ```
|
|
25091
|
+
*
|
|
25092
|
+
* @param hook_args The shared hook-argument object for the current
|
|
25093
|
+
* transition. Mutated in-place when the result carries `data`.
|
|
25094
|
+
* @param res The normalised complex result returned by
|
|
25095
|
+
* {@link abstract_hook_step} or {@link abstract_everything_hook_step}.
|
|
25096
|
+
*
|
|
25097
|
+
* @returns `true` if `res` contained a `data` property (i.e. the hook
|
|
25098
|
+
* mutated the machine's data); `false` otherwise.
|
|
25099
|
+
*
|
|
25100
|
+
* @see Machine.transition_impl
|
|
25101
|
+
* @see abstract_hook_step
|
|
25102
|
+
*
|
|
25103
|
+
*/
|
|
25104
|
+
function _update_hook_fields(hook_args, res) {
|
|
25105
|
+
if (Object.prototype.hasOwnProperty.call(res, 'data')) {
|
|
25106
|
+
hook_args.data = res.data;
|
|
25107
|
+
hook_args.next_data = res.next_data;
|
|
25108
|
+
return true;
|
|
25109
|
+
}
|
|
25110
|
+
return false;
|
|
25111
|
+
}
|
|
25002
25112
|
/**
|
|
25003
25113
|
*
|
|
25004
25114
|
* Invoke an optional transition/action hook and normalize its return value
|