state-machine-cat 10.1.2 → 10.1.3
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 -0
- package/dist/commonjs/bundle.js +64 -64
- package/package.json +20 -25
- 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 +79 -41
- 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 +40 -1
- package/src/parse/scxml/normalize-machine.mjs +1 -1
- 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 +3 -1
- 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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "state-machine-cat",
|
|
3
|
-
"version": "10.1.
|
|
3
|
+
"version": "10.1.3",
|
|
4
4
|
"description": "write beautiful state charts",
|
|
5
5
|
"main": "./dist/commonjs/index.js",
|
|
6
6
|
"module": "./src/index.mjs",
|
|
@@ -90,11 +90,6 @@
|
|
|
90
90
|
"policy": "wanted",
|
|
91
91
|
"because": "fast-xml-parser 4 has some breaking changes we still need to grok (why? how?)"
|
|
92
92
|
},
|
|
93
|
-
{
|
|
94
|
-
"package": "husky",
|
|
95
|
-
"policy": "pin",
|
|
96
|
-
"because": "(npm7 & husky don't play nice together - and it might be it's not going to be solved satisfactorily) https://github.com/typicode/husky/issues/822 "
|
|
97
|
-
},
|
|
98
93
|
{
|
|
99
94
|
"package": "viz.js",
|
|
100
95
|
"policy": "pin",
|
|
@@ -244,13 +239,13 @@
|
|
|
244
239
|
]
|
|
245
240
|
},
|
|
246
241
|
"depcruise:graph:dev": {
|
|
247
|
-
"command": "depcruise-fmt node_modules/.cache/depcruise-cache.json --output-type dot --include-only '^(bin|src|package\\.json)' --prefix vscode://file/$(pwd)/ | dot -Tsvg | depcruise-wrap-stream-in-html | browser",
|
|
242
|
+
"command": "depcruise-fmt node_modules/.cache/depcruise-cache.json --output-type dot --include-only '^(bin|src|package\\.json)' --prefix vscode://file/$(pwd)/ --highlight \"$(watskeburt develop)\"| dot -Tsvg | depcruise-wrap-stream-in-html | browser",
|
|
248
243
|
"dependencies": [
|
|
249
244
|
"depcruise:json"
|
|
250
245
|
]
|
|
251
246
|
},
|
|
252
247
|
"depcruise:graph:dev:flat": {
|
|
253
|
-
"command": "depcruise-fmt node_modules/.cache/depcruise-cache.json --output-type flat --include-only '^(bin|src|package\\.json)' --prefix vscode://file/$(pwd)/ | twopi -Tsvg | depcruise-wrap-stream-in-html | browser",
|
|
248
|
+
"command": "depcruise-fmt node_modules/.cache/depcruise-cache.json --output-type flat --include-only '^(bin|src|package\\.json)' --prefix vscode://file/$(pwd)/ --highlight \"$(watskeburt develop)\"| twopi -Tsvg | depcruise-wrap-stream-in-html | browser",
|
|
254
249
|
"dependencies": [
|
|
255
250
|
"depcruise:json"
|
|
256
251
|
]
|
|
@@ -301,7 +296,7 @@
|
|
|
301
296
|
]
|
|
302
297
|
},
|
|
303
298
|
"lint:prettier": {
|
|
304
|
-
"command": "prettier --check \"bin/*.mjs\" \"{src,test}/**/*.{js,mjs}\" \"{config,test}/**/*.{js,json}\" \"tools/*.{js,mjs,json}\" \"types
|
|
299
|
+
"command": "prettier --check \"bin/*.mjs\" \"{src,test}/**/*.{js,mjs}\" \"{config,test}/**/*.{js,json}\" \"tools/*.{js,mjs,json}\" \"{src,types}/**/*.{ts,mts}\" \"*.{json,yml,md}\" \"docs/{smcat-online-interpreter.js,*.md}\"",
|
|
305
300
|
"files": [
|
|
306
301
|
"bin/*.mjs",
|
|
307
302
|
"{src,test}/**/*.{js,mjs}",
|
|
@@ -319,15 +314,15 @@
|
|
|
319
314
|
]
|
|
320
315
|
},
|
|
321
316
|
"lint:types:tsc": {
|
|
322
|
-
"command": "tsc --noEmit --strict --types --noUnusedLocals --noUnusedParameters --pretty types/*.d.ts",
|
|
317
|
+
"command": "tsc --noEmit --strict --types --noUnusedLocals --noUnusedParameters --pretty types/*.d.ts src/cli/*.d.mts src/cli/*.d.ts src/parse/scxml/*.d.ts",
|
|
323
318
|
"files": [
|
|
324
319
|
"types/*.d.ts"
|
|
325
320
|
]
|
|
326
321
|
},
|
|
327
322
|
"lint:types:eslint": {
|
|
328
|
-
"command": "eslint types/*.d.ts",
|
|
323
|
+
"command": "eslint types/*.d.ts src/cli/*.d.mts src/cli/*.d.ts src/parse/scxml/*.d.ts",
|
|
329
324
|
"files": [
|
|
330
|
-
"types
|
|
325
|
+
"{src,types}/**/*.d.{ts,mts}",
|
|
331
326
|
".eslintrc.json"
|
|
332
327
|
]
|
|
333
328
|
},
|
|
@@ -347,10 +342,10 @@
|
|
|
347
342
|
]
|
|
348
343
|
},
|
|
349
344
|
"lint:fix:prettier": {
|
|
350
|
-
"command": "prettier --loglevel warn --write \"bin/*.mjs\" \"{src,test}/**/*.{js,mjs}\" \"{config,test}/**/*.{js,json}\" \"tools/*.{js,mjs,json}\" \"types
|
|
345
|
+
"command": "prettier --loglevel warn --write \"bin/*.mjs\" \"{src,test}/**/*.{js,mjs}\" \"{config,test}/**/*.{js,json}\" \"tools/*.{js,mjs,json}\" \"{src,types}/**/*.{ts,mts}\" \"*.{json,yml,md}\" \"docs/{smcat-online-interpreter.js,*.md}\"",
|
|
351
346
|
"files": [
|
|
352
347
|
"bin/*.mjs",
|
|
353
|
-
"{src,test}/**/*.{js,mjs}",
|
|
348
|
+
"{src,test}/**/*.{js,mjs,ts,mts}",
|
|
354
349
|
"{config,test}/**/*.{js,json}",
|
|
355
350
|
"tools/*.{js,mjs,json}",
|
|
356
351
|
"types/*.ts",
|
|
@@ -359,9 +354,9 @@
|
|
|
359
354
|
]
|
|
360
355
|
},
|
|
361
356
|
"lint:fix:types": {
|
|
362
|
-
"command": "eslint --fix types/*.d.ts",
|
|
357
|
+
"command": "eslint --fix types/*.d.ts src/cli/*.d.mts src/cli/*.d.ts src/parse/scxml/*.d.ts",
|
|
363
358
|
"files": [
|
|
364
|
-
"types
|
|
359
|
+
"{src,types}/**/*.d.{ts,mts}",
|
|
365
360
|
".eslintrc.json"
|
|
366
361
|
]
|
|
367
362
|
},
|
|
@@ -372,7 +367,7 @@
|
|
|
372
367
|
]
|
|
373
368
|
},
|
|
374
369
|
"test:cover": {
|
|
375
|
-
"command": "c8 --all --check-coverage --statements 100 --branches 99.1 --functions 100 --lines 100 --exclude \"{bin/*,config/**/*,coverage/**/*,docs/**/*,public/**/*,test/**/*,tools/**/*,types/**/*,dist/commonjs/*,src/**/*{template,-parser}.{mjs,cjs,js},tmp*}\" --reporter text-summary --reporter html --reporter lcov mocha",
|
|
370
|
+
"command": "c8 --all --check-coverage --statements 100 --branches 99.1 --functions 100 --lines 100 --exclude \"{bin/*,config/**/*,coverage/**/*,docs/**/*,public/**/*,test/**/*,tools/**/*,types/**/*,dist/commonjs/*,src/**/*.d.{ts,mts},src/**/*{template,-parser}.{mjs,cjs,js},tmp*}\" --reporter text-summary --reporter html --reporter lcov mocha",
|
|
376
371
|
"output": [
|
|
377
372
|
"coverage/lcov.info"
|
|
378
373
|
],
|
|
@@ -414,16 +409,16 @@
|
|
|
414
409
|
"wrap-ansi": "8.0.1"
|
|
415
410
|
},
|
|
416
411
|
"devDependencies": {
|
|
417
|
-
"@typescript-eslint/eslint-plugin": "5.
|
|
418
|
-
"@typescript-eslint/parser": "5.
|
|
412
|
+
"@typescript-eslint/eslint-plugin": "5.42.1",
|
|
413
|
+
"@typescript-eslint/parser": "5.42.1",
|
|
419
414
|
"c8": "7.12.0",
|
|
420
|
-
"chai": "4.3.
|
|
415
|
+
"chai": "4.3.7",
|
|
421
416
|
"chai-as-promised": "7.1.1",
|
|
422
417
|
"chai-json-schema": "1.5.1",
|
|
423
418
|
"chai-xml": "0.4.0",
|
|
424
|
-
"dependency-cruiser": "11.
|
|
425
|
-
"esbuild": "0.15.
|
|
426
|
-
"eslint": "8.
|
|
419
|
+
"dependency-cruiser": "11.18.0",
|
|
420
|
+
"esbuild": "0.15.13",
|
|
421
|
+
"eslint": "8.27.0",
|
|
427
422
|
"eslint-config-moving-meadow": "4.0.2",
|
|
428
423
|
"eslint-config-prettier": "8.5.0",
|
|
429
424
|
"eslint-plugin-budapestian": "5.0.1",
|
|
@@ -433,7 +428,7 @@
|
|
|
433
428
|
"eslint-plugin-node": "11.1.0",
|
|
434
429
|
"eslint-plugin-security": "1.5.0",
|
|
435
430
|
"eslint-plugin-unicorn": "44.0.2",
|
|
436
|
-
"husky": "8.0.
|
|
431
|
+
"husky": "8.0.2",
|
|
437
432
|
"is-pdf": "1.0.0",
|
|
438
433
|
"is-png": "3.0.1",
|
|
439
434
|
"lint-staged": "13.0.3",
|
|
@@ -443,7 +438,7 @@
|
|
|
443
438
|
"prettier": "2.7.1",
|
|
444
439
|
"query-string": "7.1.1",
|
|
445
440
|
"typescript": "4.8.4",
|
|
446
|
-
"upem": "7.3.
|
|
441
|
+
"upem": "7.3.1",
|
|
447
442
|
"watskeburt": "0.8.1",
|
|
448
443
|
"wireit": "0.7.2",
|
|
449
444
|
"xml-name-validator": "4.0.0"
|
package/src/cli/actions.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
import getStream from "get-stream";
|
|
2
3
|
import smcat from "../index-node.mjs";
|
|
3
4
|
import { getOutStream, getInStream } from "./file-name-to-stream.mjs";
|
|
@@ -31,7 +32,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
31
32
|
`;
|
|
32
33
|
|
|
33
34
|
export default {
|
|
35
|
+
/** @type {string} */
|
|
34
36
|
LICENSE,
|
|
37
|
+
/**
|
|
38
|
+
* @param {import("./cli").ICLIRenderOptions} pOptions
|
|
39
|
+
*/
|
|
35
40
|
transform(pOptions) {
|
|
36
41
|
return getStream(getInStream(pOptions.inputFrom)).then((pInput) => {
|
|
37
42
|
const lOutput = smcat.render(pInput, {
|
|
@@ -54,6 +59,10 @@ export default {
|
|
|
54
59
|
});
|
|
55
60
|
},
|
|
56
61
|
|
|
62
|
+
/**
|
|
63
|
+
* @param {any} pError
|
|
64
|
+
* @returns {string}
|
|
65
|
+
*/
|
|
57
66
|
formatError(pError) {
|
|
58
67
|
if (Boolean(pError.location)) {
|
|
59
68
|
return `\n syntax error on line ${pError.location.start.line}, column ${pError.location.start.column}:\n ${pError.message}\n\n`;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
/* eslint-disable security/detect-non-literal-fs-filename */
|
|
2
|
-
|
|
3
|
-
import * as fs from "node:fs";
|
|
3
|
+
import fs from "node:fs";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
6
|
* @param {string} pOutputTo
|
|
8
|
-
* @returns {
|
|
7
|
+
* @returns {NodeJS.WritableStream}
|
|
9
8
|
*/
|
|
10
9
|
export function getOutStream(pOutputTo) {
|
|
11
10
|
if ("-" === pOutputTo) {
|
|
@@ -13,10 +12,10 @@ export function getOutStream(pOutputTo) {
|
|
|
13
12
|
}
|
|
14
13
|
return fs.createWriteStream(pOutputTo);
|
|
15
14
|
}
|
|
15
|
+
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
18
17
|
* @param {string} pInputFrom
|
|
19
|
-
* @returns {
|
|
18
|
+
* @returns {NodeJS.ReadableStream}
|
|
20
19
|
*/
|
|
21
20
|
export function getInStream(pInputFrom) {
|
|
22
21
|
if ("-" === pInputFrom) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
// seems eslint-plugin-import and eslint-plugin-node can't handle exports
|
|
2
3
|
// fields yet. No man overboard not checking against this, because dependency-cruiser
|
|
3
4
|
// will also find them
|
|
@@ -7,6 +8,10 @@ import indentString from "indent-string";
|
|
|
7
8
|
import wrapAnsi from "wrap-ansi";
|
|
8
9
|
import dotToVectorNative from "../render/vector/dot-to-vector-native.mjs";
|
|
9
10
|
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} pString
|
|
13
|
+
* @returns {string}
|
|
14
|
+
*/
|
|
10
15
|
function wrapAndIndent(pString) {
|
|
11
16
|
const lDogmaticMaxConsoleWidth = 78;
|
|
12
17
|
const lDefaultIndent = 2;
|
|
@@ -16,6 +21,10 @@ function wrapAndIndent(pString) {
|
|
|
16
21
|
return indentString(wrapAnsi(pString, lMaxWidth), lDefaultIndent);
|
|
17
22
|
}
|
|
18
23
|
|
|
24
|
+
/**
|
|
25
|
+
* @param {boolean} pDotIsAvailable
|
|
26
|
+
* @return {string}
|
|
27
|
+
*/
|
|
19
28
|
export default (pDotIsAvailable = dotToVectorNative.isAvailable({})) => {
|
|
20
29
|
const lDescription =
|
|
21
30
|
"Write beautiful state charts - https://github.com/sverweij/state-machine-cat";
|
package/src/cli/normalize.mjs
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
// @ts-check
|
|
2
|
+
/* eslint-disable security/detect-object-injection, no-inline-comments */
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import options from "../options.mjs";
|
|
4
5
|
import { parse as parseAttributes } from "./attributes-parser.mjs";
|
|
5
6
|
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {{[extension: string]: string}} DictionaryType
|
|
9
|
+
*/
|
|
10
|
+
|
|
6
11
|
const INPUT_EXTENSIONS = {
|
|
7
12
|
".smcat": "smcat",
|
|
8
13
|
".scxml": "scxml",
|
|
@@ -11,16 +16,18 @@ const INPUT_EXTENSIONS = {
|
|
|
11
16
|
".ast": "json",
|
|
12
17
|
};
|
|
13
18
|
const OUTPUT_EXTENSIONS = {
|
|
14
|
-
".
|
|
19
|
+
".ast": "json",
|
|
15
20
|
".dot": "dot",
|
|
21
|
+
".eps": "eps",
|
|
16
22
|
".json": "json",
|
|
17
|
-
".
|
|
23
|
+
".pdf": "pdf",
|
|
24
|
+
".png": "png",
|
|
25
|
+
".ps": "ps",
|
|
26
|
+
".ps2": "ps2",
|
|
18
27
|
".scjson": "scjson",
|
|
19
28
|
".scxml": "scxml",
|
|
29
|
+
".smcat": "smcat",
|
|
20
30
|
".svg": "svg",
|
|
21
|
-
".ps": "ps",
|
|
22
|
-
".ps2": "ps2",
|
|
23
|
-
".eps": "eps",
|
|
24
31
|
};
|
|
25
32
|
|
|
26
33
|
/**
|
|
@@ -31,7 +38,7 @@ const OUTPUT_EXTENSIONS = {
|
|
|
31
38
|
* When in doubt returns pDefault
|
|
32
39
|
*
|
|
33
40
|
* @param {string} pString - filename
|
|
34
|
-
* @param {
|
|
41
|
+
* @param {DictionaryType} pExtensionMap - a dictionary with
|
|
35
42
|
* extension : classification pairs
|
|
36
43
|
* @param {string} pDefault - the default to return when the extension
|
|
37
44
|
* does not occur in the extension map
|
|
@@ -42,15 +49,26 @@ function classifyExtension(pString, pExtensionMap, pDefault) {
|
|
|
42
49
|
return pExtensionMap[path.extname(pString)] || pDefault;
|
|
43
50
|
}
|
|
44
51
|
|
|
52
|
+
/**
|
|
53
|
+
* @param {import("../../types/state-machine-cat").OutputType} pOutputType
|
|
54
|
+
* @returns {import("../../types/state-machine-cat").OutputType}
|
|
55
|
+
*/
|
|
45
56
|
function outputType2Extension(pOutputType) {
|
|
46
57
|
const lExceptions = {
|
|
47
|
-
oldsvg: "svg",
|
|
48
|
-
oldps2: "ps",
|
|
49
58
|
oldeps: "eps",
|
|
59
|
+
oldps: "ps",
|
|
60
|
+
oldps2: "ps",
|
|
61
|
+
oldsvg: "svg",
|
|
50
62
|
ps2: "ps",
|
|
51
63
|
};
|
|
52
64
|
return lExceptions[pOutputType] || pOutputType;
|
|
53
65
|
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param {string} pInputFrom
|
|
69
|
+
* @param {import("../../types/state-machine-cat").OutputType} pOutputType
|
|
70
|
+
* @returns {string}
|
|
71
|
+
*/
|
|
54
72
|
function deriveOutputFromInput(pInputFrom, pOutputType) {
|
|
55
73
|
const lExtension = outputType2Extension(pOutputType);
|
|
56
74
|
|
|
@@ -66,16 +84,28 @@ function deriveOutputFromInput(pInputFrom, pOutputType) {
|
|
|
66
84
|
.concat(lExtension);
|
|
67
85
|
}
|
|
68
86
|
|
|
87
|
+
/**
|
|
88
|
+
* @param {string|undefined} pOutputTo
|
|
89
|
+
* @param {string} pInputFrom
|
|
90
|
+
* @param {import("../../types/state-machine-cat").OutputType} pOutputType
|
|
91
|
+
* @returns {string}
|
|
92
|
+
*/
|
|
69
93
|
function determineOutputTo(pOutputTo, pInputFrom, pOutputType) {
|
|
70
|
-
return
|
|
71
|
-
? pOutputTo
|
|
72
|
-
: deriveOutputFromInput(pInputFrom, pOutputType);
|
|
94
|
+
return pOutputTo ? pOutputTo : deriveOutputFromInput(pInputFrom, pOutputType);
|
|
73
95
|
}
|
|
74
96
|
|
|
97
|
+
/**
|
|
98
|
+
* @param {import("../../types/state-machine-cat").InputType|undefined} pInputType
|
|
99
|
+
* @param {string} pInputFrom
|
|
100
|
+
* @returns {import("../../types/state-machine-cat").InputType}
|
|
101
|
+
*/
|
|
75
102
|
function determineInputType(pInputType, pInputFrom) {
|
|
76
103
|
if (pInputType) {
|
|
77
104
|
return pInputType;
|
|
78
105
|
}
|
|
106
|
+
// @ts-expect-error we can safely cast this to InputType. classifyExtension
|
|
107
|
+
// can probably use treatment with a generic, but with jsdoc annotations
|
|
108
|
+
// if at all possible would likely be awkward.
|
|
79
109
|
return classifyExtension(
|
|
80
110
|
pInputFrom,
|
|
81
111
|
INPUT_EXTENSIONS,
|
|
@@ -103,9 +133,16 @@ function determineParameter(pOptions, pParameter) {
|
|
|
103
133
|
: options.getAllowedValues()[pParameter].default;
|
|
104
134
|
}
|
|
105
135
|
|
|
136
|
+
/**
|
|
137
|
+
* @param {Partial<import("./cli").ILooseCLIRenderOptions>} pOptions
|
|
138
|
+
* @param {keyof import("./cli").ILooseCLIRenderOptions} pDotAttributes
|
|
139
|
+
* @returns {import("../../types/state-machine-cat").dotAttributesType}
|
|
140
|
+
*/
|
|
106
141
|
function determineDotAttributes(pOptions, pDotAttributes) {
|
|
107
|
-
return
|
|
108
|
-
|
|
142
|
+
return Boolean(pOptions?.[pDotAttributes]) &&
|
|
143
|
+
typeof pOptions[pDotAttributes] === "string"
|
|
144
|
+
? // @ts-expect-error parseAttributes expects a string - which we can guarantee (see above) - but tsc can't/ doesn't see it
|
|
145
|
+
parseAttributes(pOptions[pDotAttributes])
|
|
109
146
|
: [];
|
|
110
147
|
}
|
|
111
148
|
|
|
@@ -114,38 +151,39 @@ function determineDotAttributes(pOptions, pDotAttributes) {
|
|
|
114
151
|
*
|
|
115
152
|
* - guesses the input type when not given
|
|
116
153
|
* - guesses the output type when not given
|
|
117
|
-
* -
|
|
154
|
+
* - guesses the filename to output to when not given
|
|
118
155
|
* - translates parserOutput to a regular output type
|
|
119
156
|
*
|
|
120
157
|
* @param {string} pArgument an argument (containing the filename to parse)
|
|
121
|
-
* @param {
|
|
122
|
-
* @return {
|
|
158
|
+
* @param {import("./cli").ILooseCLIRenderOptions} pLooseOptions
|
|
159
|
+
* @return {import("./cli").ICLIRenderOptions}
|
|
160
|
+
* the passed options object, but normalized
|
|
123
161
|
*/
|
|
124
|
-
export default function normalize(pArgument = "-",
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
pOptions.inputType,
|
|
130
|
-
lReturnValue.inputFrom
|
|
131
|
-
);
|
|
132
|
-
lReturnValue.outputType = determineOutputType(
|
|
133
|
-
pOptions.outputType,
|
|
134
|
-
pOptions.outputTo
|
|
162
|
+
export default function normalize(pArgument = "-", pLooseOptions = {}) {
|
|
163
|
+
const lNormalizedInputFrom = pArgument || "-";
|
|
164
|
+
const lNormalizedInputType = determineInputType(
|
|
165
|
+
pLooseOptions.inputType,
|
|
166
|
+
lNormalizedInputFrom
|
|
135
167
|
);
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
lReturnValue.outputType
|
|
168
|
+
const lNormalizedOutputType = determineOutputType(
|
|
169
|
+
pLooseOptions.outputType,
|
|
170
|
+
pLooseOptions.outputTo
|
|
140
171
|
);
|
|
141
|
-
lReturnValue.engine = determineParameter(pOptions, "engine");
|
|
142
|
-
lReturnValue.direction = determineParameter(pOptions, "direction");
|
|
143
|
-
lReturnValue.dotGraphAttrs = determineDotAttributes(
|
|
144
|
-
pOptions,
|
|
145
|
-
"dotGraphAttrs"
|
|
146
|
-
);
|
|
147
|
-
lReturnValue.dotNodeAttrs = determineDotAttributes(pOptions, "dotNodeAttrs");
|
|
148
|
-
lReturnValue.dotEdgeAttrs = determineDotAttributes(pOptions, "dotEdgeAttrs");
|
|
149
172
|
|
|
150
|
-
return
|
|
173
|
+
return {
|
|
174
|
+
inputFrom: lNormalizedInputFrom,
|
|
175
|
+
inputType: lNormalizedInputType,
|
|
176
|
+
outputType: lNormalizedOutputType,
|
|
177
|
+
outputTo: determineOutputTo(
|
|
178
|
+
pLooseOptions.outputTo,
|
|
179
|
+
lNormalizedInputFrom,
|
|
180
|
+
lNormalizedOutputType
|
|
181
|
+
),
|
|
182
|
+
engine: determineParameter(pLooseOptions, "engine"),
|
|
183
|
+
direction: determineParameter(pLooseOptions, "direction"),
|
|
184
|
+
dotGraphAttrs: determineDotAttributes(pLooseOptions, "dotGraphAttrs"),
|
|
185
|
+
dotNodeAttrs: determineDotAttributes(pLooseOptions, "dotNodeAttrs"),
|
|
186
|
+
dotEdgeAttrs: determineDotAttributes(pLooseOptions, "dotEdgeAttrs"),
|
|
187
|
+
desugar: pLooseOptions?.desugar ?? false,
|
|
188
|
+
};
|
|
151
189
|
}
|
package/src/cli/validations.mjs
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
import fs from "node:fs";
|
|
2
3
|
import smcat from "../index-node.mjs";
|
|
3
4
|
import { parse as parseAttributes } from "./attributes-parser.mjs";
|
|
4
5
|
|
|
5
6
|
const allowedValues = smcat.getAllowedValues();
|
|
6
7
|
|
|
8
|
+
/**
|
|
9
|
+
* @param {{name: string}} pValue
|
|
10
|
+
* @returns {string}
|
|
11
|
+
*/
|
|
7
12
|
function getName(pValue) {
|
|
8
13
|
return pValue.name;
|
|
9
14
|
}
|
|
@@ -13,14 +18,22 @@ const VALID_INPUT_TYPES = allowedValues.inputType.values.map(getName);
|
|
|
13
18
|
const VALID_ENGINES = allowedValues.engine.values.map(getName);
|
|
14
19
|
const VALID_DIRECTIONS = allowedValues.direction.values.map(getName);
|
|
15
20
|
|
|
21
|
+
/**
|
|
22
|
+
* @param {string} pFilename
|
|
23
|
+
* @returns {boolean}
|
|
24
|
+
*/
|
|
16
25
|
function isStdout(pFilename) {
|
|
17
26
|
return "-" === pFilename;
|
|
18
27
|
}
|
|
19
28
|
|
|
29
|
+
/**
|
|
30
|
+
* @param {string} pFilename
|
|
31
|
+
* @returns {boolean}
|
|
32
|
+
*/
|
|
20
33
|
function fileExists(pFilename) {
|
|
21
34
|
try {
|
|
22
35
|
if (!isStdout(pFilename)) {
|
|
23
|
-
fs.accessSync(pFilename, fs.R_OK);
|
|
36
|
+
fs.accessSync(pFilename, fs.constants.R_OK);
|
|
24
37
|
}
|
|
25
38
|
return true;
|
|
26
39
|
} catch (pError) {
|
|
@@ -28,6 +41,15 @@ function fileExists(pFilename) {
|
|
|
28
41
|
}
|
|
29
42
|
}
|
|
30
43
|
|
|
44
|
+
/**
|
|
45
|
+
* This function is shaped so it can serve as a validation function in a
|
|
46
|
+
* commander option.
|
|
47
|
+
*
|
|
48
|
+
* @param {keyof import("../../types/state-machine-cat").IRenderOptions} pOption
|
|
49
|
+
* @param {string[]} pValidValues
|
|
50
|
+
* @param {string} pError
|
|
51
|
+
* @returns {never|keyof import("../../types/state-machine-cat").IRenderOptions}
|
|
52
|
+
*/
|
|
31
53
|
function validOption(pOption, pValidValues, pError) {
|
|
32
54
|
if (pValidValues.includes(pOption)) {
|
|
33
55
|
return pOption;
|
|
@@ -78,6 +100,10 @@ export default {
|
|
|
78
100
|
}
|
|
79
101
|
},
|
|
80
102
|
|
|
103
|
+
/**
|
|
104
|
+
* @param {import("./cli").ICLIRenderOptions} pOptions
|
|
105
|
+
* @returns {never|import("./cli").ICLIRenderOptions}
|
|
106
|
+
*/
|
|
81
107
|
validateArguments(pOptions) {
|
|
82
108
|
if (!pOptions.inputFrom) {
|
|
83
109
|
throw new Error(`\n error: Please specify an input file.\n\n`);
|
package/src/index-node.mjs
CHANGED
|
@@ -1,52 +1,18 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
import options from "./options.mjs";
|
|
2
3
|
import parse from "./parse/index.mjs";
|
|
3
4
|
import desugar from "./transform/desugar.mjs";
|
|
4
5
|
import getRenderFunction from "./render/index-node.mjs";
|
|
5
6
|
import { version } from "./version.mjs";
|
|
6
7
|
|
|
7
|
-
const KNOWN_OPTIONS = [
|
|
8
|
-
"outputType",
|
|
9
|
-
"inputType",
|
|
10
|
-
"engine",
|
|
11
|
-
"direction",
|
|
12
|
-
"dotNodeAttrs",
|
|
13
|
-
"dotEdgeAttrs",
|
|
14
|
-
"desugar",
|
|
15
|
-
];
|
|
16
|
-
|
|
17
|
-
function isKnownOption(pKnownOptions) {
|
|
18
|
-
return (pCandidateString) => pKnownOptions.includes(pCandidateString);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Remove all attributes from the input object (which'd typically be
|
|
23
|
-
* originating from commander) that are not known options options so
|
|
24
|
-
* a clean object can be passed through.
|
|
25
|
-
*
|
|
26
|
-
* @param {any} pOptions - an options object e.g. as output from commander
|
|
27
|
-
* @param {string[]} pKnownOptions - a list of known options
|
|
28
|
-
* @return {any} - an options object that only contains stuff we care about
|
|
29
|
-
*/
|
|
30
|
-
function ejectUnknownOptions(pOptions, pKnownOptions) {
|
|
31
|
-
return Object.keys(pOptions)
|
|
32
|
-
.filter(isKnownOption(pKnownOptions))
|
|
33
|
-
.reduce((pAll, pKey) => {
|
|
34
|
-
// eslint-disable-next-line security/detect-object-injection
|
|
35
|
-
pAll[pKey] = pOptions[pKey];
|
|
36
|
-
return pAll;
|
|
37
|
-
}, {});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
8
|
export default {
|
|
41
9
|
/**
|
|
42
|
-
* Translates the input script to an
|
|
10
|
+
* Translates the input script to an output-script.
|
|
43
11
|
*
|
|
44
|
-
* @param {string} pScript
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* string with the rendered content if
|
|
49
|
-
* no callback was passed and no error was found
|
|
12
|
+
* @param {string|import("../types/state-machine-cat").IStateMachine} pScript
|
|
13
|
+
* The script to translate
|
|
14
|
+
* @param {import("../types/state-machine-cat").IRenderOptions} pOptions
|
|
15
|
+
* options influencing parsing & rendering.
|
|
50
16
|
* @throws {Error} if an error occurred and no callback
|
|
51
17
|
* function was passed: the error
|
|
52
18
|
*
|
|
@@ -54,13 +20,15 @@ export default {
|
|
|
54
20
|
*
|
|
55
21
|
*/
|
|
56
22
|
render(pScript, pOptions) {
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
const lDesugar = options.getOptionValue(lOptions, "desugar");
|
|
23
|
+
const lStateMachine = parse.getAST(pScript, pOptions);
|
|
24
|
+
const lDesugar = options.getOptionValue(pOptions, "desugar");
|
|
60
25
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
26
|
+
// @ts-expect-error should be cast to OutputTypeType - or the getOptionValue
|
|
27
|
+
// function should be refactored to be more explicit in type it returns
|
|
28
|
+
// when we ask for outputType
|
|
29
|
+
return getRenderFunction(options.getOptionValue(pOptions, "outputType"))(
|
|
30
|
+
lDesugar ? desugar(lStateMachine) : lStateMachine,
|
|
31
|
+
pOptions
|
|
64
32
|
);
|
|
65
33
|
},
|
|
66
34
|
|
|
@@ -79,7 +47,7 @@ export default {
|
|
|
79
47
|
* - the possible values in an array of objects, each of which
|
|
80
48
|
* has the properties:
|
|
81
49
|
* - name: the value
|
|
82
|
-
*
|
|
50
|
+
* @returns {import("../types/state-machine-cat").IAllowedValues}
|
|
83
51
|
*/
|
|
84
52
|
getAllowedValues() {
|
|
85
53
|
return options.getAllowedValues();
|
package/src/index.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
/* eslint-disable budapestian/global-constant-pattern */
|
|
2
3
|
import options from "./options.mjs";
|
|
3
4
|
import parse from "./parse/index.mjs";
|
|
@@ -8,12 +9,11 @@ import { version as _version } from "./version.mjs";
|
|
|
8
9
|
/**
|
|
9
10
|
* Translates the input script to an output-script.
|
|
10
11
|
*
|
|
11
|
-
* @param {string} pScript
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* no callback was passed and no error was found
|
|
12
|
+
* @param {string|import("../types/state-machine-cat").IStateMachine} pScript
|
|
13
|
+
* The script to translate
|
|
14
|
+
* @param {import("../types/state-machine-cat").IRenderOptions} pOptions
|
|
15
|
+
* options influencing parsing & rendering.
|
|
16
|
+
* @return {string}
|
|
17
17
|
* @throws {Error} if an error occurred and no callback
|
|
18
18
|
* function was passed: the error
|
|
19
19
|
*
|
|
@@ -21,11 +21,11 @@ import { version as _version } from "./version.mjs";
|
|
|
21
21
|
*
|
|
22
22
|
*/
|
|
23
23
|
export function render(pScript, pOptions) {
|
|
24
|
-
const
|
|
24
|
+
const lStateMachine = parse.getAST(pScript, pOptions);
|
|
25
25
|
const lDesugar = options.getOptionValue(pOptions, "desugar");
|
|
26
26
|
|
|
27
27
|
return getRenderFunction(options.getOptionValue(pOptions, "outputType"))(
|
|
28
|
-
lDesugar ? desugar(
|
|
28
|
+
lDesugar ? desugar(lStateMachine) : lStateMachine,
|
|
29
29
|
pOptions
|
|
30
30
|
);
|
|
31
31
|
}
|
|
@@ -45,7 +45,7 @@ export const version = _version;
|
|
|
45
45
|
* - the possible values in an array of objects, each of which
|
|
46
46
|
* has the properties:
|
|
47
47
|
* - name: the value
|
|
48
|
-
*
|
|
48
|
+
* @returns {import("../types/state-machine-cat").IAllowedValues}
|
|
49
49
|
*/
|
|
50
50
|
export function getAllowedValues() {
|
|
51
51
|
return options.getAllowedValues();
|
package/src/options.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/** @type {import("../types/state-machine-cat").IAllowedValues} */
|
|
1
3
|
const ALLOWED_VALUES = Object.freeze({
|
|
2
4
|
inputType: {
|
|
3
5
|
default: "smcat",
|
|
@@ -6,21 +8,22 @@ const ALLOWED_VALUES = Object.freeze({
|
|
|
6
8
|
outputType: {
|
|
7
9
|
default: "svg",
|
|
8
10
|
values: [
|
|
9
|
-
{ name: "
|
|
10
|
-
{ name: "eps" },
|
|
11
|
-
{ name: "ps" },
|
|
12
|
-
{ name: "ps2" },
|
|
11
|
+
{ name: "ast" },
|
|
13
12
|
{ name: "dot" },
|
|
14
|
-
{ name: "
|
|
13
|
+
{ name: "eps" },
|
|
15
14
|
{ name: "json" },
|
|
16
|
-
{ name: "ast" },
|
|
17
|
-
{ name: "scxml" },
|
|
18
|
-
{ name: "oldsvg" },
|
|
19
|
-
{ name: "oldps2" },
|
|
20
15
|
{ name: "oldeps" },
|
|
21
|
-
{ name: "
|
|
16
|
+
{ name: "oldps" },
|
|
17
|
+
{ name: "oldps2" },
|
|
18
|
+
{ name: "oldsvg" },
|
|
22
19
|
{ name: "pdf" },
|
|
23
20
|
{ name: "png" },
|
|
21
|
+
{ name: "ps" },
|
|
22
|
+
{ name: "ps2" },
|
|
23
|
+
{ name: "scjson" },
|
|
24
|
+
{ name: "scxml" },
|
|
25
|
+
{ name: "smcat" },
|
|
26
|
+
{ name: "svg" },
|
|
24
27
|
],
|
|
25
28
|
},
|
|
26
29
|
engine: {
|
|
@@ -53,15 +56,18 @@ const ALLOWED_VALUES = Object.freeze({
|
|
|
53
56
|
* Returns the value for the option in the pOption object, and the default
|
|
54
57
|
* for that option in all other cases
|
|
55
58
|
*
|
|
56
|
-
* @param {
|
|
57
|
-
* @param {
|
|
58
|
-
* @return {
|
|
59
|
+
* @param {import("../types/state-machine-cat").IRenderOptions} pOptions - the options as passed in the api `render` function
|
|
60
|
+
* @param {keyof import("../types/state-machine-cat").IRenderOptions} pOptionName - the name of the option
|
|
61
|
+
* @return {string|boolean} value
|
|
59
62
|
*/
|
|
60
63
|
function getOptionValue(pOptions, pOptionName) {
|
|
61
64
|
// eslint-disable-next-line security/detect-object-injection
|
|
62
65
|
return pOptions?.[pOptionName] ?? ALLOWED_VALUES[pOptionName].default;
|
|
63
66
|
}
|
|
64
67
|
|
|
68
|
+
/**
|
|
69
|
+
* @returns {import("../types/state-machine-cat").IAllowedValues}
|
|
70
|
+
*/
|
|
65
71
|
function getAllowedValues() {
|
|
66
72
|
return ALLOWED_VALUES;
|
|
67
73
|
}
|