jssm 5.78.0 → 5.79.2

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.
@@ -1,7 +1,7 @@
1
1
  declare type StateType = string;
2
2
  import { JssmGenericState, JssmGenericConfig, JssmTransition, JssmTransitionList, // JssmTransitionRule,
3
3
  JssmMachineInternalState, JssmParseTree, JssmStateDeclaration, JssmArrow, JssmArrowDirection, JssmArrowKind, JssmLayout, JssmHistory, JssmSerialization, FslDirection, FslTheme, HookDescription, HookHandler, HookContext, HookResult, HookComplexResult } from './jssm_types';
4
- import { seq, weighted_rand_select, weighted_sample_select, histograph, weighted_histo_key } from './jssm_util';
4
+ import { seq, unique, find_repeated, weighted_rand_select, weighted_sample_select, histograph, weighted_histo_key } from './jssm_util';
5
5
  import { shapes, gviz_shapes, named_colors } from './jssm_constants';
6
6
  import { version } from './version';
7
7
  /*********
@@ -250,9 +250,13 @@ declare class Machine<mDT> {
250
250
  _post_main_transition_hook: HookHandler<mDT> | undefined;
251
251
  _post_forced_transition_hook: HookHandler<mDT> | undefined;
252
252
  _post_any_transition_hook: HookHandler<mDT> | undefined;
253
+ _property_keys: Set<string>;
254
+ _default_properties: Map<string, any>;
255
+ _state_properties: Map<string, any>;
256
+ _required_properties: Set<string>;
253
257
  _history: JssmHistory<mDT>;
254
258
  _history_length: number;
255
- 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>);
259
+ 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>);
256
260
  /********
257
261
  *
258
262
  * Internal method for fabricating states. Not meant for external use.
@@ -294,6 +298,122 @@ declare class Machine<mDT> {
294
298
  *
295
299
  */
296
300
  data(): mDT;
