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.
Files changed (37) hide show
  1. package/README.md +1 -1
  2. package/bin/smcat.mjs +5 -0
  3. package/dist/commonjs/bundle.js +64 -64
  4. package/package.json +40 -69
  5. package/src/cli/actions.mjs +9 -0
  6. package/src/cli/file-name-to-stream.mjs +5 -6
  7. package/src/cli/make-description.mjs +9 -0
  8. package/src/cli/normalize.mjs +100 -47
  9. package/src/cli/validations.mjs +27 -1
  10. package/src/index-node.mjs +15 -47
  11. package/src/index.mjs +9 -9
  12. package/src/options.mjs +19 -13
  13. package/src/parse/index.mjs +13 -0
  14. package/src/parse/parser-helpers.mjs +70 -6
  15. package/src/parse/scxml/index.mjs +72 -20
  16. package/src/parse/scxml/normalize-machine.mjs +27 -21
  17. package/src/render/dot/README.md +12 -0
  18. package/src/render/dot/attributebuilder.mjs +7 -0
  19. package/src/render/dot/counter.mjs +13 -0
  20. package/src/render/dot/index.mjs +66 -28
  21. package/src/render/dot/render-dot-from-ast.js +37 -15
  22. package/src/render/dot/state-transformers.mjs +4 -2
  23. package/src/render/dot/utl.mjs +20 -0
  24. package/src/render/index-node.mjs +9 -3
  25. package/src/render/index.mjs +3 -3
  26. package/src/render/scjson/index.mjs +6 -0
  27. package/src/render/scjson/make-valid-xml-name.mjs +7 -1
  28. package/src/render/scxml/index.mjs +2 -0
  29. package/src/render/smcat/index.js +48 -14
  30. package/src/render/vector/dot-to-vector-native.mjs +1 -1
  31. package/src/render/vector/vector-native-dot-with-fallback.mjs +3 -2
  32. package/src/render/vector/vector-with-viz-js.mjs +3 -2
  33. package/src/state-machine-model.mjs +46 -4
  34. package/src/transform/desugar.mjs +67 -18
  35. package/src/transform/utl.mjs +8 -0
  36. package/src/version.mjs +1 -1
  37. 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.2",
3
+ "version": "10.1.5",
4
4
  "description": "write beautiful state charts",
5
5
  "main": "./dist/commonjs/index.js",
6
6
  "module": "./src/index.mjs",
@@ -38,10 +38,9 @@
38
38
  "depcruise:graph:dev": "wireit",
39
39
  "depcruise:graph:dev:flat": "wireit",
40
40
  "depcruise:view-report": "wireit",
41
- "depcruise:github-actions:markdown": "wireit",
42
- "depcruise:github-actions:mermaid": "wireit",
43
- "depcruise:github-actions:mermaid:affected": "wireit",
44
- "depcruise:github-actions:mermaid:diff": "wireit",
41
+ "depcruise:github-actions:markdown": "depcruise bin src test types --config config/dependency-cruiser.js --output-type markdown",
42
+ "depcruise:github-actions:mermaid": "depcruise bin src --include-only '^(bin|src)' --config config/dependency-cruiser.js --output-type mermaid",
43
+ "depcruise:github-actions:mermaid:affected": "depcruise bin src test types tools --config config/dependency-cruiser.js --output-type mermaid --reaches \"$(watskeburt $SHA -T regex)\"",
45
44
  "lint": "wireit",
46
45
  "lint:eslint": "wireit",
47
46
  "lint:prettier": "wireit",
@@ -90,11 +89,6 @@
90
89
  "policy": "wanted",
91
90
  "because": "fast-xml-parser 4 has some breaking changes we still need to grok (why? how?)"
92
91
  },
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
92
  {
99
93
  "package": "viz.js",
100
94
  "policy": "pin",
@@ -120,7 +114,7 @@
120
114
  "packageLocks": []
121
115
  },
122
116
  "depcruise:json": {
123
- "command": "dependency-cruise --progress none --output-type json --output-to node_modules/.cache/depcruise-cache.json --config config/dependency-cruiser.js src test bin",
117
+ "command": "dependency-cruise --progress performance-log --output-type json --output-to node_modules/.cache/depcruise-cache.json --config config/dependency-cruiser.js src test bin",
124
118
  "files": [
125
119
  "src/**/*",
126
120
  "test/**/*",
@@ -244,13 +238,13 @@
244
238
  ]
245
239
  },
246
240
  "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",
241
+ "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
242
  "dependencies": [
249
243
  "depcruise:json"
250
244
  ]
251
245
  },
252
246
  "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",
