@trenskow/arguments-parser 0.3.86 → 0.3.88
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/lib/index.js +229 -213
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { basename } from 'path';
|
|
10
10
|
|
|
11
11
|
import caseit from '@trenskow/caseit';
|
|
12
|
-
import { default as isvalid,
|
|
12
|
+
import { default as isvalid, merge, keyPaths, plugins } from 'isvalid';
|
|
13
13
|
import print from '@trenskow/print';
|
|
14
14
|
|
|
15
15
|
plugins.use('argumentsParser.default', () => ({
|
|
@@ -54,7 +54,13 @@ const argumentsParser = (
|
|
|
54
54
|
help: {
|
|
55
55
|
usage: helpUsage,
|
|
56
56
|
options: helpOptions,
|
|
57
|
-
} = {}
|
|
57
|
+
} = {},
|
|
58
|
+
options = {
|
|
59
|
+
schema: {},
|
|
60
|
+
data: {},
|
|
61
|
+
validationOptions: {}
|
|
62
|
+
},
|
|
63
|
+
parameters = {}
|
|
58
64
|
} = {}
|
|
59
65
|
) => {
|
|
60
66
|
|
|
@@ -143,6 +149,32 @@ const argumentsParser = (
|
|
|
143
149
|
if (args[0] === '--help') printHelp();
|
|
144
150
|
};
|
|
145
151
|
|
|
152
|
+
const next = async (identifier, command) => {
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
|
|
156
|
+
onCommand?.(identifier, args.slice(1));
|
|
157
|
+
|
|
158
|
+
return await command({
|
|
159
|
+
args: args.slice(1),
|
|
160
|
+
argumentsParser: argumentsParser({
|
|
161
|
+
args: args.slice(1),
|
|
162
|
+
argvLevel: argvLevel + 1,
|
|
163
|
+
onCommand,
|
|
164
|
+
placeholder,
|
|
165
|
+
command: command,
|
|
166
|
+
strings,
|
|
167
|
+
options,
|
|
168
|
+
parameters
|
|
169
|
+
})
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
} catch (error) {
|
|
173
|
+
print.err(`${error.stack}`);
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
146
178
|
const result = {
|
|
147
179
|
get base() {
|
|
148
180
|
return base;
|
|
@@ -182,292 +214,276 @@ const argumentsParser = (
|
|
|
182
214
|
.replace('<command>', args[0])));
|
|
183
215
|
}
|
|
184
216
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
return await commands[tool]({
|
|
190
|
-
args: args.slice(1),
|
|
191
|
-
argumentsParser: argumentsParser({
|
|
192
|
-
args: args.slice(1),
|
|
193
|
-
argvLevel: argvLevel + 1,
|
|
194
|
-
onCommand,
|
|
195
|
-
placeholder,
|
|
196
|
-
command: commands[tool],
|
|
197
|
-
strings
|
|
198
|
-
})
|
|
199
|
-
});
|
|
217
|
+
return await next(
|
|
218
|
+
tool,
|
|
219
|
+
commands[tool]);
|
|
200
220
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
221
|
+
},
|
|
222
|
+
parameter: async (
|
|
223
|
+
identifier,
|
|
224
|
+
description,
|
|
225
|
+
schema,
|
|
226
|
+
command
|
|
227
|
+
) => {
|
|
228
|
+
|
|
229
|
+
if (typeof identifier !== 'string') {
|
|
230
|
+
throw new Error('Identifier must be a string');
|
|
204
231
|
}
|
|
205
232
|
|
|
206
|
-
|
|
207
|
-
|
|
233
|
+
helpUsage.push(`${opening}${caseit(identifier, 'kebab')}${closing}`);
|
|
234
|
+
|
|
235
|
+
helpOptions = () => {
|
|
208
236
|
|
|
209
|
-
|
|
237
|
+
print();
|
|
238
|
+
print(strings?.commands?.help?.available || 'Available commands:');
|
|
239
|
+
print();
|
|
210
240
|
|
|
211
|
-
|
|
241
|
+
list(print, {
|
|
242
|
+
[`${opening}${caseit(identifier, 'kebab')}${closing}`]: description
|
|
243
|
+
});
|
|
212
244
|
|
|
213
|
-
|
|
214
|
-
let nonOptionsIndex = args.indexOf('--');
|
|
245
|
+
};
|
|
215
246
|
|
|
216
|
-
if (
|
|
217
|
-
nonOptions = args.slice(nonOptionsIndex + 1).join(' ');
|
|
218
|
-
args = args.slice(0, nonOptionsIndex);
|
|
219
|
-
}
|
|
247
|
+
if (args.length === 0) printHelp();
|
|
220
248
|
|
|
221
|
-
|
|
222
|
-
.all()
|
|
223
|
-
.filter((keyPath) => keyPath);
|
|
249
|
+
checkHelp();
|
|
224
250
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
251
|
+
parameters[identifier] = await isvalid(
|
|
252
|
+
args[0],
|
|
253
|
+
schema);
|
|
228
254
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
255
|
+
return await next(
|
|
256
|
+
identifier,
|
|
257
|
+
command);
|
|
232
258
|
|
|
233
|
-
|
|
259
|
+
},
|
|
260
|
+
options: (schema, validationOptions = { }) => {
|
|
234
261
|
|
|
235
|
-
|
|
236
|
-
.forEach((keyPath) => {
|
|
262
|
+
validationOptions.command = validationOptions.command || command;
|
|
237
263
|
|
|
238
|
-
|
|
264
|
+
Object.assign(
|
|
265
|
+
options.validationOptions,
|
|
266
|
+
validationOptions);
|
|
239
267
|
|
|
240
|
-
|
|
268
|
+
options.schema = merge(
|
|
269
|
+
options.schema)
|
|
270
|
+
.with(schema);
|
|
241
271
|
|
|
242
|
-
|
|
243
|
-
throw new Error(`Short option "${keyPathSchema.short}" already used.`);
|
|
244
|
-
}
|
|
272
|
+
return result;
|
|
245
273
|
|
|
246
|
-
|
|
274
|
+
},
|
|
275
|
+
help(error) {
|
|
276
|
+
printHelp(error);
|
|
277
|
+
},
|
|
278
|
+
then: (...resultArguments) => {
|
|
279
|
+
return (async () => {
|
|
247
280
|
|
|
248
|
-
|
|
281
|
+
checkHelp();
|
|
249
282
|
|
|
250
|
-
|
|
283
|
+
let nonOptions;
|
|
284
|
+
let nonOptionsIndex = args.indexOf('--');
|
|
251
285
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
.
|
|
286
|
+
if (nonOptionsIndex > -1) {
|
|
287
|
+
nonOptions = args.slice(nonOptionsIndex + 1).join(' ');
|
|
288
|
+
args = args.slice(0, nonOptionsIndex);
|
|
289
|
+
}
|
|
255
290
|
|
|
256
|
-
|
|
291
|
+
const allKeyPaths = keyPaths(options.schema)
|
|
292
|
+
.all()
|
|
293
|
+
.filter((keyPath) => keyPath);
|
|
257
294
|
|
|
258
|
-
|
|
295
|
+
if (allKeyPaths.length) {
|
|
296
|
+
helpUsage.push(`${opening}${strings?.options?.help?.placeholder || 'options'}${closing}`);
|
|
297
|
+
}
|
|
259
298
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
299
|
+
if (typeof options.validationOptions.usage === 'string') {
|
|
300
|
+
helpUsage.push(options.validationOptions.usage);
|
|
301
|
+
}
|
|
263
302
|
|
|
264
|
-
|
|
265
|
-
.map((keyPath) => {
|
|
303
|
+
let shortOptions = {};
|
|
266
304
|
|
|
267
|
-
|
|
305
|
+
allKeyPaths
|
|
306
|
+
.forEach((keyPath) => {
|
|
268
307
|
|
|
269
|
-
|
|
270
|
-
let description = [keyPathSchema.description || 'No description'];
|
|
308
|
+
const keyPathSchema = keyPaths(options.schema).get(keyPath);
|
|
271
309
|
|
|
272
|
-
|
|
273
|
-
optionKeys.push(`-${shortOptions[keyPath]}`);
|
|
274
|
-
}
|
|
310
|
+
if (keyPathSchema.short) {
|
|
275
311
|
|
|
276
|
-
if (
|
|
277
|
-
|
|
312
|
+
if (shortOptions[keyPathSchema.short]) {
|
|
313
|
+
throw new Error(`Short option "${keyPathSchema.short}" already used.`);
|
|
278
314
|
}
|
|
279
315
|
|
|
280
|
-
|
|
281
|
-
description.push(`${strings?.options?.help?.allowsMultiple || '(allows multiple)'}`);
|
|
282
|
-
} else if (keyPathSchema.required === true) {
|
|
283
|
-
description.push(`${strings?.options?.help?.required || '(required)'}`);
|
|
284
|
-
} else if (typeof keyPathSchema.default !== 'undefined') {
|
|
285
|
-
|
|
286
|
-
let defaultDescription;
|
|
316
|
+
shortOptions[keyPath] = keyPathSchema.short;
|
|
287
317
|
|
|
288
|
-
|
|
289
|
-
defaultDescription = '`********`';
|
|
290
|
-
} else {
|
|
318
|
+
}
|
|
291
319
|
|
|
292
|
-
|
|
293
|
-
defaultDescription = keyPathSchema.default === true ? 'enabled' : 'disabled';
|
|
294
|
-
} else {
|
|
295
|
-
defaultDescription = `\`${keyPathSchema.defaultDescription ?? keyPathSchema.default}\``;
|
|
296
|
-
}
|
|
320
|
+
});
|
|
297
321
|
|
|
298
|
-
|
|
322
|
+
shortOptions = Object.fromEntries(
|
|
323
|
+
Object.entries(shortOptions)
|
|
324
|
+
.map(([key, value]) => [value, key]));
|
|
299
325
|
|
|
300
|
-
|
|
301
|
-
.replace('<default>', defaultDescription)}`);
|
|
326
|
+
if (allKeyPaths.length) {
|
|
302
327
|
|
|
303
|
-
|
|
328
|
+
helpOptions = () => {
|
|
304
329
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
330
|
+
print();
|
|
331
|
+
print(strings?.options?.help?.title || 'Options:');
|
|
332
|
+
print();
|
|
308
333
|
|
|
309
|
-
|
|
334
|
+
list(print, Object.fromEntries(allKeyPaths
|
|
335
|
+
.map((keyPath) => {
|
|
310
336
|
|
|
311
|
-
|
|
312
|
-
option += ` ${strings?.options?.help?.argument || `${opening}${caseit(keyPath, 'kebab')}${closing}`}`;
|
|
313
|
-
}
|
|
337
|
+
const keyPathSchema = keyPaths(options.schema).get(keyPath);
|
|
314
338
|
|
|
315
|
-
|
|
339
|
+
let optionKeys = [`--${caseit(keyPath, 'kebab')}`];
|
|
340
|
+
let description = [keyPathSchema.description || 'No description'];
|
|
316
341
|
|
|
317
|
-
|
|
342
|
+
if (shortOptions[keyPath]) {
|
|
343
|
+
optionKeys.push(`-${shortOptions[keyPath]}`);
|
|
344
|
+
}
|
|
318
345
|
|
|
319
|
-
|
|
320
|
-
|
|
346
|
+
if (typeof keyPathSchema.enum !== 'undefined') {
|
|
347
|
+
description.push(`(${opening}${keyPath}${closing}: ${Object.keys(keyPathSchema.enum).map((value) => `\`${value}\``).join(', ')})`);
|
|
348
|
+
}
|
|
321
349
|
|
|
322
|
-
|
|
350
|
+
if (keyPathSchema.type === Array) {
|
|
351
|
+
description.push(`${strings?.options?.help?.allowsMultiple || '(allows multiple)'}`);
|
|
352
|
+
} else if (keyPathSchema.required === true) {
|
|
353
|
+
description.push(`${strings?.options?.help?.required || '(required)'}`);
|
|
354
|
+
} else if (typeof keyPathSchema.default !== 'undefined') {
|
|
323
355
|
|
|
324
|
-
|
|
325
|
-
let rest = [];
|
|
356
|
+
let defaultDescription;
|
|
326
357
|
|
|
327
|
-
|
|
358
|
+
if (keyPathSchema.secret === true) {
|
|
359
|
+
defaultDescription = '`********`';
|
|
360
|
+
} else {
|
|
328
361
|
|
|
329
|
-
|
|
362
|
+
if (keyPathSchema.type === Boolean) {
|
|
363
|
+
defaultDescription = keyPathSchema.default === true ? 'enabled' : 'disabled';
|
|
364
|
+
} else {
|
|
365
|
+
defaultDescription = `\`${keyPathSchema.defaultDescription ?? keyPathSchema.default}\``;
|
|
366
|
+
}
|
|
330
367
|
|
|
331
|
-
|
|
332
|
-
rest.push(args[idx]);
|
|
333
|
-
continue;
|
|
334
|
-
}
|
|
368
|
+
}
|
|
335
369
|
|
|
336
|
-
|
|
370
|
+
description.push(`${(strings?.options?.help?.default || '(default: <default>)')
|
|
371
|
+
.replace('<default>', defaultDescription)}`);
|
|
337
372
|
|
|
338
|
-
|
|
339
|
-
key = caseit(args[idx].slice(2));
|
|
340
|
-
} else if (shortOptions[key]) {
|
|
341
|
-
key = caseit(shortOptions[key]);
|
|
342
|
-
}
|
|
373
|
+
}
|
|
343
374
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
(strings?.options?.help?.errors?.unknownOption || 'Unknown option: <option>.')
|
|
348
|
-
.replace('<option>', args[idx])));
|
|
349
|
-
}
|
|
375
|
+
if (keyPathSchema.hints?.length) {
|
|
376
|
+
description = description.concat(keyPathSchema.hints);
|
|
377
|
+
}
|
|
350
378
|
|
|
351
|
-
|
|
379
|
+
let option = optionKeys.reverse().join(', ');
|
|
352
380
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
if (args.length <= idx + 1 || args[idx + 1].slice(0, 2) === '--') {
|
|
357
|
-
printHelp(
|
|
358
|
-
new Error(
|
|
359
|
-
(strings?.options?.help?.errors?.missingArgument || 'Argument missing for option: <option>.')
|
|
360
|
-
.replace('<option>', args[idx])));
|
|
361
|
-
}
|
|
362
|
-
value = args[++idx];
|
|
363
|
-
}
|
|
381
|
+
if (keyPathSchema.type !== Boolean) {
|
|
382
|
+
option += ` ${strings?.options?.help?.argument || `${opening}${caseit(keyPath, 'kebab')}${closing}`}`;
|
|
383
|
+
}
|
|
364
384
|
|
|
365
|
-
|
|
366
|
-
data[key] = value;
|
|
367
|
-
} else if (Array.isArray(data[key])) {
|
|
368
|
-
data[key].push(value);
|
|
369
|
-
} else {
|
|
370
|
-
data[key] = [data[key], value];
|
|
371
|
-
}
|
|
385
|
+
return [option, description];
|
|
372
386
|
|
|
373
|
-
|
|
387
|
+
})), true);
|
|
374
388
|
|
|
375
|
-
|
|
376
|
-
switch (options.variadic || 'deny') {
|
|
377
|
-
case 'allow':
|
|
378
|
-
break;
|
|
379
|
-
case 'ignore':
|
|
380
|
-
rest = [];
|
|
381
|
-
break;
|
|
382
|
-
default:
|
|
383
|
-
printHelp(
|
|
384
|
-
new Error(
|
|
385
|
-
(strings?.empty?.help?.errors?.unexpected || 'Unexpected argument: <argument>.')
|
|
386
|
-
.replace('<argument>', args[0])));
|
|
389
|
+
};
|
|
387
390
|
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
try {
|
|
391
|
-
data = await isvalid(data, schema, {
|
|
392
|
-
aggregatedErrors: 'flatten'
|
|
393
|
-
});
|
|
394
|
-
} catch (error) {
|
|
395
|
-
printHelp(error);
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
return Object.assign({}, data, {
|
|
399
|
-
onError: (error) => {
|
|
400
|
-
print.err(error.message);
|
|
401
|
-
process.exit(1);
|
|
402
|
-
},
|
|
403
|
-
rest,
|
|
404
|
-
nonOptions
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
},
|
|
408
|
-
empty: async () => {
|
|
409
391
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
if (args.length > 0) {
|
|
413
|
-
printHelp(
|
|
414
|
-
new Error(
|
|
415
|
-
(strings?.empty?.help?.errors?.unexpected || 'Unexpected argument: <argument>.')
|
|
416
|
-
.replace('<argument>', args[0])));
|
|
417
|
-
}
|
|
392
|
+
let rest = [];
|
|
418
393
|
|
|
419
|
-
|
|
420
|
-
values: async (schema) => {
|
|
394
|
+
let idx;
|
|
421
395
|
|
|
422
|
-
|
|
396
|
+
for (idx = 0 ; idx < args.length ; idx++) {
|
|
423
397
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
398
|
+
if (args[idx].slice(0, 1) !== '-') {
|
|
399
|
+
rest.push(args[idx]);
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
427
402
|
|
|
428
|
-
|
|
403
|
+
let key = args[idx].slice(1);
|
|
429
404
|
|
|
430
|
-
|
|
431
|
-
|
|
405
|
+
if (args[idx].slice(1, 2) === '-') {
|
|
406
|
+
key = caseit(args[idx].slice(2));
|
|
407
|
+
} else if (shortOptions[key]) {
|
|
408
|
+
key = caseit(shortOptions[key]);
|
|
409
|
+
}
|
|
432
410
|
|
|
433
|
-
|
|
411
|
+
if (!keyPaths(options.schema).all().includes(key)) {
|
|
412
|
+
printHelp(
|
|
413
|
+
new Error(
|
|
414
|
+
(strings?.options?.help?.errors?.unknownOption || 'Unknown option: <option>.')
|
|
415
|
+
.replace('<option>', args[idx])));
|
|
416
|
+
}
|
|
434
417
|
|
|
435
|
-
|
|
436
|
-
.forEach((keyPath, idx) => {
|
|
418
|
+
let value;
|
|
437
419
|
|
|
438
|
-
|
|
420
|
+
if (keyPaths(options.schema).get(key).type === Boolean) {
|
|
421
|
+
value = true;
|
|
422
|
+
} else {
|
|
423
|
+
if (args.length <= idx + 1 || args[idx + 1].slice(0, 2) === '--') {
|
|
424
|
+
printHelp(
|
|
425
|
+
new Error(
|
|
426
|
+
(strings?.options?.help?.errors?.missingArgument || 'Argument missing for option: <option>.')
|
|
427
|
+
.replace('<option>', args[idx])));
|
|
428
|
+
}
|
|
429
|
+
value = args[++idx];
|
|
430
|
+
}
|
|
439
431
|
|
|
440
|
-
if (
|
|
441
|
-
|
|
432
|
+
if (typeof options.data[key] === 'undefined') {
|
|
433
|
+
options.data[key] = value;
|
|
434
|
+
} else if (Array.isArray(options.data[key])) {
|
|
435
|
+
options.data[key].push(value);
|
|
436
|
+
} else {
|
|
437
|
+
options.data[key] = [options.data[key], value];
|
|
442
438
|
}
|
|
443
439
|
|
|
444
|
-
|
|
445
|
-
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if (rest.length) {
|
|
443
|
+
switch (options.validationOptions.variadic || 'deny') {
|
|
444
|
+
case 'allow':
|
|
445
|
+
break;
|
|
446
|
+
case 'ignore':
|
|
447
|
+
rest = [];
|
|
448
|
+
break;
|
|
449
|
+
default:
|
|
450
|
+
printHelp(
|
|
451
|
+
new Error(
|
|
452
|
+
(strings?.empty?.help?.errors?.unexpected || 'Unexpected argument: <argument>.')
|
|
453
|
+
.replace('<argument>', args[0])));
|
|
446
454
|
}
|
|
455
|
+
}
|
|
447
456
|
|
|
448
|
-
|
|
457
|
+
if (args.length > 0) {
|
|
458
|
+
printHelp(
|
|
459
|
+
new Error(
|
|
460
|
+
(strings?.empty?.help?.errors?.unexpected || 'Unexpected argument: <argument>.')
|
|
461
|
+
.replace('<argument>', args[0])));
|
|
462
|
+
}
|
|
449
463
|
|
|
450
|
-
}
|
|
464
|
+
let data = {};
|
|
451
465
|
|
|
452
|
-
|
|
466
|
+
try {
|
|
467
|
+
data = await isvalid(options.data, options.schema, {
|
|
468
|
+
aggregatedErrors: 'flatten'
|
|
469
|
+
});
|
|
470
|
+
} catch (error) {
|
|
471
|
+
printHelp(error);
|
|
472
|
+
}
|
|
453
473
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
474
|
+
return Object.assign({}, parameters, data, {
|
|
475
|
+
onError: (error) => {
|
|
476
|
+
print.err(error.message);
|
|
477
|
+
process.exit(1);
|
|
478
|
+
},
|
|
479
|
+
rest,
|
|
480
|
+
nonOptions
|
|
481
|
+
});
|
|
460
482
|
|
|
461
|
-
|
|
462
|
-
help(error) {
|
|
463
|
-
printHelp(error);
|
|
483
|
+
})().then(...resultArguments);
|
|
464
484
|
}
|
|
465
485
|
};
|
|
466
486
|
|
|
467
|
-
result.then = (...args) => {
|
|
468
|
-
return result.empty().then(...args);
|
|
469
|
-
};
|
|
470
|
-
|
|
471
487
|
return result;
|
|
472
488
|
|
|
473
489
|
};
|