@thi.ng/args 2.3.32 → 2.3.34
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 +8 -1
- package/README.md +1 -1
- package/args.js +1 -1
- package/cli.js +4 -8
- package/coerce.d.ts +4 -4
- package/coerce.js +4 -4
- package/package.json +13 -13
- package/parse.d.ts +2 -3
- package/parse.js +15 -19
- package/usage.js +15 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2024-
|
|
3
|
+
- **Last updated**: 2024-06-21T19:34:38Z
|
|
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.
|
|
@@ -9,6 +9,13 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
9
9
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
10
10
|
and/or version bumps of transitive dependencies.
|
|
11
11
|
|
|
12
|
+
### [2.3.34](https://github.com/thi-ng/umbrella/tree/@thi.ng/args@2.3.34) (2024-06-21)
|
|
13
|
+
|
|
14
|
+
#### ♻️ Refactoring
|
|
15
|
+
|
|
16
|
+
- rename various rest args to be more semantically meaningful ([8088a56](https://github.com/thi-ng/umbrella/commit/8088a56))
|
|
17
|
+
- enforce uniform naming convention of internal functions ([56992b2](https://github.com/thi-ng/umbrella/commit/56992b2))
|
|
18
|
+
|
|
12
19
|
### [2.3.31](https://github.com/thi-ng/umbrella/tree/@thi.ng/args@2.3.31) (2024-04-20)
|
|
13
20
|
|
|
14
21
|
#### ♻️ Refactoring
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](https://mastodon.thi.ng/@toxi)
|
|
8
8
|
|
|
9
9
|
> [!NOTE]
|
|
10
|
-
> This is one of
|
|
10
|
+
> This is one of 193 standalone projects, maintained as part
|
|
11
11
|
> of the [@thi.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo
|
|
12
12
|
> and anti-framework.
|
|
13
13
|
>
|
package/args.js
CHANGED
|
@@ -55,7 +55,7 @@ const oneOf = (opts, spec) => ({
|
|
|
55
55
|
desc: $desc(opts, spec.desc)
|
|
56
56
|
});
|
|
57
57
|
const oneOfMulti = (opts, spec) => ({
|
|
58
|
-
coerce: (
|
|
58
|
+
coerce: (values) => values.map(coerceOneOf(opts)),
|
|
59
59
|
hint: $hint("ID", spec.delim),
|
|
60
60
|
multi: true,
|
|
61
61
|
group: "main",
|
package/cli.js
CHANGED
|
@@ -18,15 +18,13 @@ const cliApp = async (config) => {
|
|
|
18
18
|
let start = config.start ?? 2;
|
|
19
19
|
if (config.single) {
|
|
20
20
|
cmdID = Object.keys(config.commands)[0];
|
|
21
|
-
if (!cmdID)
|
|
22
|
-
illegalArgs("no command provided");
|
|
21
|
+
if (!cmdID) illegalArgs("no command provided");
|
|
23
22
|
cmd = config.commands[cmdID];
|
|
24
23
|
} else {
|
|
25
24
|
cmdID = argv[start];
|
|
26
25
|
cmd = config.commands[cmdID];
|
|
27
26
|
usageOpts.prefix += __descriptions(config.commands);
|
|
28
|
-
if (!cmd)
|
|
29
|
-
__usageAndExit(config, usageOpts);
|
|
27
|
+
if (!cmd) __usageAndExit(config, usageOpts);
|
|
30
28
|
start++;
|
|
31
29
|
}
|
|
32
30
|
let parsed;
|
|
@@ -38,8 +36,7 @@ const cliApp = async (config) => {
|
|
|
38
36
|
});
|
|
39
37
|
} catch (_) {
|
|
40
38
|
}
|
|
41
|
-
if (!parsed)
|
|
42
|
-
process.exit(1);
|
|
39
|
+
if (!parsed) process.exit(1);
|
|
43
40
|
if (cmd.inputs !== void 0 && cmd.inputs !== parsed.rest.length) {
|
|
44
41
|
process.stderr.write(`expected ${cmd.inputs || 0} input(s)
|
|
45
42
|
`);
|
|
@@ -55,8 +52,7 @@ const cliApp = async (config) => {
|
|
|
55
52
|
cmd
|
|
56
53
|
);
|
|
57
54
|
await cmd.fn(ctx);
|
|
58
|
-
if (config.post)
|
|
59
|
-
await config.post(ctx, cmd);
|
|
55
|
+
if (config.post) await config.post(ctx, cmd);
|
|
60
56
|
} catch (e) {
|
|
61
57
|
process.stderr.write(e.message + "\n\n");
|
|
62
58
|
process.exit(1);
|
package/coerce.d.ts
CHANGED
|
@@ -2,13 +2,13 @@ import type { Fn } from "@thi.ng/api";
|
|
|
2
2
|
import { Tuple, type KVDict, type KVMultiDict } from "./api.js";
|
|
3
3
|
export declare const coerceString: (x: string) => string;
|
|
4
4
|
export declare const coerceFloat: (x: string) => number;
|
|
5
|
-
export declare const coerceFloats: (
|
|
5
|
+
export declare const coerceFloats: (values: string[]) => number[];
|
|
6
6
|
export declare const coerceHexInt: (x: string) => number;
|
|
7
|
-
export declare const coerceHexInts: (
|
|
7
|
+
export declare const coerceHexInts: (values: string[]) => number[];
|
|
8
8
|
export declare const coerceInt: (x: string) => number;
|
|
9
|
-
export declare const coerceInts: (
|
|
9
|
+
export declare const coerceInts: (values: string[]) => number[];
|
|
10
10
|
export declare const coerceJson: <T>(x: string) => T;
|
|
11
|
-
export declare const coerceOneOf: <K extends string>(
|
|
11
|
+
export declare const coerceOneOf: <K extends string>(values: readonly K[]) => (x: string) => K;
|
|
12
12
|
export declare function coerceKV(delim?: string, strict?: boolean, multi?: false): Fn<string[], KVDict>;
|
|
13
13
|
export declare function coerceKV(delim?: string, strict?: boolean, multi?: true): Fn<string[], KVMultiDict>;
|
|
14
14
|
export declare const coerceTuple: <T>(coerce: Fn<string, T>, size: number, delim?: string) => (src: string) => Tuple<T>;
|
package/coerce.js
CHANGED
|
@@ -4,13 +4,13 @@ import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
|
|
|
4
4
|
import { Tuple } from "./api.js";
|
|
5
5
|
const coerceString = (x) => x;
|
|
6
6
|
const coerceFloat = (x) => isNumericFloat(x) ? parseFloat(x) : illegalArgs(`not a numeric value: ${x}`);
|
|
7
|
-
const coerceFloats = (
|
|
7
|
+
const coerceFloats = (values) => values.map(coerceFloat);
|
|
8
8
|
const coerceHexInt = (x) => isHex(x) ? parseInt(x, 16) : illegalArgs(`not a hex value: ${x}`);
|
|
9
|
-
const coerceHexInts = (
|
|
9
|
+
const coerceHexInts = (values) => values.map(coerceHexInt);
|
|
10
10
|
const coerceInt = (x) => isNumericInt(x) ? parseInt(x) : illegalArgs(`not an integer: ${x}`);
|
|
11
|
-
const coerceInts = (
|
|
11
|
+
const coerceInts = (values) => values.map(coerceInt);
|
|
12
12
|
const coerceJson = (x) => JSON.parse(x);
|
|
13
|
-
const coerceOneOf = (
|
|
13
|
+
const coerceOneOf = (values) => (x) => values.includes(x) ? x : illegalArgs(`invalid option: ${x}`);
|
|
14
14
|
function coerceKV(delim = "=", strict = false, multi = false) {
|
|
15
15
|
return (pairs) => pairs.reduce((acc, x) => {
|
|
16
16
|
const idx = x.indexOf(delim);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/args",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.34",
|
|
4
4
|
"description": "Declarative, functional & typechecked CLI argument/options parser, value coercions etc.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"type": "git",
|
|
11
11
|
"url": "https://github.com/thi-ng/umbrella.git"
|
|
12
12
|
},
|
|
13
|
-
"homepage": "https://
|
|
13
|
+
"homepage": "https://thi.ng/args",
|
|
14
14
|
"funding": [
|
|
15
15
|
{
|
|
16
16
|
"type": "github",
|
|
@@ -36,18 +36,18 @@
|
|
|
36
36
|
"tool:tangle": "../../node_modules/.bin/tangle src/**/*.ts"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@thi.ng/api": "^8.11.
|
|
40
|
-
"@thi.ng/checks": "^3.6.
|
|
41
|
-
"@thi.ng/errors": "^2.5.
|
|
42
|
-
"@thi.ng/logger": "^3.0.
|
|
43
|
-
"@thi.ng/strings": "^3.7.
|
|
44
|
-
"@thi.ng/text-format": "^2.2.
|
|
39
|
+
"@thi.ng/api": "^8.11.3",
|
|
40
|
+
"@thi.ng/checks": "^3.6.5",
|
|
41
|
+
"@thi.ng/errors": "^2.5.8",
|
|
42
|
+
"@thi.ng/logger": "^3.0.13",
|
|
43
|
+
"@thi.ng/strings": "^3.7.34",
|
|
44
|
+
"@thi.ng/text-format": "^2.2.6"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@microsoft/api-extractor": "^7.
|
|
48
|
-
"esbuild": "^0.
|
|
49
|
-
"typedoc": "^0.25.
|
|
50
|
-
"typescript": "^5.
|
|
47
|
+
"@microsoft/api-extractor": "^7.47.0",
|
|
48
|
+
"esbuild": "^0.21.5",
|
|
49
|
+
"typedoc": "^0.25.13",
|
|
50
|
+
"typescript": "^5.5.2"
|
|
51
51
|
},
|
|
52
52
|
"keywords": [
|
|
53
53
|
"argument",
|
|
@@ -103,5 +103,5 @@
|
|
|
103
103
|
"thi.ng": {
|
|
104
104
|
"year": 2018
|
|
105
105
|
},
|
|
106
|
-
"gitHead": "
|
|
106
|
+
"gitHead": "154c95cf9d6bab32174498ec3b5b5d87e42be7f9\n"
|
|
107
107
|
}
|
package/parse.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
1
|
import type { IObjectOf, Maybe } from "@thi.ng/api";
|
|
3
2
|
import type { Args, ParseOpts, ParseResult } from "./api.js";
|
|
4
3
|
export declare const ParseError: {
|
|
@@ -6,10 +5,10 @@ export declare const ParseError: {
|
|
|
6
5
|
origMessage: string;
|
|
7
6
|
name: string;
|
|
8
7
|
message: string;
|
|
9
|
-
stack?: string
|
|
8
|
+
stack?: string;
|
|
10
9
|
cause?: unknown;
|
|
11
10
|
};
|
|
12
|
-
captureStackTrace(targetObject: object, constructorOpt?: Function
|
|
11
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
13
12
|
prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite[]) => any) | undefined;
|
|
14
13
|
stackTraceLimit: number;
|
|
15
14
|
};
|
package/parse.js
CHANGED
|
@@ -7,7 +7,7 @@ const ParseError = defError(() => "parse error");
|
|
|
7
7
|
const parse = (specs, argv, opts) => {
|
|
8
8
|
opts = { start: 2, showUsage: true, help: ["--help", "-h"], ...opts };
|
|
9
9
|
try {
|
|
10
|
-
return
|
|
10
|
+
return __parseOpts(specs, argv, opts);
|
|
11
11
|
} catch (e) {
|
|
12
12
|
if (opts.showUsage) {
|
|
13
13
|
console.log(
|
|
@@ -17,8 +17,8 @@ const parse = (specs, argv, opts) => {
|
|
|
17
17
|
throw new ParseError(e.message);
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
|
-
const
|
|
21
|
-
const aliases =
|
|
20
|
+
const __parseOpts = (specs, argv, opts) => {
|
|
21
|
+
const aliases = __aliasIndex(specs);
|
|
22
22
|
const acc = {};
|
|
23
23
|
let id;
|
|
24
24
|
let spec;
|
|
@@ -30,37 +30,34 @@ const parseOpts = (specs, argv, opts) => {
|
|
|
30
30
|
console.log(usage(specs, opts.usageOpts));
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
|
-
const state =
|
|
33
|
+
const state = __parseKey(specs, aliases, acc, a);
|
|
34
34
|
id = state.id;
|
|
35
35
|
spec = state.spec;
|
|
36
36
|
i = i + ~~(state.state < 2);
|
|
37
|
-
if (state.state)
|
|
38
|
-
break;
|
|
37
|
+
if (state.state) break;
|
|
39
38
|
} else {
|
|
40
|
-
if (
|
|
41
|
-
break;
|
|
39
|
+
if (__parseValue(spec, acc, id, a)) break;
|
|
42
40
|
id = null;
|
|
43
41
|
i++;
|
|
44
42
|
}
|
|
45
43
|
}
|
|
46
44
|
id && illegalArgs(`missing value for: --${id}`);
|
|
47
45
|
return {
|
|
48
|
-
result:
|
|
46
|
+
result: __processResults(specs, acc),
|
|
49
47
|
index: i,
|
|
50
48
|
rest: argv.slice(i),
|
|
51
49
|
done: i >= argv.length
|
|
52
50
|
};
|
|
53
51
|
};
|
|
54
|
-
const
|
|
52
|
+
const __aliasIndex = (specs) => Object.entries(specs).reduce(
|
|
55
53
|
(acc, [k, v]) => v.alias ? (acc[v.alias] = k, acc) : acc,
|
|
56
54
|
{}
|
|
57
55
|
);
|
|
58
|
-
const
|
|
56
|
+
const __parseKey = (specs, aliases, acc, a) => {
|
|
59
57
|
if (a[0] === "-") {
|
|
60
58
|
let id;
|
|
61
59
|
if (a[1] === "-") {
|
|
62
|
-
if (a === "--")
|
|
63
|
-
return { state: 1 };
|
|
60
|
+
if (a === "--") return { state: 1 };
|
|
64
61
|
id = camel(a.substring(2));
|
|
65
62
|
} else {
|
|
66
63
|
id = aliases[a.substring(1)];
|
|
@@ -71,14 +68,13 @@ const parseKey = (specs, aliases, acc, a) => {
|
|
|
71
68
|
if (spec.flag) {
|
|
72
69
|
acc[id] = true;
|
|
73
70
|
id = void 0;
|
|
74
|
-
if (spec.fn && !spec.fn("true"))
|
|
75
|
-
return { state: 1, spec };
|
|
71
|
+
if (spec.fn && !spec.fn("true")) return { state: 1, spec };
|
|
76
72
|
}
|
|
77
73
|
return { state: 0, id, spec };
|
|
78
74
|
}
|
|
79
75
|
return { state: 2 };
|
|
80
76
|
};
|
|
81
|
-
const
|
|
77
|
+
const __parseValue = (spec, acc, id, a) => {
|
|
82
78
|
/^-[a-z]/i.test(a) && illegalArgs(`missing value for: --${id}`);
|
|
83
79
|
if (spec.multi) {
|
|
84
80
|
isArray(acc[id]) ? acc[id].push(a) : acc[id] = [a];
|
|
@@ -87,7 +83,7 @@ const parseValue = (spec, acc, id, a) => {
|
|
|
87
83
|
}
|
|
88
84
|
return spec.fn && !spec.fn(a);
|
|
89
85
|
};
|
|
90
|
-
const
|
|
86
|
+
const __processResults = (specs, acc) => {
|
|
91
87
|
let spec;
|
|
92
88
|
for (let id in specs) {
|
|
93
89
|
spec = specs[id];
|
|
@@ -98,12 +94,12 @@ const processResults = (specs, acc) => {
|
|
|
98
94
|
illegalArgs(`missing arg: --${id}`);
|
|
99
95
|
}
|
|
100
96
|
} else if (spec.coerce) {
|
|
101
|
-
|
|
97
|
+
__coerceValue(spec, acc, id);
|
|
102
98
|
}
|
|
103
99
|
}
|
|
104
100
|
return acc;
|
|
105
101
|
};
|
|
106
|
-
const
|
|
102
|
+
const __coerceValue = (spec, acc, id) => {
|
|
107
103
|
try {
|
|
108
104
|
if (spec.multi && spec.delim) {
|
|
109
105
|
acc[id] = acc[id].reduce(
|
package/usage.js
CHANGED
|
@@ -20,7 +20,7 @@ const usage = (specs, opts = {}) => {
|
|
|
20
20
|
};
|
|
21
21
|
const theme = isPlainObject(opts.color) ? { ...DEFAULT_THEME, ...opts.color } : opts.color ? DEFAULT_THEME : {};
|
|
22
22
|
const indent = repeat(" ", opts.paramWidth);
|
|
23
|
-
const format = (ids) => ids.map((id) =>
|
|
23
|
+
const format = (ids) => ids.map((id) => __argUsage(id, specs[id], opts, theme, indent));
|
|
24
24
|
const sortedIDs = Object.keys(specs).sort();
|
|
25
25
|
const groups = opts.groups ? opts.groups.map(
|
|
26
26
|
(gid) => [
|
|
@@ -29,7 +29,7 @@ const usage = (specs, opts = {}) => {
|
|
|
29
29
|
]
|
|
30
30
|
).filter((g) => !!g[1].length) : [["options", sortedIDs]];
|
|
31
31
|
return [
|
|
32
|
-
...
|
|
32
|
+
...__wrap(opts.prefix, opts.lineWidth),
|
|
33
33
|
...groups.map(
|
|
34
34
|
([gid, ids]) => [
|
|
35
35
|
...opts.showGroupNames ? [`${capitalize(gid)}:
|
|
@@ -38,35 +38,35 @@ const usage = (specs, opts = {}) => {
|
|
|
38
38
|
""
|
|
39
39
|
].join("\n")
|
|
40
40
|
),
|
|
41
|
-
...
|
|
41
|
+
...__wrap(opts.suffix, opts.lineWidth)
|
|
42
42
|
].join("\n");
|
|
43
43
|
};
|
|
44
|
-
const
|
|
45
|
-
const hint =
|
|
46
|
-
const alias =
|
|
47
|
-
const name =
|
|
44
|
+
const __argUsage = (id, spec, opts, theme, indent) => {
|
|
45
|
+
const hint = __argHint(spec, theme);
|
|
46
|
+
const alias = __argAlias(spec, theme, hint);
|
|
47
|
+
const name = __ansi(`--${kebab(id)}`, theme.param);
|
|
48
48
|
const params = `${alias}${name}${hint}`;
|
|
49
49
|
const isRequired = spec.optional === false && spec.default === void 0;
|
|
50
50
|
const prefixes = [];
|
|
51
51
|
isRequired && prefixes.push("required");
|
|
52
52
|
spec.multi && prefixes.push("multiple");
|
|
53
|
-
const body =
|
|
54
|
-
return padRight(opts.paramWidth)(params, lengthAnsi(params)) +
|
|
53
|
+
const body = __argPrefix(prefixes, theme, isRequired) + (spec.desc || "") + __argDefault(spec, opts, theme);
|
|
54
|
+
return padRight(opts.paramWidth)(params, lengthAnsi(params)) + __wrap(body, opts.lineWidth - opts.paramWidth).map((l, i) => i > 0 ? indent + l : l).join("\n");
|
|
55
55
|
};
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
const
|
|
56
|
+
const __argHint = (spec, theme) => spec.hint ? __ansi(" " + spec.hint, theme.hint) : "";
|
|
57
|
+
const __argAlias = (spec, theme, hint) => spec.alias ? `${__ansi("-" + spec.alias, theme.param)}${hint}, ` : "";
|
|
58
|
+
const __argPrefix = (prefixes, theme, isRequired) => prefixes.length ? __ansi(
|
|
59
59
|
`[${prefixes.join(", ")}] `,
|
|
60
60
|
isRequired ? theme.required : theme.multi
|
|
61
61
|
) : "";
|
|
62
|
-
const
|
|
62
|
+
const __argDefault = (spec, opts, theme) => opts.showDefaults && spec.default != null && spec.default !== false ? __ansi(
|
|
63
63
|
` (default: ${stringify(true)(
|
|
64
64
|
spec.defaultHint != void 0 ? spec.defaultHint : spec.default
|
|
65
65
|
)})`,
|
|
66
66
|
theme.default
|
|
67
67
|
) : "";
|
|
68
|
-
const
|
|
69
|
-
const
|
|
68
|
+
const __ansi = (x, col) => col != null ? `\x1B[${col}m${x}\x1B[0m` : x;
|
|
69
|
+
const __wrap = (str, width) => str ? wordWrapLines(str, {
|
|
70
70
|
width,
|
|
71
71
|
splitter: SPLIT_ANSI,
|
|
72
72
|
hard: false
|