247
+ "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
248
  "dependencies": [
255
249
  "depcruise:json"
256
250
  ]
@@ -261,30 +255,6 @@
261
255
  "depcruise:json"
262
256
  ]
263
257
  },
264
- "depcruise:github-actions:markdown": {
265
- "command": "depcruise-fmt node_modules/.cache/depcruise-cache.json --output-type markdown >> $GITHUB_STEP_SUMMARY",
266
- "dependencies": [
267
- "depcruise:json"
268
- ]
269
- },
270
- "depcruise:github-actions:mermaid": {
271
- "command": "echo '\n\n```mermaid' >> $GITHUB_STEP_SUMMARY && depcruise-fmt node_modules/.cache/depcruise-cache.json --include-only '^(bin|src)' --output-type mermaid >> $GITHUB_STEP_SUMMARY && echo '```\n\n' >> $GITHUB_STEP_SUMMARY",
272
- "dependencies": [
273
- "depcruise:json"
274
- ]
275
- },
276
- "depcruise:github-actions:mermaid:affected": {
277
- "command": "echo '\n\n```mermaid' >> $GITHUB_STEP_SUMMARY && depcruise-fmt node_modules/.cache/depcruise-cache.json --include-only --reaches '$(watskeburt $SHA -T regex)' --output-type mermaid >> $GITHUB_STEP_SUMMARY && echo '```\n\n' >> $GITHUB_STEP_SUMMARY",
278
- "dependencies": [
279
- "depcruise:json"
280
- ]
281
- },
282
- "depcruise:github-actions:mermaid:diff": {
283
- "command": "echo '\n\n```mermaid' >> $GITHUB_STEP_SUMMARY && depcruise-fmt node_modules/.cache/depcruise-cache.json --include-only '^(bin|src)' --highlight '$(watskeburt $SHA -T regex)' --output-type mermaid >> $GITHUB_STEP_SUMMARY && echo '```\n\n' >> $GITHUB_STEP_SUMMARY",
284
- "dependencies": [
285
- "depcruise:json"
286
- ]
287
- },
288
258
  "lint": {
289
259
  "dependencies": [
290
260
  "lint:eslint",
@@ -301,7 +271,7 @@
301
271
  ]
302
272
  },
303
273
  "lint:prettier": {
304
- "command": "prettier --check \"bin/*.mjs\" \"{src,test}/**/*.{js,mjs}\" \"{config,test}/**/*.{js,json}\" \"tools/*.{js,mjs,json}\" \"types/*.ts\" \"*.{json,yml,md}\" \"docs/{smcat-online-interpreter.js,*.md}\"",
274
+ "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
275
  "files": [
306
276
  "bin/*.mjs",
307
277
  "{src,test}/**/*.{js,mjs}",
@@ -319,15 +289,15 @@
319
289
  ]
320
290
  },
321
291
  "lint:types:tsc": {
322
- "command": "tsc --noEmit --strict --types --noUnusedLocals --noUnusedParameters --pretty types/*.d.ts",
292
+ "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
293
  "files": [
324
294
  "types/*.d.ts"
325
295
  ]
326
296
  },
327
297
  "lint:types:eslint": {
328
- "command": "eslint types/*.d.ts",
298
+ "command": "eslint types/*.d.ts src/cli/*.d.mts src/cli/*.d.ts src/parse/scxml/*.d.ts",
329
299
  "files": [
330
- "types/*.d.ts",
300
+ "{src,types}/**/*.d.{ts,mts}",
331
301
  ".eslintrc.json"
332
302
  ]
333
303
  },
@@ -347,10 +317,10 @@
347
317
  ]
348
318
  },
349
319
  "lint:fix:prettier": {
350
- "command": "prettier --loglevel warn --write \"bin/*.mjs\" \"{src,test}/**/*.{js,mjs}\" \"{config,test}/**/*.{js,json}\" \"tools/*.{js,mjs,json}\" \"types/*.ts\" \"*.{json,yml,md}\" \"docs/{smcat-online-interpreter.js,*.md}\"",
320
+ "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
321
  "files": [
352
322
  "bin/*.mjs",
353
- "{src,test}/**/*.{js,mjs}",
323
+ "{src,test}/**/*.{js,mjs,ts,mts}",
354
324
  "{config,test}/**/*.{js,json}",
355
325
  "tools/*.{js,mjs,json}",
356
326
  "types/*.ts",
@@ -359,9 +329,9 @@
359
329
  ]
360
330
  },
