state-machine-cat 10.1.2 → 10.1.3
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/bin/smcat.mjs +5 -0
- package/dist/commonjs/bundle.js +64 -64
- package/package.json +20 -25
- 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 +79 -41
- 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 +40 -1
- package/src/parse/scxml/normalize-machine.mjs +1 -1
- 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 +3 -1
- 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
package/src/parse/index.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
import Ajv from "ajv";
|
|
2
3
|
import options from "../options.mjs";
|
|
3
4
|
import { parse as parseSmCat } from "./smcat/smcat-parser.mjs";
|
|
@@ -6,6 +7,11 @@ import $schema from "./smcat-ast.schema.mjs";
|
|
|
6
7
|
|
|
7
8
|
const ajv = new Ajv();
|
|
8
9
|
|
|
10
|
+
/**
|
|
11
|
+
* @param {typeof $schema} pSchema
|
|
12
|
+
* @param {any} pObject
|
|
13
|
+
* @throws {Error}
|
|
14
|
+
*/
|
|
9
15
|
function validateAgainstSchema(pSchema, pObject) {
|
|
10
16
|
if (!ajv.validate(pSchema, pObject)) {
|
|
11
17
|
throw new Error(
|
|
@@ -15,12 +21,18 @@ function validateAgainstSchema(pSchema, pObject) {
|
|
|
15
21
|
}
|
|
16
22
|
|
|
17
23
|
export default {
|
|
24
|
+
/**
|
|
25
|
+
* @param {string|import("../../types/state-machine-cat").IStateMachine} pScript
|
|
26
|
+
* @param {import("../../types/state-machine-cat").IRenderOptions} pOptions
|
|
27
|
+
* @returns {import("../../types/state-machine-cat").IStateMachine}
|
|
28
|
+
*/
|
|
18
29
|
getAST(pScript, pOptions) {
|
|
19
30
|
let lReturnValue = pScript;
|
|
20
31
|
|
|
21
32
|
if (options.getOptionValue(pOptions, "inputType") === "smcat") {
|
|
22
33
|
lReturnValue = parseSmCat(pScript);
|
|
23
34
|
} else if (options.getOptionValue(pOptions, "inputType") === "scxml") {
|
|
35
|
+
// @ts-expect-error inputType scxml => it's a string
|
|
24
36
|
lReturnValue = parseSCXML(pScript);
|
|
25
37
|
} else if (typeof pScript === "string") {
|
|
26
38
|
// json
|
|
@@ -29,6 +41,7 @@ export default {
|
|
|
29
41
|
|
|
30
42
|
validateAgainstSchema($schema, lReturnValue);
|
|
31
43
|
|
|
44
|
+
// @ts-expect-error by here lReturnValue is bound to be an IStateMachine
|
|
32
45
|
return lReturnValue;
|
|
33
46
|
},
|
|
34
47
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
/* eslint-disable security/detect-object-injection */
|
|
2
3
|
import StateMachineModel from "../state-machine-model.mjs";
|
|
3
4
|
|
|
@@ -6,10 +7,20 @@ const TRIGGER_RE_AS_A_STRING =
|
|
|
6
7
|
/* eslint security/detect-non-literal-regexp:0 */
|
|
7
8
|
const TRIGGER_RE = new RegExp(TRIGGER_RE_AS_A_STRING);
|
|
8
9
|
|
|
10
|
+
/**
|
|
11
|
+
* @param {string[]} pKnownStateNames
|
|
12
|
+
* @param {string} pName
|
|
13
|
+
* @returns {boolean}
|
|
14
|
+
*/
|
|
9
15
|
function stateExists(pKnownStateNames, pName) {
|
|
10
16
|
return pKnownStateNames.includes(pName);
|
|
11
17
|
}
|
|
12
|
-
|
|
18
|
+
/**
|
|
19
|
+
* @type {{
|
|
20
|
+
* re:RegExp;
|
|
21
|
+
* stateType: import("../../types/state-machine-cat.js").StateType;
|
|
22
|
+
* }[]}
|
|
23
|
+
*/
|
|
13
24
|
const RE2STATE_TYPE = [
|
|
14
25
|
{
|
|
15
26
|
re: /initial/,
|
|
@@ -45,11 +56,19 @@ function matches(pName) {
|
|
|
45
56
|
return (pEntry) => pEntry.re.test(pName);
|
|
46
57
|
}
|
|
47
58
|
|
|
59
|
+
/**
|
|
60
|
+
* @param {string} pName
|
|
61
|
+
* @returns {import("../../types/state-machine-cat.js").StateType}
|
|
62
|
+
*/
|
|
48
63
|
function getStateType(pName) {
|
|
49
64
|
return (RE2STATE_TYPE.find(matches(pName)) || { stateType: "regular" })
|
|
50
65
|
.stateType;
|
|
51
66
|
}
|
|
52
67
|
|
|
68
|
+
/**
|
|
69
|
+
* @param {string} pName
|
|
70
|
+
* @returns {import("../../types/state-machine-cat.js").IState}
|
|
71
|
+
*/
|
|
53
72
|
function initState(pName) {
|
|
54
73
|
return {
|
|
55
74
|
name: pName,
|
|
@@ -57,30 +76,45 @@ function initState(pName) {
|
|
|
57
76
|
};
|
|
58
77
|
}
|
|
59
78
|
|
|
79
|
+
/**
|
|
80
|
+
* @param {import("../../types/state-machine-cat.js").IState} pState
|
|
81
|
+
* @returns {boolean}
|
|
82
|
+
*/
|
|
60
83
|
function isComposite(pState) {
|
|
61
84
|
return Boolean(pState.statemachine);
|
|
62
85
|
}
|
|
63
86
|
|
|
87
|
+
/**
|
|
88
|
+
* @param {import("../../types/state-machine-cat.js").IStateMachine|undefined} pStateMachine
|
|
89
|
+
* @returns {string[]}
|
|
90
|
+
*/
|
|
64
91
|
function getAlreadyDeclaredStates(pStateMachine) {
|
|
65
|
-
const lStates = pStateMachine
|
|
92
|
+
const lStates = pStateMachine?.states ?? [];
|
|
66
93
|
|
|
67
94
|
return lStates.filter(isComposite).reduce(
|
|
68
95
|
(pAllStateNames, pThisState) =>
|
|
69
96
|
pAllStateNames.concat(getAlreadyDeclaredStates(pThisState.statemachine)),
|
|
70
|
-
lStates.map((
|
|
97
|
+
lStates.map(({ name }) => name)
|
|
71
98
|
);
|
|
72
99
|
}
|
|
73
100
|
|
|
101
|
+
/**
|
|
102
|
+
* @param {import("../../types/state-machine-cat.js").IStateMachine} pStateMachine
|
|
103
|
+
* @param {string[]} pKnownStateNames
|
|
104
|
+
* @returns {import("../../types/state-machine-cat.js").IState[]}
|
|
105
|
+
*/
|
|
74
106
|
function extractUndeclaredStates(pStateMachine, pKnownStateNames) {
|
|
75
107
|
pKnownStateNames = pKnownStateNames
|
|
76
108
|
? pKnownStateNames
|
|
77
109
|
: getAlreadyDeclaredStates(pStateMachine);
|
|
78
110
|
|
|
79
|
-
pStateMachine.states = pStateMachine
|
|
80
|
-
const lTransitions = pStateMachine
|
|
111
|
+
pStateMachine.states = pStateMachine?.states ?? [];
|
|
112
|
+
const lTransitions = pStateMachine?.transitions ?? [];
|
|
81
113
|
|
|
82
114
|
pStateMachine.states.filter(isComposite).forEach((pState) => {
|
|
115
|
+
// @ts-expect-error isComposite guarantees the statemachine attribute exists, TS doesn't understand that yet, though
|
|
83
116
|
pState.statemachine.states = extractUndeclaredStates(
|
|
117
|
+
// @ts-expect-error isComposite guarantees the statemachine attribute exists, TS doesn't understand that yet, though
|
|
84
118
|
pState.statemachine,
|
|
85
119
|
pKnownStateNames
|
|
86
120
|
);
|
|
@@ -99,7 +133,13 @@ function extractUndeclaredStates(pStateMachine, pKnownStateNames) {
|
|
|
99
133
|
return pStateMachine.states;
|
|
100
134
|
}
|
|
101
135
|
|
|
136
|
+
/**
|
|
137
|
+
* @param {number} pInComingCount
|
|
138
|
+
* @param {number} pOutGoingCount
|
|
139
|
+
* @returns {import("../../types/state-machine-cat.js").StateType}
|
|
140
|
+
*/
|
|
102
141
|
function classifyForkJoin(pInComingCount, pOutGoingCount) {
|
|
142
|
+
/** @type {import("../../types/state-machine-cat.js").StateType} */
|
|
103
143
|
let lReturnValue = "junction";
|
|
104
144
|
|
|
105
145
|
if (pInComingCount <= 1 && pOutGoingCount > 1) {
|
|
@@ -112,10 +152,16 @@ function classifyForkJoin(pInComingCount, pOutGoingCount) {
|
|
|
112
152
|
return lReturnValue;
|
|
113
153
|
}
|
|
114
154
|
|
|
155
|
+
/**
|
|
156
|
+
* @param {import("../../types/state-machine-cat.js").IStateMachine} pStateMachine
|
|
157
|
+
* @param {StateMachineModel} pFlattenedStateMachineModel
|
|
158
|
+
* @returns {import("../../types/state-machine-cat.js").IStateMachine}
|
|
159
|
+
*/
|
|
115
160
|
function classifyForkJoins(
|
|
116
161
|
pStateMachine,
|
|
117
162
|
pFlattenedStateMachineModel = new StateMachineModel(pStateMachine)
|
|
118
163
|
) {
|
|
164
|
+
// TODO: mutates parameter
|
|
119
165
|
pStateMachine.states = pStateMachine.states.map((pState) => {
|
|
120
166
|
if (pState.type === "forkjoin" && !pState.typeExplicitlySet) {
|
|
121
167
|
const lInComingCount = pFlattenedStateMachineModel.findTransitionsByTo(
|
|
@@ -139,6 +185,11 @@ function classifyForkJoins(
|
|
|
139
185
|
return pStateMachine;
|
|
140
186
|
}
|
|
141
187
|
|
|
188
|
+
/**
|
|
189
|
+
* @param {import("../../types/state-machine-cat.js").IState} pStateOne
|
|
190
|
+
* @param {import("../../types/state-machine-cat.js").IState} pStateTwo
|
|
191
|
+
* @returns {boolean}
|
|
192
|
+
*/
|
|
142
193
|
function stateEqual(pStateOne, pStateTwo) {
|
|
143
194
|
return pStateOne.name === pStateTwo.name;
|
|
144
195
|
}
|
|
@@ -158,12 +209,17 @@ function uniq(pArray, pEqualFunction) {
|
|
|
158
209
|
}, []);
|
|
159
210
|
}
|
|
160
211
|
|
|
212
|
+
/**
|
|
213
|
+
* @param {String} pString
|
|
214
|
+
* @returns {{event?: string; cond?: string; action?: string}}
|
|
215
|
+
*/
|
|
161
216
|
function parseTransitionExpression(pString) {
|
|
162
217
|
// eslint-disable-next-line security/detect-unsafe-regex, unicorn/no-unsafe-regex
|
|
163
218
|
const lTransitionExpressionRe = /([^[/]+)?(\[[^\]]+\])?[^/]*(\/.+)?/;
|
|
164
219
|
const lReturnValue = {};
|
|
165
220
|
|
|
166
|
-
|
|
221
|
+
/** @type {RegExpMatchArray} */
|
|
222
|
+
// @ts-expect-error match has no fallback because lTransitionExpressionRe will match
|
|
167
223
|
// any string (every part is optional)
|
|
168
224
|
const lMatchResult = pString.match(lTransitionExpressionRe);
|
|
169
225
|
const lEventPos = 1;
|
|
@@ -195,6 +251,10 @@ function setIfNotEmpty(pObject, pProperty, pValue) {
|
|
|
195
251
|
setIf(pObject, pProperty, pValue, (pX) => pX && pX.length > 0);
|
|
196
252
|
}
|
|
197
253
|
|
|
254
|
+
/**
|
|
255
|
+
* @param {string} pActivityCandidate
|
|
256
|
+
* @returns {{type: string; body: string}}
|
|
257
|
+
*/
|
|
198
258
|
function extractAction(pActivityCandidate) {
|
|
199
259
|
const lMatch = pActivityCandidate.match(TRIGGER_RE);
|
|
200
260
|
const lTypePos = 1;
|
|
@@ -212,6 +272,10 @@ function extractAction(pActivityCandidate) {
|
|
|
212
272
|
};
|
|
213
273
|
}
|
|
214
274
|
|
|
275
|
+
/**
|
|
276
|
+
* @param {string} pString
|
|
277
|
+
* @returns {{type: string; body: string}[]}
|
|
278
|
+
*/
|
|
215
279
|
function extractActions(pString) {
|
|
216
280
|
return pString
|
|
217
281
|
.split(/\n\s*/g)
|
|
@@ -26,6 +26,11 @@ function extractActionsFromInvokes(pInvokeTriggers) {
|
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* @param {import("./scxml").ISXCMLState} pState
|
|
31
|
+
* @returns {{type: string; body: string;}[]}
|
|
32
|
+
*/
|
|
33
|
+
|
|
29
34
|
function deriveActions(pState) {
|
|
30
35
|
let lReturnValue = [];
|
|
31
36
|
|
|
@@ -43,11 +48,20 @@ function deriveActions(pState) {
|
|
|
43
48
|
return lReturnValue;
|
|
44
49
|
}
|
|
45
50
|
|
|
51
|
+
/**
|
|
52
|
+
* @param {string} pType
|
|
53
|
+
* @param {import("./scxml").ISXCMLState} pState
|
|
54
|
+
* @returns {import("../../../types/state-machine-cat").StateType}
|
|
55
|
+
*/
|
|
46
56
|
function deriveStateType(pType, pState) {
|
|
47
57
|
return pType === "history" && pState.type === "deep" ? "deephistory" : pType;
|
|
48
58
|
}
|
|
49
59
|
|
|
50
60
|
function mapState(pType) {
|
|
61
|
+
/**
|
|
62
|
+
* @param {import("./scxml").ISXCMLState} pState
|
|
63
|
+
* @return {import("../../../types/state-machine-cat").IState}
|
|
64
|
+
*/
|
|
51
65
|
return (pState) => {
|
|
52
66
|
const lReturnValue = {
|
|
53
67
|
name: pState.id,
|
|
@@ -73,6 +87,10 @@ function mapState(pType) {
|
|
|
73
87
|
};
|
|
74
88
|
}
|
|
75
89
|
|
|
90
|
+
/**
|
|
91
|
+
* @param {import("./scxml").ISCXMLTransition} pTransition
|
|
92
|
+
* @returns {{event?: string; cond?: string; action?: string; type?: string;}}
|
|
93
|
+
*/
|
|
76
94
|
function extractTransitionAttributesFromObject(pTransition) {
|
|
77
95
|
const lReturnValue = {};
|
|
78
96
|
|
|
@@ -95,6 +113,11 @@ function extractTransitionAttributesFromObject(pTransition) {
|
|
|
95
113
|
return lReturnValue;
|
|
96
114
|
}
|
|
97
115
|
|
|
116
|
+
/**
|
|
117
|
+
*
|
|
118
|
+
* @param {import("./scxml").ISCXMLTransition} pTransition
|
|
119
|
+
* @returns {{action?: string; label?: string;event?: string; cond?: string; type?: string}}
|
|
120
|
+
*/
|
|
98
121
|
function extractTransitionAttributes(pTransition) {
|
|
99
122
|
const lReturnValue = {};
|
|
100
123
|
|
|
@@ -120,7 +143,15 @@ function extractTransitionAttributes(pTransition) {
|
|
|
120
143
|
return lReturnValue;
|
|
121
144
|
}
|
|
122
145
|
|
|
146
|
+
/**
|
|
147
|
+
* @param {import("./scxml").ISXCMLState} pState
|
|
148
|
+
*/
|
|
123
149
|
function reduceTransition(pState) {
|
|
150
|
+
/**
|
|
151
|
+
* @param {import("../../../types/state-machine-cat").ITransition[]} pAllTransitions
|
|
152
|
+
* @param {import("../../../types/state-machine-cat").ITransition} pTransition
|
|
153
|
+
* @returns {import("../../../types/state-machine-cat").ITransition}
|
|
154
|
+
*/
|
|
124
155
|
return (pAllTransitions, pTransition) => {
|
|
125
156
|
// in SCXML spaces denote references to multiple states
|
|
126
157
|
// => split into multiple transitions
|
|
@@ -139,6 +170,10 @@ function reduceTransition(pState) {
|
|
|
139
170
|
};
|
|
140
171
|
}
|
|
141
172
|
|
|
173
|
+
/**
|
|
174
|
+
* @param {import("./scxml").ISXCMLState[]} pStates
|
|
175
|
+
* @returns {import("../../../types/state-machine-cat").ITransition[]}
|
|
176
|
+
*/
|
|
142
177
|
function extractTransitions(pStates) {
|
|
143
178
|
return pStates
|
|
144
179
|
.filter((pState) =>
|
|
@@ -156,6 +191,10 @@ function extractTransitions(pStates) {
|
|
|
156
191
|
);
|
|
157
192
|
}
|
|
158
193
|
|
|
194
|
+
/**
|
|
195
|
+
* @param {import("./scxml").ISCXMLMachine} pMachine
|
|
196
|
+
* @returns {import("../../../types/state-machine-cat").IStateMachine}
|
|
197
|
+
*/
|
|
159
198
|
function mapMachine(pMachine) {
|
|
160
199
|
const lMachine = normalizeMachine(pMachine);
|
|
161
200
|
const lReturnValue = {};
|
|
@@ -181,7 +220,7 @@ function mapMachine(pMachine) {
|
|
|
181
220
|
* Parses SCXML into a state machine AST.
|
|
182
221
|
*
|
|
183
222
|
* @param {string} pSCXMLString The SCXML to parse
|
|
184
|
-
* @returns {IStateMachine} state machine AST
|
|
223
|
+
* @returns {import("../../../types/state-machine-cat").IStateMachine} state machine AST
|
|
185
224
|
*/
|
|
186
225
|
export function parse(pSCXMLString) {
|
|
187
226
|
const lSCXMLString = pSCXMLString.trim();
|
|
@@ -32,7 +32,7 @@ function normalizeInitial(pMachine) {
|
|
|
32
32
|
|
|
33
33
|
if (pMachine.initial) {
|
|
34
34
|
// => it's an xml node. This detection isn't fool proof...;
|
|
35
|
-
// if it's a node but it doesn't have a
|
|
35
|
+
// if it's a node but it doesn't have a transition (which
|
|
36
36
|
// looks like an odd corner case) we won't recognize the
|
|
37
37
|
// initial
|
|
38
38
|
// the initial.id shouldn't occur (not allowed in scxml
|
|
@@ -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) {
|