state-machine-cat 10.1.9 → 10.1.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.
- package/dist/commonjs/bundle.js +1 -1
- package/dist/esm/version.mjs +1 -1
- package/package.json +5 -8
- package/src/cli/attributes-parser.mjs +0 -977
- package/src/parse/scxml/index.mjs +0 -291
- package/src/parse/smcat/smcat-parser.mjs +0 -2744
- package/src/render/dot/README.md +0 -12
- package/src/render/dot/dot.states.template.js +0 -1
- package/src/render/dot/dot.template.js +0 -1
- package/src/render/dot/index.mjs +0 -200
- package/src/render/scxml/render-from-scjson.js +0 -15
- package/src/render/scxml/scxml.states.template.js +0 -1
- package/src/render/scxml/scxml.template.js +0 -1
- package/src/render/smcat/smcat.template.js +0 -1
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-invalid-this */
|
|
2
|
-
/* eslint-disable security/detect-object-injection */
|
|
3
|
-
import fastxml from "fast-xml-parser";
|
|
4
|
-
import he from "he";
|
|
5
|
-
import castArray from "lodash/castArray.js";
|
|
6
|
-
import traverse from "traverse";
|
|
7
|
-
import utl from "../../transform/utl.mjs";
|
|
8
|
-
import parserHelpers from "../parser-helpers.mjs";
|
|
9
|
-
import { normalizeMachine } from "./normalize-machine.mjs";
|
|
10
|
-
|
|
11
|
-
const formatLabel = utl.formatLabel;
|
|
12
|
-
|
|
13
|
-
function extractActions(pState, pActionType) {
|
|
14
|
-
return castArray(pState[pActionType]).map((pAction) => ({
|
|
15
|
-
type: pActionType === "onexit" ? "exit" : "entry",
|
|
16
|
-
body: he.decode(pAction).trim(),
|
|
17
|
-
}));
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function extractActionsFromInvokes(pInvokeTriggers) {
|
|
21
|
-
return castArray(pInvokeTriggers).map((pInvokeTrigger) => {
|
|
22
|
-
const lId = he.decode(pInvokeTrigger.id || "").trim();
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
type: "activity",
|
|
26
|
-
body: lId || he.decode(pInvokeTrigger || "").trim(),
|
|
27
|
-
};
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @param {import("./scxml").INormalizedSCXMLState} pState
|
|
33
|
-
* @returns {any[]}
|
|
34
|
-
*/
|
|
35
|
-
function deriveActions(pState) {
|
|
36
|
-
let lReturnValue = [];
|
|
37
|
-
|
|
38
|
-
if (pState.onentry) {
|
|
39
|
-
lReturnValue = lReturnValue.concat(extractActions(pState, "onentry"));
|
|
40
|
-
}
|
|
41
|
-
if (pState.invoke) {
|
|
42
|
-
lReturnValue = lReturnValue.concat(
|
|
43
|
-
extractActionsFromInvokes(pState.invoke)
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
if (pState.onexit) {
|
|
47
|
-
lReturnValue = lReturnValue.concat(extractActions(pState, "onexit"));
|
|
48
|
-
}
|
|
49
|
-
return lReturnValue;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* @param {import("../../..").StateType} pType
|
|
54
|
-
* @param {import("./scxml").ISCXMLHistoryState} pState
|
|
55
|
-
* @param {any} pState
|
|
56
|
-
* @returns {import("../../..").StateType}
|
|
57
|
-
*/
|
|
58
|
-
function deriveStateType(pType, pState) {
|
|
59
|
-
return pType === "history" && pState.type === "deep" ? "deephistory" : pType;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* @param {import("../../../types/state-machine-cat").StateType} pType
|
|
64
|
-
* @returns {(any) => import("../../..").IState}
|
|
65
|
-
*/
|
|
66
|
-
function mapState(pType) {
|
|
67
|
-
return (pState) => {
|
|
68
|
-
/** @type {import("../../../types/state-machine-cat").IState} */
|
|
69
|
-
const lReturnValue = {
|
|
70
|
-
name: pState.id,
|
|
71
|
-
type: deriveStateType(pType, pState),
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
if (parserHelpers.getStateType(pState.id) !== lReturnValue.type) {
|
|
75
|
-
lReturnValue.typeExplicitlySet = true;
|
|
76
|
-
}
|
|
77
|
-
if (pState.onentry || pState.onexit || pState.invoke) {
|
|
78
|
-
lReturnValue.actions = deriveActions(pState);
|
|
79
|
-
}
|
|
80
|
-
if (
|
|
81
|
-
Object.keys(pState).some((pKey) =>
|
|
82
|
-
["initial", "state", "history", "parallel", "final"].includes(pKey)
|
|
83
|
-
)
|
|
84
|
-
) {
|
|
85
|
-
// recursion, so ...
|
|
86
|
-
// eslint-disable-next-line no-use-before-define
|
|
87
|
-
lReturnValue.statemachine = mapMachine(pState);
|
|
88
|
-
}
|
|
89
|
-
return lReturnValue;
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* @param {import("./scxml").ISCXMLTransition} pTransition
|
|
95
|
-
* @returns {{event?: string; cond?: string; action?: string; type?: string;}}
|
|
96
|
-
*/
|
|
97
|
-
function extractTransitionAttributesFromObject(pTransition) {
|
|
98
|
-
const lReturnValue = {};
|
|
99
|
-
|
|
100
|
-
if (pTransition.event) {
|
|
101
|
-
// SCXML uses spaces to distinguish multiple events
|
|
102
|
-
// the smcat ast uses linebreaks
|
|
103
|
-
lReturnValue.event = pTransition.event.split(/\s+/).join("\n");
|
|
104
|
-
}
|
|
105
|
-
if (pTransition.cond) {
|
|
106
|
-
lReturnValue.cond = pTransition.cond;
|
|
107
|
-
}
|
|
108
|
-
if (pTransition["#text"]) {
|
|
109
|
-
lReturnValue.action = he.decode(pTransition["#text"]).trim();
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (pTransition.type) {
|
|
113
|
-
lReturnValue.type = pTransition.type;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return lReturnValue;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* @param {import("./scxml").ISCXMLTransition} pTransition
|
|
121
|
-
* @returns {{action?: string; label?: string;event?: string; cond?: string; type?: string}}
|
|
122
|
-
*/
|
|
123
|
-
function extractTransitionAttributes(pTransition) {
|
|
124
|
-
const lReturnValue = {};
|
|
125
|
-
|
|
126
|
-
if (typeof pTransition === "string") {
|
|
127
|
-
lReturnValue.action = he.decode(pTransition).trim();
|
|
128
|
-
} else {
|
|
129
|
-
Object.assign(
|
|
130
|
-
lReturnValue,
|
|
131
|
-
extractTransitionAttributesFromObject(pTransition)
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const lLabel = formatLabel(
|
|
136
|
-
lReturnValue.event,
|
|
137
|
-
lReturnValue.cond,
|
|
138
|
-
lReturnValue.action
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
if (lLabel) {
|
|
142
|
-
lReturnValue.label = lLabel;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return lReturnValue;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* @param {import("./scxml").INormalizedSCXMLState} pState
|
|
150
|
-
*/
|
|
151
|
-
function reduceTransition(pState) {
|
|
152
|
-
/**
|
|
153
|
-
* @param {import("./scxml").ISCXMLTransition[]} pAllTransitions
|
|
154
|
-
* @param {import("./scxml").ISCXMLTransition} pTransition
|
|
155
|
-
* @returns {import("../../..").ITransition}
|
|
156
|
-
*/
|
|
157
|
-
return (pAllTransitions, pTransition) => {
|
|
158
|
-
// in SCXML spaces denote references to multiple states
|
|
159
|
-
// => split into multiple transitions
|
|
160
|
-
const lTargets = (pTransition?.target ?? pState.id).split(/\s+/);
|
|
161
|
-
const lTransitionAttributes = extractTransitionAttributes(pTransition);
|
|
162
|
-
|
|
163
|
-
return pAllTransitions.concat(
|
|
164
|
-
lTargets.map((pTarget) => ({
|
|
165
|
-
from: pState.id,
|
|
166
|
-
// a 'target-less transition' is typically
|
|
167
|
-
// a self-transition
|
|
168
|
-
to: pTarget,
|
|
169
|
-
...lTransitionAttributes,
|
|
170
|
-
}))
|
|
171
|
-
);
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* @param {import("./scxml").INormalizedSCXMLState[]} pStates
|
|
177
|
-
* @returns {import("../../../types/state-machine-cat").ITransition[]}
|
|
178
|
-
*/
|
|
179
|
-
function extractTransitions(pStates) {
|
|
180
|
-
return pStates
|
|
181
|
-
.filter((pState) =>
|
|
182
|
-
Object.prototype.hasOwnProperty.call(pState, "transition")
|
|
183
|
-
)
|
|
184
|
-
.reduce(
|
|
185
|
-
(pAllTransitions, pThisState) =>
|
|
186
|
-
pAllTransitions.concat(
|
|
187
|
-
castArray(pThisState.transition).reduce(
|
|
188
|
-
reduceTransition(pThisState),
|
|
189
|
-
[]
|
|
190
|
-
)
|
|
191
|
-
),
|
|
192
|
-
[]
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* @param {any} pSCXMLStateMachine
|
|
198
|
-
* @returns {import("../../..").IStateMachine}
|
|
199
|
-
*/
|
|
200
|
-
function mapMachine(pSCXMLStateMachine) {
|
|
201
|
-
const lNormalizedMachine = normalizeMachine(pSCXMLStateMachine);
|
|
202
|
-
const lReturnValue = {
|
|
203
|
-
states: lNormalizedMachine.initial
|
|
204
|
-
.map(mapState("initial"))
|
|
205
|
-
.concat(lNormalizedMachine.state.map(mapState("regular")))
|
|
206
|
-
.concat(lNormalizedMachine.parallel.map(mapState("parallel")))
|
|
207
|
-
.concat(lNormalizedMachine.history.map(mapState("history")))
|
|
208
|
-
.concat(lNormalizedMachine.final.map(mapState("final"))),
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
const lTransitions = extractTransitions(lNormalizedMachine.initial)
|
|
212
|
-
.concat(extractTransitions(lNormalizedMachine.state))
|
|
213
|
-
.concat(extractTransitions(lNormalizedMachine.parallel));
|
|
214
|
-
|
|
215
|
-
if (lTransitions.length > 0) {
|
|
216
|
-
lReturnValue.transitions = lTransitions;
|
|
217
|
-
}
|
|
218
|
-
return lReturnValue;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* This funky looking replace exists to make the output of the fast-xml-parser
|
|
223
|
-
* backwards compatible with its version 3 that in case of conflicts between
|
|
224
|
-
* attribute names and tag names gave preference to the attribute name (version 4
|
|
225
|
-
* does the opposite). The previous behaviour was undocumented and for fast-xml-parser
|
|
226
|
-
* likely a kind of edge case (normal people probably don't pass an empty attributeNamePrefix).
|
|
227
|
-
*
|
|
228
|
-
* @param {any} pObject
|
|
229
|
-
* @param {string} pAttributeNamePrefix
|
|
230
|
-
* @returns {any} the object, but
|
|
231
|
-
* - with attributes that have the same name as tags in the same parent removed,
|
|
232
|
-
* - attributes that don't have an equally named tag get their key renamed back
|
|
233
|
-
* to the one without the pAttributeNamePrefix
|
|
234
|
-
*/
|
|
235
|
-
function deDuplicateAttributesAndTags(pObject, pAttributeNamePrefix) {
|
|
236
|
-
// - 'traverse' relies on the 'this' property a 'normal' function provides,
|
|
237
|
-
// so this is not an arrow function.
|
|
238
|
-
// - while it looks iffy to have a map function without a return statement
|
|
239
|
-
// it's canonical traverse use (as per https://github.com/ljharb/js-traverse/blob/v0.6.7/README.md)
|
|
240
|
-
// eslint-disable-next-line array-callback-return
|
|
241
|
-
return traverse(pObject).map(function deDuplicate() {
|
|
242
|
-
if (this.key?.startsWith(pAttributeNamePrefix)) {
|
|
243
|
-
const pUnprefixedAttributeName = this.key.slice(
|
|
244
|
-
pAttributeNamePrefix.length
|
|
245
|
-
);
|
|
246
|
-
if (this.parent.keys.includes(pUnprefixedAttributeName)) {
|
|
247
|
-
this.remove();
|
|
248
|
-
} else {
|
|
249
|
-
this.parent.node[pUnprefixedAttributeName] = this.node;
|
|
250
|
-
this.remove();
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Parses SCXML into a state machine AST.
|
|
258
|
-
*
|
|
259
|
-
* @param {string} pSCXMLString The SCXML to parse
|
|
260
|
-
* @returns {import("../../../types/state-machine-cat").IStateMachine} state machine AST
|
|
261
|
-
*/
|
|
262
|
-
export function parse(pSCXMLString) {
|
|
263
|
-
const lTrimmedSCXMLString = pSCXMLString.trim();
|
|
264
|
-
const lAttributeNamePrefix = "@_";
|
|
265
|
-
/** @type {import("./scxml").ISCXMLAsJSON} */
|
|
266
|
-
let lXMLAsJSON = {};
|
|
267
|
-
|
|
268
|
-
const lXMLParser = new fastxml.XMLParser({
|
|
269
|
-
attributeNamePrefix: lAttributeNamePrefix,
|
|
270
|
-
ignoreAttributes: false,
|
|
271
|
-
parseTagValue: true,
|
|
272
|
-
processEntities: false,
|
|
273
|
-
tagValueProcessor: (_pTagName, pTagValue) => he.decode(pTagValue),
|
|
274
|
-
stopNodes: ["*.onentry", "*.onexit", "*.transition"],
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
try {
|
|
278
|
-
lXMLAsJSON = deDuplicateAttributesAndTags(
|
|
279
|
-
lXMLParser.parse(lTrimmedSCXMLString, true),
|
|
280
|
-
lAttributeNamePrefix
|
|
281
|
-
);
|
|
282
|
-
} catch (pError) {
|
|
283
|
-
throw new Error("That doesn't look like valid xml ...\n");
|
|
284
|
-
}
|
|
285
|
-
return mapMachine(
|
|
286
|
-
lXMLAsJSON?.scxml ?? {
|
|
287
|
-
xmlns: "http://www.w3.org/2005/07/scxml",
|
|
288
|
-
version: "1.0",
|
|
289
|
-
}
|
|
290
|
-
);
|
|
291
|
-
}
|