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.
- package/README.md +1 -1
- package/bin/smcat.mjs +5 -0
- package/dist/commonjs/bundle.js +64 -64
- package/package.json +40 -69
- package/src/cli/actions.mjs +9 -0
- package/src/cli/file-name-to-stream.mjs +5 -6
- package/src/cli/make-description.mjs +9 -0
- package/src/cli/normalize.mjs +100 -47
- package/src/cli/validations.mjs +27 -1
- package/src/index-node.mjs +15 -47
- package/src/index.mjs +9 -9
- package/src/options.mjs +19 -13
- package/src/parse/index.mjs +13 -0
- package/src/parse/parser-helpers.mjs +70 -6
- package/src/parse/scxml/index.mjs +72 -20
- package/src/parse/scxml/normalize-machine.mjs +27 -21
- package/src/render/dot/README.md +12 -0
- package/src/render/dot/attributebuilder.mjs +7 -0
- package/src/render/dot/counter.mjs +13 -0
- package/src/render/dot/index.mjs +66 -28
- package/src/render/dot/render-dot-from-ast.js +37 -15
- package/src/render/dot/state-transformers.mjs +4 -2
- package/src/render/dot/utl.mjs +20 -0
- package/src/render/index-node.mjs +9 -3
- package/src/render/index.mjs +3 -3
- package/src/render/scjson/index.mjs +6 -0
- package/src/render/scjson/make-valid-xml-name.mjs +7 -1
- package/src/render/scxml/index.mjs +2 -0
- package/src/render/smcat/index.js +48 -14
- package/src/render/vector/dot-to-vector-native.mjs +1 -1
- package/src/render/vector/vector-native-dot-with-fallback.mjs +3 -2
- package/src/render/vector/vector-with-viz-js.mjs +3 -2
- package/src/state-machine-model.mjs +46 -4
- package/src/transform/desugar.mjs +67 -18
- package/src/transform/utl.mjs +8 -0
- package/src/version.mjs +1 -1
- 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);
|
package/src/render/dot/index.mjs
CHANGED
|
@@ -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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
61
|
-
|
|
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
|
-
|
|
65
|
-
|
|
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
|
-
|
|
94
|
+
pStateMachine.junctionStates = pStateMachine.states.filter(
|
|
69
95
|
stateTransformers.isType("junction")
|
|
70
96
|
);
|
|
71
|
-
|
|
97
|
+
pStateMachine.terminateStates = pStateMachine.states.filter(
|
|
72
98
|
stateTransformers.isType("terminate")
|
|
73
99
|
);
|
|
74
|
-
|
|
75
|
-
|
|
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
|
|
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(
|
|
109
|
-
|
|
138
|
+
function nameTransition(pTransition) {
|
|
139
|
+
pTransition.name = `tr_${pTransition.from}_${
|
|
140
|
+
pTransition.to
|
|
141
|
+
}_${gCounter.nextAsString()}`;
|
|
110
142
|
|
|
111
|
-
if (Boolean(
|
|
112
|
-
|
|
143
|
+
if (Boolean(pTransition.note)) {
|
|
144
|
+
pTransition.noteName = `note_${pTransition.name}`;
|
|
113
145
|
}
|
|
114
146
|
|
|
115
|
-
return
|
|
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
|
-
|
|
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
|
|
134
|
-
const lStateMachineModel = new StateMachineModel(
|
|
171
|
+
let lStateMachine = cloneDeep(pStateMachine);
|
|
172
|
+
const lStateMachineModel = new StateMachineModel(lStateMachine);
|
|
135
173
|
|
|
136
|
-
|
|
174
|
+
lStateMachine.transitions = transformTransitions(
|
|
137
175
|
lStateMachineModel,
|
|
138
176
|
pOptions.direction
|
|
139
177
|
);
|
|
140
178
|
|
|
141
|
-
|
|
142
|
-
|
|
179
|
+
lStateMachine.states = transformStates(
|
|
180
|
+
lStateMachine.states,
|
|
143
181
|
pOptions.direction,
|
|
144
182
|
pOptions.dotNodeAttrs,
|
|
145
183
|
lStateMachineModel
|
|
146
184
|
);
|
|
147
185
|
|
|
148
|
-
|
|
186
|
+
lStateMachine = splitStates(lStateMachine);
|
|
149
187
|
|
|
150
|
-
|
|
188
|
+
lStateMachine.graphAttributes = attributebuilder.buildGraphAttributes(
|
|
151
189
|
options.getOptionValue(pOptions, "engine"),
|
|
152
190
|
options.getOptionValue(pOptions, "direction"),
|
|
153
191
|
pOptions.dotGraphAttrs
|
|
154
192
|
);
|
|
155
|
-
|
|
193
|
+
lStateMachine.nodeAttributes = attributebuilder.buildNodeAttributes(
|
|
156
194
|
pOptions.dotNodeAttrs
|
|
157
195
|
);
|
|
158
|
-
|
|
196
|
+
lStateMachine.edgeAttributes = attributebuilder.buildEdgeAttributes(
|
|
159
197
|
pOptions.dotEdgeAttrs
|
|
160
198
|
);
|
|
161
|
-
return renderDotFromAST(
|
|
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(
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
|
62
|
+
return pStateMachine;
|
|
44
63
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
12
|
-
|
|
12
|
+
const lState = cloneDeep(pState);
|
|
13
|
+
lState.label = pState.label || pState.name;
|
|
14
|
+
return lState;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
function nameNote(pState) {
|
package/src/render/dot/utl.mjs
CHANGED
|
@@ -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
|
|
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(
|
|
28
|
-
?
|
|
33
|
+
return has(lOutputType2RenderFunction, pOutputType)
|
|
34
|
+
? lOutputType2RenderFunction[pOutputType]
|
|
29
35
|
: (pX) => pX;
|
|
30
36
|
}
|
package/src/render/index.mjs
CHANGED
|
@@ -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
|
|
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(
|
|
20
|
-
?
|
|
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 {
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
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
|
-
|
|
55
|
-
|
|
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
|
-
|
|
120
|
+
/** @type {import("../../../types/state-machine-cat.js").StringRenderFunctionType} */
|
|
121
|
+
module.exports = function renderSmcat(pStateMachine) {
|
|
90
122
|
return Handlebars.templates["smcat.template.hbs"]({
|
|
91
|
-
...
|
|
92
|
-
states: transformStates(cloneDeep(
|
|
93
|
-
transitions: transformTransitions(
|
|
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 {
|
|
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
|
-
|
|
14
|
-
|
|
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
|
-
|
|
12
|
-
|
|
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")] ||
|