@hpcc-js/wasm-graphviz-cli 1.5.4 → 1.7.0

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/index.js CHANGED
@@ -2,35 +2,164 @@
2
2
 
3
3
  // src/main.ts
4
4
  import fs from "fs";
5
- import * as yargs from "yargs";
6
- import { hideBin } from "yargs/helpers";
7
5
  import { Graphviz } from "@hpcc-js/wasm-graphviz";
6
+
7
+ // src/cliArgs.ts
8
+ var HELP_TEXT = `Usage: dot-wasm [options] fileOrDot
9
+
10
+ Options:
11
+ -K, --layout <engine> Set layout engine (circo | dot | fdp | sfdp | neato |
12
+ osage | patchwork | twopi | nop | nop2). Default: dot
13
+ -T, --format <format> Set output format (svg | dot | json | dot_json |
14
+ xdot_json | plain | plain-ext). Default: svg
15
+ -n, --neato-no-op <flag> Set neato no-op flag (only valid with -K neato)
16
+ -y, --invert-y Invert Y axis in plain/plain-ext formats
17
+ -v Echo GraphViz version
18
+ -h, --help Show this help message
19
+
20
+ Examples:
21
+ dot-wasm -K neato -T xdot ./input.dot
22
+
23
+ https://github.com/hpcc-systems/hpcc-js-wasm`;
24
+ function parseArgs(args) {
25
+ const parsed = {
26
+ positional: []
27
+ };
28
+ const readValue = (flag, index) => {
29
+ if (index >= args.length) {
30
+ throw new Error(`${flag} option requires a value.`);
31
+ }
32
+ return args[index];
33
+ };
34
+ for (let i = 0; i < args.length; ++i) {
35
+ const token = args[i];
36
+ if (token === "--") {
37
+ parsed.positional.push(...args.slice(i + 1));
38
+ break;
39
+ }
40
+ if (token.startsWith("--")) {
41
+ const [rawName, maybeValue] = token.slice(2).split("=", 2);
42
+ i = handleOption(parsed, rawName, maybeValue ?? null, i, readValue);
43
+ continue;
44
+ }
45
+ if (token.startsWith("-") && token.length > 1) {
46
+ i = handleShortFlags(parsed, token.slice(1), i, readValue);
47
+ continue;
48
+ }
49
+ parsed.positional.push(token);
50
+ }
51
+ return parsed;
52
+ }
53
+ function handleOption(parsed, name, value, currentIndex, readValue) {
54
+ switch (name) {
55
+ case "layout":
56
+ parsed.layout = value ?? readValue("--layout", ++currentIndex);
57
+ return currentIndex;
58
+ case "format":
59
+ parsed.format = value ?? readValue("--format", ++currentIndex);
60
+ return currentIndex;
61
+ case "neato-no-op":
62
+ parsed.neatoNoOp = value ?? readValue("--neato-no-op", ++currentIndex);
63
+ return currentIndex;
64
+ case "invert-y":
65
+ parsed.invertY = true;
66
+ return currentIndex;
67
+ case "help":
68
+ parsed.help = true;
69
+ return currentIndex;
70
+ case "version":
71
+ parsed.version = true;
72
+ return currentIndex;
73
+ default:
74
+ throw new Error(`Unknown option --${name}`);
75
+ }
76
+ }
77
+ function handleShortFlags(parsed, flags, currentIndex, readValue) {
78
+ for (let j = 0; j < flags.length; ++j) {
79
+ const flag = flags[j];
80
+ switch (flag) {
81
+ case "K": {
82
+ const remaining = flags.slice(j + 1);
83
+ if (remaining) {
84
+ parsed.layout = remaining;
85
+ return currentIndex;
86
+ }
87
+ parsed.layout = readValue("-K", ++currentIndex);
88
+ return currentIndex;
89
+ }
90
+ case "T": {
91
+ const remaining = flags.slice(j + 1);
92
+ if (remaining) {
93
+ parsed.format = remaining;
94
+ return currentIndex;
95
+ }
96
+ parsed.format = readValue("-T", ++currentIndex);
97
+ return currentIndex;
98
+ }
99
+ case "n": {
100
+ const remaining = flags.slice(j + 1);
101
+ if (remaining) {
102
+ parsed.neatoNoOp = remaining;
103
+ return currentIndex;
104
+ }
105
+ parsed.neatoNoOp = readValue("-n", ++currentIndex);
106
+ return currentIndex;
107
+ }
108
+ case "y":
109
+ parsed.invertY = true;
110
+ break;
111
+ case "v":
112
+ parsed.version = true;
113
+ break;
114
+ case "h":
115
+ parsed.help = true;
116
+ break;
117
+ default:
118
+ throw new Error(`Unknown option -${flag}`);
119
+ }
120
+ }
121
+ return currentIndex;
122
+ }
123
+
124
+ // src/main.ts
8
125
  async function main() {
9
- const myYargs = yargs.default(hideBin(process.argv));
10
- myYargs.usage("Usage: dot-wasm [options] fileOrDot").demandCommand(0, 1).example("dot-wasm -K neato -T xdot ./input.dot", "Execute NEATO layout and outputs XDOT format.").alias("K", "layout").nargs("K", 1).describe("K", "Set layout engine (circo | dot | fdp | sfdp | neato | osage | patchwork | twopi | nop | nop2). By default, dot is used.").alias("T", "format").nargs("T", 1).describe("T", "Set output language to one of the supported formats (svg | dot | json | dot_json | xdot_json | plain | plain-ext). By default, svg is produced.").alias("n", "neato-no-op").nargs("n", 1).describe("n", 'Sets no-op flag in neato. "-n 1" assumes neato nodes have already been positioned and all nodes have a pos attribute giving the positions. It then performs an optional adjustment to remove node-node overlap, depending on the value of the overlap attribute, computes the edge layouts, depending on the value of the splines attribute, and emits the graph in the appropriate format.\n"-n 2" Use node positions as specified, with no adjustment to remove node-node overlaps, and use any edge layouts already specified by the pos attribute. neato computes an edge layout for any edge that does not have a pos attribute. As usual, edge layout is guided by the splines attribute.').alias("y", "invert-y").nargs("y", 0).describe("y", "By default, the coordinate system used in generic output formats, such as attributed dot, extended dot, plain and plain-ext, is the standard cartesian system with the origin in the lower left corner, and with increasing y coordinates as points move from bottom to top. If the -y flag is used, the coordinate system is inverted, so that increasing values of y correspond to movement from top to bottom.").nargs("v", 0).describe("v", "Echo GraphViz library version").help("h").alias("h", "help").epilog("https://github.com/hpcc-systems/hpcc-js-wasm");
11
- const argv = await myYargs.argv;
12
126
  try {
127
+ const parsed = parseArgs(process.argv.slice(2));
128
+ if (parsed.help) {
129
+ console.log(HELP_TEXT);
130
+ return;
131
+ }
132
+ if (parsed.positional.length > 1) {
133
+ throw new Error("Only one 'fileOrDot' argument is allowed.");
134
+ }
13
135
  let dot;
14
- if (fs.existsSync(argv._[0])) {
15
- dot = fs.readFileSync(argv._[0], "utf8");
16
- } else {
17
- dot = argv._[0];
136
+ const fileOrDot = parsed.positional[0];
137
+ if (fileOrDot) {
138
+ if (fs.existsSync(fileOrDot)) {
139
+ dot = fs.readFileSync(fileOrDot, "utf8");
140
+ } else {
141
+ dot = fileOrDot;
142
+ }
18
143
  }
19
144
  const graphviz = await Graphviz.load();
20
- if (argv.v) {
145
+ if (parsed.version) {
21
146
  console.log(`GraphViz version: ${graphviz.version()}`);
22
- } else if (dot) {
23
- if (argv.n && argv.layout.trim() !== "neato") {
24
- throw new Error("-n option is only supported with -T neato");
147
+ return;
148
+ }
149
+ if (dot) {
150
+ const layout = (parsed.layout ?? "dot").trim();
151
+ const format = (parsed.format ?? "svg").trim();
152
+ if (parsed.neatoNoOp && layout !== "neato") {
153
+ throw new Error("-n option is only supported with -K neato");
25
154
  }
26
155
  const ext = {};
27
- if (argv.n) {
28
- ext.nop = parseInt(argv.n);
156
+ if (parsed.neatoNoOp) {
157
+ ext.nop = parseInt(parsed.neatoNoOp, 10);
29
158
  }
30
- if (argv.y) {
159
+ if (parsed.invertY) {
31
160
  ext.yInvert = true;
32
161
  }
33
- const response = graphviz.layout(dot, argv.format?.trim() ?? "svg", argv.layout?.trim() ?? "dot", ext);
162
+ const response = graphviz.layout(dot, format, layout, ext);
34
163
  console.log(response);
35
164
  } else {
36
165
  throw new Error("'fileOrDot' is required.");
@@ -38,7 +167,7 @@ async function main() {
38
167
  } catch (e) {
39
168
  console.error(`Error: ${e?.message}
40
169
  `);
41
- myYargs.showHelp();
170
+ console.error(HELP_TEXT);
42
171
  }
43
172
  }
44
173
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hpcc-js/wasm-graphviz-cli",
3
- "version": "1.5.4",
3
+ "version": "1.7.0",
4
4
  "description": "hpcc-js - WASM Graphviz Cli",
5
5
  "type": "module",
6
6
  "bin": {
@@ -31,13 +31,13 @@
31
31
  "lint-skypack": "npx -y @skypack/package-check",
32
32
  "lint-eslint": "eslint src/**/*.ts",
33
33
  "lint": "run-p lint-eslint",
34
- "test": "node bin/index.js --help",
34
+ "test:unit": "vitest run",
35
+ "test": "npm run test:unit && node bin/index.js --help",
35
36
  "update": "npx -y npm-check-updates -u -t minor",
36
37
  "update-major": "npx -y npm-check-updates -u"
37
38
  },
38
39
  "dependencies": {
39
- "@hpcc-js/wasm-graphviz": "^1.13.0",
40
- "yargs": "18.0.0"
40
+ "@hpcc-js/wasm-graphviz": "^1.16.0"
41
41
  },
42
42
  "keywords": [
43
43
  "graphviz",
@@ -55,5 +55,5 @@
55
55
  },
56
56
  "homepage": "https://hpcc-systems.github.io/hpcc-js-wasm/",
57
57
  "license": "Apache-2.0",
58
- "gitHead": "adbfa7aea45d38911cd2109336c471cfd5142ddd"
58
+ "gitHead": "3fa48df3d5a7a6c43bf4f0c8839f1f9df27080da"
59
59
  }
package/src/cliArgs.ts ADDED
@@ -0,0 +1,136 @@
1
+ export interface ParsedArgs {
2
+ layout?: string;
3
+ format?: string;
4
+ neatoNoOp?: string;
5
+ invertY?: boolean;
6
+ version?: boolean;
7
+ help?: boolean;
8
+ positional: string[];
9
+ }
10
+
11
+ export const HELP_TEXT = `Usage: dot-wasm [options] fileOrDot
12
+
13
+ Options:
14
+ -K, --layout <engine> Set layout engine (circo | dot | fdp | sfdp | neato |
15
+ osage | patchwork | twopi | nop | nop2). Default: dot
16
+ -T, --format <format> Set output format (svg | dot | json | dot_json |
17
+ xdot_json | plain | plain-ext). Default: svg
18
+ -n, --neato-no-op <flag> Set neato no-op flag (only valid with -K neato)
19
+ -y, --invert-y Invert Y axis in plain/plain-ext formats
20
+ -v Echo GraphViz version
21
+ -h, --help Show this help message
22
+
23
+ Examples:
24
+ dot-wasm -K neato -T xdot ./input.dot
25
+
26
+ https://github.com/hpcc-systems/hpcc-js-wasm`;
27
+
28
+ export function parseArgs(args: string[]): ParsedArgs {
29
+ const parsed: ParsedArgs = {
30
+ positional: []
31
+ };
32
+
33
+ const readValue = (flag: string, index: number): string => {
34
+ if (index >= args.length) {
35
+ throw new Error(`${flag} option requires a value.`);
36
+ }
37
+ return args[index];
38
+ };
39
+
40
+ for (let i = 0; i < args.length; ++i) {
41
+ const token = args[i];
42
+
43
+ if (token === "--") {
44
+ parsed.positional.push(...args.slice(i + 1));
45
+ break;
46
+ }
47
+
48
+ if (token.startsWith("--")) {
49
+ const [rawName, maybeValue] = token.slice(2).split("=", 2);
50
+ i = handleOption(parsed, rawName, maybeValue ?? null, i, readValue);
51
+ continue;
52
+ }
53
+
54
+ if (token.startsWith("-") && token.length > 1) {
55
+ i = handleShortFlags(parsed, token.slice(1), i, readValue);
56
+ continue;
57
+ }
58
+
59
+ parsed.positional.push(token);
60
+ }
61
+
62
+ return parsed;
63
+ }
64
+
65
+ function handleOption(parsed: ParsedArgs, name: string, value: string | null, currentIndex: number, readValue: (flag: string, index: number) => string): number {
66
+ switch (name) {
67
+ case "layout":
68
+ parsed.layout = value ?? readValue("--layout", ++currentIndex);
69
+ return currentIndex;
70
+ case "format":
71
+ parsed.format = value ?? readValue("--format", ++currentIndex);
72
+ return currentIndex;
73
+ case "neato-no-op":
74
+ parsed.neatoNoOp = value ?? readValue("--neato-no-op", ++currentIndex);
75
+ return currentIndex;
76
+ case "invert-y":
77
+ parsed.invertY = true;
78
+ return currentIndex;
79
+ case "help":
80
+ parsed.help = true;
81
+ return currentIndex;
82
+ case "version":
83
+ parsed.version = true;
84
+ return currentIndex;
85
+ default:
86
+ throw new Error(`Unknown option --${name}`);
87
+ }
88
+ }
89
+
90
+ function handleShortFlags(parsed: ParsedArgs, flags: string, currentIndex: number, readValue: (flag: string, index: number) => string): number {
91
+ for (let j = 0; j < flags.length; ++j) {
92
+ const flag = flags[j];
93
+ switch (flag) {
94
+ case "K": {
95
+ const remaining = flags.slice(j + 1);
96
+ if (remaining) {
97
+ parsed.layout = remaining;
98
+ return currentIndex;
99
+ }
100
+ parsed.layout = readValue("-K", ++currentIndex);
101
+ return currentIndex;
102
+ }
103
+ case "T": {
104
+ const remaining = flags.slice(j + 1);
105
+ if (remaining) {
106
+ parsed.format = remaining;
107
+ return currentIndex;
108
+ }
109
+ parsed.format = readValue("-T", ++currentIndex);
110
+ return currentIndex;
111
+ }
112
+ case "n": {
113
+ const remaining = flags.slice(j + 1);
114
+ if (remaining) {
115
+ parsed.neatoNoOp = remaining;
116
+ return currentIndex;
117
+ }
118
+ parsed.neatoNoOp = readValue("-n", ++currentIndex);
119
+ return currentIndex;
120
+ }
121
+ case "y":
122
+ parsed.invertY = true;
123
+ break;
124
+ case "v":
125
+ parsed.version = true;
126
+ break;
127
+ case "h":
128
+ parsed.help = true;
129
+ break;
130
+ default:
131
+ throw new Error(`Unknown option -${flag}`);
132
+ }
133
+ }
134
+
135
+ return currentIndex;
136
+ }
package/src/main.ts CHANGED
@@ -1,69 +1,63 @@
1
1
  import fs from "fs";
2
- import * as yargs from "yargs";
3
- import { hideBin } from "yargs/helpers";
4
2
  import { Graphviz, Engine, Format, Options } from "@hpcc-js/wasm-graphviz";
3
+ import { HELP_TEXT, parseArgs } from "./cliArgs.ts";
5
4
 
6
5
  export async function main() {
7
6
 
8
- const myYargs = yargs.default(hideBin(process.argv)) as yargs.Argv<{ vx: boolean, layout: Engine, format: Format, n: string }>;
9
- myYargs
10
- .usage("Usage: dot-wasm [options] fileOrDot")
11
- .demandCommand(0, 1)
12
- .example("dot-wasm -K neato -T xdot ./input.dot", "Execute NEATO layout and outputs XDOT format.")
13
- .alias("K", "layout")
14
- .nargs("K", 1)
15
- .describe("K", "Set layout engine (circo | dot | fdp | sfdp | neato | osage | patchwork | twopi | nop | nop2). By default, dot is used.")
16
- .alias("T", "format")
17
- .nargs("T", 1)
18
- .describe("T", "Set output language to one of the supported formats (svg | dot | json | dot_json | xdot_json | plain | plain-ext). By default, svg is produced.")
19
- .alias("n", "neato-no-op")
20
- .nargs("n", 1)
21
- .describe("n", "Sets no-op flag in neato. \"-n 1\" assumes neato nodes have already been positioned and all nodes have a pos attribute giving the positions. It then performs an optional adjustment to remove node-node overlap, depending on the value of the overlap attribute, computes the edge layouts, depending on the value of the splines attribute, and emits the graph in the appropriate format.\n\"-n 2\" Use node positions as specified, with no adjustment to remove node-node overlaps, and use any edge layouts already specified by the pos attribute. neato computes an edge layout for any edge that does not have a pos attribute. As usual, edge layout is guided by the splines attribute.")
22
- .alias("y", "invert-y")
23
- .nargs("y", 0)
24
- .describe("y", "By default, the coordinate system used in generic output formats, such as attributed dot, extended dot, plain and plain-ext, is the standard cartesian system with the origin in the lower left corner, and with increasing y coordinates as points move from bottom to top. If the -y flag is used, the coordinate system is inverted, so that increasing values of y correspond to movement from top to bottom.")
25
- .nargs("v", 0)
26
- .describe("v", "Echo GraphViz library version")
27
- .help("h")
28
- .alias("h", "help")
29
- .epilog("https://github.com/hpcc-systems/hpcc-js-wasm")
30
- ;
7
+ try {
8
+ const parsed = parseArgs(process.argv.slice(2));
31
9
 
32
- const argv = await myYargs.argv;
10
+ if (parsed.help) {
11
+ console.log(HELP_TEXT);
12
+ return;
13
+ }
33
14
 
34
- try {
35
- let dot;
36
- if (fs.existsSync(argv._[0] as string)) {
37
- dot = fs.readFileSync(argv._[0], "utf8");
38
- } else {
39
- dot = argv._[0] as string;
15
+ if (parsed.positional.length > 1) {
16
+ throw new Error("Only one 'fileOrDot' argument is allowed.");
40
17
  }
18
+
19
+ let dot: string | undefined;
20
+ const fileOrDot = parsed.positional[0];
21
+ if (fileOrDot) {
22
+ if (fs.existsSync(fileOrDot)) {
23
+ dot = fs.readFileSync(fileOrDot, "utf8");
24
+ } else {
25
+ dot = fileOrDot;
26
+ }
27
+ }
28
+
41
29
  const graphviz = await Graphviz.load();
42
30
 
43
- if (argv.v) {
31
+ if (parsed.version) {
44
32
  console.log(`GraphViz version: ${graphviz.version()}`);
45
- } else if (dot) {
33
+ return;
34
+ }
35
+
36
+ if (dot) {
37
+
38
+ const layout = (parsed.layout ?? "dot").trim();
39
+ const format = (parsed.format ?? "svg").trim();
46
40
 
47
- if (argv.n && argv.layout.trim() !== "neato") {
48
- throw new Error("-n option is only supported with -T neato");
41
+ if (parsed.neatoNoOp && layout !== "neato") {
42
+ throw new Error("-n option is only supported with -K neato");
49
43
  }
50
44
 
51
45
  const ext: Options = {
52
46
  };
53
- if (argv.n) {
54
- ext.nop = parseInt(argv.n);
47
+ if (parsed.neatoNoOp) {
48
+ ext.nop = parseInt(parsed.neatoNoOp, 10);
55
49
  }
56
- if (argv.y) {
50
+ if (parsed.invertY) {
57
51
  ext.yInvert = true;
58
52
  }
59
53
 
60
- const response = graphviz.layout(dot, (argv.format?.trim() ?? "svg") as Format, (argv.layout?.trim() ?? "dot") as Engine, ext);
54
+ const response = graphviz.layout(dot, format as Format, layout as Engine, ext);
61
55
  console.log(response);
62
56
  } else {
63
57
  throw new Error("'fileOrDot' is required.");
64
58
  }
65
59
  } catch (e: any) {
66
60
  console.error(`Error: ${e?.message}\n`);
67
- myYargs.showHelp();
61
+ console.error(HELP_TEXT);
68
62
  }
69
- }
63
+ }
@@ -0,0 +1,11 @@
1
+ export interface ParsedArgs {
2
+ layout?: string;
3
+ format?: string;
4
+ neatoNoOp?: string;
5
+ invertY?: boolean;
6
+ version?: boolean;
7
+ help?: boolean;
8
+ positional: string[];
9
+ }
10
+ export declare const HELP_TEXT = "Usage: dot-wasm [options] fileOrDot\n\nOptions:\n -K, --layout <engine> Set layout engine (circo | dot | fdp | sfdp | neato |\n osage | patchwork | twopi | nop | nop2). Default: dot\n -T, --format <format> Set output format (svg | dot | json | dot_json |\n xdot_json | plain | plain-ext). Default: svg\n -n, --neato-no-op <flag> Set neato no-op flag (only valid with -K neato)\n -y, --invert-y Invert Y axis in plain/plain-ext formats\n -v Echo GraphViz version\n -h, --help Show this help message\n\nExamples:\n dot-wasm -K neato -T xdot ./input.dot\n\nhttps://github.com/hpcc-systems/hpcc-js-wasm";
11
+ export declare function parseArgs(args: string[]): ParsedArgs;