jackspeak 4.0.0 → 4.0.2
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/dist/commonjs/index.d.ts +61 -69
- package/dist/commonjs/index.d.ts.map +1 -1
- package/dist/commonjs/index.js +197 -292
- package/dist/commonjs/index.js.map +1 -1
- package/dist/esm/index.d.ts +61 -69
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +192 -288
- package/dist/esm/index.js.map +1 -1
- package/package.json +10 -11
- package/dist/commonjs/parse-args-cjs.cjs.map +0 -1
- package/dist/commonjs/parse-args-cjs.d.cts.map +0 -1
- package/dist/commonjs/parse-args.d.ts +0 -4
- package/dist/commonjs/parse-args.js +0 -50
- package/dist/esm/parse-args.d.ts +0 -4
- package/dist/esm/parse-args.d.ts.map +0 -1
- package/dist/esm/parse-args.js +0 -26
- package/dist/esm/parse-args.js.map +0 -1
package/dist/esm/index.js
CHANGED
|
@@ -1,19 +1,54 @@
|
|
|
1
|
-
import { inspect } from 'node:util';
|
|
2
|
-
import { parseArgs } from './parse-args.js';
|
|
1
|
+
import { inspect, parseArgs, } from 'node:util';
|
|
3
2
|
// it's a tiny API, just cast it inline, it's fine
|
|
4
3
|
//@ts-ignore
|
|
5
4
|
import cliui from '@isaacs/cliui';
|
|
6
5
|
import { basename } from 'node:path';
|
|
7
|
-
const
|
|
6
|
+
export const isConfigType = (t) => typeof t === 'string' &&
|
|
7
|
+
(t === 'string' || t === 'number' || t === 'boolean');
|
|
8
|
+
const isValidValue = (v, type, multi) => {
|
|
9
|
+
if (multi) {
|
|
10
|
+
if (!Array.isArray(v))
|
|
11
|
+
return false;
|
|
12
|
+
return !v.some((v) => !isValidValue(v, type, false));
|
|
13
|
+
}
|
|
14
|
+
if (Array.isArray(v))
|
|
15
|
+
return false;
|
|
16
|
+
return typeof v === type;
|
|
17
|
+
};
|
|
18
|
+
const isValidOption = (v, vo) => !!vo &&
|
|
19
|
+
(Array.isArray(v) ? v.every(x => isValidOption(x, vo)) : vo.includes(v));
|
|
20
|
+
/**
|
|
21
|
+
* Determine whether an unknown object is a {@link ConfigOption} based only
|
|
22
|
+
* on its `type` and `multiple` property
|
|
23
|
+
*/
|
|
24
|
+
export const isConfigOptionOfType = (o, type, multi) => !!o &&
|
|
25
|
+
typeof o === 'object' &&
|
|
26
|
+
isConfigType(o.type) &&
|
|
27
|
+
o.type === type &&
|
|
28
|
+
!!o.multiple === multi;
|
|
29
|
+
/**
|
|
30
|
+
* Determine whether an unknown object is a {@link ConfigOption} based on
|
|
31
|
+
* it having all valid properties
|
|
32
|
+
*/
|
|
33
|
+
export const isConfigOption = (o, type, multi) => isConfigOptionOfType(o, type, multi) &&
|
|
34
|
+
undefOrType(o.short, 'string') &&
|
|
35
|
+
undefOrType(o.description, 'string') &&
|
|
36
|
+
undefOrType(o.hint, 'string') &&
|
|
37
|
+
undefOrType(o.validate, 'function') &&
|
|
38
|
+
(o.type === 'boolean' ?
|
|
39
|
+
o.validOptions === undefined
|
|
40
|
+
: undefOrTypeArray(o.validOptions, o.type)) &&
|
|
41
|
+
(o.default === undefined || isValidValue(o.default, type, multi));
|
|
42
|
+
const isHeading = (r) => r.type === 'heading';
|
|
43
|
+
const isDescription = (r) => r.type === 'description';
|
|
44
|
+
const width = Math.min(process?.stdout?.columns ?? 80, 80);
|
|
8
45
|
// indentation spaces from heading level
|
|
9
46
|
const indent = (n) => (n - 1) * 2;
|
|
10
|
-
const toEnvKey = (pref, key) =>
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
.replace(/ /g, '_');
|
|
16
|
-
};
|
|
47
|
+
const toEnvKey = (pref, key) => [pref, key.replace(/[^a-zA-Z0-9]+/g, ' ')]
|
|
48
|
+
.join(' ')
|
|
49
|
+
.trim()
|
|
50
|
+
.toUpperCase()
|
|
51
|
+
.replace(/ /g, '_');
|
|
17
52
|
const toEnvVal = (value, delim = '\n') => {
|
|
18
53
|
const str = typeof value === 'string' ? value
|
|
19
54
|
: typeof value === 'boolean' ?
|
|
@@ -35,254 +70,144 @@ const fromEnvVal = (env, type, multiple, delim = '\n') => (multiple ?
|
|
|
35
70
|
: type === 'string' ? env
|
|
36
71
|
: type === 'boolean' ? env === '1'
|
|
37
72
|
: +env.trim());
|
|
38
|
-
export const isConfigType = (t) => typeof t === 'string' &&
|
|
39
|
-
(t === 'string' || t === 'number' || t === 'boolean');
|
|
40
73
|
const undefOrType = (v, t) => v === undefined || typeof v === t;
|
|
41
74
|
const undefOrTypeArray = (v, t) => v === undefined || (Array.isArray(v) && v.every(x => typeof x === t));
|
|
42
|
-
const isValidOption = (v, vo) => Array.isArray(v) ? v.every(x => isValidOption(x, vo)) : vo.includes(v);
|
|
43
75
|
// print the value type, for error message reporting
|
|
44
76
|
const valueType = (v) => typeof v === 'string' ? 'string'
|
|
45
77
|
: typeof v === 'boolean' ? 'boolean'
|
|
46
78
|
: typeof v === 'number' ? 'number'
|
|
47
79
|
: Array.isArray(v) ?
|
|
48
|
-
joinTypes([...new Set(v.map(v => valueType(v)))])
|
|
80
|
+
`${joinTypes([...new Set(v.map(v => valueType(v)))])}[]`
|
|
49
81
|
: `${v.type}${v.multiple ? '[]' : ''}`;
|
|
50
82
|
const joinTypes = (types) => types.length === 1 && typeof types[0] === 'string' ?
|
|
51
83
|
types[0]
|
|
52
84
|
: `(${types.join('|')})`;
|
|
53
|
-
const
|
|
54
|
-
if (
|
|
55
|
-
if (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
: undefOrTypeArray(o.validOptions, o.type)) &&
|
|
74
|
-
(o.default === undefined || isValidValue(o.default, type, multi)) &&
|
|
75
|
-
!!o.multiple === multi;
|
|
76
|
-
function num(o = {}) {
|
|
77
|
-
const { default: def, validate: val, validOptions, ...rest } = o;
|
|
78
|
-
if (def !== undefined && !isValidValue(def, 'number', false)) {
|
|
79
|
-
throw new TypeError('invalid default value', {
|
|
80
|
-
cause: {
|
|
81
|
-
found: def,
|
|
82
|
-
wanted: 'number',
|
|
83
|
-
},
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
if (!undefOrTypeArray(validOptions, 'number')) {
|
|
87
|
-
throw new TypeError('invalid validOptions', {
|
|
88
|
-
cause: {
|
|
89
|
-
found: validOptions,
|
|
90
|
-
wanted: 'number[]',
|
|
91
|
-
},
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
const validate = val ?
|
|
95
|
-
val
|
|
96
|
-
: undefined;
|
|
97
|
-
return {
|
|
98
|
-
...rest,
|
|
99
|
-
default: def,
|
|
100
|
-
validate,
|
|
101
|
-
validOptions,
|
|
102
|
-
type: 'number',
|
|
103
|
-
multiple: false,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
function numList(o = {}) {
|
|
107
|
-
const { default: def, validate: val, validOptions, ...rest } = o;
|
|
108
|
-
if (def !== undefined && !isValidValue(def, 'number', true)) {
|
|
109
|
-
throw new TypeError('invalid default value', {
|
|
110
|
-
cause: {
|
|
111
|
-
found: def,
|
|
112
|
-
wanted: 'number[]',
|
|
113
|
-
},
|
|
114
|
-
});
|
|
85
|
+
const validateFieldMeta = (field, fieldMeta) => {
|
|
86
|
+
if (fieldMeta) {
|
|
87
|
+
if (field.type !== undefined && field.type !== fieldMeta.type) {
|
|
88
|
+
throw new TypeError(`invalid type`, {
|
|
89
|
+
cause: {
|
|
90
|
+
found: field.type,
|
|
91
|
+
wanted: [fieldMeta.type, undefined],
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (field.multiple !== undefined &&
|
|
96
|
+
!!field.multiple !== fieldMeta.multiple) {
|
|
97
|
+
throw new TypeError(`invalid multiple`, {
|
|
98
|
+
cause: {
|
|
99
|
+
found: field.multiple,
|
|
100
|
+
wanted: [fieldMeta.multiple, undefined],
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return fieldMeta;
|
|
115
105
|
}
|
|
116
|
-
if (!
|
|
117
|
-
throw new TypeError(
|
|
106
|
+
if (!isConfigType(field.type)) {
|
|
107
|
+
throw new TypeError(`invalid type`, {
|
|
118
108
|
cause: {
|
|
119
|
-
found:
|
|
120
|
-
wanted: 'number
|
|
109
|
+
found: field.type,
|
|
110
|
+
wanted: ['string', 'number', 'boolean'],
|
|
121
111
|
},
|
|
122
112
|
});
|
|
123
113
|
}
|
|
124
|
-
const validate = val ?
|
|
125
|
-
val
|
|
126
|
-
: undefined;
|
|
127
114
|
return {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
validate,
|
|
131
|
-
validOptions,
|
|
132
|
-
type: 'number',
|
|
133
|
-
multiple: true,
|
|
115
|
+
type: field.type,
|
|
116
|
+
multiple: !!field.multiple,
|
|
134
117
|
};
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
default: def,
|
|
160
|
-
validate,
|
|
161
|
-
validOptions,
|
|
162
|
-
type: 'string',
|
|
163
|
-
multiple: false,
|
|
118
|
+
};
|
|
119
|
+
const validateField = (o, type, multiple) => {
|
|
120
|
+
const validateValidOptions = (def, validOptions) => {
|
|
121
|
+
if (!undefOrTypeArray(validOptions, type)) {
|
|
122
|
+
throw new TypeError('invalid validOptions', {
|
|
123
|
+
cause: {
|
|
124
|
+
found: validOptions,
|
|
125
|
+
wanted: valueType({ type, multiple: true }),
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (def !== undefined && validOptions !== undefined) {
|
|
130
|
+
const valid = Array.isArray(def) ?
|
|
131
|
+
def.every(v => validOptions.includes(v))
|
|
132
|
+
: validOptions.includes(def);
|
|
133
|
+
if (!valid) {
|
|
134
|
+
throw new TypeError('invalid default value not in validOptions', {
|
|
135
|
+
cause: {
|
|
136
|
+
found: def,
|
|
137
|
+
wanted: validOptions,
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
164
142
|
};
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const { default: def, validate: val, validOptions, ...rest } = o;
|
|
168
|
-
if (def !== undefined && !isValidValue(def, 'string', true)) {
|
|
143
|
+
if (o.default !== undefined &&
|
|
144
|
+
!isValidValue(o.default, type, multiple)) {
|
|
169
145
|
throw new TypeError('invalid default value', {
|
|
170
146
|
cause: {
|
|
171
|
-
found:
|
|
172
|
-
wanted:
|
|
147
|
+
found: o.default,
|
|
148
|
+
wanted: valueType({ type, multiple }),
|
|
173
149
|
},
|
|
174
150
|
});
|
|
175
151
|
}
|
|
176
|
-
if (
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
found: validOptions,
|
|
180
|
-
wanted: 'string[]',
|
|
181
|
-
},
|
|
182
|
-
});
|
|
152
|
+
if (isConfigOptionOfType(o, 'number', false) ||
|
|
153
|
+
isConfigOptionOfType(o, 'number', true)) {
|
|
154
|
+
validateValidOptions(o.default, o.validOptions);
|
|
183
155
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
return {
|
|
188
|
-
...rest,
|
|
189
|
-
default: def,
|
|
190
|
-
validate,
|
|
191
|
-
validOptions,
|
|
192
|
-
type: 'string',
|
|
193
|
-
multiple: true,
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
function flag(o = {}) {
|
|
197
|
-
const { hint, default: def, validate: val, ...rest } = o;
|
|
198
|
-
delete rest.validOptions;
|
|
199
|
-
if (def !== undefined && !isValidValue(def, 'boolean', false)) {
|
|
200
|
-
throw new TypeError('invalid default value');
|
|
201
|
-
}
|
|
202
|
-
const validate = val ?
|
|
203
|
-
val
|
|
204
|
-
: undefined;
|
|
205
|
-
if (hint !== undefined) {
|
|
206
|
-
throw new TypeError('cannot provide hint for flag');
|
|
156
|
+
else if (isConfigOptionOfType(o, 'string', false) ||
|
|
157
|
+
isConfigOptionOfType(o, 'string', true)) {
|
|
158
|
+
validateValidOptions(o.default, o.validOptions);
|
|
207
159
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
function flagList(o = {}) {
|
|
217
|
-
const { hint, default: def, validate: val, ...rest } = o;
|
|
218
|
-
delete rest.validOptions;
|
|
219
|
-
if (def !== undefined && !isValidValue(def, 'boolean', true)) {
|
|
220
|
-
throw new TypeError('invalid default value');
|
|
221
|
-
}
|
|
222
|
-
const validate = val ?
|
|
223
|
-
val
|
|
224
|
-
: undefined;
|
|
225
|
-
if (hint !== undefined) {
|
|
226
|
-
throw new TypeError('cannot provide hint for flag list');
|
|
160
|
+
else if (isConfigOptionOfType(o, 'boolean', false) ||
|
|
161
|
+
isConfigOptionOfType(o, 'boolean', true)) {
|
|
162
|
+
if (o.hint !== undefined) {
|
|
163
|
+
throw new TypeError('cannot provide hint for flag');
|
|
164
|
+
}
|
|
165
|
+
if (o.validOptions !== undefined) {
|
|
166
|
+
throw new TypeError('cannot provide validOptions for flag');
|
|
167
|
+
}
|
|
227
168
|
}
|
|
228
|
-
return
|
|
229
|
-
|
|
230
|
-
default: def,
|
|
231
|
-
validate,
|
|
232
|
-
type: 'boolean',
|
|
233
|
-
multiple: true,
|
|
234
|
-
};
|
|
235
|
-
}
|
|
169
|
+
return o;
|
|
170
|
+
};
|
|
236
171
|
const toParseArgsOptionsConfig = (options) => {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
: String(config.default),
|
|
259
|
-
};
|
|
172
|
+
return Object.entries(options).reduce((acc, [longOption, o]) => {
|
|
173
|
+
const p = {
|
|
174
|
+
type: 'string',
|
|
175
|
+
multiple: !!o.multiple,
|
|
176
|
+
...(typeof o.short === 'string' ? { short: o.short } : undefined),
|
|
177
|
+
};
|
|
178
|
+
const setNoBool = () => {
|
|
179
|
+
if (!longOption.startsWith('no-') && !options[`no-${longOption}`]) {
|
|
180
|
+
acc[`no-${longOption}`] = {
|
|
181
|
+
type: 'boolean',
|
|
182
|
+
multiple: !!o.multiple,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
const setDefault = (def, fn) => {
|
|
187
|
+
if (def !== undefined) {
|
|
188
|
+
p.default = fn(def);
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
if (isConfigOption(o, 'number', false)) {
|
|
192
|
+
setDefault(o.default, String);
|
|
260
193
|
}
|
|
261
|
-
else {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
type: 'boolean',
|
|
278
|
-
multiple: config.multiple,
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
return c;
|
|
194
|
+
else if (isConfigOption(o, 'number', true)) {
|
|
195
|
+
setDefault(o.default, d => d.map(v => String(v)));
|
|
196
|
+
}
|
|
197
|
+
else if (isConfigOption(o, 'string', false) ||
|
|
198
|
+
isConfigOption(o, 'string', true)) {
|
|
199
|
+
setDefault(o.default, v => v);
|
|
200
|
+
}
|
|
201
|
+
else if (isConfigOption(o, 'boolean', false) ||
|
|
202
|
+
isConfigOption(o, 'boolean', true)) {
|
|
203
|
+
p.type = 'boolean';
|
|
204
|
+
setDefault(o.default, v => v);
|
|
205
|
+
setNoBool();
|
|
206
|
+
}
|
|
207
|
+
acc[longOption] = p;
|
|
208
|
+
return acc;
|
|
209
|
+
}, {});
|
|
283
210
|
};
|
|
284
|
-
const isHeading = (r) => r.type === 'heading';
|
|
285
|
-
const isDescription = (r) => r.type === 'description';
|
|
286
211
|
/**
|
|
287
212
|
* Class returned by the {@link jack} function and all configuration
|
|
288
213
|
* definition methods. This is what gets chained together.
|
|
@@ -320,16 +245,12 @@ export class Jack {
|
|
|
320
245
|
this.validate(values);
|
|
321
246
|
}
|
|
322
247
|
catch (er) {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
328
|
-
else {
|
|
329
|
-
e.cause = { path: source };
|
|
330
|
-
}
|
|
248
|
+
if (source && er instanceof Error) {
|
|
249
|
+
/* c8 ignore next */
|
|
250
|
+
const cause = typeof er.cause === 'object' ? er.cause : {};
|
|
251
|
+
er.cause = { ...cause, path: source };
|
|
331
252
|
}
|
|
332
|
-
throw
|
|
253
|
+
throw er;
|
|
333
254
|
}
|
|
334
255
|
for (const [field, value] of Object.entries(values)) {
|
|
335
256
|
const my = this.#configSet[field];
|
|
@@ -392,10 +313,9 @@ export class Jack {
|
|
|
392
313
|
if (args === process.argv) {
|
|
393
314
|
args = args.slice(process._eval !== undefined ? 1 : 2);
|
|
394
315
|
}
|
|
395
|
-
const options = toParseArgsOptionsConfig(this.#configSet);
|
|
396
316
|
const result = parseArgs({
|
|
397
317
|
args,
|
|
398
|
-
options,
|
|
318
|
+
options: toParseArgsOptionsConfig(this.#configSet),
|
|
399
319
|
// always strict, but using our own logic
|
|
400
320
|
strict: false,
|
|
401
321
|
allowPositionals: this.#allowPositionals,
|
|
@@ -488,13 +408,10 @@ export class Jack {
|
|
|
488
408
|
for (const [field, value] of Object.entries(p.values)) {
|
|
489
409
|
const valid = this.#configSet[field]?.validate;
|
|
490
410
|
const validOptions = this.#configSet[field]?.validOptions;
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
if (valid && !valid(value)) {
|
|
496
|
-
cause = cause || { name: field, found: value };
|
|
497
|
-
}
|
|
411
|
+
const cause = validOptions && !isValidOption(value, validOptions) ?
|
|
412
|
+
{ name: field, found: value, validOptions: validOptions }
|
|
413
|
+
: valid && !valid(value) ? { name: field, found: value }
|
|
414
|
+
: undefined;
|
|
498
415
|
if (cause) {
|
|
499
416
|
throw new Error(`Invalid value provided for --${field}: ${JSON.stringify(value)}`, { cause });
|
|
500
417
|
}
|
|
@@ -547,18 +464,11 @@ export class Jack {
|
|
|
547
464
|
},
|
|
548
465
|
});
|
|
549
466
|
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
!
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
found: value,
|
|
556
|
-
validOptions: config.validOptions,
|
|
557
|
-
};
|
|
558
|
-
}
|
|
559
|
-
if (config.validate && !config.validate(value)) {
|
|
560
|
-
cause = cause || { name: field, found: value };
|
|
561
|
-
}
|
|
467
|
+
const cause = config.validOptions && !isValidOption(value, config.validOptions) ?
|
|
468
|
+
{ name: field, found: value, validOptions: config.validOptions }
|
|
469
|
+
: config.validate && !config.validate(value) ?
|
|
470
|
+
{ name: field, found: value }
|
|
471
|
+
: undefined;
|
|
562
472
|
if (cause) {
|
|
563
473
|
throw new Error(`Invalid config value for ${field}: ${value}`, {
|
|
564
474
|
cause,
|
|
@@ -595,37 +505,37 @@ export class Jack {
|
|
|
595
505
|
* Add one or more number fields.
|
|
596
506
|
*/
|
|
597
507
|
num(fields) {
|
|
598
|
-
return this.#
|
|
508
|
+
return this.#addFieldsWith(fields, 'number', false);
|
|
599
509
|
}
|
|
600
510
|
/**
|
|
601
511
|
* Add one or more multiple number fields.
|
|
602
512
|
*/
|
|
603
513
|
numList(fields) {
|
|
604
|
-
return this.#
|
|
514
|
+
return this.#addFieldsWith(fields, 'number', true);
|
|
605
515
|
}
|
|
606
516
|
/**
|
|
607
517
|
* Add one or more string option fields.
|
|
608
518
|
*/
|
|
609
519
|
opt(fields) {
|
|
610
|
-
return this.#
|
|
520
|
+
return this.#addFieldsWith(fields, 'string', false);
|
|
611
521
|
}
|
|
612
522
|
/**
|
|
613
523
|
* Add one or more multiple string option fields.
|
|
614
524
|
*/
|
|
615
525
|
optList(fields) {
|
|
616
|
-
return this.#
|
|
526
|
+
return this.#addFieldsWith(fields, 'string', true);
|
|
617
527
|
}
|
|
618
528
|
/**
|
|
619
529
|
* Add one or more flag fields.
|
|
620
530
|
*/
|
|
621
531
|
flag(fields) {
|
|
622
|
-
return this.#
|
|
532
|
+
return this.#addFieldsWith(fields, 'boolean', false);
|
|
623
533
|
}
|
|
624
534
|
/**
|
|
625
535
|
* Add one or more multiple flag fields.
|
|
626
536
|
*/
|
|
627
537
|
flagList(fields) {
|
|
628
|
-
return this.#
|
|
538
|
+
return this.#addFieldsWith(fields, 'boolean', true);
|
|
629
539
|
}
|
|
630
540
|
/**
|
|
631
541
|
* Generic field definition method. Similar to flag/flagList/number/etc,
|
|
@@ -633,29 +543,22 @@ export class Jack {
|
|
|
633
543
|
* fields on each one, or Jack won't know how to define them.
|
|
634
544
|
*/
|
|
635
545
|
addFields(fields) {
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
});
|
|
644
|
-
}
|
|
645
|
-
Object.assign(next.#configSet, fields);
|
|
646
|
-
return next;
|
|
546
|
+
return this.#addFields(this, fields);
|
|
547
|
+
}
|
|
548
|
+
#addFieldsWith(fields, type, multiple) {
|
|
549
|
+
return this.#addFields(this, fields, {
|
|
550
|
+
type,
|
|
551
|
+
multiple,
|
|
552
|
+
});
|
|
647
553
|
}
|
|
648
|
-
#addFields(fields,
|
|
649
|
-
const next = this;
|
|
554
|
+
#addFields(next, fields, opt) {
|
|
650
555
|
Object.assign(next.#configSet, Object.fromEntries(Object.entries(fields).map(([name, field]) => {
|
|
651
556
|
this.#validateName(name, field);
|
|
652
|
-
const
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
});
|
|
658
|
-
return [name, option];
|
|
557
|
+
const { type, multiple } = validateFieldMeta(field, opt);
|
|
558
|
+
const value = { ...field, type, multiple };
|
|
559
|
+
validateField(value, type, multiple);
|
|
560
|
+
next.#fields.push({ type: 'config', name, value });
|
|
561
|
+
return [name, value];
|
|
659
562
|
})));
|
|
660
563
|
return next;
|
|
661
564
|
}
|
|
@@ -691,6 +594,7 @@ export class Jack {
|
|
|
691
594
|
if (this.#usage)
|
|
692
595
|
return this.#usage;
|
|
693
596
|
let headingLevel = 1;
|
|
597
|
+
//@ts-ignore
|
|
694
598
|
const ui = cliui({ width });
|
|
695
599
|
const first = this.#fields[0];
|
|
696
600
|
let start = first?.type === 'heading' ? 1 : 0;
|
|
@@ -932,6 +836,10 @@ export class Jack {
|
|
|
932
836
|
return `Jack ${inspect(this.toJSON(), options)}`;
|
|
933
837
|
}
|
|
934
838
|
}
|
|
839
|
+
/**
|
|
840
|
+
* Main entry point. Create and return a {@link Jack} object.
|
|
841
|
+
*/
|
|
842
|
+
export const jack = (options = {}) => new Jack(options);
|
|
935
843
|
// Unwrap and un-indent, so we can wrap description
|
|
936
844
|
// strings however makes them look nice in the code.
|
|
937
845
|
const normalize = (s, pre = false) => {
|
|
@@ -993,8 +901,4 @@ const normalizeOneLine = (s, pre = false) => {
|
|
|
993
901
|
.trim();
|
|
994
902
|
return pre ? `\`${n}\`` : n;
|
|
995
903
|
};
|
|
996
|
-
/**
|
|
997
|
-
* Main entry point. Create and return a {@link Jack} object.
|
|
998
|
-
*/
|
|
999
|
-
export const jack = (options = {}) => new Jack(options);
|
|
1000
904
|
//# sourceMappingURL=index.js.map
|