@trenskow/arguments-parser 0.3.137 → 0.3.139
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/index.js +1 -84
- package/lib/arguments-parser.js +488 -0
- package/lib/autocomplete/index.js +6 -19
- package/lib/index.js +18 -468
- package/lib/plugins/autocomplete.js +25 -0
- package/lib/plugins/dummies.js +20 -0
- package/lib/plugins/hints.js +30 -0
- package/lib/plugins/index.js +21 -0
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -6,87 +6,4 @@
|
|
|
6
6
|
// See license in LICENSE.
|
|
7
7
|
//
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
basename,
|
|
11
|
-
extname
|
|
12
|
-
} from 'path';
|
|
13
|
-
|
|
14
|
-
import {
|
|
15
|
-
plugins
|
|
16
|
-
} from 'isvalid';
|
|
17
|
-
|
|
18
|
-
import argumentsParser from './lib/index.js';
|
|
19
|
-
import autocomplete from './lib/autocomplete/index.js';
|
|
20
|
-
|
|
21
|
-
plugins.use('argumentsParser.dummies', () => ({
|
|
22
|
-
phase: 'pre',
|
|
23
|
-
supportsType: () => true,
|
|
24
|
-
validatorsForType: () => ({
|
|
25
|
-
description: ['string'],
|
|
26
|
-
defaultDescription: ['string'],
|
|
27
|
-
secret: ['boolean'],
|
|
28
|
-
short: ['string']
|
|
29
|
-
}),
|
|
30
|
-
validate: (data) => data,
|
|
31
|
-
formalize: (schema) => schema
|
|
32
|
-
}));
|
|
33
|
-
|
|
34
|
-
plugins.use('argumentsParser.hints', () => ({
|
|
35
|
-
phase: 'pre',
|
|
36
|
-
supportsType: () => true,
|
|
37
|
-
validatorsForType: () => ({
|
|
38
|
-
hints: ['array', 'string']
|
|
39
|
-
}),
|
|
40
|
-
validate: (data) => data,
|
|
41
|
-
formalize: (data, _, schema) => {
|
|
42
|
-
|
|
43
|
-
if (!Array.isArray(data)) data = [data];
|
|
44
|
-
|
|
45
|
-
if (schema.errors.hints) {
|
|
46
|
-
data.push(schema.errors.hints);
|
|
47
|
-
delete schema.errors.hints;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (data.some((data) => typeof data !== 'string')) throw new Error('Must be a string.');
|
|
51
|
-
|
|
52
|
-
return data;
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
}));
|
|
56
|
-
|
|
57
|
-
plugins.use('argumentsParser.autocomplete', () => ({
|
|
58
|
-
phase: 'pre',
|
|
59
|
-
supportsType: () => true,
|
|
60
|
-
validatorsForType: () => ({
|
|
61
|
-
autocomplete: ['array', 'function']
|
|
62
|
-
}),
|
|
63
|
-
validate: (data) => data,
|
|
64
|
-
formalize: (data) => {
|
|
65
|
-
|
|
66
|
-
if (!(Array.isArray(data) && data.every((data) => typeof data === 'string')) && typeof data !== 'function') {
|
|
67
|
-
throw new Error('Must be a string or a function.');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return data;
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
}));
|
|
74
|
-
|
|
75
|
-
if (process.argv[2] === '_completion') {
|
|
76
|
-
|
|
77
|
-
let command = basename(process.env.COMPLETION_PATH || process.argv[1]);
|
|
78
|
-
|
|
79
|
-
const ext = extname(command);
|
|
80
|
-
|
|
81
|
-
if (ext.length) command = command.slice(0, -ext.length);
|
|
82
|
-
|
|
83
|
-
autocomplete.script({
|
|
84
|
-
shell: process.argv[3],
|
|
85
|
-
command
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
process.exit(0);
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export default typeof process.env.AUTOCOMPLETE_INDEX !== 'undefined' ? autocomplete() : argumentsParser;
|
|
9
|
+
export { default } from './lib/index.js';
|
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
//
|
|
2
|
+
// arguments-parser.js
|
|
3
|
+
// @trenskow/arguments-parser
|
|
4
|
+
//
|
|
5
|
+
// Created by Kristian Trenskow on 2023/08/07
|
|
6
|
+
// See license in LICENSE.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
basename
|
|
11
|
+
} from 'path';
|
|
12
|
+
|
|
13
|
+
import caseit from '@trenskow/caseit';
|
|
14
|
+
import { default as isvalid, merge, keyPaths } from 'isvalid';
|
|
15
|
+
import print from '@trenskow/print';
|
|
16
|
+
|
|
17
|
+
const argumentsParser = (
|
|
18
|
+
{
|
|
19
|
+
args = process.argv.slice(2),
|
|
20
|
+
argvLevel = 0,
|
|
21
|
+
placeholder = '<>',
|
|
22
|
+
command,
|
|
23
|
+
onCommand,
|
|
24
|
+
onParameter,
|
|
25
|
+
strings = {},
|
|
26
|
+
help: {
|
|
27
|
+
usage: helpUsage,
|
|
28
|
+
options: helpOptions,
|
|
29
|
+
} = {},
|
|
30
|
+
options = {
|
|
31
|
+
schema: {},
|
|
32
|
+
data: {},
|
|
33
|
+
validationOptions: {}
|
|
34
|
+
},
|
|
35
|
+
parameters = {}
|
|
36
|
+
} = {}
|
|
37
|
+
) => {
|
|
38
|
+
|
|
39
|
+
const [opening, closing] = placeholder.split('');
|
|
40
|
+
|
|
41
|
+
const base = `${process.argv.slice(1, argvLevel + 2).map(((arg) => basename(arg))).join(' ')}`;
|
|
42
|
+
|
|
43
|
+
const list = (print, items, spacing = false) => {
|
|
44
|
+
|
|
45
|
+
const maxLength = Object.keys(items)
|
|
46
|
+
.reduce((length, key) => Math.max(length, key.length), 0);
|
|
47
|
+
|
|
48
|
+
Object.entries(items)
|
|
49
|
+
.forEach(([key, description], idx) => {
|
|
50
|
+
|
|
51
|
+
if (spacing && idx > 0) print();
|
|
52
|
+
|
|
53
|
+
print.nn(` ${key}`, { minimumLength: maxLength + 4 });
|
|
54
|
+
|
|
55
|
+
if (!Array.isArray(description)) description = [description];
|
|
56
|
+
|
|
57
|
+
description
|
|
58
|
+
.forEach((description, idx) => {
|
|
59
|
+
|
|
60
|
+
if (idx > 0) {
|
|
61
|
+
print.nn('', { minimumLength: maxLength + 4 });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
print.sentence(description);
|
|
65
|
+
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
if (typeof helpUsage === 'undefined') {
|
|
73
|
+
helpUsage = [
|
|
74
|
+
strings?.help?.usage || 'Usage:',
|
|
75
|
+
base
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const printHelp = (error) => {
|
|
80
|
+
|
|
81
|
+
print();
|
|
82
|
+
|
|
83
|
+
if (command) {
|
|
84
|
+
print.bold(command.description);
|
|
85
|
+
print();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
print(helpUsage.join(' '));
|
|
89
|
+
|
|
90
|
+
if (helpOptions) {
|
|
91
|
+
print.nn(helpOptions());
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (error) {
|
|
95
|
+
|
|
96
|
+
print();
|
|
97
|
+
|
|
98
|
+
(error.errors || [error])
|
|
99
|
+
.forEach((error) => {
|
|
100
|
+
|
|
101
|
+
let message = error.message;
|
|
102
|
+
|
|
103
|
+
if (error.keyPath?.[0]) {
|
|
104
|
+
message = `${caseit(error.keyPath[0], 'kebab')}: ${message}`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
print.bold((strings?.commands?.help?.error || 'Error: <message>')
|
|
108
|
+
.replace('<message>', message));
|
|
109
|
+
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
print();
|
|
115
|
+
|
|
116
|
+
process.exit(error ? 1 : 0);
|
|
117
|
+
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const checkHelp = () => {
|
|
121
|
+
if (args[0] === '--help') printHelp();
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const next = async (identifier, command) => {
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
|
|
128
|
+
return await command({
|
|
129
|
+
args: args.slice(1),
|
|
130
|
+
argumentsParser: argumentsParser({
|
|
131
|
+
args: args.slice(1),
|
|
132
|
+
argvLevel: argvLevel + 1,
|
|
133
|
+
onCommand,
|
|
134
|
+
onParameter,
|
|
135
|
+
placeholder,
|
|
136
|
+
command: command,
|
|
137
|
+
strings,
|
|
138
|
+
options,
|
|
139
|
+
parameters
|
|
140
|
+
}),
|
|
141
|
+
parameters
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
} catch (error) {
|
|
145
|
+
print.err(`${error.stack}`);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const result = {
|
|
152
|
+
get base() {
|
|
153
|
+
return base;
|
|
154
|
+
},
|
|
155
|
+
command: async (commands) => {
|
|
156
|
+
|
|
157
|
+
helpUsage.push(`${opening}${strings?.commands?.help?.placeholder || 'command'}${closing}`);
|
|
158
|
+
|
|
159
|
+
helpOptions = () => {
|
|
160
|
+
|
|
161
|
+
print();
|
|
162
|
+
print(strings?.commands?.help?.available || 'Available commands:');
|
|
163
|
+
print();
|
|
164
|
+
|
|
165
|
+
const tools = Object.entries(commands).map(([key, command]) => ({
|
|
166
|
+
name: `${caseit(key, 'kebab')}${Array.isArray(command.parameters) ? ` ${command.parameters.map((parameter) => `${opening}${caseit(parameter, 'kebab')}${closing}`).join(' ')}` : ''}`,
|
|
167
|
+
description: commands[key].description
|
|
168
|
+
}));
|
|
169
|
+
|
|
170
|
+
tools.sort((a, b) => a.name > b.name ? 1 : -1);
|
|
171
|
+
|
|
172
|
+
list(print, Object.fromEntries(tools
|
|
173
|
+
.map((tool) => [tool.name, tool.description || (strings?.commands?.help?.noDescription || 'No description')])));
|
|
174
|
+
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
if (args.length === 0) printHelp();
|
|
178
|
+
|
|
179
|
+
checkHelp();
|
|
180
|
+
|
|
181
|
+
const tool = caseit(args[0]);
|
|
182
|
+
|
|
183
|
+
if (!commands[tool]) {
|
|
184
|
+
printHelp(
|
|
185
|
+
new Error(
|
|
186
|
+
(strings?.commands?.help?.errors?.notFound || '<command>: Command not found')
|
|
187
|
+
.replace('<command>', args[0])));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
onCommand?.(tool, args.slice(1));
|
|
191
|
+
|
|
192
|
+
return await next(
|
|
193
|
+
tool,
|
|
194
|
+
commands[tool]);
|
|
195
|
+
|
|
196
|
+
},
|
|
197
|
+
parameter: async ({
|
|
198
|
+
identifier,
|
|
199
|
+
description,
|
|
200
|
+
schema
|
|
201
|
+
} = {}, command) => {
|
|
202
|
+
|
|
203
|
+
if (typeof identifier !== 'string') {
|
|
204
|
+
throw new Error('Identifier must be a string');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
description = description || command.description || strings?.commands?.help?.noDescription || 'No description.';
|
|
208
|
+
|
|
209
|
+
helpUsage.push(`${opening}${caseit(identifier, 'kebab')}${closing}`);
|
|
210
|
+
|
|
211
|
+
helpOptions = () => {
|
|
212
|
+
|
|
213
|
+
print();
|
|
214
|
+
print(strings?.commands?.help?.available || 'Available commands:');
|
|
215
|
+
print();
|
|
216
|
+
|
|
217
|
+
list(print, {
|
|
218
|
+
[`${opening}${caseit(identifier, 'kebab')}${closing}`]: description
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
if (args.length === 0) printHelp();
|
|
224
|
+
|
|
225
|
+
checkHelp();
|
|
226
|
+
|
|
227
|
+
parameters[identifier] = args[0];
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
if (typeof schema !== 'undefined') {
|
|
231
|
+
parameters[identifier] = await isvalid(
|
|
232
|
+
parameters[identifier],
|
|
233
|
+
schema);
|
|
234
|
+
}
|
|
235
|
+
} catch (error) {
|
|
236
|
+
printHelp(error);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
(onParameter || onCommand)?.(identifier, args.slice(1));
|
|
240
|
+
|
|
241
|
+
return await next(
|
|
242
|
+
identifier,
|
|
243
|
+
command);
|
|
244
|
+
|
|
245
|
+
},
|
|
246
|
+
options: (schema, validationOptions = {}) => {
|
|
247
|
+
|
|
248
|
+
validationOptions.command = validationOptions.command || command;
|
|
249
|
+
|
|
250
|
+
Object.assign(
|
|
251
|
+
options.validationOptions,
|
|
252
|
+
validationOptions);
|
|
253
|
+
|
|
254
|
+
options.schema = merge(
|
|
255
|
+
schema, {
|
|
256
|
+
transform: {
|
|
257
|
+
post: (key, validator) => {
|
|
258
|
+
if (key === 'enum') {
|
|
259
|
+
return validator.map((value) => caseit(value, 'kebab'));
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
})
|
|
264
|
+
.with(options.schema);
|
|
265
|
+
|
|
266
|
+
return result;
|
|
267
|
+
|
|
268
|
+
},
|
|
269
|
+
help(error) {
|
|
270
|
+
printHelp(error);
|
|
271
|
+
},
|
|
272
|
+
then: (...resultArguments) => {
|
|
273
|
+
return (async () => {
|
|
274
|
+
|
|
275
|
+
let nonOptions;
|
|
276
|
+
let nonOptionsIndex = args.indexOf('--');
|
|
277
|
+
|
|
278
|
+
if (nonOptionsIndex > -1) {
|
|
279
|
+
nonOptions = args.slice(nonOptionsIndex + 1).join(' ');
|
|
280
|
+
args = args.slice(0, nonOptionsIndex);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const allKeyPaths = keyPaths(options.schema)
|
|
284
|
+
.all()
|
|
285
|
+
.filter((keyPath) => keyPath);
|
|
286
|
+
|
|
287
|
+
if (allKeyPaths.length) {
|
|
288
|
+
helpUsage.push(`${opening}${strings?.options?.help?.placeholder || 'options'}${closing}`);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (typeof options.validationOptions.usage === 'string') {
|
|
292
|
+
helpUsage.push(options.validationOptions.usage);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
let shortOptions = {};
|
|
296
|
+
|
|
297
|
+
allKeyPaths
|
|
298
|
+
.forEach((keyPath) => {
|
|
299
|
+
|
|
300
|
+
const keyPathSchema = keyPaths(options.schema).get(keyPath);
|
|
301
|
+
|
|
302
|
+
if (keyPathSchema.short) {
|
|
303
|
+
|
|
304
|
+
if (shortOptions[keyPathSchema.short]) {
|
|
305
|
+
throw new Error(`Short option "${keyPathSchema.short}" already used.`);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
shortOptions[keyPath] = keyPathSchema.short;
|
|
309
|
+
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
shortOptions = Object.fromEntries(
|
|
315
|
+
Object.entries(shortOptions)
|
|
316
|
+
.map(([key, value]) => [value, key]));
|
|
317
|
+
|
|
318
|
+
if (allKeyPaths.length) {
|
|
319
|
+
|
|
320
|
+
helpOptions = () => {
|
|
321
|
+
|
|
322
|
+
print();
|
|
323
|
+
print(strings?.options?.help?.title || 'Options:');
|
|
324
|
+
print();
|
|
325
|
+
|
|
326
|
+
list(print, Object.fromEntries(allKeyPaths
|
|
327
|
+
.map((keyPath) => {
|
|
328
|
+
|
|
329
|
+
const keyPathSchema = keyPaths(options.schema).get(keyPath);
|
|
330
|
+
|
|
331
|
+
let optionKeys = [`--${caseit(keyPath, 'kebab')}`];
|
|
332
|
+
|
|
333
|
+
let description = [keyPathSchema.description || strings?.commands?.help?.noDescription || 'No description'];
|
|
334
|
+
|
|
335
|
+
if (keyPathSchema.short) {
|
|
336
|
+
optionKeys.push(`-${keyPathSchema.short}`);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (typeof keyPathSchema.enum !== 'undefined') {
|
|
340
|
+
description.push(`(${opening}${keyPath}${closing}: ${Object.keys(keyPathSchema.enum).map((value) => `\`${value}\``).join(', ')})`);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (keyPathSchema.type === Array) {
|
|
344
|
+
description.push(`${strings?.options?.help?.allowsMultiple || '(allows multiple)'}`);
|
|
345
|
+
} else if (keyPathSchema.required === true) {
|
|
346
|
+
description.push(`${strings?.options?.help?.required || '(required)'}`);
|
|
347
|
+
} else if (typeof keyPathSchema.default !== 'undefined') {
|
|
348
|
+
|
|
349
|
+
let defaultDescription;
|
|
350
|
+
|
|
351
|
+
if (keyPathSchema.secret === true) {
|
|
352
|
+
defaultDescription = '`********`';
|
|
353
|
+
} else {
|
|
354
|
+
|
|
355
|
+
if (keyPathSchema.type === Boolean) {
|
|
356
|
+
defaultDescription = keyPathSchema.default === true ? 'enabled' : 'disabled';
|
|
357
|
+
} else {
|
|
358
|
+
defaultDescription = `\`${keyPathSchema.defaultDescription ?? keyPathSchema.default}\``;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
description.push(`${(strings?.options?.help?.default || '(default: <default>)')
|
|
364
|
+
.replace('<default>', defaultDescription)}`);
|
|
365
|
+
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (keyPathSchema.hints?.length) {
|
|
369
|
+
description = description.concat(keyPathSchema.hints);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
let option = optionKeys.reverse().join(', ');
|
|
373
|
+
|
|
374
|
+
if (keyPathSchema.type !== Boolean) {
|
|
375
|
+
option += ` ${strings?.options?.help?.argument || `${opening}${caseit(keyPath, 'kebab')}${closing}`}`;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return [option, description];
|
|
379
|
+
|
|
380
|
+
})), true);
|
|
381
|
+
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
checkHelp();
|
|
386
|
+
|
|
387
|
+
let rest = [];
|
|
388
|
+
|
|
389
|
+
let idx;
|
|
390
|
+
|
|
391
|
+
checkHelp();
|
|
392
|
+
|
|
393
|
+
for (idx = 0; idx < args.length; idx++) {
|
|
394
|
+
|
|
395
|
+
if (args[idx].slice(0, 1) !== '-') {
|
|
396
|
+
rest.push(args[idx]);
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
let key = args[idx].slice(1);
|
|
401
|
+
|
|
402
|
+
if (args[idx].slice(1, 2) === '-') {
|
|
403
|
+
key = caseit(args[idx].slice(2));
|
|
404
|
+
} else if (shortOptions[key]) {
|
|
405
|
+
key = caseit(shortOptions[key]);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (!keyPaths(options.schema).all().includes(key)) {
|
|
409
|
+
printHelp(
|
|
410
|
+
new Error(
|
|
411
|
+
(strings?.options?.help?.errors?.unknownOption || 'Unknown option: <option>.')
|
|
412
|
+
.replace('<option>', args[idx])));
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
let value;
|
|
416
|
+
|
|
417
|
+
if (keyPaths(options.schema).get(key).type === Boolean) {
|
|
418
|
+
value = true;
|
|
419
|
+
} else {
|
|
420
|
+
if (args.length <= idx + 1 || args[idx + 1].slice(0, 2) === '--') {
|
|
421
|
+
printHelp(
|
|
422
|
+
new Error(
|
|
423
|
+
(strings?.options?.help?.errors?.missingArgument || 'Argument missing for option: <option>.')
|
|
424
|
+
.replace('<option>', args[idx])));
|
|
425
|
+
}
|
|
426
|
+
value = args[++idx];
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (typeof options.data[key] === 'undefined') {
|
|
430
|
+
options.data[key] = value;
|
|
431
|
+
} else if (Array.isArray(options.data[key])) {
|
|
432
|
+
options.data[key].push(value);
|
|
433
|
+
} else {
|
|
434
|
+
options.data[key] = [options.data[key], value];
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (rest.length) {
|
|
440
|
+
switch (options.validationOptions.variadic || 'deny') {
|
|
441
|
+
case 'allow':
|
|
442
|
+
break;
|
|
443
|
+
case 'ignore':
|
|
444
|
+
rest = [];
|
|
445
|
+
break;
|
|
446
|
+
default:
|
|
447
|
+
printHelp(
|
|
448
|
+
new Error(
|
|
449
|
+
(strings?.empty?.help?.errors?.unexpected || 'Unexpected argument: <argument>.')
|
|
450
|
+
.replace('<argument>', args[0])));
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (args.length - idx > 0) {
|
|
455
|
+
printHelp(
|
|
456
|
+
new Error(
|
|
457
|
+
(strings?.empty?.help?.errors?.unexpected || 'Unexpected argument: <argument>.')
|
|
458
|
+
.replace('<argument>', args[0])));
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
let data = {};
|
|
462
|
+
|
|
463
|
+
try {
|
|
464
|
+
data = await isvalid(options.data, options.schema, {
|
|
465
|
+
aggregatedErrors: 'flatten'
|
|
466
|
+
});
|
|
467
|
+
} catch (error) {
|
|
468
|
+
printHelp(error);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return Object.assign({}, data, {
|
|
472
|
+
onError: (error) => {
|
|
473
|
+
print.err(error.message);
|
|
474
|
+
process.exit(1);
|
|
475
|
+
},
|
|
476
|
+
rest,
|
|
477
|
+
nonOptions
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
})().then(...resultArguments);
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
return result;
|
|
485
|
+
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
export default argumentsParser;
|
|
@@ -27,7 +27,7 @@ const supported = {
|
|
|
27
27
|
|
|
28
28
|
const currentShell = basename(process.env.SHELL || '');
|
|
29
29
|
|
|
30
|
-
const
|
|
30
|
+
const autocomplete = () => {
|
|
31
31
|
|
|
32
32
|
const writer = supported[currentShell];
|
|
33
33
|
|
|
@@ -188,15 +188,7 @@ const argumentsParser = () => {
|
|
|
188
188
|
validationOptions);
|
|
189
189
|
|
|
190
190
|
options.schema = merge(
|
|
191
|
-
schema
|
|
192
|
-
transform: {
|
|
193
|
-
post: (key, validator) => {
|
|
194
|
-
if (key === 'enum') {
|
|
195
|
-
return validator.map((value) => caseit(value, 'kebab'));
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
})
|
|
191
|
+
schema)
|
|
200
192
|
.with(options.schema);
|
|
201
193
|
|
|
202
194
|
return result;
|
|
@@ -240,7 +232,7 @@ const argumentsParser = () => {
|
|
|
240
232
|
|
|
241
233
|
if (schemas[idx].enum) {
|
|
242
234
|
return Object.keys(schemas[idx].enum)
|
|
243
|
-
.filter((item) =>
|
|
235
|
+
.filter((item) => key !== item && item.startsWith(current))
|
|
244
236
|
.map((item) => ({
|
|
245
237
|
type: 'option',
|
|
246
238
|
argument: caseit(item, 'kebab')
|
|
@@ -296,7 +288,7 @@ const argumentsParser = () => {
|
|
|
296
288
|
if (variadic === 'allow' && !variadicOnly && current === Array(current.length).fill('-').join('')) {
|
|
297
289
|
items = items.concat([{
|
|
298
290
|
type: 'option',
|
|
299
|
-
argument: '--'.slice(0, -current.length)
|
|
291
|
+
argument: current.length ? '--'.slice(0, -current.length) : '--'
|
|
300
292
|
}]);
|
|
301
293
|
}
|
|
302
294
|
|
|
@@ -306,11 +298,6 @@ const argumentsParser = () => {
|
|
|
306
298
|
|
|
307
299
|
};
|
|
308
300
|
|
|
309
|
-
if (args.length === 0) {
|
|
310
|
-
return output(
|
|
311
|
-
await complete(-1));
|
|
312
|
-
}
|
|
313
|
-
|
|
314
301
|
for (idx = 0; idx < autocompleteIndex || idx < args.length; idx++) {
|
|
315
302
|
|
|
316
303
|
if (!schemas[idx]) {
|
|
@@ -351,7 +338,7 @@ const argumentsParser = () => {
|
|
|
351
338
|
|
|
352
339
|
};
|
|
353
340
|
|
|
354
|
-
|
|
341
|
+
autocomplete.script = ({
|
|
355
342
|
shell = currentShell,
|
|
356
343
|
command
|
|
357
344
|
}) => {
|
|
@@ -370,4 +357,4 @@ argumentsParser.script = ({
|
|
|
370
357
|
|
|
371
358
|
};
|
|
372
359
|
|
|
373
|
-
export default
|
|
360
|
+
export default autocomplete;
|
package/lib/index.js
CHANGED
|
@@ -2,487 +2,37 @@
|
|
|
2
2
|
// index.js
|
|
3
3
|
// @trenskow/arguments-parser
|
|
4
4
|
//
|
|
5
|
-
// Created by Kristian Trenskow on
|
|
5
|
+
// Created by Kristian Trenskow on 2026/08/04
|
|
6
6
|
// See license in LICENSE.
|
|
7
7
|
//
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
|
-
basename
|
|
10
|
+
basename,
|
|
11
|
+
extname
|
|
11
12
|
} from 'path';
|
|
12
13
|
|
|
13
|
-
import
|
|
14
|
-
import { default as isvalid, merge, keyPaths } from 'isvalid';
|
|
15
|
-
import print from '@trenskow/print';
|
|
14
|
+
import plugins from './plugins/index.js';
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
args = process.argv.slice(2),
|
|
20
|
-
argvLevel = 0,
|
|
21
|
-
placeholder = '<>',
|
|
22
|
-
command,
|
|
23
|
-
onCommand,
|
|
24
|
-
onParameter,
|
|
25
|
-
strings = {},
|
|
26
|
-
help: {
|
|
27
|
-
usage: helpUsage,
|
|
28
|
-
options: helpOptions,
|
|
29
|
-
} = {},
|
|
30
|
-
options = {
|
|
31
|
-
schema: {},
|
|
32
|
-
data: {},
|
|
33
|
-
validationOptions: {}
|
|
34
|
-
},
|
|
35
|
-
parameters = {}
|
|
36
|
-
} = {}
|
|
37
|
-
) => {
|
|
16
|
+
import argumentsParser from './arguments-parser.js';
|
|
17
|
+
import autocomplete from './autocomplete/index.js';
|
|
38
18
|
|
|
39
|
-
|
|
19
|
+
plugins();
|
|
40
20
|
|
|
41
|
-
|
|
21
|
+
if (process.argv[2] === '_completion') {
|
|
42
22
|
|
|
43
|
-
|
|
23
|
+
let command = basename(process.env.COMPLETION_PATH || process.argv[1]);
|
|
44
24
|
|
|
45
|
-
|
|
46
|
-
.reduce((length, key) => Math.max(length, key.length), 0);
|
|
25
|
+
const ext = extname(command);
|
|
47
26
|
|
|
48
|
-
|
|
49
|
-
.forEach(([key, description], idx) => {
|
|
27
|
+
if (ext.length) command = command.slice(0, -ext.length);
|
|
50
28
|
|
|
51
|
-
|
|
29
|
+
autocomplete.script({
|
|
30
|
+
shell: process.argv[3],
|
|
31
|
+
command
|
|
32
|
+
});
|
|
52
33
|
|
|
53
|
-
|
|
34
|
+
process.exit(0);
|
|
54
35
|
|
|
55
|
-
|
|
36
|
+
}
|
|
56
37
|
|
|
57
|
-
|
|
58
|
-
.forEach((description, idx) => {
|
|
59
|
-
|
|
60
|
-
if (idx > 0) {
|
|
61
|
-
print.nn('', { minimumLength: maxLength + 4 });
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
print.sentence(description);
|
|
65
|
-
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
if (typeof helpUsage === 'undefined') {
|
|
73
|
-
helpUsage = [
|
|
74
|
-
strings?.help?.usage || 'Usage:',
|
|
75
|
-
base
|
|
76
|
-
];
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const printHelp = (error) => {
|
|
80
|
-
|
|
81
|
-
print();
|
|
82
|
-
|
|
83
|
-
if (command) {
|
|
84
|
-
print.bold(command.description);
|
|
85
|
-
print();
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
print(helpUsage.join(' '));
|
|
89
|
-
|
|
90
|
-
if (helpOptions) {
|
|
91
|
-
print.nn(helpOptions());
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (error) {
|
|
95
|
-
|
|
96
|
-
print();
|
|
97
|
-
|
|
98
|
-
(error.errors || [error])
|
|
99
|
-
.forEach((error) => {
|
|
100
|
-
|
|
101
|
-
let message = error.message;
|
|
102
|
-
|
|
103
|
-
if (error.keyPath?.[0]) {
|
|
104
|
-
message = `${caseit(error.keyPath[0], 'kebab')}: ${message}`;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
print.bold((strings?.commands?.help?.error || 'Error: <message>')
|
|
108
|
-
.replace('<message>', message));
|
|
109
|
-
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
print();
|
|
115
|
-
|
|
116
|
-
process.exit(error ? 1 : 0);
|
|
117
|
-
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const checkHelp = () => {
|
|
121
|
-
if (args[0] === '--help') printHelp();
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const next = async (identifier, command) => {
|
|
125
|
-
|
|
126
|
-
try {
|
|
127
|
-
|
|
128
|
-
return await command({
|
|
129
|
-
args: args.slice(1),
|
|
130
|
-
argumentsParser: argumentsParser({
|
|
131
|
-
args: args.slice(1),
|
|
132
|
-
argvLevel: argvLevel + 1,
|
|
133
|
-
onCommand,
|
|
134
|
-
onParameter,
|
|
135
|
-
placeholder,
|
|
136
|
-
command: command,
|
|
137
|
-
strings,
|
|
138
|
-
options,
|
|
139
|
-
parameters
|
|
140
|
-
}),
|
|
141
|
-
parameters
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
} catch (error) {
|
|
145
|
-
print.err(`${error.stack}`);
|
|
146
|
-
process.exit(1);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
const result = {
|
|
152
|
-
get base() {
|
|
153
|
-
return base;
|
|
154
|
-
},
|
|
155
|
-
command: async (commands) => {
|
|
156
|
-
|
|
157
|
-
helpUsage.push(`${opening}${strings?.commands?.help?.placeholder || 'command'}${closing}`);
|
|
158
|
-
|
|
159
|
-
helpOptions = () => {
|
|
160
|
-
|
|
161
|
-
print();
|
|
162
|
-
print(strings?.commands?.help?.available || 'Available commands:');
|
|
163
|
-
print();
|
|
164
|
-
|
|
165
|
-
const tools = Object.entries(commands).map(([key, command]) => ({
|
|
166
|
-
name: `${caseit(key, 'kebab')}${Array.isArray(command.parameters) ? ` ${command.parameters.map((parameter) => `${opening}${caseit(parameter, 'kebab')}${closing}`).join(' ')}` : ''}`,
|
|
167
|
-
description: commands[key].description
|
|
168
|
-
}));
|
|
169
|
-
|
|
170
|
-
tools.sort((a, b) => a.name > b.name ? 1 : -1);
|
|
171
|
-
|
|
172
|
-
list(print, Object.fromEntries(tools
|
|
173
|
-
.map((tool) => [tool.name, tool.description || (strings?.commands?.help?.noDescription || 'No description')])));
|
|
174
|
-
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
if (args.length === 0) printHelp();
|
|
178
|
-
|
|
179
|
-
checkHelp();
|
|
180
|
-
|
|
181
|
-
const tool = caseit(args[0]);
|
|
182
|
-
|
|
183
|
-
if (!commands[tool]) {
|
|
184
|
-
printHelp(
|
|
185
|
-
new Error(
|
|
186
|
-
(strings?.commands?.help?.errors?.notFound || '<command>: Command not found')
|
|
187
|
-
.replace('<command>', args[0])));
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
onCommand?.(tool, args.slice(1));
|
|
191
|
-
|
|
192
|
-
return await next(
|
|
193
|
-
tool,
|
|
194
|
-
commands[tool]);
|
|
195
|
-
|
|
196
|
-
},
|
|
197
|
-
parameter: async ({
|
|
198
|
-
identifier,
|
|
199
|
-
description,
|
|
200
|
-
schema
|
|
201
|
-
} = {}, command) => {
|
|
202
|
-
|
|
203
|
-
if (typeof identifier !== 'string') {
|
|
204
|
-
throw new Error('Identifier must be a string');
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
description = description || command.description || strings?.commands?.help?.noDescription || 'No description.';
|
|
208
|
-
|
|
209
|
-
helpUsage.push(`${opening}${caseit(identifier, 'kebab')}${closing}`);
|
|
210
|
-
|
|
211
|
-
helpOptions = () => {
|
|
212
|
-
|
|
213
|
-
print();
|
|
214
|
-
print(strings?.commands?.help?.available || 'Available commands:');
|
|
215
|
-
print();
|
|
216
|
-
|
|
217
|
-
list(print, {
|
|
218
|
-
[`${opening}${caseit(identifier, 'kebab')}${closing}`]: description
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
if (args.length === 0) printHelp();
|
|
224
|
-
|
|
225
|
-
checkHelp();
|
|
226
|
-
|
|
227
|
-
parameters[identifier] = args[0];
|
|
228
|
-
|
|
229
|
-
try {
|
|
230
|
-
if (typeof schema !== 'undefined') {
|
|
231
|
-
parameters[identifier] = await isvalid(
|
|
232
|
-
parameters[identifier],
|
|
233
|
-
schema);
|
|
234
|
-
}
|
|
235
|
-
} catch (error) {
|
|
236
|
-
printHelp(error);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
(onParameter || onCommand)?.(identifier, args.slice(1));
|
|
240
|
-
|
|
241
|
-
return await next(
|
|
242
|
-
identifier,
|
|
243
|
-
command);
|
|
244
|
-
|
|
245
|
-
},
|
|
246
|
-
options: (schema, validationOptions = {}) => {
|
|
247
|
-
|
|
248
|
-
validationOptions.command = validationOptions.command || command;
|
|
249
|
-
|
|
250
|
-
Object.assign(
|
|
251
|
-
options.validationOptions,
|
|
252
|
-
validationOptions);
|
|
253
|
-
|
|
254
|
-
options.schema = merge(
|
|
255
|
-
schema, {
|
|
256
|
-
transform: {
|
|
257
|
-
post: (key, validator) => {
|
|
258
|
-
if (key === 'enum') {
|
|
259
|
-
return validator.map((value) => caseit(value, 'kebab'));
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
})
|
|
264
|
-
.with(options.schema);
|
|
265
|
-
|
|
266
|
-
return result;
|
|
267
|
-
|
|
268
|
-
},
|
|
269
|
-
help(error) {
|
|
270
|
-
printHelp(error);
|
|
271
|
-
},
|
|
272
|
-
then: (...resultArguments) => {
|
|
273
|
-
return (async () => {
|
|
274
|
-
|
|
275
|
-
let nonOptions;
|
|
276
|
-
let nonOptionsIndex = args.indexOf('--');
|
|
277
|
-
|
|
278
|
-
if (nonOptionsIndex > -1) {
|
|
279
|
-
nonOptions = args.slice(nonOptionsIndex + 1).join(' ');
|
|
280
|
-
args = args.slice(0, nonOptionsIndex);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
const allKeyPaths = keyPaths(options.schema)
|
|
284
|
-
.all()
|
|
285
|
-
.filter((keyPath) => keyPath);
|
|
286
|
-
|
|
287
|
-
if (allKeyPaths.length) {
|
|
288
|
-
helpUsage.push(`${opening}${strings?.options?.help?.placeholder || 'options'}${closing}`);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
if (typeof options.validationOptions.usage === 'string') {
|
|
292
|
-
helpUsage.push(options.validationOptions.usage);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
let shortOptions = {};
|
|
296
|
-
|
|
297
|
-
allKeyPaths
|
|
298
|
-
.forEach((keyPath) => {
|
|
299
|
-
|
|
300
|
-
const keyPathSchema = keyPaths(options.schema).get(keyPath);
|
|
301
|
-
|
|
302
|
-
if (keyPathSchema.short) {
|
|
303
|
-
|
|
304
|
-
if (shortOptions[keyPathSchema.short]) {
|
|
305
|
-
throw new Error(`Short option "${keyPathSchema.short}" already used.`);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
shortOptions[keyPath] = keyPathSchema.short;
|
|
309
|
-
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
shortOptions = Object.fromEntries(
|
|
315
|
-
Object.entries(shortOptions)
|
|
316
|
-
.map(([key, value]) => [value, key]));
|
|
317
|
-
|
|
318
|
-
if (allKeyPaths.length) {
|
|
319
|
-
|
|
320
|
-
helpOptions = () => {
|
|
321
|
-
|
|
322
|
-
print();
|
|
323
|
-
print(strings?.options?.help?.title || 'Options:');
|
|
324
|
-
print();
|
|
325
|
-
|
|
326
|
-
list(print, Object.fromEntries(allKeyPaths
|
|
327
|
-
.map((keyPath) => {
|
|
328
|
-
|
|
329
|
-
const keyPathSchema = keyPaths(options.schema).get(keyPath);
|
|
330
|
-
|
|
331
|
-
let optionKeys = [`--${caseit(keyPath, 'kebab')}`];
|
|
332
|
-
|
|
333
|
-
let description = [keyPathSchema.description || strings?.commands?.help?.noDescription || 'No description'];
|
|
334
|
-
|
|
335
|
-
if (keyPathSchema.short) {
|
|
336
|
-
optionKeys.push(`-${keyPathSchema.short}`);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
if (typeof keyPathSchema.enum !== 'undefined') {
|
|
340
|
-
description.push(`(${opening}${keyPath}${closing}: ${Object.keys(keyPathSchema.enum).map((value) => `\`${caseit(value, 'kebab')}\``).join(', ')})`);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
if (keyPathSchema.type === Array) {
|
|
344
|
-
description.push(`${strings?.options?.help?.allowsMultiple || '(allows multiple)'}`);
|
|
345
|
-
} else if (keyPathSchema.required === true) {
|
|
346
|
-
description.push(`${strings?.options?.help?.required || '(required)'}`);
|
|
347
|
-
} else if (typeof keyPathSchema.default !== 'undefined') {
|
|
348
|
-
|
|
349
|
-
let defaultDescription;
|
|
350
|
-
|
|
351
|
-
if (keyPathSchema.secret === true) {
|
|
352
|
-
defaultDescription = '`********`';
|
|
353
|
-
} else {
|
|
354
|
-
|
|
355
|
-
if (keyPathSchema.type === Boolean) {
|
|
356
|
-
defaultDescription = keyPathSchema.default === true ? 'enabled' : 'disabled';
|
|
357
|
-
} else {
|
|
358
|
-
defaultDescription = `\`${keyPathSchema.defaultDescription ?? keyPathSchema.default}\``;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
description.push(`${(strings?.options?.help?.default || '(default: <default>)')
|
|
364
|
-
.replace('<default>', defaultDescription)}`);
|
|
365
|
-
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
if (keyPathSchema.hints?.length) {
|
|
369
|
-
description = description.concat(keyPathSchema.hints);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
let option = optionKeys.reverse().join(', ');
|
|
373
|
-
|
|
374
|
-
if (keyPathSchema.type !== Boolean) {
|
|
375
|
-
option += ` ${strings?.options?.help?.argument || `${opening}${caseit(keyPath, 'kebab')}${closing}`}`;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
return [option, description];
|
|
379
|
-
|
|
380
|
-
})), true);
|
|
381
|
-
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
checkHelp();
|
|
386
|
-
|
|
387
|
-
let rest = [];
|
|
388
|
-
|
|
389
|
-
let idx;
|
|
390
|
-
|
|
391
|
-
checkHelp();
|
|
392
|
-
|
|
393
|
-
for (idx = 0; idx < args.length; idx++) {
|
|
394
|
-
|
|
395
|
-
if (args[idx].slice(0, 1) !== '-') {
|
|
396
|
-
rest.push(args[idx]);
|
|
397
|
-
continue;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
let key = args[idx].slice(1);
|
|
401
|
-
|
|
402
|
-
if (args[idx].slice(1, 2) === '-') {
|
|
403
|
-
key = caseit(args[idx].slice(2));
|
|
404
|
-
} else if (shortOptions[key]) {
|
|
405
|
-
key = caseit(shortOptions[key]);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
if (!keyPaths(options.schema).all().includes(key)) {
|
|
409
|
-
printHelp(
|
|
410
|
-
new Error(
|
|
411
|
-
(strings?.options?.help?.errors?.unknownOption || 'Unknown option: <option>.')
|
|
412
|
-
.replace('<option>', args[idx])));
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
let value;
|
|
416
|
-
|
|
417
|
-
if (keyPaths(options.schema).get(key).type === Boolean) {
|
|
418
|
-
value = true;
|
|
419
|
-
} else {
|
|
420
|
-
if (args.length <= idx + 1 || args[idx + 1].slice(0, 2) === '--') {
|
|
421
|
-
printHelp(
|
|
422
|
-
new Error(
|
|
423
|
-
(strings?.options?.help?.errors?.missingArgument || 'Argument missing for option: <option>.')
|
|
424
|
-
.replace('<option>', args[idx])));
|
|
425
|
-
}
|
|
426
|
-
value = args[++idx];
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
if (typeof options.data[key] === 'undefined') {
|
|
430
|
-
options.data[key] = value;
|
|
431
|
-
} else if (Array.isArray(options.data[key])) {
|
|
432
|
-
options.data[key].push(value);
|
|
433
|
-
} else {
|
|
434
|
-
options.data[key] = [options.data[key], value];
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
if (rest.length) {
|
|
440
|
-
switch (options.validationOptions.variadic || 'deny') {
|
|
441
|
-
case 'allow':
|
|
442
|
-
break;
|
|
443
|
-
case 'ignore':
|
|
444
|
-
rest = [];
|
|
445
|
-
break;
|
|
446
|
-
default:
|
|
447
|
-
printHelp(
|
|
448
|
-
new Error(
|
|
449
|
-
(strings?.empty?.help?.errors?.unexpected || 'Unexpected argument: <argument>.')
|
|
450
|
-
.replace('<argument>', args[0])));
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
if (args.length - idx > 0) {
|
|
455
|
-
printHelp(
|
|
456
|
-
new Error(
|
|
457
|
-
(strings?.empty?.help?.errors?.unexpected || 'Unexpected argument: <argument>.')
|
|
458
|
-
.replace('<argument>', args[0])));
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
let data = {};
|
|
462
|
-
|
|
463
|
-
try {
|
|
464
|
-
data = await isvalid(options.data, options.schema, {
|
|
465
|
-
aggregatedErrors: 'flatten'
|
|
466
|
-
});
|
|
467
|
-
} catch (error) {
|
|
468
|
-
printHelp(error);
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
return Object.assign({}, data, {
|
|
472
|
-
onError: (error) => {
|
|
473
|
-
print.err(error.message);
|
|
474
|
-
process.exit(1);
|
|
475
|
-
},
|
|
476
|
-
rest,
|
|
477
|
-
nonOptions
|
|
478
|
-
});
|
|
479
|
-
|
|
480
|
-
})().then(...resultArguments);
|
|
481
|
-
}
|
|
482
|
-
};
|
|
483
|
-
|
|
484
|
-
return result;
|
|
485
|
-
|
|
486
|
-
};
|
|
487
|
-
|
|
488
|
-
export default argumentsParser;
|
|
38
|
+
export default typeof process.env.AUTOCOMPLETE_INDEX !== 'undefined' ? autocomplete() : argumentsParser;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//
|
|
2
|
+
// autocomplete.js
|
|
3
|
+
// @trenskow/arguments-parser
|
|
4
|
+
//
|
|
5
|
+
// Created by Kristian Trenskow on 2028/08/04
|
|
6
|
+
// See license in LICENSE.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
export default () => ({
|
|
10
|
+
phase: 'pre',
|
|
11
|
+
supportsType: () => true,
|
|
12
|
+
validatorsForType: () => ({
|
|
13
|
+
autocomplete: ['array', 'function']
|
|
14
|
+
}),
|
|
15
|
+
validate: (data) => data,
|
|
16
|
+
formalize: (data) => {
|
|
17
|
+
|
|
18
|
+
if (!(Array.isArray(data) && data.every((data) => typeof data === 'string')) && typeof data !== 'function') {
|
|
19
|
+
throw new Error('Must be a string or a function.');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return data;
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//
|
|
2
|
+
// dummies.js
|
|
3
|
+
// @trenskow/arguments-parser
|
|
4
|
+
//
|
|
5
|
+
// Created by Kristian Trenskow on 2028/08/04
|
|
6
|
+
// See license in LICENSE.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
export default () => ({
|
|
10
|
+
phase: 'pre',
|
|
11
|
+
supportsType: () => true,
|
|
12
|
+
validatorsForType: () => ({
|
|
13
|
+
description: ['string'],
|
|
14
|
+
defaultDescription: ['string'],
|
|
15
|
+
secret: ['boolean'],
|
|
16
|
+
short: ['string']
|
|
17
|
+
}),
|
|
18
|
+
validate: (data) => data,
|
|
19
|
+
formalize: (schema) => schema
|
|
20
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//
|
|
2
|
+
// hints.js
|
|
3
|
+
// @trenskow/arguments-parser
|
|
4
|
+
//
|
|
5
|
+
// Created by Kristian Trenskow on 2028/08/04
|
|
6
|
+
// See license in LICENSE.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
export default () => ({
|
|
10
|
+
phase: 'pre',
|
|
11
|
+
supportsType: () => true,
|
|
12
|
+
validatorsForType: () => ({
|
|
13
|
+
hints: ['array', 'string']
|
|
14
|
+
}),
|
|
15
|
+
validate: (data) => data,
|
|
16
|
+
formalize: (data, _, schema) => {
|
|
17
|
+
|
|
18
|
+
if (!Array.isArray(data)) data = [data];
|
|
19
|
+
|
|
20
|
+
if (schema.errors.hints) {
|
|
21
|
+
data.push(schema.errors.hints);
|
|
22
|
+
delete schema.errors.hints;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (data.some((data) => typeof data !== 'string')) throw new Error('Must be a string.');
|
|
26
|
+
|
|
27
|
+
return data;
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//
|
|
2
|
+
// plugins.js
|
|
3
|
+
// @trenskow/arguments-parser
|
|
4
|
+
//
|
|
5
|
+
// Created by Kristian Trenskow on 2028/08/04
|
|
6
|
+
// See license in LICENSE.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
plugins
|
|
11
|
+
} from 'isvalid';
|
|
12
|
+
|
|
13
|
+
import autocomplete from './autocomplete.js';
|
|
14
|
+
import dummies from './dummies.js';
|
|
15
|
+
import hints from './hints.js';
|
|
16
|
+
|
|
17
|
+
export default () => {
|
|
18
|
+
plugins.use('argumentsParser.dummies', dummies);
|
|
19
|
+
plugins.use('argumentsParser.hints', hints);
|
|
20
|
+
plugins.use('argumentsParser.autocomplete', autocomplete);
|
|
21
|
+
};
|