301
+ /*********
302
+ *
303
+ * Get the current value of a given property name.
304
+ *
305
+ * ```typescript
306
+ *
307
+ * ```
308
+ *
309
+ * @param name The relevant property name to look up
310
+ *
311
+ * @returns The value behind the prop name. Because functional props are
312
+ * evaluated as getters, this can be anything.
313
+ *
314
+ */
315
+ prop(name: string): any;
316
+ /*********
317
+ *
318
+ * Get the current value of a given property name. If missing on the state
319
+ * and without a global default, throw, unlike {@link prop}, which would
320
+ * return `undefined` instead.
321
+ *
322
+ * ```typescript
323
+ *
324
+ * ```
325
+ *
326
+ * @param name The relevant property name to look up
327
+ *
328
+ * @returns The value behind the prop name. Because functional props are
329
+ * evaluated as getters, this can be anything.
330
+ *
331
+ */
332
+ strict_prop(name: string): any;
333
+ /*********
334
+ *
335
+ * Get the current value of every prop, as an object. If no current definition
336
+ * exists for a prop - that is, if the prop was defined without a default and
337
+ * the current state also doesn't define the prop - then that prop will be listed
338
+ * in the returned object with a value of `undefined`.
339
+ *
340
+ * ```typescript
341
+ * const traffic_light = sm`
342
+ *
343
+ * property can_go default true;
344
+ * property hesitate default true;
345
+ * property stop_first default false;
346
+ *
347
+ * Off -> Red => Green => Yellow => Red;
348
+ * [Red Yellow Green] ~> [Off FlashingRed];
349
+ * FlashingRed -> Red;
350
+ *
351
+ * state Red: { property stop_first true; property can_go false; };
352
+ * state Off: { property stop_first true; };
353
+ * state FlashingRed: { property stop_first true; };
354
+ * state Green: { property hesitate false; };
355
+ *
356
+ * `;
357
+ *
358
+ * traffic_light.state(); // Off
359
+ * traffic_light.props(); // { can_go: true, hesitate: true, stop_first: true; }
360
+ *
361
+ * traffic_light.go('Red');
362
+ * traffic_light.props(); // { can_go: false, hesitate: true, stop_first: true; }
363
+ *
364
+ * traffic_light.go('Green');
365
+ * traffic_light.props(); // { can_go: true, hesitate: false, stop_first: false; }
366
+ * ```
367
+ *
368
+ */
369
+ props(): object;
370
+ /*********
371
+ *
372
+ * Get the current value of every prop, as an object. Compare
373
+ * {@link prop_map}, which returns a `Map`.
374
+ *
375
+ * ```typescript
376
+ *
377
+ * ```
378
+ *
379
+ */
380
+ /*********
381
+ *
382
+ * Get the current value of every prop, as an object. Compare
383
+ * {@link prop_map}, which returns a `Map`. Akin to {@link strict_prop},
384
+ * this throws if a required prop is missing.
385
+ *
386
+ * ```typescript
387
+ *
388
+ * ```
389
+ *
390
+ */
391
+ /*********
392
+ *
393
+ * Check whether a given string is a known property's name.
394
+ *
395
+ * ```typescript
396
+ * const example = sm`property foo default 1; a->b;`;
397
+ *
398
+ * example.known_prop('foo'); // true
399
+ * example.known_prop('bar'); // false
400
+ * ```
401
+ *
402
+ * @param prop_name The relevant property name to look up
403
+ *
404
+ */
405
+ known_prop(prop_name: string): boolean;
406
+ /*********
407
+ *
408
+ * List all known property names. If you'd also like values, use
409
+ * {@link props} instead. The order of the properties is not defined, and
410
+ * the properties generally will not be sorted.
411
+ *
412
+ * ```typescript
413
+ * ```
414
+ *
415
+ */
416
+ known_props(): string[];
297
417
  /********
298
418
  *
299
419
  * Check whether a given state is final (either has no exits or is marked
@@ -696,15 +816,27 @@ declare class Machine<mDT> {
696
816
  * Instruct the machine to complete an action. Synonym for {@link action}.
697
817
  *
698
818
  * ```typescript
699
- * const light = sm`red 'next' -> green 'next' -> yellow 'next' -> red; [red yellow green] 'shutdown' ~> off 'start' -> red;`;
819
+ * const light = sm`
820
+ * off 'start' -> red;
821
+ * red 'next' -> green 'next' -> yellow 'next' -> red;
822
+ * [red yellow green] 'shutdown' ~> off;
823
+ * `;
700
824
  *
701
- * light.state(); // 'red'
702
- * light.do('next'); // true
703
- * light.state(); // 'green'
825
+ * light.state(); // 'off'
826
+ * light.do('start'); // true
827
+ * light.state(); // 'red'
828
+ * light.do('next'); // true
829
+ * light.state(); // 'green'
830
+ * light.do('next'); // true
831
+ * light.state(); // 'yellow'
832
+ * light.do('dance'); // !! false - no such action
833
+ * light.state(); // 'yellow'
834
+ * light.do('start'); // !! false - yellow does not have the action start
835
+ * light.state(); // 'yellow'
704
836
  * ```
705
837
  *
706
838
  * @typeparam mDT The type of the machine data member; usually omitted
707
- *
839
+ b *
708
840
  * @param actionName The action to engage
709
841
  *
710
842
  * @param newData The data change to insert during the action
@@ -716,11 +848,21 @@ declare class Machine<mDT> {
716
848
  * Instruct the machine to complete a transition. Synonym for {@link go}.
717
849
  *
718
850
  * ```typescript
719
- * const light = sm`red -> green -> yellow -> red; [red yellow green] 'shutdown' ~> off 'start' -> red;`;
851
+ * const light = sm`
852
+ * off 'start' -> red;
853
+ * red 'next' -> green 'next' -> yellow 'next' -> red;
854
+ * [red yellow green] 'shutdown' ~> off;
855
+ * `;
720
856
  *
721
- * light.state(); // 'red'
722
- * light.transition('green'); // true
723
- * light.state(); // 'green'
857
+ * light.state(); // 'off'
858
+ * light.go('red'); // true
859
+ * light.state(); // 'red'
860
+ * light.go('green'); // true
861
+ * light.state(); // 'green'
862
+ * light.go('blue'); // !! false - no such state
863
+ * light.state(); // 'green'
864
+ * light.go('red'); // !! false - green may not go directly to red, only to yellow
865
+ * light.state(); // 'green'
724
866
  * ```
725
867
  *
726
868
  * @typeparam mDT The type of the machine data member; usually omitted
@@ -833,4 +975,4 @@ declare function is_hook_complex_result<mDT>(hr: unknown): hr is HookComplexResu
833
975
  declare function is_hook_rejection<mDT>(hr: HookResult<mDT>): boolean;
834
976
  declare function abstract_hook_step<mDT>(maybe_hook: HookHandler<mDT> | undefined, hook_args: HookContext<mDT>): HookComplexResult<mDT>;
835
977
  declare function deserialize<mDT>(machine_string: string, ser: JssmSerialization<mDT>): Machine<mDT>;
836
- export { version, transfer_state_properties, Machine, deserialize, make, wrap_parse as parse, compile, sm, from, arrow_direction, arrow_left_kind, arrow_right_kind, 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 };
978
+ 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,18 @@ 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
+ const ret = { agg_as: 'property_definition', val: { name: rule.name } };
357
+ if (rule.hasOwnProperty('default_value')) {
358
+ ret.val.default_value = rule.default_value;
359
+ }
360
+ if (rule.hasOwnProperty('required')) {
361
+ ret.val.required = rule.required;
362
+ }
363
+ return ret;
364
+ }
365
+ // state properties are in here
354
366
  if (rule.key === 'state_declaration') {
355
367
  if (!rule.name) {
356
368
  throw new JssmError(undefined, 'State declarations must have a name');
@@ -361,6 +373,7 @@ function compile_rule_handler(rule) {
361
373
  'arrange_end_declaration'].includes(rule.key)) {
362
374
  return { agg_as: rule.key, val: [rule.value] };
363
375
  }
376
+ // things that can only exist once and are just a value under their own name
364
377
  const tautologies = [
365
378
  'graph_layout', 'start_states', 'end_states', 'machine_name', 'machine_version',
366
379
  'machine_comment', 'machine_author', 'machine_contributor', 'machine_definition',
@@ -440,6 +453,8 @@ function compile(tree) {
440
453
  machine_license: [],
441
454
  machine_name: [],
442
455
  machine_reference: [],
456
+ property_definition: [],
457
+ state_property: {},
443
458
  theme: [],
444
459
  flow: [],
445
460
  dot_preamble: [],
@@ -452,10 +467,15 @@ function compile(tree) {
452
467
  const rule = compile_rule_handler(tr), agg_as = rule.agg_as, val = rule.val; // TODO FIXME no any
453
468
  results[agg_as] = results[agg_as].concat(val);
454
469
  });
470
+ const property_keys = results['property_definition'].map(pd => pd.name), repeat_props = find_repeated(property_keys);
471
+ if (repeat_props.length) {
472
+ throw new JssmError(undefined, `Cannot repeat property definitions. Saw ${JSON.stringify(repeat_props)}`);
473
+ }
455
474
  const assembled_transitions = [].concat(...results['transition']);
456
475
  const result_cfg = {
457
476
  start_states: results.start_states.length ? results.start_states : [assembled_transitions[0].from],
458
- transitions: assembled_transitions
477
+ transitions: assembled_transitions,
478
+ state_property: []
459
479
  };
460
480
  const oneOnlyKeys = [
461
481
  'graph_layout', 'machine_name', 'machine_version', 'machine_comment',
@@ -473,11 +493,27 @@ function compile(tree) {
473
493
  }
474
494
  });
475
495
  ['arrange_declaration', 'arrange_start_declaration', 'arrange_end_declaration',
476
- 'machine_author', 'machine_contributor', 'machine_reference', 'state_declaration'].map((multiKey) => {
496
+ 'machine_author', 'machine_contributor', 'machine_reference',
497
+ 'state_declaration', 'property_definition'].map((multiKey) => {
477
498
  if (results[multiKey].length) {
478
499
  result_cfg[multiKey] = results[multiKey];
479
500
  }
480
501
  });
502
+ // re-walk state declarations, already wrapped up, to get state properties,
503
+ // which go out in a different datastructure
504
+ results.state_declaration.forEach(sd => {
505
+ sd.declarations.forEach(decl => {
506
+ if (decl.key === 'state_property') {
507
+ const label = name_bind_prop_and_state(decl.name, sd.state);
508
+ if (result_cfg.state_property.findIndex(c => c.name === label) !== -1) {
509
+ throw new JssmError(undefined, `A state may only bind a property once (${sd.state} re-binds ${decl.name})`);
510
+ }
511
+ else {
512
+ result_cfg.state_property.push({ name: label, default_value: decl.value });
513
+ }
514
+ }
515
+ });
516
+ });
481
517
  return result_cfg;
482
518
  }
483
519
  /*********
@@ -527,6 +563,9 @@ function transfer_state_properties(state_decl) {
527
563
  case 'border-color':
528
564
  state_decl.borderColor = d.value;
529
565
  break;
566
+ case 'state_property':
567
+ state_decl.property = { name: d.name, value: d.value };
568
+ break;
530
569
  default: throw new JssmError(undefined, `Unknown state property: '${JSON.stringify(d)}'`);
531
570
  }
532
571
  });
@@ -535,7 +574,7 @@ function transfer_state_properties(state_decl) {
535
574
  // TODO add a lotta docblock here
536
575
  class Machine {
537
576
  // 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 }) {
577
+ 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
578
  this._instance_name = instance_name;
540
579
  this._state = start_states[0];
541
580
  this._states = new Map();
@@ -600,6 +639,10 @@ class Machine {
600
639
  this._post_forced_transition_hook = undefined;
601
640
  this._post_any_transition_hook = undefined;
602
641
  this._data = data;
642
+ this._property_keys = new Set();
643
+ this._default_properties = new Map();
644
+ this._state_properties = new Map();
645
+ this._required_properties = new Set();
603
646
  this._history_length = history || 0;
604
647
  this._history = new circular_buffer(this._history_length);
605
648
  if (state_declaration) {
@@ -697,6 +740,48 @@ class Machine {
697
740
  */
