state-machine-cat 10.1.2 → 10.1.5

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.
Files changed (37) hide show
  1. package/README.md +1 -1
  2. package/bin/smcat.mjs +5 -0
  3. package/dist/commonjs/bundle.js +64 -64
  4. package/package.json +40 -69
  5. package/src/cli/actions.mjs +9 -0
  6. package/src/cli/file-name-to-stream.mjs +5 -6
  7. package/src/cli/make-description.mjs +9 -0
  8. package/src/cli/normalize.mjs +100 -47
  9. package/src/cli/validations.mjs +27 -1
  10. package/src/index-node.mjs +15 -47
  11. package/src/index.mjs +9 -9
  12. package/src/options.mjs +19 -13
  13. package/src/parse/index.mjs +13 -0
  14. package/src/parse/parser-helpers.mjs +70 -6
  15. package/src/parse/scxml/index.mjs +72 -20
  16. package/src/parse/scxml/normalize-machine.mjs +27 -21
  17. package/src/render/dot/README.md +12 -0
  18. package/src/render/dot/attributebuilder.mjs +7 -0
  19. package/src/render/dot/counter.mjs +13 -0
  20. package/src/render/dot/index.mjs +66 -28
  21. package/src/render/dot/render-dot-from-ast.js +37 -15
  22. package/src/render/dot/state-transformers.mjs +4 -2
  23. package/src/render/dot/utl.mjs +20 -0
  24. package/src/render/index-node.mjs +9 -3
  25. package/src/render/index.mjs +3 -3
  26. package/src/render/scjson/index.mjs +6 -0
  27. package/src/render/scjson/make-valid-xml-name.mjs +7 -1
  28. package/src/render/scxml/index.mjs +2 -0
  29. package/src/render/smcat/index.js +48 -14
  30. package/src/render/vector/dot-to-vector-native.mjs +1 -1
  31. package/src/render/vector/vector-native-dot-with-fallback.mjs +3 -2
  32. package/src/render/vector/vector-with-viz-js.mjs +3 -2
  33. package/src/state-machine-model.mjs +46 -4
  34. package/src/transform/desugar.mjs +67 -18
  35. package/src/transform/utl.mjs +8 -0
  36. package/src/version.mjs +1 -1
  37. package/types/state-machine-cat.d.ts +41 -14
@@ -0,0 +1,12 @@
1
+ ## Why does this renderer use `#FFFFFF01` instead of `transparent` for transparency?
2
+
3
+ Typically you'll use the `dot` output to translate it to scalable vector graphics
4
+ (svg) with GraphViz. In svg `transparent` isn't a color, though (see issue [#129](https://github.com/sverweij/state-machine-cat/issues/129)).
5
+ In web browsers this isn't a problem, but less lenient svg interpreters will
6
+ render it as black instead. This is suboptimal.
7
+
8
+ The obvious alternative is to use `#FFFFFF00` (as svg does allow RGBA), however
9
+ GraphViz translates this into `transparent` nonetheless. So to hack around this
10
+ the dot renderer uses `01` in the alpha channel in stead (`#FFFFFF01`). GrapViz
11
+ nicely translates this to `fill="#ffffff" fill-opacity="0.004"` which is sufficiently
12
+ transparent for all practical purposes.
@@ -44,6 +44,13 @@ function toNameValueString(pAttribute) {
44
44
  }
45
45
 
