state-machine-cat 14.0.3 → 14.0.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.
@@ -1,42 +1,40 @@
1
1
  import path from "node:path";
2
2
  import { getAllowedValues } from "../options.mjs";
3
3
  import { parse as parseAttributes } from "./attributes-parser.mjs";
4
- const INPUT_EXTENSIONS = {
5
- ".smcat": "smcat",
6
- ".scxml": "scxml",
7
- ".xml": "scxml",
8
- ".json": "json",
9
- ".ast": "json",
10
- };
11
- const OUTPUT_EXTENSIONS = {
12
- ".ast": "json",
13
- ".dot": "dot",
14
- ".eps": "eps",
15
- ".json": "json",
16
- ".pdf": "pdf",
17
- ".png": "png",
18
- ".ps": "ps",
19
- ".ps2": "ps2",
20
- ".scjson": "scjson",
21
- ".scxml": "scxml",
22
- ".smcat": "smcat",
23
- ".svg": "svg",
24
- };
4
+ const INPUT_EXTENSIONS = new Map([
5
+ [".smcat", "smcat"],
6
+ [".scxml", "scxml"],
7
+ [".xml", "scxml"],
8
+ [".json", "json"],
9
+ [".ast", "json"],
10
+ ]);
11
+ const OUTPUT_EXTENSIONS = new Map([
12
+ [".ast", "json"],
13
+ [".dot", "dot"],
14
+ [".eps", "eps"],
15
+ [".json", "json"],
16
+ [".pdf", "pdf"],
17
+ [".png", "png"],
18
+ [".ps", "ps"],
19
+ [".ps2", "ps2"],
20
+ [".scjson", "scjson"],
21
+ [".scxml", "scxml"],
22
+ [".smcat", "smcat"],
23
+ [".svg", "svg"],
24
+ ]);
25
+ const NON_OBVIOUS_OUTPUT_EXTENSIONS = new Map([
26
+ ["oldeps", "eps"],
27
+ ["oldps", "ps"],
28
+ ["oldps2", "ps"],
29
+ ["oldsvg", "svg"],
30
+ ["ps2", "ps2"],
31
+ ]);
25
32
  function classifyExtension(pString, pExtensionMap, pDefault) {
26
- return pExtensionMap[path.extname(pString)] || pDefault;
27
- }
28
- function outputType2Extension(pOutputType) {
29
- const lExceptions = {
30
- oldeps: "eps",
31
- oldps: "ps",
32
- oldps2: "ps",
33
- oldsvg: "svg",
34
- ps2: "ps",
35
- };
36
- return lExceptions[pOutputType] || pOutputType;
33
+ return pExtensionMap.get(path.extname(pString)) || pDefault;
37
34
  }
38
35
  function deriveOutputFromInput(pInputFrom, pOutputType) {
39
- const lExtension = outputType2Extension(pOutputType);
36
+ const lExtension =
37
+ NON_OBVIOUS_OUTPUT_EXTENSIONS.get(pOutputType) || pOutputType;
40
38
  if (!pInputFrom || "-" === pInputFrom) {
41
39
  return "-";
42
40
  }
package/dist/index.mjs CHANGED
@@ -7,9 +7,7 @@ import getRenderFunction from "./render/index.mjs";
7
7
  import { version as _version } from "./version.mjs";
8
8
  let gDesugarModule = null;
9
9
  async function desugar(pStateMachine) {
10
- if (!gDesugarModule) {
11
- gDesugarModule = await import("./transform/desugar.mjs");
12
- }
10
+ gDesugarModule ??= await import("./transform/desugar.mjs");
13
11
  const lDesugarFunction = gDesugarModule.default;
14
12
  return lDesugarFunction(pStateMachine);
15
13
  }
@@ -1,7 +1,4 @@
1
1
  import StateMachineModel from "../state-machine-model.mjs";
2
- const TRIGGER_RE_AS_A_STRING =
3
- "^(entry|activity|exit)\\s*/\\s*([^\\n$]*)(\\n|$)";
4
- const TRIGGER_RE = new RegExp(TRIGGER_RE_AS_A_STRING);
5
2
  function stateExists(pKnownStateNames, pName) {
6
3
  return pKnownStateNames.includes(pName);
7
4
  }
@@ -131,23 +128,23 @@ export function uniq(pArray, pEqualFunction) {
131
128
  return pBag.concat(pMarble);
132
129
  }, []);
