state-machine-cat 12.0.18 → 12.0.19
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/dist/cli/cli.mjs +2 -17
- package/dist/parse/scxml/index.mjs +1 -1
- package/dist/render/dot/index.mjs +24 -4
- package/dist/render/dot/utl.mjs +3 -2
- package/dist/state-machine-model.mjs +19 -12
- package/dist/version.mjs +1 -1
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -518,7 +518,7 @@ eat -> sleep [color="blue" width=3.5] : belly full;
|
|
|
518
518
|
|
|
519
519
|
... would yield this diagram:
|
|
520
520
|
|
|
521
|
-
<img width="
|
|
521
|
+
<img width="488" alt="colored states and transitions" src="https://raw.githubusercontent.com/sverweij/state-machine-cat/main/docs/pics/10colored_states_and_transitions.png">
|
|
522
522
|
|
|
523
523
|
What does 'experimental' mean?
|
|
524
524
|
|
package/dist/cli/cli.mjs
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
1
|
import { parseArgs } from "node:util";
|
|
3
|
-
import
|
|
2
|
+
import { version } from "../version.mjs";
|
|
4
3
|
import { formatError, displayLicense, transform } from "./actions.mjs";
|
|
5
4
|
import normalize from "./normalize.mjs";
|
|
6
5
|
import validations from "./validations.mjs";
|
|
7
|
-
const $package = JSON.parse(
|
|
8
|
-
readFileSync(new URL("../../package.json", import.meta.url), "utf8"),
|
|
9
|
-
);
|
|
10
6
|
const HELP_TEXT = `Usage: smcat [options] [infile]
|
|
11
7
|
|
|
12
8
|
Write beautiful state charts - https://github.com/sverweij/state-machine-cat
|
|
@@ -130,31 +126,20 @@ function parseArguments(pArguments) {
|
|
|
130
126
|
);
|
|
131
127
|
return { values: camelizeObject(values), positionals };
|
|
132
128
|
}
|
|
133
|
-
function assertNodeVersion(pCurrentNodeVersion, pSupportedEngines) {
|
|
134
|
-
if (!satisfies(pCurrentNodeVersion, pSupportedEngines)) {
|
|
135
|
-
throw new Error(
|
|
136
|
-
`\nERROR: your node version (${pCurrentNodeVersion}) is not recent enough.\n` +
|
|
137
|
-
` state-machine-cat is supported on node ${pSupportedEngines}\n\n`,
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
129
|
export default async function cli(pArguments = process.argv, pOptions) {
|
|
142
130
|
const lOptions = {
|
|
143
|
-
currentNodeVersion: process.versions.node,
|
|
144
|
-
supportedEngines: $package.engines.node,
|
|
145
131
|
outStream: process.stdout,
|
|
146
132
|
errorStream: process.stderr,
|
|
147
133
|
...pOptions,
|
|
148
134
|
};
|
|
149
135
|
try {
|
|
150
|
-
assertNodeVersion(lOptions.currentNodeVersion, lOptions.supportedEngines);
|
|
151
136
|
const { values, positionals } = parseArguments(pArguments.slice(2));
|
|
152
137
|
if (values.help) {
|
|
153
138
|
lOptions.outStream.write(HELP_TEXT, "utf8");
|
|
154
139
|
return;
|
|
155
140
|
}
|
|
156
141
|
if (values.version) {
|
|
157
|
-
lOptions.outStream.write(`${
|
|
142
|
+
lOptions.outStream.write(`${version}\n`, "utf8");
|
|
158
143
|
return;
|
|
159
144
|
}
|
|
160
145
|
if (values.license) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fastxml from "fast-xml-parser";
|
|
2
2
|
import he from "he";
|
|
3
|
-
import traverse from "
|
|
3
|
+
import traverse from "neotraverse";
|
|
4
4
|
import utl from "../../transform/utl.mjs";
|
|
5
5
|
import parserHelpers from "../parser-helpers.mjs";
|
|
6
6
|
import { castArray } from "./utl.mjs";
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
normalizeState,
|
|
17
17
|
stateNote,
|
|
18
18
|
} from "./utl.mjs";
|
|
19
|
+
let gRenderedTransitions = new Set();
|
|
19
20
|
function initial(pState, pIndent) {
|
|
20
21
|
const lActiveAttribute = pState.active ? " penwidth=3.0" : "";
|
|
21
22
|
return `${pIndent} "${pState.name}" [shape=circle style=filled class="${pState.class}" color="${pState.color}" fillcolor="${pState.color}" fixedsize=true height=0.15 label=""${lActiveAttribute}]${pState.noteText}`;
|
|
@@ -164,13 +165,28 @@ const STATE_TYPE2FUNCTION = new Map([
|
|
|
164
165
|
]);
|
|
165
166
|
function state(pState, pIndent, pOptions, pModel) {
|
|
166
167
|
const lState = normalizeState(pState, pOptions, pIndent);
|
|
168
|
+
const lCandidateTransitions = pModel.findTransitionsToSiblings(
|
|
169
|
+
pState.name,
|
|
170
|
+
gRenderedTransitions,
|
|
171
|
+
);
|
|
172
|
+
lCandidateTransitions.forEach((pTransition) => {
|
|
173
|
+
gRenderedTransitions.add(pTransition.id);
|
|
174
|
+
});
|
|
175
|
+
const lTransitions = transitions(
|
|
176
|
+
lCandidateTransitions,
|
|
177
|
+
pIndent,
|
|
178
|
+
pOptions,
|
|
179
|
+
pModel,
|
|
180
|
+
);
|
|
167
181
|
return (
|
|
168
182
|
(STATE_TYPE2FUNCTION.get(pState.type) ?? regular)(
|
|
169
183
|
lState,
|
|
170
184
|
pIndent,
|
|
171
185
|
pOptions,
|
|
172
186
|
pModel,
|
|
173
|
-
) +
|
|
187
|
+
) +
|
|
188
|
+
lTransitions +
|
|
189
|
+
"\n"
|
|
174
190
|
);
|
|
175
191
|
}
|
|
176
192
|
function states(pStates, pIndent, pOptions, pModel) {
|
|
@@ -233,19 +249,23 @@ export default function renderDot(pStateMachine, pOptions = {}, pIndent = "") {
|
|
|
233
249
|
const lNodeAttributes = buildNodeAttributes(pOptions.dotNodeAttrs || []);
|
|
234
250
|
const lEdgeAttributes = buildEdgeAttributes(pOptions.dotEdgeAttrs || []);
|
|
235
251
|
const lModel = new StateMachineModel(pStateMachine);
|
|
252
|
+
gRenderedTransitions = new Set();
|
|
236
253
|
const lStates = states(pStateMachine.states, pIndent, pOptions, lModel);
|
|
237
|
-
const
|
|
238
|
-
lModel.flattenedTransitions
|
|
254
|
+
const lRemainingTransitions = transitions(
|
|
255
|
+
lModel.flattenedTransitions.filter(
|
|
256
|
+
(pTransition) => !gRenderedTransitions.has(pTransition.id),
|
|
257
|
+
),
|
|
239
258
|
pIndent,
|
|
240
259
|
pOptions,
|
|
241
260
|
lModel,
|
|
242
261
|
);
|
|
262
|
+
gRenderedTransitions = new Set();
|
|
243
263
|
return `digraph "state transitions" {
|
|
244
264
|
${lGraphAttributes}
|
|
245
265
|
node [${lNodeAttributes}]
|
|
246
266
|
edge [${lEdgeAttributes}]
|
|
247
267
|
|
|
248
|
-
${lStates}${
|
|
268
|
+
${lStates}${lRemainingTransitions}
|
|
249
269
|
}
|
|
250
270
|
`;
|
|
251
271
|
}
|
package/dist/render/dot/utl.mjs
CHANGED
|
@@ -42,7 +42,8 @@ export function isVertical(pDirection) {
|
|
|
42
42
|
export function isCompositeSelf(pStateMachineModel, pTransition) {
|
|
43
43
|
return (
|
|
44
44
|
pTransition.from === pTransition.to &&
|
|
45
|
-
pStateMachineModel.findStateByName(pTransition.from)
|
|
45
|
+
(pStateMachineModel.findStateByName(pTransition.from)?.statemachine ??
|
|
46
|
+
false) &&
|
|
46
47
|
pTransition.type !== "internal"
|
|
47
48
|
);
|
|
48
49
|
}
|
|
@@ -94,7 +95,7 @@ export function getTransitionPorts(pOptions, pModel, pTransition) {
|
|
|
94
95
|
if (isVertical(lDirection)) {
|
|
95
96
|
lTailPorts = ' tailport="e" headport="e"';
|
|
96
97
|
lHeadPorts = ' tailport="w"';
|
|
97
|
-
} else if (pModel.findStateByName(pTransition.from)
|
|
98
|
+
} else if (pModel.findStateByName(pTransition.from)?.parent ?? false) {
|
|
98
99
|
lTailPorts = ' tailport="n" headport="n"';
|
|
99
100
|
lHeadPorts = ' tailport="s"';
|
|
100
101
|
}
|
|
@@ -1,21 +1,18 @@
|
|
|
1
|
-
function
|
|
2
|
-
let lReturnValue = [];
|
|
1
|
+
function flattenStatesToMap(pStates, pMap, pParent = "") {
|
|
3
2
|
pStates
|
|
4
3
|
.filter((pState) => Boolean(pState.statemachine))
|
|
5
4
|
.forEach((pState) => {
|
|
6
5
|
if (Object.hasOwn(pState.statemachine, "states")) {
|
|
7
|
-
|
|
8
|
-
flattenStates(pState.statemachine.states, true),
|
|
9
|
-
);
|
|
6
|
+
flattenStatesToMap(pState.statemachine.states, pMap, pState.name);
|
|
10
7
|
}
|
|
11
8
|
});
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
pStates.forEach((pState) =>
|
|
10
|
+
pMap.set(pState.name, {
|
|
14
11
|
name: pState.name,
|
|
15
12
|
type: pState.type,
|
|
16
13
|
statemachine: Boolean(pState.statemachine),
|
|
17
|
-
|
|
18
|
-
})
|
|
14
|
+
parent: pParent,
|
|
15
|
+
}),
|
|
19
16
|
);
|
|
20
17
|
}
|
|
21
18
|
function flattenTransitions(pStateMachine) {
|
|
@@ -38,17 +35,18 @@ export default class StateMachineModel {
|
|
|
38
35
|
_flattenedTransitions;
|
|
39
36
|
_flattenedStates;
|
|
40
37
|
constructor(pStateMachine) {
|
|
41
|
-
this._flattenedStates =
|
|
38
|
+
this._flattenedStates = new Map();
|
|
39
|
+
flattenStatesToMap(pStateMachine.states ?? [], this._flattenedStates);
|
|
42
40
|
this._flattenedTransitions = flattenTransitions(pStateMachine);
|
|
43
41
|
}
|
|
44
42
|
get flattenedTransitions() {
|
|
45
43
|
return this._flattenedTransitions;
|
|
46
44
|
}
|
|
47
45
|
findStateByName(pName) {
|
|
48
|
-
return this._flattenedStates.
|
|
46
|
+
return this._flattenedStates.get(pName);
|
|
49
47
|
}
|
|
50
48
|
findStatesByTypes(pTypes) {
|
|
51
|
-
return this._flattenedStates.filter((pState) =>
|
|
49
|
+
return Array.from(this._flattenedStates.values()).filter((pState) =>
|
|
52
50
|
pTypes.includes(pState.type),
|
|
53
51
|
);
|
|
54
52
|
}
|
|
@@ -70,4 +68,13 @@ export default class StateMachineModel {
|
|
|
70
68
|
(pTransition) => pTransition.to === pToStateName,
|
|
71
69
|
);
|
|
72
70
|
}
|
|
71
|
+
findTransitionsToSiblings(pStateName, pExcludeIds) {
|
|
72
|
+
return this._flattenedTransitions.filter(
|
|
73
|
+
(pTransition) =>
|
|
74
|
+
!pExcludeIds.has(pTransition.id) &&
|
|
75
|
+
pTransition.from === pStateName &&
|
|
76
|
+
this._flattenedStates.get(pTransition.to)?.parent ===
|
|
77
|
+
this._flattenedStates.get(pStateName)?.parent,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
73
80
|
}
|
package/dist/version.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = "12.0.
|
|
1
|
+
export const version = "12.0.19";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "state-machine-cat",
|
|
3
|
-
"version": "12.0.
|
|
3
|
+
"version": "12.0.19",
|
|
4
4
|
"description": "write beautiful state charts",
|
|
5
5
|
"main": "./dist/index.mjs",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -44,8 +44,7 @@
|
|
|
44
44
|
"ajv": "8.17.1",
|
|
45
45
|
"fast-xml-parser": "4.5.1",
|
|
46
46
|
"he": "1.2.0",
|
|
47
|
-
"
|
|
48
|
-
"traverse": "0.6.8"
|
|
47
|
+
"neotraverse": "0.6.18"
|
|
49
48
|
},
|
|
50
49
|
"engines": {
|
|
51
50
|
"node": "^18.17||>=20"
|