jssm 5.85.8 → 5.85.10

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.
@@ -0,0 +1,363 @@
1
+ import { JssmError } from './jssm_error';
2
+ import { parse } from './fsl_parser';
3
+ import { arrow_left_kind, arrow_right_kind } from './jssm_arrow';
4
+ import { find_repeated, name_bind_prop_and_state } from './jssm_util';
5
+ import { reduce as reduce_to_639 } from 'reduce-to-639-1';
6
+ /*********
7
+ *
8
+ * Internal method meant to perform factory assembly of an edge. Not meant for
9
+ * external use.
10
+ *
11
+ * @internal
12
+ *
13
+ * @typeparam mDT The type of the machine data member; usually omitted
14
+ *
15
+ */
16
+ // TODO add at-param to docblock
17
+ function makeTransition(this_se, from, to, isRight, _wasList, _wasIndex) {
18
+ const kind = isRight
19
+ ? arrow_right_kind(this_se.kind)
20
+ : arrow_left_kind(this_se.kind), edge = {
21
+ from,
22
+ to,
23
+ kind,
24
+ forced_only: kind === 'forced',
25
+ main_path: kind === 'main'
26
+ };
27
+ // if ((wasList !== undefined) && (wasIndex === undefined)) { throw new JssmError(undefined, `Must have an index if transition was in a list"); }
28
+ // if ((wasIndex !== undefined) && (wasList === undefined)) { throw new JssmError(undefined, `Must be in a list if transition has an index"); }
29
+ /*
30
+ if (typeof edge.to === 'object') {
31
+
32
+ if (edge.to.key === 'cycle') {
33
+ if (wasList === undefined) { throw new JssmError(undefined, "Must have a waslist if a to is type cycle"); }
34
+ const nextIndex = wrapBy(wasIndex, edge.to.value, wasList.length);
35
+ edge.to = wasList[nextIndex];
36
+ }
37
+
38
+ }
39
+ */
40
+ const action = isRight ? 'r_action' : 'l_action', probability = isRight ? 'r_probability' : 'l_probability';
41
+ if (this_se[action]) {
42
+ edge.action = this_se[action];
43
+ }
44
+ if (this_se[probability]) {
45
+ edge.probability = this_se[probability];
46
+ }
47
+ return edge;
48
+ }
49
+ /*********
50
+ *
51
+ * This method wraps the parser call that comes from the peg grammar,
52
+ * {@link parse}. Generally neither this nor that should be used directly
53
+ * unless you mean to develop plugins or extensions for the machine.
54
+ *
55
+ * Parses the intermediate representation of a compiled string down to a
56
+ * machine configuration object. If you're using this (probably don't,) you're
57
+ * probably also using {@link compile} and {@link Machine.constructor}.
58
+ *
59
+ * ```typescript
60
+ * import { parse, compile, Machine } from 'jssm';
61
+ *
62
+ * const intermediate = wrap_parse('a -> b;', {});
63
+ * // [ {key:'transition', from:'a', se:{kind:'->',to:'b'}} ]
64
+ *
65
+ * const cfg = compile(intermediate);
66
+ * // { start_states:['a'], transitions: [{ from:'a', to:'b', kind:'legal', forced_only:false, main_path:false }] }
67
+ *
68
+ * const machine = new Machine(cfg);
69
+ * // Machine { _instance_name: undefined, _state: 'a', ...
70
+ * ```
71
+ *
72
+ * This method is mostly for plugin and intermediate tool authors, or people
73
+ * who need to work with the machine's intermediate representation.
74
+ *
75
+ * # Hey!
76
+ *
77
+ * Most people looking at this want either the `sm` operator or method `from`,
78
+ * which perform all the steps in the chain. The library's author mostly uses
79
+ * operator `sm`, and mostly falls back to `.from` when needing to parse
80
+ * strings dynamically instead of from template literals.
81
+ *
82
+ * Operator {@link sm}:
83
+ *
84
+ * ```typescript
85
+ * import { sm } from 'jssm';
86
+ *
87
+ * const lswitch = sm`on <=> off;`;
88
+ * ```
89
+ *
90
+ * Method {@link from}:
91
+ *
92
+ * ```typescript
93
+ * import * as jssm from 'jssm';
94
+ *
95
+ * const toggle = jssm.from('up <=> down;');
96
+ * ```
97
+ *
98
+ * `wrap_parse` itself is an internal convenience method for alting out an
99
+ * object as the options call. Not generally meant for external use.
100
+ *
101
+ * @param input The FSL code to be evaluated
102
+ *
103
+ * @param options Things to control about the instance
104
+ *
105
+ */
106
+ function wrap_parse(input, options) {
107
+ return parse(input, options || {});
108
+ }
109
+ /*********
110
+ *
111
+ * Internal method performing one step in compiling rules for transitions. Not
112
+ * generally meant for external use.
113
+ *
114
+ * @internal
115
+ *
116
+ * @typeparam mDT The type of the machine data member; usually omitted
117
+ *
118
+ */
119
+ function compile_rule_transition_step(acc, from, to, this_se, next_se) {
120
+ const edges = [];
121
+ const uFrom = (Array.isArray(from) ? from : [from]), uTo = (Array.isArray(to) ? to : [to]);
122
+ uFrom.map((f) => {
123
+ uTo.map((t) => {
124
+ const right = makeTransition(this_se, f, t, true);
125
+ if (right.kind !== 'none') {
126
+ edges.push(right);
127
+ }
128
+ const left = makeTransition(this_se, t, f, false);
129
+ if (left.kind !== 'none') {
130
+ edges.push(left);
131
+ }
132
+ });
133
+ });
134
+ const new_acc = acc.concat(edges);
135
+ if (next_se) {
136
+ return compile_rule_transition_step(new_acc, to, next_se.to, next_se, next_se.se);
137
+ }
138
+ else {
139
+ return new_acc;
140
+ }
141
+ }
142
+ /*********
143
+ *
144
+ * Internal method performing one step in compiling rules for transitions. Not
145
+ * generally meant for external use.
146
+ *
147
+ * @internal
148
+ *
149
+ */
150
+ function compile_rule_handle_transition(rule) {
151
+ return compile_rule_transition_step([], rule.from, rule.se.to, rule.se, rule.se.se);
152
+ }
153
+ /*********
154
+ *
155
+ * Internal method performing one step in compiling rules for transitions. Not
156
+ * generally meant for external use.
157
+ *
158
+ * @internal
159
+ *
160
+ */
161
+ function compile_rule_handler(rule) {
162
+ if (rule.key === 'transition') {
163
+ return { agg_as: 'transition', val: compile_rule_handle_transition(rule) };
164
+ }
165
+ if (rule.key === 'machine_language') {
166
+ return { agg_as: 'machine_language', val: reduce_to_639(rule.value) };
167
+ }
168
+ // manually rehandled to make `undefined` as a property safe
169
+ if (rule.key === 'property_definition') {
170
+ const ret = { agg_as: 'property_definition', val: { name: rule.name } };
171
+ if (rule.hasOwnProperty('default_value')) {
172
+ ret.val.default_value = rule.default_value;
173
+ }
174
+ if (rule.hasOwnProperty('required')) {
175
+ ret.val.required = rule.required;
176
+ }
177
+ return ret;
178
+ }
179
+ // state properties are in here
180
+ if (rule.key === 'state_declaration') {
181
+ if (!rule.name) {
182
+ throw new JssmError(undefined, 'State declarations must have a name');
183
+ }
184
+ return { agg_as: 'state_declaration', val: { state: rule.name, declarations: rule.value } };
185
+ }
186
+ if (['arrange_declaration', 'arrange_start_declaration',
187
+ 'arrange_end_declaration'].includes(rule.key)) {
188
+ return { agg_as: rule.key, val: [rule.value] };
189
+ }
190
+ // things that can only exist once and are just a value under their own name
191
+ const tautologies = [
192
+ 'graph_layout', 'start_states', 'end_states', 'machine_name', 'machine_version',
193
+ 'machine_comment', 'machine_author', 'machine_contributor', 'machine_definition',
194
+ 'machine_reference', 'machine_license', 'fsl_version', 'state_config', 'theme',
195
+ 'flow', 'dot_preamble', 'default_state_config', 'default_start_state_config',
196
+ 'default_end_state_config', 'default_hooked_state_config',
197
+ 'default_active_state_config', 'default_terminal_state_config'
198
+ ];
199
+ if (tautologies.includes(rule.key)) {
200
+ return { agg_as: rule.key, val: rule.value };
201
+ }
202
+ throw new JssmError(undefined, `compile_rule_handler: Unknown rule: ${JSON.stringify(rule)}`);
203
+ }
204
+ /*********
205
+ *
206
+ * Compile a machine's JSON intermediate representation to a config object. If
207
+ * you're using this (probably don't,) you're probably also using
208
+ * {@link parse} to get the IR, and the object constructor
209
+ * {@link Machine.construct} to turn the config object into a workable machine.
210
+ *
211
+ * ```typescript
212
+ * import { parse, compile, Machine } from 'jssm';
213
+ *
214
+ * const intermediate = parse('a -> b;');
215
+ * // [ {key:'transition', from:'a', se:{kind:'->',to:'b'}} ]
216
+ *
217
+ * const cfg = compile(intermediate);
218
+ * // { start_states:['a'], transitions: [{ from:'a', to:'b', kind:'legal', forced_only:false, main_path:false }] }
219
+ *
220
+ * const machine = new Machine(cfg);
221
+ * // Machine { _instance_name: undefined, _state: 'a', ...
222
+ * ```
223
+ *
224
+ * This method is mostly for plugin and intermediate tool authors, or people
225
+ * who need to work with the machine's intermediate representation.
226
+ *
227
+ * # Hey!
228
+ *
229
+ * Most people looking at this want either the `sm` operator or method `from`,
230
+ * which perform all the steps in the chain. The library's author mostly uses
231
+ * operator `sm`, and mostly falls back to `.from` when needing to parse
232
+ * strings dynamically instead of from template literals.
233
+ *
234
+ * Operator {@link sm}:
235
+ *
236
+ * ```typescript
237
+ * import { sm } from 'jssm';
238
+ *
239
+ * const lswitch = sm`on <=> off;`;
240
+ * ```
241
+ *
242
+ * Method {@link from}:
243
+ *
244
+ * ```typescript
245
+ * import * as jssm from 'jssm';
246
+ *
247
+ * const toggle = jssm.from('up <=> down;');
248
+ * ```
249
+ *
250
+ * @typeparam mDT The type of the machine data member; usually omitted
251
+ *
252
+ * @param tree The parse tree to be boiled down into a machine config
253
+ *
254
+ */
255
+ function compile(tree) {
256
+ const results = {
257
+ graph_layout: [],
258
+ transition: [],
259
+ start_states: [],
260
+ end_states: [],
261
+ state_config: [],
262
+ state_declaration: [],
263
+ fsl_version: [],
264
+ machine_author: [],
265
+ machine_comment: [],
266
+ machine_contributor: [],
267
+ machine_definition: [],
268
+ machine_language: [],
269
+ machine_license: [],
270
+ machine_name: [],
271
+ machine_reference: [],
272
+ property_definition: [],
273
+ state_property: {},
274
+ theme: [],
275
+ flow: [],
276
+ dot_preamble: [],
277
+ arrange_declaration: [],
278
+ arrange_start_declaration: [],
279
+ arrange_end_declaration: [],
280
+ machine_version: [],
281
+ default_state_config: [],
282
+ default_active_state_config: [],
283
+ default_hooked_state_config: [],
284
+ default_terminal_state_config: [],
285
+ default_start_state_config: [],
286
+ default_end_state_config: [],
287
+ };
288
+ tree.map((tr) => {
289
+ const rule = compile_rule_handler(tr), agg_as = rule.agg_as, val = rule.val; // TODO FIXME no any
290
+ results[agg_as] = results[agg_as].concat(val);
291
+ });
292
+ const property_keys = results['property_definition'].map(pd => pd.name), repeat_props = find_repeated(property_keys);
293
+ if (repeat_props.length) {
294
+ throw new JssmError(undefined, `Cannot repeat property definitions. Saw ${JSON.stringify(repeat_props)}`);
295
+ }
296
+ const assembled_transitions = [].concat(...results['transition']);
297
+ const result_cfg = {
298
+ start_states: results.start_states.length ? results.start_states : [assembled_transitions[0].from],
299
+ end_states: results.end_states,
300
+ transitions: assembled_transitions,
301
+ state_property: [],
302
+ };
303
+ const oneOnlyKeys = [
304
+ 'graph_layout', 'machine_name', 'machine_version', 'machine_comment',
305
+ 'fsl_version', 'machine_license', 'machine_definition', 'machine_language',
306
+ 'flow', 'dot_preamble'
307
+ ];
308
+ oneOnlyKeys.map((oneOnlyKey) => {
309
+ if (results[oneOnlyKey].length > 1) {
310
+ throw new JssmError(undefined, `May only have one ${oneOnlyKey} statement maximum: ${JSON.stringify(results[oneOnlyKey])}`);
311
+ }
312
+ else {
313
+ if (results[oneOnlyKey].length) {
314
+ result_cfg[oneOnlyKey] = results[oneOnlyKey][0];
315
+ }
316
+ }
317
+ });
318
+ ['arrange_declaration', 'arrange_start_declaration', 'arrange_end_declaration',
319
+ 'machine_author', 'machine_contributor', 'machine_reference', 'theme',
320
+ 'state_declaration', 'property_definition', 'default_state_config',
321
+ 'default_start_state_config', 'default_end_state_config',
322
+ 'default_hooked_state_config', 'default_terminal_state_config',
323
+ 'default_active_state_config'].map((multiKey) => {
324
+ if (results[multiKey].length) {
325
+ result_cfg[multiKey] = results[multiKey];
326
+ }
327
+ });
328
+ // re-walk state declarations, already wrapped up, to get state properties,
329
+ // which go out in a different datastructure
330
+ results.state_declaration.forEach(sd => {
331
+ sd.declarations.forEach(decl => {
332
+ if (decl.key === 'state_property') {
333
+ const label = name_bind_prop_and_state(decl.name, sd.state);
334
+ if (result_cfg.state_property.findIndex(c => c.name === label) !== -1) {
335
+ throw new JssmError(undefined, `A state may only bind a property once (${sd.state} re-binds ${decl.name})`);
336
+ }
337
+ else {
338
+ result_cfg.state_property.push({ name: label, default_value: decl.value });
339
+ }
340
+ }
341
+ });
342
+ });
343
+ return result_cfg;
344
+ }
345
+ /*********
346
+ *
347
+ * An internal convenience wrapper for parsing then compiling a machine string.
348
+ * Not generally meant for external use. Please see {@link compile} or
349
+ * {@link sm}.
350
+ *
351
+ * @typeparam mDT The type of the machine data member; usually omitted
352
+ *
353
+ * @param plan The FSL code to be evaluated and built into a machine config
354
+ *
355
+ */
356
+ function make(plan) {
357
+ return compile(wrap_parse(plan));
358
+ }
359
+ export { compile,
360
+ // compile_rule_handler,
361
+ // compile_rule_transition_step,
362
+ // compile_rule_handle_transition,
363
+ make, makeTransition, wrap_parse };
@@ -0,0 +1,4 @@
1
+ import { FslTheme, JssmBaseTheme } from './jssm_types';
2
+ import { base_theme } from './themes/jssm_base_stylesheet';
3
+ declare const theme_mapping: Map<FslTheme, JssmBaseTheme>;
4
+ export { theme_mapping, base_theme };
@@ -0,0 +1,13 @@
1
+ import { base_theme } from './themes/jssm_base_stylesheet';
2
+ import { default_theme } from './themes/jssm_theme_default';
3
+ import { modern_theme } from './themes/jssm_theme_modern';
4
+ import { ocean_theme } from './themes/jssm_theme_ocean';
5
+ import { plain_theme } from './themes/jssm_theme_plain';
6
+ import { bold_theme } from './themes/jssm_theme_bold';
7
+ const theme_mapping = new Map();
8
+ theme_mapping.set('default', default_theme);
9
+ theme_mapping.set('modern', modern_theme);
10
+ theme_mapping.set('ocean', ocean_theme);
11
+ theme_mapping.set('plain', plain_theme);
12
+ theme_mapping.set('bold', bold_theme);
13
+ export { theme_mapping, base_theme };
@@ -44,10 +44,10 @@ declare type JssmPropertyDefinition = {
44
44
  };
