state-machine-cat 10.1.6 → 10.1.7
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 -4
- package/dist/commonjs/bundle.js +67 -67
- package/{src → dist/esm}/cli/actions.mjs +24 -40
- package/dist/esm/cli/attributes-parser.mjs +981 -0
- package/dist/esm/cli/file-name-to-stream.mjs +13 -0
- package/dist/esm/cli/make-description.mjs +21 -0
- package/dist/esm/cli/normalize.mjs +95 -0
- package/dist/esm/cli/validations.mjs +70 -0
- package/dist/esm/index-node.mjs +16 -0
- package/dist/esm/index.mjs +19 -0
- package/dist/esm/options.mjs +61 -0
- package/dist/esm/parse/index.mjs +27 -0
- package/dist/esm/parse/parser-helpers.mjs +175 -0
- package/dist/esm/parse/scxml/index.mjs +136 -0
- package/dist/esm/parse/scxml/normalize-machine.mjs +44 -0
- package/dist/esm/parse/smcat/smcat-parser.mjs +2924 -0
- package/dist/esm/parse/smcat-ast.schema.mjs +170 -0
- package/dist/esm/render/dot/attributebuilder.mjs +51 -0
- package/dist/esm/render/dot/counter.mjs +16 -0
- package/dist/esm/render/dot/dot.states.template.js +26 -0
- package/dist/esm/render/dot/dot.template.js +14 -0
- package/dist/esm/render/dot/index.mjs +106 -0
- package/dist/esm/render/dot/render-dot-from-ast.js +29 -0
- package/dist/esm/render/dot/state-transformers.mjs +113 -0
- package/dist/esm/render/dot/transition-transformers.mjs +49 -0
- package/dist/esm/render/dot/utl.mjs +29 -0
- package/dist/esm/render/index-node.mjs +28 -0
- package/dist/esm/render/index.mjs +20 -0
- package/dist/esm/render/scjson/index.mjs +121 -0
- package/dist/esm/render/scjson/make-valid-event-names.mjs +27 -0
- package/dist/esm/render/scjson/make-valid-xml-name.mjs +19 -0
- package/dist/esm/render/scxml/index.mjs +4 -0
- package/dist/esm/render/scxml/render-from-scjson.js +9 -0
- package/dist/esm/render/scxml/scxml.states.template.js +14 -0
- package/dist/esm/render/scxml/scxml.template.js +6 -0
- package/dist/esm/render/smcat/index.js +63 -0
- package/dist/esm/render/smcat/smcat.template.js +13 -0
- package/dist/esm/render/vector/dot-to-vector-native.mjs +35 -0
- package/dist/esm/render/vector/vector-native-dot-with-fallback.mjs +37 -0
- package/dist/esm/render/vector/vector-with-viz-js.mjs +13 -0
- package/dist/esm/state-machine-model.mjs +58 -0
- package/dist/esm/transform/desugar.mjs +77 -0
- package/dist/esm/transform/utl.mjs +16 -0
- package/dist/esm/version.mjs +1 -0
- package/package.json +32 -41
- package/src/render/dot/dot.states.template.js +1 -1
- package/src/render/dot/index.mjs +14 -14
- package/types/state-machine-cat.d.ts +4 -4
- package/src/cli/file-name-to-stream.mjs +0 -25
- package/src/cli/make-description.mjs +0 -45
- package/src/cli/normalize.mjs +0 -204
- package/src/cli/validations.mjs +0 -140
- package/src/index-node.mjs +0 -55
- package/src/index.mjs +0 -58
- package/src/options.mjs +0 -78
- package/src/parse/index.mjs +0 -47
- package/src/parse/parser-helpers.mjs +0 -297
- package/src/parse/scxml/normalize-machine.mjs +0 -73
- package/src/parse/smcat-ast.schema.mjs +0 -187
- package/src/render/dot/attributebuilder.mjs +0 -68
- package/src/render/dot/counter.mjs +0 -33
- package/src/render/dot/render-dot-from-ast.js +0 -70
- package/src/render/dot/state-transformers.mjs +0 -128
- package/src/render/dot/transition-transformers.mjs +0 -52
- package/src/render/dot/utl.mjs +0 -56
- package/src/render/index-node.mjs +0 -36
- package/src/render/index.mjs +0 -22
- package/src/render/scjson/index.mjs +0 -175
- package/src/render/scjson/make-valid-event-names.mjs +0 -71
- package/src/render/scjson/make-valid-xml-name.mjs +0 -70
- package/src/render/scxml/index.mjs +0 -8
- package/src/render/smcat/index.js +0 -129
- package/src/render/vector/dot-to-vector-native.mjs +0 -60
- package/src/render/vector/vector-native-dot-with-fallback.mjs +0 -55
- package/src/render/vector/vector-with-viz-js.mjs +0 -18
- package/src/state-machine-model.mjs +0 -124
- package/src/transform/desugar.mjs +0 -222
- package/src/transform/utl.mjs +0 -26
- package/src/version.mjs +0 -2
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
/** @type {any} - the type definitions for Handlebars don't match what we're actually using - hence this override*/
|
|
3
|
-
const Handlebars = require("handlebars/dist/handlebars.runtime.js");
|
|
4
|
-
const cloneDeep = require("lodash/cloneDeep.js");
|
|
5
|
-
|
|
6
|
-
// eslint-disable-next-line import/no-unassigned-import
|
|
7
|
-
require("./smcat.template.js");
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @typedef {{hasExtendedAttributes?: boolean} & import("../../../types/state-machine-cat.js").IState} IExtendedState
|
|
11
|
-
* @typedef {{actions: string;} & Omit<IExtendedState, "actions">} IFlattenedActionsState
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
const NAME_QUOTABLE = /;|,|{| |\[/;
|
|
15
|
-
const ACTIONS_QUOTABLE = /;|,|{/;
|
|
16
|
-
const LABEL_QUOTABLE = /;|{/;
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @param {RegExp} pRegExp
|
|
20
|
-
* @param {string} pString
|
|
21
|
-
* @returns {string}
|
|
22
|
-
*/
|
|
23
|
-
function quoteIfNecessary(pRegExp, pString) {
|
|
24
|
-
return pRegExp.test(pString) ? `"${pString}"` : pString;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
Handlebars.registerPartial(
|
|
28
|
-
"smcat.template.hbs",
|
|
29
|
-
Handlebars.templates["smcat.template.hbs"]
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* @param {string} pString
|
|
34
|
-
* @returns {string}
|
|
35
|
-
*/
|
|
36
|
-
function formatActionType(pString) {
|
|
37
|
-
return pString === "activity" ? "" : `${pString}/ `;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* @param {IExtendedState} pState
|
|
42
|
-
* @returns {IFlattenedActionsState}
|
|
43
|
-
*/
|
|
44
|
-
function flattenActions(pState) {
|
|
45
|
-
return {
|
|
46
|
-
...pState,
|
|
47
|
-
actions: (pState.actions || [])
|
|
48
|
-
.map((pAction) => `${formatActionType(pAction.type)}${pAction.body}`)
|
|
49
|
-
.join("\n "),
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* @param {IExtendedState} pState
|
|
55
|
-
* @returns {IExtendedState}
|
|
56
|
-
*/
|
|
57
|
-
/* eslint complexity:0 */
|
|
58
|
-
function flagExtendedStateAttributes(pState) {
|
|
59
|
-
if (
|
|
60
|
-
Object.prototype.hasOwnProperty.call(pState, "label") ||
|
|
61
|
-
Object.prototype.hasOwnProperty.call(pState, "typeExplicitlySet") ||
|
|
62
|
-
Object.prototype.hasOwnProperty.call(pState, "color") ||
|
|
63
|
-
Object.prototype.hasOwnProperty.call(pState, "active") ||
|
|
64
|
-
Object.prototype.hasOwnProperty.call(pState, "class")
|
|
65
|
-
) {
|
|
66
|
-
// note & fixme: mutating a parameter here
|
|
67
|
-
pState.hasExtendedAttributes = true;
|
|
68
|
-
}
|
|
69
|
-
return pState;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* @param {import("../../../types/state-machine-cat.js").IState[]} pStates
|
|
74
|
-
* @returns {IFlattenedActionsState[]}
|
|
75
|
-
*/
|
|
76
|
-
function transformStates(pStates) {
|
|
77
|
-
pStates
|
|
78
|
-
.map(flagExtendedStateAttributes)
|
|
79
|
-
.filter((pState) => pState.statemachine)
|
|
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
|
|
84
|
-
pState.statemachine.states = transformStates(
|
|
85
|
-
// @ts-expect-error - see above
|
|
86
|
-
pState.statemachine.states
|
|
87
|
-
);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
return pStates.map(flattenActions);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function flagExtendedTransitionAttributes(pTransition) {
|
|
94
|
-
if (
|
|
95
|
-
Object.prototype.hasOwnProperty.call(pTransition, "type") ||
|
|
96
|
-
Object.prototype.hasOwnProperty.call(pTransition, "color") ||
|
|
97
|
-
Object.prototype.hasOwnProperty.call(pTransition, "class")
|
|
98
|
-
) {
|
|
99
|
-
pTransition.hasExtendedAttributes = true;
|
|
100
|
-
}
|
|
101
|
-
return pTransition;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function transformTransitions(pTransitions) {
|
|
105
|
-
return pTransitions.map(flagExtendedTransitionAttributes);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
Handlebars.registerHelper("quotifyState", (pItem) =>
|
|
109
|
-
quoteIfNecessary(NAME_QUOTABLE, pItem)
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
Handlebars.registerHelper("quotifyLabel", (pItem) =>
|
|
113
|
-
quoteIfNecessary(LABEL_QUOTABLE, pItem)
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
Handlebars.registerHelper("quotifyActions", (pItem) =>
|
|
117
|
-
quoteIfNecessary(ACTIONS_QUOTABLE, pItem)
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
/** @type {import("../../../types/state-machine-cat.js").StringRenderFunctionType} */
|
|
121
|
-
module.exports = function renderSmcat(pStateMachine) {
|
|
122
|
-
return Handlebars.templates["smcat.template.hbs"]({
|
|
123
|
-
...pStateMachine,
|
|
124
|
-
states: transformStates(cloneDeep(pStateMachine.states)),
|
|
125
|
-
transitions: transformTransitions(
|
|
126
|
-
cloneDeep(pStateMachine.transitions || [])
|
|
127
|
-
),
|
|
128
|
-
});
|
|
129
|
-
};
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
|
-
|
|
3
|
-
const DEFAULT_OPTIONS = {
|
|
4
|
-
exec: "dot",
|
|
5
|
-
format: "svg",
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Takes a graphviz dot program (as a string), runs it through the dot
|
|
10
|
-
* executable specified in pOptions.exec (default: 'dot') and returns
|
|
11
|
-
* the result
|
|
12
|
-
*
|
|
13
|
-
* @param {string} pDot The dot program as a string
|
|
14
|
-
* @param {{exec: string, format: import("../../../types/state-machine-cat").OutputType}} pOptions
|
|
15
|
-
* exec: the path to the executable to run. Default: 'dot'
|
|
16
|
-
* @return {string} the dot program converted into an svg
|
|
17
|
-
* @throws {Error} when something ontowards has happened (executable not found, erroneous dot program)
|
|
18
|
-
*/
|
|
19
|
-
function convert(pDot, pOptions) {
|
|
20
|
-
const lOptions = {
|
|
21
|
-
...DEFAULT_OPTIONS,
|
|
22
|
-
...pOptions,
|
|
23
|
-
};
|
|
24
|
-
const { stdout, status, error } = spawnSync(
|
|
25
|
-
lOptions.exec,
|
|
26
|
-
[`-T${lOptions.format}`],
|
|
27
|
-
{
|
|
28
|
-
// cwd: lOptions.workingDirectory,
|
|
29
|
-
input: pDot,
|
|
30
|
-
}
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
// 0: okeleedokelee
|
|
34
|
-
// 1: error in the program
|
|
35
|
-
// -2: executable not found
|
|
36
|
-
if (status === 0) {
|
|
37
|
-
return stdout.toString("binary");
|
|
38
|
-
} else if (error) {
|
|
39
|
-
throw new Error(error);
|
|
40
|
-
} else {
|
|
41
|
-
throw new Error(`Unexpected error occurred. Exit code ${status}`);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function isAvailable(pOptions) {
|
|
46
|
-
const lOptions = {
|
|
47
|
-
...DEFAULT_OPTIONS,
|
|
48
|
-
...pOptions,
|
|
49
|
-
};
|
|
50
|
-
const { status, stderr } = spawnSync(lOptions.exec, ["-V"]);
|
|
51
|
-
|
|
52
|
-
return (
|
|
53
|
-
status === 0 && stderr.toString("utf8").startsWith("dot - graphviz version")
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export default {
|
|
58
|
-
convert,
|
|
59
|
-
isAvailable,
|
|
60
|
-
};
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import dotToSvgJs from "viz.js";
|
|
2
|
-
import indentString from "indent-string";
|
|
3
|
-
import wrapAnsi from "wrap-ansi";
|
|
4
|
-
import chalk from "chalk";
|
|
5
|
-
import options from "../../options.mjs";
|
|
6
|
-
import ast2dot from "../dot/index.mjs";
|
|
7
|
-
import dotToVectorNative from "./dot-to-vector-native.mjs";
|
|
8
|
-
|
|
9
|
-
const DEFAULT_INDENT = 2;
|
|
10
|
-
const DOGMATIC_CONSOLE_WIDTH = 78;
|
|
11
|
-
const VIZ_JS_UNSUPPORTED_OUTPUT_FORMATS = ["pdf", "png"];
|
|
12
|
-
|
|
13
|
-
/** @type {import("../../../types/state-machine-cat.js").StringRenderFunctionType} */
|
|
14
|
-
export default (pStateMachine, pOptions) => {
|
|
15
|
-
const lDotProgram = ast2dot(pStateMachine, pOptions);
|
|
16
|
-
const lDotOptions = {
|
|
17
|
-
engine: options.getOptionValue(pOptions, "engine"),
|
|
18
|
-
format: options.getOptionValue(pOptions, "outputType"),
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
if (dotToVectorNative.isAvailable(pOptions)) {
|
|
22
|
-
return dotToVectorNative.convert(lDotProgram, lDotOptions);
|
|
23
|
-
} else {
|
|
24
|
-
if (VIZ_JS_UNSUPPORTED_OUTPUT_FORMATS.includes(lDotOptions.format)) {
|
|
25
|
-
throw new Error(
|
|
26
|
-
"GraphViz 'dot' executable not found. Falling back to viz.js.\n\n" +
|
|
27
|
-
"'viz.js' doesn't support the 'pdf' and 'png' output formats. Either " +
|
|
28
|
-
"select a format that it does support or install GraphViz " +
|
|
29
|
-
"(recommended), which has support for both formats.\n"
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
process.stderr.write(
|
|
34
|
-
indentString(
|
|
35
|
-
wrapAnsi(
|
|
36
|
-
`\n${chalk.yellow(
|
|
37
|
-
"warning:"
|
|
38
|
-
)} GraphViz 'dot' executable not found. Falling back to viz.js.\n\n` +
|
|
39
|
-
"On node >=12 this fallback will trigger a warning from the " +
|
|
40
|
-
`node runtime:\n${chalk.italic(
|
|
41
|
-
"Invalid asm.js: Function definition doesn't match use"
|
|
42
|
-
)}.\n` +
|
|
43
|
-
"It's harmless and the svg will generate just fine. However, if " +
|
|
44
|
-
"you want to avoid the warning install GraphViz and make sure it's " +
|
|
45
|
-
"available in your path." +
|
|
46
|
-
"\n\n",
|
|
47
|
-
DOGMATIC_CONSOLE_WIDTH
|
|
48
|
-
),
|
|
49
|
-
DEFAULT_INDENT
|
|
50
|
-
)
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
return dotToSvgJs(lDotProgram, lDotOptions);
|
|
54
|
-
}
|
|
55
|
-
};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import viz from "viz.js";
|
|
2
|
-
import options from "../../options.mjs";
|
|
3
|
-
import ast2dot from "../dot/index.mjs";
|
|
4
|
-
|
|
5
|
-
const OUTPUT_TYPE2FORMAT = {
|
|
6
|
-
oldsvg: "svg",
|
|
7
|
-
oldps2: "ps2",
|
|
8
|
-
oldeps: "eps",
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
/** @type {import("../../../types/state-machine-cat.js").StringRenderFunctionType} */
|
|
12
|
-
export default (pStateMachine, pOptions) =>
|
|
13
|
-
viz(ast2dot(pStateMachine, pOptions), {
|
|
14
|
-
engine: options.getOptionValue(pOptions, "engine"),
|
|
15
|
-
format:
|
|
16
|
-
OUTPUT_TYPE2FORMAT[options.getOptionValue(pOptions, "outputType")] ||
|
|
17
|
-
"svg",
|
|
18
|
-
});
|
|
@@ -1,124 +0,0 @@
|
|
|
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
|
-
*/
|
|
7
|
-
function flattenStates(pStates, pHasParent = false) {
|
|
8
|
-
let lReturnValue = [];
|
|
9
|
-
|
|
10
|
-
pStates
|
|
11
|
-
.filter((pState) => Boolean(pState.statemachine))
|
|
12
|
-
.forEach((pState) => {
|
|
13
|
-
if (Object.prototype.hasOwnProperty.call(pState.statemachine, "states")) {
|
|
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
|
|
17
|
-
flattenStates(pState.statemachine.states, true)
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
return lReturnValue.concat(
|
|
23
|
-
pStates.map((pState) => ({
|
|
24
|
-
name: pState.name,
|
|
25
|
-
type: pState.type,
|
|
26
|
-
statemachine: Boolean(pState.statemachine),
|
|
27
|
-
hasParent: pHasParent,
|
|
28
|
-
}))
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* @param {import("../types/state-machine-cat").IStateMachine} pStateMachine
|
|
34
|
-
* @returns {import("../types/state-machine-cat").ITransition[]}
|
|
35
|
-
*/
|
|
36
|
-
function flattenTransitions(pStateMachine) {
|
|
37
|
-
/** @type {import("../types/state-machine-cat").ITransition[]} */
|
|
38
|
-
let lTransitions = [];
|
|
39
|
-
|
|
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
|
|
43
|
-
lTransitions = pStateMachine.transitions;
|
|
44
|
-
}
|
|
45
|
-
if (Object.prototype.hasOwnProperty.call(pStateMachine, "states")) {
|
|
46
|
-
pStateMachine.states
|
|
47
|
-
.filter((pState) => Boolean(pState.statemachine))
|
|
48
|
-
.forEach((pState) => {
|
|
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
|
|
52
|
-
flattenTransitions(pState.statemachine)
|
|
53
|
-
);
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
return lTransitions;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export default class StateMachineModel {
|
|
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);
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* @returns {import("../types/state-machine-cat").ITransition[]}
|
|
69
|
-
*/
|
|
70
|
-
get flattenedTransitions() {
|
|
71
|
-
return this._flattenedTransitions;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* @param {string} pName
|
|
76
|
-
* @returns {any} // IFlattenedState
|
|
77
|
-
*/
|
|
78
|
-
findStateByName(pName) {
|
|
79
|
-
return this._flattenedStates.find((pState) => pState.name === pName);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* @param {import("../types/state-machine-cat").StateType[]} pTypes
|
|
84
|
-
* @returns {any} // IFlattenedState
|
|
85
|
-
*/
|
|
86
|
-
findStatesByTypes(pTypes) {
|
|
87
|
-
return this._flattenedStates.filter((pState) =>
|
|
88
|
-
pTypes.includes(pState.type)
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* @param {string} pStateName
|
|
94
|
-
* @returns {import("../types/state-machine-cat").ITransition[]}
|
|
95
|
-
*/
|
|
96
|
-
findExternalSelfTransitions(pStateName) {
|
|
97
|
-
return this._flattenedTransitions.filter(
|
|
98
|
-
(pTransition) =>
|
|
99
|
-
pTransition.from === pStateName &&
|
|
100
|
-
pTransition.to === pStateName &&
|
|
101
|
-
pTransition.type !== "internal"
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* @param {string} pFromStateName
|
|
107
|
-
* @returns {import("../types/state-machine-cat").ITransition[]}
|
|
108
|
-
*/
|
|
109
|
-
findTransitionsByFrom(pFromStateName) {
|
|
110
|
-
return this._flattenedTransitions.filter(
|
|
111
|
-
(pTransition) => pTransition.from === pFromStateName
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* @param {string} pToStateName
|
|
117
|
-
* @returns {import("../types/state-machine-cat").ITransition[]}
|
|
118
|
-
*/
|
|
119
|
-
findTransitionsByTo(pToStateName) {
|
|
120
|
-
return this._flattenedTransitions.filter(
|
|
121
|
-
(pTransition) => pTransition.to === pToStateName
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
/* eslint-disable security/detect-object-injection */
|
|
3
|
-
import cloneDeep from "lodash/cloneDeep.js";
|
|
4
|
-
import reject from "lodash/reject.js";
|
|
5
|
-
import StateMachineModel from "../state-machine-model.mjs";
|
|
6
|
-
import utl from "./utl.mjs";
|
|
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
|
-
*/
|
|
18
|
-
function fuseTransitionAttribute(pIncomingThing, pOutgoingThing, pJoinChar) {
|
|
19
|
-
return pIncomingThing
|
|
20
|
-
? `${pIncomingThing}${pJoinChar}${pOutgoingThing}`
|
|
21
|
-
: pOutgoingThing;
|
|
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
|
-
*/
|
|
29
|
-
function fuseIncomingToOutgoing(pIncomingTransition, pOutgoingTransition) {
|
|
30
|
-
// in:
|
|
31
|
-
// a => ]: event [condition]/ action;
|
|
32
|
-
// ] => b: event_to_b [condition_to_b]/ action to b;
|
|
33
|
-
//
|
|
34
|
-
// out:
|
|
35
|
-
// a => b: event [condition]/ action\naction to b;
|
|
36
|
-
//
|
|
37
|
-
// events and conditions are illegal on transitions outgoing
|
|
38
|
-
// from forks, so we ignore them
|
|
39
|
-
/** @type {import("../../types/state-machine-cat.js").ITransition} */
|
|
40
|
-
const lReturnValue = {
|
|
41
|
-
...pIncomingTransition,
|
|
42
|
-
...pOutgoingTransition,
|
|
43
|
-
from: pIncomingTransition.from,
|
|
44
|
-
to: pOutgoingTransition.to,
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
if (pOutgoingTransition.action) {
|
|
48
|
-
lReturnValue.action = fuseTransitionAttribute(
|
|
49
|
-
pIncomingTransition.action,
|
|
50
|
-
pOutgoingTransition.action,
|
|
51
|
-
"\n"
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
if (lReturnValue.event || lReturnValue.cond || lReturnValue.action) {
|
|
55
|
-
lReturnValue.label = utl.formatLabel(
|
|
56
|
-
lReturnValue.event,
|
|
57
|
-
lReturnValue.cond,
|
|
58
|
-
lReturnValue.action
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return lReturnValue;
|
|
63
|
-
}
|
|
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
|
-
*/
|
|
71
|
-
function fuseTransitions(
|
|
72
|
-
pTransitions,
|
|
73
|
-
pPseudoStateNames,
|
|
74
|
-
pOutgoingTransitionMap
|
|
75
|
-
) {
|
|
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
|
-
);
|
|
101
|
-
}
|
|
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
|
-
*/
|
|
109
|
-
function deSugarPseudoStates(
|
|
110
|
-
pMachine,
|
|
111
|
-
pPseudoStateNames,
|
|
112
|
-
pOutgoingTransitionMap
|
|
113
|
-
) {
|
|
114
|
-
const lMachine = cloneDeep(pMachine);
|
|
115
|
-
|
|
116
|
-
if (lMachine.transitions && pPseudoStateNames.length > 0) {
|
|
117
|
-
lMachine.transitions = fuseTransitions(
|
|
118
|
-
lMachine.transitions,
|
|
119
|
-
pPseudoStateNames,
|
|
120
|
-
pOutgoingTransitionMap
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
lMachine.states = lMachine.states.map((pState) =>
|
|
125
|
-
pState.statemachine
|
|
126
|
-
? {
|
|
127
|
-
...pState,
|
|
128
|
-
statemachine: deSugarPseudoStates(
|
|
129
|
-
pState.statemachine,
|
|
130
|
-
pPseudoStateNames,
|
|
131
|
-
pOutgoingTransitionMap
|
|
132
|
-
),
|
|
133
|
-
}
|
|
134
|
-
: pState
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
return lMachine;
|
|
138
|
-
}
|
|
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
|
-
*/
|
|
145
|
-
function removeStatesCascading(pMachine, pStateNames) {
|
|
146
|
-
const lMachine = cloneDeep(pMachine);
|
|
147
|
-
|
|
148
|
-
if (lMachine.transitions) {
|
|
149
|
-
lMachine.transitions = reject(lMachine.transitions, (pTransition) =>
|
|
150
|
-
pStateNames.some(
|
|
151
|
-
(pJunctionStateName) =>
|
|
152
|
-
pJunctionStateName === pTransition.from ||
|
|
153
|
-
pJunctionStateName === pTransition.to
|
|
154
|
-
)
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
lMachine.states = reject(lMachine.states, (pState) =>
|
|
159
|
-
pStateNames.includes(pState.name)
|
|
160
|
-
).map((pState) =>
|
|
161
|
-
pState.statemachine
|
|
162
|
-
? {
|
|
163
|
-
...pState,
|
|
164
|
-
statemachine: removeStatesCascading(pState.statemachine, pStateNames),
|
|
165
|
-
}
|
|
166
|
-
: pState
|
|
167
|
-
);
|
|
168
|
-
return lMachine;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Takes a state machine and replaces all forks with transitions from its
|
|
173
|
-
* respective inputs and outputs
|
|
174
|
-
*
|
|
175
|
-
* e.g.
|
|
176
|
-
* ```smcat
|
|
177
|
-
* a => ];
|
|
178
|
-
* b => ];
|
|
179
|
-
* ] => c;
|
|
180
|
-
* ] => d;
|
|
181
|
-
* ```
|
|
182
|
-
*
|
|
183
|
-
* will become
|
|
184
|
-
* ```smcat
|
|
185
|
-
* a => c;
|
|
186
|
-
* a => d;
|
|
187
|
-
* b => c;
|
|
188
|
-
* b => d;
|
|
189
|
-
* ```
|
|
190
|
-
*
|
|
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
|
|
194
|
-
*/
|
|
195
|
-
export default (
|
|
196
|
-
pMachine,
|
|
197
|
-
pDesugarableStates = ["fork", "junction", "choice"]
|
|
198
|
-
) => {
|
|
199
|
-
const lModel = new StateMachineModel(pMachine);
|
|
200
|
-
|
|
201
|
-
/** @type {string[]} */
|
|
202
|
-
const lPseudoStateNames = lModel
|
|
203
|
-
.findStatesByTypes(pDesugarableStates)
|
|
204
|
-
.map(({ name }) => name);
|
|
205
|
-
|
|
206
|
-
/** @type {ITransitionMap} */
|
|
207
|
-
const lOutgoingTransitionMap = lPseudoStateNames.reduce(
|
|
208
|
-
(pAll, pStateName) => {
|
|
209
|
-
pAll[pStateName] = lModel.findTransitionsByFrom(pStateName);
|
|
210
|
-
return pAll;
|
|
211
|
-
},
|
|
212
|
-
{}
|
|
213
|
-
);
|
|
214
|
-
|
|
215
|
-
const lMachine = deSugarPseudoStates(
|
|
216
|
-
pMachine,
|
|
217
|
-
lPseudoStateNames,
|
|
218
|
-
lOutgoingTransitionMap
|
|
219
|
-
);
|
|
220
|
-
|
|
221
|
-
return removeStatesCascading(lMachine, lPseudoStateNames);
|
|
222
|
-
};
|
package/src/transform/utl.mjs
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
4
|
-
* @param {string} [pEvent]
|
|
5
|
-
* @param {string} [pCond]
|
|
6
|
-
* @param {string} [pActions]
|
|
7
|
-
* @returns {string}
|
|
8
|
-
*/
|
|
9
|
-
function formatLabel(pEvent, pCond, pActions) {
|
|
10
|
-
let lReturnValue = "";
|
|
11
|
-
|
|
12
|
-
if (pEvent) {
|
|
13
|
-
lReturnValue += pEvent;
|
|
14
|
-
}
|
|
15
|
-
if (pCond) {
|
|
16
|
-
lReturnValue += ` [${pCond}]`;
|
|
17
|
-
}
|
|
18
|
-
if (pActions) {
|
|
19
|
-
lReturnValue += `/ ${pActions}`;
|
|
20
|
-
}
|
|
21
|
-
return lReturnValue.trim();
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export default {
|
|
25
|
-
formatLabel,
|
|
26
|
-
};
|
package/src/version.mjs
DELETED