@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.
Files changed (2) hide show
  1. package/lib/index.js +229 -213
  2. 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, keyPaths, formalize, plugins } from '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
- try {
186
-
187
- onCommand?.(tool, args.slice(1));
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
- } catch (error) {
202
- print.err(`${error.stack}`);
203
- process.exit(1);
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
- options: async (schema, options = { }) => {
233
+ helpUsage.push(`${opening}${caseit(identifier, 'kebab')}${closing}`);
234
+
235
+ helpOptions = () => {
208
236
 
209
- options.command = options.command || command;
237
+ print();
238
+ print(strings?.commands?.help?.available || 'Available commands:');
239
+ print();
210
240
 
211
- schema = formalize(schema);
241
+ list(print, {
242
+ [`${opening}${caseit(identifier, 'kebab')}${closing}`]: description
243
+ });
212
244
 
213
- let nonOptions;
214
- let nonOptionsIndex = args.indexOf('--');
245
+ };
215
246
 
216
- if (nonOptionsIndex > -1) {
217
- nonOptions = args.slice(nonOptionsIndex + 1).join(' ');
218
- args = args.slice(0, nonOptionsIndex);
219
- }
247
+ if (args.length === 0) printHelp();
220
248
 
221
- const allKeyPaths = keyPaths(schema)
222
- .all()
223
- .filter((keyPath) => keyPath);
249
+ checkHelp();
224
250
 
225
- if (allKeyPaths.length) {
226
- helpUsage.push(`${opening}${strings?.options?.help?.placeholder || 'options'}${closing}`);
227
- }
251
+ parameters[identifier] = await isvalid(
252
+ args[0],
253
+ schema);
228
254
 
229
- if (typeof options.usage === 'string') {
230
- helpUsage.push(options.usage);
231
- }
255
+ return await next(
256
+ identifier,
257
+ command);
232
258
 
233
- let shortOptions = {};
259
+ },
260
+ options: (schema, validationOptions = { }) => {
234
261
 
235
- allKeyPaths
236
- .forEach((keyPath) => {
262
+ validationOptions.command = validationOptions.command || command;
237
263
 
238
- const keyPathSchema = keyPaths(schema).get(keyPath);
264
+ Object.assign(
265
+ options.validationOptions,
266
+ validationOptions);
239
267
 
240
- if (keyPathSchema.short) {
268
+ options.schema = merge(
269
+ options.schema)
270
+ .with(schema);
241
271
 
242
- if (shortOptions[keyPathSchema.short]) {
243
- throw new Error(`Short option "${keyPathSchema.short}" already used.`);
244
- }
272
+ return result;
245
273
 
246
- shortOptions[keyPath] = keyPathSchema.short;
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
- shortOptions = Object.fromEntries(
253
- Object.entries(shortOptions)
254
- .map(([key, value]) => [value, key]));
286
+ if (nonOptionsIndex > -1) {
287
+ nonOptions = args.slice(nonOptionsIndex + 1).join(' ');
288
+ args = args.slice(0, nonOptionsIndex);
289
+ }
255
290
 
256
- if (allKeyPaths.length) {
291
+ const allKeyPaths = keyPaths(options.schema)
292
+ .all()
293
+ .filter((keyPath) => keyPath);
257
294
 
258
- helpOptions = () => {
295
+ if (allKeyPaths.length) {
296
+ helpUsage.push(`${opening}${strings?.options?.help?.placeholder || 'options'}${closing}`);
297
+ }
259
298
 
260
- print();
261
- print(strings?.options?.help?.title || 'Options:');
262
- print();
299
+ if (typeof options.validationOptions.usage === 'string') {
300
+ helpUsage.push(options.validationOptions.usage);
301
+ }
263
302
 
264
- list(print, Object.fromEntries(allKeyPaths
265
- .map((keyPath) => {
303
+ let shortOptions = {};
266
304
 
267
- const keyPathSchema = keyPaths(schema).get(keyPath);
305
+ allKeyPaths
306
+ .forEach((keyPath) => {
268
307
 
269
- let optionKeys = [`--${caseit(keyPath, 'kebab')}`];
270
- let description = [keyPathSchema.description || 'No description'];
308
+ const keyPathSchema = keyPaths(options.schema).get(keyPath);
271
309
 
272
- if (shortOptions[keyPath]) {
273
- optionKeys.push(`-${shortOptions[keyPath]}`);
274
- }
310
+ if (keyPathSchema.short) {
275
311
 
276
- if (typeof keyPathSchema.enum !== 'undefined') {
277
- description.push(`(${opening}${keyPath}${closing}: ${Object.keys(keyPathSchema.enum).map((value) => `\`${value}\``).join(', ')})`);
312
+ if (shortOptions[keyPathSchema.short]) {
313
+ throw new Error(`Short option "${keyPathSchema.short}" already used.`);
278
314
  }
279
315
 
280
- if (keyPathSchema.type === Array) {
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
- if (keyPathSchema.secret === true) {
289
- defaultDescription = '`********`';
290
- } else {
318
+ }
291
319
 
292
- if (keyPathSchema.type === Boolean) {
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
- description.push(`${(strings?.options?.help?.default || '(default: <default>)')
301
- .replace('<default>', defaultDescription)}`);
326
+ if (allKeyPaths.length) {
302
327
 
303
- }
328
+ helpOptions = () => {
304
329
 
305
- if (keyPathSchema.hints?.length) {
306
- description = description.concat(keyPathSchema.hints);
307
- }
330
+ print();
331
+ print(strings?.options?.help?.title || 'Options:');
332
+ print();
308
333
 
309
- let option = optionKeys.reverse().join(', ');
334
+ list(print, Object.fromEntries(allKeyPaths
335
+ .map((keyPath) => {
310
336
 
311
- if (keyPathSchema.type !== Boolean) {
312
- option += ` ${strings?.options?.help?.argument || `${opening}${caseit(keyPath, 'kebab')}${closing}`}`;
313
- }
337
+ const keyPathSchema = keyPaths(options.schema).get(keyPath);
314
338
 
315
- return [option, description];
339
+ let optionKeys = [`--${caseit(keyPath, 'kebab')}`];
340
+ let description = [keyPathSchema.description || 'No description'];
316
341
 
317
- })), true);
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
- checkHelp();
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
- let data = {};
325
- let rest = [];
356
+ let defaultDescription;
326
357
 
327
- let idx;
358
+ if (keyPathSchema.secret === true) {
359
+ defaultDescription = '`********`';
360
+ } else {
328
361
 
329
- for (idx = 0 ; idx < args.length ; idx++) {
362
+ if (keyPathSchema.type === Boolean) {
363
+ defaultDescription = keyPathSchema.default === true ? 'enabled' : 'disabled';
364
+ } else {
365
+ defaultDescription = `\`${keyPathSchema.defaultDescription ?? keyPathSchema.default}\``;
366
+ }
330
367
 
331
- if (args[idx].slice(0, 1) !== '-') {
332
- rest.push(args[idx]);
333
- continue;
334
- }
368
+ }
335
369
 
336
- let key = args[idx].slice(1);
370
+ description.push(`${(strings?.options?.help?.default || '(default: <default>)')
371
+ .replace('<default>', defaultDescription)}`);
337
372
 
338
- if (args[idx].slice(1, 2) === '-') {
339
- key = caseit(args[idx].slice(2));
340
- } else if (shortOptions[key]) {
341
- key = caseit(shortOptions[key]);
342
- }
373
+ }
343
374
 
344
- if (!keyPaths(schema).all().includes(key)) {
345
- printHelp(
346
- new Error(
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
- let value;
379
+ let option = optionKeys.reverse().join(', ');
352
380
 
353
- if (keyPaths(schema).get(key).type === Boolean) {
354
- value = true;
355
- } else {
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
- if (typeof data[key] === 'undefined') {
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
- if (rest.length) {
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
- checkHelp();
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
- schema = formalize(schema);
396
+ for (idx = 0 ; idx < args.length ; idx++) {
423
397
 
424
- if (schema.type !== Object) {
425
- throw new Error('Schema must be an object.');
426
- }
398
+ if (args[idx].slice(0, 1) !== '-') {
399
+ rest.push(args[idx]);
400
+ continue;
401
+ }
427
402
 
428
- const schemaKeyPaths = keyPaths(schema);
403
+ let key = args[idx].slice(1);
429
404
 
430
- const allKeyPaths = schemaKeyPaths.all({ maxDepth: 2 })
431
- .filter((keyPath) => keyPath);
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
- let lastNonRequiredIndex = -1;
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
- allKeyPaths
436
- .forEach((keyPath, idx) => {
418
+ let value;
437
419
 
438
- const schema = schemaKeyPaths.get(keyPath);
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 (schema.required && idx > lastNonRequiredIndex + 1) {
441
- throw new Error('Required arguments must come first.');
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
- if (schema.type !== String) {
445
- throw new Error('Schema must be an object of strings.');
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
- helpUsage = helpUsage.concat([`${opening}${caseit(keyPath, 'kebab')}${closing}`]);
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
- checkHelp();
466
+ try {
467
+ data = await isvalid(options.data, options.schema, {
468
+ aggregatedErrors: 'flatten'
469
+ });
470
+ } catch (error) {
471
+ printHelp(error);
472
+ }
453
473
 
454
- try {
455
- return await isvalid(Object.fromEntries(
456
- allKeyPaths.map((keyPath, idx) => [keyPath, args[idx]])), schema);
457
- } catch (error) {
458
- return printHelp(error);
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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trenskow/arguments-parser",
3
- "version": "0.3.86",
3
+ "version": "0.3.88",
4
4
  "description": "Yet another arguments parser.",
5
5
  "main": "index.js",
6
6
  "type": "module",