jssm 5.112.3 → 5.113.0
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/deno/README.md +347 -0
- package/dist/deno/jssm.js +1 -0
- package/dist/{es6 → deno}/jssm_constants.d.ts +5 -0
- package/dist/{es6 → deno}/jssm_types.d.ts +298 -5
- 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 +241 -2
- package/jssm.es6.d.ts +241 -2
- package/jssm_viz.es5.d.cts +216 -2
- package/jssm_viz.es6.d.ts +216 -2
- package/package.json +18 -2
- package/.clocignore +0 -1
- package/.codeclimate.yml +0 -22
- package/.editorconfig +0 -12
- package/.eslintrc +0 -20
- package/.gitattributes +0 -17
- package/.log-progress.json +0 -9
- package/.nycrc +0 -6
- package/.travis.yml +0 -9
- package/CHANGELOG.md +0 -263
- package/CLAUDE.md +0 -11
- package/dist/es6/fsl_parser.js +0 -1
- package/dist/es6/jssm.js +0 -3320
- package/dist/es6/jssm_arrow.js +0 -211
- package/dist/es6/jssm_compiler.js +0 -380
- package/dist/es6/jssm_constants.js +0 -121
- package/dist/es6/jssm_error.js +0 -47
- package/dist/es6/jssm_theme.js +0 -24
- package/dist/es6/jssm_types.js +0 -3
- package/dist/es6/jssm_util.js +0 -337
- package/dist/es6/jssm_viz.js +0 -560
- package/dist/es6/jssm_viz_colors.js +0 -63
- package/dist/es6/themes/jssm_base_stylesheet.d.ts +0 -11
- package/dist/es6/themes/jssm_base_stylesheet.js +0 -58
- package/dist/es6/themes/jssm_theme_bold.d.ts +0 -11
- package/dist/es6/themes/jssm_theme_bold.js +0 -58
- package/dist/es6/themes/jssm_theme_default.d.ts +0 -11
- package/dist/es6/themes/jssm_theme_default.js +0 -58
- package/dist/es6/themes/jssm_theme_modern.d.ts +0 -11
- package/dist/es6/themes/jssm_theme_modern.js +0 -58
- package/dist/es6/themes/jssm_theme_ocean.d.ts +0 -11
- package/dist/es6/themes/jssm_theme_ocean.js +0 -56
- package/dist/es6/themes/jssm_theme_plain.d.ts +0 -11
- package/dist/es6/themes/jssm_theme_plain.js +0 -70
- package/dist/es6/version.js +0 -2
- package/dist/jssm.es5.nonmin.cjs +0 -24506
- package/dist/jssm.es6.nonmin.cjs +0 -24473
- package/dist/jssm_viz.es5.iife.nonmin.cjs +0 -24679
- package/dist/jssm_viz.es5.nonmin.cjs +0 -24674
- package/dist/jssm_viz.es6.nonmin.cjs +0 -24661
- package/jest-dragon.config.cjs +0 -36
- package/jest-spec.config.cjs +0 -36
- package/jest-stoch.config.cjs +0 -36
- package/jest-unicode.config.cjs +0 -36
- package/log-progress.data.json +0 -28
- package/rollup.config.deno.js +0 -44
- package/rollup.config.es5.js +0 -52
- package/rollup.config.es6.js +0 -55
- package/rollup.config.viz.es5.js +0 -46
- package/rollup.config.viz.es6.js +0 -46
- package/rollup.config.viz.iife.js +0 -36
- package/tutorial_learn_testing.md +0 -168
- package/typedoc-options.cjs +0 -69
- /package/dist/{es6 → deno}/fsl_parser.d.ts +0 -0
- /package/dist/{es6 → deno}/jssm.d.ts +0 -0
- /package/dist/{es6 → deno}/jssm_arrow.d.ts +0 -0
- /package/dist/{es6 → deno}/jssm_compiler.d.ts +0 -0
- /package/dist/{es6 → deno}/jssm_error.d.ts +0 -0
- /package/dist/{es6 → deno}/jssm_theme.d.ts +0 -0
- /package/dist/{es6 → deno}/jssm_util.d.ts +0 -0
- /package/dist/{es6 → deno}/jssm_viz.d.ts +0 -0
- /package/dist/{es6 → deno}/jssm_viz_colors.d.ts +0 -0
- /package/dist/{es6 → deno}/version.d.ts +0 -0
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
/*******
|
|
2
|
-
*
|
|
3
|
-
* Convenience aliases for common mathematical and numeric constants from
|
|
4
|
-
* `Number` and `Math`. Re-exported so that FSL data expressions and tests
|
|
5
|
-
* can reference them without importing `Math` directly.
|
|
6
|
-
*
|
|
7
|
-
* Includes: `NegInfinity`, `PosInfinity`, `Epsilon`, `Pi`, `E`, `Root2`,
|
|
8
|
-
* `RootHalf`, `Ln2`, `Ln10`, `Log2E`, `Log10E`, `MaxSafeInt`, `MinSafeInt`,
|
|
9
|
-
* `MaxPosNum`, `MinPosNum`, `Phi` (golden ratio), `EulerC` (Euler–Mascheroni).
|
|
10
|
-
*
|
|
11
|
-
*/
|
|
12
|
-
export const NegInfinity = Number.NEGATIVE_INFINITY, PosInfinity = Number.POSITIVE_INFINITY, Epsilon = Number.EPSILON, Pi = Math.PI, E = Math.E, Root2 = Math.SQRT2, RootHalf = Math.SQRT1_2, Ln2 = Math.LN2, Ln10 = Math.LN10, Log2E = Math.LOG2E, Log10E = Math.LOG10E, MaxSafeInt = Number.MAX_SAFE_INTEGER, MinSafeInt = Number.MIN_SAFE_INTEGER, MaxPosNum = Number.MAX_VALUE, MinPosNum = Number.MIN_VALUE, Phi = 1.61803398874989484820, EulerC = 0.57721566490153286060;
|
|
13
|
-
/*******
|
|
14
|
-
*
|
|
15
|
-
* Complete list of node shapes supported by Graphviz. Used by jssm-viz to
|
|
16
|
-
* validate and render state shapes in FSL `state ... : { shape: ... }` blocks.
|
|
17
|
-
*
|
|
18
|
-
* `shapes` is an alias for `gviz_shapes`.
|
|
19
|
-
*
|
|
20
|
-
*/
|
|
21
|
-
const gviz_shapes = [
|
|
22
|
-
"box3d",
|
|
23
|
-
"polygon",
|
|
24
|
-
"ellipse",
|
|
25
|
-
"oval",
|
|
26
|
-
"circle",
|
|
27
|
-
"point",
|
|
28
|
-
"egg",
|
|
29
|
-
"triangle",
|
|
30
|
-
"plaintext",
|
|
31
|
-
"plain",
|
|
32
|
-
"diamond",
|
|
33
|
-
"trapezium",
|
|
34
|
-
"parallelogram",
|
|
35
|
-
"house",
|
|
36
|
-
"pentagon",
|
|
37
|
-
"hexagon",
|
|
38
|
-
"septagon",
|
|
39
|
-
"octagon",
|
|
40
|
-
"doublecircle",
|
|
41
|
-
"doubleoctagon",
|
|
42
|
-
"tripleoctagon",
|
|
43
|
-
"invtriangle",
|
|
44
|
-
"invtrapezium",
|
|
45
|
-
"invhouse",
|
|
46
|
-
"Mdiamond",
|
|
47
|
-
"Msquare",
|
|
48
|
-
"Mcircle",
|
|
49
|
-
"rectangle",
|
|
50
|
-
"rect",
|
|
51
|
-
"square",
|
|
52
|
-
"star",
|
|
53
|
-
"none",
|
|
54
|
-
"underline",
|
|
55
|
-
"cylinder",
|
|
56
|
-
"note",
|
|
57
|
-
"tab",
|
|
58
|
-
"folder",
|
|
59
|
-
"box",
|
|
60
|
-
"component",
|
|
61
|
-
"promoter",
|
|
62
|
-
"cds",
|
|
63
|
-
"terminator",
|
|
64
|
-
"utr",
|
|
65
|
-
"primersite",
|
|
66
|
-
"restrictionsite",
|
|
67
|
-
"fivepoverhang",
|
|
68
|
-
"threepoverhang",
|
|
69
|
-
"noverhang",
|
|
70
|
-
"assembly",
|
|
71
|
-
"signature",
|
|
72
|
-
"insulator",
|
|
73
|
-
"ribosite",
|
|
74
|
-
"rnastab",
|
|
75
|
-
"proteasesite",
|
|
76
|
-
"proteinstab",
|
|
77
|
-
"rpromoter",
|
|
78
|
-
"rarrow",
|
|
79
|
-
"larrow",
|
|
80
|
-
"lpromoter",
|
|
81
|
-
"record"
|
|
82
|
-
];
|
|
83
|
-
const shapes = gviz_shapes;
|
|
84
|
-
/*******
|
|
85
|
-
*
|
|
86
|
-
* List of CSS/SVG named colors accepted by jssm-viz for state styling
|
|
87
|
-
* properties like `background-color` and `text-color`. Case-insensitive
|
|
88
|
-
* matching is done at parse time; the canonical casing here follows the
|
|
89
|
-
* CSS specification.
|
|
90
|
-
*
|
|
91
|
-
*/
|
|
92
|
-
const named_colors = [
|
|
93
|
-
"AliceBlue", "AntiqueWhite", "Aqua", "Aquamarine", "Azure", "Beige",
|
|
94
|
-
"Bisque", "Black", "BlanchedAlmond", "Blue", "BlueViolet", "Brown",
|
|
95
|
-
"BurlyWood", "CadetBlue", "Chartreuse", "Chocolate", "Coral",
|
|
96
|
-
"CornflowerBlue", "Cornsilk", "Crimson", "Cyan", "DarkBlue", "DarkCyan",
|
|
97
|
-
"DarkGoldenRod", "DarkGray", "DarkGrey", "DarkGreen", "DarkKhaki",
|
|
98
|
-
"DarkMagenta", "DarkOliveGreen", "Darkorange", "DarkOrchid", "DarkRed",
|
|
99
|
-
"DarkSalmon", "DarkSeaGreen", "DarkSlateBlue", "DarkSlateGray",
|
|
100
|
-
"DarkSlateGrey", "DarkTurquoise", "DarkViolet", "DeepPink", "DeepSkyBlue",
|
|
101
|
-
"DimGray", "DimGrey", "DodgerBlue", "FireBrick", "FloralWhite", "ForestGreen",
|
|
102
|
-
"Fuchsia", "Gainsboro", "GhostWhite", "Gold", "GoldenRod", "Gray", "Grey",
|
|
103
|
-
"Green", "GreenYellow", "HoneyDew", "HotPink", "IndianRed", "Indigo", "Ivory",
|
|
104
|
-
"Khaki", "Lavender", "LavenderBlush", "LawnGreen", "LemonChiffon",
|
|
105
|
-
"LightBlue", "LightCoral", "LightCyan", "LightGoldenRodYellow", "LightGray",
|
|
106
|
-
"LightGrey", "LightGreen", "LightPink", "LightSalmon", "LightSeaGreen",
|
|
107
|
-
"LightSkyBlue", "LightSlateGray", "LightSlateGrey", "LightSteelBlue",
|
|
108
|
-
"LightYellow", "Lime", "LimeGreen", "Linen", "Magenta", "Maroon",
|
|
109
|
-
"MediumAquaMarine", "MediumBlue", "MediumOrchid", "MediumPurple",
|
|
110
|
-
"MediumSeaGreen", "MediumSlateBlue", "MediumSpringGreen", "MediumTurquoise",
|
|
111
|
-
"MediumVioletRed", "MidnightBlue", "MintCream", "MistyRose", "Moccasin",
|
|
112
|
-
"NavajoWhite", "Navy", "OldLace", "Olive", "OliveDrab", "Orange", "OrangeRed",
|
|
113
|
-
"Orchid", "PaleGoldenRod", "PaleGreen", "PaleTurquoise", "PaleVioletRed",
|
|
114
|
-
"PapayaWhip", "PeachPuff", "Peru", "Pink", "Plum", "PowderBlue", "Purple",
|
|
115
|
-
"Red", "RosyBrown", "RoyalBlue", "SaddleBrown", "Salmon", "SandyBrown",
|
|
116
|
-
"SeaGreen", "SeaShell", "Sienna", "Silver", "SkyBlue", "SlateBlue",
|
|
117
|
-
"SlateGray", "SlateGrey", "Snow", "SpringGreen", "SteelBlue", "Tan", "Teal",
|
|
118
|
-
"Thistle", "Tomato", "Turquoise", "Violet", "Wheat", "White", "WhiteSmoke",
|
|
119
|
-
"Yellow", "YellowGreen"
|
|
120
|
-
];
|
|
121
|
-
export { gviz_shapes, shapes, named_colors, };
|
package/dist/es6/jssm_error.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/*******
|
|
2
|
-
*
|
|
3
|
-
* Custom error class for jssm. Enriches the standard `Error` with
|
|
4
|
-
* machine context (current state, instance name) and an optional
|
|
5
|
-
* `requested_state` so that error messages are self-describing.
|
|
6
|
-
*
|
|
7
|
-
* ```typescript
|
|
8
|
-
* throw new JssmError(machine, 'no such state', { requested_state: 'Blue' });
|
|
9
|
-
* // JssmError: [[my-light]]: no such state (at "Red", requested "Blue")
|
|
10
|
-
* ```
|
|
11
|
-
*
|
|
12
|
-
* @param machine - The `Machine` instance that raised the error, or
|
|
13
|
-
* `undefined` if no machine is available. Used to
|
|
14
|
-
* read `state()` and `instance_name()` for context.
|
|
15
|
-
* @param message - A human-readable description of the error.
|
|
16
|
-
* @param JEEI - Optional {@link JssmErrorExtendedInfo} with extra
|
|
17
|
-
* context such as `requested_state`.
|
|
18
|
-
*
|
|
19
|
-
*/
|
|
20
|
-
class JssmError extends Error {
|
|
21
|
-
constructor(machine, message, JEEI) {
|
|
22
|
-
const { requested_state } = (JEEI === undefined)
|
|
23
|
-
? { requested_state: undefined }
|
|
24
|
-
: JEEI;
|
|
25
|
-
const follow_ups = [];
|
|
26
|
-
if (machine) {
|
|
27
|
-
if (machine.state() !== undefined) {
|
|
28
|
-
follow_ups.push(`at "${machine.state()}"`);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
if (requested_state !== undefined) {
|
|
32
|
-
follow_ups.push(`requested "${requested_state}"`);
|
|
33
|
-
}
|
|
34
|
-
const complex_msg = `${((machine === null || machine === void 0 ? void 0 : machine.instance_name()) !== undefined)
|
|
35
|
-
? `[[${machine.instance_name()}]]: `
|
|
36
|
-
: ''}${message}${follow_ups.length
|
|
37
|
-
? ` (${follow_ups.join(', ')})`
|
|
38
|
-
: ''}`;
|
|
39
|
-
super(complex_msg);
|
|
40
|
-
this.name = 'JssmError';
|
|
41
|
-
this.message = complex_msg;
|
|
42
|
-
this.base_message = message;
|
|
43
|
-
this.requested_state = requested_state;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
;
|
|
47
|
-
export { JssmError };
|
package/dist/es6/jssm_theme.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { base_theme } from './themes/jssm_base_stylesheet';
|
|
2
|
-
import { default_theme } from './themes/jssm_theme_default';
|
|
3
|
-
import { modern_theme } from './themes/jssm_theme_modern';
|
|
4
|
-
import { ocean_theme } from './themes/jssm_theme_ocean';
|
|
5
|
-
import { plain_theme } from './themes/jssm_theme_plain';
|
|
6
|
-
import { bold_theme } from './themes/jssm_theme_bold';
|
|
7
|
-
/*******
|
|
8
|
-
*
|
|
9
|
-
* Registry mapping theme names to their stylesheet definitions. Each entry
|
|
10
|
-
* maps an {@link FslTheme} string (e.g. `'default'`, `'ocean'`) to a
|
|
11
|
-
* {@link JssmBaseTheme} object containing colors, shapes, and other visual
|
|
12
|
-
* defaults used by jssm-viz when rendering state machine diagrams.
|
|
13
|
-
*
|
|
14
|
-
* Add new themes by importing their definition and calling
|
|
15
|
-
* `theme_mapping.set(name, theme)`.
|
|
16
|
-
*
|
|
17
|
-
*/
|
|
18
|
-
const theme_mapping = new Map();
|
|
19
|
-
theme_mapping.set('default', default_theme);
|
|
20
|
-
theme_mapping.set('modern', modern_theme);
|
|
21
|
-
theme_mapping.set('ocean', ocean_theme);
|
|
22
|
-
theme_mapping.set('plain', plain_theme);
|
|
23
|
-
theme_mapping.set('bold', bold_theme);
|
|
24
|
-
export { theme_mapping, base_theme };
|
package/dist/es6/jssm_types.js
DELETED
package/dist/es6/jssm_util.js
DELETED
|
@@ -1,337 +0,0 @@
|
|
|
1
|
-
import { JssmError } from './jssm_error';
|
|
2
|
-
/*******
|
|
3
|
-
*
|
|
4
|
-
* Predicate for validating an array for uniqueness. Returns `true` when
|
|
5
|
-
* `el` is the first occurrence in `source`, `false` otherwise. Intended
|
|
6
|
-
* for use as an `Array.filter` callback. Not generally meant for external
|
|
7
|
-
* use.
|
|
8
|
-
*
|
|
9
|
-
* ```typescript
|
|
10
|
-
* [1, 2, 2, 3].filter(arr_uniq_p); // [1, 2, 3]
|
|
11
|
-
* ```
|
|
12
|
-
*
|
|
13
|
-
* @param el - The current element being tested.
|
|
14
|
-
* @param i - The index of the current element.
|
|
15
|
-
* @param source - The full array being filtered.
|
|
16
|
-
*
|
|
17
|
-
* @returns `true` if `el` is the first occurrence in `source`.
|
|
18
|
-
*
|
|
19
|
-
*/
|
|
20
|
-
function arr_uniq_p(el, i, source) {
|
|
21
|
-
return source.indexOf(el) === i;
|
|
22
|
-
}
|
|
23
|
-
/*******
|
|
24
|
-
*
|
|
25
|
-
* Wraps a string in an array, or passes through if already non-string.
|
|
26
|
-
* Used to normalize arguments that accept either a single state name or
|
|
27
|
-
* an array of state names.
|
|
28
|
-
*
|
|
29
|
-
* ```typescript
|
|
30
|
-
* array_box_if_string('hello'); // ['hello']
|
|
31
|
-
* array_box_if_string(['a','b']); // ['a','b']
|
|
32
|
-
* ```
|
|
33
|
-
*
|
|
34
|
-
* @param n - A string to box, or a value to pass through unchanged.
|
|
35
|
-
*
|
|
36
|
-
* @returns The input wrapped in an array if it was a string, otherwise the
|
|
37
|
-
* input unchanged.
|
|
38
|
-
*
|
|
39
|
-
*/
|
|
40
|
-
const array_box_if_string = n => typeof n === 'string' ? [n] : n;
|
|
41
|
-
/*******
|
|
42
|
-
*
|
|
43
|
-
* Selects a single item from a weighted array of objects using cumulative
|
|
44
|
-
* probability. Each object in the array should have a numeric property
|
|
45
|
-
* indicating its relative weight (defaults to `'probability'`). Objects
|
|
46
|
-
* missing the property are treated as weight 1.
|
|
47
|
-
*
|
|
48
|
-
* ```typescript
|
|
49
|
-
* const opts = [
|
|
50
|
-
* { value: 'common', probability: 0.8 },
|
|
51
|
-
* { value: 'rare', probability: 0.2 }
|
|
52
|
-
* ];
|
|
53
|
-
*
|
|
54
|
-
* weighted_rand_select(opts); // most often { value: 'common', ... }
|
|
55
|
-
* ```
|
|
56
|
-
*
|
|
57
|
-
* @param options - Non-empty array of objects to choose from.
|
|
58
|
-
* @param probability_property - Name of the numeric weight property on each
|
|
59
|
-
* object. Defaults to `'probability'`.
|
|
60
|
-
* @param rng - Optional random number generator `() => number`
|
|
61
|
-
* in `[0, 1)`. Defaults to `Math.random`.
|
|
62
|
-
*
|
|
63
|
-
* @returns One element from `options`, chosen by weighted random selection.
|
|
64
|
-
*
|
|
65
|
-
* @throws {TypeError} If `options` is not a non-empty array of objects.
|
|
66
|
-
*
|
|
67
|
-
*/
|
|
68
|
-
// this is explicitly about other peoples' data, so it has to be weakly typed
|
|
69
|
-
/* eslint-disable flowtype/no-weak-types */
|
|
70
|
-
const weighted_rand_select = (options, probability_property = 'probability', rng) => {
|
|
71
|
-
if (!Array.isArray(options)) {
|
|
72
|
-
throw new TypeError('options must be a non-empty array of objects');
|
|
73
|
-
}
|
|
74
|
-
if (options.length === 0) {
|
|
75
|
-
throw new TypeError('options must be a non-empty array of objects');
|
|
76
|
-
}
|
|
77
|
-
if (!(typeof options[0] === 'object')) {
|
|
78
|
-
throw new TypeError('options must be a non-empty array of objects');
|
|
79
|
-
}
|
|
80
|
-
const frand = rng
|
|
81
|
-
? (cap) => rng() * cap
|
|
82
|
-
: (cap) => Math.random() * cap, or_one = (item) => item === undefined ? 1 : item, prob_sum = options.reduce((acc, val) => acc + or_one(val[probability_property]), 0), rnd = frand(prob_sum);
|
|
83
|
-
let cursor = 0, cursor_sum = 0;
|
|
84
|
-
while (cursor < options.length && (cursor_sum += or_one(options[cursor++][probability_property])) <= rnd) { } // eslint-disable-line no-empty,fp/no-loops
|
|
85
|
-
return options[cursor - 1];
|
|
86
|
-
};
|
|
87
|
-
/* eslint-enable flowtype/no-weak-types */
|
|
88
|
-
/*******
|
|
89
|
-
*
|
|
90
|
-
* Returns, for a non-negative integer argument `n`, the series `[0 .. n]`.
|
|
91
|
-
*
|
|
92
|
-
* ```typescript
|
|
93
|
-
* import { seq } from './jssm';
|
|
94
|
-
*
|
|
95
|
-
* seq(5); // [0, 1, 2, 3, 4]
|
|
96
|
-
* seq(0); // []
|
|
97
|
-
* ```
|
|
98
|
-
*
|
|
99
|
-
*/
|
|
100
|
-
function seq(n) {
|
|
101
|
-
if (!(Number.isInteger(n))) {
|
|
102
|
-
throw new TypeError('seq/1 takes a non-negative integer n as an argument');
|
|
103
|
-
}
|
|
104
|
-
if (n < 0) {
|
|
105
|
-
throw new TypeError('seq/1 takes a non-negative integer n as an argument');
|
|
106
|
-
}
|
|
107
|
-
return (new Array(n))
|
|
108
|
-
.fill(true)
|
|
109
|
-
.map((_, i) => i);
|
|
110
|
-
}
|
|
111
|
-
/*******
|
|
112
|
-
*
|
|
113
|
-
* Returns the histograph of an array as a `Map`. Makes no attempt to cope
|
|
114
|
-
* with deep equality; will fail for complex contents, as such.
|
|
115
|
-
*
|
|
116
|
-
* ```typescript
|
|
117
|
-
* import { histograph } from './jssm';
|
|
118
|
-
*
|
|
119
|
-
* histograph( [0, 0, 1, 1, 2, 2, 1] ); // Map()
|
|
120
|
-
* ```
|
|
121
|
-
*
|
|
122
|
-
*/
|
|
123
|
-
const histograph = (ar) => // eslint-disable-line flowtype/no-weak-types
|
|
124
|
-
[...ar].sort()
|
|
125
|
-
.reduce((m, v) => // TODO FIXME eslint-disable-line flowtype/no-weak-types,no-sequences
|
|
126
|
-
(m.set(v, (m.has(v) ? m.get(v) + 1 : 1)), m), new Map());
|
|
127
|
-
/*******
|
|
128
|
-
*
|
|
129
|
-
* Draws `n` weighted random samples from an array of objects. Each draw is
|
|
130
|
-
* independent (with replacement), delegating to {@link weighted_rand_select}.
|
|
131
|
-
*
|
|
132
|
-
* ```typescript
|
|
133
|
-
* const opts = [
|
|
134
|
-
* { value: 'a', probability: 0.9 },
|
|
135
|
-
* { value: 'b', probability: 0.1 }
|
|
136
|
-
* ];
|
|
137
|
-
*
|
|
138
|
-
* weighted_sample_select(3, opts, 'probability');
|
|
139
|
-
* // e.g. [ { value: 'a', ... }, { value: 'a', ... }, { value: 'b', ... } ]
|
|
140
|
-
* ```
|
|
141
|
-
*
|
|
142
|
-
* @param n - Number of samples to draw.
|
|
143
|
-
* @param options - Non-empty array of weighted objects.
|
|
144
|
-
* @param probability_property - Name of the numeric weight property.
|
|
145
|
-
* @param rng - Optional random number generator.
|
|
146
|
-
*
|
|
147
|
-
* @returns An array of `n` independently selected items.
|
|
148
|
-
*
|
|
149
|
-
*/
|
|
150
|
-
const weighted_sample_select = (n, options, probability_property, rng) => // TODO FIXME no any // eslint-disable-line flowtype/no-weak-types
|
|
151
|
-
seq(n)
|
|
152
|
-
.map((_i) => // TODO FIXME eslint-disable-line flowtype/no-weak-types
|
|
153
|
-
weighted_rand_select(options, probability_property, rng));
|
|
154
|
-
/*******
|
|
155
|
-
*
|
|
156
|
-
* Draws `n` weighted random samples, extracts a named key from each, and
|
|
157
|
-
* returns a histograph (`Map`) of how often each key value appeared. Useful
|
|
158
|
-
* for validating that a probabilistic transition distribution is roughly
|
|
159
|
-
* correct over many trials.
|
|
160
|
-
*
|
|
161
|
-
* ```typescript
|
|
162
|
-
* const opts = [
|
|
163
|
-
* { to: 'a', probability: 0.7 },
|
|
164
|
-
* { to: 'b', probability: 0.3 }
|
|
165
|
-
* ];
|
|
166
|
-
*
|
|
167
|
-
* weighted_histo_key(1000, opts, 'probability', 'to');
|
|
168
|
-
* // Map { 'a' => ~700, 'b' => ~300 }
|
|
169
|
-
* ```
|
|
170
|
-
*
|
|
171
|
-
* @param n - Number of samples to draw.
|
|
172
|
-
* @param opts - Non-empty array of weighted objects.
|
|
173
|
-
* @param prob_prop - Name of the numeric weight property.
|
|
174
|
-
* @param extract - Name of the property to extract from each sample for
|
|
175
|
-
* histogramming.
|
|
176
|
-
* @param rng - Optional random number generator.
|
|
177
|
-
*
|
|
178
|
-
* @returns A `Map` from extracted key values to their occurrence counts.
|
|
179
|
-
*
|
|
180
|
-
*/
|
|
181
|
-
const weighted_histo_key = (n, opts, prob_prop, extract, rng) => // TODO FIXME no any // eslint-disable-line flowtype/no-weak-types
|
|
182
|
-
histograph(weighted_sample_select(n, opts, prob_prop, rng)
|
|
183
|
-
.map((s) => s[extract] // TODO FIXME eslint-disable-line flowtype/no-weak-types
|
|
184
|
-
));
|
|
185
|
-
/*******
|
|
186
|
-
*
|
|
187
|
-
* Internal method generating composite keys for the hook lookup map by
|
|
188
|
-
* JSON-serializing a `[property, state]` pair. Not meant for external use.
|
|
189
|
-
*
|
|
190
|
-
* ```typescript
|
|
191
|
-
* name_bind_prop_and_state('color', 'Red'); // '["color","Red"]'
|
|
192
|
-
* ```
|
|
193
|
-
*
|
|
194
|
-
* @param prop - The property name (e.g. a data key or hook category).
|
|
195
|
-
* @param state - The state name to bind to.
|
|
196
|
-
*
|
|
197
|
-
* @returns A deterministic JSON string key for the `[prop, state]` pair.
|
|
198
|
-
*
|
|
199
|
-
* @throws {JssmError} If either argument is not a string.
|
|
200
|
-
*
|
|
201
|
-
*/
|
|
202
|
-
function name_bind_prop_and_state(prop, state) {
|
|
203
|
-
if (typeof prop !== 'string') {
|
|
204
|
-
throw new JssmError(undefined, `Name of property must be a string; got ${prop}`);
|
|
205
|
-
}
|
|
206
|
-
if (typeof state !== 'string') {
|
|
207
|
-
throw new JssmError(undefined, `Name of state must be a string; got ${state}`);
|
|
208
|
-
}
|
|
209
|
-
return JSON.stringify([prop, state]);
|
|
210
|
-
}
|
|
211
|
-
/*******
|
|
212
|
-
*
|
|
213
|
-
* Internal method generating composite keys for transition hooks by
|
|
214
|
-
* JSON-serializing a `[from, to]` state pair. Used to look up hooks
|
|
215
|
-
* registered on a specific edge. Not meant for external use.
|
|
216
|
-
*
|
|
217
|
-
* ```typescript
|
|
218
|
-
* hook_name('Red', 'Green'); // '["Red","Green"]'
|
|
219
|
-
* ```
|
|
220
|
-
*
|
|
221
|
-
* @param from - The source state name.
|
|
222
|
-
* @param to - The target state name.
|
|
223
|
-
*
|
|
224
|
-
* @returns A deterministic JSON string key for the `[from, to]` pair.
|
|
225
|
-
*
|
|
226
|
-
*/
|
|
227
|
-
const hook_name = (from, to) => JSON.stringify([from, to]);
|
|
228
|
-
/*******
|
|
229
|
-
*
|
|
230
|
-
* Internal method generating composite keys for named-action hooks by
|
|
231
|
-
* JSON-serializing a `[from, to, action]` triple. Used to look up hooks
|
|
232
|
-
* registered on a specific action-labeled edge. Not meant for external use.
|
|
233
|
-
*
|
|
234
|
-
* ```typescript
|
|
235
|
-
* named_hook_name('Red', 'Green', 'next'); // '["Red","Green","next"]'
|
|
236
|
-
* ```
|
|
237
|
-
*
|
|
238
|
-
* @param from - The source state name.
|
|
239
|
-
* @param to - The target state name.
|
|
240
|
-
* @param action - The action label on the edge.
|
|
241
|
-
*
|
|
242
|
-
* @returns A deterministic JSON string key for the `[from, to, action]` triple.
|
|
243
|
-
*
|
|
244
|
-
*/
|
|
245
|
-
const named_hook_name = (from, to, action) => JSON.stringify([from, to, action]);
|
|
246
|
-
/*******
|
|
247
|
-
*
|
|
248
|
-
* Creates a SplitMix32 random generator. Used by the randomness test suite.
|
|
249
|
-
*
|
|
250
|
-
* Sourced from `bryc`: https://github.com/bryc/code/blob/master/jshash/PRNGs.md#splitmix32
|
|
251
|
-
*
|
|
252
|
-
* Replaces the Mulberry generator, which was found to have problems
|
|
253
|
-
*
|
|
254
|
-
*/
|
|
255
|
-
function gen_splitmix32(a) {
|
|
256
|
-
if (a === undefined) {
|
|
257
|
-
a = new Date().getTime();
|
|
258
|
-
}
|
|
259
|
-
return function () {
|
|
260
|
-
a |= 0;
|
|
261
|
-
a = a + 0x9e3779b9 | 0;
|
|
262
|
-
let t = a ^ a >>> 16;
|
|
263
|
-
t = Math.imul(t, 0x21f0aaad);
|
|
264
|
-
t = t ^ t >>> 15;
|
|
265
|
-
t = Math.imul(t, 0x735a2d97);
|
|
266
|
-
return ((t = t ^ t >>> 15) >>> 0) / 4294967296;
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
/*******
|
|
270
|
-
*
|
|
271
|
-
* Reduces an array to its unique contents. Compares with `===` and makes no
|
|
272
|
-
* effort to deep-compare contents; two matching arrays or objects contained
|
|
273
|
-
* will be treated as distinct, according to javascript rules. This also means
|
|
274
|
-
* that `NaNs` will be ***dropped***, because they do not self-compare.
|
|
275
|
-
*
|
|
276
|
-
* ```typescript
|
|
277
|
-
* unique( [] ); // []
|
|
278
|
-
* unique( [0,0] ); // [0]
|
|
279
|
-
* unique( [0,1,2, 0,1,2, 0,1,2] ); // [0,1,2]
|
|
280
|
-
* unique( [ [1], [1] ] ); // [ [1], [1] ] because arrays don't match
|
|
281
|
-
* unique( [0,NaN,2] ); // [0,2]
|
|
282
|
-
* ```
|
|
283
|
-
*
|
|
284
|
-
*/
|
|
285
|
-
const unique = (arr) => arr.filter((v, i, a) => a.indexOf(v) === i);
|
|
286
|
-
/*******
|
|
287
|
-
*
|
|
288
|
-
* Lists all repeated items in an array along with their counts. Subject to
|
|
289
|
-
* matching rules of Map. `NaN` is manually removed because of conflict rules
|
|
290
|
-
* around {@link unique}. Because these are compared with `===` and because
|
|
291
|
-
* arrays and objects never match that way unless they're the same object,
|
|
292
|
-
* arrays and objects are never considered repeats.
|
|
293
|
-
*
|
|
294
|
-
* ```typescript
|
|
295
|
-
* find_repeated<string>([ ]); // []
|
|
296
|
-
* find_repeated<string>([ "one" ]); // []
|
|
297
|
-
* find_repeated<string>([ "one", "two" ]); // []
|
|
298
|
-
* find_repeated<string>([ "one", "one" ]); // [ ["one", 2] ]
|
|
299
|
-
* find_repeated<string>([ "one", "two", "one" ]); // [ ["one", 2] ]
|
|
300
|
-
* find_repeated<number>([ 0, NaN, 0, NaN ]); // [ [0, 2] ]
|
|
301
|
-
* ```
|
|
302
|
-
*
|
|
303
|
-
*/
|
|
304
|
-
function find_repeated(arr) {
|
|
305
|
-
const uniqued = unique(arr);
|
|
306
|
-
if (uniqued.length !== arr.length) {
|
|
307
|
-
const residue_keys = new Map();
|
|
308
|
-
arr.forEach(k => residue_keys.set(k, residue_keys.has(k)
|
|
309
|
-
? (residue_keys.get(k) + 1)
|
|
310
|
-
: 1));
|
|
311
|
-
uniqued.forEach(k => residue_keys.set(k, residue_keys.get(k) - 1));
|
|
312
|
-
return [...residue_keys.entries()]
|
|
313
|
-
.filter((e) => ((e[1] > 0) && (!(Number.isNaN(e[0])))))
|
|
314
|
-
.map((e) => [e[0], e[1] + 1]);
|
|
315
|
-
}
|
|
316
|
-
else {
|
|
317
|
-
return [];
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
/*******
|
|
321
|
-
*
|
|
322
|
-
* Returns a `Promise` that resolves after `ms` milliseconds. Useful for
|
|
323
|
-
* inserting delays in async test flows or demos.
|
|
324
|
-
*
|
|
325
|
-
* ```typescript
|
|
326
|
-
* await sleep(100); // pauses execution for 100ms
|
|
327
|
-
* ```
|
|
328
|
-
*
|
|
329
|
-
* @param ms - Number of milliseconds to wait before resolving.
|
|
330
|
-
*
|
|
331
|
-
* @returns A `Promise<void>` that resolves after the timeout.
|
|
332
|
-
*
|
|
333
|
-
*/
|
|
334
|
-
function sleep(ms) {
|
|
335
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
336
|
-
}
|
|
337
|
-
export { seq, unique, find_repeated, arr_uniq_p, histograph, weighted_histo_key, weighted_rand_select, weighted_sample_select, array_box_if_string, name_bind_prop_and_state, hook_name, named_hook_name, gen_splitmix32, sleep };
|