361
331
  "lint:fix:types": {
362
- "command": "eslint --fix types/*.d.ts",
332
+ "command": "eslint --fix types/*.d.ts src/cli/*.d.mts src/cli/*.d.ts src/parse/scxml/*.d.ts",
363
333
  "files": [
364
- "types/*.d.ts",
334
+ "{src,types}/**/*.d.{ts,mts}",
365
335
  ".eslintrc.json"
366
336
  ]
367
337
  },
@@ -372,9 +342,10 @@
372
342
  ]
373
343
  },
374
344
  "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",
345
+ "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 --reporter json-summary mocha",
376
346
  "output": [
377
- "coverage/lcov.info"
347
+ "coverage/lcov.info",
348
+ "coverage/coverage-summary.json"
378
349
  ],
379
350
  "files": [
380
351
  "{src,test}/**/*.{js,mjs,json}"
@@ -400,9 +371,9 @@
400
371
  "state-machine-cat": "bin/smcat.mjs"
401
372
  },
402
373
  "dependencies": {
403
- "ajv": "8.11.0",
404
- "chalk": "5.1.2",
405
- "commander": "9.4.1",
374
+ "ajv": "8.12.0",
375
+ "chalk": "5.2.0",
376
+ "commander": "10.0.0",
406
377
  "fast-xml-parser": "3.21.1",
407
378
  "get-stream": "6.0.1",
408
379
  "handlebars": "4.7.7",
@@ -414,38 +385,38 @@
414
385
  "wrap-ansi": "8.0.1"
415
386
  },
416
387
  "devDependencies": {
417
- "@typescript-eslint/eslint-plugin": "5.40.1",
418
- "@typescript-eslint/parser": "5.40.1",
388
+ "@typescript-eslint/eslint-plugin": "5.48.2",
389
+ "@typescript-eslint/parser": "5.48.2",
419
390
  "c8": "7.12.0",
420
- "chai": "4.3.6",
391
+ "chai": "4.3.7",
421
392
  "chai-as-promised": "7.1.1",
422
393
  "chai-json-schema": "1.5.1",
423
394
  "chai-xml": "0.4.0",
424
- "dependency-cruiser": "11.17.0",
425
- "esbuild": "0.15.12",
426
- "eslint": "8.26.0",
395
+ "dependency-cruiser": "12.5.1",
396
+ "esbuild": "0.17.3",
397
+ "eslint": "8.32.0",
427
398
  "eslint-config-moving-meadow": "4.0.2",
428
- "eslint-config-prettier": "8.5.0",
399
+ "eslint-config-prettier": "8.6.0",
429
400
  "eslint-plugin-budapestian": "5.0.1",
430
401
  "eslint-plugin-eslint-comments": "3.2.0",
431
- "eslint-plugin-import": "2.26.0",
402
+ "eslint-plugin-import": "2.27.5",
432
403
  "eslint-plugin-mocha": "10.1.0",
433
404
  "eslint-plugin-node": "11.1.0",
434
- "eslint-plugin-security": "1.5.0",
435
- "eslint-plugin-unicorn": "44.0.2",
436
- "husky": "8.0.1",
405
+ "eslint-plugin-security": "1.6.0",
406
+ "eslint-plugin-unicorn": "45.0.2",
407
+ "husky": "8.0.3",
437
408
  "is-pdf": "1.0.0",
438
409
  "is-png": "3.0.1",
439
- "lint-staged": "13.0.3",
440
- "mocha": "10.1.0",
410
+ "lint-staged": "13.1.0",
411
+ "mocha": "10.2.0",
441
412
  "npm-run-all": "4.1.5",
442
413
  "peggy": "2.0.1",
443
- "prettier": "2.7.1",
444
- "query-string": "7.1.1",
445
- "typescript": "4.8.4",
446
- "upem": "7.3.0",
447
- "watskeburt": "0.8.1",
448
- "wireit": "0.7.2",
414
+ "prettier": "2.8.3",
415
+ "query-string": "8.1.0",
416
+ "typescript": "4.9.4",
417
+ "upem": "7.3.1",
418
+ "watskeburt": "0.9.0",
419
+ "wireit": "0.9.3",
449
420
  "xml-name-validator": "4.0.0"
450
421
  },