45
45
  declare type JssmTransitionPermitter<DataType> = (OldState: StateType, NewState: StateType, OldData: DataType, NewData: DataType) => boolean;
46
46
  declare type JssmTransitionPermitterMaybeArray<DataType> = JssmTransitionPermitter<DataType> | Array<JssmTransitionPermitter<DataType>>;
47
- declare type JssmTransition<DataType> = {
47
+ declare type JssmTransition<StateType, DataType> = {
48
48
  from: StateType;
49
49
  to: StateType;
50
- name?: string;
50
+ name?: StateType;
51
51
  action?: StateType;
52
52
  check?: JssmTransitionPermitterMaybeArray<DataType>;
53
53
  probability?: number;
@@ -55,7 +55,7 @@ declare type JssmTransition<DataType> = {
55
55
  forced_only: boolean;
56
56
  main_path: boolean;
57
57
  };
58
- declare type JssmTransitions<DataType> = JssmTransition<DataType>[];
58
+ declare type JssmTransitions<StateType, DataType> = JssmTransition<StateType, DataType>[];
59
59
  declare type JssmTransitionList = {
60
60
  entrances: Array<StateType>;
61
61
  exits: Array<StateType>;
@@ -79,7 +79,7 @@ declare type JssmMachineInternalState<DataType> = {
79
79
  edge_map: Map<StateType, Map<StateType, number>>;
80
80
  actions: Map<StateType, Map<StateType, number>>;
81
81
  reverse_actions: Map<StateType, Map<StateType, number>>;
82
- edges: Array<JssmTransition<DataType>>;
82
+ edges: Array<JssmTransition<StateType, DataType>>;
83
83
  };
84
84
  declare type JssmStatePermitter<DataType> = (OldState: StateType, NewState: StateType, OldData: DataType, NewData: DataType) => boolean;
85
85
  declare type JssmStatePermitterMaybeArray<DataType> = JssmStatePermitter<DataType> | Array<JssmStatePermitter<DataType>>;
@@ -88,7 +88,7 @@ declare type JssmGenericMachine<DataType> = {
88
88
  state: StateType;
89
89
  data?: DataType;
90
90
  nodes?: Array<StateType>;
91
- transitions: JssmTransitions<DataType>;
91
+ transitions: JssmTransitions<StateType, DataType>;
92
92
  check?: JssmStatePermitterMaybeArray<DataType>;
93
93
  min_transitions?: number;
94
94
  max_transitions?: number;
@@ -173,10 +173,10 @@ declare type JssmBaseTheme = {
173
173
  title: undefined;
174
174
  };
175
175
  declare type JssmTheme = Partial<JssmBaseTheme>;
176
- declare type JssmGenericConfig<DataType> = {
176
+ declare type JssmGenericConfig<StateType, DataType> = {
177
177
  graph_layout?: JssmLayout;
178
178
  complete?: Array<StateType>;
179
- transitions: JssmTransitions<DataType>;
179
+ transitions: JssmTransitions<StateType, DataType>;
180
180
  theme?: FslTheme[];
181
181
  flow?: FslDirection;
182
182
  name?: string;
@@ -217,22 +217,22 @@ declare type JssmGenericConfig<DataType> = {
217
217
  default_terminal_state_config?: JssmStateStyleKeyList;
218
218
  default_active_state_config?: JssmStateStyleKeyList;
219
219
  };
220
- declare type JssmCompileRule = {
220
+ declare type JssmCompileRule<StateType> = {
221
221
  agg_as: string;
222
222
  val: any;
223
223
  };
224
- declare type JssmCompileSe = {
224
+ declare type JssmCompileSe<StateType, mDT> = {
225
225
  to: StateType;
226
- se: JssmCompileSe;
226
+ se: JssmCompileSe<StateType, mDT>;
227
227
  kind: JssmArrow;
228
228
  l_action?: StateType;
229
229
  r_action?: StateType;
230
230
  l_probability: number;
231
231
  r_probability: number;
232
232
  };
233
- declare type JssmCompileSeStart<DataType> = {
234
- from: DataType;
235
- se: JssmCompileSe;
233
+ declare type JssmCompileSeStart<StateType, DataType> = {
234
+ from: StateType;
235
+ se: JssmCompileSe<StateType, DataType>;
236
236
  key: string;
237
237
  value?: string | number;
238
238
  name?: string;
@@ -240,8 +240,8 @@ declare type JssmCompileSeStart<DataType> = {
240
240
  default_value?: any;
241
241
  required?: boolean;
242
242
  };
243
- declare type JssmParseTree = Array<JssmCompileSeStart<StateType>>;
244
- declare type JssmParseFunctionType = (string: any) => JssmParseTree;
243
+ declare type JssmParseTree<StateType, mDT> = Array<JssmCompileSeStart<StateType, mDT>>;
244
+ declare type JssmParseFunctionType<StateType, mDT> = (string: any) => JssmParseTree<StateType, mDT>;
245
245
  declare type BasicHookDescription<mDT> = {
246
246
  kind: 'hook';
247
247
  from: string;
@@ -1,2 +1,2 @@
1
- const version = "5.85.8", build_time = 1663038933181;
1
+ const version = "5.85.10", build_time = 1663374435658;
2
2
  export { version, build_time };