jssm 5.162.34 → 5.162.35

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.
@@ -24454,7 +24454,7 @@ function fslSemanticSpans(text) {
24454
24454
  * Useful for runtime diagnostics and for embedding in serialized machine
24455
24455
  * snapshots so that deserializers can detect version-skew.
24456
24456
  */
24457
- const version = "5.162.34";
24457
+ const version = "5.162.35";
24458
24458
 
24459
24459
  /**
24460
24460
  * The FSL Markdown fence convention parser — pure, host-agnostic logic that
@@ -24620,7 +24620,7 @@ var __classPrivateFieldGet = (undefined && undefined.__classPrivateFieldGet) ||
24620
24620
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
24621
24621
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
24622
24622
  };
24623
- var _Machine_instances, _Machine_unsubscribe_entry, _Machine_subscribe, _Machine_fire_one, _Machine_has_subscribers, _Machine_fire, _Machine_validate_hook_description, _Machine_recompute_hook_flags, _Machine_fire_hook_rejection, _Machine_fire_boundary_actions, _Machine_resolved_themes, _Machine_individual_state_config, _Machine_groups_by_depth, _Machine_compose_state_config;
24623
+ var _Machine_instances, _Machine_unsubscribe_entry, _Machine_subscribe, _Machine_validate_hook_description, _Machine_recompute_hook_flags, _Machine_resolved_themes, _Machine_individual_state_config, _Machine_groups_by_depth, _Machine_compose_state_config;
24624
24624
  const { state_name_chars, state_name_first_chars, action_label_chars } = constants;
24625
24625
  const empty_string_set = new Set();
24626
24626
  // The spatial fields (besides `handler`, which every hook needs) that each
@@ -25620,7 +25620,7 @@ class Machine {
25620
25620
  const oldData = this._data;
25621
25621
  this._data = newData;
25622
25622
  if (oldData !== newData) {
25623
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire).call(this, 'data-change', {
25623
+ this._fire('data-change', {
25624
25624
  from: this._state,
25625
25625
  to: this._state,
25626
25626
  old_data: oldData,
@@ -27216,6 +27216,127 @@ class Machine {
27216
27216
  }
27217
27217
  return false;
27218
27218
  }
27219
+ /**
27220
+ * Invoke a single event-handler entry, respecting its filter, once-removal
27221
+ * semantics, and the error re-fire / recursion-guard logic. Extracted so
27222
+ * {@link _fire} can share identical behavior between the size-1 fast-path
27223
+ * and the general snapshotted loop.
27224
+ * @param entry - The subscriber descriptor to invoke.
27225
+ * @param set - The live Set that owns `entry`; needed for once-removal.
27226
+ * @param name - The event name being dispatched (used in error re-fires).
27227
+ * @param detail - The event payload forwarded to the handler.
27228
+ * @internal
27229
+ */
27230
+ // PERF: this and the sibling dispatch methods (_fire, _fire_boundary_actions,
27231
+ // _fire_hook_rejection, _has_subscribers) are intentionally underscore-
27232
+ // convention, NOT `#`-private. They are called on the per-transition hot
27233
+ // path (_fire_boundary_actions runs on every transition), and a `#`-private
27234
+ // method cannot be inlined the way its `_` twin can (brand check), so
27235
+ // privatizing them in 5.162.8 cost ~20-25% on transition/action dispatch.
27236
+ // Do not re-privatize. StoneCypher/fsl#1959
27237
+ _fire_one(entry, set, name, detail) {
27238
+ // filter check
27239
+ if (entry.filter !== undefined) {
27240
+ for (const [k, v] of Object.entries(entry.filter)) {
27241
+ if (v !== detail[k]) {
27242
+ return;
27243
+ }
27244
+ }
27245
+ }
27246
+ // once removal happens BEFORE invocation so a throwing handler still
27247
+ // gets removed and so re-entrant `on` calls during the handler see
27248
+ // the post-removal state.
27249
+ if (entry.once) {
27250
+ __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_unsubscribe_entry).call(this, set, entry);
27251
+ }
27252
+ try {
27253
+ entry.handler(detail);
27254
+ }
27255
+ catch (error) {
27256
+ if (name === 'error' || this._firing_error) {
27257
+ // surface to stderr as a last resort but never recurse;
27258
+ // `console` is in the JS standard library and present in every
27259
+ // supported runtime, so guarding it would just add an untestable
27260
+ // branch. See #638.
27261
+ console.error(error);
27262
+ }
27263
+ else {
27264
+ this._firing_error = true;
27265
+ try {
27266
+ this._fire('error', {
27267
+ error: error,
27268
+ source_event: name,
27269
+ source_detail: detail,
27270
+ handler: entry.handler
27271
+ });
27272
+ }
27273
+ finally {
27274
+ this._firing_error = false;
27275
+ }
27276
+ }
27277
+ }
27278
+ }
27279
+ /**
27280
+ * Dispatch an event to every registered subscriber in registration
27281
+ * order. Filters are checked first; non-matching handlers are skipped
27282
+ * without invoking the handler. Exceptions thrown by a handler are
27283
+ * caught and re-emitted as an `error` event so subsequent handlers
27284
+ * still run.
27285
+ *
27286
+ * Re-entry into the `error` event itself is guarded — if an `error`
27287
+ * handler throws, the new exception is swallowed rather than rebroadcast
27288
+ * to avoid an infinite loop.
27289
+ *
27290
+ * When exactly one subscriber is registered the common case avoids the
27291
+ * `Array.from(set)` snapshot allocation by capturing the lone entry into a
27292
+ * local first — equivalent to a 1-element snapshot but allocation-free.
27293
+ * The general path still snapshots for re-entrancy safety.
27294
+ * @internal
27295
+ */
27296
+ /**
27297
+ * Whether at least one live subscriber is registered for `name`. Used by
27298
+ * the transition-commit observation block to skip building a detail
27299
+ * literal that {@link Machine._fire} would immediately discard — a panel
27300
+ * listening only to `'transition'` (fsl-bind, fsl-viz, fsl-info-panel)
27301
+ * previously paid for the exit/entry/data-change detail allocations on
27302
+ * every transition. Read at fire time, so a listener installed by a
27303
+ * pre-hook is still seen (#671).
27304
+ * @param name The event name to probe.
27305
+ * @returns `true` when a subsequent `_fire(name, ...)` would reach at
27306
+ * least one handler.
27307
+ *
27308
+ * ```typescript
27309
+ * machine.on('transition', () => {});
27310
+ * machine._has_subscribers('transition'); // true
27311
+ * machine._has_subscribers('exit'); // false
27312
+ * ```
27313
+ * @see Machine._fire
27314
+ * @internal
27315
+ */
27316
+ _has_subscribers(name) {
27317
+ const set = this._event_handlers.get(name);
27318
+ return (set !== undefined) && (set.size > 0);
27319
+ }
27320
+ _fire(name, detail) {
27321
+ const set = this._event_handlers.get(name);
27322
+ if (set === undefined || set.size === 0) {
27323
+ return;
27324
+ }
27325
+ // Fast-path: single subscriber — capture entry before invoking so that
27326
+ // even if the handler mutates `set` (via off/once auto-removal) we hold a
27327
+ // stable reference. Behaviorally identical to a 1-element snapshot.
27328
+ if (set.size === 1) {
27329
+ const only = set.values().next().value;
27330
+ this._fire_one(only, set, name, detail);
27331
+ return;
27332
+ }
27333
+ // General path: snapshot so handlers can `off()` mid-loop without
27334
+ // disturbing iteration.
27335
+ const entries = [...set];
27336
+ for (const entry of entries) {
27337
+ this._fire_one(entry, set, name, detail);
27338
+ }
27339
+ }
27219
27340
  set_hook(HookDesc) {
27220
27341
  __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_validate_hook_description).call(this, HookDesc);
