@thi.ng/args 2.10.1 → 3.0.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/CHANGELOG.md +15 -1
- package/README.md +31 -13
- package/api.d.ts +66 -24
- package/args.d.ts +121 -81
- package/args.js +66 -50
- package/coerce.d.ts +0 -3
- package/coerce.js +0 -6
- package/package.json +3 -3
- package/parse.js +18 -20
- package/usage.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2025-09-
|
|
3
|
+
- **Last updated**: 2025-09-26T11:53:06Z
|
|
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.
|
|
@@ -11,6 +11,20 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
11
11
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
12
12
|
and/or version bumps of transitive dependencies.
|
|
13
13
|
|
|
14
|
+
# [3.0.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/args@3.0.0) (2025-09-26)
|
|
15
|
+
|
|
16
|
+
#### 🛑 Breaking changes
|
|
17
|
+
|
|
18
|
+
- update arg specs & arg factory fns, simplify types ([7ad3efb](https://github.com/thi-ng/umbrella/commit/7ad3efb))
|
|
19
|
+
- BREAKING CHANGES: update arg specs & arg factory fns, simplify types
|
|
20
|
+
- add `type` field in all arg specs
|
|
21
|
+
- add/update arg-related types
|
|
22
|
+
- update required arg handling: `optional: false` => `required: true`
|
|
23
|
+
- update delimiter handling (move into arg specs)
|
|
24
|
+
- update `tuple()` arg order
|
|
25
|
+
- remove obsolete coercion fns (`coerceFloats()` etc.)
|
|
26
|
+
- update tests
|
|
27
|
+
|
|
14
28
|
## [2.10.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/args@2.10.0) (2025-09-04)
|
|
15
29
|
|
|
16
30
|
#### 🚀 Features
|
package/README.md
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
- [Re-usable argument presets](#re-usable-argument-presets)
|
|
20
20
|
- [CLI app framework](#cli-app-framework)
|
|
21
21
|
- [Status](#status)
|
|
22
|
+
- [Breaking changes in 3.0.0](#breaking-changes-in-300)
|
|
22
23
|
- [Installation](#installation)
|
|
23
24
|
- [Dependencies](#dependencies)
|
|
24
25
|
- [Projects using this package](#projects-using-this-package)
|
|
@@ -97,6 +98,15 @@ section](#projects-using-this-package) in this readme.
|
|
|
97
98
|
|
|
98
99
|
[Search or submit any issues for this package](https://github.com/thi-ng/umbrella/issues?q=%5Bargs%5D+in%3Atitle)
|
|
99
100
|
|
|
101
|
+
### Breaking changes in 3.0.0
|
|
102
|
+
|
|
103
|
+
- Required arguments are now to be specified using either `required: true` or
|
|
104
|
+
given a `default` value
|
|
105
|
+
- Tuple argument order has been swapped (to be more aligned with `size` and
|
|
106
|
+
`vec`) to: `tuple(size, coerce, {...})`
|
|
107
|
+
- Where applicable, `delim`iters are now to be included in the arg spec (rather
|
|
108
|
+
than given as separate function arg)
|
|
109
|
+
|
|
100
110
|
## Installation
|
|
101
111
|
|
|
102
112
|
```bash
|
|
@@ -115,7 +125,7 @@ For Node.js REPL:
|
|
|
115
125
|
const args = await import("@thi.ng/args");
|
|
116
126
|
```
|
|
117
127
|
|
|
118
|
-
Package sizes (brotli'd, pre-treeshake): ESM: 3.
|
|
128
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 3.39 KB
|
|
119
129
|
|
|
120
130
|
## Dependencies
|
|
121
131
|
|
|
@@ -191,42 +201,50 @@ const specs: Args<TestArgs> = {
|
|
|
191
201
|
hint: "PATH",
|
|
192
202
|
desc: "Config file path (CLI args always take precedence over those settings)",
|
|
193
203
|
}),
|
|
204
|
+
|
|
194
205
|
// boolean flag (default: false)
|
|
195
206
|
force: flag({
|
|
196
207
|
alias: "f",
|
|
197
208
|
desc: "Force operation",
|
|
198
|
-
// side effect
|
|
199
|
-
// parsing only continues if
|
|
209
|
+
// side effect and/or validation
|
|
210
|
+
// parsing only continues if function returns true
|
|
200
211
|
fn: (_) => (console.log("force mode enabled"), true),
|
|
201
212
|
}),
|
|
213
|
+
|
|
202
214
|
// hex int value
|
|
203
215
|
bg: hex({
|
|
204
216
|
desc: "Background color",
|
|
205
|
-
// mandatory args require a `default` value and/or `
|
|
217
|
+
// mandatory args require a `default` value and/or `required: true`
|
|
206
218
|
default: 0xffffff,
|
|
207
219
|
defaultHint: "ffffff",
|
|
208
220
|
}),
|
|
221
|
+
|
|
209
222
|
// enum value (mandatory)
|
|
210
223
|
type: oneOf(["png", "jpg", "gif", "tiff"], {
|
|
211
224
|
alias: "t",
|
|
212
225
|
desc: "Image type",
|
|
213
|
-
// mandatory args require a `default` value and/or `
|
|
214
|
-
|
|
226
|
+
// mandatory args require a `default` value and/or `required: true`
|
|
227
|
+
required: true,
|
|
215
228
|
}),
|
|
229
|
+
|
|
216
230
|
// fixed size numeric tuple w/ `x` as delimiter
|
|
217
|
-
|
|
218
|
-
// syntax sugar for
|
|
219
|
-
size:
|
|
231
|
+
size: size(2, { hint: "WxH", desc: "Target size", delim: "x" }),
|
|
232
|
+
// syntax sugar for:
|
|
233
|
+
// size: tuple(2, coerceInt, { hint: "WxH", desc: "Target size" }, "x"),
|
|
234
|
+
|
|
220
235
|
// another version for tuples of floating point values
|
|
221
|
-
|
|
222
|
-
|
|
236
|
+
pos: vec(2, { desc: "Lat/Lon coordinates", hint: "LAT,LON" }),
|
|
237
|
+
// syntax sugar for:
|
|
238
|
+
// pos: tuple(2, coerceFloat, { desc: "Lat/Lon" }),
|
|
239
|
+
|
|
223
240
|
// JSON string arg
|
|
224
241
|
xtra: json({
|
|
225
242
|
alias: "x",
|
|
226
243
|
desc: "Extra options",
|
|
227
244
|
group: "extra",
|
|
228
245
|
}),
|
|
229
|
-
|
|
246
|
+
|
|
247
|
+
// key-value pairs parsed into an object (multiple allowed)
|
|
230
248
|
define: kvPairs({
|
|
231
249
|
alias: "D",
|
|
232
250
|
desc: "Define dict entry",
|
|
@@ -382,7 +400,7 @@ const HELLO: Command<HelloOpts, CommonOpts> = {
|
|
|
382
400
|
name: string({
|
|
383
401
|
alias: "n",
|
|
384
402
|
desc: "Name for greeting",
|
|
385
|
-
|
|
403
|
+
required: true,
|
|
386
404
|
}),
|
|
387
405
|
},
|
|
388
406
|
// this command does not accept any inputs
|
package/api.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import type { Fn, Fn2, IDeref, IObjectOf } from "@thi.ng/api";
|
|
1
|
+
import type { Fn, Fn2, IDeref, IObjectOf, Predicate } from "@thi.ng/api";
|
|
2
2
|
import type { ILogger } from "@thi.ng/logger";
|
|
3
3
|
import type { FormatPresets } from "@thi.ng/text-format";
|
|
4
4
|
export interface ArgSpecBase {
|
|
5
|
+
/**
|
|
6
|
+
* Unique arg type ID
|
|
7
|
+
*/
|
|
8
|
+
type: string;
|
|
5
9
|
/**
|
|
6
10
|
* Shorthand for given arg/option
|
|
7
11
|
*/
|
|
@@ -31,44 +35,82 @@ export interface ArgSpecBase {
|
|
|
31
35
|
*/
|
|
32
36
|
group?: string;
|
|
33
37
|
}
|
|
34
|
-
export type
|
|
35
|
-
|
|
38
|
+
export type ArgSpec<T> = ArgSpecBase & ArgSpecRequired<T>;
|
|
39
|
+
export type ArgSpecRequired<T> = undefined extends T ? {
|
|
40
|
+
default?: T;
|
|
41
|
+
} : {
|
|
42
|
+
required: true;
|
|
36
43
|
} | {
|
|
37
44
|
default: T;
|
|
38
45
|
};
|
|
39
|
-
export type
|
|
46
|
+
export type Args<T extends object> = {
|
|
47
|
+
[id in keyof T]: ArgSpec<T[id]>;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Partial arg spec given to various argument factory functions.
|
|
51
|
+
*/
|
|
52
|
+
export type ArgDef = Omit<ArgSpecBase, "type">;
|
|
53
|
+
/**
|
|
54
|
+
* Partial arg spec (for required arguments) given to various argument factory
|
|
55
|
+
* functions.
|
|
56
|
+
*/
|
|
57
|
+
export type ArgDefRequired<T> = ArgDef & ({
|
|
58
|
+
default: T;
|
|
59
|
+
} | {
|
|
60
|
+
required: true;
|
|
61
|
+
});
|
|
62
|
+
/**
|
|
63
|
+
* @internal
|
|
64
|
+
*/
|
|
40
65
|
export type ArgSpecExt = ArgSpec<any> & {
|
|
66
|
+
/**
|
|
67
|
+
* Value coercion fn.
|
|
68
|
+
*/
|
|
41
69
|
coerce?: Fn<any, any>;
|
|
70
|
+
/**
|
|
71
|
+
* Delimiter to split values (only used for `multi` args and if `split=false`)
|
|
72
|
+
*/
|
|
42
73
|
delim?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Default value
|
|
76
|
+
*/
|
|
43
77
|
default?: any;
|
|
44
|
-
|
|
45
|
-
|
|
78
|
+
/**
|
|
79
|
+
* User defined validation fn (can be used for side effects too).
|
|
80
|
+
*/
|
|
81
|
+
fn?: Predicate<string>;
|
|
82
|
+
/**
|
|
83
|
+
* Indicator flag for args accepting multiple values
|
|
84
|
+
*/
|
|
46
85
|
multi?: boolean;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
} : KVDict extends T[id] ? ArgSpec<T[id]> & {
|
|
57
|
-
coerce: Fn<string[], Exclude<T[id], undefined>>;
|
|
58
|
-
multi: true;
|
|
59
|
-
} : KVMultiDict extends T[id] ? ArgSpec<T[id]> & {
|
|
60
|
-
coerce: Fn<string[], Exclude<T[id], undefined>>;
|
|
61
|
-
multi: true;
|
|
62
|
-
} : ArgSpec<T[id]> & {
|
|
63
|
-
coerce: Fn<string, Exclude<T[id], undefined>>;
|
|
64
|
-
};
|
|
86
|
+
/**
|
|
87
|
+
* Indicator flag for required args.
|
|
88
|
+
*/
|
|
89
|
+
required?: true;
|
|
90
|
+
/**
|
|
91
|
+
* Unless false, collected values are split via `delim` prior to calling
|
|
92
|
+
* coercion function. Only used for `multi` specs.
|
|
93
|
+
*/
|
|
94
|
+
split?: boolean;
|
|
65
95
|
};
|
|
66
96
|
export type KVDict = IObjectOf<string>;
|
|
67
97
|
export type KVMultiDict = IObjectOf<string[]>;
|
|
68
98
|
export interface ParseResult<T> {
|
|
99
|
+
/**
|
|
100
|
+
* Parsed arguments
|
|
101
|
+
*/
|
|
69
102
|
result: T;
|
|
103
|
+
/**
|
|
104
|
+
* `process.argv` index (+1) where parsing stopped
|
|
105
|
+
*/
|
|
70
106
|
index: number;
|
|
107
|
+
/**
|
|
108
|
+
* If true, all elements of `process.argv` have been consumed
|
|
109
|
+
*/
|
|
71
110
|
done: boolean;
|
|
111
|
+
/**
|
|
112
|
+
* Remaining unparsed elements of `process.argv` (if any)
|
|
113
|
+
*/
|
|
72
114
|
rest: string[];
|
|
73
115
|
}
|
|
74
116
|
export interface ParseOpts {
|
package/args.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { type Fn } from "@thi.ng/api/fn";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ArgDef, ArgDefRequired, KVDict, KVMultiDict, Tuple } from "./api.js";
|
|
3
3
|
/**
|
|
4
4
|
* Returns a full {@link ArgSpec} for a boolean flag. The mere presence of this
|
|
5
5
|
* arg will enable the flag.
|
|
6
6
|
*
|
|
7
7
|
* @param spec -
|
|
8
8
|
*/
|
|
9
|
-
export declare const flag: <S extends
|
|
10
|
-
|
|
9
|
+
export declare const flag: <S extends ArgDef>(spec: S) => S & {
|
|
10
|
+
type: "flag";
|
|
11
11
|
default: boolean;
|
|
12
12
|
group: string;
|
|
13
13
|
};
|
|
@@ -16,7 +16,8 @@ export declare const flag: <S extends Partial<ArgSpec<boolean>>>(spec: S) => S &
|
|
|
16
16
|
*
|
|
17
17
|
* @param spec -
|
|
18
18
|
*/
|
|
19
|
-
export declare const string: <S extends
|
|
19
|
+
export declare const string: <S extends ArgDef | ArgDefRequired<string>>(spec: S) => S & {
|
|
20
|
+
type: "string";
|
|
20
21
|
coerce: Fn<string, string>;
|
|
21
22
|
hint: string;
|
|
22
23
|
group: string;
|
|
@@ -28,13 +29,15 @@ export declare const string: <S extends Partial<ArgSpec<string>>>(spec: S) => S
|
|
|
28
29
|
*
|
|
29
30
|
* @param spec -
|
|
30
31
|
*/
|
|
31
|
-
export declare const strings: <S extends
|
|
32
|
-
delim
|
|
33
|
-
}
|
|
34
|
-
|
|
32
|
+
export declare const strings: <S extends ArgDef | ArgDefRequired<unknown[]>>(spec: S & {
|
|
33
|
+
delim?: string;
|
|
34
|
+
}) => S & {
|
|
35
|
+
type: "strings";
|
|
36
|
+
coerce: Fn<string[], unknown[]>;
|
|
35
37
|
hint: string;
|
|
36
|
-
multi: true;
|
|
37
38
|
group: string;
|
|
39
|
+
delim: string;
|
|
40
|
+
multi: true;
|
|
38
41
|
};
|
|
39
42
|
/**
|
|
40
43
|
* Returns a full {@link ArgSpec} for a floating point value arg. The value
|
|
@@ -42,21 +45,28 @@ export declare const strings: <S extends Partial<ArgSpec<string[]> & {
|
|
|
42
45
|
*
|
|
43
46
|
* @param spec -
|
|
44
47
|
*/
|
|
45
|
-
export declare const float: <S extends
|
|
48
|
+
export declare const float: <S extends ArgDef | ArgDefRequired<number>>(spec: S) => S & {
|
|
49
|
+
type: "float";
|
|
46
50
|
coerce: Fn<string, number>;
|
|
47
51
|
hint: string;
|
|
48
52
|
group: string;
|
|
49
53
|
};
|
|
50
54
|
/**
|
|
51
|
-
* Returns a full {@link ArgSpec} for a
|
|
52
|
-
*
|
|
55
|
+
* Multi-arg version of {@link float}. Returns a full {@link ArgSpec} for a
|
|
56
|
+
* multi floating point value arg. This argument can be provided mutiple times
|
|
57
|
+
* with values being coerced into numbers and collected into an array.
|
|
53
58
|
*
|
|
54
59
|
* @param spec -
|
|
55
60
|
*/
|
|
56
|
-
export declare const
|
|
57
|
-
|
|
61
|
+
export declare const floats: <S extends ArgDef | ArgDefRequired<unknown[]>>(spec: S & {
|
|
62
|
+
delim?: string;
|
|
63
|
+
}) => S & {
|
|
64
|
+
type: "floats";
|
|
65
|
+
coerce: Fn<string[], unknown[]>;
|
|
58
66
|
hint: string;
|
|
59
67
|
group: string;
|
|
68
|
+
delim: string;
|
|
69
|
+
multi: true;
|
|
60
70
|
};
|
|
61
71
|
/**
|
|
62
72
|
* Returns a full {@link ArgSpec} for a single integer value arg. The value
|
|
@@ -64,66 +74,57 @@ export declare const hex: <S extends Partial<ArgSpec<number>>>(spec: S) => S & {
|
|
|
64
74
|
*
|
|
65
75
|
* @param spec -
|
|
66
76
|
*/
|
|
67
|
-
export declare const int: <S extends
|
|
77
|
+
export declare const int: <S extends ArgDef | ArgDefRequired<number>>(spec: S) => S & {
|
|
78
|
+
type: "int";
|
|
68
79
|
coerce: Fn<string, number>;
|
|
69
80
|
hint: string;
|
|
70
81
|
group: string;
|
|
71
82
|
};
|
|
72
83
|
/**
|
|
73
|
-
* Multi-arg version of {@link
|
|
74
|
-
*
|
|
75
|
-
*
|
|
84
|
+
* Multi-arg version of {@link int}. Returns a full {@link ArgSpec} for a multi
|
|
85
|
+
* integer value arg. This argument can be provided mutiple times with values
|
|
86
|
+
* being coerced into numbers and collected into an array.
|
|
76
87
|
*
|
|
77
88
|
* @param spec -
|
|
78
89
|
*/
|
|
79
|
-
export declare const
|
|
80
|
-
delim
|
|
81
|
-
}
|
|
82
|
-
|
|
90
|
+
export declare const ints: <S extends ArgDef | ArgDefRequired<unknown[]>>(spec: S & {
|
|
91
|
+
delim?: string;
|
|
92
|
+
}) => S & {
|
|
93
|
+
type: "ints";
|
|
94
|
+
coerce: Fn<string[], unknown[]>;
|
|
83
95
|
hint: string;
|
|
84
|
-
multi: true;
|
|
85
96
|
group: string;
|
|
86
|
-
};
|
|
87
|
-
/**
|
|
88
|
-
* Multi-arg version of {@link hex}. Returns a full {@link ArgSpec} for a multi
|
|
89
|
-
* hex integer value arg. This argument can be provided mutiple times with
|
|
90
|
-
* values being coerced into numbers and collected into an array.
|
|
91
|
-
*
|
|
92
|
-
* @param spec -
|
|
93
|
-
*/
|
|
94
|
-
export declare const hexes: <S extends Partial<ArgSpec<number[]> & {
|
|
95
97
|
delim: string;
|
|
96
|
-
}>>(spec: S) => S & {
|
|
97
|
-
coerce: Fn<string[], number[]>;
|
|
98
|
-
hint: string;
|
|
99
98
|
multi: true;
|
|
100
|
-
group: string;
|
|
101
99
|
};
|
|
102
100
|
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* being coerced into numbers and collected into an array.
|
|
101
|
+
* Returns a full {@link ArgSpec} for a single hex integer value arg. The value
|
|
102
|
+
* will be autoatically coerced into a number using {@link coerceHexInt}.
|
|
106
103
|
*
|
|
107
104
|
* @param spec -
|
|
108
105
|
*/
|
|
109
|
-
export declare const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
coerce: Fn<string[], number[]>;
|
|
106
|
+
export declare const hex: <S extends ArgDef | ArgDefRequired<number>>(spec: S) => S & {
|
|
107
|
+
type: "hex";
|
|
108
|
+
coerce: Fn<string, number>;
|
|
113
109
|
hint: string;
|
|
114
|
-
multi: true;
|
|
115
110
|
group: string;
|
|
116
111
|
};
|
|
117
112
|
/**
|
|
118
|
-
*
|
|
119
|
-
*
|
|
113
|
+
* Multi-arg version of {@link hex}. Returns a full {@link ArgSpec} for a multi
|
|
114
|
+
* hex integer value arg. This argument can be provided mutiple times with
|
|
115
|
+
* values being coerced into numbers and collected into an array.
|
|
120
116
|
*
|
|
121
117
|
* @param spec -
|
|
122
118
|
*/
|
|
123
|
-
export declare const
|
|
124
|
-
|
|
119
|
+
export declare const hexes: <S extends ArgDef | ArgDefRequired<unknown[]>>(spec: S & {
|
|
120
|
+
delim?: string;
|
|
121
|
+
}) => S & {
|
|
122
|
+
type: "hexes";
|
|
123
|
+
coerce: Fn<string[], unknown[]>;
|
|
125
124
|
hint: string;
|
|
126
125
|
group: string;
|
|
126
|
+
delim: string;
|
|
127
|
+
multi: true;
|
|
127
128
|
};
|
|
128
129
|
/**
|
|
129
130
|
* Returns full {@link ArgSpec} for an enum-like string value arg. The raw CLI
|
|
@@ -132,12 +133,13 @@ export declare const json: <T, S extends Partial<ArgSpec<T>>>(spec: S) => S & {
|
|
|
132
133
|
* @param opts -
|
|
133
134
|
* @param spec -
|
|
134
135
|
*/
|
|
135
|
-
export declare const oneOf: <K extends string, S extends
|
|
136
|
+
export declare const oneOf: <K extends string, S extends ArgDef | ArgDefRequired<K>>(opts: readonly K[], spec: S) => S & {
|
|
137
|
+
type: "oneOf";
|
|
136
138
|
coerce: Fn<string, K>;
|
|
139
|
+
desc: string;
|
|
137
140
|
hint: string;
|
|
138
141
|
group: string;
|
|
139
|
-
|
|
140
|
-
desc: string;
|
|
142
|
+
opts: readonly K[];
|
|
141
143
|
};
|
|
142
144
|
/**
|
|
143
145
|
* Multi-arg version of {@link oneOf}. Returns full {@link ArgSpec} for multiple
|
|
@@ -147,15 +149,17 @@ export declare const oneOf: <K extends string, S extends Partial<ArgSpec<K>>>(op
|
|
|
147
149
|
* @param opts -
|
|
148
150
|
* @param spec -
|
|
149
151
|
*/
|
|
150
|
-
export declare const oneOfMulti: <K extends string, S extends
|
|
151
|
-
delim
|
|
152
|
-
}
|
|
153
|
-
|
|
152
|
+
export declare const oneOfMulti: <K extends string, S extends ArgDef | ArgDefRequired<K>>(opts: readonly K[], spec: S & {
|
|
153
|
+
delim?: string;
|
|
154
|
+
}) => S & {
|
|
155
|
+
type: "oneOfMulti";
|
|
156
|
+
coerce: Fn<string, K>;
|
|
157
|
+
desc: string;
|
|
154
158
|
hint: string;
|
|
155
|
-
multi: true;
|
|
156
159
|
group: string;
|
|
157
|
-
|
|
158
|
-
|
|
160
|
+
multi: true;
|
|
161
|
+
opts: readonly K[];
|
|
162
|
+
delim?: string;
|
|
159
163
|
};
|
|
160
164
|
/**
|
|
161
165
|
* Returns a full {@link ArgSpec} for multiple `key=value` pair args, coerced
|
|
@@ -167,13 +171,19 @@ export declare const oneOfMulti: <K extends string, S extends Partial<ArgSpec<K[
|
|
|
167
171
|
* is true, only full KV pairs are allowed.
|
|
168
172
|
*
|
|
169
173
|
* @param spec -
|
|
170
|
-
* @param delim -
|
|
171
174
|
*/
|
|
172
|
-
export declare const kvPairs: <S extends
|
|
175
|
+
export declare const kvPairs: <S extends ArgDef | ArgDefRequired<KVDict>>(spec: S & {
|
|
176
|
+
delim?: string;
|
|
177
|
+
strict?: boolean;
|
|
178
|
+
}) => S & {
|
|
179
|
+
type: "kvPairs";
|
|
173
180
|
coerce: Fn<string[], KVDict>;
|
|
174
181
|
hint: string;
|
|
175
|
-
multi: true;
|
|
176
182
|
group: string;
|
|
183
|
+
multi: true;
|
|
184
|
+
kvDelim?: string;
|
|
185
|
+
strict?: boolean;
|
|
186
|
+
split: false;
|
|
177
187
|
};
|
|
178
188
|
/**
|
|
179
189
|
* Like {@link kvPairs}, but coerces KV pairs into a result {@link KVMultiDict}
|
|
@@ -181,20 +191,24 @@ export declare const kvPairs: <S extends Partial<ArgSpec<KVDict>>>(spec: S, deli
|
|
|
181
191
|
* into arrays).
|
|
182
192
|
*
|
|
183
193
|
* @param spec -
|
|
184
|
-
* @param delim -
|
|
185
|
-
* @param strict -
|
|
186
194
|
*/
|
|
187
|
-
export declare const kvPairsMulti: <S extends
|
|
195
|
+
export declare const kvPairsMulti: <S extends ArgDef | ArgDefRequired<KVMultiDict>>(spec: S & {
|
|
196
|
+
delim?: string;
|
|
197
|
+
strict?: boolean;
|
|
198
|
+
}) => S & {
|
|
199
|
+
type: "kvPairsMulti";
|
|
188
200
|
coerce: Fn<string[], KVMultiDict>;
|
|
189
201
|
hint: string;
|
|
190
|
-
multi: true;
|
|
191
202
|
group: string;
|
|
203
|
+
multi: true;
|
|
204
|
+
delim?: string;
|
|
205
|
+
strict?: boolean;
|
|
192
206
|
};
|
|
193
207
|
/**
|
|
194
208
|
* Returns a full {@link ArgSpec} for a fixed `size` tuple extracted from a
|
|
195
|
-
* single value string. The individual values are delimited by `delim`
|
|
196
|
-
* be coerced into their target type via `coerce`. The result
|
|
197
|
-
* wrapped in a {@link Tuple} instance.
|
|
209
|
+
* single value string. The individual values are delimited by `delim` (default:
|
|
210
|
+
* `,`) and will be coerced into their target type via `coerce`. The result
|
|
211
|
+
* tuple will be wrapped in a {@link Tuple} instance.
|
|
198
212
|
*
|
|
199
213
|
* @remarks
|
|
200
214
|
* An error will be thrown if the number of extracted values differs from the
|
|
@@ -205,7 +219,7 @@ export declare const kvPairsMulti: <S extends Partial<ArgSpec<KVMultiDict>>>(spe
|
|
|
205
219
|
* import { coerceInt, parse, tuple } from "@thi.ng/args";
|
|
206
220
|
*
|
|
207
221
|
* console.log(
|
|
208
|
-
* parse({ a: tuple(
|
|
222
|
+
* parse({ a: tuple(2, coerceInt, {})}, ["--a", "1,2"])
|
|
209
223
|
* );
|
|
210
224
|
* // {
|
|
211
225
|
* // result: { a: Tuple { value: [1, 2] } },
|
|
@@ -215,39 +229,65 @@ export declare const kvPairsMulti: <S extends Partial<ArgSpec<KVMultiDict>>>(spe
|
|
|
215
229
|
* // }
|
|
216
230
|
* ```
|
|
217
231
|
*
|
|
218
|
-
* @param coerce -
|
|
219
232
|
* @param size -
|
|
233
|
+
* @param coerce -
|
|
220
234
|
* @param spec -
|
|
221
|
-
* @param delim -
|
|
222
235
|
*/
|
|
223
|
-
export declare const tuple: <T, S extends
|
|
236
|
+
export declare const tuple: <T, S extends ArgDef | ArgDefRequired<Tuple<T>>>(size: number, coerce: Fn<string, T>, spec: S & {
|
|
237
|
+
delim?: string;
|
|
238
|
+
}) => S & {
|
|
239
|
+
type: "tuple";
|
|
224
240
|
coerce: Fn<string, Tuple<T>>;
|
|
225
241
|
hint: string;
|
|
226
242
|
group: string;
|
|
243
|
+
size: number;
|
|
244
|
+
delim?: string;
|
|
227
245
|
};
|
|
228
246
|
/**
|
|
229
|
-
* Syntax sugar for `tuple(
|
|
247
|
+
* Syntax sugar for `tuple(size, coerceInt, {...})`. See {@link tuple} for
|
|
248
|
+
* further details.
|
|
230
249
|
*
|
|
231
250
|
* @param size -
|
|
232
251
|
* @param spec -
|
|
233
|
-
* @param delim -
|
|
234
252
|
*/
|
|
235
|
-
export declare const size: <S extends
|
|
253
|
+
export declare const size: <S extends ArgDef | ArgDefRequired<Tuple<number>>>(size: number, spec: S & {
|
|
254
|
+
delim?: string;
|
|
255
|
+
}) => S & {
|
|
256
|
+
type: "tuple";
|
|
236
257
|
coerce: Fn<string, Tuple<number>>;
|
|
237
258
|
hint: string;
|
|
238
259
|
group: string;
|
|
260
|
+
size: number;
|
|
261
|
+
delim?: string;
|
|
239
262
|
};
|
|
240
263
|
/**
|
|
241
|
-
* Syntax sugar for `tuple(
|
|
264
|
+
* Syntax sugar for `tuple(size, coerceFloat, {...})`. See {@link tuple} for
|
|
265
|
+
* further details.
|
|
242
266
|
*
|
|
243
267
|
* @param size -
|
|
244
268
|
* @param spec -
|
|
245
|
-
* @param delim -
|
|
246
269
|
*/
|
|
247
|
-
export declare const vec: <S extends
|
|
270
|
+
export declare const vec: <S extends ArgDef | ArgDefRequired<Tuple<number>>>(size: number, spec: S & {
|
|
271
|
+
delim?: string;
|
|
272
|
+
}) => S & {
|
|
273
|
+
type: "tuple";
|
|
248
274
|
coerce: Fn<string, Tuple<number>>;
|
|
249
275
|
hint: string;
|
|
250
276
|
group: string;
|
|
277
|
+
size: number;
|
|
278
|
+
delim?: string;
|
|
279
|
+
};
|
|
280
|
+
/**
|
|
281
|
+
* Returns full {@link ArgSpec} for a JSON value arg. The raw CLI value string
|
|
282
|
+
* will be automcatically coerced using {@link coerceJson}.
|
|
283
|
+
*
|
|
284
|
+
* @param spec -
|
|
285
|
+
*/
|
|
286
|
+
export declare const json: <T, S extends ArgDef | ArgDefRequired<T>>(spec: S) => S & {
|
|
287
|
+
type: "json";
|
|
288
|
+
coerce: Fn<string, T>;
|
|
289
|
+
hint: string;
|
|
290
|
+
group: string;
|
|
251
291
|
};
|
|
252
292
|
/**
|
|
253
293
|
* Re-usable preset arg spec for a `--dry-run` flag.
|
|
@@ -256,7 +296,7 @@ export declare const ARG_DRY_RUN: {
|
|
|
256
296
|
dryRun: {
|
|
257
297
|
desc: string;
|
|
258
298
|
} & {
|
|
259
|
-
|
|
299
|
+
type: "flag";
|
|
260
300
|
default: boolean;
|
|
261
301
|
group: string;
|
|
262
302
|
};
|
|
@@ -269,7 +309,7 @@ export declare const ARG_QUIET: {
|
|
|
269
309
|
alias: string;
|
|
270
310
|
desc: string;
|
|
271
311
|
} & {
|
|
272
|
-
|
|
312
|
+
type: "flag";
|
|
273
313
|
default: boolean;
|
|
274
314
|
group: string;
|
|
275
315
|
};
|
|
@@ -282,7 +322,7 @@ export declare const ARG_VERBOSE: {
|
|
|
282
322
|
alias: string;
|
|
283
323
|
desc: string;
|
|
284
324
|
} & {
|
|
285
|
-
|
|
325
|
+
type: "flag";
|
|
286
326
|
default: boolean;
|
|
287
327
|
group: string;
|
|
288
328
|
};
|
package/args.js
CHANGED
|
@@ -2,88 +2,104 @@ import { identity } from "@thi.ng/api/fn";
|
|
|
2
2
|
import { repeat } from "@thi.ng/strings/repeat";
|
|
3
3
|
import {
|
|
4
4
|
coerceFloat,
|
|
5
|
-
coerceFloats,
|
|
6
5
|
coerceHexInt,
|
|
7
|
-
coerceHexInts,
|
|
8
6
|
coerceInt,
|
|
9
|
-
coerceInts,
|
|
10
7
|
coerceJson,
|
|
11
8
|
coerceKV,
|
|
12
9
|
coerceOneOf,
|
|
13
10
|
coerceTuple
|
|
14
11
|
} from "./coerce.js";
|
|
15
|
-
const
|
|
12
|
+
const __desc = (opts, prefix) => `${prefix ? prefix + ": " : ""}${opts.map((x) => `"${x}"`).join(", ")}`;
|
|
13
|
+
const __hint = (hint, delim) => hint + (delim ? `[${delim}..]` : "");
|
|
14
|
+
const defSingle = (type, coerce, hint) => (spec) => ({
|
|
15
|
+
type,
|
|
16
16
|
coerce,
|
|
17
17
|
hint,
|
|
18
18
|
group: "main",
|
|
19
19
|
...spec
|
|
20
20
|
});
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
const defMulti = (type, coerce, hint, delim = ",") => (spec) => ({
|
|
22
|
+
type,
|
|
23
|
+
delim,
|
|
24
|
+
hint: __hint(hint, spec.delim ?? delim),
|
|
25
|
+
coerce: (x) => x.map(coerce),
|
|
25
26
|
group: "main",
|
|
27
|
+
multi: true,
|
|
26
28
|
...spec
|
|
27
29
|
});
|
|
28
|
-
const $hint = (hint, delim) => hint + (delim ? `[${delim}..]` : "");
|
|
29
30
|
const flag = (spec) => ({
|
|
30
|
-
|
|
31
|
-
default: false,
|
|
31
|
+
type: "flag",
|
|
32
32
|
group: "flags",
|
|
33
|
+
default: false,
|
|
33
34
|
...spec
|
|
34
35
|
});
|
|
35
|
-
const string =
|
|
36
|
-
const strings =
|
|
37
|
-
const float =
|
|
38
|
-
const
|
|
39
|
-
const int =
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
const json = (spec) => ({
|
|
44
|
-
coerce: coerceJson,
|
|
45
|
-
hint: "JSON",
|
|
46
|
-
group: "main",
|
|
47
|
-
...spec
|
|
48
|
-
});
|
|
49
|
-
const $desc = (opts, prefix) => `${prefix ? prefix + ": " : ""}${opts.map((x) => `"${x}"`).join(", ")}`;
|
|
36
|
+
const string = defSingle("string", identity, "STR");
|
|
37
|
+
const strings = defMulti("strings", identity, "STR");
|
|
38
|
+
const float = defSingle("float", coerceFloat, "NUM");
|
|
39
|
+
const floats = defMulti("floats", coerceFloat, "NUM");
|
|
40
|
+
const int = defSingle("int", coerceInt, "INT");
|
|
41
|
+
const ints = defMulti("ints", coerceInt, "INT");
|
|
42
|
+
const hex = defSingle("hex", coerceHexInt, "HEX");
|
|
43
|
+
const hexes = defMulti("hexes", coerceHexInt, "HEX");
|
|
50
44
|
const oneOf = (opts, spec) => ({
|
|
51
|
-
coerce: coerceOneOf(opts),
|
|
52
|
-
hint: "ID",
|
|
53
|
-
group: "main",
|
|
54
45
|
...spec,
|
|
55
|
-
|
|
46
|
+
type: "oneOf",
|
|
47
|
+
coerce: coerceOneOf(opts),
|
|
48
|
+
hint: spec.hint ?? "ID",
|
|
49
|
+
desc: __desc(opts, spec.desc),
|
|
50
|
+
group: spec.group ?? "main",
|
|
51
|
+
opts
|
|
56
52
|
});
|
|
57
53
|
const oneOfMulti = (opts, spec) => ({
|
|
58
|
-
coerce: (values) => values.map(coerceOneOf(opts)),
|
|
59
|
-
hint: $hint("ID", spec.delim),
|
|
60
|
-
multi: true,
|
|
61
|
-
group: "main",
|
|
62
54
|
...spec,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
55
|
+
type: "oneOfMulti",
|
|
56
|
+
coerce: coerceOneOf(opts),
|
|
57
|
+
hint: spec.hint ?? __hint("ID", spec.delim),
|
|
58
|
+
desc: __desc(opts, spec.desc),
|
|
59
|
+
group: spec.group ?? "main",
|
|
68
60
|
multi: true,
|
|
69
|
-
|
|
70
|
-
...spec
|
|
61
|
+
opts
|
|
71
62
|
});
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
63
|
+
const kvPairs = (spec) => {
|
|
64
|
+
if (!spec.delim) spec.delim = "=";
|
|
65
|
+
return {
|
|
66
|
+
type: "kvPairs",
|
|
67
|
+
coerce: coerceKV(spec.delim, spec.strict, false),
|
|
68
|
+
hint: `key${spec.delim}val`,
|
|
69
|
+
group: "main",
|
|
70
|
+
multi: true,
|
|
71
|
+
split: false,
|
|
72
|
+
...spec
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
const kvPairsMulti = (spec) => ({
|
|
76
|
+
type: "kvPairsMulti",
|
|
77
|
+
coerce: coerceKV(spec.delim, spec.strict, true),
|
|
78
|
+
hint: `key${spec.delim}val`,
|
|
76
79
|
group: "main",
|
|
80
|
+
multi: true,
|
|
77
81
|
...spec
|
|
78
82
|
});
|
|
79
|
-
const tuple = (
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
const tuple = (size2, coerce, spec) => {
|
|
84
|
+
if (!spec.delim) spec.delim = ",";
|
|
85
|
+
return {
|
|
86
|
+
type: "tuple",
|
|
87
|
+
hint: [...repeat("N", size2)].join(spec.delim),
|
|
88
|
+
coerce: coerceTuple(coerce, size2, spec.delim),
|
|
89
|
+
group: "main",
|
|
90
|
+
size: size2,
|
|
91
|
+
...spec
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
const size = (size2, spec) => tuple(size2, coerceInt, spec);
|
|
95
|
+
const vec = (size2, spec) => tuple(size2, coerceInt, spec);
|
|
96
|
+
const json = (spec) => ({
|
|
97
|
+
type: "json",
|
|
98
|
+
coerce: coerceJson,
|
|
99
|
+
hint: "JSON",
|
|
82
100
|
group: "main",
|
|
83
101
|
...spec
|
|
84
102
|
});
|
|
85
|
-
const size = (size2, spec, delim = "x") => tuple(coerceInt, size2, spec, delim);
|
|
86
|
-
const vec = (size2, spec, delim = ",") => tuple(coerceFloat, size2, spec, delim);
|
|
87
103
|
const ARG_DRY_RUN = {
|
|
88
104
|
dryRun: flag({
|
|
89
105
|
desc: "Dry run (no changes applied)"
|
package/coerce.d.ts
CHANGED
|
@@ -2,11 +2,8 @@ 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: (values: string[]) => number[];
|
|
6
5
|
export declare const coerceHexInt: (x: string) => number;
|
|
7
|
-
export declare const coerceHexInts: (values: string[]) => number[];
|
|
8
6
|
export declare const coerceInt: (x: string) => number;
|
|
9
|
-
export declare const coerceInts: (values: string[]) => number[];
|
|
10
7
|
export declare const coerceJson: <T>(x: string) => T;
|
|
11
8
|
export declare const coerceOneOf: <K extends string>(values: readonly K[]) => (x: string) => K;
|
|
12
9
|
export declare function coerceKV(delim?: string, strict?: boolean, multi?: false): Fn<string[], KVDict>;
|
package/coerce.js
CHANGED
|
@@ -4,11 +4,8 @@ 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 = (values) => values.map(coerceFloat);
|
|
8
7
|
const coerceHexInt = (x) => isHex(x) ? parseInt(x, 16) : illegalArgs(`not a hex value: ${x}`);
|
|
9
|
-
const coerceHexInts = (values) => values.map(coerceHexInt);
|
|
10
8
|
const coerceInt = (x) => isNumericInt(x) ? parseInt(x) : illegalArgs(`not an integer: ${x}`);
|
|
11
|
-
const coerceInts = (values) => values.map(coerceInt);
|
|
12
9
|
const coerceJson = (x) => JSON.parse(x);
|
|
13
10
|
const coerceOneOf = (values) => (x) => values.includes(x) ? x : illegalArgs(`invalid option: ${x}`);
|
|
14
11
|
function coerceKV(delim = "=", strict = false, multi = false) {
|
|
@@ -38,11 +35,8 @@ const coerceTuple = (coerce, size, delim = ",") => (src) => {
|
|
|
38
35
|
};
|
|
39
36
|
export {
|
|
40
37
|
coerceFloat,
|
|
41
|
-
coerceFloats,
|
|
42
38
|
coerceHexInt,
|
|
43
|
-
coerceHexInts,
|
|
44
39
|
coerceInt,
|
|
45
|
-
coerceInts,
|
|
46
40
|
coerceJson,
|
|
47
41
|
coerceKV,
|
|
48
42
|
coerceOneOf,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/args",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Declarative, functional CLI argument/options parser, app framework, arg value coercions, multi/sub-commands, usage generation, error handling etc.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"@thi.ng/api": "^8.12.2",
|
|
43
43
|
"@thi.ng/checks": "^3.7.18",
|
|
44
44
|
"@thi.ng/errors": "^2.5.42",
|
|
45
|
-
"@thi.ng/logger": "^3.
|
|
45
|
+
"@thi.ng/logger": "^3.2.0",
|
|
46
46
|
"@thi.ng/strings": "^3.9.22",
|
|
47
47
|
"@thi.ng/text-format": "^2.2.41"
|
|
48
48
|
},
|
|
@@ -110,5 +110,5 @@
|
|
|
110
110
|
"tag": "cli",
|
|
111
111
|
"year": 2018
|
|
112
112
|
},
|
|
113
|
-
"gitHead": "
|
|
113
|
+
"gitHead": "f3fa7a4798132f2faf9eb1ef12d99b9ca2148ec3\n"
|
|
114
114
|
}
|
package/parse.js
CHANGED
|
@@ -58,25 +58,23 @@ const __aliasIndex = (specs) => Object.entries(specs).reduce(
|
|
|
58
58
|
{}
|
|
59
59
|
);
|
|
60
60
|
const __parseKey = (specs, aliases, acc, a) => {
|
|
61
|
-
if (a[0]
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
return { state: 0, id, spec };
|
|
61
|
+
if (a[0] !== "-") return { state: 2 };
|
|
62
|
+
let id;
|
|
63
|
+
if (a[1] === "-") {
|
|
64
|
+
if (a.length === 2) return { state: 1 };
|
|
65
|
+
id = camel(a.substring(2));
|
|
66
|
+
} else {
|
|
67
|
+
id = aliases[a.substring(1)];
|
|
68
|
+
!id && illegalArgs(`unknown option: ${a}`);
|
|
69
|
+
}
|
|
70
|
+
const spec = specs[id];
|
|
71
|
+
!spec && illegalArgs(id);
|
|
72
|
+
if (spec.type === "flag") {
|
|
73
|
+
acc[id] = true;
|
|
74
|
+
id = void 0;
|
|
75
|
+
if (spec.fn && !spec.fn("true")) return { state: 1, spec };
|
|
78
76
|
}
|
|
79
|
-
return { state:
|
|
77
|
+
return { state: 0, id, spec };
|
|
80
78
|
};
|
|
81
79
|
const __parseValue = (spec, acc, id, a) => {
|
|
82
80
|
if (spec.multi) {
|
|
@@ -93,7 +91,7 @@ const __processResults = (specs, acc) => {
|
|
|
93
91
|
if (acc[id] === void 0) {
|
|
94
92
|
if (spec.default !== void 0) {
|
|
95
93
|
acc[id] = spec.default;
|
|
96
|
-
} else if (spec.
|
|
94
|
+
} else if (spec.required) {
|
|
97
95
|
illegalArgs(`missing arg: --${kebab(id)}`);
|
|
98
96
|
}
|
|
99
97
|
} else if (spec.coerce) {
|
|
@@ -104,7 +102,7 @@ const __processResults = (specs, acc) => {
|
|
|
104
102
|
};
|
|
105
103
|
const __coerceValue = (spec, acc, id) => {
|
|
106
104
|
try {
|
|
107
|
-
if (spec.multi && spec.delim) {
|
|
105
|
+
if (spec.multi && spec.delim && spec.split !== false) {
|
|
108
106
|
acc[id] = acc[id].reduce(
|
|
109
107
|
(acc2, x) => (acc2.push(...x.split(spec.delim)), acc2),
|
|
110
108
|
[]
|
package/usage.js
CHANGED
|
@@ -48,7 +48,7 @@ const __argUsage = (id, spec, opts, theme, indent) => {
|
|
|
48
48
|
const alias = __argAlias(spec, theme, hint);
|
|
49
49
|
const name = __ansi(`--${kebab(id)}`, theme.param);
|
|
50
50
|
const params = `${alias}${name}${hint}`;
|
|
51
|
-
const isRequired = spec.
|
|
51
|
+
const isRequired = !!spec.required && spec.default === void 0;
|
|
52
52
|
const prefixes = [];
|
|
53
53
|
isRequired && prefixes.push("required");
|
|
54
54
|
spec.multi && prefixes.push("multiple");
|