jssm 5.44.0 → 5.46.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.
Files changed (85) hide show
  1. package/dist/es6/jssm.d.ts +6 -1
  2. package/dist/es6/jssm.js +104 -14
  3. package/dist/es6/jssm_types.d.ts +26 -1
  4. package/dist/es6/jssm_util.d.ts +3 -1
  5. package/dist/es6/jssm_util.js +3 -1
  6. package/dist/es6/version.js +1 -1
  7. package/dist/jssm.es5.cjs.js +1 -1
  8. package/jssm.d.ts +6 -1
  9. package/jssm_types.d.ts +26 -1
  10. package/jssm_util.d.ts +3 -1
  11. package/package.json +2 -3
  12. package/.codeclimate.yml +0 -22
  13. package/.editorconfig +0 -12
  14. package/.eslintrc +0 -20
  15. package/.nycrc +0 -6
  16. package/.travis.yml +0 -9
  17. package/dist/jssm.es5.iife.js +0 -1
  18. package/jest-spec.config.js +0 -27
  19. package/jest-stoch.config.js +0 -27
  20. package/rollup.config.iife.js +0 -44
  21. package/rollup.config.js +0 -44
  22. package/src/demo/index.html +0 -38
  23. package/src/demo/style.css +0 -2
  24. package/src/ts/jssm-dot.peg +0 -928
  25. package/src/ts/jssm.ts +0 -1120
  26. package/src/ts/jssm_types.ts +0 -346
  27. package/src/ts/jssm_util.ts +0 -100
  28. package/src/ts/tests/actions.spec.ts +0 -167
  29. package/src/ts/tests/arrange.spec.ts +0 -72
  30. package/src/ts/tests/arrange.stoch.ts +0 -4
  31. package/src/ts/tests/array_box_if_string.spec.ts +0 -30
  32. package/src/ts/tests/array_transitions.spec.ts +0 -129
  33. package/src/ts/tests/arrow unicode.spec.ts +0 -88
  34. package/src/ts/tests/arrow.spec.ts +0 -124
  35. package/src/ts/tests/colors.spec.ts +0 -58
  36. package/src/ts/tests/comment.spec.ts +0 -134
  37. package/src/ts/tests/compile.spec.ts +0 -79
  38. package/src/ts/tests/constants.spec.ts +0 -98
  39. package/src/ts/tests/cycles.spec.ts +0 -153
  40. package/src/ts/tests/dot_preamble.spec.ts +0 -16
  41. package/src/ts/tests/embedded_sm.spec.ts +0 -36
  42. package/src/ts/tests/flow.spec.ts +0 -22
  43. package/src/ts/tests/forced transitions.spec.ts +0 -26
  44. package/src/ts/tests/general.spec.ts +0 -933
  45. package/src/ts/tests/graph node lists.spec.ts +0 -21
  46. package/src/ts/tests/histo.spec.ts +0 -24
  47. package/src/ts/tests/hooks.spec.ts +0 -28
  48. package/src/ts/tests/language.spec.ts +0 -37
  49. package/src/ts/tests/language_data/belarussian.json +0 -14
  50. package/src/ts/tests/language_data/bengali.json +0 -16
  51. package/src/ts/tests/language_data/emoji.json +0 -22
  52. package/src/ts/tests/language_data/english.json +0 -17
  53. package/src/ts/tests/language_data/french.json +0 -17
  54. package/src/ts/tests/language_data/german.json +0 -17
  55. package/src/ts/tests/language_data/hebrew.json +0 -16
  56. package/src/ts/tests/language_data/portuguese.json +0 -13
  57. package/src/ts/tests/language_data/russian.json +0 -13
  58. package/src/ts/tests/language_data/spanish.json +0 -17
  59. package/src/ts/tests/language_data/ukrainian.json +0 -19
  60. package/src/ts/tests/layout.spec.ts +0 -29
  61. package/src/ts/tests/machine_attributes.spec.ts +0 -398
  62. package/src/ts/tests/machine_name.spec.ts +0 -14
  63. package/src/ts/tests/named lists.spec.ts +0 -24
  64. package/src/ts/tests/nominated states.spec.ts +0 -133
  65. package/src/ts/tests/parse actions.spec.ts +0 -32
  66. package/src/ts/tests/parse.spec.ts +0 -94
  67. package/src/ts/tests/probability.spec.ts +0 -146
  68. package/src/ts/tests/r639.spec.ts +0 -27
  69. package/src/ts/tests/sample_select.spec.ts +0 -173
  70. package/src/ts/tests/seq.spec.ts +0 -14
  71. package/src/ts/tests/seq.stoch.ts +0 -83
  72. package/src/ts/tests/shapes.spec.ts +0 -63
  73. package/src/ts/tests/sm_tag.spec.ts +0 -37
  74. package/src/ts/tests/special characters.spec.ts +0 -39
  75. package/src/ts/tests/state_declaration.spec.ts +0 -214
  76. package/src/ts/tests/state_style.spec.ts +0 -82
  77. package/src/ts/tests/stop light.spec.ts +0 -157
  78. package/src/ts/tests/stripes.spec.ts +0 -52
  79. package/src/ts/tests/theme.spec.ts +0 -45
  80. package/src/ts/tests/weighted_histo_key.spec.ts +0 -22
  81. package/src/ts/tests/weighted_rand_select.spec.ts +0 -27
  82. package/src/ts/tests/weighted_sample_select.spec.ts +0 -24
  83. package/src/ts/version.ts +0 -3
  84. package/tree.txt +0 -1794
  85. package/tsconfig.json +0 -27
