jssm 5.124.1 → 5.125.1
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 +6 -6
- package/dist/cdn/viz.js +119 -11
- package/dist/cli/fsl-render.cjs +1 -1
- package/dist/cli/fsl.cjs +1 -1
- package/dist/deno/README.md +6 -6
- package/dist/deno/jssm.d.ts +14 -1
- package/dist/deno/jssm.js +1 -1
- package/dist/deno/jssm_viz.d.ts +78 -6
- 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 +14 -1
- package/jssm.es6.d.ts +14 -1
- package/jssm_viz.es5.d.cts +92 -7
- package/jssm_viz.es6.d.ts +92 -7
- 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.
|
|
21
|
+
* Generated for version 5.125.1 at 5/20/2026, 3:45:22 PM
|
|
22
22
|
|
|
23
23
|
-->
|
|
24
|
-
# jssm 5.
|
|
24
|
+
# jssm 5.125.1
|
|
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/) ·
|
|
@@ -281,7 +281,7 @@ That decision shows up everywhere downstream:
|
|
|
281
281
|
or run `npm run benny` against your own machine.
|
|
282
282
|
|
|
283
283
|
- **More thoroughly tested than any other JavaScript state-machine
|
|
284
|
-
library.** 6,
|
|
284
|
+
library.** 6,104 tests at 100.0% line coverage
|
|
285
285
|
([report](https://coveralls.io/github/StoneCypher/jssm)), plus
|
|
286
286
|
fuzz testing via `fast-check`, with parser test data across ten natural
|
|
287
287
|
languages and Emoji.
|
|
@@ -414,11 +414,11 @@ If your contribution is missing here, please open an issue.
|
|
|
414
414
|
|
|
415
415
|
<br/>
|
|
416
416
|
|
|
417
|
-
***6,
|
|
417
|
+
***6,104 tests***, run 56,891 times.
|
|
418
418
|
|
|
419
|
-
- 5,
|
|
419
|
+
- 5,591 specs with 100.0% coverage
|
|
420
420
|
- 513 fuzz tests with 4.5% coverage
|
|
421
|
-
- 4,
|
|
421
|
+
- 4,355 TypeScript lines - 1.4 tests per line, 13.1 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/viz.js
CHANGED
|
@@ -21041,7 +21041,7 @@ var constants = /*#__PURE__*/Object.freeze({
|
|
|
21041
21041
|
* Useful for runtime diagnostics and for embedding in serialized machine
|
|
21042
21042
|
* snapshots so that deserializers can detect version-skew.
|
|
21043
21043
|
*/
|
|
21044
|
-
const version = "5.
|
|
21044
|
+
const version = "5.125.1";
|
|
21045
21045
|
|
|
21046
21046
|
// whargarbl lots of these return arrays could/should be sets
|
|
21047
21047
|
const { state_name_chars, state_name_first_chars, action_label_chars } = constants;
|
|
@@ -22522,9 +22522,22 @@ class Machine {
|
|
|
22522
22522
|
}
|
|
22523
22523
|
*/
|
|
22524
22524
|
/** List all action names available as exits from a given state.
|
|
22525
|
+
*
|
|
22526
|
+
* Returns the empty array (does not throw) when `whichState` exists but has
|
|
22527
|
+
* no action-named exits — including terminal states, states whose only
|
|
22528
|
+
* exits are plain `->` transitions, and states in machines that use no
|
|
22529
|
+
* actions at all. Only nonexistent states cause a throw.
|
|
22530
|
+
*
|
|
22525
22531
|
* @param whichState - The state to inspect. Defaults to the current state.
|
|
22526
|
-
* @returns An array of action name strings.
|
|
22532
|
+
* @returns An array of action name strings, possibly empty.
|
|
22527
22533
|
* @throws {JssmError} If the state does not exist.
|
|
22534
|
+
*
|
|
22535
|
+
* @example
|
|
22536
|
+
* const m = sm`a 'go' -> b; b -> c;`;
|
|
22537
|
+
* m.list_exit_actions('a'); // => ['go']
|
|
22538
|
+
* m.list_exit_actions('b'); // => []
|
|
22539
|
+
* m.list_exit_actions('c'); // => []
|
|
22540
|
+
* expect(() => m.list_exit_actions('z')).toThrow();
|
|
22528
22541
|
*/
|
|
22529
22542
|
list_exit_actions(whichState = this.state()) {
|
|
22530
22543
|
const ra_base = this._reverse_actions.get(whichState);
|
|
@@ -24357,18 +24370,113 @@ function vc(col) {
|
|
|
24357
24370
|
return (_a = default_viz_colors[col]) !== null && _a !== void 0 ? _a : '';
|
|
24358
24371
|
}
|
|
24359
24372
|
/**
|
|
24360
|
-
*
|
|
24361
|
-
*
|
|
24362
|
-
*
|
|
24363
|
-
*
|
|
24364
|
-
*
|
|
24373
|
+
* Convert a state name into a URL-friendly slug suitable for use as the
|
|
24374
|
+
* body of a dot/SVG node identifier. The transformation is:
|
|
24375
|
+
*
|
|
24376
|
+
* 1. Lowercase
|
|
24377
|
+
* 2. Any run of characters outside `[a-z0-9]` (after lowercasing) becomes
|
|
24378
|
+
* a single `-`
|
|
24379
|
+
* 3. Leading and trailing `-` are trimmed
|
|
24380
|
+
*
|
|
24381
|
+
* If the result is empty (e.g. for a state named `"!!!"`), the empty
|
|
24382
|
+
* string is returned — callers are expected to fall back to an indexed
|
|
24383
|
+
* placeholder like `node-N`. See {@link slug_states} for the collision-
|
|
24384
|
+
* resolving wrapper that consumes this helper.
|
|
24385
|
+
*
|
|
24386
|
+
* ```typescript
|
|
24387
|
+
* slug_for('Green Light'); // 'green-light'
|
|
24388
|
+
* slug_for('!!!'); // ''
|
|
24389
|
+
* slug_for(' Foo Bar '); // 'foo-bar'
|
|
24390
|
+
* ```
|
|
24391
|
+
*
|
|
24392
|
+
* @param state The state name to slugify.
|
|
24393
|
+
* @returns The lowercase hyphen-separated slug, or empty string if none of
|
|
24394
|
+
* the characters were retainable.
|
|
24395
|
+
*
|
|
24396
|
+
* @internal
|
|
24397
|
+
*/
|
|
24398
|
+
function slug_for(state) {
|
|
24399
|
+
return state
|
|
24400
|
+
.toLowerCase()
|
|
24401
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
24402
|
+
.replace(/^-+|-+$/g, '');
|
|
24403
|
+
}
|
|
24404
|
+
/**
|
|
24405
|
+
* Build a `Map<state, slug>` assigning every state in `states` a unique,
|
|
24406
|
+
* deterministic, URL-safe slug used as its dot/SVG node identifier.
|
|
24407
|
+
*
|
|
24408
|
+
* Algorithm:
|
|
24409
|
+
*
|
|
24410
|
+
* 1. Slug each state via {@link slug_for}. States whose slug comes out
|
|
24411
|
+
* empty fall back to `node-N`, where `N` is the state's declaration
|
|
24412
|
+
* index (1-based, to match user-visible numbering).
|
|
24413
|
+
* 2. Walk the state list in declaration order, tracking how many times
|
|
24414
|
+
* each base slug has already been used. The first occurrence keeps
|
|
24415
|
+
* the base slug; subsequent collisions get `-2`, `-3`, … suffixes.
|
|
24416
|
+
* If the proposed suffixed slug itself collides with a base slug
|
|
24417
|
+
* used later, the counter advances until a free slot is found.
|
|
24418
|
+
*
|
|
24419
|
+
* This yields a deterministic mapping given the state-declaration order,
|
|
24420
|
+
* so output is stable across runs.
|
|
24421
|
+
*
|
|
24422
|
+
* ```typescript
|
|
24423
|
+
* slug_states(['Red Light', 'red-light']);
|
|
24424
|
+
* // Map { 'Red Light' => 'red-light', 'red-light' => 'red-light-2' }
|
|
24425
|
+
*
|
|
24426
|
+
* slug_states(['!!!', '???']);
|
|
24427
|
+
* // Map { '!!!' => 'node-1', '???' => 'node-2' }
|
|
24428
|
+
* ```
|
|
24429
|
+
*
|
|
24430
|
+
* @param states States in declaration order.
|
|
24431
|
+
* @returns A `Map` from each state name to its unique slug.
|
|
24432
|
+
*
|
|
24433
|
+
* @internal
|
|
24434
|
+
*/
|
|
24435
|
+
function slug_states(states) {
|
|
24436
|
+
const used = new Set();
|
|
24437
|
+
const out = new Map();
|
|
24438
|
+
states.forEach((s, i) => {
|
|
24439
|
+
const base = slug_for(s) || `node-${i + 1}`;
|
|
24440
|
+
let candidate = base;
|
|
24441
|
+
let n = 2;
|
|
24442
|
+
while (used.has(candidate)) {
|
|
24443
|
+
candidate = `${base}-${n}`;
|
|
24444
|
+
n += 1;
|
|
24445
|
+
}
|
|
24446
|
+
used.add(candidate);
|
|
24447
|
+
out.set(s, candidate);
|
|
24448
|
+
});
|
|
24449
|
+
return out;
|
|
24450
|
+
}
|
|
24451
|
+
/**
|
|
24452
|
+
* Build a graphviz-safe node identifier for a state. Accepts either a
|
|
24453
|
+
* `string[]` (legacy test-only path; returns an index-based `n0`/`n1`
|
|
24454
|
+
* identifier via `indexOf`), or a precomputed `Map<state, slug>` produced
|
|
24455
|
+
* by {@link slug_states} (used by all rendering hot paths).
|
|
24456
|
+
*
|
|
24457
|
+
* When a slug map is supplied, the identifier is the slug wrapped in
|
|
24458
|
+
* double quotes — dot allows quoted identifiers, and the slug alphabet
|
|
24459
|
+
* (lowercase alphanumerics + `-`) requires quoting because bare dot IDs
|
|
24460
|
+
* may not contain `-`. Graphviz round-trips the quoted form through to
|
|
24461
|
+
* the SVG `<title>` element and uses the slug as a stable basis for the
|
|
24462
|
+
* generated SVG element `id` attribute.
|
|
24463
|
+
*
|
|
24464
|
+
* ```typescript
|
|
24465
|
+
* node_of('Red Light', new Map([['Red Light', 'red-light']]));
|
|
24466
|
+
* // '"red-light"'
|
|
24467
|
+
* ```
|
|
24365
24468
|
*
|
|
24366
24469
|
* @internal
|
|
24367
24470
|
*/
|
|
24368
24471
|
function node_of(state, state_index) {
|
|
24369
|
-
|
|
24370
|
-
|
|
24371
|
-
|
|
24472
|
+
if (Array.isArray(state_index)) {
|
|
24473
|
+
return `n${state_index.indexOf(state)}`;
|
|
24474
|
+
}
|
|
24475
|
+
const v = state_index.get(state);
|
|
24476
|
+
if (typeof v === 'string') {
|
|
24477
|
+
return `"${v}"`;
|
|
24478
|
+
}
|
|
24479
|
+
return `n${v}`;
|
|
24372
24480
|
}
|
|
24373
24481
|
/**
|
|
24374
24482
|
* Compose a graphviz `style` string from a pre-computed
|
|
@@ -24706,7 +24814,7 @@ function arranges_for(u_jssm, state_index) {
|
|
|
24706
24814
|
function machine_to_dot(u_jssm, opts = {}) {
|
|
24707
24815
|
var _a;
|
|
24708
24816
|
const l_states = u_jssm.states();
|
|
24709
|
-
const state_index =
|
|
24817
|
+
const state_index = slug_states(l_states);
|
|
24710
24818
|
const state_kinds = classify_states(u_jssm, l_states);
|
|
24711
24819
|
const nodes = states_to_nodes_string(u_jssm, l_states, state_index, state_kinds, opts.hide_state_labels === true);
|
|
24712
24820
|
const edges = states_to_edges_string(u_jssm, l_states, state_index, state_kinds);
|