27221
27342
  switch (HookDesc.kind) {
@@ -27396,7 +27517,7 @@ class Machine {
27396
27517
  // added after a style has already been computed and memoized.
27397
27518
  this._static_state_config_cache.clear();
27398
27519
  // fire the registration event for inspector tools (#638)
27399
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire).call(this, 'hook-registration', { description: HookDesc });
27520
+ this._fire('hook-registration', { description: HookDesc });
27400
27521
  }
27401
27522
  /**
27402
27523
  * Remove a previously-registered hook described by a
@@ -27599,7 +27720,7 @@ class Machine {
27599
27720
  // See set_hook: the hooked-state styling layer depends on which states
27600
27721
  // carry hooks, so removing one can change a state's composed style.
27601
27722
  this._static_state_config_cache.clear();
27602
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire).call(this, 'hook-removal', { description: HookDesc });
27723
+ this._fire('hook-removal', { description: HookDesc });
27603
27724
  }
27604
27725
  return removed;
27605
27726
  }
@@ -28046,14 +28167,14 @@ class Machine {
28046
28167
  if (dataProvided) {
28047
28168
  this._data = newData;
28048
28169
  }
28049
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire).call(this, 'override', {
28170
+ this._fire('override', {
28050
28171
  from: fromState,
28051
28172
  to: newState,
28052
28173
  old_data: oldData,
28053
28174
  new_data: this._data
28054
28175
  });
28055
28176
  if (dataProvided && (oldData !== newData)) {
28056
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire).call(this, 'data-change', {
28177
+ this._fire('data-change', {
28057
28178
  from: fromState,
28058
28179
  to: newState,
28059
28180
  old_data: oldData,
@@ -28063,7 +28184,7 @@ class Machine {
28063
28184
  }
28064
28185
  // An override is still a real state change that may cross group/state
28065
28186
  // boundaries, so its boundary-hook actions fire too (depth-bounded).
28066
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire_boundary_actions).call(this, fromState, newState);
28187
+ this._fire_boundary_actions(fromState, newState);
28067
28188
  }
28068
28189
  else {
28069
28190
  throw new JssmError(this, `Cannot override state to "${newState}", a state that does not exist`);
@@ -28073,6 +28194,164 @@ class Machine {
28073
28194
  throw new JssmError(this, "Code specifies no override, but config tries to permit; config may not be less strict than code");
28074
28195
  }
28075
28196
  }
28197
+ /*********
28198
+ *
28199
+ * Fire a `'rejection'` event caused by a hook vetoing a pending transition.
28200
+ * Extracted from the per-call closures inside {@link transition_impl} so
28201
+ * that it is allocated once at class-definition time rather than on every
28202
+ * hooked transition.
28203
+ *
28204
+ * @param hook_name Name of the hook that rejected (e.g. `'exit'`).
28205
+ * @param fromState State the machine was in when the transition was
28206
+ * attempted; used as the `from` field of the rejection event.
28207
+ * @param newState State that would have been entered had the hook
28208
+ * passed; used as the `to` field of the rejection event.
28209
+ * @param fromAction Action name when the transition was initiated by an
28210
+ * action call; `undefined` for plain state transitions.
28211
+ * @param oldData Machine data at the moment the transition was
28212
+ * attempted, before any hook mutations.
28213
+ * @param newData The `next_data` value passed to the transition call.
28214
+ * @param wasForced Whether the transition was attempted via
28215
+ * `force_transition`.
28216
+ *
28217
+ * @see transition_impl
28218
+ * @see _fire
28219
+ *
28220
+ * @internal
28221
+ *
28222
+ */
28223
+ _fire_hook_rejection(hook_name, fromState, newState, fromAction, oldData, newData, wasForced) {
28224
+ // Every hook veto in transition_impl's pre-commit pipeline exits through
28225
+ // here, so this is the single close point for the reentrancy guard on the
28226
+ // rejection path: clear it before firing the event so a `rejection` listener
28227
+ // may itself transition (the outer transition is abandoned, not reverted).
28228
+ // #1953
28229
+ this._committing_transition = false;
28230
+ this._fire('rejection', {
28231
+ from: fromState,
28232
+ to: newState,
28233
+ action: fromAction,
28234
+ data: oldData,
28235
+ next_data: newData,
28236
+ reason: 'hook',
28237
+ hook_name,
28238
+ forced: wasForced
28239
+ });
28240
+ }
28241
+ /*********
28242
+ *
28243
+ * Fire the FSL boundary-hook actions for a single, already-committed state
28244
+ * change. In FSL, `do` is a synonym for `action`, so `on enter &g do 'X';`
28245
+ * means "when the machine crosses INTO group `g`, dispatch machine action
28246
+ * `X`" — and likewise `on exit` / plain-state subjects. This is the runtime
28247
+ * that fires those parked hooks.
28248
+ *
28249
+ * Crossing semantics (statechart convention — exits before enters):
28250
+ *
28251
+ * 1. `prev_groups` / `next_groups` are the deep (transitive) group sets of
28252
+ * the old and new states, from `_state_to_groups`.
28253
+ * 2. **Exits** fire first: every group in `prev_groups \ next_groups` with an
28254
+ * `onExit`, plus the plain `prev_state`'s `onExit` (when the state name
28255
+ * actually changed).
28256
+ * 3. **Enters** fire next: every group in `next_groups \ prev_groups` with an
28257
+ * `onEnter`, plus the plain `next_state`'s `onEnter` (when the state name
28258
+ * changed).
28259
+ * 4. A group present in BOTH sets is a transition *within* that group and
28260
+ * fires neither of its boundary hooks. `prev_state === next_state` fires
28261
+ * nothing at all.
28262
+ * 5. "Fire its action" is `this.action(label)`. If that action is not valid
28263
+ * from the current state, `action` is a safe no-op (returns `false`) — an
28264
+ * inapplicable boundary action never throws.
28265
+ * 6. Multi-membership and nesting both fan out naturally: a state in groups
28266
+ * A and B fires both; crossing an inner and an outer boundary fires both
28267
+ * levels.
28268
+ *
28269
+ * Because firing an action can drive a further transition (which crosses
28270
+ * more boundaries, which fires more actions), this is a bounded
28271
+ * run-to-completion: `_boundary_depth` tracks the live cascade depth and a
28272
+ * cascade deeper than `_boundary_depth_limit` throws a {@link JssmError}
28273
+ * rather than overflowing the stack or hanging. The limit defaults to 100
28274
+ * and is configurable via the `boundary_depth_limit` constructor option.
28275
+ *
28276
+ * @param prev_state The state the machine was in before this commit.
28277
+ * @param next_state The state the machine is in now (already committed).
28278
+ *
28279
+ * @throws {JssmError} If cascaded boundary firing exceeds `_boundary_depth_limit`
28280
+ * (a probable infinite loop).
28281
+ *
28282
+ * @see action
28283
+ * @see transition_impl
28284
+ *
28285
+ * @internal
28286
+ *
28287
+ */
28288
+ _fire_boundary_actions(prev_state, next_state) {
28289
+ var _a, _b, _c, _d, _e, _f;
28290
+ // Nothing crosses a boundary when the state name is unchanged.
28291
+ if (prev_state === next_state) {
28292
+ return;
28293
+ }
28294
+ // Skip entirely for machines that declared no boundary hooks at all — the
28295
+ // overwhelming common case, and it keeps the hot transition path free of
28296
+ // set arithmetic.
28297
+ if (this._group_hooks.size === 0 && this._state_hooks.size === 0) {
28298
+ return;
28299
+ }
28300
+ if (this._boundary_depth >= this._boundary_depth_limit) {
28301
+ throw new JssmError(this, `boundary-hook action cascade exceeded depth limit (${this._boundary_depth_limit}) `
28302
+ + `crossing from ${JSON.stringify(prev_state)} to ${JSON.stringify(next_state)} `
28303
+ + `(possible infinite loop)`);
28304
+ }
28305
+ const prev_groups = (_a = this._state_to_groups.get(prev_state)) !== null && _a !== void 0 ? _a : empty_string_set;
28306
+ const next_groups = (_b = this._state_to_groups.get(next_state)) !== null && _b !== void 0 ? _b : empty_string_set;
28307
+ // The labels to dispatch, gathered before any firing so that re-entrant
28308
+ // transitions caused by an early action cannot perturb which boundaries the
28309
+ // *current* crossing fires. Exits precede enters (statechart convention).
28310
+ const labels = [];
28311
+ // Exits: groups left (in prev but not next), then the plain prev state.
28312
+ for (const group of prev_groups) {
28313
+ if (next_groups.has(group)) {
28314
+ continue;
28315
+ }
28316
+ const label = (_c = this._group_hooks.get(group)) === null || _c === void 0 ? void 0 : _c.onExit;
28317
+ if (label !== undefined) {
28318
+ labels.push(label);
28319
+ }
28320
+ }
28321
+ const prev_state_exit = (_d = this._state_hooks.get(prev_state)) === null || _d === void 0 ? void 0 : _d.onExit;
28322
+ if (prev_state_exit !== undefined) {
28323
+ labels.push(prev_state_exit);
28324
+ }
28325
+ // Enters: groups entered (in next but not prev), then the plain next state.
28326
+ for (const group of next_groups) {
28327
+ if (prev_groups.has(group)) {
28328
+ continue;
28329
+ }
28330
+ const label = (_e = this._group_hooks.get(group)) === null || _e === void 0 ? void 0 : _e.onEnter;
28331
+ if (label !== undefined) {
28332
+ labels.push(label);
28333
+ }
28334
+ }
28335
+ const next_state_enter = (_f = this._state_hooks.get(next_state)) === null || _f === void 0 ? void 0 : _f.onEnter;
28336
+ if (next_state_enter !== undefined) {
28337
+ labels.push(next_state_enter);
28338
+ }
28339
+ if (labels.length === 0) {
28340
+ return;
28341
+ }
28342
+ // Each dispatched action re-enters transition_impl, which (on success) calls
28343
+ // back here for the boundary it just crossed. The depth counter brackets
28344
+ // the whole fan-out so a self-perpetuating cascade is bounded, not infinite.
28345
+ this._boundary_depth += 1;
28346
+ try {
28347
+ for (const label of labels) {
28348
+ this.action(label); // safe no-op (returns false) if inapplicable here
28349
+ }
28350
+ }
28351
+ finally {
28352
+ this._boundary_depth -= 1;
28353
+ }
28354
+ }
28076
28355
  /*********
28077
28356
  *
28078
28357
  * Shared transition core used by {@link transition}, {@link force_transition},
@@ -28230,7 +28509,7 @@ class Machine {
28230
28509
  // when nothing is subscribed. Gate is read at fire time, so a listener
28231
28510
  // registered inside a pre-hook still receives the event. #671
28232
28511
  if (wasAction && this._event_listener_count !== 0) {
28233
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire).call(this, 'action', {
28512
+ this._fire('action', {
28234
28513
  action: newStateOrAction,
28235
28514
  from: this._state,
28236
28515
  to: newState,
@@ -28250,7 +28529,7 @@ class Machine {
28250
28529
  // Open the pre-commit window: from here until the commit below, any
28251
28530
  // reentrant transition_impl call (a hook transitioning the machine)
28252
28531
  // throws instead of being silently reverted. The `finally` below closes
28253
- // it on every exit path; #fire_hook_rejection additionally clears it
28532
+ // it on every exit path; _fire_hook_rejection additionally clears it
28254
28533
  // before firing the rejection event so a rejection listener may itself
28255
28534
  // transition. The pipeline body is intentionally left at its original
28256
28535
  // indentation to keep this fix's diff focused. #1953
@@ -28261,7 +28540,7 @@ class Machine {
28261
28540
  if (this._pre_everything_hook !== undefined) {
28262
28541
  const outcome = abstract_everything_hook_step(this._pre_everything_hook, Object.assign(Object.assign({}, hook_args), { hook_name: 'pre everything' }));
28263
28542
  if (!outcome.pass) {
28264
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire_hook_rejection).call(this, 'pre everything', fromState, newState, fromAction, oldData, newData, wasForced);
28543
+ this._fire_hook_rejection('pre everything', fromState, newState, fromAction, oldData, newData, wasForced);
28265
28544
  return false;
28266
28545
  }
28267
28546
  if (_update_hook_fields(hook_args, outcome)) {
@@ -28272,7 +28551,7 @@ class Machine {
28272
28551
  // 1a. any action hook
28273
28552
  const outcome = abstract_hook_step(this._any_action_hook, hook_args);
28274
28553
  if (!outcome.pass) {
28275
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire_hook_rejection).call(this, 'any action', fromState, newState, fromAction, oldData, newData, wasForced);
28554
+ this._fire_hook_rejection('any action', fromState, newState, fromAction, oldData, newData, wasForced);
28276
28555
  return false;
28277
28556
  }
28278
28557
  if (_update_hook_fields(hook_args, outcome)) {
@@ -28281,7 +28560,7 @@ class Machine {
28281
28560
  // 1b. global specific action hook
28282
28561
  const outcome2 = abstract_hook_step(this._global_action_hooks.get(actionId), hook_args);
28283
28562
  if (!outcome2.pass) {
28284
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire_hook_rejection).call(this, 'global action', fromState, newState, fromAction, oldData, newData, wasForced);
28563
+ this._fire_hook_rejection('global action', fromState, newState, fromAction, oldData, newData, wasForced);
28285
28564
  return false;
28286
28565
  }
28287
28566
  if (_update_hook_fields(hook_args, outcome2)) {
@@ -28298,7 +28577,7 @@ class Machine {
28298
28577
  if (this._any_transition_hook !== undefined) {
28299
28578
  const outcome = abstract_hook_step(this._any_transition_hook, hook_args);
28300
28579
  if (!outcome.pass) {
28301
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire_hook_rejection).call(this, 'any transition', fromState, newState, fromAction, oldData, newData, wasForced);
28580
+ this._fire_hook_rejection('any transition', fromState, newState, fromAction, oldData, newData, wasForced);
28302
28581
  return false;
28303
28582
  }
28304
28583
  if (_update_hook_fields(hook_args, outcome)) {
@@ -28309,7 +28588,7 @@ class Machine {
28309
28588
  if (this._has_exit_hooks) {
28310
28589
  const outcome = abstract_hook_step(this._exit_hooks.get(this._state_id), hook_args);
28311
28590
  if (!outcome.pass) {
28312
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire_hook_rejection).call(this, 'exit', fromState, newState, fromAction, oldData, newData, wasForced);
28591
+ this._fire_hook_rejection('exit', fromState, newState, fromAction, oldData, newData, wasForced);
28313
28592
  return false;
28314
28593
  }
28315
28594
  if (_update_hook_fields(hook_args, outcome)) {
@@ -28326,7 +28605,7 @@ class Machine {
28326
28605
  const nh = byPair === undefined ? undefined : byPair.get(actionId);
28327
28606
  const outcome = abstract_hook_step(nh, hook_args);
28328
28607
  if (!outcome.pass) {
28329
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire_hook_rejection).call(this, 'named', fromState, newState, fromAction, oldData, newData, wasForced);
28608
+ this._fire_hook_rejection('named', fromState, newState, fromAction, oldData, newData, wasForced);
28330
28609
  return false;
28331
28610
  }
28332
28611
  if (_update_hook_fields(hook_args, outcome)) {
@@ -28339,7 +28618,7 @@ class Machine {
28339
28618
  const h = this._hooks.get(pre_pair_id);
28340
28619
  const outcome = abstract_hook_step(h, hook_args);
28341
28620
  if (!outcome.pass) {
28342
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire_hook_rejection).call(this, 'hook', fromState, newState, fromAction, oldData, newData, wasForced);
28621
+ this._fire_hook_rejection('hook', fromState, newState, fromAction, oldData, newData, wasForced);
28343
28622
  return false;
28344
28623
  }
28345
28624
  if (_update_hook_fields(hook_args, outcome)) {
@@ -28351,7 +28630,7 @@ class Machine {
28351
28630
  if (trans_type === 'legal') {
28352
28631
  const outcome = abstract_hook_step(this._standard_transition_hook, hook_args);
28353
28632
  if (!outcome.pass) {
28354
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire_hook_rejection).call(this, 'standard transition', fromState, newState, fromAction, oldData, newData, wasForced);
28633
+ this._fire_hook_rejection('standard transition', fromState, newState, fromAction, oldData, newData, wasForced);
28355
28634
  return false;
28356
28635
  }
28357
28636
  if (_update_hook_fields(hook_args, outcome)) {
@@ -28362,7 +28641,7 @@ class Machine {
28362
28641
  else if (trans_type === 'main') {
28363
28642
  const outcome = abstract_hook_step(this._main_transition_hook, hook_args);
28364
28643
  if (!outcome.pass) {
28365
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire_hook_rejection).call(this, 'main transition', fromState, newState, fromAction, oldData, newData, wasForced);
28644
+ this._fire_hook_rejection('main transition', fromState, newState, fromAction, oldData, newData, wasForced);
28366
28645
  return false;
28367
28646
  }
28368
28647
  if (_update_hook_fields(hook_args, outcome)) {
@@ -28373,7 +28652,7 @@ class Machine {
28373
28652
  else if (trans_type === 'forced') {
28374
28653
  const outcome = abstract_hook_step(this._forced_transition_hook, hook_args);
28375
28654
  if (!outcome.pass) {
28376
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire_hook_rejection).call(this, 'forced transition', fromState, newState, fromAction, oldData, newData, wasForced);
28655
+ this._fire_hook_rejection('forced transition', fromState, newState, fromAction, oldData, newData, wasForced);
28377
28656
  return false;
28378
28657
  }
28379
28658
  if (_update_hook_fields(hook_args, outcome)) {
@@ -28384,7 +28663,7 @@ class Machine {
28384
28663
  if (this._has_entry_hooks) {
28385
28664
  const outcome = abstract_hook_step(this._entry_hooks.get(newStateId), hook_args);
28386
28665
  if (!outcome.pass) {
28387
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire_hook_rejection).call(this, 'entry', fromState, newState, fromAction, oldData, newData, wasForced);
28666
+ this._fire_hook_rejection('entry', fromState, newState, fromAction, oldData, newData, wasForced);
28388
28667
  return false;
28389
28668
  }
28390
28669
  if (_update_hook_fields(hook_args, outcome)) {
@@ -28395,7 +28674,7 @@ class Machine {
28395
28674
  if (this._everything_hook !== undefined) {
28396
28675
  const outcome = abstract_everything_hook_step(this._everything_hook, Object.assign(Object.assign({}, hook_args), { hook_name: 'everything' }));
28397
28676
  if (!outcome.pass) {
28398
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire_hook_rejection).call(this, 'everything', fromState, newState, fromAction, oldData, newData, wasForced);
28677
+ this._fire_hook_rejection('everything', fromState, newState, fromAction, oldData, newData, wasForced);
28399
28678
  return false;
28400
28679
  }
28401
28680
  if (_update_hook_fields(hook_args, outcome)) {
@@ -28462,7 +28741,7 @@ class Machine {
28462
28741
  // when nothing is subscribed. A listener still receives the event
28463
28742
  // because the gate is read at fire time. #671
28464
28743
  if (this._event_listener_count !== 0) {
28465
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire).call(this, 'rejection', {
28744
+ this._fire('rejection', {
28466
28745
  from: fromState,
28467
28746
  to: newStateOrAction, // we never resolved a real target
28468
28747
  action: fromAction,
@@ -28563,16 +28842,16 @@ class Machine {
28563
28842
  // listening only to 'transition' previously paid for the exit/entry/
28564
28843
  // data-change/terminal/complete allocations _fire then discarded.
28565
28844
  // Gates read at fire time, like the outer count, preserving #671.
28566
- if (__classPrivateFieldGet(this, _Machine_instances, "m", _Machine_has_subscribers).call(this, 'exit')) {
28567
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire).call(this, 'exit', {
28845
+ if (this._has_subscribers('exit')) {
28846
+ this._fire('exit', {
28568
28847
  state: fromState,
28569
28848
  to: newState,
28570
28849
  action: fromAction,
28571
28850
  data: newData_after
28572
28851
  });
28573
28852
  }
28574
- if (__classPrivateFieldGet(this, _Machine_instances, "m", _Machine_has_subscribers).call(this, 'transition')) {
28575
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire).call(this, 'transition', {
28853
+ if (this._has_subscribers('transition')) {
28854
+ this._fire('transition', {
28576
28855
  from: fromState,
28577
28856
  to: newState,
28578
28857
  action: fromAction,
@@ -28582,16 +28861,16 @@ class Machine {
28582
28861
  forced: wasForced
28583
28862
  });
28584
28863
  }
28585
- if (__classPrivateFieldGet(this, _Machine_instances, "m", _Machine_has_subscribers).call(this, 'entry')) {
28586
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire).call(this, 'entry', {
28864
+ if (this._has_subscribers('entry')) {
28865
+ this._fire('entry', {
28587
28866
  state: newState,
28588
28867
  from: fromState,
28589
28868
  action: fromAction,
28590
28869
  data: newData_after
28591
28870
  });
28592
28871
  }
28593
- if ((oldData !== newData_after) && __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_has_subscribers).call(this, 'data-change')) {
28594
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire).call(this, 'data-change', {
28872
+ if ((oldData !== newData_after) && this._has_subscribers('data-change')) {
28873
+ this._fire('data-change', {
28595
28874
  from: fromState,
28596
28875
  to: newState,
28597
28876
  action: fromAction,
@@ -28605,18 +28884,18 @@ class Machine {
28605
28884
  // each redo has_state plus its own map walk. Same predicates:
28606
28885
  // terminal = no exits, complete = the constructor-set flag. #735
28607
28886
  const new_state_rec = this._states.get(newState);
28608
- if ((new_state_rec.to.length === 0) && __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_has_subscribers).call(this, 'terminal')) {
28609
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire).call(this, 'terminal', { state: newState, data: newData_after });
28887
+ if ((new_state_rec.to.length === 0) && this._has_subscribers('terminal')) {
28888
+ this._fire('terminal', { state: newState, data: newData_after });
28610
28889
  }
28611
- if (new_state_rec.complete && __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_has_subscribers).call(this, 'complete')) {
28612
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire).call(this, 'complete', { state: newState, data: newData_after });
28890
+ if (new_state_rec.complete && this._has_subscribers('complete')) {
28891
+ this._fire('complete', { state: newState, data: newData_after });
28613
28892
  }
28614
28893
  }
28615
28894
  // FSL boundary-hook actions (`on enter/exit &g do 'X'`) fire after the
28616
28895
  // state is committed and after the observation events, matching the
28617
28896
  // statechart "exits before enters" convention. Cascades are depth-bounded
28618
28897
  // inside the helper.
28619
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire_boundary_actions).call(this, fromState, newState);
28898
+ this._fire_boundary_actions(fromState, newState);
28620
28899
  // Clear the departed state's `after` timer and re-establish the new state's,
28621
28900
  // now that the transition has actually committed. This clear runs only on a
28622
28901
  // successful commit -- a hook that VETOES the transition returns above, so
@@ -29574,7 +29853,7 @@ class Machine {
29574
29853
  this._after_any_hook({ data: this._data, next_data: this._data });
29575
29854
  }
29576
29855
  }
29577
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire).call(this, 'timeout', { from: from_state, to: next_state, after_time });
29856
+ this._fire('timeout', { from: from_state, to: next_state, after_time });
29578
29857
  this.go(next_state);
29579
29858
  }, after_time);
29580
29859
  this._timeout_target = next_state;
@@ -29648,69 +29927,6 @@ _Machine_instances = new WeakSet(), _Machine_unsubscribe_entry = function _Machi
29648
29927
  set.add(entry);
29649
29928
  this._event_listener_count++;
29650
29929
  return () => { __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_unsubscribe_entry).call(this, set, entry); };
29651
- }, _Machine_fire_one = function _Machine_fire_one(entry, set, name, detail) {
29652
- // filter check
29653
- if (entry.filter !== undefined) {
29654
- for (const [k, v] of Object.entries(entry.filter)) {
29655
- if (v !== detail[k]) {
29656
- return;
29657
- }
29658
- }
29659
- }
29660
- // once removal happens BEFORE invocation so a throwing handler still
29661
- // gets removed and so re-entrant `on` calls during the handler see
29662
- // the post-removal state.
29663
- if (entry.once) {
29664
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_unsubscribe_entry).call(this, set, entry);
29665
- }
29666
- try {
29667
- entry.handler(detail);
29668
- }
29669
- catch (error) {
29670
- if (name === 'error' || this._firing_error) {
29671
- // surface to stderr as a last resort but never recurse;
29672
- // `console` is in the JS standard library and present in every
29673
- // supported runtime, so guarding it would just add an untestable
29674
- // branch. See #638.
29675
- console.error(error);
29676
- }
29677
- else {
29678
- this._firing_error = true;
29679
- try {
29680
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire).call(this, 'error', {
29681
- error: error,
29682
- source_event: name,
29683
- source_detail: detail,
29684
- handler: entry.handler
29685
- });
29686
- }
29687
- finally {
29688
- this._firing_error = false;
29689
- }
29690
- }
29691
- }
29692
- }, _Machine_has_subscribers = function _Machine_has_subscribers(name) {
29693
- const set = this._event_handlers.get(name);
29694
- return (set !== undefined) && (set.size > 0);
29695
- }, _Machine_fire = function _Machine_fire(name, detail) {
29696
- const set = this._event_handlers.get(name);
29697
- if (set === undefined || set.size === 0) {
29698
- return;
29699
- }
29700
- // Fast-path: single subscriber — capture entry before invoking so that
29701
- // even if the handler mutates `set` (via off/once auto-removal) we hold a
29702
- // stable reference. Behaviorally identical to a 1-element snapshot.
29703
- if (set.size === 1) {
29704
- const only = set.values().next().value;
29705
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire_one).call(this, only, set, name, detail);
29706
- return;
29707
- }
29708
- // General path: snapshot so handlers can `off()` mid-loop without
29709
- // disturbing iteration.
29710
- const entries = [...set];
29711
- for (const entry of entries) {
29712
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire_one).call(this, entry, set, name, detail);
29713
- }
29714
29930
  }, _Machine_validate_hook_description = function _Machine_validate_hook_description(HookDesc) {
29715
29931
  const required = hook_required_fields[HookDesc.kind];
29716
29932
  if (required === undefined) {
@@ -29782,89 +29998,6 @@ _Machine_instances = new WeakSet(), _Machine_unsubscribe_entry = function _Machi
29782
29998
  this._pre_post_everything_hook !== undefined,
29783
29999
  this._post_everything_hook !== undefined,
29784
30000
  ].includes(true);
29785
- }, _Machine_fire_hook_rejection = function _Machine_fire_hook_rejection(hook_name, fromState, newState, fromAction, oldData, newData, wasForced) {
29786
- // Every hook veto in transition_impl's pre-commit pipeline exits through
29787
- // here, so this is the single close point for the reentrancy guard on the
29788
- // rejection path: clear it before firing the event so a `rejection` listener
29789
- // may itself transition (the outer transition is abandoned, not reverted).
29790
- // #1953
29791
- this._committing_transition = false;
29792
- __classPrivateFieldGet(this, _Machine_instances, "m", _Machine_fire).call(this, 'rejection', {
29793
- from: fromState,
29794
- to: newState,
29795
- action: fromAction,
29796
- data: oldData,
29797
- next_data: newData,
29798
- reason: 'hook',
29799
- hook_name,
29800
- forced: wasForced
29801
- });
29802
- }, _Machine_fire_boundary_actions = function _Machine_fire_boundary_actions(prev_state, next_state) {
29803
- var _a, _b, _c, _d, _e, _f;
29804
- // Nothing crosses a boundary when the state name is unchanged.
29805
- if (prev_state === next_state) {
29806
- return;
29807
- }
29808
- // Skip entirely for machines that declared no boundary hooks at all — the
29809
- // overwhelming common case, and it keeps the hot transition path free of
29810
- // set arithmetic.
29811
- if (this._group_hooks.size === 0 && this._state_hooks.size === 0) {
29812
- return;
29813
- }
29814
- if (this._boundary_depth >= this._boundary_depth_limit) {
29815
- throw new JssmError(this, `boundary-hook action cascade exceeded depth limit (${this._boundary_depth_limit}) `
29816
- + `crossing from ${JSON.stringify(prev_state)} to ${JSON.stringify(next_state)} `
29817
- + `(possible infinite loop)`);
29818
- }
29819
- const prev_groups = (_a = this._state_to_groups.get(prev_state)) !== null && _a !== void 0 ? _a : empty_string_set;
29820
- const next_groups = (_b = this._state_to_groups.get(next_state)) !== null && _b !== void 0 ? _b : empty_string_set;
29821
- // The labels to dispatch, gathered before any firing so that re-entrant
29822
- // transitions caused by an early action cannot perturb which boundaries the
29823
- // *current* crossing fires. Exits precede enters (statechart convention).
29824
- const labels = [];
29825
- // Exits: groups left (in prev but not next), then the plain prev state.
29826
- for (const group of prev_groups) {
29827
- if (next_groups.has(group)) {
29828
- continue;
29829
- }
29830
- const label = (_c = this._group_hooks.get(group)) === null || _c === void 0 ? void 0 : _c.onExit;
29831
- if (label !== undefined) {
29832
- labels.push(label);
29833
- }
29834
- }
29835
- const prev_state_exit = (_d = this._state_hooks.get(prev_state)) === null || _d === void 0 ? void 0 : _d.onExit;
29836
- if (prev_state_exit !== undefined) {
29837
- labels.push(prev_state_exit);
29838
- }
29839
- // Enters: groups entered (in next but not prev), then the plain next state.
29840
- for (const group of next_groups) {
29841
- if (prev_groups.has(group)) {
29842
- continue;
29843
- }
29844
- const label = (_e = this._group_hooks.get(group)) === null || _e === void 0 ? void 0 : _e.onEnter;
29845
- if (label !== undefined) {
29846
- labels.push(label);
29847
- }
29848
- }
29849
- const next_state_enter = (_f = this._state_hooks.get(next_state)) === null || _f === void 0 ? void 0 : _f.onEnter;
29850
- if (next_state_enter !== undefined) {
29851
- labels.push(next_state_enter);
29852
- }
29853
- if (labels.length === 0) {
29854
- return;
29855
- }
29856
- // Each dispatched action re-enters transition_impl, which (on success) calls
29857
- // back here for the boundary it just crossed. The depth counter brackets
29858
- // the whole fan-out so a self-perpetuating cascade is bounded, not infinite.
29859
- this._boundary_depth += 1;
29860
- try {
29861
- for (const label of labels) {
29862
- this.action(label); // safe no-op (returns false) if inapplicable here
29863
- }
29864
- }
29865
- finally {
29866
- this._boundary_depth -= 1;
29867
- }
29868
30001
  }, _Machine_resolved_themes = function _Machine_resolved_themes() {
29869
30002
  const themes = [];
29870
30003
  for (const th of this._themes) {