package/src/ts/jssm.ts DELETED
@@ -1,1120 +0,0 @@
1
-
2
- // whargarbl lots of these return arrays could/should be sets
3
-
4
- type StateType = string;
5
-
6
- import { reduce as reduce_to_639 } from 'reduce-to-639-1';
7
-
8
-
9
-
10
-
11
-
12
- import {
13
-
14
- JssmGenericState, JssmGenericConfig,
15
- JssmTransition, JssmTransitionList, // JssmTransitionRule,
16
- JssmMachineInternalState,
17
- JssmParseTree,
18
- JssmStateDeclaration, JssmStateDeclarationRule,
19
- JssmCompileSe, JssmCompileSeStart, JssmCompileRule,
20
- JssmArrow, JssmArrowDirection, JssmArrowKind,
21
- JssmLayout,
22
- FslDirection, FslTheme
23
-
24
- } from './jssm_types';
25
-
26
-
27
-
28
-
29
-
30
- import {
31
- seq, weighted_rand_select, weighted_sample_select, histograph,
32
- weighted_histo_key, array_box_if_string
33
- } from './jssm_util';
34
-
35
-
36
-
37
-
38
-
39
- import { parse } from './jssm-dot'; // TODO FIXME WHARGARBL this could be post-typed
40
-
41
- import { version } from './version'; // replaced from package.js in build // TODO FIXME currently broken
42
-
43
-
44
-
45
-
46
-
47
- /* eslint-disable complexity */
48
-
49
- function arrow_direction(arrow: JssmArrow): JssmArrowDirection {
50
-
51
- switch ( String(arrow) ) {
52
-
53
- case '->' : case '→' :
54
- case '=>' : case '⇒' :
55
- case '~>' : case '↛' :
56
- return 'right';
57
-
58
- case '<-' : case '←' :
59
- case '<=' : case '⇐' :
60
- case '<~' : case '↚' :
61
- return 'left';
62
-
63
- case '<->' : case '↔' :
64
- case '<-=>' : case '←⇒' : case '←=>' : case '<-⇒' :
65
- case '<-~>' : case '←↛' : case '←~>' : case '<-↛' :
66
-
67
- case '<=>' : case '⇔' :
68
- case '<=->' : case '⇐→' : case '⇐->' : case '<=→' :
69
- case '<=~>' : case '⇐↛' : case '⇐~>' : case '<=↛' :
70
-
71
- case '<~>' : case '↮' :
72
- case '<~->' : case '↚→' : case '↚->' : case '<~→' :
73
- case '<~=>' : case '↚⇒' : case '↚=>' : case '<~⇒' :
74
- return 'both';
75
-
76
- default:
77
- throw new Error(`arrow_direction: unknown arrow type ${arrow}`);
78
-
79
- }
80
-
81
- }
82
-
83
- /* eslint-enable complexity */
84
-
85
-
86
-
87
-
88
-
89
- /* eslint-disable complexity */
90
-
91
- function arrow_left_kind(arrow: JssmArrow): JssmArrowKind {
92
-
93
- switch ( String(arrow) ) {
94
-
95
- case '->' : case '→' :
96
- case '=>' : case '⇒' :
97
- case '~>' : case '↛' :
98
- return 'none';
99
-
100
- case '<-': case '←' :
101
- case '<->': case '↔' :
102
- case '<-=>': case '←⇒' :
103
- case '<-~>': case '←↛' :
104
- return 'legal';
105
-
106
- case '<=': case '⇐' :
107
- case '<=>': case '⇔' :
108
- case '<=->': case '⇐→' :
109
- case '<=~>': case '⇐↛' :
110
- return 'main';
111
-
112
- case '<~': case '↚' :
113
- case '<~>': case '↮' :
114
- case '<~->': case '↚→' :
115
- case '<~=>': case '↚⇒' :
116
- return 'forced';
117
-
118
- default:
119
- throw new Error(`arrow_direction: unknown arrow type ${arrow}`);
120
-
121
- }
122
-
123
- }
124
-
125
- /* eslint-enable complexity */
126
-
127
-
128
-
129
-
130
-
131
- /* eslint-disable complexity */
132
-
133
- function arrow_right_kind(arrow: JssmArrow): JssmArrowKind {
134
-
135
- switch ( String(arrow) ) {
136
-
137
- case '<-' : case '←' :
138
- case '<=' : case '⇐' :
139
- case '<~' : case '↚' :
140
- return 'none';
141
-
142
- case '->' : case '→' :
143
- case '<->': case '↔' :
144
- case '<=->': case '⇐→' :
145
- case '<~->': case '↚→' :
146
- return 'legal';
147
-
148
- case '=>' : case '⇒' :
149
- case '<=>': case '⇔' :
150
- case '<-=>': case '←⇒' :
151
- case '<~=>': case '↚⇒' :
152
- return 'main';
153
-
154
- case '~>' : case '↛' :
155
- case '<~>': case '↮' :
156
- case '<-~>': case '←↛' :
157
- case '<=~>': case '⇐↛' :
158
- return 'forced';
159
-
160
- default:
161
- throw new Error(`arrow_direction: unknown arrow type ${arrow}`);
162
-
163
- }
164
-
165
- }
166
-
167
- /* eslint-enable complexity */
168
-
169
-
170
-
171
-
172
-
173
- function makeTransition<mDT>(
174
- this_se : JssmCompileSe,
175
- from : string,
176
- to : string,
177
- isRight : boolean,
178
- _wasList? : Array<string>,
179
- _wasIndex? : number
180
- ) : JssmTransition<mDT> {
181
-
182
- const kind : JssmArrowKind = isRight? arrow_right_kind(this_se.kind) : arrow_left_kind(this_se.kind),
183
- edge : JssmTransition<mDT> = {
184
- from,
185
- to,
186
- kind,
187
- forced_only : kind === 'forced',
188
- main_path : kind === 'main'
189
- };
190
-
191
- // if ((wasList !== undefined) && (wasIndex === undefined)) { throw new TypeError("Must have an index if transition was in a list"); }
192
- // if ((wasIndex !== undefined) && (wasList === undefined)) { throw new TypeError("Must be in a list if transition has an index"); }
193
- /*
194
- if (typeof edge.to === 'object') {
195
-
196
- if (edge.to.key === 'cycle') {
197
- if (wasList === undefined) { throw "Must have a waslist if a to is type cycle"; }
198
- const nextIndex = wrapBy(wasIndex, edge.to.value, wasList.length);
199
- edge.to = wasList[nextIndex];
200
- }
201
-
202
- }
203
- */
204
- const action : string = isRight? 'r_action' : 'l_action',
205
- probability : string = isRight? 'r_probability' : 'l_probability';
206
-
207
- if (this_se[action]) { edge.action = this_se[action]; }
208
- if (this_se[probability]) { edge.probability = this_se[probability]; }
209
-
210
- return edge;
211
-
212
- }
213
-
214
-
215
-
216
-
217
-
218
- function wrap_parse(input: string, options?: Object) {
219
- return parse(input, options || {});
220
- }
221
-
222
-
223
-
224
-
225
-
226
- function compile_rule_transition_step<mDT>(
227
- acc : Array< JssmTransition<mDT> >,
228
- from : string,
229
- to : string,
230
- this_se : JssmCompileSe,
231
- next_se : JssmCompileSe
232
- ) : Array< JssmTransition<mDT> > { // todo flow describe the parser representation of a transition step extension
233
-
234
- const edges : Array< JssmTransition<mDT> > = [];
235
-
236
- const uFrom : Array< string > = (Array.isArray(from)? from : [from]),
237
- uTo : Array< string > = (Array.isArray(to)? to : [to] );
238
-
239
- uFrom.map( (f: string) => {
240
- uTo.map( (t: string) => {
241
-
242
- const right: JssmTransition<mDT> = makeTransition(this_se, f, t, true);
243
- if (right.kind !== 'none') { edges.push(right); }
244
-
245
- const left: JssmTransition<mDT> = makeTransition(this_se, t, f, false);
246
- if (left.kind !== 'none') { edges.push(left); }
247
-
248
- });
249
- });
250
-
251
- const new_acc: Array< JssmTransition<mDT> > = acc.concat(edges);
252
-
253
- if (next_se) {
254
- return compile_rule_transition_step(new_acc, to, next_se.to, next_se, next_se.se);
255
- } else {
256
- return new_acc;
257
- }
258
-
259
- }
260
-
261
-
262
-
263
- function compile_rule_handle_transition(rule: JssmCompileSeStart<StateType>): any { // TODO FIXME no any // todo flow describe the parser representation of a transition
264
- return compile_rule_transition_step([], rule.from, rule.se.to, rule.se, rule.se.se);
265
- }
266
-
267
-
268
-
269
- function compile_rule_handler(rule: JssmCompileSeStart<StateType>): JssmCompileRule { // todo flow describe the output of the parser
270
-
271
- if (rule.key === 'transition') {
272
- return { agg_as: 'transition', val: compile_rule_handle_transition(rule) };
273
- }
274
-
275
- if (rule.key === 'machine_language') {
276
- return { agg_as: 'machine_language', val: reduce_to_639(rule.value) };
277
- }
278
-
279
- if (rule.key === 'state_declaration') {
280
- if (!rule.name) { throw new Error('State declarations must have a name'); }
281
- return { agg_as: 'state_declaration', val: { state: rule.name, declarations: rule.value } };
282
- }
283
-
284
- if (['arrange_declaration', 'arrange_start_declaration',
285
- 'arrange_end_declaration'].includes(rule.key)) {
286
- return { agg_as: rule.key, val: [rule.value] };
287
- }
288
-
289
- const tautologies : Array<string> = [
290
- 'graph_layout', 'start_states', 'end_states', 'machine_name', 'machine_version',
291
- 'machine_comment', 'machine_author', 'machine_contributor', 'machine_definition',
292
- 'machine_reference', 'machine_license', 'fsl_version', 'state_config', 'theme',
293
- 'flow', 'dot_preamble'
294
- ];
295
-
296
- if (tautologies.includes(rule.key)) {
297
- return { agg_as: rule.key, val: rule.value };
298
- }
299
-
300
- throw new Error(`compile_rule_handler: Unknown rule: ${JSON.stringify(rule)}`);
301
-
302
- }
303
-
304
-
305
-
306
-
307
-
308
- function compile<mDT>(tree: JssmParseTree): JssmGenericConfig<mDT> { // todo flow describe the output of the parser
309
-
310
- const results : {
311
- graph_layout : Array< JssmLayout >,
312
- transition : Array< JssmTransition<mDT> >,
313
- start_states : Array< string >,
314
- end_states : Array< string >,
315
- state_config : Array< any >, // TODO COMEBACK no any
316
- state_declaration : Array< string >,
317
- fsl_version : Array< string >,
318
- machine_author : Array< string >,
319
- machine_comment : Array< string >,
320
- machine_contributor : Array< string >,
321
- machine_definition : Array< string >,
322
- machine_language : Array< string >,
323
- machine_license : Array< string >,
324
- machine_name : Array< string >,
325
- machine_reference : Array< string >,
326
- theme : Array< string >,
327
- flow : Array< string >,
328
- dot_preamble : Array< string >,
329
- arrange_declaration : Array< Array< string > >, // TODO COMEBACK CHECKME
330
- arrange_start_declaration : Array< Array< string > >, // TODO COMEBACK CHECKME
331
- arrange_end_declaration : Array< Array< string > >, // TODO COMEBACK CHECKME
332
- machine_version : Array< string > // TODO COMEBACK semver
333
- } = {
334
- graph_layout : [],
335
- transition : [],
336
- start_states : [],
337
- end_states : [],
338
- state_config : [],
339
- state_declaration : [],
340
- fsl_version : [],
341
- machine_author : [],
342
- machine_comment : [],
343
- machine_contributor : [],
344
- machine_definition : [],
345
- machine_language : [],
346
- machine_license : [],
347
- machine_name : [],
348
- machine_reference : [],
349
- theme : [],
350
- flow : [],
351
- dot_preamble : [],
352
- arrange_declaration : [],
353
- arrange_start_declaration : [],
354
- arrange_end_declaration : [],
355
- machine_version : []
356
- };
357
-
358
- tree.map( (tr : JssmCompileSeStart<StateType>) => {
359
-
360
- const rule : JssmCompileRule = compile_rule_handler(tr),
361
- agg_as : string = rule.agg_as,
362
- val : any = rule.val; // TODO FIXME no any
363
-
364
- results[agg_as] = results[agg_as].concat(val);
365
-
366
- });
367
-
368
- const assembled_transitions : Array< JssmTransition<mDT> > = [].concat(... results['transition']);
369
-
370
- const result_cfg : JssmGenericConfig<mDT> = {
371
- start_states : results.start_states.length? results.start_states : [assembled_transitions[0].from],
372
- transitions : assembled_transitions
373
- };
374
-
375
- const oneOnlyKeys : Array<string> = [
376
- 'graph_layout', 'machine_name', 'machine_version', 'machine_comment',
377
- 'fsl_version', 'machine_license', 'machine_definition', 'machine_language',
378
- 'theme', 'flow', 'dot_preamble'
379
- ];
380
-
381
- oneOnlyKeys.map( (oneOnlyKey : string) => {
382
- if (results[oneOnlyKey].length > 1) {
383
- throw new Error(
384
- `May only have one ${oneOnlyKey} statement maximum: ${JSON.stringify(results[oneOnlyKey])}`
385
- );
386
- } else {
387
- if (results[oneOnlyKey].length) {
388
- result_cfg[oneOnlyKey] = results[oneOnlyKey][0];
389
- }
390
- }
391
- });
392
-
393
- ['arrange_declaration', 'arrange_start_declaration', 'arrange_end_declaration',
394
- 'machine_author', 'machine_contributor', 'machine_reference', 'state_declaration'].map(
395
- (multiKey : string) => {
396
- if (results[multiKey].length) {
397
- result_cfg[multiKey] = results[multiKey];
398
- }
399
- }
400
- );
401
-
402
- return result_cfg;
403
-
404
- }
405
-
406
-
407
-
408
-
409
-
410
- function make<mDT>(plan: string): JssmGenericConfig<mDT> {
411
- return compile(wrap_parse(plan));
412
- }
413
-
414
-
415
-
416
-
417
-
418
- function transfer_state_properties(state_decl: JssmStateDeclaration): JssmStateDeclaration {
419
-
420
- state_decl.declarations.map( (d: JssmStateDeclarationRule) => {
421
- switch (d.key) {
422
-
423
- case 'shape' : state_decl.shape = d.value; break;
424
- case 'color' : state_decl.color = d.value; break;
425
- case 'corners' : state_decl.corners = d.value; break;
426
- case 'linestyle' : state_decl.linestyle = d.value; break;
427
-
428
- case 'text-color' : state_decl.textColor = d.value; break;
429
- case 'background-color' : state_decl.backgroundColor = d.value; break;
430
- case 'border-color' : state_decl.borderColor = d.value; break;
431
-
432
- default: throw new Error(`Unknown state property: '${JSON.stringify(d)}'`);
433
-
434
- }
435
- });
436
-
437
- return state_decl;
438
-
439
- }
440
-
441
-
442
-
443
-
444
-
445
- class Machine<mDT> {
446
-
447
-
448
- _state : StateType;
449
- _states : Map<StateType, JssmGenericState>;
450
- _edges : Array<JssmTransition<mDT>>;
451
- _edge_map : Map<StateType, Map<StateType, number>>;
452
- _named_transitions : Map<StateType, number>;
453
- _actions : Map<StateType, Map<StateType, number>>;
454
- _reverse_actions : Map<StateType, Map<StateType, number>>;
455
- _reverse_action_targets : Map<StateType, Map<StateType, number>>;
456
-
457
- _machine_author? : Array<string>;
458
- _machine_comment? : string;
459
- _machine_contributor? : Array<string>;
460
- _machine_definition? : string;
461
- _machine_language? : string;
462
- _machine_license? : string;
463
- _machine_name? : string;
464
- _machine_version? : string;
465
- _fsl_version? : string;
466
- _raw_state_declaration? : Array<Object>;
467
- _state_declarations : Map<StateType, JssmStateDeclaration>;
468
-
469
- _graph_layout : JssmLayout;
470
- _dot_preamble : string;
471
- _arrange_declaration : Array<Array<StateType>>;
472
- _arrange_start_declaration : Array<Array<StateType>>;
473
- _arrange_end_declaration : Array<Array<StateType>>;
474
-
475
- _theme : FslTheme;
476
- _flow : FslDirection;
477
-
478
-
479
- // whargarbl this badly needs to be broken up, monolith master
480
- constructor({
481
- start_states,
482
- complete = [],
483
- transitions,
484
- machine_author,
485
- machine_comment,
486
- machine_contributor,
487
- machine_definition,
488
- machine_language,
489
- machine_license,
490
- machine_name,
491
- machine_version,
492
- state_declaration,
493
- fsl_version,
494
- dot_preamble = undefined,
495
- arrange_declaration = [],
496
- arrange_start_declaration = [],
497
- arrange_end_declaration = [],
498
- theme = 'default',
499
- flow = 'down',
500
- graph_layout = 'dot'
501
- } : JssmGenericConfig<mDT>) {
502
-
503
- this._state = start_states[0];
504
- this._states = new Map();
505
- this._state_declarations = new Map();
506
- this._edges = [];
507
- this._edge_map = new Map();
508
- this._named_transitions = new Map();
509
- this._actions = new Map();
510
- this._reverse_actions = new Map();
511
- this._reverse_action_targets = new Map(); // todo
512
-
513
- this._machine_author = array_box_if_string(machine_author);
514
- this._machine_comment = machine_comment;
515
- this._machine_contributor = array_box_if_string(machine_contributor);
516
- this._machine_definition = machine_definition;
517
- this._machine_language = machine_language;
518
- this._machine_license = machine_license;
519
- this._machine_name = machine_name;
520
- this._machine_version = machine_version;
521
- this._raw_state_declaration = state_declaration || [];
522
- this._fsl_version = fsl_version;
523
-
524
- this._arrange_declaration = arrange_declaration;
525
- this._arrange_start_declaration = arrange_start_declaration;
526
- this._arrange_end_declaration = arrange_end_declaration;
527
-
528
- this._dot_preamble = dot_preamble;
529
- this._theme = theme;
530
- this._flow = flow;
531
- this._graph_layout = graph_layout;
532
-
533
-
534
- if (state_declaration) {
535
- state_declaration.map( (state_decl: JssmStateDeclaration) => {
536
-
537
- if (this._state_declarations.has(state_decl.state)) { // no repeats
538
- throw new Error(`Added the same state declaration twice: ${JSON.stringify(state_decl.state)}`);
539
- }
540
-
541
- this._state_declarations.set( state_decl.state, transfer_state_properties(state_decl) );
542
-
543
- } );
544
- }
545
-
546
-
547
- transitions.map( (tr:JssmTransition<mDT>) => {
548
-
549
- if (tr.from === undefined) { throw new Error(`transition must define 'from': ${JSON.stringify(tr)}`); }
550
- if (tr.to === undefined) { throw new Error(`transition must define 'to': ${ JSON.stringify(tr)}`); }
551
-
552
- // get the cursors. what a mess
553
- const cursor_from: JssmGenericState
554
- = this._states.get(tr.from)
555
- || { name: tr.from, from: [], to: [], complete: complete.includes(tr.from) };
556
-
557
- if (!(this._states.has(tr.from))) {
558
- this._new_state(cursor_from);
559
- }
560
-
561
- const cursor_to: JssmGenericState
562
- = this._states.get(tr.to)
563
- || {name: tr.to, from: [], to: [], complete: complete.includes(tr.to) };
564
-
565
- if (!(this._states.has(tr.to))) {
566
- this._new_state(cursor_to);
567
- }
568
-
569
- // guard against existing connections being re-added
570
- if (cursor_from.to.includes(tr.to)) {
571
- throw new Error(`already has ${JSON.stringify(tr.from)} to ${JSON.stringify(tr.to)}`);
572
- } else {
573
- cursor_from.to.push(tr.to);
574
- cursor_to.from.push(tr.from);
575
- }
576
-
577
- // add the edge; note its id
578
- this._edges.push(tr);
579
- const thisEdgeId: number = this._edges.length - 1;
580
-
581
- // guard against repeating a transition name
582
- if (tr.name) {
583
- if (this._named_transitions.has(tr.name)) {
584
- throw new Error(`named transition "${JSON.stringify(tr.name)}" already created`);
585
- } else {
586
- this._named_transitions.set(tr.name, thisEdgeId);
587
- }
588
- }
589
-
590
- // set up the mapping, so that edges can be looked up by endpoint pairs
591
- const from_mapping: Map<StateType, number> = this._edge_map.get(tr.from) || new Map();
592
- if (!(this._edge_map.has(tr.from))) {
593
- this._edge_map.set(tr.from, from_mapping);
594
- }
595
-
596
- // const to_mapping = from_mapping.get(tr.to);
597
- from_mapping.set(tr.to, thisEdgeId); // already checked that this mapping doesn't exist, above
598
-
599
- // set up the action mapping, so that actions can be looked up by origin
600
- if (tr.action) {
601
-
602
-
603
- // forward mapping first by action name
604
- let actionMap: Map<StateType, number> = this._actions.get(tr.action); // TODO FIXME ?Map equiv
605
- if (!(actionMap)) {
606
- actionMap = new Map();
607
- this._actions.set(tr.action, actionMap);
608
- }
609
-
610
- if (actionMap.has(tr.from)) {
611
- throw new Error(`action ${JSON.stringify(tr.action)} already attached to origin ${JSON.stringify(tr.from)}`);
612
- } else {
613
- actionMap.set(tr.from, thisEdgeId);
614
- }
615
-
616
-
617
- // reverse mapping first by state origin name
618
- let rActionMap: Map<StateType, number> = this._reverse_actions.get(tr.from); // TODO FIXME ?Map equiv
619
- if (!(rActionMap)) {
620
- rActionMap = new Map();
621
- this._reverse_actions.set(tr.from, rActionMap);
622
- }
623
-
624
- // no need to test for reverse mapping pre-presence;
625
- // forward mapping already covers collisions
626
- rActionMap.set(tr.action, thisEdgeId);
627
-
628
-
629
- // reverse mapping first by state target name
630
- if (!(this._reverse_action_targets.has(tr.to))) {
631
- this._reverse_action_targets.set(tr.to, new Map());
632
- }
633
-
634
- /* todo comeback
635
- fundamental problem is roActionMap needs to be a multimap
636
- const roActionMap = this._reverse_action_targets.get(tr.to); // wasteful - already did has - refactor
637
- if (roActionMap) {
638
- if (roActionMap.has(tr.action)) {
639
- throw new Error(`ro-action ${tr.to} already attached to action ${tr.action}`);
640
- } else {
641
- roActionMap.set(tr.action, thisEdgeId);
642
- }
643
- } else {
644
- throw new Error('should be impossible - flow doesn\'t know .set precedes .get yet again. severe error?');
645
- }
646
- */
647
- }
648
-
649
- });
650
-
651
- }
652
-
653
- _new_state(state_config: JssmGenericState): StateType {
654
-
655
- if (this._states.has(state_config.name)) {
656
- throw new Error(`state ${JSON.stringify(state_config.name)} already exists`);
657
- }
658
-
659
- this._states.set(state_config.name, state_config);
660
- return state_config.name;
661
-
662
- }
663
-
664
-
665
-
666
- state(): StateType {
667
- return this._state;
668
- }
669
-
670
- /* whargarbl todo major
671
- when we reimplement this, reintroduce this change to the is_final call
672
-
673
- is_changing(): boolean {
674
- return true; // todo whargarbl
675
- }
676
- */
677
-
678
-
679
- state_is_final(whichState: StateType): boolean {
680
- return ( (this.state_is_terminal(whichState)) && (this.state_is_complete(whichState)) );
681
- }
682
-
683
- is_final(): boolean {
684
- // return ((!this.is_changing()) && this.state_is_final(this.state()));
685
- return this.state_is_final(this.state());
686
- }
687
-
688
- graph_layout(): string {
689
- return this._graph_layout;
690
- }
691
-
692
- dot_preamble(): string {
693
- return this._dot_preamble;
694
- }
695
-
696
-
697
-
698
- machine_author(): Array<string> {
699
- return this._machine_author;
700
- }
701
-
702
- machine_comment(): string {
703
- return this._machine_comment;
704
- }
705
-
706
- machine_contributor(): Array<string> {
707
- return this._machine_contributor;
708
- }
709
-
710
- machine_definition(): string {
711
- return this._machine_definition;
712
- }
713
-
714
- machine_language(): string {
715
- return this._machine_language;
716
- }
717
-
718
- machine_license(): string {
719
- return this._machine_license;
720
- }
721
-
722
- machine_name(): string {
723
- return this._machine_name;
724
- }
725
-
726
- machine_version(): string {
727
- return this._machine_version;
728
- }
729
-
730
- raw_state_declarations(): Array<Object> {
731
- return this._raw_state_declaration;
732
- }
733
-
734
- state_declaration(which: StateType): JssmStateDeclaration {
735
- return this._state_declarations.get(which);
736
- }
737
-
738
- state_declarations(): Map<StateType, JssmStateDeclaration> {
739
- return this._state_declarations;
740
- }
741
-
742
- fsl_version(): string {
743
- return this._fsl_version;
744
- }
745
-
746
-
747
-
748
- machine_state(): JssmMachineInternalState<mDT> {
749
-
750
- return {
751
- internal_state_impl_version : 1,
752
-
753
- actions : this._actions,
754
- edge_map : this._edge_map,
755
- edges : this._edges,
756
- named_transitions : this._named_transitions,
757
- reverse_actions : this._reverse_actions,
758
- // reverse_action_targets : this._reverse_action_targets,
759
- state : this._state,
760
- states : this._states
761
- };
762
-
763
- }
764
-
765
- /*
766
- load_machine_state(): boolean {
767
- return false; // todo whargarbl
768
- }
769
- */
770
-
771
-
772
- states(): Array<StateType> {
773
- return Array.from(this._states.keys());
774
- }
775
-
776
- state_for(whichState: StateType): JssmGenericState {
777
- const state: JssmGenericState = this._states.get(whichState);
778
- if (state) { return state; }
779
- else { throw new Error(`no such state ${JSON.stringify(state)}`); }
780
- }
781
-
782
- has_state(whichState: StateType): boolean {
783
- return this._states.get(whichState) !== undefined;
784
- }
785
-
786
-
787
-
788
- list_edges(): Array< JssmTransition<mDT> > {
789
- return this._edges;
790
- }
791
-
792
- list_named_transitions(): Map<StateType, number> {
793
- return this._named_transitions;
794
- }
795
-
796
- list_actions(): Array<StateType> {
797
- return Array.from(this._actions.keys());
798
- }
799
-
800
-
801
-
802
- theme(): FslTheme {
803
- return this._theme; // constructor sets this to "default" otherwise
804
- }
805
-
806
- flow(): FslDirection {
807
- return this._flow;
808
- }
809
-
810
-
811
-
812
- get_transition_by_state_names(from: StateType, to: StateType): number {
813
-
814
- const emg : Map<StateType, number> = this._edge_map.get(from);
815
-
816
- if (emg) {
817
- return emg.get(to);
818
- } else {
819
- return undefined;
820
- }
821
-
822
- }
823
-
824
-
825
-
826
- lookup_transition_for(from: StateType, to: StateType): JssmTransition<mDT> {
827
- const id : number = this.get_transition_by_state_names(from, to);
828
- return ((id === undefined) || (id === null))? undefined : this._edges[id];
829
- }
830
-
831
-
832
-
833
- list_transitions(whichState: StateType = this.state()): JssmTransitionList {
834
- return {entrances: this.list_entrances(whichState), exits: this.list_exits(whichState)};
835
- }
836
-
837
- list_entrances(whichState: StateType = this.state()): Array<StateType> {
838
- return (this._states.get(whichState)
839
- || {from: undefined}).from
840
- || [];
841
- }
842
-
843
- list_exits(whichState: StateType = this.state()): Array<StateType> {
844
- return (this._states.get(whichState)
845
- || {to: undefined}).to
846
- || [];
847
- }
848
-
849
-
850
-
851
- probable_exits_for(whichState: StateType): Array< JssmTransition<mDT> > {
852
-
853
- const wstate: JssmGenericState = this._states.get(whichState);
854
- if (!(wstate)) { throw new Error(`No such state ${JSON.stringify(whichState)} in probable_exits_for`); }
855
-
856
- const wstate_to : Array<StateType> = wstate.to,
857
-
858
- wtf : Array< JssmTransition<mDT> > // wstate_to_filtered -> wtf
859
- = wstate_to
860
- .map( (ws) : JssmTransition<mDT> => this.lookup_transition_for(this.state(), ws))
861
- .filter(Boolean);
862
-
863
- return wtf;
864
-
865
- }
866
-
867
- probabilistic_transition(): boolean {
868
- const selected : JssmTransition<mDT> = weighted_rand_select(this.probable_exits_for(this.state()));
869
- return this.transition( selected.to );
870
- }
871
-
872
- probabilistic_walk(n: number): Array<StateType> {
873
- return seq(n)
874
- .map(() : StateType => {
875
- const state_was: StateType = this.state();
876
- this.probabilistic_transition();
877
- return state_was;
878
- })
879
- .concat([this.state()]);
880
- }
881
-
882
- probabilistic_histo_walk(n: number): Map<StateType, number> {
883
- return histograph(this.probabilistic_walk(n));
884
- }
885
-
886
-
887
-
888
- actions(whichState: StateType = this.state() ): Array<StateType> {
889
- const wstate : Map<StateType, number> = this._reverse_actions.get(whichState);
890
- if (wstate) { return Array.from(wstate.keys()); }
891
- else { throw new Error(`No such state ${JSON.stringify(whichState)}`); }
892
- }
893
-
894
- list_states_having_action(whichState: StateType): Array<StateType> {
895
- const wstate : Map<StateType, number> = this._actions.get(whichState);
896
- if (wstate) { return Array.from(wstate.keys()); }
897
- else { throw new Error(`No such state ${JSON.stringify(whichState)}`); }
898
- }
899
-
900
- // comeback
901
- /*
902
- list_entrance_actions(whichState: mNT = this.state() ) : Array<mNT> {
903
- return [... (this._reverse_action_targets.get(whichState) || new Map()).values()] // wasteful
904
- .map( (edgeId:any) => (this._edges[edgeId] : any)) // whargarbl burn out any
905
- .filter( (o:any) => o.to === whichState)
906
- .map( filtered => filtered.from );
907
- }
908
- */
909
- list_exit_actions(whichState: StateType = this.state() ): Array<StateType> { // these are mNT, not ?mNT
910
- const ra_base: Map<StateType, number> = this._reverse_actions.get(whichState);
911
- if (!(ra_base)) { throw new Error(`No such state ${JSON.stringify(whichState)}`); }
912
-
913
- return Array.from(ra_base.values())
914
- .map ( (edgeId: number) : JssmTransition<mDT> => this._edges[edgeId] )
915
- .filter ( (o: JssmTransition<mDT>) : boolean => o.from === whichState )
916
- .map ( (filtered: JssmTransition<mDT>) : StateType => filtered.action );
917
- }
918
-
919
- probable_action_exits(whichState: StateType = this.state() ) : Array<any> { // these are mNT // TODO FIXME no any
920
- const ra_base: Map<StateType, number> = this._reverse_actions.get(whichState);
921
- if (!(ra_base)) { throw new Error(`No such state ${JSON.stringify(whichState)}`); }
922
-
923
- return Array.from(ra_base.values())
924
- .map ( (edgeId: number): JssmTransition<mDT> => this._edges[edgeId] )
925
- .filter ( (o: JssmTransition<mDT>): boolean => o.from === whichState )
926
- .map ( (filtered): any => ( { action : filtered.action, // TODO FIXME no any
927
- probability : filtered.probability
928
- } )
929
- );
930
- }
931
-
932
-
933
-
934
- // TODO FIXME test that is_unenterable on non-state throws
935
- is_unenterable(whichState: StateType): boolean {
936
- if (!(this.has_state(whichState))) { throw new Error(`No such state ${whichState}`); }
937
- return this.list_entrances(whichState).length === 0;
938
- }
939
-
940
- has_unenterables(): boolean {
941
- return this.states().some( (x: StateType): boolean => this.is_unenterable(x));
942
- }
943
-
944
-
945
-
946
- is_terminal(): boolean {
947
- return this.state_is_terminal(this.state());
948
- }
949
-
950
- // TODO FIXME test that state_is_terminal on non-state throws
951
- state_is_terminal(whichState: StateType): boolean {
952
- if (!(this.has_state(whichState))) { throw new Error(`No such state ${whichState}`); }
953
- return this.list_exits(whichState).length === 0;
954
- }
955
-
956
- has_terminals(): boolean {
957
- return this.states().some( (x): boolean => this.state_is_terminal(x));
958
- }
959
-
960
-
961
-
962
- is_complete(): boolean {
963
- return this.state_is_complete(this.state());
964
- }
965
-
966
- state_is_complete(whichState: StateType) : boolean {
967
- const wstate: JssmGenericState = this._states.get(whichState);
968
- if (wstate) { return wstate.complete; }
969
- else { throw new Error(`No such state ${JSON.stringify(whichState)}`); }
970
- }
971
-
972
- has_completes(): boolean {
973
- return this.states().some( (x): boolean => this.state_is_complete(x) );
974
- }
975
-
976
-
977
-
978
- action(name: StateType, newData?: mDT): boolean {
979
- // todo whargarbl implement hooks
980
- // todo whargarbl implement data stuff
981
- // todo major incomplete whargarbl comeback
982
- if (this.valid_action(name, newData)) {
983
- const edge: JssmTransition<mDT> = this.current_action_edge_for(name);
984
- this._state = edge.to;
985
- return true;
986
- } else {
987
- return false;
988
- }
989
- }
990
-
991
- transition(newState: StateType, newData?: mDT): boolean {
992
- // todo whargarbl implement hooks
993
- // todo whargarbl implement data stuff
994
- // todo major incomplete whargarbl comeback
995
- if (this.valid_transition(newState, newData)) {
996
- this._state = newState;
997
- return true;
998
- } else {
999
- return false;
1000
- }
1001
- }
1002
-
1003
- // can leave machine in inconsistent state. generally do not use
1004
- force_transition(newState: StateType, newData?: mDT): boolean {
1005
- // todo whargarbl implement hooks
1006
- // todo whargarbl implement data stuff
1007
- // todo major incomplete whargarbl comeback
1008
- if (this.valid_force_transition(newState, newData)) {
1009
- this._state = newState;
1010
- return true;
1011
- } else {
1012
- return false;
1013
- }
1014
- }
1015
-
1016
-
1017
-
1018
- current_action_for(action: StateType): number {
1019
- const action_base: Map<StateType, number> = this._actions.get(action);
1020
- return action_base? action_base.get(this.state()): undefined;
1021
- }
1022
-
1023
- current_action_edge_for(action: StateType): JssmTransition<mDT> {
1024
- const idx: number = this.current_action_for(action);
1025
- if ((idx === undefined) || (idx === null)) { throw new Error(`No such action ${JSON.stringify(action)}`); }
1026
- return this._edges[idx];
1027
- }
1028
-
1029
- valid_action(action: StateType, _newData?: mDT): boolean { // todo comeback unignore newData
1030
- // todo whargarbl implement hooks
1031
- // todo whargarbl implement data stuff
1032
- // todo major incomplete whargarbl comeback
1033
- return this.current_action_for(action) !== undefined;
1034
- }
1035
-
1036
- valid_transition(newState: StateType, _newData?: mDT): boolean { // todo comeback unignore newData
1037
- // todo whargarbl implement hooks
1038
- // todo whargarbl implement data stuff
1039
- // todo major incomplete whargarbl comeback
1040
- const transition_for: JssmTransition<mDT> = this.lookup_transition_for(this.state(), newState);
1041
-
1042
- if (!(transition_for)) { return false; }
1043
- if (transition_for.forced_only) { return false; }
1044
-
1045
- return true;
1046
-
1047
- }
1048
-
1049
- valid_force_transition(newState: StateType, _newData?: mDT): boolean { // todo comeback unignore newData
1050
- // todo whargarbl implement hooks
1051
- // todo whargarbl implement data stuff
1052
- // todo major incomplete whargarbl comeback
1053
- return (this.lookup_transition_for(this.state(), newState) !== undefined);
1054
- }
1055
-
1056
- /* eslint-disable no-use-before-define */
1057
- /* eslint-disable class-methods-use-this */
1058
- sm(template_strings: TemplateStringsArray, ... remainder /* , arguments */): Machine<mDT> {
1059
- return sm(template_strings, ... remainder);
1060
- }
1061
- /* eslint-enable class-methods-use-this */
1062
- /* eslint-enable no-use-before-define */
1063
-
1064
-
1065
- }
1066
-
1067
-
1068
-
1069
-
1070
-
1071
- function sm<mDT>(template_strings: TemplateStringsArray, ... remainder /* , arguments */): Machine<mDT> {
1072
-
1073
- // foo`a${1}b${2}c` will come in as (['a','b','c'],1,2)
1074
- // this includes when a and c are empty strings
1075
- // therefore template_strings will always have one more el than template_args
1076
- // therefore map the smaller container and toss the last one on on the way out
1077
-
1078
- return new Machine(make(template_strings.reduce(
1079
-
1080
- // in general avoiding `arguments` is smart. however with the template
1081
- // string notation, as designed, it's not really worth the hassle
1082
-
1083
- /* eslint-disable prefer-rest-params */
1084
- (acc, val, idx): string => `${acc}${remainder[idx-1]}${val}` // arguments[0] is never loaded, so args doesn't need to be gated
1085
- /* eslint-enable prefer-rest-params */
1086
-
1087
- )));
1088
-
1089
- }
1090
-
1091
-
1092
-
1093
-
1094
-
1095
- export {
1096
-
1097
- version,
1098
-
1099
- transfer_state_properties,
1100
-
1101
- Machine,
1102
-
1103
- make,
1104
- wrap_parse as parse,
1105
- compile,
1106
-
1107
- sm,
1108
-
1109
- arrow_direction,
1110
- arrow_left_kind,
1111
- arrow_right_kind,
1112
-
1113
- // WHARGARBL TODO these should be exported to a utility library
1114
- seq,
1115
- weighted_rand_select,
1116
- histograph,
1117
- weighted_sample_select,
1118
- weighted_histo_key
1119
-
1120
- };