133
130
  }
131
+ const TRANSITION_EXPRESSION_RE =
132
+ /(?<event>[^[/]{1,256})?(?<condition>\[[^\]]{1,256}\])?[^/]{0,100}(?<action>\/.{1,2048})?/;
134
133
  export function parseTransitionExpression(pString) {
135
- const lTransitionExpressionRe = /([^[/]+)?(\[[^\]]+\])?[^/]*(\/.+)?/;
136
134
  const lReturnValue = {};
137
- const lMatchResult = lTransitionExpressionRe.exec(pString);
138
- const lEventPos = 1;
139
- const lConditionPos = 2;
140
- const lActionPos = 3;
141
- if (lMatchResult[lEventPos]) {
142
- lReturnValue.event = lMatchResult[lEventPos].trim();
143
- }
144
- if (lMatchResult[lConditionPos]) {
145
- lReturnValue.cond = lMatchResult[lConditionPos].slice(1, -1).trim();
146
- }
147
- if (lMatchResult[lActionPos]) {
148
- lReturnValue.action = lMatchResult[lActionPos]
149
- .slice(1, lMatchResult[lActionPos].length)
150
- .trim();
135
+ const lMatch = TRANSITION_EXPRESSION_RE.exec(pString);
136
+ if (lMatch?.groups) {
137
+ if (lMatch.groups.event) {
138
+ lReturnValue.event = lMatch.groups.event.trim();
139
+ }
140
+ if (lMatch.groups.condition) {
141
+ lReturnValue.cond = lMatch.groups.condition.slice(1, -1).trim();
142
+ }
143
+ if (lMatch.groups.action) {
144
+ lReturnValue.action = lMatch.groups.action
145
+ .slice(1, lMatch.groups.action.length)
146
+ .trim();
147
+ }
151
148
  }
152
149
  return lReturnValue;
153
150
  }
@@ -159,20 +156,16 @@ export function setIf(pObject, pProperty, pValue, pCondition = Boolean) {
159
156
  export function setIfNotEmpty(pObject, pProperty, pValue) {
160
157
  setIf(pObject, pProperty, pValue, (pX) => pX && pX.length > 0);
161
158
  }
159
+ const TRIGGER_RE =
160
+ /^(?<triggerType>entry|activity|exit)\s{0,100}\/\s{0,100}(?<triggerBody>[^\n$]{0,2048})(?:\n|$)/;
162
161
  function extractAction(pActivityCandidate) {
162
+ const lReturnValue = { type: "activity", body: pActivityCandidate };
163
163
  const lMatch = TRIGGER_RE.exec(pActivityCandidate);
164
- const lTypePos = 1;
165
- const lBodyPos = 2;
166
- if (lMatch) {
167
- return {
168
- type: lMatch[lTypePos],
169
- body: lMatch[lBodyPos],
170
- };
164
+ if (lMatch?.groups) {
165
+ lReturnValue.type = lMatch.groups.triggerType;
166
+ lReturnValue.body = lMatch.groups.triggerBody;
171
167
  }
172
- return {
173
- type: "activity",
174
- body: pActivityCandidate,
175
- };
168
+ return lReturnValue;
176
169
  }
177
170
  export function extractActions(pString) {
178
171
  return pString
@@ -454,7 +454,7 @@ function peg$parse(input, options) {
454
454
  return parseInt(digits.join(""), 10);
455
455
  }
456
456
  function peg$f32(s) {
457
- return s.join("").replace(/\\\"/g, '"');
457
+ return s.join("").replaceAll(/\\\"/g, '"');
458
458
  }
459
459
  function peg$f33(c) {
460
460
  return c;
@@ -124,7 +124,7 @@ function choiceActions(pActions, pActive) {
124
124
  }
125
125
  return lReturnValue;
126
126
  })
127
- .join("\\n");
127
+ .join(String.raw`\n`);
128
128
  }
129
129
  function choice(pState, pIndent) {
130
130
  const lActiveAttribute = pState.active ? "penwidth=3.0 " : "";
@@ -1,39 +1,36 @@
1
1
  import he from "he";
2
2
  import { getOptionValue } from "../../options.mjs";
3
+ const COLORABLE_STATE_TYPES = new Set([
4
+ "initial",
5
+ "fork",
6
+ "join",
7
+ "junction",
8
+ "forkjoin",
9
+ "terminate",
10
+ "final",
11
+ ]);
3
12
  function getStateColor(pState, pNodeAttributes) {
4
13
  const lNodeColor = (pNodeAttributes || []).find(
5
14
  (pAttribute) => pAttribute.name === "color",
6
15
  )?.value;
7
- if (
8
- lNodeColor &&
9
- !pState.color &&
10
- [
11
- "initial",
12
- "fork",
13
- "join",
14
- "junction",
15
- "forkjoin",
16
- "terminate",
17
- "final",
18
- ].includes(pState.type)
19
- ) {
16
+ if (lNodeColor && !pState.color && COLORABLE_STATE_TYPES.has(pState.type)) {
20
17
  return lNodeColor;
21
18
  }
22
19
  return pState.color ?? "black";
23
20
  }
24
21
  export function escapeString(pString) {
25
22
  return pString
26
- .replace(/\\/g, "\\\\")
27
- .replace(/\n\s*/g, "\\l")
28
- .replace(/"/g, '\\"')
29
- .concat("\\l");
23
+ .replaceAll("\\", String.raw`\\`)
24
+ .replaceAll(/\n\s*/g, String.raw`\l`)
25
+ .replaceAll('"', String.raw`\"`)
26
+ .concat(String.raw`\l`);
30
27
  }
31
28
  export function escapeLabelString(pString) {
32
29
  return pString
33
- .replace(/\\/g, "\\\\")
34
- .replace(/\n\s*/g, " \\l")
35
- .replace(/"/g, '\\"')
36
- .concat(" \\l");
30
+ .replaceAll("\\", String.raw`\\`)
31
+ .replaceAll(/\n\s*/g, String.raw` \l`)
32
+ .replaceAll('"', String.raw`\"`)
33
+ .concat(String.raw` \l`);
37
34
  }
38
35
  export function isVertical(pDirection) {
39
36
  const lDirection = pDirection || "top-down";
@@ -6,34 +6,24 @@ let gSCXMLModule = null;
6
6
  export default async function getRenderFunction(pOutputType) {
7
7
  switch (pOutputType) {
8
8
  case "smcat": {
9
- if (!gSmCatModule) {
10
- gSmCatModule = await import("./smcat.mjs");
11
- }
9
+ gSmCatModule ??= await import("./smcat.mjs");
12
10
  return gSmCatModule.default;
13
11
  }
14
12
  case "dot": {
15
- if (!gDotModule) {
16
- gDotModule = await import("./dot/index.mjs");
17
- }
13
+ gDotModule ??= await import("./dot/index.mjs");
18
14
  return gDotModule.default;
19
15
  }
20
16
  case "svg":
21
17
  case "oldsvg": {
22
- if (!gSVGModule) {
23
- gSVGModule = await import("./vector/vector-with-wasm.mjs");
24
- }
18
+ gSVGModule ??= await import("./vector/vector-with-wasm.mjs");
25
19
  return gSVGModule.default;
26
20
  }
27
21
  case "scjson": {
28
- if (!gSCJSONModule) {
29
- gSCJSONModule = await import("./scjson/index.mjs");
30
- }
22
+ gSCJSONModule ??= await import("./scjson/index.mjs");
31
23
  return gSCJSONModule.default;
32
24
  }
33
25
  case "scxml": {
34
- if (!gSCXMLModule) {
35
- gSCXMLModule = await import("./scxml/index.mjs");
36
- }
26
+ gSCXMLModule ??= await import("./scxml/index.mjs");
37
27
  return gSCXMLModule.default;
38
28
  }
39
29
  default:
@@ -1,17 +1,17 @@
1
1
  import StateMachineModel from "../../state-machine-model.mjs";
2
2
  import makeValidXMLName from "./make-valid-xml-name.mjs";
3
3
  import makeValidEventNames from "./make-valid-event-names.mjs";
4
- const STATE_TYPE2SCXML_STATE_KIND = {
5
- regular: "state",
6
- initial: "initial",
7
- final: "final",
8
- terminate: "final",
9
- parallel: "parallel",
10
- history: "history",
11
- deephistory: "history",
12
- };
4
+ const STATE_TYPE2SCXML_STATE_KIND = new Map([
5
+ ["regular", "state"],
6
+ ["initial", "initial"],
7
+ ["final", "final"],
8
+ ["terminate", "final"],
9
+ ["parallel", "parallel"],
10
+ ["history", "history"],
11
+ ["deephistory", "history"],
12
+ ]);
13
13
  function stateType2SCXMLStateKind(pStateType) {
14
- return STATE_TYPE2SCXML_STATE_KIND[pStateType] || "state";
14
+ return STATE_TYPE2SCXML_STATE_KIND.get(pStateType) || "state";
15
15
  }
16
16
  function transformTransition(pTransition) {
17
17
  const lReturnValue = {
@@ -2,7 +2,7 @@ const EVENT_CHAR_FORBIDDEN_RE =
2
2
  /[\u00B7\u0300-\u036F\u203F-\u2040\u0000-\u0029\u002B-\u002C\u002F\u003B-\u0040\u005B-\u0060\u007B-\u00BF\u00D7\u00F7\u0300-\u036F\u037E\u2000-\u200B\u200E-\u206F\u2190-\u2BFF\u2FF0-\u3000\uD800-\uF8FF\uFDD0-\uFDEF\uFFFE-\uFFFF]/g;
3
3
  const START_EVENT_CHAR_FORBIDDEN_EXTRA_RE = /[.]/g;
4
4
  function makeValidEventChar(pCandidateEventStringTail) {
5
- return pCandidateEventStringTail.replace(EVENT_CHAR_FORBIDDEN_RE, "_");
5
+ return pCandidateEventStringTail.replaceAll(EVENT_CHAR_FORBIDDEN_RE, "_");
6
6
  }
7
7
  function makeValidEventStartChar(pCandidateEventStringStart) {
8
8
  let lReturnValue = makeValidEventChar(pCandidateEventStringStart);
@@ -12,12 +12,12 @@ function makeValidEventStartChar(pCandidateEventStringStart) {
12
12
  return lReturnValue;
13
13
  }
14
14
  function makeValidEventName(pCandidateEventName) {
15
- pCandidateEventName = pCandidateEventName.replace(/\s+/g, " ").trim();
15
+ pCandidateEventName = pCandidateEventName.replaceAll(/\s+/g, " ").trim();
16
16
  return makeValidEventStartChar(pCandidateEventName[0]).concat(
17
17
  makeValidEventChar(pCandidateEventName.slice(1)),
18
18
  );
19
19
  }
20
- export default (pCandidateEventNames) => {
20
+ export default function makeValidEventNames(pCandidateEventNames) {
21
21
  const lCandidateEventNames = pCandidateEventNames ?? "";
22
22
  if (lCandidateEventNames.length === 0) {
23
23
  return "empty";
@@ -27,4 +27,4 @@ export default (pCandidateEventNames) => {
27
27
  .filter((pCandidateEventName) => pCandidateEventName.length > 0)
28
28
  .map(makeValidEventName)
29
29
  .join(" ");
30
- };
30
+ }
@@ -3,7 +3,7 @@ const NAME_CHAR_FORBIDDEN_RE =
3
3
  const START_NAME_CHAR_FORBIDDEN_EXTRA_RE =
4
4
  /[-.0-9\u00B7\u0300-\u036F\u203F-\u2040]/g;
5
5
  function makeValidNameChars(pCandidateNameTail) {
6
- return pCandidateNameTail.replace(NAME_CHAR_FORBIDDEN_RE, "_");
6
+ return pCandidateNameTail.replaceAll(NAME_CHAR_FORBIDDEN_RE, "_");
7
7
  }
8
8
  function makeValidNameStartChar(pCandidateChar) {
9
9
  let lReturnValue = makeValidNameChars(pCandidateChar);
@@ -12,7 +12,7 @@ function makeValidNameStartChar(pCandidateChar) {
12
12
  }
13
13
  return lReturnValue;
14
14
  }
15
- export default (pCandidateName) => {
15
+ export default function makeValidXMLName(pCandidateName) {
16
16
  pCandidateName = pCandidateName || "";
17
17
  if (pCandidateName.length === 0) {
18
18
  return `__empty`;
@@ -20,4 +20,4 @@ export default (pCandidateName) => {
20
20
  return makeValidNameStartChar(pCandidateName[0]).concat(
21
21
  makeValidNameChars(pCandidateName.slice(1)),
22
22
  );
23
- };
23
+ }
@@ -2,7 +2,7 @@ import he from "he";
2
2
  const INDENT_LENGTH = 4;
3
3
  function indentString(pString, pCount) {
4
4
  const lRegex = /^(?!\s*$)/gm;
5
- return pString.replace(lRegex, " ".repeat(pCount));
5
+ return pString.replaceAll(lRegex, " ".repeat(pCount));
6
6
  }
7
7
  function renderTransitionAttributes(pTransition) {
8
8
  let lReturnValue = "";
@@ -1,14 +1,14 @@
1
1
  const NAME_QUOTABLE = /[;,{[ ]/;
2
2
  const ACTIONS_QUOTABLE = /[;,{}]/;
3
3
  const LABEL_QUOTABLE = /[;{]/;
4
- const RENDERABLE_STATE_ATTRIBUTES = [
4
+ const RENDERABLE_STATE_ATTRIBUTES = new Set([
5
5
  "label",
6
6
  "type",
7
7
  "color",
8
8
  "active",
9
9
  "class",
10
- ];
11
- const RENDERABLE_TRANSITION_ATTRIBUTES = ["type", "color", "class"];
10
+ ]);
11
+ const RENDERABLE_TRANSITION_ATTRIBUTES = new Set(["type", "color", "class"]);
12
12
  function quoteIfNecessary(pRegExp, pString) {
13
13
  return pRegExp.test(pString) ? `"${pString}"` : pString;
14
14
  }
@@ -35,7 +35,7 @@ function extendedAttribute(pKey, pValue) {
35
35
  }
36
36
  function extendedStateAttributes(pState) {
37
37
  return Object.entries(pState)
38
- .filter(([pKey]) => RENDERABLE_STATE_ATTRIBUTES.includes(pKey))
38
+ .filter(([pKey]) => RENDERABLE_STATE_ATTRIBUTES.has(pKey))
39
39
  .filter(([pKey]) => pKey !== "type" || pState.typeExplicitlySet)
40
40
  .map(([pKey, pValue]) => extendedAttribute(pKey, pValue))
41
41
  .join(" ");
@@ -75,12 +75,12 @@ function states(pStates, pIndent = "") {
75
75
  }
76
76
  function transitionHasExtendedAttributes(pTransition) {
77
77
  return Object.entries(pTransition).some(([pKey]) =>
78
- RENDERABLE_TRANSITION_ATTRIBUTES.includes(pKey),
78
+ RENDERABLE_TRANSITION_ATTRIBUTES.has(pKey),
79
79
  );
80
80
  }
81
81
  function extendedTransitionAttributes(pTransition) {
82
82
  return Object.entries(pTransition)
83
- .filter(([pKey]) => RENDERABLE_TRANSITION_ATTRIBUTES.includes(pKey))
83
+ .filter(([pKey]) => RENDERABLE_TRANSITION_ATTRIBUTES.has(pKey))
84
84
  .map(([pKey, pValue]) => extendedAttribute(pKey, pValue))
85
85
  .join(" ");
86
86
  }
@@ -2,7 +2,7 @@ import { Graphviz } from "@hpcc-js/wasm-graphviz";
2
2
  import { getOptionValue } from "../../options.mjs";
3
3
  import ast2dot from "../dot/index.mjs";
4
4
  import { isAvailable, convert } from "./dot-to-vector-native.mjs";
5
- const VIZ_JS_UNSUPPORTED_OUTPUT_FORMATS = ["pdf", "png"];
5
+ const VIZ_JS_UNSUPPORTED_OUTPUT_FORMATS = new Set(["pdf", "png"]);
6
6
  const gGraphViz = await Graphviz.load();
7
7
  const renderVector = (pStateMachine, pOptions) => {
8
8
  const lDotProgram = ast2dot(pStateMachine, pOptions);
@@ -13,7 +13,7 @@ const renderVector = (pStateMachine, pOptions) => {
13
13
  if (isAvailable(pOptions)) {
14
14
  return convert(lDotProgram, lDotOptions);
15
15
  } else {
16
- if (VIZ_JS_UNSUPPORTED_OUTPUT_FORMATS.includes(lDotOptions.format)) {
16
+ if (VIZ_JS_UNSUPPORTED_OUTPUT_FORMATS.has(lDotOptions.format)) {
17
17
  throw new Error(
18
18
  "GraphViz 'dot' executable not found. Falling back to wasm.\n\n" +
19
19
  "The compiled-to-wasm version of GraphViz we use doesn't support the " +
@@ -40,6 +40,9 @@ export default class StateMachineModel {
40
40
  get flattenedTransitions() {
41
41
  return this.#flattenedTransitions;
42
42
  }
43
+ get flattenedStates() {
44
+ return this.#flattenedStates;
45
+ }
43
46
  findStateByName(pName) {
44
47
  return this.#flattenedStates.get(pName);
45
48
  }
@@ -116,10 +116,10 @@ function removeStatesCascading(pMachine, pStateNames) {
116
116
  );
117
117
  return lMachine;
118
118
  }
119
- export default (
119
+ export default function desugar(
120
120
  pMachine,
121
121
  pDesugarableStates = ["fork", "junction", "choice"],
122
- ) => {
122
+ ) {
123
123
  const lModel = new StateMachineModel(pMachine);
124
124
  const lPseudoStateNames = lModel
125
125
  .findStatesByTypes(pDesugarableStates)
@@ -139,4 +139,4 @@ export default (
139
139
  new Counter(lMaximumTransitionId),
140
140
  );
141
141
  return removeStatesCascading(lMachine, lPseudoStateNames);
142
- };
142
+ }
package/dist/version.mjs CHANGED
@@ -1 +1 @@
1
- export const version = "14.0.3";
1
+ export const version = "14.0.5";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "state-machine-cat",
3
- "version": "14.0.3",
3
+ "version": "14.0.5",
4
4
  "description": "write beautiful state charts",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",
@@ -41,8 +41,8 @@
41
41
  "state-machine-cat": "dist/cli/main.mjs"
42
42
  },
43
43
  "dependencies": {
44
- "@hpcc-js/wasm-graphviz": "1.18.0",
45
- "fast-xml-parser": "5.3.3",
44
+ "@hpcc-js/wasm-graphviz": "1.20.1",
45
+ "fast-xml-parser": "5.3.4",
46
46
  "he": "1.2.0",
47
47
  "neotraverse": "0.6.18"
48
48
  },