jssm 5.85.8 → 5.85.9

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
- 1055 merges; 167 releases; Changlogging the last 10 commits; Full changelog at [CHANGELOG.long.md](CHANGELOG.long.md)
5
+ 1056 merges; 167 releases; Changlogging the last 10 commits; Full changelog at [CHANGELOG.long.md](CHANGELOG.long.md)
6
6
 
7
7
 
8
8
 
@@ -18,6 +18,22 @@ Published tags:
18
18
 
19
19
 
20
20
 
21
+  
22
+
23
+  
24
+
25
+ ## [Untagged] - 9/12/2022 8:18:05 PM
26
+
27
+ Commit [013999a77ce43ceed5eb982754ffe480fdddf159](https://github.com/StoneCypher/jssm/commit/013999a77ce43ceed5eb982754ffe480fdddf159)
28
+
29
+ Author: `John Haugeland <stonecypher@gmail.com>`
30
+
31
+ * Pull arrows out into modules
32
+ * Fixes StoneCypher/fsl#1206
33
+
34
+
35
+
36
+
21
37
  &nbsp;
22
38
 
23
39
  &nbsp;
@@ -159,24 +175,4 @@ Commit [6475296d979dab3d227828b80319d60c4f6ab2f5](https://github.com/StoneCypher
159
175
 
160
176
  Author: `John Haugeland <stonecypher@gmail.com>`
161
177
 
162
- * Reintroduce display text, lost in a bad merge
163
-
164
-
165
-
166
-
167
- &nbsp;
168
-
169
- &nbsp;
170
-
171
- <a name="5__85__2" />
172
-
173
- ## [5.85.2] - 9/12/2022 10:03:27 AM
174
-
175
- Commit [98b7b14217ea7e83550e4ed15b6b6be80799e246](https://github.com/StoneCypher/jssm/commit/98b7b14217ea7e83550e4ed15b6b6be80799e246)
176
-
177
- Author: `John Haugeland <stonecypher@gmail.com>`
178
-
179
- Merges [461a287, 0f3025a]
180
-
181
- * Merge pull request #539 from StoneCypher/TrimTweet
182
- * Shorten the tweet notice
178
+ * Reintroduce display text, lost in a bad merge
package/README.md CHANGED
@@ -18,7 +18,7 @@ Please edit the file it's derived from, instead: `./src/md/readme_base.md`
18
18
 
19
19
 
20
20
 
21
- * Generated for version 5.85.8 at 9/12/2022, 8:16:52 PM
21
+ * Generated for version 5.85.9 at 9/12/2022, 9:03:57 PM
22
22
 
23
23
  -->
24
24
  # jssm
@@ -29,7 +29,7 @@ share online. Easy to embed.
29
29
 
30
30
  Readable, useful state machines as one-liner strings.
31
31
 
32
- ***4,864 tests*** run 5,755 times. 4,855 specs with 100.0% coverage, 9 fuzz tests with 13.2% coverage. With 2,725 lines, that's about 1.8 tests per line, or 2.1 generated tests per line.
32
+ ***4,866 tests*** run 5,757 times. 4,857 specs with 100.0% coverage, 9 fuzz tests with 13.6% coverage. With 2,754 lines, that's about 1.8 tests per line, or 2.1 generated tests per line.
33
33
 
34
34
  ***Meet your new state machine library.***
35
35
 
@@ -1,133 +1,12 @@
1
1
  declare type StateType = string;
2
2
  import { JssmGenericState, JssmGenericConfig, JssmStateConfig, JssmTransition, JssmTransitionList, // JssmTransitionRule,
3
- JssmMachineInternalState, JssmParseTree, JssmStateDeclaration, JssmStateStyleKeyList, JssmLayout, JssmHistory, JssmSerialization, FslDirection, FslDirections, FslTheme, HookDescription, HookHandler, HookContext, HookResult, HookComplexResult } from './jssm_types';
3
+ JssmMachineInternalState, JssmStateDeclaration, JssmStateStyleKeyList, JssmLayout, JssmHistory, JssmSerialization, FslDirection, FslDirections, FslTheme, HookDescription, HookHandler, HookContext, HookResult, HookComplexResult } from './jssm_types';
4
4
  import { arrow_direction, arrow_left_kind, arrow_right_kind } from './jssm_arrow';
5
+ import { compile, make, wrap_parse } from './jssm_compiler';
5
6
  import { seq, unique, find_repeated, weighted_rand_select, weighted_sample_select, histograph, weighted_histo_key } from './jssm_util';
6
7
  import * as constants from './jssm_constants';
7
8
  declare const shapes: string[], gviz_shapes: string[], named_colors: string[];
8
9
  import { version, build_time } from './version';
9
- /*********
10
- *
11
- * This method wraps the parser call that comes from the peg grammar,
12
- * {@link parse}. Generally neither this nor that should be used directly
13
- * unless you mean to develop plugins or extensions for the machine.
14
- *
15
- * Parses the intermediate representation of a compiled string down to a
16
- * machine configuration object. If you're using this (probably don't,) you're
17
- * probably also using {@link compile} and {@link Machine.constructor}.
18
- *
19
- * ```typescript
20
- * import { parse, compile, Machine } from 'jssm';
21
- *
22
- * const intermediate = wrap_parse('a -> b;', {});
23
- * // [ {key:'transition', from:'a', se:{kind:'->',to:'b'}} ]
24
- *
25
- * const cfg = compile(intermediate);
26
- * // { start_states:['a'], transitions: [{ from:'a', to:'b', kind:'legal', forced_only:false, main_path:false }] }
27
- *
28
- * const machine = new Machine(cfg);
29
- * // Machine { _instance_name: undefined, _state: 'a', ...
30
- * ```
31
- *
32
- * This method is mostly for plugin and intermediate tool authors, or people
33
- * who need to work with the machine's intermediate representation.
34
- *
35
- * # Hey!
36
- *
37
- * Most people looking at this want either the `sm` operator or method `from`,
38
- * which perform all the steps in the chain. The library's author mostly uses
39
- * operator `sm`, and mostly falls back to `.from` when needing to parse
40
- * strings dynamically instead of from template literals.
41
- *
42
- * Operator {@link sm}:
43
- *
44
- * ```typescript
45
- * import { sm } from 'jssm';
46
- *
47
- * const lswitch = sm`on <=> off;`;
48
- * ```
49
- *
50
- * Method {@link from}:
51
- *
52
- * ```typescript
53
- * import * as jssm from 'jssm';
54
- *
55
- * const toggle = jssm.from('up <=> down;');
56
- * ```
57
- *
58
- * `wrap_parse` itself is an internal convenience method for alting out an
59
- * object as the options call. Not generally meant for external use.
60
- *
61
- * @param input The FSL code to be evaluated
62
- *
63
- * @param options Things to control about the instance
64
- *
65
- */
66
- declare function wrap_parse(input: string, options?: Object): any;
67
- /*********
68
- *
69
- * Compile a machine's JSON intermediate representation to a config object. If
70
- * you're using this (probably don't,) you're probably also using
71
- * {@link parse} to get the IR, and the object constructor
72
- * {@link Machine.construct} to turn the config object into a workable machine.
73
- *
74
- * ```typescript
75
- * import { parse, compile, Machine } from 'jssm';
76
- *
77
- * const intermediate = parse('a -> b;');
78
- * // [ {key:'transition', from:'a', se:{kind:'->',to:'b'}} ]
79
- *
80
- * const cfg = compile(intermediate);
81
- * // { start_states:['a'], transitions: [{ from:'a', to:'b', kind:'legal', forced_only:false, main_path:false }] }
82
- *
83
- * const machine = new Machine(cfg);
84
- * // Machine { _instance_name: undefined, _state: 'a', ...
85
- * ```
86
- *
87
- * This method is mostly for plugin and intermediate tool authors, or people
88
- * who need to work with the machine's intermediate representation.
89
- *
90
- * # Hey!
91
- *
92
- * Most people looking at this want either the `sm` operator or method `from`,
93
- * which perform all the steps in the chain. The library's author mostly uses
94
- * operator `sm`, and mostly falls back to `.from` when needing to parse
95
- * strings dynamically instead of from template literals.
96
- *
97
- * Operator {@link sm}:
98
- *
99
- * ```typescript
100
- * import { sm } from 'jssm';
101
- *
102
- * const lswitch = sm`on <=> off;`;
103
- * ```
104
- *
105
- * Method {@link from}:
106
- *
107
- * ```typescript
108
- * import * as jssm from 'jssm';
109
- *
110
- * const toggle = jssm.from('up <=> down;');
111
- * ```
112
- *
113
- * @typeparam mDT The type of the machine data member; usually omitted
114
- *
115
- * @param tree The parse tree to be boiled down into a machine config
116
- *
117
- */
118
- declare function compile<mDT>(tree: JssmParseTree): JssmGenericConfig<mDT>;
119
- /*********
120
- *
121
- * An internal convenience wrapper for parsing then compiling a machine string.
122
- * Not generally meant for external use. Please see {@link compile} or
123
- * {@link sm}.
124
- *
125
- * @typeparam mDT The type of the machine data member; usually omitted
126
- *
127
- * @param plan The FSL code to be evaluated and built into a machine config
128
- *
129
- */
130
- declare function make<mDT>(plan: string): JssmGenericConfig<mDT>;
131
10
  /*********
132
11
  *
133
12
  * An internal method meant to take a series of declarations and fold them into
@@ -142,7 +21,7 @@ declare function state_style_condense(jssk: JssmStateStyleKeyList): JssmStateCon
142
21
  declare class Machine<mDT> {
143
22
  _state: StateType;
144
23
  _states: Map<StateType, JssmGenericState>;
145
- _edges: Array<JssmTransition<mDT>>;
24
+ _edges: Array<JssmTransition<StateType, mDT>>;
146
25
  _edge_map: Map<StateType, Map<StateType, number>>;
147
26
  _named_transitions: Map<StateType, number>;
148
27
  _actions: Map<StateType, Map<StateType, number>>;
@@ -217,7 +96,7 @@ declare class Machine<mDT> {
217
96
  _start_state_style: JssmStateConfig;
218
97
  _end_state_style: JssmStateConfig;
219
98
  _state_labels: Map<string, string>;
220
- constructor({ start_states, end_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, default_state_config, default_active_state_config, default_hooked_state_config, default_terminal_state_config, default_start_state_config, default_end_state_config }: JssmGenericConfig<mDT>);
99
+ constructor({ start_states, end_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, default_state_config, default_active_state_config, default_hooked_state_config, default_terminal_state_config, default_start_state_config, default_end_state_config }: JssmGenericConfig<StateType, mDT>);
221
100
  /********
222
101
  *
223
102
  * Internal method for fabricating states. Not meant for external use.
@@ -598,7 +477,7 @@ declare class Machine<mDT> {
598
477
  * @typeparam mDT The type of the machine data member; usually omitted
599
478
  *
600
479
  */
601
- list_edges(): Array<JssmTransition<mDT>>;
480
+ list_edges(): Array<JssmTransition<StateType, mDT>>;
602
481
  list_named_transitions(): Map<StateType, number>;
603
482
  list_actions(): Array<StateType>;
604
483
  get uses_actions(): boolean;
@@ -607,7 +486,7 @@ declare class Machine<mDT> {
607
486
  set themes(to: FslTheme | FslTheme[]);
608
487
  flow(): FslDirection;
609
488
  get_transition_by_state_names(from: StateType, to: StateType): number;
610
- lookup_transition_for(from: StateType, to: StateType): JssmTransition<mDT>;
489
+ lookup_transition_for(from: StateType, to: StateType): JssmTransition<StateType, mDT>;
611
490
  /********
612
491
  *
613
492
  * List all transitions attached to the current state, sorted by entrance and
@@ -669,7 +548,7 @@ declare class Machine<mDT> {
669
548
  *
670
549
  */
671
550
  list_exits(whichState?: StateType): Array<StateType>;
672
- probable_exits_for(whichState: StateType): Array<JssmTransition<mDT>>;
551
+ probable_exits_for(whichState: StateType): Array<JssmTransition<StateType, mDT>>;
673
552
  probabilistic_transition(): boolean;
674
553
  probabilistic_walk(n: number): Array<StateType>;
675
554
  probabilistic_histo_walk(n: number): Map<StateType, number>;
@@ -762,7 +641,7 @@ declare class Machine<mDT> {
762
641
  post_hook_any_transition(handler: HookHandler<mDT>): Machine<mDT>;
763
642
  post_hook_entry(to: string, handler: HookHandler<mDT>): Machine<mDT>;
764
643
  post_hook_exit(from: string, handler: HookHandler<mDT>): Machine<mDT>;
765
- edges_between(from: string, to: string): JssmTransition<mDT>[];
644
+ edges_between(from: string, to: string): JssmTransition<StateType, mDT>[];
766
645
  transition_impl(newStateOrAction: StateType, newData: mDT | undefined, wasForced: boolean, wasAction: boolean): boolean;
767
646
  /*********
768
647
  *
@@ -1130,7 +1009,7 @@ declare class Machine<mDT> {
1130
1009
  */
1131
1010
  force_transition(newState: StateType, newData?: mDT): boolean;
1132
1011
  current_action_for(action: StateType): number;
1133
- current_action_edge_for(action: StateType): JssmTransition<mDT>;
1012
+ current_action_edge_for(action: StateType): JssmTransition<StateType, mDT>;
1134
1013
  valid_action(action: StateType, _newData?: mDT): boolean;
1135
1014
  valid_transition(newState: StateType, _newData?: mDT): boolean;
1136
1015
  valid_force_transition(newState: StateType, _newData?: mDT): boolean;
@@ -1183,7 +1062,7 @@ declare function sm<mDT>(template_strings: TemplateStringsArray, ...remainder: a
1183
1062
  * @param ExtraConstructorFields Extra non-code configuration to pass at creation time
1184
1063
  *
1185
1064
  */
1186
- declare function from<mDT>(MachineAsString: string, ExtraConstructorFields?: Partial<JssmGenericConfig<mDT>> | undefined): Machine<mDT>;
1065
+ declare function from<mDT>(MachineAsString: string, ExtraConstructorFields?: Partial<JssmGenericConfig<StateType, mDT>> | undefined): Machine<mDT>;
1187
1066
  declare function is_hook_complex_result<mDT>(hr: unknown): hr is HookComplexResult<mDT>;
1188
1067
  declare function is_hook_rejection<mDT>(hr: HookResult<mDT>): boolean;
1189
1068
  declare function abstract_hook_step<mDT>(maybe_hook: HookHandler<mDT> | undefined, hook_args: HookContext<mDT>): HookComplexResult<mDT>;
package/dist/es6/jssm.js CHANGED
@@ -1,8 +1,11 @@
1
1
  // whargarbl lots of these return arrays could/should be sets
2
- import { reduce as reduce_to_639 } from 'reduce-to-639-1';
3
2
  import { circular_buffer } from 'circular_buffer_js';
4
3
  import { FslDirections } from './jssm_types';
5
4
  import { arrow_direction, arrow_left_kind, arrow_right_kind } from './jssm_arrow';
5
+ import { compile, make, wrap_parse } from './jssm_compiler';
6
+ // compile_rule_handler,
7
+ // compile_rule_transition_step,
8
+ // compile_rule_handle_transition,
6
9
  import { base_theme } from './themes/jssm_base_stylesheet';
7
10
  import { default_theme } from './themes/jssm_theme_default';
8
11
  import { modern_theme } from './themes/jssm_theme_modern';
@@ -18,362 +21,8 @@ theme_mapping.set('bold', bold_theme);
18
21
  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';
19
22
  import * as constants from './jssm_constants';
20
23
  const { shapes, gviz_shapes, named_colors } = constants;
21
- import { parse } from './fsl_parser';
22
24
  import { version, build_time } from './version'; // replaced from package.js in build
23
25
  import { JssmError } from './jssm_error';
24
- /*********
25
- *
26
- * Internal method meant to perform factory assembly of an edge. Not meant for
27
- * external use.
28
- *
29
- * @internal
30
- *
31
- * @typeparam mDT The type of the machine data member; usually omitted
32
- *
33
- */
34
- // TODO add at-param to docblock
35
- function makeTransition(this_se, from, to, isRight, _wasList, _wasIndex) {
36
- const kind = isRight
37
- ? arrow_right_kind(this_se.kind)
38
- : arrow_left_kind(this_se.kind), edge = {
39
- from,
40
- to,
41
- kind,
42
- forced_only: kind === 'forced',
43
- main_path: kind === 'main'
44
- };
45
- // if ((wasList !== undefined) && (wasIndex === undefined)) { throw new JssmError(undefined, `Must have an index if transition was in a list"); }
46
- // if ((wasIndex !== undefined) && (wasList === undefined)) { throw new JssmError(undefined, `Must be in a list if transition has an index"); }
47
- /*
48
- if (typeof edge.to === 'object') {
49
-
50
- if (edge.to.key === 'cycle') {
51
- if (wasList === undefined) { throw new JssmError(undefined, "Must have a waslist if a to is type cycle"); }
52
- const nextIndex = wrapBy(wasIndex, edge.to.value, wasList.length);
53
- edge.to = wasList[nextIndex];
54
- }
55
-
56
- }
57
- */
58
- const action = isRight ? 'r_action' : 'l_action', probability = isRight ? 'r_probability' : 'l_probability';
59
- if (this_se[action]) {
60
- edge.action = this_se[action];
61
- }
62
- if (this_se[probability]) {
63
- edge.probability = this_se[probability];
64
- }
65
- return edge;
66
- }
67
- /*********
68
- *
69
- * This method wraps the parser call that comes from the peg grammar,
70
- * {@link parse}. Generally neither this nor that should be used directly
71
- * unless you mean to develop plugins or extensions for the machine.
72
- *
73
- * Parses the intermediate representation of a compiled string down to a
74
- * machine configuration object. If you're using this (probably don't,) you're
75
- * probably also using {@link compile} and {@link Machine.constructor}.
76
- *
77
- * ```typescript
78
- * import { parse, compile, Machine } from 'jssm';
79
- *
80
- * const intermediate = wrap_parse('a -> b;', {});
81
- * // [ {key:'transition', from:'a', se:{kind:'->',to:'b'}} ]
82
- *
83
- * const cfg = compile(intermediate);
84
- * // { start_states:['a'], transitions: [{ from:'a', to:'b', kind:'legal', forced_only:false, main_path:false }] }
85
- *
86
- * const machine = new Machine(cfg);
87
- * // Machine { _instance_name: undefined, _state: 'a', ...
88
- * ```
89
- *
90
- * This method is mostly for plugin and intermediate tool authors, or people
91
- * who need to work with the machine's intermediate representation.
92
- *
93
- * # Hey!
94
- *
95
- * Most people looking at this want either the `sm` operator or method `from`,
96
- * which perform all the steps in the chain. The library's author mostly uses
97
- * operator `sm`, and mostly falls back to `.from` when needing to parse
98
- * strings dynamically instead of from template literals.
99
- *
100
- * Operator {@link sm}:
101
- *
102
- * ```typescript
103
- * import { sm } from 'jssm';
104
- *
105
- * const lswitch = sm`on <=> off;`;
106
- * ```
107
- *
108
- * Method {@link from}:
109
- *
110
- * ```typescript
111
- * import * as jssm from 'jssm';
112
- *
113
- * const toggle = jssm.from('up <=> down;');
114
- * ```
115
- *
116
- * `wrap_parse` itself is an internal convenience method for alting out an
117
- * object as the options call. Not generally meant for external use.
118
- *
119
- * @param input The FSL code to be evaluated
120
- *
121
- * @param options Things to control about the instance
122
- *
123
- */
124
- function wrap_parse(input, options) {
125
- return parse(input, options || {});
126
- }
127
- /*********
128
- *
129
- * Internal method performing one step in compiling rules for transitions. Not
130
- * generally meant for external use.
131
- *
132
- * @internal
133
- *
134
- * @typeparam mDT The type of the machine data member; usually omitted
135
- *
136
- */
137
- function compile_rule_transition_step(acc, from, to, this_se, next_se) {
138
- const edges = [];
139
- const uFrom = (Array.isArray(from) ? from : [from]), uTo = (Array.isArray(to) ? to : [to]);
140
- uFrom.map((f) => {
141
- uTo.map((t) => {
142
- const right = makeTransition(this_se, f, t, true);
143
- if (right.kind !== 'none') {
144
- edges.push(right);
145
- }
146
- const left = makeTransition(this_se, t, f, false);
147
- if (left.kind !== 'none') {
148
- edges.push(left);
149
- }
150
- });
151
- });
152
- const new_acc = acc.concat(edges);
153
- if (next_se) {
154
- return compile_rule_transition_step(new_acc, to, next_se.to, next_se, next_se.se);
155
- }
156
- else {
157
- return new_acc;
158
- }
159
- }
160
- /*********
161
- *
162
- * Internal method performing one step in compiling rules for transitions. Not
163
- * generally meant for external use.
164
- *
165
- * @internal
166
- *
167
- */
168
- function compile_rule_handle_transition(rule) {
169
- return compile_rule_transition_step([], rule.from, rule.se.to, rule.se, rule.se.se);
170
- }
171
- /*********
172
- *
173
- * Internal method performing one step in compiling rules for transitions. Not
174
- * generally meant for external use.
175
- *
176
- * @internal
177
- *
178
- */
179
- function compile_rule_handler(rule) {
180
- if (rule.key === 'transition') {
181
- return { agg_as: 'transition', val: compile_rule_handle_transition(rule) };
182
- }
183
- if (rule.key === 'machine_language') {
184
- return { agg_as: 'machine_language', val: reduce_to_639(rule.value) };
185
- }
186
- // manually rehandled to make `undefined` as a property safe
187
- if (rule.key === 'property_definition') {
188
- const ret = { agg_as: 'property_definition', val: { name: rule.name } };
189
- if (rule.hasOwnProperty('default_value')) {
190
- ret.val.default_value = rule.default_value;
191
- }
192
- if (rule.hasOwnProperty('required')) {
193
- ret.val.required = rule.required;
194
- }
195
- return ret;
196
- }
197
- // state properties are in here
198
- if (rule.key === 'state_declaration') {
199
- if (!rule.name) {
200
- throw new JssmError(undefined, 'State declarations must have a name');
201
- }
202
- return { agg_as: 'state_declaration', val: { state: rule.name, declarations: rule.value } };
203
- }
204
- if (['arrange_declaration', 'arrange_start_declaration',
205
- 'arrange_end_declaration'].includes(rule.key)) {
206
- return { agg_as: rule.key, val: [rule.value] };
207
- }
208
- // things that can only exist once and are just a value under their own name
209
- const tautologies = [
210
- 'graph_layout', 'start_states', 'end_states', 'machine_name', 'machine_version',
211
- 'machine_comment', 'machine_author', 'machine_contributor', 'machine_definition',
212
- 'machine_reference', 'machine_license', 'fsl_version', 'state_config', 'theme',
213
- 'flow', 'dot_preamble', 'default_state_config', 'default_start_state_config',
214
- 'default_end_state_config', 'default_hooked_state_config',
215
- 'default_active_state_config', 'default_terminal_state_config'
216
- ];
217
- if (tautologies.includes(rule.key)) {
218
- return { agg_as: rule.key, val: rule.value };
219
- }
220
- throw new JssmError(undefined, `compile_rule_handler: Unknown rule: ${JSON.stringify(rule)}`);
221
- }
222
- /*********
223
- *
224
- * Compile a machine's JSON intermediate representation to a config object. If
225
- * you're using this (probably don't,) you're probably also using
226
- * {@link parse} to get the IR, and the object constructor
227
- * {@link Machine.construct} to turn the config object into a workable machine.
228
- *
229
- * ```typescript
230
- * import { parse, compile, Machine } from 'jssm';
231
- *
232
- * const intermediate = parse('a -> b;');
233
- * // [ {key:'transition', from:'a', se:{kind:'->',to:'b'}} ]
234
- *
235
- * const cfg = compile(intermediate);
236
- * // { start_states:['a'], transitions: [{ from:'a', to:'b', kind:'legal', forced_only:false, main_path:false }] }
237
- *
238
- * const machine = new Machine(cfg);
239
- * // Machine { _instance_name: undefined, _state: 'a', ...
240
- * ```
241
- *
242
- * This method is mostly for plugin and intermediate tool authors, or people
243
- * who need to work with the machine's intermediate representation.
244
- *
245
- * # Hey!
246
- *
247
- * Most people looking at this want either the `sm` operator or method `from`,
248
- * which perform all the steps in the chain. The library's author mostly uses
249
- * operator `sm`, and mostly falls back to `.from` when needing to parse
250
- * strings dynamically instead of from template literals.
251
- *
252
- * Operator {@link sm}:
253
- *
254
- * ```typescript
255
- * import { sm } from 'jssm';
256
- *
257
- * const lswitch = sm`on <=> off;`;
258
- * ```
259
- *
260
- * Method {@link from}:
261
- *
262
- * ```typescript
263
- * import * as jssm from 'jssm';
264
- *
265
- * const toggle = jssm.from('up <=> down;');
266
- * ```
267
- *
268
- * @typeparam mDT The type of the machine data member; usually omitted
269
- *
270
- * @param tree The parse tree to be boiled down into a machine config
271
- *
272
- */
273
- function compile(tree) {
274
- const results = {
275
- graph_layout: [],
276
- transition: [],
277
- start_states: [],
278
- end_states: [],
279
- state_config: [],
280
- state_declaration: [],
281
- fsl_version: [],
282
- machine_author: [],
283
- machine_comment: [],
284
- machine_contributor: [],
285
- machine_definition: [],
286
- machine_language: [],
287
- machine_license: [],
288
- machine_name: [],
289
- machine_reference: [],
290
- property_definition: [],
291
- state_property: {},
292
- theme: [],
293
- flow: [],
294
- dot_preamble: [],
295
- arrange_declaration: [],
296
- arrange_start_declaration: [],
297
- arrange_end_declaration: [],
298
- machine_version: [],
299
- default_state_config: [],
300
- default_active_state_config: [],
301
- default_hooked_state_config: [],
302
- default_terminal_state_config: [],
303
- default_start_state_config: [],
304
- default_end_state_config: [],
305
- };
306
- tree.map((tr) => {
307
- const rule = compile_rule_handler(tr), agg_as = rule.agg_as, val = rule.val; // TODO FIXME no any
308
- results[agg_as] = results[agg_as].concat(val);
309
- });
310
- const property_keys = results['property_definition'].map(pd => pd.name), repeat_props = find_repeated(property_keys);
311
- if (repeat_props.length) {
312
- throw new JssmError(undefined, `Cannot repeat property definitions. Saw ${JSON.stringify(repeat_props)}`);
313
- }
314
- const assembled_transitions = [].concat(...results['transition']);
315
- const result_cfg = {
316
- start_states: results.start_states.length ? results.start_states : [assembled_transitions[0].from],
317
- end_states: results.end_states,
318
- transitions: assembled_transitions,
319
- state_property: [],
320
- };
321
- const oneOnlyKeys = [
322
- 'graph_layout', 'machine_name', 'machine_version', 'machine_comment',
323
- 'fsl_version', 'machine_license', 'machine_definition', 'machine_language',
324
- 'flow', 'dot_preamble'
325
- ];
326
- oneOnlyKeys.map((oneOnlyKey) => {
327
- if (results[oneOnlyKey].length > 1) {
328
- throw new JssmError(undefined, `May only have one ${oneOnlyKey} statement maximum: ${JSON.stringify(results[oneOnlyKey])}`);
329
- }
330
- else {
331
- if (results[oneOnlyKey].length) {
332
- result_cfg[oneOnlyKey] = results[oneOnlyKey][0];
333
- }
334
- }
335
- });
336
- ['arrange_declaration', 'arrange_start_declaration', 'arrange_end_declaration',
337
- 'machine_author', 'machine_contributor', 'machine_reference', 'theme',
338
- 'state_declaration', 'property_definition', 'default_state_config',
339
- 'default_start_state_config', 'default_end_state_config',
340
- 'default_hooked_state_config', 'default_terminal_state_config',
341
- 'default_active_state_config'].map((multiKey) => {
342
- if (results[multiKey].length) {
343
- result_cfg[multiKey] = results[multiKey];
344
- }
345
- });
346
- // re-walk state declarations, already wrapped up, to get state properties,
347
- // which go out in a different datastructure
348
- results.state_declaration.forEach(sd => {
349
- sd.declarations.forEach(decl => {
350
- if (decl.key === 'state_property') {
351
- const label = name_bind_prop_and_state(decl.name, sd.state);
352
- if (result_cfg.state_property.findIndex(c => c.name === label) !== -1) {
353
- throw new JssmError(undefined, `A state may only bind a property once (${sd.state} re-binds ${decl.name})`);
354
- }
355
- else {
356
- result_cfg.state_property.push({ name: label, default_value: decl.value });
357
- }
358
- }
359
- });
360
- });
361
- return result_cfg;
362
- }
363
- /*********
364
- *
365
- * An internal convenience wrapper for parsing then compiling a machine string.
366
- * Not generally meant for external use. Please see {@link compile} or
367
- * {@link sm}.
368
- *
369
- * @typeparam mDT The type of the machine data member; usually omitted
370
- *
371
- * @param plan The FSL code to be evaluated and built into a machine config
372
- *
373
- */
374
- function make(plan) {
375
- return compile(wrap_parse(plan));
376
- }
377
26
  /*********
378
27
  *
379
28
  * An internal method meant to take a series of declarations and fold them into