46
46
  export default {
47
+ /**
48
+ *
49
+ * @param {string} pEngine
50
+ * @param {string} pDirection
51
+ * @param {*} pDotGraphAttributes
52
+ * @returns {string}
53
+ */
47
54
  buildGraphAttributes: (pEngine, pDirection, pDotGraphAttributes) =>
48
55
  GENERIC_GRAPH_ATTRIBUTES.concat(GRAPH_ATTRIBUTES[pEngine] || [])
49
56
  .concat(DIRECTION_ATTRIBUTES[pDirection] || [])
@@ -1,18 +1,31 @@
1
+ // @ts-check
1
2
  export default class Counter {
2
3
  constructor() {
3
4
  this.reset();
4
5
  }
5
6
 
7
+ /**
8
+ * @returns {void}
9
+ */
6
10
  reset() {
7
11
  this.COUNTER = 0;
8
12
  }
9
13
 
14
+ /**
15
+ * @returns {number}
16
+ */
10
17
  next() {
18
+ // @ts-expect-error TS thinks COUNTER can possibly be null as it doesn't
19
+ // see that the function the constructor calls ensures it won't
11
20
  // eslint-disable-next-line no-plusplus
12
21
  return ++this.COUNTER;
13
22
  }
14
23
 
24
+ /**
25
+ * @returns {string}
26
+ */
15
27
  nextAsString() {
28
+ /** @type {number} */
16
29
  const lBase = 10;
17
30
 
18
31
  return this.next().toString(lBase);
@@ -10,6 +10,10 @@ import utl from "./utl.mjs";
10
10
 
11
11
  let gCounter = {};
12
12
 
13
+ /**
14
+ * @param {StateMachineModel} pStateMachineModel
15
+ * @returns {(pState: import("../../../types/state-machine-cat.js").IState) => import("../../../types/state-machine-cat.js").IState}
16
+ */
13
17
  function addExternalSelfTransitions(pStateMachineModel) {
14
18
  return (pState) => {
15
19
  if (Object.prototype.hasOwnProperty.call(pState, "statemachine")) {
@@ -21,6 +25,13 @@ function addExternalSelfTransitions(pStateMachineModel) {
21
25
  };
22
26
  }
23
27
 
28
+ /**
29
+ * @param {import("../../../types/state-machine-cat.js").IState[]} pStates
30
+ * @param {string} pDirection
31
+ * @param {import("../../../types/state-machine-cat.js").dotAttributesType} pNodeAttributes
32
+ * @param {StateMachineModel} pStateMachineModel
33
+ * @returns {import("../../../types/state-machine-cat.js").IState[]}
34
+ */
24
35
  function transformStates(
25
36
  pStates,
26
37
  pDirection,
@@ -30,7 +41,11 @@ function transformStates(
30
41
  pStates
31
42
  .filter((pState) => pState.statemachine)
32
43
  .forEach((pState) => {
44
+ // @ts-expect-error - statemachine is _not_ potentially undefined, because of
45
+ // the filter
33
46
  pState.statemachine.states = transformStates(
47
+ // @ts-expect-error - statemachine is _not_ potentially undefined, because of
48
+ // the filter
34
49
  pState.statemachine.states,
35
50
  pDirection,
36
51
  pNodeAttributes,
@@ -51,30 +66,45 @@ function transformStates(
51
66
  .map(addExternalSelfTransitions(pStateMachineModel));
52
67
  }
53
68
 
54
- function splitStates(pAST) {
55
- pAST.initialStates = pAST.states.filter(stateTransformers.isType("initial"));
56
- pAST.regularStates = pAST.states.filter(
69
+ /**
70
+ *
71
+ * @param {import("../../../types/state-machine-cat.js").IStateMachine} pStateMachine
72
+ * @returns {import("../../../types/state-machine-cat.js").IStateMachine}
73
+ */
74
+ function splitStates(pStateMachine) {
75
+ pStateMachine.initialStates = pStateMachine.states.filter(
76
+ stateTransformers.isType("initial")
77
+ );
78
+ pStateMachine.regularStates = pStateMachine.states.filter(
57
79
  (pState) =>
58
80
  stateTransformers.isType("regular")(pState) && !pState.statemachine
59
81
  );
60
- pAST.historyStates = pAST.states.filter(stateTransformers.isType("history"));
61
- pAST.deepHistoryStates = pAST.states.filter(
82
+ pStateMachine.historyStates = pStateMachine.states.filter(
83
+ stateTransformers.isType("history")
84
+ );
85
+ pStateMachine.deepHistoryStates = pStateMachine.states.filter(
62
86
  stateTransformers.isType("deephistory")
63
87
  );
64
- pAST.choiceStates = pAST.states.filter(stateTransformers.isType("choice"));
65
- pAST.forkjoinStates = pAST.states.filter(
88
+ pStateMachine.choiceStates = pStateMachine.states.filter(
89
+ stateTransformers.isType("choice")
90
+ );
91
+ pStateMachine.forkjoinStates = pStateMachine.states.filter(
66
92
  stateTransformers.isOneOfTypes(["fork", "join", "forkjoin"])
67
93
  );
68
- pAST.junctionStates = pAST.states.filter(
94
+ pStateMachine.junctionStates = pStateMachine.states.filter(
69
95
  stateTransformers.isType("junction")
70
96
  );
71
- pAST.terminateStates = pAST.states.filter(
97
+ pStateMachine.terminateStates = pStateMachine.states.filter(
72
98
  stateTransformers.isType("terminate")
73
99
  );
74
- pAST.finalStates = pAST.states.filter(stateTransformers.isType("final"));
75
- pAST.compositeStates = pAST.states.filter((pState) => pState.statemachine);
100
+ pStateMachine.finalStates = pStateMachine.states.filter(
101
+ stateTransformers.isType("final")
102
+ );
103
+ pStateMachine.compositeStates = pStateMachine.states.filter(
104
+ (pState) => pState.statemachine
105
+ );
76
106
 
77
- return pAST;
107
+ return pStateMachine;
78
108
  }
79
109
 
80
110
  function addEndTypes(pStateMachineModel) {
@@ -105,16 +135,23 @@ function addCompositeSelfFlag(pStateMachineModel) {
105
135
  };
106
136
  }
107
137
 
108
- function nameTransition(pTrans) {
109
- pTrans.name = `tr_${pTrans.from}_${pTrans.to}_${gCounter.nextAsString()}`;
138
+ function nameTransition(pTransition) {
139
+ pTransition.name = `tr_${pTransition.from}_${
140
+ pTransition.to
141
+ }_${gCounter.nextAsString()}`;
110
142
 
111
- if (Boolean(pTrans.note)) {
112
- pTrans.noteName = `note_${pTrans.name}`;
143
+ if (Boolean(pTransition.note)) {
144
+ pTransition.noteName = `note_${pTransition.name}`;
113
145
  }
114
146
 
115
- return pTrans;
147
+ return pTransition;
116
148
  }
117
149
 
150
+ /**
151
+ * @param {StateMachineModel} pStateMachineModel
152
+ * @param {string} pDirection
153
+ * @returns {import("../../../types/state-machine-cat.js").ITransition}
154
+ */
118
155
  function transformTransitions(pStateMachineModel, pDirection) {
119
156
  return pStateMachineModel.flattenedTransitions
120
157
  .map(nameTransition)
@@ -126,37 +163,38 @@ function transformTransitions(pStateMachineModel, pDirection) {
126
163
  .map(transitionTransformers.addPorts(pDirection));
127
164
  }
128
165
 
129
- export default (pAST, pOptions) => {
166
+ /** @type {import("../../../types/state-machine-cat.js").StringRenderFunctionType} */
167
+ export default (pStateMachine, pOptions) => {
130
168
  pOptions = pOptions || {};
131
169
  gCounter = new Counter();
132
170
 
133
- let lAST = cloneDeep(pAST);
134
- const lStateMachineModel = new StateMachineModel(lAST);
171
+ let lStateMachine = cloneDeep(pStateMachine);
172
+ const lStateMachineModel = new StateMachineModel(lStateMachine);
135
173
 
136
- lAST.transitions = transformTransitions(
174
+ lStateMachine.transitions = transformTransitions(
137
175
  lStateMachineModel,
138
176
  pOptions.direction
139
177
  );
140
178
 
141
- lAST.states = transformStates(
142
- lAST.states,
179
+ lStateMachine.states = transformStates(
180
+ lStateMachine.states,
143
181
  pOptions.direction,
144
182
  pOptions.dotNodeAttrs,
145
183
  lStateMachineModel
146
184
  );
147
185
 
148
- lAST = splitStates(lAST);
186
+ lStateMachine = splitStates(lStateMachine);
149
187
 
150
- lAST.graphAttributes = attributebuilder.buildGraphAttributes(
188
+ lStateMachine.graphAttributes = attributebuilder.buildGraphAttributes(
151
189
  options.getOptionValue(pOptions, "engine"),
152
190
  options.getOptionValue(pOptions, "direction"),
153
191
  pOptions.dotGraphAttrs
154
192
  );
155
- lAST.nodeAttributes = attributebuilder.buildNodeAttributes(
193
+ lStateMachine.nodeAttributes = attributebuilder.buildNodeAttributes(
156
194
  pOptions.dotNodeAttrs
157
195
  );
158
- lAST.edgeAttributes = attributebuilder.buildEdgeAttributes(
196
+ lStateMachine.edgeAttributes = attributebuilder.buildEdgeAttributes(
159
197
  pOptions.dotEdgeAttrs
160
198
  );
161
- return renderDotFromAST(lAST);
199
+ return renderDotFromAST(lStateMachine);
162
200
  };
@@ -1,3 +1,4 @@
1
+ /** @type {any} - the Handlebars delivered types don't seem to cover everythint in handlebars ...*/
1
2
  const Handlebars = require("handlebars/dist/handlebars.runtime.js");
2
3
  // eslint-disable-next-line import/no-unassigned-import
3
4
  require("./dot.template.js");
@@ -15,34 +16,55 @@ Handlebars.registerHelper("stateSection", (pStateMachine) =>
15
16
  );
16
17
 
17
18
  // TODO: duplicate from the one in state-transformers.js
19
+ /**
20
+ *
21
+ * @param {string} pString
22
+ * @returns {(pState: import("../../../types/state-machine-cat.js").IState) => Boolean}
23
+ */
18
24
  function isType(pString) {
19
25
  return (pState) => pState.type === pString;
20
26
  }
27
+ /**
28
+ *
29
+ * @param {string[]} pStringArray
30
+ * @returns {(pState: import("../../../types/state-machine-cat.js").IState) => Boolean}
31
+ */
21
32
  // TODO: duplicate from the one in state-transformers.js
22
33
  function isOneOfTypes(pStringArray) {
23
34
  return (pState) => pStringArray.includes(pState.type);
24
35
  }
25
36
 
26
37
  // TODO: duplicate from the one in index.js
27
- function splitStates(pAST) {
28
- pAST.initialStates = pAST.states.filter(isType("initial"));
29
- pAST.regularStates = pAST.states.filter(
38
+ function splitStates(pStateMachine) {
39
+ pStateMachine.initialStates = pStateMachine.states.filter(isType("initial"));
40
+ pStateMachine.regularStates = pStateMachine.states.filter(
30
41
  (pState) => isType("regular")(pState) && !pState.statemachine
31
42
  );
32
- pAST.historyStates = pAST.states.filter(isType("history"));
33
- pAST.deepHistoryStates = pAST.states.filter(isType("deephistory"));
34
- pAST.choiceStates = pAST.states.filter(isType("choice"));
35
- pAST.forkjoinStates = pAST.states.filter(
43
+ pStateMachine.historyStates = pStateMachine.states.filter(isType("history"));
44
+ pStateMachine.deepHistoryStates = pStateMachine.states.filter(
45
+ isType("deephistory")
46
+ );
47
+ pStateMachine.choiceStates = pStateMachine.states.filter(isType("choice"));
48
+ pStateMachine.forkjoinStates = pStateMachine.states.filter(
36
49
  isOneOfTypes(["fork", "join", "forkjoin"])
37
50
  );
38
- pAST.junctionStates = pAST.states.filter(isType("junction"));
39
- pAST.terminateStates = pAST.states.filter(isType("terminate"));
40
- pAST.finalStates = pAST.states.filter(isType("final"));
41
- pAST.compositeStates = pAST.states.filter((pState) => pState.statemachine);
51
+ pStateMachine.junctionStates = pStateMachine.states.filter(
52
+ isType("junction")
53
+ );
54
+ pStateMachine.terminateStates = pStateMachine.states.filter(
55
+ isType("terminate")
56
+ );
57
+ pStateMachine.finalStates = pStateMachine.states.filter(isType("final"));
58
+ pStateMachine.compositeStates = pStateMachine.states.filter(
59
+ (pState) => pState.statemachine
60
+ );
42
61
 
43
- return pAST;
62
+ return pStateMachine;
44
63
  }
45
-
46
- module.exports = function renderDotFromAST(pAST) {
47
- return Handlebars.templates["dot.template.hbs"](pAST);
64
+ /**
65
+ * @param {import("../../../types/state-machine-cat.js").IStateMachine} pStateMachine
66
+ * @returns {string}
67
+ */
68
+ module.exports = function renderDotFromAST(pStateMachine) {
69
+ return Handlebars.templates["dot.template.hbs"](pStateMachine);
48
70
  };
@@ -1,3 +1,4 @@
1
+ import cloneDeep from "lodash/cloneDeep.js";
1
2
  import utl from "./utl.mjs";
2
3
 
3
4
  function isType(pString) {
@@ -8,8 +9,9 @@ function isOneOfTypes(pStringArray) {
8
9
  }
9
10
 
10
11
  function setLabel(pState) {
11
- pState.label = pState.label || pState.name;
12
- return pState;
12
+ const lState = cloneDeep(pState);
13
+ lState.label = pState.label || pState.name;
14
+ return lState;
13
15
  }
14
16
 
15
17
  function nameNote(pState) {
@@ -1,3 +1,9 @@
1
+ // @ts-check
2
+
3
+ /**
4
+ * @param {string} pString
5
+ * @returns {string}
6
+ */
1
7
  function escapeString(pString) {
2
8
  return pString
3
9
  .replace(/\\/g, "\\\\")
@@ -6,6 +12,10 @@ function escapeString(pString) {
6
12
  .concat("\\l");
7
13
  }
8
14
 
15
+ /**
16
+ * @param {string} pString
17
+ * @returns {string}
18
+ */
9
19
  function escapeLabelString(pString) {
10
20
  return pString
11
21
  .replace(/\\/g, "\\\\")
@@ -14,12 +24,22 @@ function escapeLabelString(pString) {
14
24
  .concat(" \\l");
15
25
  }
16
26
 
27
+ /**
28
+ * @param {string} pDirection
29
+ * @returns {boolean}
30
+ */
17
31
  function isVertical(pDirection) {
18
32
  const lDirection = pDirection || "top-down";
19
33
 
20
34
  return lDirection === "top-down" || lDirection === "bottom-top";
21
35
  }
22
36
 
37
+ /**
38
+ *
39
+ * @param {import("../../state-machine-model.mjs").default} pStateMachineModel
40
+ * @param {import("../../../types/state-machine-cat").ITransition} pTransition
41
+ * @returns {boolean}
42
+ */
23
43
  function isCompositeSelf(pStateMachineModel, pTransition) {
24
44
  return (
25
45
  pTransition.from === pTransition.to &&
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  /* eslint-disable security/detect-object-injection */
2
3
  import has from "lodash/has.js";
3
4
  import smcat from "./smcat/index.js";
@@ -7,8 +8,13 @@ import oldVector from "./vector/vector-with-viz-js.mjs";
7
8
  import scjson from "./scjson/index.mjs";
8
9
  import scxml from "./scxml/index.mjs";
9
10
 
11
+ /**
12
+ *
13
+ * @param {import("../../types/state-machine-cat.js").OutputType} pOutputType
14
+ * @returns {import("../../types/state-machine-cat.js").RenderFunctionType}
15
+ */
10
16
  export default function getRenderFunction(pOutputType) {
11
- const lOutputtype2Renderfunction = {
17
+ const lOutputType2RenderFunction = {
12
18
  smcat,
13
19
  dot,
14
20
  svg: vector,
@@ -24,7 +30,7 @@ export default function getRenderFunction(pOutputType) {
24
30
  scxml,
25
31
  };
26
32
 
27
- return has(lOutputtype2Renderfunction, pOutputType)
28
- ? lOutputtype2Renderfunction[pOutputType]
33
+ return has(lOutputType2RenderFunction, pOutputType)
34
+ ? lOutputType2RenderFunction[pOutputType]
29
35
  : (pX) => pX;
30
36
  }
@@ -7,7 +7,7 @@ import scjson from "./scjson/index.mjs";
7
7
  import scxml from "./scxml/index.mjs";
8
8
 
9
9
  export default function getRenderFunction(pOutputType) {
10
- const lOutputtype2Renderfunction = {
10
+ const lOutputType2RenderFunction = {
11
11
  smcat,
12
12
  dot,
13
13
  svg,
@@ -16,7 +16,7 @@ export default function getRenderFunction(pOutputType) {
16
16
  scxml,
17
17
  };
18
18
 
19
- return has(lOutputtype2Renderfunction, pOutputType)
20
- ? lOutputtype2Renderfunction[pOutputType]
19
+ return has(lOutputType2RenderFunction, pOutputType)
20
+ ? lOutputType2RenderFunction[pOutputType]
21
21
  : (pX) => pX;
22
22
  }
@@ -137,6 +137,12 @@ function findInitialStateName(pStateMachine, pInitialPseudoStateName) {
137
137
  return lReturnValue;
138
138
  }
139
139
 
140
+ /**
141
+ * @param {import("../../..").IStateMachine} pStateMachine
142
+ * @param {import("../../..").IRenderOptions} [_pOptions]
143
+ * @param {import("../../..").ITransition[]} [pTransitions] (no need to specify - used in recursion)
144
+ * @returns {any} TODO: scjson data structure
145
+ */
140
146
  export default function render(pStateMachine, _pOptions, pTransitions) {
141
147
  const lInitialPseudoStateName = findInitialPseudoStateName(pStateMachine);
142
148
  const lInitialStateName = findInitialStateName(
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  /*
2
3
  * In the XML spec we read: https://www.w3.org/TR/xml/#NT-Name:
3
4
  *
@@ -18,6 +19,11 @@ const NAME_CHAR_FORBIDDEN_RE =
18
19
  const START_NAME_CHAR_FORBIDDEN_EXTRA_RE =
19
20
  /[-|.|0-9|\u00B7|\u0300-\u036F|\u203F-\u2040]/g;
20
21
 
22
+ /**
23
+ *
24
+ * @param {string} pCandidateNameTail
25
+ * @returns {string}
26
+ */
21
27
  function makeValidNameChars(pCandidateNameTail) {
22
28
  return pCandidateNameTail.replace(NAME_CHAR_FORBIDDEN_RE, "_");
23
29
  }
@@ -25,7 +31,7 @@ function makeValidNameChars(pCandidateNameTail) {
25
31
  /**
26
32
  * if it's an invalid NameStartChar but a valid NameChar smack a '_' in front of it
27
33
  * if it's an invalid NameChar as well - run it through the makeValidNameChars replacer
28
- * @param {char} pCandidateChar - start char
34
+ * @param {string} pCandidateChar - start char
29
35
  * @returns {string} valid start string
30
36
  */
31
37
  function makeValidNameStartChar(pCandidateChar) {
@@ -1,6 +1,8 @@
1
+ // @ts-check
1
2
  import ast2scjson from "../scjson/index.mjs";
2
3
  import renderFomSCJSON from "./render-from-scjson.js";
3
4
 
5
+ /** @type {import("../../..").StringRenderFunctionType} */
4
6
  export default function renderSCXML(pStateMachine) {
5
7
  return renderFomSCJSON(ast2scjson(pStateMachine));
6
8
  }
@@ -1,13 +1,25 @@
1
+ // @ts-check
2
+ /** @type {any} - the type definitions for Handlebars don't match what we're actually using - hence this override*/
1
3
  const Handlebars = require("handlebars/dist/handlebars.runtime.js");
2
4
  const cloneDeep = require("lodash/cloneDeep.js");
3
5
 
4
6
  // eslint-disable-next-line import/no-unassigned-import
5
7
  require("./smcat.template.js");
6
8
 
9
+ /**
10
+ * @typedef {{hasExtendedAttributes?: boolean} & import("../../../types/state-machine-cat.js").IState} IExtendedState
11
+ * @typedef {{actions: string;} & Omit<IExtendedState, "actions">} IFlattenedActionsState
12
+ */
13
+
7
14
  const NAME_QUOTABLE = /;|,|{| |\[/;
8
15
  const ACTIONS_QUOTABLE = /;|,|{/;
9
16
  const LABEL_QUOTABLE = /;|{/;
10
17
 
18
+ /**
19
+ * @param {RegExp} pRegExp
20
+ * @param {string} pString
21
+ * @returns {string}
22
+ */
11
23
  function quoteIfNecessary(pRegExp, pString) {
12
24
  return pRegExp.test(pString) ? `"${pString}"` : pString;
13
25
  }
@@ -17,20 +29,31 @@ Handlebars.registerPartial(
17
29
  Handlebars.templates["smcat.template.hbs"]
18
30
  );
19
31
 
32
+ /**
33
+ * @param {string} pString
34
+ * @returns {string}
35
+ */
20
36
  function formatActionType(pString) {
21
37
  return pString === "activity" ? "" : `${pString}/ `;
22
38
  }
23
39
 
40
+ /**
41
+ * @param {IExtendedState} pState
42
+ * @returns {IFlattenedActionsState}
43
+ */
24
44
  function flattenActions(pState) {
25
- const lReturnValue = { ...pState };
26
-
27
- lReturnValue.actions = (pState.actions || [])
28
- .map((pAction) => `${formatActionType(pAction.type)}${pAction.body}`)
29
- .join("\n ");
30
-
31
- return lReturnValue;
45
+ return {
46
+ ...pState,
47
+ actions: (pState.actions || [])
48
+ .map((pAction) => `${formatActionType(pAction.type)}${pAction.body}`)
49
+ .join("\n "),
50
+ };
32
51
  }
33
52
 
53
+ /**
54
+ * @param {IExtendedState} pState
55
+ * @returns {IExtendedState}
56
+ */
34
57
  /* eslint complexity:0 */
35
58
  function flagExtendedStateAttributes(pState) {
36
59
  if (
@@ -40,19 +63,27 @@ function flagExtendedStateAttributes(pState) {
40
63
  Object.prototype.hasOwnProperty.call(pState, "active") ||
41
64
  Object.prototype.hasOwnProperty.call(pState, "class")
42
65
  ) {
66
+ // note & fixme: mutating a parameter here
43
67
  pState.hasExtendedAttributes = true;
44
68
  }
45
69
  return pState;
46
70
  }
47
71
 
48
- function transformStates(pStates, pDirection) {
72
+ /**
73
+ * @param {import("../../../types/state-machine-cat.js").IState[]} pStates
74
+ * @returns {IFlattenedActionsState[]}
75
+ */
76
+ function transformStates(pStates) {
49
77
  pStates
50
78
  .map(flagExtendedStateAttributes)
51
79
  .filter((pState) => pState.statemachine)
52
80
  .forEach((pState) => {
81
+ // @ts-expect-error because of the filter above the statemachine is
82
+ // sure to exist, although TS currently doesn't detect this.
83
+ // also fixme: mutating a parameter here
53
84
  pState.statemachine.states = transformStates(
54
- pState.statemachine.states,
55
- pDirection
85
+ // @ts-expect-error - see above
86
+ pState.statemachine.states
56
87
  );
57
88
  });
58
89
 
@@ -86,10 +117,13 @@ Handlebars.registerHelper("quotifyActions", (pItem) =>
86
117
  quoteIfNecessary(ACTIONS_QUOTABLE, pItem)
87
118
  );
88
119
 
89
- module.exports = function renderSmcat(pAST) {
120
+ /** @type {import("../../../types/state-machine-cat.js").StringRenderFunctionType} */
121
+ module.exports = function renderSmcat(pStateMachine) {
90
122
  return Handlebars.templates["smcat.template.hbs"]({
91
- ...pAST,
92
- states: transformStates(cloneDeep(pAST.states)),
93
- transitions: transformTransitions(cloneDeep(pAST.transitions || [])),
123
+ ...pStateMachine,
124
+ states: transformStates(cloneDeep(pStateMachine.states)),
125
+ transitions: transformTransitions(
126
+ cloneDeep(pStateMachine.transitions || [])
127
+ ),
94
128
  });
95
129
  };
@@ -11,7 +11,7 @@ const DEFAULT_OPTIONS = {
11
11
  * the result
12
12
  *
13
13
  * @param {string} pDot The dot program as a string
14
- * @param {object} pOptions
14
+ * @param {{exec: string, format: import("../../../types/state-machine-cat").OutputType}} pOptions
15
15
  * exec: the path to the executable to run. Default: 'dot'
16
16
  * @return {string} the dot program converted into an svg
17
17
  * @throws {Error} when something ontowards has happened (executable not found, erroneous dot program)
@@ -10,8 +10,9 @@ const DEFAULT_INDENT = 2;
10
10
  const DOGMATIC_CONSOLE_WIDTH = 78;
11
11
  const VIZ_JS_UNSUPPORTED_OUTPUT_FORMATS = ["pdf", "png"];
12
12
 
13
- export default (pAST, pOptions) => {
14
- const lDotProgram = ast2dot(pAST, pOptions);
13
+ /** @type {import("../../../types/state-machine-cat.js").StringRenderFunctionType} */
14
+ export default (pStateMachine, pOptions) => {
15
+ const lDotProgram = ast2dot(pStateMachine, pOptions);
15
16
  const lDotOptions = {
16
17
  engine: options.getOptionValue(pOptions, "engine"),
17
18
  format: options.getOptionValue(pOptions, "outputType"),
@@ -8,8 +8,9 @@ const OUTPUT_TYPE2FORMAT = {
8
8
  oldeps: "eps",
9
9
  };
10
10
 
11
- export default (pAST, pOptions) =>
12
- viz(ast2dot(pAST, pOptions), {
11
+ /** @type {import("../../../types/state-machine-cat.js").StringRenderFunctionType} */
12
+ export default (pStateMachine, pOptions) =>
13
+ viz(ast2dot(pStateMachine, pOptions), {
13
14
  engine: options.getOptionValue(pOptions, "engine"),
14
15
  format:
15
16
  OUTPUT_TYPE2FORMAT[options.getOptionValue(pOptions, "outputType")] ||