@thi.ng/args 2.2.45 → 2.2.46

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/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2023-12-09T19:12:03Z
3
+ - **Last updated**: 2023-12-11T10:07:09Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
package/README.md CHANGED
@@ -69,7 +69,7 @@ For Node.js REPL:
69
69
  const args = await import("@thi.ng/args");
70
70
  ```
71
71
 
72
- Package sizes (brotli'd, pre-treeshake): ESM: 2.39 KB
72
+ Package sizes (brotli'd, pre-treeshake): ESM: 2.31 KB
73
73
 
74
74
  ## Dependencies
75
75
 
package/api.js CHANGED
@@ -1,19 +1,19 @@
1
- export const DEFAULT_THEME = {
2
- default: 95,
3
- hint: 90,
4
- multi: 90,
5
- param: 96,
6
- required: 33,
1
+ const DEFAULT_THEME = {
2
+ default: 95,
3
+ hint: 90,
4
+ multi: 90,
5
+ param: 96,
6
+ required: 33
7
7
  };
8
- /**
9
- * Wrapper for fixed size tuple values produced by {@link tuple}.
10
- */
11
- export class Tuple {
12
- value;
13
- constructor(value) {
14
- this.value = value;
15
- }
16
- deref() {
17
- return this.value;
18
- }
8
+ class Tuple {
9
+ constructor(value) {
10
+ this.value = value;
11
+ }
12
+ deref() {
13
+ return this.value;
14
+ }
19
15
  }
16
+ export {
17
+ DEFAULT_THEME,
18
+ Tuple
19
+ };
package/args.js CHANGED
@@ -1,214 +1,105 @@
1
1
  import { identity } from "@thi.ng/api/fn";
2
2
  import { repeat } from "@thi.ng/strings/repeat";
3
- import { coerceFloat, coerceFloats, coerceHexInt, coerceHexInts, coerceInt, coerceInts, coerceJson, coerceKV, coerceOneOf, coerceTuple, } from "./coerce.js";
3
+ import {
4
+ coerceFloat,
5
+ coerceFloats,
6
+ coerceHexInt,
7
+ coerceHexInts,
8
+ coerceInt,
9
+ coerceInts,
10
+ coerceJson,
11
+ coerceKV,
12
+ coerceOneOf,
13
+ coerceTuple
14
+ } from "./coerce.js";
4
15
  const $single = (coerce, hint) => (spec) => ({
5
- coerce,
6
- hint,
7
- group: "main",
8
- ...spec,
16
+ coerce,
17
+ hint,
18
+ group: "main",
19
+ ...spec
9
20
  });
10
21
  const $multi = (coerce, hint) => (spec) => ({
11
- hint: $hint(hint, spec.delim),
12
- multi: true,
13
- coerce,
14
- group: "main",
15
- ...spec,
22
+ hint: $hint(hint, spec.delim),
23
+ multi: true,
24
+ coerce,
25
+ group: "main",
26
+ ...spec
16
27
  });
17
28
  const $hint = (hint, delim) => hint + (delim ? `[${delim}..]` : "");
18
- /**
19
- * Returns a full {@link ArgSpec} for a boolean flag. The mere presence of this
20
- * arg will enable the flag.
21
- *
22
- * @param spec -
23
- */
24
- export const flag = (spec) => ({
25
- flag: true,
26
- default: false,
27
- group: "flags",
28
- ...spec,
29
+ const flag = (spec) => ({
30
+ flag: true,
31
+ default: false,
32
+ group: "flags",
33
+ ...spec
29
34
  });
30
- /**
31
- * Returns a full {@link ArgSpec} for a string value arg.
32
- *
33
- * @param spec -
34
- */
35
- export const string = $single(identity, "STR");
36
- /**
37
- * Multi-arg version of {@link string}. Returns a full {@link ArgSpec} for a
38
- * multi string value arg. This argument can be provided mutiple times with
39
- * values collected into an array.
40
- *
41
- * @param spec -
42
- */
43
- export const strings = $multi(identity, "STR");
44
- /**
45
- * Returns a full {@link ArgSpec} for a floating point value arg. The value
46
- * will be autoatically coerced into a number using {@link coerceFloat}.
47
- *
48
- * @param spec -
49
- */
50
- export const float = $single(coerceFloat, "NUM");
51
- /**
52
- * Returns a full {@link ArgSpec} for a single hex integer value arg. The value
53
- * will be autoatically coerced into a number using {@link coerceHexInt}.
54
- *
55
- * @param spec -
56
- */
57
- export const hex = $single(coerceHexInt, "HEX");
58
- /**
59
- * Returns a full {@link ArgSpec} for a single integer value arg. The value
60
- * will be autoatically coerced into a number using {@link coerceInt}.
61
- *
62
- * @param spec -
63
- */
64
- export const int = $single(coerceInt, "INT");
65
- /**
66
- * Multi-arg version of {@link float}. Returns a full {@link ArgSpec} for a
67
- * multi floating point value arg. This argument can be provided mutiple times
68
- * with values being coerced into numbers and collected into an array.
69
- *
70
- * @param spec -
71
- */
72
- export const floats = $multi(coerceFloats, "NUM");
73
- /**
74
- * Multi-arg version of {@link hex}. Returns a full {@link ArgSpec} for a multi
75
- * hex integer value arg. This argument can be provided mutiple times with
76
- * values being coerced into numbers and collected into an array.
77
- *
78
- * @param spec -
79
- */
80
- export const hexes = $multi(coerceHexInts, "HEX");
81
- /**
82
- * Multi-arg version of {@link int}. Returns a full {@link ArgSpec} for a multi
83
- * integer value arg. This argument can be provided mutiple times with values
84
- * being coerced into numbers and collected into an array.
85
- *
86
- * @param spec -
87
- */
88
- export const ints = $multi(coerceInts, "INT");
89
- /**
90
- * Returns full {@link ArgSpec} for a JSON value arg. The raw CLI value string
91
- * will be automcatically coerced using {@link coerceJson}.
92
- *
93
- * @param spec -
94
- */
95
- export const json = (spec) => ({
96
- coerce: coerceJson,
97
- hint: "JSON",
98
- group: "main",
99
- ...spec,
35
+ const string = $single(identity, "STR");
36
+ const strings = $multi(identity, "STR");
37
+ const float = $single(coerceFloat, "NUM");
38
+ const hex = $single(coerceHexInt, "HEX");
39
+ const int = $single(coerceInt, "INT");
40
+ const floats = $multi(coerceFloats, "NUM");
41
+ const hexes = $multi(coerceHexInts, "HEX");
42
+ const ints = $multi(coerceInts, "INT");
43
+ const json = (spec) => ({
44
+ coerce: coerceJson,
45
+ hint: "JSON",
46
+ group: "main",
47
+ ...spec
100
48
  });
101
49
  const $desc = (opts, prefix) => `${prefix ? prefix + ": " : ""}${opts.map((x) => `"${x}"`).join(", ")}`;
102
- /**
103
- * Returns full {@link ArgSpec} for an enum-like string value arg. The raw CLI
104
- * value string will be automcatically validated using {@link coerceOneOf}.
105
- *
106
- * @param opts -
107
- * @param spec -
108
- */
109
- export const oneOf = (opts, spec) => ({
110
- coerce: coerceOneOf(opts),
111
- hint: "ID",
112
- group: "main",
113
- ...spec,
114
- desc: $desc(opts, spec.desc),
50
+ const oneOf = (opts, spec) => ({
51
+ coerce: coerceOneOf(opts),
52
+ hint: "ID",
53
+ group: "main",
54
+ ...spec,
55
+ desc: $desc(opts, spec.desc)
115
56
  });
116
- /**
117
- * Multi-arg version of {@link oneOf}. Returns full {@link ArgSpec} for multiple
118
- * enum-like string value args. The raw CLI value strings will be automcatically
119
- * validated using {@link coerceOneOf} and collected into an array.
120
- *
121
- * @param opts -
122
- * @param spec -
123
- */
124
- export const oneOfMulti = (opts, spec) => ({
125
- coerce: (xs) => xs.map(coerceOneOf(opts)),
126
- hint: $hint("ID", spec.delim),
127
- multi: true,
128
- group: "main",
129
- ...spec,
130
- desc: $desc(opts, spec.desc),
57
+ const oneOfMulti = (opts, spec) => ({
58
+ coerce: (xs) => xs.map(coerceOneOf(opts)),
59
+ hint: $hint("ID", spec.delim),
60
+ multi: true,
61
+ group: "main",
62
+ ...spec,
63
+ desc: $desc(opts, spec.desc)
131
64
  });
132
- /**
133
- * Returns a full {@link ArgSpec} for multiple `key=value` pair args, coerced
134
- * into a result object.
135
- *
136
- * @remarks
137
- * The default delimiter (`=`) can be overridden. Also by default, key-only args
138
- * are allowed and will receive a `"true"` as their value. However, if `strict`
139
- * is true, only full KV pairs are allowed.
140
- *
141
- * @param spec -
142
- * @param delim -
143
- */
144
- export const kvPairs = (spec, delim = "=", strict) => ({
145
- coerce: coerceKV(delim, strict),
146
- hint: `key${delim}val`,
147
- multi: true,
148
- group: "main",
149
- ...spec,
65
+ const kvPairs = (spec, delim = "=", strict) => ({
66
+ coerce: coerceKV(delim, strict),
67
+ hint: `key${delim}val`,
68
+ multi: true,
69
+ group: "main",
70
+ ...spec
150
71
  });
151
- /**
152
- * Like {@link kvPairs}, but coerces KV pairs into a result {@link KVMultiDict}
153
- * which supports multiple values per given key (each key's values are collected
154
- * into arrays).
155
- *
156
- * @param spec -
157
- * @param delim -
158
- * @param strict -
159
- */
160
- export const kvPairsMulti = (spec, delim = "=", strict) => ({
161
- coerce: coerceKV(delim, strict, true),
162
- hint: `key${delim}val(s)`,
163
- multi: true,
164
- group: "main",
165
- ...spec,
72
+ const kvPairsMulti = (spec, delim = "=", strict) => ({
73
+ coerce: coerceKV(delim, strict, true),
74
+ hint: `key${delim}val(s)`,
75
+ multi: true,
76
+ group: "main",
77
+ ...spec
166
78
  });
167
- /**
168
- * Returns a full {@link ArgSpec} for a fixed `size` tuple extracted from a
169
- * single value string. The individual values are delimited by `delim` and will
170
- * be coerced into their target type via `coerce`. The result tuple will be
171
- * wrapped in a {@link Tuple} instance.
172
- *
173
- * @remarks
174
- * An error will be thrown if the number of extracted values differs from the
175
- * specified tuple size or any value coercion fails.
176
- *
177
- * @example
178
- * ```ts
179
- * parse({ a: tuple(coerceInt, 2, {})}, ["--a", "1,2"])
180
- * // {
181
- * // result: { a: Tuple { value: [1, 2] } },
182
- * // index: 2,
183
- * // rest: [],
184
- * // done: true
185
- * // }
186
- * ```
187
- *
188
- * @param coerce -
189
- * @param size -
190
- * @param spec -
191
- * @param delim -
192
- */
193
- export const tuple = (coerce, size, spec, delim = ",") => ({
194
- coerce: coerceTuple(coerce, size, delim),
195
- hint: [...repeat("N", size)].join(delim),
196
- group: "main",
197
- ...spec,
79
+ const tuple = (coerce, size2, spec, delim = ",") => ({
80
+ coerce: coerceTuple(coerce, size2, delim),
81
+ hint: [...repeat("N", size2)].join(delim),
82
+ group: "main",
83
+ ...spec
198
84
  });
199
- /**
200
- * Syntax sugar for `tuple(coerceInt, size, {...}, delim)`.
201
- *
202
- * @param size -
203
- * @param spec -
204
- * @param delim -
205
- */
206
- export const size = (size, spec, delim = "x") => tuple(coerceInt, size, spec, delim);
207
- /**
208
- * Syntax sugar for `tuple(coerceFloat, size, {...}, delim)`.
209
- *
210
- * @param size -
211
- * @param spec -
212
- * @param delim -
213
- */
214
- export const vec = (size, spec, delim = ",") => tuple(coerceFloat, size, spec, delim);
85
+ const size = (size2, spec, delim = "x") => tuple(coerceInt, size2, spec, delim);
86
+ const vec = (size2, spec, delim = ",") => tuple(coerceFloat, size2, spec, delim);
87
+ export {
88
+ flag,
89
+ float,
90
+ floats,
91
+ hex,
92
+ hexes,
93
+ int,
94
+ ints,
95
+ json,
96
+ kvPairs,
97
+ kvPairsMulti,
98
+ oneOf,
99
+ oneOfMulti,
100
+ size,
101
+ string,
102
+ strings,
103
+ tuple,
104
+ vec
105
+ };
package/coerce.js CHANGED
@@ -2,42 +2,50 @@ import { isHex } from "@thi.ng/checks/is-hex";
2
2
  import { isNumericFloat, isNumericInt } from "@thi.ng/checks/is-numeric";
3
3
  import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
4
4
  import { Tuple } from "./api.js";
5
- export const coerceString = (x) => x;
6
- export const coerceFloat = (x) => isNumericFloat(x)
7
- ? parseFloat(x)
8
- : illegalArgs(`not a numeric value: ${x}`);
9
- export const coerceFloats = (xs) => xs.map(coerceFloat);
10
- export const coerceHexInt = (x) => isHex(x) ? parseInt(x, 16) : illegalArgs(`not a hex value: ${x}`);
11
- export const coerceHexInts = (xs) => xs.map(coerceHexInt);
12
- export const coerceInt = (x) => isNumericInt(x) ? parseInt(x) : illegalArgs(`not an integer: ${x}`);
13
- export const coerceInts = (xs) => xs.map(coerceInt);
14
- export const coerceJson = (x) => JSON.parse(x);
15
- export const coerceOneOf = (xs) => (x) => xs.includes(x) ? x : illegalArgs(`invalid option: ${x}`);
16
- export function coerceKV(delim = "=", strict = false, multi = false) {
17
- return (pairs) => pairs.reduce((acc, x) => {
18
- const idx = x.indexOf(delim);
19
- strict &&
20
- idx < 1 &&
21
- illegalArgs(`got '${x}', but expected a 'key${delim}value' pair`);
22
- if (idx > 0) {
23
- const id = x.substring(0, idx);
24
- const val = x.substring(idx + 1);
25
- if (multi) {
26
- acc[id] ? acc[id].push(val) : (acc[id] = [val]);
27
- }
28
- else {
29
- acc[id] = val;
30
- }
31
- }
32
- else {
33
- acc[x] = multi ? ["true"] : "true";
34
- }
35
- return acc;
36
- }, {});
5
+ const coerceString = (x) => x;
6
+ const coerceFloat = (x) => isNumericFloat(x) ? parseFloat(x) : illegalArgs(`not a numeric value: ${x}`);
7
+ const coerceFloats = (xs) => xs.map(coerceFloat);
8
+ const coerceHexInt = (x) => isHex(x) ? parseInt(x, 16) : illegalArgs(`not a hex value: ${x}`);
9
+ const coerceHexInts = (xs) => xs.map(coerceHexInt);
10
+ const coerceInt = (x) => isNumericInt(x) ? parseInt(x) : illegalArgs(`not an integer: ${x}`);
11
+ const coerceInts = (xs) => xs.map(coerceInt);
12
+ const coerceJson = (x) => JSON.parse(x);
13
+ const coerceOneOf = (xs) => (x) => xs.includes(x) ? x : illegalArgs(`invalid option: ${x}`);
14
+ function coerceKV(delim = "=", strict = false, multi = false) {
15
+ return (pairs) => pairs.reduce((acc, x) => {
16
+ const idx = x.indexOf(delim);
17
+ strict && idx < 1 && illegalArgs(
18
+ `got '${x}', but expected a 'key${delim}value' pair`
19
+ );
20
+ if (idx > 0) {
21
+ const id = x.substring(0, idx);
22
+ const val = x.substring(idx + 1);
23
+ if (multi) {
24
+ acc[id] ? acc[id].push(val) : acc[id] = [val];
25
+ } else {
26
+ acc[id] = val;
27
+ }
28
+ } else {
29
+ acc[x] = multi ? ["true"] : "true";
30
+ }
31
+ return acc;
32
+ }, {});
37
33
  }
38
- export const coerceTuple = (coerce, size, delim = ",") => (src) => {
39
- const parts = src.split(delim);
40
- parts.length !== size &&
41
- illegalArgs(`got '${src}', but expected a tuple of ${size} values`);
42
- return new Tuple(parts.map(coerce));
34
+ const coerceTuple = (coerce, size, delim = ",") => (src) => {
35
+ const parts = src.split(delim);
36
+ parts.length !== size && illegalArgs(`got '${src}', but expected a tuple of ${size} values`);
37
+ return new Tuple(parts.map(coerce));
38
+ };
39
+ export {
40
+ coerceFloat,
41
+ coerceFloats,
42
+ coerceHexInt,
43
+ coerceHexInts,
44
+ coerceInt,
45
+ coerceInts,
46
+ coerceJson,
47
+ coerceKV,
48
+ coerceOneOf,
49
+ coerceString,
50
+ coerceTuple
43
51
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/args",
3
- "version": "2.2.45",
3
+ "version": "2.2.46",
4
4
  "description": "Declarative, functional & typechecked CLI argument/options parser, value coercions etc.",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -24,7 +24,9 @@
24
24
  "author": "Karsten Schmidt (https://thi.ng)",
25
25
  "license": "Apache-2.0",
26
26
  "scripts": {
27
- "build": "yarn clean && tsc --declaration",
27
+ "build": "yarn build:esbuild && yarn build:decl",
28
+ "build:decl": "tsc --declaration --emitDeclarationOnly",
29
+ "build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts",
28
30
  "clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc",
29
31
  "doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",
30
32
  "doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
@@ -33,13 +35,14 @@
33
35
  "test": "bun test"
34
36
  },
35
37
  "dependencies": {
36
- "@thi.ng/api": "^8.9.11",
37
- "@thi.ng/checks": "^3.4.11",
38
- "@thi.ng/errors": "^2.4.5",
39
- "@thi.ng/strings": "^3.7.2"
38
+ "@thi.ng/api": "^8.9.12",
39
+ "@thi.ng/checks": "^3.4.12",
40
+ "@thi.ng/errors": "^2.4.6",
41
+ "@thi.ng/strings": "^3.7.3"
40
42
  },
41
43
  "devDependencies": {
42
44
  "@microsoft/api-extractor": "^7.38.3",
45
+ "esbuild": "^0.19.8",
43
46
  "rimraf": "^5.0.5",
44
47
  "tools": "^0.0.1",
45
48
  "typedoc": "^0.25.4",
@@ -94,5 +97,5 @@
94
97
  "thi.ng": {
95
98
  "year": 2018
96
99
  },
97
- "gitHead": "25f2ac8ff795a432a930119661b364d4d93b59a0\n"
100
+ "gitHead": "5e7bafedfc3d53bc131469a28de31dd8e5b4a3ff\n"
98
101
  }
package/parse.js CHANGED
@@ -3,118 +3,120 @@ import { defError } from "@thi.ng/errors/deferror";
3
3
  import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
4
4
  import { camel } from "@thi.ng/strings/case";
5
5
  import { usage } from "./usage.js";
6
- export const ParseError = defError(() => "parse error");
7
- export const parse = (specs, argv, opts) => {
8
- opts = { start: 2, showUsage: true, help: ["--help", "-h"], ...opts };
9
- try {
10
- return parseOpts(specs, argv, opts);
11
- }
12
- catch (e) {
13
- if (opts.showUsage) {
14
- console.log(e.message + "\n\n" + usage(specs, opts.usageOpts));
15
- }
16
- throw new ParseError(e.message);
6
+ const ParseError = defError(() => "parse error");
7
+ const parse = (specs, argv, opts) => {
8
+ opts = { start: 2, showUsage: true, help: ["--help", "-h"], ...opts };
9
+ try {
10
+ return parseOpts(specs, argv, opts);
11
+ } catch (e) {
12
+ if (opts.showUsage) {
13
+ console.log(
14
+ e.message + "\n\n" + usage(specs, opts.usageOpts)
15
+ );
17
16
  }
17
+ throw new ParseError(e.message);
18
+ }
18
19
  };
19
20
  const parseOpts = (specs, argv, opts) => {
20
- const aliases = aliasIndex(specs);
21
- const acc = {};
22
- let id;
23
- let spec;
24
- let i = opts.start;
25
- for (; i < argv.length;) {
26
- const a = argv[i];
27
- if (!id) {
28
- if (opts.help.includes(a)) {
29
- console.log(usage(specs, opts.usageOpts));
30
- return;
31
- }
32
- const state = parseKey(specs, aliases, acc, a);
33
- id = state.id;
34
- spec = state.spec;
35
- i = i + ~~(state.state < 2);
36
- if (state.state)
37
- break;
38
- }
39
- else {
40
- if (parseValue(spec, acc, id, a))
41
- break;
42
- id = null;
43
- i++;
44
- }
21
+ const aliases = aliasIndex(specs);
22
+ const acc = {};
23
+ let id;
24
+ let spec;
25
+ let i = opts.start;
26
+ for (; i < argv.length; ) {
27
+ const a = argv[i];
28
+ if (!id) {
29
+ if (opts.help.includes(a)) {
30
+ console.log(usage(specs, opts.usageOpts));
31
+ return;
32
+ }
33
+ const state = parseKey(specs, aliases, acc, a);
34
+ id = state.id;
35
+ spec = state.spec;
36
+ i = i + ~~(state.state < 2);
37
+ if (state.state)
38
+ break;
39
+ } else {
40
+ if (parseValue(spec, acc, id, a))
41
+ break;
42
+ id = null;
43
+ i++;
45
44
  }
46
- id && illegalArgs(`missing value for: --${id}`);
47
- return {
48
- result: processResults(specs, acc),
49
- index: i,
50
- rest: argv.slice(i),
51
- done: i >= argv.length,
52
- };
45
+ }
46
+ id && illegalArgs(`missing value for: --${id}`);
47
+ return {
48
+ result: processResults(specs, acc),
49
+ index: i,
50
+ rest: argv.slice(i),
51
+ done: i >= argv.length
52
+ };
53
53
  };
54
- const aliasIndex = (specs) => Object.entries(specs).reduce((acc, [k, v]) => (v.alias ? ((acc[v.alias] = k), acc) : acc), {});
54
+ const aliasIndex = (specs) => Object.entries(specs).reduce(
55
+ (acc, [k, v]) => v.alias ? (acc[v.alias] = k, acc) : acc,
56
+ {}
57
+ );
55
58
  const parseKey = (specs, aliases, acc, a) => {
56
- if (a[0] === "-") {
57
- let id;
58
- if (a[1] === "-") {
59
- // terminator arg, stop parsing
60
- if (a === "--")
61
- return { state: 1 };
62
- id = camel(a.substring(2));
63
- }
64
- else {
65
- id = aliases[a.substring(1)];
66
- !id && illegalArgs(`unknown option: ${a}`);
67
- }
68
- const spec = specs[id];
69
- !spec && illegalArgs(id);
70
- if (spec.flag) {
71
- acc[id] = true;
72
- id = undefined;
73
- // stop parsing if fn returns false
74
- if (spec.fn && !spec.fn("true"))
75
- return { state: 1, spec };
76
- }
77
- return { state: 0, id, spec };
59
+ if (a[0] === "-") {
60
+ let id;
61
+ if (a[1] === "-") {
62
+ if (a === "--")
63
+ return { state: 1 };
64
+ id = camel(a.substring(2));
65
+ } else {
66
+ id = aliases[a.substring(1)];
67
+ !id && illegalArgs(`unknown option: ${a}`);
68
+ }
69
+ const spec = specs[id];
70
+ !spec && illegalArgs(id);
71
+ if (spec.flag) {
72
+ acc[id] = true;
73
+ id = void 0;
74
+ if (spec.fn && !spec.fn("true"))
75
+ return { state: 1, spec };
78
76
  }
79
- // no option arg, stop parsing
80
- return { state: 2 };
77
+ return { state: 0, id, spec };
78
+ }
79
+ return { state: 2 };
81
80
  };
82
81
  const parseValue = (spec, acc, id, a) => {
83
- /^-[a-z]/i.test(a) && illegalArgs(`missing value for: --${id}`);
84
- if (spec.multi) {
85
- isArray(acc[id]) ? acc[id].push(a) : (acc[id] = [a]);
86
- }
87
- else {
88
- acc[id] = a;
89
- }
90
- return spec.fn && !spec.fn(a);
82
+ /^-[a-z]/i.test(a) && illegalArgs(`missing value for: --${id}`);
83
+ if (spec.multi) {
84
+ isArray(acc[id]) ? acc[id].push(a) : acc[id] = [a];
85
+ } else {
86
+ acc[id] = a;
87
+ }
88
+ return spec.fn && !spec.fn(a);
91
89
  };
92
90
  const processResults = (specs, acc) => {
93
- let spec;
94
- for (let id in specs) {
95
- spec = specs[id];
96
- if (acc[id] === undefined) {
97
- if (spec.default !== undefined) {
98
- acc[id] = spec.default;
99
- }
100
- else if (spec.optional === false) {
101
- illegalArgs(`missing arg: --${id}`);
102
- }
103
- }
104
- else if (spec.coerce) {
105
- coerceValue(spec, acc, id);
106
- }
91
+ let spec;
92
+ for (let id in specs) {
93
+ spec = specs[id];
94
+ if (acc[id] === void 0) {
95
+ if (spec.default !== void 0) {
96
+ acc[id] = spec.default;
97
+ } else if (spec.optional === false) {
98
+ illegalArgs(`missing arg: --${id}`);
99
+ }
100
+ } else if (spec.coerce) {
101
+ coerceValue(spec, acc, id);
107
102
  }
108
- return acc;
103
+ }
104
+ return acc;
109
105
  };
110
106
  const coerceValue = (spec, acc, id) => {
111
- try {
112
- if (spec.multi && spec.delim) {
113
- acc[id] = acc[id].reduce((acc, x) => (acc.push(...x.split(spec.delim)), acc), []);
114
- }
115
- acc[id] = spec.coerce(acc[id]);
116
- }
117
- catch (e) {
118
- throw new Error(`arg --${id}: ${e.message}`);
107
+ try {
108
+ if (spec.multi && spec.delim) {
109
+ acc[id] = acc[id].reduce(
110
+ (acc2, x) => (acc2.push(...x.split(spec.delim)), acc2),
111
+ []
112
+ );
119
113
  }
114
+ acc[id] = spec.coerce(acc[id]);
115
+ } catch (e) {
116
+ throw new Error(`arg --${id}: ${e.message}`);
117
+ }
118
+ };
119
+ export {
120
+ ParseError,
121
+ parse
120
122
  };
package/usage.js CHANGED
@@ -4,73 +4,72 @@ import { padRight } from "@thi.ng/strings/pad-right";
4
4
  import { repeat } from "@thi.ng/strings/repeat";
5
5
  import { stringify } from "@thi.ng/strings/stringify";
6
6
  import { SPLIT_ANSI, wordWrapLines } from "@thi.ng/strings/word-wrap";
7
- import { DEFAULT_THEME, } from "./api.js";
8
- export const usage = (specs, opts = {}) => {
9
- opts = {
10
- lineWidth: 80,
11
- paramWidth: 32,
12
- showDefaults: true,
13
- prefix: "",
14
- suffix: "",
15
- groups: ["flags", "main"],
16
- ...opts,
17
- };
18
- const theme = opts.color !== false
19
- ? { ...DEFAULT_THEME, ...opts.color }
20
- : {};
21
- const indent = repeat(" ", opts.paramWidth);
22
- const format = (ids) => ids.map((id) => argUsage(id, specs[id], opts, theme, indent));
23
- const sortedIDs = Object.keys(specs).sort();
24
- const groups = opts.groups
25
- ? opts.groups
26
- .map((gid) => [
27
- gid,
28
- sortedIDs.filter((id) => specs[id].group === gid),
29
- ])
30
- .filter((g) => !!g[1].length)
31
- : [["options", sortedIDs]];
32
- return [
33
- ...wrap(opts.prefix, opts.lineWidth),
34
- ...groups.map(([gid, ids]) => [
35
- ...(opts.showGroupNames ? [`${capitalize(gid)}:\n`] : []),
36
- ...format(ids),
37
- "",
38
- ].join("\n")),
39
- ...wrap(opts.suffix, opts.lineWidth),
40
- ].join("\n");
7
+ import {
8
+ DEFAULT_THEME
9
+ } from "./api.js";
10
+ const usage = (specs, opts = {}) => {
11
+ opts = {
12
+ lineWidth: 80,
13
+ paramWidth: 32,
14
+ showDefaults: true,
15
+ prefix: "",
16
+ suffix: "",
17
+ groups: ["flags", "main"],
18
+ ...opts
19
+ };
20
+ const theme = opts.color !== false ? { ...DEFAULT_THEME, ...opts.color } : {};
21
+ const indent = repeat(" ", opts.paramWidth);
22
+ const format = (ids) => ids.map((id) => argUsage(id, specs[id], opts, theme, indent));
23
+ const sortedIDs = Object.keys(specs).sort();
24
+ const groups = opts.groups ? opts.groups.map(
25
+ (gid) => [
26
+ gid,
27
+ sortedIDs.filter((id) => specs[id].group === gid)
28
+ ]
29
+ ).filter((g) => !!g[1].length) : [["options", sortedIDs]];
30
+ return [
31
+ ...wrap(opts.prefix, opts.lineWidth),
32
+ ...groups.map(
33
+ ([gid, ids]) => [
34
+ ...opts.showGroupNames ? [`${capitalize(gid)}:
35
+ `] : [],
36
+ ...format(ids),
37
+ ""
38
+ ].join("\n")
39
+ ),
40
+ ...wrap(opts.suffix, opts.lineWidth)
41
+ ].join("\n");
41
42
  };
42
43
  const argUsage = (id, spec, opts, theme, indent) => {
43
- const hint = argHint(spec, theme);
44
- const alias = argAlias(spec, theme, hint);
45
- const name = ansi(`--${kebab(id)}`, theme.param);
46
- const params = `${alias}${name}${hint}`;
47
- const isRequired = spec.optional === false && spec.default === undefined;
48
- const prefixes = [];
49
- isRequired && prefixes.push("required");
50
- spec.multi && prefixes.push("multiple");
51
- const body = argPrefix(prefixes, theme, isRequired) +
52
- (spec.desc || "") +
53
- argDefault(spec, opts, theme);
54
- return (padRight(opts.paramWidth)(params, lengthAnsi(params)) +
55
- wrap(body, opts.lineWidth - opts.paramWidth)
56
- .map((l, i) => (i > 0 ? indent + l : l))
57
- .join("\n"));
44
+ const hint = argHint(spec, theme);
45
+ const alias = argAlias(spec, theme, hint);
46
+ const name = ansi(`--${kebab(id)}`, theme.param);
47
+ const params = `${alias}${name}${hint}`;
48
+ const isRequired = spec.optional === false && spec.default === void 0;
49
+ const prefixes = [];
50
+ isRequired && prefixes.push("required");
51
+ spec.multi && prefixes.push("multiple");
52
+ const body = argPrefix(prefixes, theme, isRequired) + (spec.desc || "") + argDefault(spec, opts, theme);
53
+ return padRight(opts.paramWidth)(params, lengthAnsi(params)) + wrap(body, opts.lineWidth - opts.paramWidth).map((l, i) => i > 0 ? indent + l : l).join("\n");
58
54
  };
59
55
  const argHint = (spec, theme) => spec.hint ? ansi(" " + spec.hint, theme.hint) : "";
60
56
  const argAlias = (spec, theme, hint) => spec.alias ? `${ansi("-" + spec.alias, theme.param)}${hint}, ` : "";
61
- const argPrefix = (prefixes, theme, isRequired) => prefixes.length
62
- ? ansi(`[${prefixes.join(", ")}] `, isRequired ? theme.required : theme.multi)
63
- : "";
64
- const argDefault = (spec, opts, theme) => opts.showDefaults && spec.default != null && spec.default !== false
65
- ? ansi(` (default: ${stringify(true)(spec.defaultHint != undefined
66
- ? spec.defaultHint
67
- : spec.default)})`, theme.default)
68
- : "";
69
- const ansi = (x, col) => col != null ? `\x1b[${col}m${x}\x1b[0m` : x;
70
- const wrap = (str, width) => str
71
- ? wordWrapLines(str, {
72
- width,
73
- splitter: SPLIT_ANSI,
74
- hard: true,
75
- })
76
- : [];
57
+ const argPrefix = (prefixes, theme, isRequired) => prefixes.length ? ansi(
58
+ `[${prefixes.join(", ")}] `,
59
+ isRequired ? theme.required : theme.multi
60
+ ) : "";
61
+ const argDefault = (spec, opts, theme) => opts.showDefaults && spec.default != null && spec.default !== false ? ansi(
62
+ ` (default: ${stringify(true)(
63
+ spec.defaultHint != void 0 ? spec.defaultHint : spec.default
64
+ )})`,
65
+ theme.default
66
+ ) : "";
67
+ const ansi = (x, col) => col != null ? `\x1B[${col}m${x}\x1B[0m` : x;
68
+ const wrap = (str, width) => str ? wordWrapLines(str, {
69
+ width,
70
+ splitter: SPLIT_ANSI,
71
+ hard: true
72
+ }) : [];
73
+ export {
74
+ usage
75
+ };