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
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/**
|
|
3
|
+
* @param {import("../types/state-machine-cat").IState[]} pStates
|
|
4
|
+
* @param {boolean} pHasParent
|
|
5
|
+
* @returns {any} // IFlattenedState - a state, but flattened (statemachine is a boolean, the new attr hasParent as well)
|
|
6
|
+
*/
|
|
1
7
|
function flattenStates(pStates, pHasParent = false) {
|
|
2
8
|
let lReturnValue = [];
|
|
3
9
|
|
|
@@ -6,6 +12,8 @@ function flattenStates(pStates, pHasParent = false) {
|
|
|
6
12
|
.forEach((pState) => {
|
|
7
13
|
if (Object.prototype.hasOwnProperty.call(pState.statemachine, "states")) {
|
|
8
14
|
lReturnValue = lReturnValue.concat(
|
|
15
|
+
// @ts-expect-error TS doesn't detect that after the call in the filter
|
|
16
|
+
// the .statemachine is guaranteed to exist
|
|
9
17
|
flattenStates(pState.statemachine.states, true)
|
|
10
18
|
);
|
|
11
19
|
}
|
|
@@ -21,10 +29,17 @@ function flattenStates(pStates, pHasParent = false) {
|
|
|
21
29
|
);
|
|
22
30
|
}
|
|
23
31
|
|
|
32
|
+
/**
|
|
33
|
+
* @param {import("../types/state-machine-cat").IStateMachine} pStateMachine
|
|
34
|
+
* @returns {import("../types/state-machine-cat").ITransition[]}
|
|
35
|
+
*/
|
|
24
36
|
function flattenTransitions(pStateMachine) {
|
|
37
|
+
/** @type {import("../types/state-machine-cat").ITransition[]} */
|
|
25
38
|
let lTransitions = [];
|
|
26
39
|
|
|
27
40
|
if (Object.prototype.hasOwnProperty.call(pStateMachine, "transitions")) {
|
|
41
|
+
// @ts-expect-error TS doesn't detect that after the call in the if the
|
|
42
|
+
// .transitions is guaranteed to exist
|
|
28
43
|
lTransitions = pStateMachine.transitions;
|
|
29
44
|
}
|
|
30
45
|
if (Object.prototype.hasOwnProperty.call(pStateMachine, "states")) {
|
|
@@ -32,6 +47,8 @@ function flattenTransitions(pStateMachine) {
|
|
|
32
47
|
.filter((pState) => Boolean(pState.statemachine))
|
|
33
48
|
.forEach((pState) => {
|
|
34
49
|
lTransitions = lTransitions.concat(
|
|
50
|
+
// @ts-expect-error TS doesn't detect that after the call in the filter
|
|
51
|
+
// the .statemachine is guaranteed to exist
|
|
35
52
|
flattenTransitions(pState.statemachine)
|
|
36
53
|
);
|
|
37
54
|
});
|
|
@@ -40,25 +57,42 @@ function flattenTransitions(pStateMachine) {
|
|
|
40
57
|
}
|
|
41
58
|
|
|
42
59
|
export default class StateMachineModel {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
60
|
+
/**
|
|
61
|
+
* @param {import("../types/state-machine-cat").IStateMachine} pStateMachine
|
|
62
|
+
*/
|
|
63
|
+
constructor(pStateMachine) {
|
|
64
|
+
this._flattenedStates = flattenStates(pStateMachine.states || []);
|
|
65
|
+
this._flattenedTransitions = flattenTransitions(pStateMachine);
|
|
46
66
|
}
|
|
47
|
-
|
|
67
|
+
/**
|
|
68
|
+
* @returns {import("../types/state-machine-cat").ITransition[]}
|
|
69
|
+
*/
|
|
48
70
|
get flattenedTransitions() {
|
|
49
71
|
return this._flattenedTransitions;
|
|
50
72
|
}
|
|
51
73
|
|
|
74
|
+
/**
|
|
75
|
+
* @param {string} pName
|
|
76
|
+
* @returns {any} // IFlattenedState
|
|
77
|
+
*/
|
|
52
78
|
findStateByName(pName) {
|
|
53
79
|
return this._flattenedStates.find((pState) => pState.name === pName);
|
|
54
80
|
}
|
|
55
81
|
|
|
82
|
+
/**
|
|
83
|
+
* @param {import("../types/state-machine-cat").StateType[]} pTypes
|
|
84
|
+
* @returns {any} // IFlattenedState
|
|
85
|
+
*/
|
|
56
86
|
findStatesByTypes(pTypes) {
|
|
57
87
|
return this._flattenedStates.filter((pState) =>
|
|
58
88
|
pTypes.includes(pState.type)
|
|
59
89
|
);
|
|
60
90
|
}
|
|
61
91
|
|
|
92
|
+
/**
|
|
93
|
+
* @param {string} pStateName
|
|
94
|
+
* @returns {import("../types/state-machine-cat").ITransition[]}
|
|
95
|
+
*/
|
|
62
96
|
findExternalSelfTransitions(pStateName) {
|
|
63
97
|
return this._flattenedTransitions.filter(
|
|
64
98
|
(pTransition) =>
|
|
@@ -68,12 +102,20 @@ export default class StateMachineModel {
|
|
|
68
102
|
);
|
|
69
103
|
}
|
|
70
104
|
|
|
105
|
+
/**
|
|
106
|
+
* @param {string} pFromStateName
|
|
107
|
+
* @returns {import("../types/state-machine-cat").ITransition[]}
|
|
108
|
+
*/
|
|
71
109
|
findTransitionsByFrom(pFromStateName) {
|
|
72
110
|
return this._flattenedTransitions.filter(
|
|
73
111
|
(pTransition) => pTransition.from === pFromStateName
|
|
74
112
|
);
|
|
75
113
|
}
|
|
76
114
|
|
|
115
|
+
/**
|
|
116
|
+
* @param {string} pToStateName
|
|
117
|
+
* @returns {import("../types/state-machine-cat").ITransition[]}
|
|
118
|
+
*/
|
|
77
119
|
findTransitionsByTo(pToStateName) {
|
|
78
120
|
return this._flattenedTransitions.filter(
|
|
79
121
|
(pTransition) => pTransition.to === pToStateName
|
|
@@ -1,14 +1,31 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
/* eslint-disable security/detect-object-injection */
|
|
2
3
|
import cloneDeep from "lodash/cloneDeep.js";
|
|
3
4
|
import reject from "lodash/reject.js";
|
|
4
5
|
import StateMachineModel from "../state-machine-model.mjs";
|
|
5
6
|
import utl from "./utl.mjs";
|
|
6
7
|
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {{[stateName: string]: import("../../types/state-machine-cat.js").ITransition[]}} ITransitionMap
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param {string|undefined} pIncomingThing
|
|
14
|
+
* @param {string} pOutgoingThing
|
|
15
|
+
* @param {string} pJoinChar
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
7
18
|
function fuseTransitionAttribute(pIncomingThing, pOutgoingThing, pJoinChar) {
|
|
8
19
|
return pIncomingThing
|
|
9
20
|
? `${pIncomingThing}${pJoinChar}${pOutgoingThing}`
|
|
10
21
|
: pOutgoingThing;
|
|
11
22
|
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {import("../../types/state-machine-cat.js").ITransition} pIncomingTransition
|
|
26
|
+
* @param {import("../../types/state-machine-cat.js").ITransition} pOutgoingTransition
|
|
27
|
+
* @returns {import("../../types/state-machine-cat.js").ITransition}
|
|
28
|
+
*/
|
|
12
29
|
function fuseIncomingToOutgoing(pIncomingTransition, pOutgoingTransition) {
|
|
13
30
|
// in:
|
|
14
31
|
// a => ]: event [condition]/ action;
|
|
@@ -19,6 +36,7 @@ function fuseIncomingToOutgoing(pIncomingTransition, pOutgoingTransition) {
|
|
|
19
36
|
//
|
|
20
37
|
// events and conditions are illegal on transitions outgoing
|
|
21
38
|
// from forks, so we ignore them
|
|
39
|
+
/** @type {import("../../types/state-machine-cat.js").ITransition} */
|
|
22
40
|
const lReturnValue = {
|
|
23
41
|
...pIncomingTransition,
|
|
24
42
|
...pOutgoingTransition,
|
|
@@ -44,27 +62,50 @@ function fuseIncomingToOutgoing(pIncomingTransition, pOutgoingTransition) {
|
|
|
44
62
|
return lReturnValue;
|
|
45
63
|
}
|
|
46
64
|
|
|
65
|
+
/**
|
|
66
|
+
* @param {import("../../types/state-machine-cat.js").ITransition[]} pTransitions
|
|
67
|
+
* @param {string[]} pPseudoStateNames
|
|
68
|
+
* @param {ITransitionMap} pOutgoingTransitionMap
|
|
69
|
+
* @returns {import("../../types/state-machine-cat.js").ITransition[]}
|
|
70
|
+
*/
|
|
47
71
|
function fuseTransitions(
|
|
48
72
|
pTransitions,
|
|
49
73
|
pPseudoStateNames,
|
|
50
74
|
pOutgoingTransitionMap
|
|
51
75
|
) {
|
|
52
|
-
return pTransitions.reduce(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
76
|
+
return pTransitions.reduce(
|
|
77
|
+
/**
|
|
78
|
+
* @param {import("../../types/state-machine-cat.js").ITransition[]} pAll
|
|
79
|
+
* @param {import("../../types/state-machine-cat.js").ITransition} pTransition
|
|
80
|
+
* @returns {import("../../types/state-machine-cat.js").ITransition[]}
|
|
81
|
+
*/
|
|
82
|
+
(pAll, pTransition) => {
|
|
83
|
+
pPseudoStateNames.forEach((pStateName, pIndex) => {
|
|
84
|
+
if (
|
|
85
|
+
pStateName === pTransition.to &&
|
|
86
|
+
pOutgoingTransitionMap[pStateName]
|
|
87
|
+
) {
|
|
88
|
+
pAll = pAll.concat(
|
|
89
|
+
pOutgoingTransitionMap[pStateName].map((pOutgoingTransition) =>
|
|
90
|
+
fuseIncomingToOutgoing(pTransition, pOutgoingTransition)
|
|
91
|
+
)
|
|
92
|
+
);
|
|
93
|
+
} else {
|
|
94
|
+
pAll = pIndex === 0 ? pAll.concat(pTransition) : pAll;
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
return pAll;
|
|
98
|
+
},
|
|
99
|
+
[]
|
|
100
|
+
);
|
|
66
101
|
}
|
|
67
102
|
|
|
103
|
+
/**
|
|
104
|
+
* @param {import("../../types/state-machine-cat.js").IStateMachine} pMachine
|
|
105
|
+
* @param {string[]} pPseudoStateNames
|
|
106
|
+
* @param {ITransitionMap} pOutgoingTransitionMap
|
|
107
|
+
* @returns {import("../../types/state-machine-cat.js").IStateMachine}
|
|
108
|
+
*/
|
|
68
109
|
function deSugarPseudoStates(
|
|
69
110
|
pMachine,
|
|
70
111
|
pPseudoStateNames,
|
|
@@ -96,6 +137,11 @@ function deSugarPseudoStates(
|
|
|
96
137
|
return lMachine;
|
|
97
138
|
}
|
|
98
139
|
|
|
140
|
+
/**
|
|
141
|
+
* @param {import("../../types/state-machine-cat.js").IStateMachine} pMachine
|
|
142
|
+
* @param {string[]} pStateNames
|
|
143
|
+
* @returns {import("../../types/state-machine-cat.js").IStateMachine}
|
|
144
|
+
*/
|
|
99
145
|
function removeStatesCascading(pMachine, pStateNames) {
|
|
100
146
|
const lMachine = cloneDeep(pMachine);
|
|
101
147
|
|
|
@@ -142,19 +188,22 @@ function removeStatesCascading(pMachine, pStateNames) {
|
|
|
142
188
|
* b => d;
|
|
143
189
|
* ```
|
|
144
190
|
*
|
|
145
|
-
* @param {IStateMachine} pMachine The state machine still containing forks
|
|
146
|
-
* @param {StateType[]} pDesugarableStates array of de-sugarable states
|
|
147
|
-
* @returns {IStateMachine}
|
|
191
|
+
* @param {import("../../types/state-machine-cat.js").IStateMachine} pMachine The state machine still containing forks
|
|
192
|
+
* @param {import("../../types/state-machine-cat.js").StateType[]} pDesugarableStates array of de-sugarable states
|
|
193
|
+
* @returns {import("../../types/state-machine-cat.js").IStateMachine} the transformed state machine
|
|
148
194
|
*/
|
|
149
195
|
export default (
|
|
150
196
|
pMachine,
|
|
151
197
|
pDesugarableStates = ["fork", "junction", "choice"]
|
|
152
198
|
) => {
|
|
153
199
|
const lModel = new StateMachineModel(pMachine);
|
|
200
|
+
|
|
201
|
+
/** @type {string[]} */
|
|
154
202
|
const lPseudoStateNames = lModel
|
|
155
203
|
.findStatesByTypes(pDesugarableStates)
|
|
156
|
-
.map((
|
|
204
|
+
.map(({ name }) => name);
|
|
157
205
|
|
|
206
|
+
/** @type {ITransitionMap} */
|
|
158
207
|
const lOutgoingTransitionMap = lPseudoStateNames.reduce(
|
|
159
208
|
(pAll, pStateName) => {
|
|
160
209
|
pAll[pStateName] = lModel.findTransitionsByFrom(pStateName);
|
package/src/transform/utl.mjs
CHANGED
package/src/version.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// generated by tools/get-version.mjs - edits will be overwritten
|
|
2
|
-
export const version = "10.1.
|
|
2
|
+
export const version = "10.1.5";
|
|
@@ -183,13 +183,22 @@ export function getAllowedValues(): IAllowedValues;
|
|
|
183
183
|
export type InputType = "smcat" | "json" | "scxml";
|
|
184
184
|
|
|
185
185
|
export type OutputType =
|
|
186
|
-
| "
|
|
186
|
+
| "ast"
|
|
187
187
|
| "dot"
|
|
188
|
+
| "eps"
|
|
188
189
|
| "json"
|
|
189
|
-
| "
|
|
190
|
-
| "
|
|
190
|
+
| "oldeps"
|
|
191
|
+
| "oldps"
|
|
192
|
+
| "oldps2"
|
|
193
|
+
| "oldsvg"
|
|
194
|
+
| "pdf"
|
|
195
|
+
| "png"
|
|
196
|
+
| "ps"
|
|
197
|
+
| "ps2"
|
|
191
198
|
| "scjson"
|
|
192
|
-
| "scxml"
|
|
199
|
+
| "scxml"
|
|
200
|
+
| "smcat"
|
|
201
|
+
| "svg";
|
|
193
202
|
|
|
194
203
|
export type EngineType = "dot" | "circo" | "fdp" | "neato" | "osage" | "twopi";
|
|
195
204
|
|
|
@@ -204,7 +213,7 @@ export type dotAttributesType = {
|
|
|
204
213
|
value: string;
|
|
205
214
|
}[];
|
|
206
215
|
|
|
207
|
-
export interface
|
|
216
|
+
export interface IBaseRenderOptions {
|
|
208
217
|
/**
|
|
209
218
|
* How to interpret the input (defaults to 'smcat')
|
|
210
219
|
*/
|
|
@@ -222,6 +231,17 @@ export interface IRenderOptions {
|
|
|
222
231
|
* (defaults to 'top-down')
|
|
223
232
|
*/
|
|
224
233
|
direction?: DirectionType;
|
|
234
|
+
/**
|
|
235
|
+
* If true state machine cat will replace 'sugar' pseudo states
|
|
236
|
+
* (choice, forks and junctions) with their equivalent meaning
|
|
237
|
+
* (defaults to false).
|
|
238
|
+
*
|
|
239
|
+
* For details: https://github.com/sverweij/state-machine-cat/blob/master/docs/desugar.md
|
|
240
|
+
*/
|
|
241
|
+
desugar?: boolean;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export interface IRenderOptions extends IBaseRenderOptions {
|
|
225
245
|
/**
|
|
226
246
|
* For the 'dot' renderer: Graph attributes to the engine
|
|
227
247
|
*/
|
|
@@ -234,18 +254,25 @@ export interface IRenderOptions {
|
|
|
234
254
|
* For the 'dot' renderer: Edge attributes to the engine
|
|
235
255
|
*/
|
|
236
256
|
dotEdgeAttrs?: dotAttributesType;
|
|
237
|
-
/**
|
|
238
|
-
* If true state machine cat will replace 'sugar' pseudo states
|
|
239
|
-
* (choice, forks and junctions) with their equivalent meaning
|
|
240
|
-
* (defaults to false).
|
|
241
|
-
*
|
|
242
|
-
* For details: https://github.com/sverweij/state-machine-cat/blob/master/docs/desugar.md
|
|
243
|
-
*/
|
|
244
|
-
desugar?: boolean;
|
|
245
257
|
}
|
|
246
258
|
|
|
259
|
+
export type StringRenderFunctionType = (
|
|
260
|
+
pScript: IStateMachine,
|
|
261
|
+
pOptions: IRenderOptions
|
|
262
|
+
) => string;
|
|
263
|
+
|
|
264
|
+
export type WhateverRenderFunctionType = (
|
|
265
|
+
pScript: IStateMachine,
|
|
266
|
+
pOptions: IRenderOptions
|
|
267
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
268
|
+
) => any;
|
|
269
|
+
|
|
270
|
+
export type RenderFunctionType =
|
|
271
|
+
| StringRenderFunctionType
|
|
272
|
+
| WhateverRenderFunctionType;
|
|
273
|
+
|
|
247
274
|
/**
|
|
248
|
-
* Translates the input script to an
|
|
275
|
+
* Translates the input script to an output script.
|
|
249
276
|
*
|
|
250
277
|
* @param pScript The script to translate
|
|
251
278
|
* @param pOptions options influencing parsing & rendering.
|