698
741
  }
699
742
  });
743
+ if (Array.isArray(property_definition)) {
744
+ property_definition.forEach(pr => {
745
+ this._property_keys.add(pr.name);
746
+ if (pr.hasOwnProperty('default_value')) {
747
+ this._default_properties.set(pr.name, pr.default_value);
748
+ }
749
+ if (pr.hasOwnProperty('required') && (pr.required === true)) {
750
+ this._required_properties.add(pr.name);
751
+ }
752
+ });
753
+ }
754
+ if (Array.isArray(state_property)) {
755
+ state_property.forEach(sp => {
756
+ this._state_properties.set(sp.name, sp.default_value);
757
+ });
758
+ }
759
+ // done building, do checks
760
+ this._state_properties.forEach((_value, key) => {
761
+ const inside = JSON.parse(key);
762
+ if (Array.isArray(inside)) {
763
+ const j_property = inside[0];
764
+ if (typeof j_property === 'string') {
765
+ const j_state = inside[1];
766
+ if (typeof j_state === 'string') {
767
+ if (!(this.known_prop(j_property))) {
768
+ throw new JssmError(this, `State "${j_state}" has property "${j_property}" which is not globally declared`);
769
+ }
770
+ }
771
+ }
772
+ }
773
+ });
774
+ this._required_properties.forEach(dp_key => {
775
+ if (this._default_properties.has(dp_key)) {
776
+ throw new JssmError(this, `The property "${dp_key}" is required, but also has a default; these conflict`);
777
+ }
778
+ this.states().forEach(s => {
779
+ const bound_name = name_bind_prop_and_state(dp_key, s);
780
+ if (!(this._state_properties.has(bound_name))) {
781
+ throw new JssmError(this, `State "${s}" is missing required property "${dp_key}"`);
782
+ }
783
+ });
784
+ });
700
785
  }