451
422
  "eslintIgnore": [
@@ -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 {import("node:fs").WriteStream}
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 {import("node:fs").ReadStream}
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";
@@ -1,8 +1,13 @@
1
- /* eslint-disable security/detect-object-injection */
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",
@@ -10,17 +15,20 @@ const INPUT_EXTENSIONS = {
10
15
  ".json": "json",
11
16
  ".ast": "json",
12
17
  };
18
+
13
19
  const OUTPUT_EXTENSIONS = {
14
- ".smcat": "smcat",
20
+ ".ast": "json",
15
21
  ".dot": "dot",
22
+ ".eps": "eps",
16
23
  ".json": "json",
17
- ".ast": "json",
24
+ ".pdf": "pdf",
25
+ ".png": "png",
26
+ ".ps": "ps",
27
+ ".ps2": "ps2",
18
28
  ".scjson": "scjson",
19
29
  ".scxml": "scxml",
30
+ ".smcat": "smcat",
20
31
  ".svg": "svg",
21
- ".ps": "ps",
22
- ".ps2": "ps2",
23
- ".eps": "eps",
24
32
  };
25
33
 
26
34
  /**
@@ -31,7 +39,7 @@ const OUTPUT_EXTENSIONS = {
31
39
  * When in doubt returns pDefault
32
40
  *
33
41
  * @param {string} pString - filename
34
- * @param {object} pExtensionMap - a dictionary with
42
+ * @param {DictionaryType} pExtensionMap - a dictionary with
35
43
  * extension : classification pairs
36
44
  * @param {string} pDefault - the default to return when the extension
37
45
  * does not occur in the extension map
@@ -42,15 +50,26 @@ function classifyExtension(pString, pExtensionMap, pDefault) {
42
50
  return pExtensionMap[path.extname(pString)] || pDefault;
43
51
  }
44
52
 
53
+ /**
54
+ * @param {import("../..").OutputType} pOutputType
55
+ * @returns {import("../..").OutputType}
56
+ */
45
57
  function outputType2Extension(pOutputType) {
46
58
  const lExceptions = {
47
- oldsvg: "svg",
48
- oldps2: "ps",
49
59
  oldeps: "eps",
60
+ oldps: "ps",
61
+ oldps2: "ps",
62
+ oldsvg: "svg",
50
63
  ps2: "ps",
51
64
  };
52
65
  return lExceptions[pOutputType] || pOutputType;
53
66
  }
67
+
68
+ /**
69
+ * @param {string} pInputFrom
70
+ * @param {import("../..").OutputType} pOutputType
71
+ * @returns {string}
72
+ */
54
73
  function deriveOutputFromInput(pInputFrom, pOutputType) {
55
74
  const lExtension = outputType2Extension(pOutputType);
56
75
 
@@ -66,46 +85,79 @@ function deriveOutputFromInput(pInputFrom, pOutputType) {
66
85
  .concat(lExtension);
67
86
  }
68
87
 
88
+ /**
89
+ * @param {string|undefined} pOutputTo
90
+ * @param {string} pInputFrom
91
+ * @param {import("../..").OutputType} pOutputType
92
+ * @returns {string}
93
+ */
69
94
  function determineOutputTo(pOutputTo, pInputFrom, pOutputType) {
70
- return Boolean(pOutputTo)
71
- ? pOutputTo
72
- : deriveOutputFromInput(pInputFrom, pOutputType);
95
+ return pOutputTo ? pOutputTo : deriveOutputFromInput(pInputFrom, pOutputType);
73
96
  }
74
97
 
75
- function determineInputType(pInputType, pInputFrom) {
98
+ /**
99
+ * @param {string} pInputFrom
100
+ * @param {import("../..").InputType} [pInputType]
101
+ * @returns {import("../..").InputType}
102
+ */
103
+ function determineInputType(pInputFrom, pInputType) {
76
104
  if (pInputType) {
77
105
  return pInputType;
78
106
  }
107
+ // @ts-expect-error we can safely cast this to InputType. classifyExtension
108
+ // can probably use treatment with a generic, but with jsdoc annotations
109
+ // if at all possible would likely be awkward.
79
110
  return classifyExtension(
80
111
  pInputFrom,
81
112
  INPUT_EXTENSIONS,
82
113
  options.getAllowedValues().inputType.default
83
114
  );
84
115
  }
85
-
86
- function determineOutputType(pOutputType, pOutputTo) {
87
- if (Boolean(pOutputType)) {
116
+ /**
117
+ *
118
+ * @param {string} [pOutputTo]
119
+ * @param {import("../..").OutputType} [pOutputType]
120
+ * @returns {import("../..").OutputType}
121
+ */
122
+ function determineOutputType(pOutputTo, pOutputType) {
123
+ if (pOutputType) {
88
124
  return pOutputType;
89
125
  }
90
- if (Boolean(pOutputTo)) {
126
+ if (pOutputTo) {
127
+ // @ts-expect-error we can safely cast this to OutputType. classifyExtension
128
+ // can probably use treatment with a generic, but with jsdoc annotations
129
+ // if at all possible would likely be awkward.
91
130
  return classifyExtension(
92
131
  pOutputTo,
93
132
  OUTPUT_EXTENSIONS,
94
133
  options.getAllowedValues().outputType.default
95
134
  );
96
135
  }
136
+ // @ts-expect-error cast to OutputType is safe - see above
97
137
  return options.getAllowedValues().outputType.default;
98
138
  }
99
-
139
+ /**
140
+ *
141
+ * @param {import("./cli").ILooseCLIRenderOptions} pOptions
142
+ * @param {string} pParameter
143
+ * @returns string
144
+ */
100
145
  function determineParameter(pOptions, pParameter) {
101
146
  return Object.prototype.hasOwnProperty.call(pOptions, pParameter)
102
147
  ? pOptions[pParameter]
103
148
  : options.getAllowedValues()[pParameter].default;
104
149
  }
105
150
 
151
+ /**
152
+ * @param {Partial<import("./cli").ILooseCLIRenderOptions>} pOptions
153
+ * @param {keyof import("./cli").ILooseCLIRenderOptions} pDotAttributes
154
+ * @returns {import("../..").dotAttributesType}
155
+ */
106
156
  function determineDotAttributes(pOptions, pDotAttributes) {
107
- return Object.prototype.hasOwnProperty.call(pOptions, pDotAttributes)
108
- ? parseAttributes(pOptions[pDotAttributes])
157
+ return Boolean(pOptions?.[pDotAttributes]) &&
158
+ typeof pOptions[pDotAttributes] === "string"
159
+ ? // @ts-expect-error parseAttributes expects a string - which we can guarantee (see above) - but tsc can't/ doesn't see it
160
+ parseAttributes(pOptions[pDotAttributes])
109
161
  : [];
110
162
  }
111
163
 
@@ -114,38 +166,39 @@ function determineDotAttributes(pOptions, pDotAttributes) {
114
166
  *
115
167
  * - guesses the input type when not given
116
168
  * - guesses the output type when not given
117
- * - gueses the filename to output to when not given
169
+ * - guesses the filename to output to when not given
118
170
  * - translates parserOutput to a regular output type
119
171
  *
120
172
  * @param {string} pArgument an argument (containing the filename to parse)
121
- * @param {object} pOptions a commander options object
122
- * @return {object} a commander options object with options 'normalized'
173
+ * @param {import("./cli").ILooseCLIRenderOptions} pLooseOptions
174
+ * @return {import("./cli").ICLIRenderOptions}
175
+ * the passed options object, but normalized
123
176
  */
124
- export default function normalize(pArgument = "-", pOptions = {}) {
125
- const lReturnValue = { ...pOptions };
126
-
127
- lReturnValue.inputFrom = pArgument || "-";
128
- lReturnValue.inputType = determineInputType(
129
- pOptions.inputType,
130
- lReturnValue.inputFrom
131
- );
132
- lReturnValue.outputType = determineOutputType(
133
- pOptions.outputType,
134
- pOptions.outputTo
177
+ export default function normalize(pArgument = "-", pLooseOptions = {}) {
178
+ const lNormalizedInputFrom = pArgument || "-";
179
+ const lNormalizedInputType = determineInputType(
180
+ lNormalizedInputFrom,
181
+ pLooseOptions.inputType
135
182
  );
136
- lReturnValue.outputTo = determineOutputTo(
137
- pOptions.outputTo,
138
- lReturnValue.inputFrom,
139
- lReturnValue.outputType
183
+ const lNormalizedOutputType = determineOutputType(
184
+ pLooseOptions.outputTo,
185
+ pLooseOptions.outputType
140
186
  );
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
187
 
150
- return lReturnValue;
188
+ return {
189
+ inputFrom: lNormalizedInputFrom,
190
+ inputType: lNormalizedInputType,
191
+ outputType: lNormalizedOutputType,
192
+ outputTo: determineOutputTo(
193
+ pLooseOptions.outputTo,
194
+ lNormalizedInputFrom,
195
+ lNormalizedOutputType
196
+ ),
197
+ engine: determineParameter(pLooseOptions, "engine"),
198
+ direction: determineParameter(pLooseOptions, "direction"),
199
+ dotGraphAttrs: determineDotAttributes(pLooseOptions, "dotGraphAttrs"),
200
+ dotNodeAttrs: determineDotAttributes(pLooseOptions, "dotNodeAttrs"),
201
+ dotEdgeAttrs: determineDotAttributes(pLooseOptions, "dotEdgeAttrs"),
202
+ desugar: pLooseOptions?.desugar ?? false,
203
+ };
151
204
  }
@@ -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`);