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.
- package/CHANGELOG.md +38 -45
- package/README.md +2 -2
- package/dist/es6/jssm-dot.js +1 -1
- package/dist/es6/jssm.d.ts +154 -12
- package/dist/es6/jssm.js +280 -19
- package/dist/es6/jssm_types.d.ts +18 -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 +154 -12
- package/jssm_types.d.ts +18 -3
- package/jssm_util.d.ts +44 -1
- package/package.json +1 -1
package/dist/es6/jssm.d.ts
CHANGED
|
@@ -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`
|
|
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();
|
|
702
|
-
* light.do('
|
|
703
|
-
* light.state();
|
|
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`
|
|
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();
|
|
722
|
-
* light.
|
|
723
|
-
* light.state();
|
|
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',
|
|
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`
|
|
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();
|
|
1774
|
-
* light.do('
|
|
1775
|
-
* light.state();
|
|
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`
|
|
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();
|
|
1796
|
-
* light.
|
|
1797
|
-
* light.state();
|
|
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 };
|
package/dist/es6/jssm_types.d.ts
CHANGED
|
@@ -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> =
|
|
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?:
|
|
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 };
|