701
786
  /********
702
787
  *
@@ -763,6 +848,165 @@ class Machine {
763
848
  return true; // todo whargarbl
764
849
  }
765
850
  */
851
+ // NEEDS_DOCS
852
+ /*********
853
+ *
854
+ * Get the current value of a given property name.
855
+ *
856
+ * ```typescript
857
+ *
858
+ * ```
859
+ *
860
+ * @param name The relevant property name to look up
861
+ *
862
+ * @returns The value behind the prop name. Because functional props are
863
+ * evaluated as getters, this can be anything.
864
+ *
865
+ */
866
+ prop(name) {
867
+ const bound_name = name_bind_prop_and_state(name, this.state());
868
+ if (this._state_properties.has(bound_name)) {
869
+ return this._state_properties.get(bound_name);
870
+ }
871
+ else if (this._default_properties.has(name)) {
872
+ return this._default_properties.get(name);
873
+ }
874
+ else {
875
+ return undefined;
876
+ }
877
+ }
878
+ // NEEDS_DOCS
879
+ /*********
880
+ *
881
+ * Get the current value of a given property name. If missing on the state
882
+ * and without a global default, throw, unlike {@link prop}, which would
883
+ * return `undefined` instead.
884
+ *
885
+ * ```typescript
886
+ *
887
+ * ```
888
+ *
889
+ * @param name The relevant property name to look up
890
+ *
891
+ * @returns The value behind the prop name. Because functional props are
892
+ * evaluated as getters, this can be anything.
893
+ *
894
+ */
895
+ strict_prop(name) {
896
+ const bound_name = name_bind_prop_and_state(name, this.state());
897
+ if (this._state_properties.has(bound_name)) {
898
+ return this._state_properties.get(bound_name);
899
+ }
900
+ else if (this._default_properties.has(name)) {
901
+ return this._default_properties.get(name);
902
+ }
903
+ else {
904
+ throw new JssmError(this, `Strictly requested a prop '${name}' which doesn't exist on current state '${this.state()}' and has no default`);
905
+ }
906
+ }
907
+ // NEEDS_DOCS
908
+ // COMEBACK add prop_map, sparse_props and strict_props to doc text when implemented
909
+ /*********
910
+ *
911
+ * Get the current value of every prop, as an object. If no current definition
912
+ * exists for a prop - that is, if the prop was defined without a default and
913
+ * the current state also doesn't define the prop - then that prop will be listed
914
+ * in the returned object with a value of `undefined`.
915
+ *
916
+ * ```typescript
917
+ * const traffic_light = sm`
918
+ *
919
+ * property can_go default true;
920
+ * property hesitate default true;
921
+ * property stop_first default false;
922
+ *
923
+ * Off -> Red => Green => Yellow => Red;
924
+ * [Red Yellow Green] ~> [Off FlashingRed];
925
+ * FlashingRed -> Red;
926
+ *
927
+ * state Red: { property stop_first true; property can_go false; };
928
+ * state Off: { property stop_first true; };
929
+ * state FlashingRed: { property stop_first true; };
930
+ * state Green: { property hesitate false; };
931
+ *
932
+ * `;
933
+ *
934
+ * traffic_light.state(); // Off
935
+ * traffic_light.props(); // { can_go: true, hesitate: true, stop_first: true; }
936
+ *
937
+ * traffic_light.go('Red');
938
+ * traffic_light.props(); // { can_go: false, hesitate: true, stop_first: true; }
939
+ *
940
+ * traffic_light.go('Green');
941
+ * traffic_light.props(); // { can_go: true, hesitate: false, stop_first: false; }
942
+ * ```
943
+ *
944
+ */
945
+ props() {
946
+ const ret = {};
947
+ this.known_props().forEach(p => ret[p] = this.prop(p));
948
+ return ret;
949
+ }
950
+ // NEEDS_DOCS
951
+ // TODO COMEBACK
952
+ /*********
953
+ *
954
+ * Get the current value of every prop, as an object. Compare
955
+ * {@link prop_map}, which returns a `Map`.
956
+ *
957
+ * ```typescript
958
+ *
959
+ * ```
960
+ *
961
+ */
962
+ // sparse_props(name: string): object {
963
+ // }
964
+ // NEEDS_DOCS
965
+ // TODO COMEBACK
966
+ /*********
967
+ *
968
+ * Get the current value of every prop, as an object. Compare
969
+ * {@link prop_map}, which returns a `Map`. Akin to {@link strict_prop},
970
+ * this throws if a required prop is missing.
971
+ *
972
+ * ```typescript
973
+ *
974
+ * ```
975
+ *
976
+ */
977
+ // strict_props(name: string): object {
978
+ // }
979
+ /*********
980
+ *
981
+ * Check whether a given string is a known property's name.
982
+ *
983
+ * ```typescript
984
+ * const example = sm`property foo default 1; a->b;`;
985
+ *
986
+ * example.known_prop('foo'); // true
987
+ * example.known_prop('bar'); // false
988
+ * ```
989
+ *
990
+ * @param prop_name The relevant property name to look up
991
+ *
992
+ */
993
+ known_prop(prop_name) {
994
+ return this._property_keys.has(prop_name);
995
+ }
996
+ // NEEDS_DOCS
997
+ /*********
998
+ *
999
+ * List all known property names. If you'd also like values, use
1000
+ * {@link props} instead. The order of the properties is not defined, and
1001
+ * the properties generally will not be sorted.
1002
+ *
1003
+ * ```typescript
1004
+ * ```
1005
+ *
1006
+ */
1007
+ known_props() {
1008
+ return [...this._property_keys];
1009
+ }
766
1010
  /********
767
1011
  *
768
1012
  * Check whether a given state is final (either has no exits or is marked
@@ -881,11 +1125,6 @@ class Machine {
881
1125
  states: this._states
882
1126
  };
883
1127
  }
884
- /*
885
- load_machine_state(): boolean {
886
- return false; // todo whargarbl
887
- }
888
- */
889
1128
  /*********
890
1129
  *
891
1130
  * List all the states known by the machine. Please note that the order of
@@ -1768,15 +2007,27 @@ class Machine {
1768
2007
  * Instruct the machine to complete an action. Synonym for {@link action}.
1769
2008
  *
1770
2009
  * ```typescript
1771
- * const light = sm`red 'next' -> green 'next' -> yellow 'next' -> red; [red yellow green] 'shutdown' ~> off 'start' -> red;`;
2010
+ * const light = sm`
2011
+ * off 'start' -> red;
2012
+ * red 'next' -> green 'next' -> yellow 'next' -> red;
2013
+ * [red yellow green] 'shutdown' ~> off;
2014
+ * `;
1772
2015
  *
1773
- * light.state(); // 'red'
1774
- * light.do('next'); // true
1775
- * light.state(); // 'green'
2016
+ * light.state(); // 'off'
2017
+ * light.do('start'); // true
2018
+ * light.state(); // 'red'
2019
+ * light.do('next'); // true
2020
+ * light.state(); // 'green'
2021
+ * light.do('next'); // true
2022
+ * light.state(); // 'yellow'
2023
+ * light.do('dance'); // !! false - no such action
2024
+ * light.state(); // 'yellow'
2025
+ * light.do('start'); // !! false - yellow does not have the action start
2026
+ * light.state(); // 'yellow'
1776
2027
  * ```
1777
2028
  *
1778
2029
  * @typeparam mDT The type of the machine data member; usually omitted
1779
- *
2030
+ b *
1780
2031
  * @param actionName The action to engage
1781
2032
  *
1782
2033
  * @param newData The data change to insert during the action
@@ -1790,11 +2041,21 @@ class Machine {
1790
2041
  * Instruct the machine to complete a transition. Synonym for {@link go}.
1791
2042
  *
1792
2043
  * ```typescript
1793
- * const light = sm`red -> green -> yellow -> red; [red yellow green] 'shutdown' ~> off 'start' -> red;`;
2044
+ * const light = sm`
2045
+ * off 'start' -> red;
2046
+ * red 'next' -> green 'next' -> yellow 'next' -> red;
2047
+ * [red yellow green] 'shutdown' ~> off;
2048
+ * `;
1794
2049
  *
1795
- * light.state(); // 'red'
1796
- * light.transition('green'); // true
1797
- * light.state(); // 'green'
2050
+ * light.state(); // 'off'
2051
+ * light.go('red'); // true
2052
+ * light.state(); // 'red'
2053
+ * light.go('green'); // true
2054
+ * light.state(); // 'green'
2055
+ * light.go('blue'); // !! false - no such state
2056
+ * light.state(); // 'green'
2057
+ * light.go('red'); // !! false - green may not go directly to red, only to yellow
2058
+ * light.state(); // 'green'
1798
2059
  * ```
1799
2060
  *
1800
2061
  * @typeparam mDT The type of the machine data member; usually omitted
@@ -2015,4 +2276,4 @@ function deserialize(machine_string, ser) {
2015
2276
  }
2016
2277
  export { version, transfer_state_properties, Machine, deserialize, make, wrap_parse as parse, compile, sm, from, arrow_direction, arrow_left_kind, arrow_right_kind,
2017
2278
  // WHARGARBL TODO these should be exported to a utility library
2018
- 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 };
2279
+ 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 };
@@ -35,6 +35,11 @@ declare type JssmSerialization<DataType> = {
35
35
  history_capacity: number;
36
36
  data: DataType;
37
37
  };
38
+ declare type JssmPropertyDefinition = {
39
+ name: string;
40
+ default_value?: any;
41
+ required?: boolean;
42
+ };
38
43
  declare type JssmTransitionPermitter<DataType> = (OldState: StateType, NewState: StateType, OldData: DataType, NewData: DataType) => boolean;
39
44
  declare type JssmTransitionPermitterMaybeArray<DataType> = JssmTransitionPermitter<DataType> | Array<JssmTransitionPermitter<DataType>>;
40
45
  declare type JssmTransition<DataType> = {
@@ -48,7 +53,7 @@ declare type JssmTransition<DataType> = {
48
53
  forced_only: boolean;
49
54
  main_path: boolean;
50
55
  };
51
- declare type JssmTransitions<DataType> = Array<JssmTransition<DataType>>;
56
+ declare type JssmTransitions<DataType> = JssmTransition<DataType>[];
52
57
  declare type JssmTransitionList = {
53
58
  entrances: Array<StateType>;
54
59
  exits: Array<StateType>;
@@ -93,6 +98,7 @@ declare type JssmGenericMachine<DataType> = {
93
98
  declare type JssmStateDeclarationRule = {
94
99
  key: string;
95
100
  value: any;
101
+ name?: string;
96
102
  };
97
103
  declare type JssmStateDeclaration = {
98
104
  declarations: Array<JssmStateDeclarationRule>;
@@ -104,6 +110,10 @@ declare type JssmStateDeclaration = {
104
110
  backgroundColor?: JssmColor;
105
111
  borderColor?: JssmColor;
106
112
  state: StateType;
113
+ property?: {
114
+ name: string;
115
+ value: unknown;
116
+ };
107
117
  };
108
118
  declare type JssmGenericConfig<DataType> = {
109
119
  graph_layout?: JssmLayout;
@@ -125,7 +135,9 @@ declare type JssmGenericConfig<DataType> = {
125
135
  dot_preamble?: string;
126
136
  start_states: Array<StateType>;
127
137
  end_states?: Array<StateType>;
128
- state_declaration?: Array<Object>;
138
+ state_declaration?: Object[];
139
+ property_definition?: JssmPropertyDefinition[];
140
+ state_property?: JssmPropertyDefinition[];
129
141
  arrange_declaration?: Array<Array<StateType>>;
130
142
  arrange_start_declaration?: Array<Array<StateType>>;
131
143
  arrange_end_declaration?: Array<Array<StateType>>;
@@ -160,6 +172,9 @@ declare type JssmCompileSeStart<DataType> = {
160
172
  key: string;
161
173
  value?: string | number;
162
174
  name?: string;
175
+ state?: string;
176
+ default_value?: any;
177
+ required?: boolean;
163
178
  };
164
179
  declare type JssmParseTree = Array<JssmCompileSeStart<StateType>>;
165
180
  declare type JssmParseFunctionType = (string: any) => JssmParseTree;
@@ -275,4 +290,4 @@ declare type JssmErrorExtendedInfo = {
275
290
  requested_state?: StateType | undefined;
276
291
  };
277
292
  declare type JssmHistory<mDT> = circular_buffer<[StateType, mDT]>;
278
- export { JssmColor, JssmShape, JssmTransition, JssmTransitions, JssmTransitionList, JssmTransitionRule, JssmArrow, JssmArrowKind, JssmArrowDirection, JssmGenericConfig, JssmGenericState, JssmGenericMachine, JssmParseTree, JssmCompileSe, JssmCompileSeStart, JssmCompileRule, JssmPermitted, JssmPermittedOpt, JssmResult, JssmStateDeclaration, JssmStateDeclarationRule, JssmLayout, JssmHistory, JssmSerialization, JssmParseFunctionType, JssmMachineInternalState, JssmErrorExtendedInfo, FslDirection, FslTheme, HookDescription, HookHandler, HookContext, HookResult, HookComplexResult };
293
+ export { JssmColor, JssmShape, JssmTransition, JssmTransitions, JssmTransitionList, JssmTransitionRule, JssmArrow, JssmArrowKind, JssmArrowDirection, JssmGenericConfig, JssmGenericState, JssmGenericMachine, JssmParseTree, JssmCompileSe, JssmCompileSeStart, JssmCompileRule, JssmPermitted, JssmPermittedOpt, JssmResult, JssmStateDeclaration, JssmStateDeclarationRule, JssmLayout, JssmHistory, JssmSerialization, JssmPropertyDefinition, JssmParseFunctionType, JssmMachineInternalState, JssmErrorExtendedInfo, FslDirection, FslTheme, HookDescription, HookHandler, HookContext, HookResult, HookComplexResult };