jackspeak 2.3.5 → 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/dist/commonjs/index.d.ts.map +1 -1
- package/dist/commonjs/index.js +92 -83
- package/dist/commonjs/index.js.map +1 -1
- package/dist/commonjs/package.json +3 -1
- package/dist/commonjs/parse-args-cjs.cjs.map +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +92 -83
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/package.json +3 -1
- package/dist/esm/parse-args.js.map +1 -1
- package/package.json +14 -10
- package/dist/commonjs/parse-args.d.ts.map +0 -1
- package/dist/commonjs/parse-args.js.map +0 -1
package/dist/esm/index.js
CHANGED
|
@@ -15,50 +15,38 @@ const toEnvKey = (pref, key) => {
|
|
|
15
15
|
.replace(/ /g, '_');
|
|
16
16
|
};
|
|
17
17
|
const toEnvVal = (value, delim = '\n') => {
|
|
18
|
-
const str = typeof value === 'string'
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
? value
|
|
22
|
-
? '1'
|
|
18
|
+
const str = typeof value === 'string' ? value
|
|
19
|
+
: typeof value === 'boolean' ?
|
|
20
|
+
value ? '1'
|
|
23
21
|
: '0'
|
|
24
|
-
: typeof value === 'number'
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
.map((v) => toEnvVal(v))
|
|
29
|
-
.join(delim)
|
|
30
|
-
: /* c8 ignore start */
|
|
31
|
-
undefined;
|
|
22
|
+
: typeof value === 'number' ? String(value)
|
|
23
|
+
: Array.isArray(value) ?
|
|
24
|
+
value.map((v) => toEnvVal(v)).join(delim)
|
|
25
|
+
: /* c8 ignore start */ undefined;
|
|
32
26
|
if (typeof str !== 'string') {
|
|
33
27
|
throw new Error(`could not serialize value to environment: ${JSON.stringify(value)}`);
|
|
34
28
|
}
|
|
35
29
|
/* c8 ignore stop */
|
|
36
30
|
return str;
|
|
37
31
|
};
|
|
38
|
-
const fromEnvVal = (env, type, multiple, delim = '\n') => (multiple
|
|
39
|
-
? env
|
|
40
|
-
? env.split(delim).map(v => fromEnvVal(v, type, false))
|
|
32
|
+
const fromEnvVal = (env, type, multiple, delim = '\n') => (multiple ?
|
|
33
|
+
env ? env.split(delim).map(v => fromEnvVal(v, type, false))
|
|
41
34
|
: []
|
|
42
|
-
: type === 'string'
|
|
43
|
-
? env
|
|
44
|
-
: type === 'boolean'
|
|
45
|
-
? env === '1'
|
|
35
|
+
: type === 'string' ? env
|
|
36
|
+
: type === 'boolean' ? env === '1'
|
|
46
37
|
: +env.trim());
|
|
47
38
|
export const isConfigType = (t) => typeof t === 'string' &&
|
|
48
39
|
(t === 'string' || t === 'number' || t === 'boolean');
|
|
49
40
|
const undefOrType = (v, t) => v === undefined || typeof v === t;
|
|
50
41
|
// print the value type, for error message reporting
|
|
51
|
-
const valueType = (v) => typeof v === 'string'
|
|
52
|
-
? '
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
? 'number'
|
|
57
|
-
: Array.isArray(v)
|
|
58
|
-
? joinTypes([...new Set(v.map(v => valueType(v)))]) + '[]'
|
|
42
|
+
const valueType = (v) => typeof v === 'string' ? 'string'
|
|
43
|
+
: typeof v === 'boolean' ? 'boolean'
|
|
44
|
+
: typeof v === 'number' ? 'number'
|
|
45
|
+
: Array.isArray(v) ?
|
|
46
|
+
joinTypes([...new Set(v.map(v => valueType(v)))]) + '[]'
|
|
59
47
|
: `${v.type}${v.multiple ? '[]' : ''}`;
|
|
60
|
-
const joinTypes = (types) => types.length === 1 && typeof types[0] === 'string'
|
|
61
|
-
|
|
48
|
+
const joinTypes = (types) => types.length === 1 && typeof types[0] === 'string' ?
|
|
49
|
+
types[0]
|
|
62
50
|
: `(${types.join('|')})`;
|
|
63
51
|
const isValidValue = (v, type, multi) => {
|
|
64
52
|
if (multi) {
|
|
@@ -85,9 +73,7 @@ function num(o = {}) {
|
|
|
85
73
|
if (def !== undefined && !isValidValue(def, 'number', false)) {
|
|
86
74
|
throw new TypeError('invalid default value');
|
|
87
75
|
}
|
|
88
|
-
const validate = val
|
|
89
|
-
? val
|
|
90
|
-
: undefined;
|
|
76
|
+
const validate = val ? val : undefined;
|
|
91
77
|
return {
|
|
92
78
|
...rest,
|
|
93
79
|
default: def,
|
|
@@ -101,9 +87,7 @@ function numList(o = {}) {
|
|
|
101
87
|
if (def !== undefined && !isValidValue(def, 'number', true)) {
|
|
102
88
|
throw new TypeError('invalid default value');
|
|
103
89
|
}
|
|
104
|
-
const validate = val
|
|
105
|
-
? val
|
|
106
|
-
: undefined;
|
|
90
|
+
const validate = val ? val : undefined;
|
|
107
91
|
return {
|
|
108
92
|
...rest,
|
|
109
93
|
default: def,
|
|
@@ -117,9 +101,7 @@ function opt(o = {}) {
|
|
|
117
101
|
if (def !== undefined && !isValidValue(def, 'string', false)) {
|
|
118
102
|
throw new TypeError('invalid default value');
|
|
119
103
|
}
|
|
120
|
-
const validate = val
|
|
121
|
-
? val
|
|
122
|
-
: undefined;
|
|
104
|
+
const validate = val ? val : undefined;
|
|
123
105
|
return {
|
|
124
106
|
...rest,
|
|
125
107
|
default: def,
|
|
@@ -133,9 +115,7 @@ function optList(o = {}) {
|
|
|
133
115
|
if (def !== undefined && !isValidValue(def, 'string', true)) {
|
|
134
116
|
throw new TypeError('invalid default value');
|
|
135
117
|
}
|
|
136
|
-
const validate = val
|
|
137
|
-
? val
|
|
138
|
-
: undefined;
|
|
118
|
+
const validate = val ? val : undefined;
|
|
139
119
|
return {
|
|
140
120
|
...rest,
|
|
141
121
|
default: def,
|
|
@@ -149,8 +129,8 @@ function flag(o = {}) {
|
|
|
149
129
|
if (def !== undefined && !isValidValue(def, 'boolean', false)) {
|
|
150
130
|
throw new TypeError('invalid default value');
|
|
151
131
|
}
|
|
152
|
-
const validate = val
|
|
153
|
-
|
|
132
|
+
const validate = val ?
|
|
133
|
+
val
|
|
154
134
|
: undefined;
|
|
155
135
|
if (hint !== undefined) {
|
|
156
136
|
throw new TypeError('cannot provide hint for flag');
|
|
@@ -168,9 +148,7 @@ function flagList(o = {}) {
|
|
|
168
148
|
if (def !== undefined && !isValidValue(def, 'boolean', true)) {
|
|
169
149
|
throw new TypeError('invalid default value');
|
|
170
150
|
}
|
|
171
|
-
const validate = val
|
|
172
|
-
? val
|
|
173
|
-
: undefined;
|
|
151
|
+
const validate = val ? val : undefined;
|
|
174
152
|
if (hint !== undefined) {
|
|
175
153
|
throw new TypeError('cannot provide hint for flag list');
|
|
176
154
|
}
|
|
@@ -202,8 +180,8 @@ const toParseArgsOptionsConfig = (options) => {
|
|
|
202
180
|
c[longOption] = {
|
|
203
181
|
type: 'string',
|
|
204
182
|
multiple: false,
|
|
205
|
-
default: config.default === undefined
|
|
206
|
-
|
|
183
|
+
default: config.default === undefined ?
|
|
184
|
+
undefined
|
|
207
185
|
: String(config.default),
|
|
208
186
|
};
|
|
209
187
|
}
|
|
@@ -269,14 +247,25 @@ export class Jack {
|
|
|
269
247
|
this.validate(values);
|
|
270
248
|
}
|
|
271
249
|
catch (er) {
|
|
272
|
-
|
|
250
|
+
const e = er;
|
|
251
|
+
if (source && e && typeof e === 'object') {
|
|
252
|
+
if (e.cause && typeof e.cause === 'object') {
|
|
253
|
+
Object.assign(e.cause, { path: source });
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
e.cause = { path: source };
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
throw e;
|
|
273
260
|
}
|
|
274
261
|
for (const [field, value] of Object.entries(values)) {
|
|
275
262
|
const my = this.#configSet[field];
|
|
276
263
|
// already validated, just for TS's benefit
|
|
277
264
|
/* c8 ignore start */
|
|
278
265
|
if (!my) {
|
|
279
|
-
throw new Error('unexpected field in config set: ' + field
|
|
266
|
+
throw new Error('unexpected field in config set: ' + field, {
|
|
267
|
+
cause: { found: field },
|
|
268
|
+
});
|
|
280
269
|
}
|
|
281
270
|
/* c8 ignore stop */
|
|
282
271
|
my.default = value;
|
|
@@ -347,18 +336,27 @@ export class Jack {
|
|
|
347
336
|
throw new Error(`Unknown option '${token.rawName}'. ` +
|
|
348
337
|
`To specify a positional argument starting with a '-', ` +
|
|
349
338
|
`place it at the end of the command after '--', as in ` +
|
|
350
|
-
`'-- ${token.rawName}'
|
|
339
|
+
`'-- ${token.rawName}'`, {
|
|
340
|
+
cause: {
|
|
341
|
+
found: token.rawName + (token.value ? `=${token.value}` : ''),
|
|
342
|
+
},
|
|
343
|
+
});
|
|
351
344
|
}
|
|
352
345
|
if (value === undefined) {
|
|
353
346
|
if (token.value === undefined) {
|
|
354
347
|
if (my.type !== 'boolean') {
|
|
355
|
-
throw new Error(`No value provided for ${token.rawName}, expected ${my.type}
|
|
348
|
+
throw new Error(`No value provided for ${token.rawName}, expected ${my.type}`, {
|
|
349
|
+
cause: {
|
|
350
|
+
name: token.rawName,
|
|
351
|
+
wanted: valueType(my),
|
|
352
|
+
},
|
|
353
|
+
});
|
|
356
354
|
}
|
|
357
355
|
value = true;
|
|
358
356
|
}
|
|
359
357
|
else {
|
|
360
358
|
if (my.type === 'boolean') {
|
|
361
|
-
throw new Error(`Flag ${token.rawName} does not take a value, received '${token.value}'
|
|
359
|
+
throw new Error(`Flag ${token.rawName} does not take a value, received '${token.value}'`, { cause: { found: token } });
|
|
362
360
|
}
|
|
363
361
|
if (my.type === 'string') {
|
|
364
362
|
value = token.value;
|
|
@@ -367,7 +365,13 @@ export class Jack {
|
|
|
367
365
|
value = +token.value;
|
|
368
366
|
if (value !== value) {
|
|
369
367
|
throw new Error(`Invalid value '${token.value}' provided for ` +
|
|
370
|
-
`'${token.rawName}' option, expected number
|
|
368
|
+
`'${token.rawName}' option, expected number`, {
|
|
369
|
+
cause: {
|
|
370
|
+
name: token.rawName,
|
|
371
|
+
found: token.value,
|
|
372
|
+
wanted: 'number',
|
|
373
|
+
},
|
|
374
|
+
});
|
|
371
375
|
}
|
|
372
376
|
}
|
|
373
377
|
}
|
|
@@ -393,7 +397,7 @@ export class Jack {
|
|
|
393
397
|
for (const [field, value] of Object.entries(p.values)) {
|
|
394
398
|
const valid = this.#configSet[field]?.validate;
|
|
395
399
|
if (valid && !valid(value)) {
|
|
396
|
-
throw new Error(`Invalid value provided for --${field}: ${JSON.stringify(value)}
|
|
400
|
+
throw new Error(`Invalid value provided for --${field}: ${JSON.stringify(value)}`, { cause: { name: field, found: value } });
|
|
397
401
|
}
|
|
398
402
|
}
|
|
399
403
|
this.#writeEnv(p);
|
|
@@ -410,7 +414,7 @@ export class Jack {
|
|
|
410
414
|
// recurse so we get the core config key we care about.
|
|
411
415
|
this.#noNoFields(yes, val, s);
|
|
412
416
|
if (this.#configSet[yes]?.type === 'boolean') {
|
|
413
|
-
throw new Error(`do not set '${s}', instead set '${yes}' as desired
|
|
417
|
+
throw new Error(`do not set '${s}', instead set '${yes}' as desired.`, { cause: { found: s, wanted: yes } });
|
|
414
418
|
}
|
|
415
419
|
}
|
|
416
420
|
/**
|
|
@@ -419,22 +423,31 @@ export class Jack {
|
|
|
419
423
|
*/
|
|
420
424
|
validate(o) {
|
|
421
425
|
if (!o || typeof o !== 'object') {
|
|
422
|
-
throw new Error('Invalid config: not an object'
|
|
426
|
+
throw new Error('Invalid config: not an object', {
|
|
427
|
+
cause: { found: o },
|
|
428
|
+
});
|
|
423
429
|
}
|
|
424
430
|
for (const field in o) {
|
|
425
431
|
this.#noNoFields(field, o[field]);
|
|
426
432
|
const config = this.#configSet[field];
|
|
427
433
|
if (!config) {
|
|
428
|
-
throw new Error(`Unknown config option: ${field}
|
|
434
|
+
throw new Error(`Unknown config option: ${field}`, {
|
|
435
|
+
cause: { found: field },
|
|
436
|
+
});
|
|
429
437
|
}
|
|
430
438
|
if (!isValidValue(o[field], config.type, !!config.multiple)) {
|
|
431
|
-
throw
|
|
432
|
-
|
|
433
|
-
|
|
439
|
+
throw new Error(`Invalid value ${valueType(o[field])} for ${field}, expected ${valueType(config)}`, {
|
|
440
|
+
cause: {
|
|
441
|
+
name: field,
|
|
442
|
+
found: o[field],
|
|
443
|
+
wanted: valueType(config),
|
|
444
|
+
},
|
|
434
445
|
});
|
|
435
446
|
}
|
|
436
447
|
if (config.validate && !config.validate(o[field])) {
|
|
437
|
-
throw new Error(`Invalid config value for ${field}: ${o[field]}
|
|
448
|
+
throw new Error(`Invalid config value for ${field}: ${o[field]}`, {
|
|
449
|
+
cause: { name: field, found: o[field] },
|
|
450
|
+
});
|
|
438
451
|
}
|
|
439
452
|
}
|
|
440
453
|
}
|
|
@@ -748,18 +761,14 @@ export class Jack {
|
|
|
748
761
|
const dmDelim = mult && (desc.includes('\n') ? '\n\n' : '\n');
|
|
749
762
|
const text = normalize(desc + dmDelim + mult);
|
|
750
763
|
const hint = value.hint ||
|
|
751
|
-
(value.type === 'number'
|
|
752
|
-
|
|
753
|
-
: value.type === 'string'
|
|
754
|
-
? field.name
|
|
764
|
+
(value.type === 'number' ? 'n'
|
|
765
|
+
: value.type === 'string' ? field.name
|
|
755
766
|
: undefined);
|
|
756
|
-
const short = !value.short
|
|
757
|
-
|
|
758
|
-
: value.type === 'boolean'
|
|
759
|
-
? `-${value.short} `
|
|
767
|
+
const short = !value.short ? ''
|
|
768
|
+
: value.type === 'boolean' ? `-${value.short} `
|
|
760
769
|
: `-${value.short}<${hint}> `;
|
|
761
|
-
const left = value.type === 'boolean'
|
|
762
|
-
|
|
770
|
+
const left = value.type === 'boolean' ?
|
|
771
|
+
`${short}--${field.name}`
|
|
763
772
|
: `${short}--${field.name}=<${hint}>`;
|
|
764
773
|
const row = { text, left, type: 'config' };
|
|
765
774
|
if (text.length > width - maxMax) {
|
|
@@ -787,8 +796,8 @@ export class Jack {
|
|
|
787
796
|
...(def.multiple ? { multiple: true } : {}),
|
|
788
797
|
...(def.delim ? { delim: def.delim } : {}),
|
|
789
798
|
...(def.short ? { short: def.short } : {}),
|
|
790
|
-
...(def.description
|
|
791
|
-
|
|
799
|
+
...(def.description ?
|
|
800
|
+
{ description: normalize(def.description) }
|
|
792
801
|
: {}),
|
|
793
802
|
...(def.validate ? { validate: def.validate } : {}),
|
|
794
803
|
...(def.default !== undefined ? { default: def.default } : {}),
|
|
@@ -804,12 +813,12 @@ export class Jack {
|
|
|
804
813
|
}
|
|
805
814
|
// Unwrap and un-indent, so we can wrap description
|
|
806
815
|
// strings however makes them look nice in the code.
|
|
807
|
-
const normalize = (s, pre = false) => pre
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
816
|
+
const normalize = (s, pre = false) => pre ?
|
|
817
|
+
// prepend a ZWSP to each line so cliui doesn't strip it.
|
|
818
|
+
s
|
|
819
|
+
.split('\n')
|
|
820
|
+
.map(l => `\u200b${l}`)
|
|
821
|
+
.join('\n')
|
|
813
822
|
: s
|
|
814
823
|
// remove single line breaks, except for lists
|
|
815
824
|
.replace(/([^\n])\n[ \t]*([^\n])/g, (_, $1, $2) => !/^[-*]/.test($2) ? `${$1} ${$2}` : `${$1}\n${$2}`)
|
|
@@ -823,8 +832,8 @@ const normalize = (s, pre = false) => pre
|
|
|
823
832
|
// normalize for markdown printing, remove leading spaces on lines
|
|
824
833
|
const normalizeMarkdown = (s, pre = false) => {
|
|
825
834
|
const n = normalize(s, pre).replace(/\\/g, '\\\\');
|
|
826
|
-
return pre
|
|
827
|
-
|
|
835
|
+
return pre ?
|
|
836
|
+
`\`\`\`\n${n.replace(/\u200b/g, '')}\n\`\`\``
|
|
828
837
|
: n.replace(/\n +/g, '\n').trim();
|
|
829
838
|
};
|
|
830
839
|
const normalizeOneLine = (s, pre = false) => {
|