jssm 5.77.1 → 5.79.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/CHANGELOG.md +37 -44
- package/README.md +2 -2
- package/dist/es6/jssm-dot.js +1 -1
- package/dist/es6/jssm.d.ts +166 -16
- package/dist/es6/jssm.js +277 -22
- package/dist/es6/jssm_types.d.ts +27 -3
- package/dist/es6/jssm_util.d.ts +44 -1
- package/dist/es6/jssm_util.js +68 -1
- package/dist/es6/version.js +1 -1
- package/dist/jssm.es5.cjs.js +1 -1
- package/dist/jssm.es5.iife.js +1 -1
- package/jssm.d.ts +166 -16
- package/jssm_types.d.ts +27 -3
- package/jssm_util.d.ts +44 -1
- package/package.json +1 -1
package/dist/es6/jssm.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
declare type StateType = string;
|
|
2
|
-
import { circular_buffer } from 'circular_buffer_js';
|
|
3
2
|
import { JssmGenericState, JssmGenericConfig, JssmTransition, JssmTransitionList, // JssmTransitionRule,
|
|
4
|
-
JssmMachineInternalState, JssmParseTree, JssmStateDeclaration, JssmArrow, JssmArrowDirection, JssmArrowKind, JssmLayout, FslDirection, FslTheme, HookDescription, HookHandler, HookContext, HookResult, HookComplexResult } from './jssm_types';
|
|
5
|
-
import { seq, weighted_rand_select, weighted_sample_select, histograph, weighted_histo_key } from './jssm_util';
|
|
3
|
+
JssmMachineInternalState, JssmParseTree, JssmStateDeclaration, JssmArrow, JssmArrowDirection, JssmArrowKind, JssmLayout, JssmHistory, JssmSerialization, FslDirection, FslTheme, HookDescription, HookHandler, HookContext, HookResult, HookComplexResult } from './jssm_types';
|
|
4
|
+
import { seq, unique, find_repeated, weighted_rand_select, weighted_sample_select, histograph, weighted_histo_key } from './jssm_util';
|
|
6
5
|
import { shapes, gviz_shapes, named_colors } from './jssm_constants';
|
|
7
6
|
import { version } from './version';
|
|
8
7
|
/*********
|
|
@@ -251,9 +250,12 @@ declare class Machine<mDT> {
|
|
|
251
250
|
_post_main_transition_hook: HookHandler<mDT> | undefined;
|
|
252
251
|
_post_forced_transition_hook: HookHandler<mDT> | undefined;
|
|
253
252
|
_post_any_transition_hook: HookHandler<mDT> | undefined;
|
|
254
|
-
|
|
253
|
+
_property_keys: Set<string>;
|
|
254
|
+
_default_properties: Map<string, any>;
|
|
255
|
+
_state_properties: Map<string, any>;
|
|
256
|
+
_history: JssmHistory<mDT>;
|
|
255
257
|
_history_length: number;
|
|
256
|
-
constructor({ start_states, complete, transitions, machine_author, machine_comment, machine_contributor, machine_definition, machine_language, machine_license, machine_name, machine_version, state_declaration, fsl_version, dot_preamble, arrange_declaration, arrange_start_declaration, arrange_end_declaration, theme, flow, graph_layout, instance_name, history, data }: JssmGenericConfig<mDT>);
|
|
258
|
+
constructor({ start_states, complete, transitions, machine_author, machine_comment, machine_contributor, machine_definition, machine_language, machine_license, machine_name, machine_version, state_declaration, property_definition, state_property, fsl_version, dot_preamble, arrange_declaration, arrange_start_declaration, arrange_end_declaration, theme, flow, graph_layout, instance_name, history, data }: JssmGenericConfig<mDT>);
|
|
257
259
|
/********
|
|
258
260
|
*
|
|
259
261
|
* Internal method for fabricating states. Not meant for external use.
|
|
@@ -295,6 +297,122 @@ declare class Machine<mDT> {
|
|
|
295
297
|
*
|
|
296
298
|
*/
|
|
297
299
|
data(): mDT;
|
|
300
|
+
/*********
|
|
301
|
+
*
|
|
302
|
+
* Get the current value of a given property name.
|
|
303
|
+
*
|
|
304
|
+
* ```typescript
|
|
305
|
+
*
|
|
306
|
+
* ```
|
|
307
|
+
*
|
|
308
|
+
* @param name The relevant property name to look up
|
|
309
|
+
*
|
|
310
|
+
* @returns The value behind the prop name. Because functional props are
|
|
311
|
+
* evaluated as getters, this can be anything.
|
|
312
|
+
*
|
|
313
|
+
*/
|
|
314
|
+
prop(name: string): any;
|
|
315
|
+
/*********
|
|
316
|
+
*
|
|
317
|
+
* Get the current value of a given property name. If missing on the state
|
|
318
|
+
* and without a global default, throw, unlike {@link prop}, which would
|
|
319
|
+
* return `undefined` instead.
|
|
320
|
+
*
|
|
321
|
+
* ```typescript
|
|
322
|
+
*
|
|
323
|
+
* ```
|
|
324
|
+
*
|
|
325
|
+
* @param name The relevant property name to look up
|
|
326
|
+
*
|
|
327
|
+
* @returns The value behind the prop name. Because functional props are
|
|
328
|
+
* evaluated as getters, this can be anything.
|
|
329
|
+
*
|
|
330
|
+
*/
|
|
331
|
+
strict_prop(name: string): any;
|
|
332
|
+
/*********
|
|
333
|
+
*
|
|
334
|
+
* Get the current value of every prop, as an object. If no current definition
|
|
335
|
+
* exists for a prop - that is, if the prop was defined without a default and
|
|
336
|
+
* the current state also doesn't define the prop - then that prop will be listed
|
|
337
|
+
* in the returned object with a value of `undefined`.
|
|
338
|
+
*
|
|
339
|
+
* ```typescript
|
|
340
|
+
* const traffic_light = sm`
|
|
341
|
+
*
|
|
342
|
+
* property can_go default true;
|
|
343
|
+
* property hesitate default true;
|
|
344
|
+
* property stop_first default false;
|
|
345
|
+
*
|
|
346
|
+
* Off -> Red => Green => Yellow => Red;
|
|
347
|
+
* [Red Yellow Green] ~> [Off FlashingRed];
|
|
348
|
+
* FlashingRed -> Red;
|
|
349
|
+
*
|
|
350
|
+
* state Red: { property stop_first true; property can_go false; };
|
|
351
|
+
* state Off: { property stop_first true; };
|
|
352
|
+
* state FlashingRed: { property stop_first true; };
|
|
353
|
+
* state Green: { property hesitate false; };
|
|
354
|
+
*
|
|
355
|
+
* `;
|
|
356
|
+
*
|
|
357
|
+
* traffic_light.state(); // Off
|
|
358
|
+
* traffic_light.props(); // { can_go: true, hesitate: true, stop_first: true; }
|
|
359
|
+
*
|
|
360
|
+
* traffic_light.go('Red');
|
|
361
|
+
* traffic_light.props(); // { can_go: false, hesitate: true, stop_first: true; }
|
|
362
|
+
*
|
|
363
|
+
* traffic_light.go('Green');
|
|
364
|
+
* traffic_light.props(); // { can_go: true, hesitate: false, stop_first: false; }
|
|
365
|
+
* ```
|
|
366
|
+
*
|
|
367
|
+
*/
|
|
368
|
+
props(): object;
|
|
369
|
+
/*********
|
|
370
|
+
*
|
|
371
|
+
* Get the current value of every prop, as an object. Compare
|
|
372
|
+
* {@link prop_map}, which returns a `Map`.
|
|
373
|
+
*
|
|
374
|
+
* ```typescript
|
|
375
|
+
*
|
|
376
|
+
* ```
|
|
377
|
+
*
|
|
378
|
+
*/
|
|
379
|
+
/*********
|
|
380
|
+
*
|
|
381
|
+
* Get the current value of every prop, as an object. Compare
|
|
382
|
+
* {@link prop_map}, which returns a `Map`. Akin to {@link strict_prop},
|
|
383
|
+
* this throws if a required prop is missing.
|
|
384
|
+
*
|
|
385
|
+
* ```typescript
|
|
386
|
+
*
|
|
387
|
+
* ```
|
|
388
|
+
*
|
|
389
|
+
*/
|
|
390
|
+
/*********
|
|
391
|
+
*
|
|
392
|
+
* Check whether a given string is a known property's name.
|
|
393
|
+
*
|
|
394
|
+
* ```typescript
|
|
395
|
+
* const example = sm`property foo default 1; a->b;`;
|
|
396
|
+
*
|
|
397
|
+
* example.known_prop('foo'); // true
|
|
398
|
+
* example.known_prop('bar'); // false
|
|
399
|
+
* ```
|
|
400
|
+
*
|
|
401
|
+
* @param prop_name The relevant property name to look up
|
|
402
|
+
*
|
|
403
|
+
*/
|
|
404
|
+
known_prop(prop_name: string): boolean;
|
|
405
|
+
/*********
|
|
406
|
+
*
|
|
407
|
+
* List all known property names. If you'd also like values, use
|
|
408
|
+
* {@link props} instead. The order of the properties is not defined, and
|
|
409
|
+
* the properties generally will not be sorted.
|
|
410
|
+
*
|
|
411
|
+
* ```typescript
|
|
412
|
+
* ```
|
|
413
|
+
*
|
|
414
|
+
*/
|
|
415
|
+
known_props(): string[];
|
|
298
416
|
/********
|
|
299
417
|
*
|
|
300
418
|
* Check whether a given state is final (either has no exits or is marked
|
|
@@ -330,10 +448,19 @@ declare class Machine<mDT> {
|
|
|
330
448
|
* console.log( final_test.is_final() ); // true
|
|
331
449
|
* ```
|
|
332
450
|
*
|
|
451
|
+
*/
|
|
452
|
+
is_final(): boolean;
|
|
453
|
+
/********
|
|
454
|
+
*
|
|
455
|
+
* Serialize the current machine, including all defining state but not the
|
|
456
|
+
* machine string, to a structure. This means you will need the machine
|
|
457
|
+
* string to recreate (to not waste repeated space;) if you want the machine
|
|
458
|
+
* string embedded, call {@link serialize_with_string} instead.
|
|
459
|
+
*
|
|
333
460
|
* @typeparam mDT The type of the machine data member; usually omitted
|
|
334
461
|
*
|
|
335
462
|
*/
|
|
336
|
-
|
|
463
|
+
serialize(comment?: string | undefined): JssmSerialization<mDT>;
|
|
337
464
|
graph_layout(): string;
|
|
338
465
|
dot_preamble(): string;
|
|
339
466
|
machine_author(): Array<string>;
|
|
@@ -688,15 +815,27 @@ declare class Machine<mDT> {
|
|
|
688
815
|
* Instruct the machine to complete an action. Synonym for {@link action}.
|
|
689
816
|
*
|
|
690
817
|
* ```typescript
|
|
691
|
-
* const light = sm`
|
|
818
|
+
* const light = sm`
|
|
819
|
+
* off 'start' -> red;
|
|
820
|
+
* red 'next' -> green 'next' -> yellow 'next' -> red;
|
|
821
|
+
* [red yellow green] 'shutdown' ~> off;
|
|
822
|
+
* `;
|
|
692
823
|
*
|
|
693
|
-
* light.state();
|
|
694
|
-
* light.do('
|
|
695
|
-
* light.state();
|
|
824
|
+
* light.state(); // 'off'
|
|
825
|
+
* light.do('start'); // true
|
|
826
|
+
* light.state(); // 'red'
|
|
827
|
+
* light.do('next'); // true
|
|
828
|
+
* light.state(); // 'green'
|
|
829
|
+
* light.do('next'); // true
|
|
830
|
+
* light.state(); // 'yellow'
|
|
831
|
+
* light.do('dance'); // !! false - no such action
|
|
832
|
+
* light.state(); // 'yellow'
|
|
833
|
+
* light.do('start'); // !! false - yellow does not have the action start
|
|
834
|
+
* light.state(); // 'yellow'
|
|
696
835
|
* ```
|
|
697
836
|
*
|
|
698
837
|
* @typeparam mDT The type of the machine data member; usually omitted
|
|
699
|
-
|
|
838
|
+
b *
|
|
700
839
|
* @param actionName The action to engage
|
|
701
840
|
*
|
|
702
841
|
* @param newData The data change to insert during the action
|
|
@@ -708,11 +847,21 @@ declare class Machine<mDT> {
|
|
|
708
847
|
* Instruct the machine to complete a transition. Synonym for {@link go}.
|
|
709
848
|
*
|
|
710
849
|
* ```typescript
|
|
711
|
-
* const light = sm`
|
|
850
|
+
* const light = sm`
|
|
851
|
+
* off 'start' -> red;
|
|
852
|
+
* red 'next' -> green 'next' -> yellow 'next' -> red;
|
|
853
|
+
* [red yellow green] 'shutdown' ~> off;
|
|
854
|
+
* `;
|
|
712
855
|
*
|
|
713
|
-
* light.state();
|
|
714
|
-
* light.
|
|
715
|
-
* light.state();
|
|
856
|
+
* light.state(); // 'off'
|
|
857
|
+
* light.go('red'); // true
|
|
858
|
+
* light.state(); // 'red'
|
|
859
|
+
* light.go('green'); // true
|
|
860
|
+
* light.state(); // 'green'
|
|
861
|
+
* light.go('blue'); // !! false - no such state
|
|
862
|
+
* light.state(); // 'green'
|
|
863
|
+
* light.go('red'); // !! false - green may not go directly to red, only to yellow
|
|
864
|
+
* light.state(); // 'green'
|
|
716
865
|
* ```
|
|
717
866
|
*
|
|
718
867
|
* @typeparam mDT The type of the machine data member; usually omitted
|
|
@@ -824,4 +973,5 @@ declare function from<mDT>(MachineAsString: string, ExtraConstructorFields?: Par
|
|
|
824
973
|
declare function is_hook_complex_result<mDT>(hr: unknown): hr is HookComplexResult<mDT>;
|
|
825
974
|
declare function is_hook_rejection<mDT>(hr: HookResult<mDT>): boolean;
|
|
826
975
|
declare function abstract_hook_step<mDT>(maybe_hook: HookHandler<mDT> | undefined, hook_args: HookContext<mDT>): HookComplexResult<mDT>;
|
|
827
|
-
|
|
976
|
+
declare function deserialize<mDT>(machine_string: string, ser: JssmSerialization<mDT>): Machine<mDT>;
|
|
977
|
+
export { version, transfer_state_properties, Machine, deserialize, make, wrap_parse as parse, compile, sm, from, arrow_direction, arrow_left_kind, arrow_right_kind, seq, unique, find_repeated, weighted_rand_select, histograph, weighted_sample_select, weighted_histo_key, shapes, gviz_shapes, named_colors, is_hook_rejection, is_hook_complex_result, abstract_hook_step };
|
package/dist/es6/jssm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// whargarbl lots of these return arrays could/should be sets
|
|
2
2
|
import { reduce as reduce_to_639 } from 'reduce-to-639-1';
|
|
3
3
|
import { circular_buffer } from 'circular_buffer_js';
|
|
4
|
-
import { seq, weighted_rand_select, weighted_sample_select, histograph, weighted_histo_key, array_box_if_string, hook_name, named_hook_name } from './jssm_util';
|
|
4
|
+
import { seq, unique, find_repeated, weighted_rand_select, weighted_sample_select, histograph, weighted_histo_key, array_box_if_string, name_bind_prop_and_state, hook_name, named_hook_name } from './jssm_util';
|
|
5
5
|
import { shapes, gviz_shapes, named_colors } from './jssm_constants';
|
|
6
6
|
import { parse } from './jssm-dot';
|
|
7
7
|
import { version } from './version'; // replaced from package.js in build
|
|
@@ -351,6 +351,16 @@ function compile_rule_handler(rule) {
|
|
|
351
351
|
if (rule.key === 'machine_language') {
|
|
352
352
|
return { agg_as: 'machine_language', val: reduce_to_639(rule.value) };
|
|
353
353
|
}
|
|
354
|
+
// manually rehandled to make `undefined` as a property safe
|
|
355
|
+
if (rule.key === 'property_definition') {
|
|
356
|
+
if (rule.hasOwnProperty('default_value')) {
|
|
357
|
+
return { agg_as: 'property_definition', val: { name: rule.name, default_value: rule.default_value } };
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
return { agg_as: 'property_definition', val: { name: rule.name } };
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
// state properties are in here
|
|
354
364
|
if (rule.key === 'state_declaration') {
|
|
355
365
|
if (!rule.name) {
|
|
356
366
|
throw new JssmError(undefined, 'State declarations must have a name');
|
|
@@ -361,6 +371,7 @@ function compile_rule_handler(rule) {
|
|
|
361
371
|
'arrange_end_declaration'].includes(rule.key)) {
|
|
362
372
|
return { agg_as: rule.key, val: [rule.value] };
|
|
363
373
|
}
|
|
374
|
+
// things that can only exist once and are just a value under their own name
|
|
364
375
|
const tautologies = [
|
|
365
376
|
'graph_layout', 'start_states', 'end_states', 'machine_name', 'machine_version',
|
|
366
377
|
'machine_comment', 'machine_author', 'machine_contributor', 'machine_definition',
|
|
@@ -440,6 +451,8 @@ function compile(tree) {
|
|
|
440
451
|
machine_license: [],
|
|
441
452
|
machine_name: [],
|
|
442
453
|
machine_reference: [],
|
|
454
|
+
property_definition: [],
|
|
455
|
+
state_property: {},
|
|
443
456
|
theme: [],
|
|
444
457
|
flow: [],
|
|
445
458
|
dot_preamble: [],
|
|
@@ -452,10 +465,15 @@ function compile(tree) {
|
|
|
452
465
|
const rule = compile_rule_handler(tr), agg_as = rule.agg_as, val = rule.val; // TODO FIXME no any
|
|
453
466
|
results[agg_as] = results[agg_as].concat(val);
|
|
454
467
|
});
|
|
468
|
+
const property_keys = results['property_definition'].map(pd => pd.name), repeat_props = find_repeated(property_keys);
|
|
469
|
+
if (repeat_props.length) {
|
|
470
|
+
throw new JssmError(undefined, `Cannot repeat property definitions. Saw ${JSON.stringify(repeat_props)}`);
|
|
471
|
+
}
|
|
455
472
|
const assembled_transitions = [].concat(...results['transition']);
|
|
456
473
|
const result_cfg = {
|
|
457
474
|
start_states: results.start_states.length ? results.start_states : [assembled_transitions[0].from],
|
|
458
|
-
transitions: assembled_transitions
|
|
475
|
+
transitions: assembled_transitions,
|
|
476
|
+
state_property: []
|
|
459
477
|
};
|
|
460
478
|
const oneOnlyKeys = [
|
|
461
479
|
'graph_layout', 'machine_name', 'machine_version', 'machine_comment',
|
|
@@ -473,11 +491,28 @@ function compile(tree) {
|
|
|
473
491
|
}
|
|
474
492
|
});
|
|
475
493
|
['arrange_declaration', 'arrange_start_declaration', 'arrange_end_declaration',
|
|
476
|
-
'machine_author', 'machine_contributor', 'machine_reference',
|
|
494
|
+
'machine_author', 'machine_contributor', 'machine_reference',
|
|
495
|
+
'state_declaration', 'property_definition'].map((multiKey) => {
|
|
477
496
|
if (results[multiKey].length) {
|
|
478
497
|
result_cfg[multiKey] = results[multiKey];
|
|
479
498
|
}
|
|
480
499
|
});
|
|
500
|
+
// re-walk state declarations, already wrapped up, to get state properties,
|
|
501
|
+
// which go out in a different datastructure
|
|
502
|
+
results.state_declaration.forEach(sd => {
|
|
503
|
+
sd.declarations.forEach(decl => {
|
|
504
|
+
if (decl.key === 'state_property') {
|
|
505
|
+
const label = name_bind_prop_and_state(decl.name, sd.state);
|
|
506
|
+
console.log(`Bind ${sd.state}:${decl.name} as ${label}`);
|
|
507
|
+
if (result_cfg.state_property.findIndex(c => c.name === label) !== -1) {
|
|
508
|
+
throw new JssmError(undefined, `A state may only bind a property once (${sd.state} re-binds ${decl.name})`);
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
result_cfg.state_property.push({ name: label, default_value: decl.value });
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
});
|
|
481
516
|
return result_cfg;
|
|
482
517
|
}
|
|
483
518
|
/*********
|
|
@@ -527,6 +562,9 @@ function transfer_state_properties(state_decl) {
|
|
|
527
562
|
case 'border-color':
|
|
528
563
|
state_decl.borderColor = d.value;
|
|
529
564
|
break;
|
|
565
|
+
case 'state_property':
|
|
566
|
+
state_decl.property = { name: d.name, value: d.value };
|
|
567
|
+
break;
|
|
530
568
|
default: throw new JssmError(undefined, `Unknown state property: '${JSON.stringify(d)}'`);
|
|
531
569
|
}
|
|
532
570
|
});
|
|
@@ -535,7 +573,7 @@ function transfer_state_properties(state_decl) {
|
|
|
535
573
|
// TODO add a lotta docblock here
|
|
536
574
|
class Machine {
|
|
537
575
|
// whargarbl this badly needs to be broken up, monolith master
|
|
538
|
-
constructor({ start_states, complete = [], transitions, machine_author, machine_comment, machine_contributor, machine_definition, machine_language, machine_license, machine_name, machine_version, state_declaration, fsl_version, dot_preamble = undefined, arrange_declaration = [], arrange_start_declaration = [], arrange_end_declaration = [], theme = 'default', flow = 'down', graph_layout = 'dot', instance_name, history, data }) {
|
|
576
|
+
constructor({ start_states, complete = [], transitions, machine_author, machine_comment, machine_contributor, machine_definition, machine_language, machine_license, machine_name, machine_version, state_declaration, property_definition, state_property, fsl_version, dot_preamble = undefined, arrange_declaration = [], arrange_start_declaration = [], arrange_end_declaration = [], theme = 'default', flow = 'down', graph_layout = 'dot', instance_name, history, data }) {
|
|
539
577
|
this._instance_name = instance_name;
|
|
540
578
|
this._state = start_states[0];
|
|
541
579
|
this._states = new Map();
|
|
@@ -600,6 +638,9 @@ class Machine {
|
|
|
600
638
|
this._post_forced_transition_hook = undefined;
|
|
601
639
|
this._post_any_transition_hook = undefined;
|
|
602
640
|
this._data = data;
|
|
641
|
+
this._property_keys = new Set();
|
|
642
|
+
this._default_properties = new Map();
|
|
643
|
+
this._state_properties = new Map();
|
|
603
644
|
this._history_length = history || 0;
|
|
604
645
|
this._history = new circular_buffer(this._history_length);
|
|
605
646
|
if (state_declaration) {
|
|
@@ -697,6 +738,19 @@ class Machine {
|
|
|
697
738
|
*/
|
|
698
739
|
}
|
|
699
740
|
});
|
|
741
|
+
if (Array.isArray(property_definition)) {
|
|
742
|
+
property_definition.forEach(pr => {
|
|
743
|
+
this._property_keys.add(pr.name);
|
|
744
|
+
if (pr.hasOwnProperty('default_value')) {
|
|
745
|
+
this._default_properties.set(pr.name, pr.default_value);
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
if (Array.isArray(state_property)) {
|
|
750
|
+
state_property.forEach(sp => {
|
|
751
|
+
this._state_properties.set(sp.name, sp.default_value);
|
|
752
|
+
});
|
|
753
|
+
}
|
|
700
754
|
}
|
|
701
755
|
/********
|
|
702
756
|
*
|
|
@@ -763,6 +817,165 @@ class Machine {
|
|
|
763
817
|
return true; // todo whargarbl
|
|
764
818
|
}
|
|
765
819
|
*/
|
|
820
|
+
// NEEDS_DOCS
|
|
821
|
+
/*********
|
|
822
|
+
*
|
|
823
|
+
* Get the current value of a given property name.
|
|
824
|
+
*
|
|
825
|
+
* ```typescript
|
|
826
|
+
*
|
|
827
|
+
* ```
|
|
828
|
+
*
|
|
829
|
+
* @param name The relevant property name to look up
|
|
830
|
+
*
|
|
831
|
+
* @returns The value behind the prop name. Because functional props are
|
|
832
|
+
* evaluated as getters, this can be anything.
|
|
833
|
+
*
|
|
834
|
+
*/
|
|
835
|
+
prop(name) {
|
|
836
|
+
const bound_name = name_bind_prop_and_state(name, this.state());
|
|
837
|
+
if (this._state_properties.has(bound_name)) {
|
|
838
|
+
return this._state_properties.get(bound_name);
|
|
839
|
+
}
|
|
840
|
+
else if (this._default_properties.has(name)) {
|
|
841
|
+
return this._default_properties.get(name);
|
|
842
|
+
}
|
|
843
|
+
else {
|
|
844
|
+
return undefined;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
// NEEDS_DOCS
|
|
848
|
+
/*********
|
|
849
|
+
*
|
|
850
|
+
* Get the current value of a given property name. If missing on the state
|
|
851
|
+
* and without a global default, throw, unlike {@link prop}, which would
|
|
852
|
+
* return `undefined` instead.
|
|
853
|
+
*
|
|
854
|
+
* ```typescript
|
|
855
|
+
*
|
|
856
|
+
* ```
|
|
857
|
+
*
|
|
858
|
+
* @param name The relevant property name to look up
|
|
859
|
+
*
|
|
860
|
+
* @returns The value behind the prop name. Because functional props are
|
|
861
|
+
* evaluated as getters, this can be anything.
|
|
862
|
+
*
|
|
863
|
+
*/
|
|
864
|
+
strict_prop(name) {
|
|
865
|
+
const bound_name = name_bind_prop_and_state(name, this.state());
|
|
866
|
+
if (this._state_properties.has(bound_name)) {
|
|
867
|
+
return this._state_properties.get(bound_name);
|
|
868
|
+
}
|
|
869
|
+
else if (this._default_properties.has(name)) {
|
|
870
|
+
return this._default_properties.get(name);
|
|
871
|
+
}
|
|
872
|
+
else {
|
|
873
|
+
throw new JssmError(this, `Strictly requested a prop '${name}' which doesn't exist on current state '${this.state()}' and has no default`);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
// NEEDS_DOCS
|
|
877
|
+
// COMEBACK add prop_map, sparse_props and strict_props to doc text when implemented
|
|
878
|
+
/*********
|
|
879
|
+
*
|
|
880
|
+
* Get the current value of every prop, as an object. If no current definition
|
|
881
|
+
* exists for a prop - that is, if the prop was defined without a default and
|
|
882
|
+
* the current state also doesn't define the prop - then that prop will be listed
|
|
883
|
+
* in the returned object with a value of `undefined`.
|
|
884
|
+
*
|
|
885
|
+
* ```typescript
|
|
886
|
+
* const traffic_light = sm`
|
|
887
|
+
*
|
|
888
|
+
* property can_go default true;
|
|
889
|
+
* property hesitate default true;
|
|
890
|
+
* property stop_first default false;
|
|
891
|
+
*
|
|
892
|
+
* Off -> Red => Green => Yellow => Red;
|
|
893
|
+
* [Red Yellow Green] ~> [Off FlashingRed];
|
|
894
|
+
* FlashingRed -> Red;
|
|
895
|
+
*
|
|
896
|
+
* state Red: { property stop_first true; property can_go false; };
|
|
897
|
+
* state Off: { property stop_first true; };
|
|
898
|
+
* state FlashingRed: { property stop_first true; };
|
|
899
|
+
* state Green: { property hesitate false; };
|
|
900
|
+
*
|
|
901
|
+
* `;
|
|
902
|
+
*
|
|
903
|
+
* traffic_light.state(); // Off
|
|
904
|
+
* traffic_light.props(); // { can_go: true, hesitate: true, stop_first: true; }
|
|
905
|
+
*
|
|
906
|
+
* traffic_light.go('Red');
|
|
907
|
+
* traffic_light.props(); // { can_go: false, hesitate: true, stop_first: true; }
|
|
908
|
+
*
|
|
909
|
+
* traffic_light.go('Green');
|
|
910
|
+
* traffic_light.props(); // { can_go: true, hesitate: false, stop_first: false; }
|
|
911
|
+
* ```
|
|
912
|
+
*
|
|
913
|
+
*/
|
|
914
|
+
props() {
|
|
915
|
+
const ret = {};
|
|
916
|
+
this.known_props().forEach(p => ret[p] = this.prop(p));
|
|
917
|
+
return ret;
|
|
918
|
+
}
|
|
919
|
+
// NEEDS_DOCS
|
|
920
|
+
// TODO COMEBACK
|
|
921
|
+
/*********
|
|
922
|
+
*
|
|
923
|
+
* Get the current value of every prop, as an object. Compare
|
|
924
|
+
* {@link prop_map}, which returns a `Map`.
|
|
925
|
+
*
|
|
926
|
+
* ```typescript
|
|
927
|
+
*
|
|
928
|
+
* ```
|
|
929
|
+
*
|
|
930
|
+
*/
|
|
931
|
+
// sparse_props(name: string): object {
|
|
932
|
+
// }
|
|
933
|
+
// NEEDS_DOCS
|
|
934
|
+
// TODO COMEBACK
|
|
935
|
+
/*********
|
|
936
|
+
*
|
|
937
|
+
* Get the current value of every prop, as an object. Compare
|
|
938
|
+
* {@link prop_map}, which returns a `Map`. Akin to {@link strict_prop},
|
|
939
|
+
* this throws if a required prop is missing.
|
|
940
|
+
*
|
|
941
|
+
* ```typescript
|
|
942
|
+
*
|
|
943
|
+
* ```
|
|
944
|
+
*
|
|
945
|
+
*/
|
|
946
|
+
// strict_props(name: string): object {
|
|
947
|
+
// }
|
|
948
|
+
/*********
|
|
949
|
+
*
|
|
950
|
+
* Check whether a given string is a known property's name.
|
|
951
|
+
*
|
|
952
|
+
* ```typescript
|
|
953
|
+
* const example = sm`property foo default 1; a->b;`;
|
|
954
|
+
*
|
|
955
|
+
* example.known_prop('foo'); // true
|
|
956
|
+
* example.known_prop('bar'); // false
|
|
957
|
+
* ```
|
|
958
|
+
*
|
|
959
|
+
* @param prop_name The relevant property name to look up
|
|
960
|
+
*
|
|
961
|
+
*/
|
|
962
|
+
known_prop(prop_name) {
|
|
963
|
+
return this._property_keys.has(prop_name);
|
|
964
|
+
}
|
|
965
|
+
// NEEDS_DOCS
|
|
966
|
+
/*********
|
|
967
|
+
*
|
|
968
|
+
* List all known property names. If you'd also like values, use
|
|
969
|
+
* {@link props} instead. The order of the properties is not defined, and
|
|
970
|
+
* the properties generally will not be sorted.
|
|
971
|
+
*
|
|
972
|
+
* ```typescript
|
|
973
|
+
* ```
|
|
974
|
+
*
|
|
975
|
+
*/
|
|
976
|
+
known_props() {
|
|
977
|
+
return [...this._property_keys];
|
|
978
|
+
}
|
|
766
979
|
/********
|
|
767
980
|
*
|
|
768
981
|
* Check whether a given state is final (either has no exits or is marked
|
|
@@ -800,13 +1013,32 @@ class Machine {
|
|
|
800
1013
|
* console.log( final_test.is_final() ); // true
|
|
801
1014
|
* ```
|
|
802
1015
|
*
|
|
803
|
-
* @typeparam mDT The type of the machine data member; usually omitted
|
|
804
|
-
*
|
|
805
1016
|
*/
|
|
806
1017
|
is_final() {
|
|
807
1018
|
// return ((!this.is_changing()) && this.state_is_final(this.state()));
|
|
808
1019
|
return this.state_is_final(this.state());
|
|
809
1020
|
}
|
|
1021
|
+
/********
|
|
1022
|
+
*
|
|
1023
|
+
* Serialize the current machine, including all defining state but not the
|
|
1024
|
+
* machine string, to a structure. This means you will need the machine
|
|
1025
|
+
* string to recreate (to not waste repeated space;) if you want the machine
|
|
1026
|
+
* string embedded, call {@link serialize_with_string} instead.
|
|
1027
|
+
*
|
|
1028
|
+
* @typeparam mDT The type of the machine data member; usually omitted
|
|
1029
|
+
*
|
|
1030
|
+
*/
|
|
1031
|
+
serialize(comment) {
|
|
1032
|
+
return {
|
|
1033
|
+
comment,
|
|
1034
|
+
state: this._state,
|
|
1035
|
+
data: this._data,
|
|
1036
|
+
jssm_version: version,
|
|
1037
|
+
history: this._history.toArray(),
|
|
1038
|
+
history_capacity: this._history.capacity,
|
|
1039
|
+
timestamp: new Date().getTime(),
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
810
1042
|
graph_layout() {
|
|
811
1043
|
return this._graph_layout;
|
|
812
1044
|
}
|
|
@@ -862,11 +1094,6 @@ class Machine {
|
|
|
862
1094
|
states: this._states
|
|
863
1095
|
};
|
|
864
1096
|
}
|
|
865
|
-
/*
|
|
866
|
-
load_machine_state(): boolean {
|
|
867
|
-
return false; // todo whargarbl
|
|
868
|
-
}
|
|
869
|
-
*/
|
|
870
1097
|
/*********
|
|
871
1098
|
*
|
|
872
1099
|
* List all the states known by the machine. Please note that the order of
|
|
@@ -1749,15 +1976,27 @@ class Machine {
|
|
|
1749
1976
|
* Instruct the machine to complete an action. Synonym for {@link action}.
|
|
1750
1977
|
*
|
|
1751
1978
|
* ```typescript
|
|
1752
|
-
* const light = sm`
|
|
1979
|
+
* const light = sm`
|
|
1980
|
+
* off 'start' -> red;
|
|
1981
|
+
* red 'next' -> green 'next' -> yellow 'next' -> red;
|
|
1982
|
+
* [red yellow green] 'shutdown' ~> off;
|
|
1983
|
+
* `;
|
|
1753
1984
|
*
|
|
1754
|
-
* light.state();
|
|
1755
|
-
* light.do('
|
|
1756
|
-
* light.state();
|
|
1985
|
+
* light.state(); // 'off'
|
|
1986
|
+
* light.do('start'); // true
|
|
1987
|
+
* light.state(); // 'red'
|
|
1988
|
+
* light.do('next'); // true
|
|
1989
|
+
* light.state(); // 'green'
|
|
1990
|
+
* light.do('next'); // true
|
|
1991
|
+
* light.state(); // 'yellow'
|
|
1992
|
+
* light.do('dance'); // !! false - no such action
|
|
1993
|
+
* light.state(); // 'yellow'
|
|
1994
|
+
* light.do('start'); // !! false - yellow does not have the action start
|
|
1995
|
+
* light.state(); // 'yellow'
|
|
1757
1996
|
* ```
|
|
1758
1997
|
*
|
|
1759
1998
|
* @typeparam mDT The type of the machine data member; usually omitted
|
|
1760
|
-
|
|
1999
|
+
b *
|
|
1761
2000
|
* @param actionName The action to engage
|
|
1762
2001
|
*
|
|
1763
2002
|
* @param newData The data change to insert during the action
|
|
@@ -1771,11 +2010,21 @@ class Machine {
|
|
|
1771
2010
|
* Instruct the machine to complete a transition. Synonym for {@link go}.
|
|
1772
2011
|
*
|
|
1773
2012
|
* ```typescript
|
|
1774
|
-
* const light = sm`
|
|
2013
|
+
* const light = sm`
|
|
2014
|
+
* off 'start' -> red;
|
|
2015
|
+
* red 'next' -> green 'next' -> yellow 'next' -> red;
|
|
2016
|
+
* [red yellow green] 'shutdown' ~> off;
|
|
2017
|
+
* `;
|
|
1775
2018
|
*
|
|
1776
|
-
* light.state();
|
|
1777
|
-
* light.
|
|
1778
|
-
* light.state();
|
|
2019
|
+
* light.state(); // 'off'
|
|
2020
|
+
* light.go('red'); // true
|
|
2021
|
+
* light.state(); // 'red'
|
|
2022
|
+
* light.go('green'); // true
|
|
2023
|
+
* light.state(); // 'green'
|
|
2024
|
+
* light.go('blue'); // !! false - no such state
|
|
2025
|
+
* light.state(); // 'green'
|
|
2026
|
+
* light.go('red'); // !! false - green may not go directly to red, only to yellow
|
|
2027
|
+
* light.state(); // 'green'
|
|
1779
2028
|
* ```
|
|
1780
2029
|
*
|
|
1781
2030
|
* @typeparam mDT The type of the machine data member; usually omitted
|
|
@@ -1988,6 +2237,12 @@ function abstract_hook_step(maybe_hook, hook_args) {
|
|
|
1988
2237
|
return { pass: true };
|
|
1989
2238
|
}
|
|
1990
2239
|
}
|
|
1991
|
-
|
|
2240
|
+
function deserialize(machine_string, ser) {
|
|
2241
|
+
const machine = from(machine_string, { data: ser.data, history: ser.history_capacity });
|
|
2242
|
+
machine._state = ser.state;
|
|
2243
|
+
ser.history.forEach(history_item => machine._history.push(history_item));
|
|
2244
|
+
return machine;
|
|
2245
|
+
}
|
|
2246
|
+
export { version, transfer_state_properties, Machine, deserialize, make, wrap_parse as parse, compile, sm, from, arrow_direction, arrow_left_kind, arrow_right_kind,
|
|
1992
2247
|
// WHARGARBL TODO these should be exported to a utility library
|
|
1993
|
-
seq, weighted_rand_select, histograph, weighted_sample_select, weighted_histo_key, shapes, gviz_shapes, named_colors, is_hook_rejection, is_hook_complex_result, abstract_hook_step };
|
|
2248
|
+
seq, unique, find_repeated, weighted_rand_select, histograph, weighted_sample_select, weighted_histo_key, shapes, gviz_shapes, named_colors, is_hook_rejection, is_hook_complex_result, abstract_hook_step };
|