yargs 15.3.1 → 15.4.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/CHANGELOG.md +21 -0
- package/LICENSE +2 -3
- package/README.md +5 -5
- package/build/lib/apply-extends.d.ts +2 -0
- package/build/lib/apply-extends.js +65 -0
- package/build/lib/argsert.d.ts +2 -0
- package/build/lib/argsert.js +65 -0
- package/build/lib/command.d.ts +64 -0
- package/build/lib/command.js +416 -0
- package/build/lib/common-types.d.ts +36 -0
- package/build/lib/common-types.js +25 -0
- package/build/lib/completion-templates.d.ts +2 -0
- package/{lib → build/lib}/completion-templates.js +6 -5
- package/build/lib/completion.d.ts +21 -0
- package/build/lib/completion.js +135 -0
- package/build/lib/is-promise.d.ts +1 -0
- package/build/lib/is-promise.js +9 -0
- package/build/lib/levenshtein.d.ts +1 -0
- package/{lib → build/lib}/levenshtein.js +33 -33
- package/build/lib/middleware.d.ts +10 -0
- package/build/lib/middleware.js +57 -0
- package/build/lib/obj-filter.d.ts +1 -0
- package/build/lib/obj-filter.js +14 -0
- package/build/lib/parse-command.d.ts +11 -0
- package/build/lib/parse-command.js +36 -0
- package/build/lib/process-argv.d.ts +2 -0
- package/build/lib/process-argv.js +31 -0
- package/build/lib/usage.d.ts +49 -0
- package/build/lib/usage.js +540 -0
- package/build/lib/validation.d.ts +34 -0
- package/build/lib/validation.js +330 -0
- package/build/lib/yargs.d.ts +274 -0
- package/build/lib/yargs.js +1190 -0
- package/build/lib/yerror.d.ts +4 -0
- package/build/lib/yerror.js +11 -0
- package/index.js +1 -1
- package/locales/ja.json +6 -4
- package/package.json +26 -13
- package/yargs.js +2 -1291
- package/lib/apply-extends.js +0 -67
- package/lib/argsert.js +0 -68
- package/lib/command.js +0 -462
- package/lib/completion.js +0 -132
- package/lib/is-promise.js +0 -3
- package/lib/middleware.js +0 -64
- package/lib/obj-filter.js +0 -11
- package/lib/process-argv.js +0 -34
- package/lib/usage.js +0 -571
- package/lib/validation.js +0 -394
- package/lib/yerror.js +0 -11
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isCommandBuilderCallback = exports.isCommandBuilderDefinition = exports.isCommandHandlerDefinition = exports.command = void 0;
|
|
4
|
+
const common_types_1 = require("./common-types");
|
|
5
|
+
const is_promise_1 = require("./is-promise");
|
|
6
|
+
const middleware_1 = require("./middleware");
|
|
7
|
+
const parse_command_1 = require("./parse-command");
|
|
8
|
+
const path = require("path");
|
|
9
|
+
const util_1 = require("util");
|
|
10
|
+
const yargs_1 = require("./yargs");
|
|
11
|
+
const requireDirectory = require("require-directory");
|
|
12
|
+
const whichModule = require("which-module");
|
|
13
|
+
const Parser = require("yargs-parser");
|
|
14
|
+
const DEFAULT_MARKER = /(^\*)|(^\$0)/;
|
|
15
|
+
// handles parsing positional arguments,
|
|
16
|
+
// and populating argv with said positional
|
|
17
|
+
// arguments.
|
|
18
|
+
function command(yargs, usage, validation, globalMiddleware = []) {
|
|
19
|
+
const self = {};
|
|
20
|
+
let handlers = {};
|
|
21
|
+
let aliasMap = {};
|
|
22
|
+
let defaultCommand;
|
|
23
|
+
self.addHandler = function addHandler(cmd, description, builder, handler, commandMiddleware, deprecated) {
|
|
24
|
+
let aliases = [];
|
|
25
|
+
const middlewares = middleware_1.commandMiddlewareFactory(commandMiddleware);
|
|
26
|
+
handler = handler || (() => { });
|
|
27
|
+
if (Array.isArray(cmd)) {
|
|
28
|
+
aliases = cmd.slice(1);
|
|
29
|
+
cmd = cmd[0];
|
|
30
|
+
}
|
|
31
|
+
else if (isCommandHandlerDefinition(cmd)) {
|
|
32
|
+
let command = (Array.isArray(cmd.command) || typeof cmd.command === 'string') ? cmd.command : moduleName(cmd);
|
|
33
|
+
if (cmd.aliases)
|
|
34
|
+
command = [].concat(command).concat(cmd.aliases);
|
|
35
|
+
self.addHandler(command, extractDesc(cmd), cmd.builder, cmd.handler, cmd.middlewares, cmd.deprecated);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// allow a module to be provided instead of separate builder and handler
|
|
39
|
+
if (isCommandBuilderDefinition(builder)) {
|
|
40
|
+
self.addHandler([cmd].concat(aliases), description, builder.builder, builder.handler, builder.middlewares, builder.deprecated);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// parse positionals out of cmd string
|
|
44
|
+
const parsedCommand = parse_command_1.parseCommand(cmd);
|
|
45
|
+
// remove positional args from aliases only
|
|
46
|
+
aliases = aliases.map(alias => parse_command_1.parseCommand(alias).cmd);
|
|
47
|
+
// check for default and filter out '*''
|
|
48
|
+
let isDefault = false;
|
|
49
|
+
const parsedAliases = [parsedCommand.cmd].concat(aliases).filter((c) => {
|
|
50
|
+
if (DEFAULT_MARKER.test(c)) {
|
|
51
|
+
isDefault = true;
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
});
|
|
56
|
+
// standardize on $0 for default command.
|
|
57
|
+
if (parsedAliases.length === 0 && isDefault)
|
|
58
|
+
parsedAliases.push('$0');
|
|
59
|
+
// shift cmd and aliases after filtering out '*'
|
|
60
|
+
if (isDefault) {
|
|
61
|
+
parsedCommand.cmd = parsedAliases[0];
|
|
62
|
+
aliases = parsedAliases.slice(1);
|
|
63
|
+
cmd = cmd.replace(DEFAULT_MARKER, parsedCommand.cmd);
|
|
64
|
+
}
|
|
65
|
+
// populate aliasMap
|
|
66
|
+
aliases.forEach((alias) => {
|
|
67
|
+
aliasMap[alias] = parsedCommand.cmd;
|
|
68
|
+
});
|
|
69
|
+
if (description !== false) {
|
|
70
|
+
usage.command(cmd, description, isDefault, aliases, deprecated);
|
|
71
|
+
}
|
|
72
|
+
handlers[parsedCommand.cmd] = {
|
|
73
|
+
original: cmd,
|
|
74
|
+
description,
|
|
75
|
+
handler,
|
|
76
|
+
builder: builder || {},
|
|
77
|
+
middlewares,
|
|
78
|
+
deprecated,
|
|
79
|
+
demanded: parsedCommand.demanded,
|
|
80
|
+
optional: parsedCommand.optional
|
|
81
|
+
};
|
|
82
|
+
if (isDefault)
|
|
83
|
+
defaultCommand = handlers[parsedCommand.cmd];
|
|
84
|
+
};
|
|
85
|
+
self.addDirectory = function addDirectory(dir, context, req, callerFile, opts) {
|
|
86
|
+
opts = opts || {};
|
|
87
|
+
// disable recursion to support nested directories of subcommands
|
|
88
|
+
if (typeof opts.recurse !== 'boolean')
|
|
89
|
+
opts.recurse = false;
|
|
90
|
+
// exclude 'json', 'coffee' from require-directory defaults
|
|
91
|
+
if (!Array.isArray(opts.extensions))
|
|
92
|
+
opts.extensions = ['js'];
|
|
93
|
+
// allow consumer to define their own visitor function
|
|
94
|
+
const parentVisit = typeof opts.visit === 'function' ? opts.visit : (o) => o;
|
|
95
|
+
// call addHandler via visitor function
|
|
96
|
+
opts.visit = function visit(obj, joined, filename) {
|
|
97
|
+
const visited = parentVisit(obj, joined, filename);
|
|
98
|
+
// allow consumer to skip modules with their own visitor
|
|
99
|
+
if (visited) {
|
|
100
|
+
// check for cyclic reference
|
|
101
|
+
// each command file path should only be seen once per execution
|
|
102
|
+
if (~context.files.indexOf(joined))
|
|
103
|
+
return visited;
|
|
104
|
+
// keep track of visited files in context.files
|
|
105
|
+
context.files.push(joined);
|
|
106
|
+
self.addHandler(visited);
|
|
107
|
+
}
|
|
108
|
+
return visited;
|
|
109
|
+
};
|
|
110
|
+
requireDirectory({ require: req, filename: callerFile }, dir, opts);
|
|
111
|
+
};
|
|
112
|
+
// lookup module object from require()d command and derive name
|
|
113
|
+
// if module was not require()d and no name given, throw error
|
|
114
|
+
function moduleName(obj) {
|
|
115
|
+
const mod = whichModule(obj);
|
|
116
|
+
if (!mod)
|
|
117
|
+
throw new Error(`No command name given for module: ${util_1.inspect(obj)}`);
|
|
118
|
+
return commandFromFilename(mod.filename);
|
|
119
|
+
}
|
|
120
|
+
// derive command name from filename
|
|
121
|
+
function commandFromFilename(filename) {
|
|
122
|
+
return path.basename(filename, path.extname(filename));
|
|
123
|
+
}
|
|
124
|
+
function extractDesc({ describe, description, desc }) {
|
|
125
|
+
for (const test of [describe, description, desc]) {
|
|
126
|
+
if (typeof test === 'string' || test === false)
|
|
127
|
+
return test;
|
|
128
|
+
common_types_1.assertNotStrictEqual(test, true);
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
self.getCommands = () => Object.keys(handlers).concat(Object.keys(aliasMap));
|
|
133
|
+
self.getCommandHandlers = () => handlers;
|
|
134
|
+
self.hasDefaultCommand = () => !!defaultCommand;
|
|
135
|
+
self.runCommand = function runCommand(command, yargs, parsed, commandIndex) {
|
|
136
|
+
let aliases = parsed.aliases;
|
|
137
|
+
const commandHandler = handlers[command] || handlers[aliasMap[command]] || defaultCommand;
|
|
138
|
+
const currentContext = yargs.getContext();
|
|
139
|
+
let numFiles = currentContext.files.length;
|
|
140
|
+
const parentCommands = currentContext.commands.slice();
|
|
141
|
+
// what does yargs look like after the builder is run?
|
|
142
|
+
let innerArgv = parsed.argv;
|
|
143
|
+
let positionalMap = {};
|
|
144
|
+
if (command) {
|
|
145
|
+
currentContext.commands.push(command);
|
|
146
|
+
currentContext.fullCommands.push(commandHandler.original);
|
|
147
|
+
}
|
|
148
|
+
const builder = commandHandler.builder;
|
|
149
|
+
if (isCommandBuilderCallback(builder)) {
|
|
150
|
+
// a function can be provided, which builds
|
|
151
|
+
// up a yargs chain and possibly returns it.
|
|
152
|
+
const builderOutput = builder(yargs.reset(parsed.aliases));
|
|
153
|
+
const innerYargs = yargs_1.isYargsInstance(builderOutput) ? builderOutput : yargs;
|
|
154
|
+
if (shouldUpdateUsage(innerYargs)) {
|
|
155
|
+
innerYargs.getUsageInstance().usage(usageFromParentCommandsCommandHandler(parentCommands, commandHandler), commandHandler.description);
|
|
156
|
+
}
|
|
157
|
+
innerArgv = innerYargs._parseArgs(null, null, true, commandIndex);
|
|
158
|
+
aliases = innerYargs.parsed.aliases;
|
|
159
|
+
}
|
|
160
|
+
else if (isCommandBuilderOptionDefinitions(builder)) {
|
|
161
|
+
// as a short hand, an object can instead be provided, specifying
|
|
162
|
+
// the options that a command takes.
|
|
163
|
+
const innerYargs = yargs.reset(parsed.aliases);
|
|
164
|
+
if (shouldUpdateUsage(innerYargs)) {
|
|
165
|
+
innerYargs.getUsageInstance().usage(usageFromParentCommandsCommandHandler(parentCommands, commandHandler), commandHandler.description);
|
|
166
|
+
}
|
|
167
|
+
Object.keys(commandHandler.builder).forEach((key) => {
|
|
168
|
+
innerYargs.option(key, builder[key]);
|
|
169
|
+
});
|
|
170
|
+
innerArgv = innerYargs._parseArgs(null, null, true, commandIndex);
|
|
171
|
+
aliases = innerYargs.parsed.aliases;
|
|
172
|
+
}
|
|
173
|
+
if (!yargs._hasOutput()) {
|
|
174
|
+
positionalMap = populatePositionals(commandHandler, innerArgv, currentContext);
|
|
175
|
+
}
|
|
176
|
+
const middlewares = globalMiddleware.slice(0).concat(commandHandler.middlewares);
|
|
177
|
+
middleware_1.applyMiddleware(innerArgv, yargs, middlewares, true);
|
|
178
|
+
// we apply validation post-hoc, so that custom
|
|
179
|
+
// checks get passed populated positional arguments.
|
|
180
|
+
if (!yargs._hasOutput()) {
|
|
181
|
+
yargs._runValidation(innerArgv, aliases, positionalMap, yargs.parsed.error, !command);
|
|
182
|
+
}
|
|
183
|
+
if (commandHandler.handler && !yargs._hasOutput()) {
|
|
184
|
+
yargs._setHasOutput();
|
|
185
|
+
// to simplify the parsing of positionals in commands,
|
|
186
|
+
// we temporarily populate '--' rather than _, with arguments
|
|
187
|
+
const populateDoubleDash = !!yargs.getOptions().configuration['populate--'];
|
|
188
|
+
if (!populateDoubleDash)
|
|
189
|
+
yargs._copyDoubleDash(innerArgv);
|
|
190
|
+
innerArgv = middleware_1.applyMiddleware(innerArgv, yargs, middlewares, false);
|
|
191
|
+
let handlerResult;
|
|
192
|
+
if (is_promise_1.isPromise(innerArgv)) {
|
|
193
|
+
handlerResult = innerArgv.then(argv => commandHandler.handler(argv));
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
handlerResult = commandHandler.handler(innerArgv);
|
|
197
|
+
}
|
|
198
|
+
const handlerFinishCommand = yargs.getHandlerFinishCommand();
|
|
199
|
+
if (is_promise_1.isPromise(handlerResult)) {
|
|
200
|
+
yargs.getUsageInstance().cacheHelpMessage();
|
|
201
|
+
handlerResult
|
|
202
|
+
.then(value => {
|
|
203
|
+
if (handlerFinishCommand) {
|
|
204
|
+
handlerFinishCommand(value);
|
|
205
|
+
}
|
|
206
|
+
})
|
|
207
|
+
.catch(error => {
|
|
208
|
+
try {
|
|
209
|
+
yargs.getUsageInstance().fail(null, error);
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
// fail's throwing would cause an unhandled rejection.
|
|
213
|
+
}
|
|
214
|
+
})
|
|
215
|
+
.then(() => {
|
|
216
|
+
yargs.getUsageInstance().clearCachedHelpMessage();
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
if (handlerFinishCommand) {
|
|
221
|
+
handlerFinishCommand(handlerResult);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (command) {
|
|
226
|
+
currentContext.commands.pop();
|
|
227
|
+
currentContext.fullCommands.pop();
|
|
228
|
+
}
|
|
229
|
+
numFiles = currentContext.files.length - numFiles;
|
|
230
|
+
if (numFiles > 0)
|
|
231
|
+
currentContext.files.splice(numFiles * -1, numFiles);
|
|
232
|
+
return innerArgv;
|
|
233
|
+
};
|
|
234
|
+
function shouldUpdateUsage(yargs) {
|
|
235
|
+
return !yargs.getUsageInstance().getUsageDisabled() &&
|
|
236
|
+
yargs.getUsageInstance().getUsage().length === 0;
|
|
237
|
+
}
|
|
238
|
+
function usageFromParentCommandsCommandHandler(parentCommands, commandHandler) {
|
|
239
|
+
const c = DEFAULT_MARKER.test(commandHandler.original) ? commandHandler.original.replace(DEFAULT_MARKER, '').trim() : commandHandler.original;
|
|
240
|
+
const pc = parentCommands.filter((c) => { return !DEFAULT_MARKER.test(c); });
|
|
241
|
+
pc.push(c);
|
|
242
|
+
return `$0 ${pc.join(' ')}`;
|
|
243
|
+
}
|
|
244
|
+
self.runDefaultBuilderOn = function (yargs) {
|
|
245
|
+
common_types_1.assertNotStrictEqual(defaultCommand, undefined);
|
|
246
|
+
if (shouldUpdateUsage(yargs)) {
|
|
247
|
+
// build the root-level command string from the default string.
|
|
248
|
+
const commandString = DEFAULT_MARKER.test(defaultCommand.original)
|
|
249
|
+
? defaultCommand.original : defaultCommand.original.replace(/^[^[\]<>]*/, '$0 ');
|
|
250
|
+
yargs.getUsageInstance().usage(commandString, defaultCommand.description);
|
|
251
|
+
}
|
|
252
|
+
const builder = defaultCommand.builder;
|
|
253
|
+
if (isCommandBuilderCallback(builder)) {
|
|
254
|
+
builder(yargs);
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
Object.keys(builder).forEach((key) => {
|
|
258
|
+
yargs.option(key, builder[key]);
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
// transcribe all positional arguments "command <foo> <bar> [apple]"
|
|
263
|
+
// onto argv.
|
|
264
|
+
function populatePositionals(commandHandler, argv, context) {
|
|
265
|
+
argv._ = argv._.slice(context.commands.length); // nuke the current commands
|
|
266
|
+
const demanded = commandHandler.demanded.slice(0);
|
|
267
|
+
const optional = commandHandler.optional.slice(0);
|
|
268
|
+
const positionalMap = {};
|
|
269
|
+
validation.positionalCount(demanded.length, argv._.length);
|
|
270
|
+
while (demanded.length) {
|
|
271
|
+
const demand = demanded.shift();
|
|
272
|
+
populatePositional(demand, argv, positionalMap);
|
|
273
|
+
}
|
|
274
|
+
while (optional.length) {
|
|
275
|
+
const maybe = optional.shift();
|
|
276
|
+
populatePositional(maybe, argv, positionalMap);
|
|
277
|
+
}
|
|
278
|
+
argv._ = context.commands.concat(argv._);
|
|
279
|
+
postProcessPositionals(argv, positionalMap, self.cmdToParseOptions(commandHandler.original));
|
|
280
|
+
return positionalMap;
|
|
281
|
+
}
|
|
282
|
+
function populatePositional(positional, argv, positionalMap) {
|
|
283
|
+
const cmd = positional.cmd[0];
|
|
284
|
+
if (positional.variadic) {
|
|
285
|
+
positionalMap[cmd] = argv._.splice(0).map(String);
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
if (argv._.length)
|
|
289
|
+
positionalMap[cmd] = [String(argv._.shift())];
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// we run yargs-parser against the positional arguments
|
|
293
|
+
// applying the same parsing logic used for flags.
|
|
294
|
+
function postProcessPositionals(argv, positionalMap, parseOptions) {
|
|
295
|
+
// combine the parsing hints we've inferred from the command
|
|
296
|
+
// string with explicitly configured parsing hints.
|
|
297
|
+
const options = Object.assign({}, yargs.getOptions());
|
|
298
|
+
options.default = Object.assign(parseOptions.default, options.default);
|
|
299
|
+
for (const key of Object.keys(parseOptions.alias)) {
|
|
300
|
+
options.alias[key] = (options.alias[key] || []).concat(parseOptions.alias[key]);
|
|
301
|
+
}
|
|
302
|
+
options.array = options.array.concat(parseOptions.array);
|
|
303
|
+
delete options.config; // don't load config when processing positionals.
|
|
304
|
+
const unparsed = [];
|
|
305
|
+
Object.keys(positionalMap).forEach((key) => {
|
|
306
|
+
positionalMap[key].map((value) => {
|
|
307
|
+
if (options.configuration['unknown-options-as-args'])
|
|
308
|
+
options.key[key] = true;
|
|
309
|
+
unparsed.push(`--${key}`);
|
|
310
|
+
unparsed.push(value);
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
// short-circuit parse.
|
|
314
|
+
if (!unparsed.length)
|
|
315
|
+
return;
|
|
316
|
+
const config = Object.assign({}, options.configuration, {
|
|
317
|
+
'populate--': true
|
|
318
|
+
});
|
|
319
|
+
const parsed = Parser.detailed(unparsed, Object.assign({}, options, {
|
|
320
|
+
configuration: config
|
|
321
|
+
}));
|
|
322
|
+
if (parsed.error) {
|
|
323
|
+
yargs.getUsageInstance().fail(parsed.error.message, parsed.error);
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
// only copy over positional keys (don't overwrite
|
|
327
|
+
// flag arguments that were already parsed).
|
|
328
|
+
const positionalKeys = Object.keys(positionalMap);
|
|
329
|
+
Object.keys(positionalMap).forEach((key) => {
|
|
330
|
+
positionalKeys.push(...parsed.aliases[key]);
|
|
331
|
+
});
|
|
332
|
+
Object.keys(parsed.argv).forEach((key) => {
|
|
333
|
+
if (positionalKeys.indexOf(key) !== -1) {
|
|
334
|
+
// any new aliases need to be placed in positionalMap, which
|
|
335
|
+
// is used for validation.
|
|
336
|
+
if (!positionalMap[key])
|
|
337
|
+
positionalMap[key] = parsed.argv[key];
|
|
338
|
+
argv[key] = parsed.argv[key];
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
self.cmdToParseOptions = function (cmdString) {
|
|
344
|
+
const parseOptions = {
|
|
345
|
+
array: [],
|
|
346
|
+
default: {},
|
|
347
|
+
alias: {},
|
|
348
|
+
demand: {}
|
|
349
|
+
};
|
|
350
|
+
const parsed = parse_command_1.parseCommand(cmdString);
|
|
351
|
+
parsed.demanded.forEach((d) => {
|
|
352
|
+
const [cmd, ...aliases] = d.cmd;
|
|
353
|
+
if (d.variadic) {
|
|
354
|
+
parseOptions.array.push(cmd);
|
|
355
|
+
parseOptions.default[cmd] = [];
|
|
356
|
+
}
|
|
357
|
+
parseOptions.alias[cmd] = aliases;
|
|
358
|
+
parseOptions.demand[cmd] = true;
|
|
359
|
+
});
|
|
360
|
+
parsed.optional.forEach((o) => {
|
|
361
|
+
const [cmd, ...aliases] = o.cmd;
|
|
362
|
+
if (o.variadic) {
|
|
363
|
+
parseOptions.array.push(cmd);
|
|
364
|
+
parseOptions.default[cmd] = [];
|
|
365
|
+
}
|
|
366
|
+
parseOptions.alias[cmd] = aliases;
|
|
367
|
+
});
|
|
368
|
+
return parseOptions;
|
|
369
|
+
};
|
|
370
|
+
self.reset = () => {
|
|
371
|
+
handlers = {};
|
|
372
|
+
aliasMap = {};
|
|
373
|
+
defaultCommand = undefined;
|
|
374
|
+
return self;
|
|
375
|
+
};
|
|
376
|
+
// used by yargs.parse() to freeze
|
|
377
|
+
// the state of commands such that
|
|
378
|
+
// we can apply .parse() multiple times
|
|
379
|
+
// with the same yargs instance.
|
|
380
|
+
const frozens = [];
|
|
381
|
+
self.freeze = () => {
|
|
382
|
+
frozens.push({
|
|
383
|
+
handlers,
|
|
384
|
+
aliasMap,
|
|
385
|
+
defaultCommand
|
|
386
|
+
});
|
|
387
|
+
};
|
|
388
|
+
self.unfreeze = () => {
|
|
389
|
+
const frozen = frozens.pop();
|
|
390
|
+
common_types_1.assertNotStrictEqual(frozen, undefined);
|
|
391
|
+
({
|
|
392
|
+
handlers,
|
|
393
|
+
aliasMap,
|
|
394
|
+
defaultCommand
|
|
395
|
+
} = frozen);
|
|
396
|
+
};
|
|
397
|
+
return self;
|
|
398
|
+
}
|
|
399
|
+
exports.command = command;
|
|
400
|
+
function isCommandHandlerDefinition(cmd) {
|
|
401
|
+
return typeof cmd === 'object';
|
|
402
|
+
}
|
|
403
|
+
exports.isCommandHandlerDefinition = isCommandHandlerDefinition;
|
|
404
|
+
function isCommandBuilderDefinition(builder) {
|
|
405
|
+
return typeof builder === 'object' &&
|
|
406
|
+
!!builder.builder &&
|
|
407
|
+
typeof builder.handler === 'function';
|
|
408
|
+
}
|
|
409
|
+
exports.isCommandBuilderDefinition = isCommandBuilderDefinition;
|
|
410
|
+
function isCommandBuilderCallback(builder) {
|
|
411
|
+
return typeof builder === 'function';
|
|
412
|
+
}
|
|
413
|
+
exports.isCommandBuilderCallback = isCommandBuilderCallback;
|
|
414
|
+
function isCommandBuilderOptionDefinitions(builder) {
|
|
415
|
+
return typeof builder === 'object';
|
|
416
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An object whose all properties have the same type.
|
|
3
|
+
*/
|
|
4
|
+
export declare type Dictionary<T = any> = {
|
|
5
|
+
[key: string]: T;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Returns the keys of T that match Dictionary<U> and are not arrays.
|
|
9
|
+
*/
|
|
10
|
+
export declare type DictionaryKeyof<T, U = any> = Exclude<KeyOf<T, Dictionary<U>>, KeyOf<T, any[]>>;
|
|
11
|
+
/**
|
|
12
|
+
* Returns the keys of T that match U.
|
|
13
|
+
*/
|
|
14
|
+
export declare type KeyOf<T, U> = Exclude<{
|
|
15
|
+
[K in keyof T]: T[K] extends U ? K : never;
|
|
16
|
+
}[keyof T], undefined>;
|
|
17
|
+
/**
|
|
18
|
+
* An array whose first element is not undefined.
|
|
19
|
+
*/
|
|
20
|
+
export declare type NotEmptyArray<T = any> = [T, ...T[]];
|
|
21
|
+
/**
|
|
22
|
+
* Returns the type of a Dictionary or array values.
|
|
23
|
+
*/
|
|
24
|
+
export declare type ValueOf<T> = T extends (infer U)[] ? U : T[keyof T];
|
|
25
|
+
/**
|
|
26
|
+
* Typing wrapper around assert.notStrictEqual()
|
|
27
|
+
*/
|
|
28
|
+
export declare function assertNotStrictEqual<N, T>(actual: T | N, expected: N, message?: string | Error): asserts actual is Exclude<T, N>;
|
|
29
|
+
/**
|
|
30
|
+
* Asserts actual is a single key, not a key array or a key map.
|
|
31
|
+
*/
|
|
32
|
+
export declare function assertSingleKey(actual: string | string[] | Dictionary): asserts actual is string;
|
|
33
|
+
/**
|
|
34
|
+
* Typing wrapper around Object.keys()
|
|
35
|
+
*/
|
|
36
|
+
export declare function objectKeys<T>(object: T): (keyof T)[];
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.objectKeys = exports.assertSingleKey = exports.assertNotStrictEqual = void 0;
|
|
4
|
+
const assert_1 = require("assert");
|
|
5
|
+
/**
|
|
6
|
+
* Typing wrapper around assert.notStrictEqual()
|
|
7
|
+
*/
|
|
8
|
+
function assertNotStrictEqual(actual, expected, message) {
|
|
9
|
+
assert_1.notStrictEqual(actual, expected, message);
|
|
10
|
+
}
|
|
11
|
+
exports.assertNotStrictEqual = assertNotStrictEqual;
|
|
12
|
+
/**
|
|
13
|
+
* Asserts actual is a single key, not a key array or a key map.
|
|
14
|
+
*/
|
|
15
|
+
function assertSingleKey(actual) {
|
|
16
|
+
assert_1.strictEqual(typeof actual, 'string');
|
|
17
|
+
}
|
|
18
|
+
exports.assertSingleKey = assertSingleKey;
|
|
19
|
+
/**
|
|
20
|
+
* Typing wrapper around Object.keys()
|
|
21
|
+
*/
|
|
22
|
+
function objectKeys(object) {
|
|
23
|
+
return Object.keys(object);
|
|
24
|
+
}
|
|
25
|
+
exports.objectKeys = objectKeys;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const completionShTemplate = "###-begin-{{app_name}}-completions-###\n#\n# yargs command completion script\n#\n# Installation: {{app_path}} {{completion_command}} >> ~/.bashrc\n# or {{app_path}} {{completion_command}} >> ~/.bash_profile on OSX.\n#\n_yargs_completions()\n{\n local cur_word args type_list\n\n cur_word=\"${COMP_WORDS[COMP_CWORD]}\"\n args=(\"${COMP_WORDS[@]}\")\n\n # ask yargs to generate completions.\n type_list=$({{app_path}} --get-yargs-completions \"${args[@]}\")\n\n COMPREPLY=( $(compgen -W \"${type_list}\" -- ${cur_word}) )\n\n # if no match was found, fall back to filename completion\n if [ ${#COMPREPLY[@]} -eq 0 ]; then\n COMPREPLY=()\n fi\n\n return 0\n}\ncomplete -o default -F _yargs_completions {{app_name}}\n###-end-{{app_name}}-completions-###\n";
|
|
2
|
+
export declare const completionZshTemplate = "###-begin-{{app_name}}-completions-###\n#\n# yargs command completion script\n#\n# Installation: {{app_path}} {{completion_command}} >> ~/.zshrc\n# or {{app_path}} {{completion_command}} >> ~/.zsh_profile on OSX.\n#\n_{{app_name}}_yargs_completions()\n{\n local reply\n local si=$IFS\n IFS=$'\n' reply=($(COMP_CWORD=\"$((CURRENT-1))\" COMP_LINE=\"$BUFFER\" COMP_POINT=\"$CURSOR\" {{app_path}} --get-yargs-completions \"${words[@]}\"))\n IFS=$si\n _describe 'values' reply\n}\ncompdef _{{app_name}}_yargs_completions {{app_name}}\n###-end-{{app_name}}-completions-###\n";
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.completionZshTemplate = exports.completionShTemplate = void 0;
|
|
4
|
+
exports.completionShTemplate = `###-begin-{{app_name}}-completions-###
|
|
3
5
|
#
|
|
4
6
|
# yargs command completion script
|
|
5
7
|
#
|
|
@@ -27,8 +29,7 @@ _yargs_completions()
|
|
|
27
29
|
}
|
|
28
30
|
complete -o default -F _yargs_completions {{app_name}}
|
|
29
31
|
###-end-{{app_name}}-completions-###
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
`;
|
|
32
33
|
exports.completionZshTemplate = `###-begin-{{app_name}}-completions-###
|
|
33
34
|
#
|
|
34
35
|
# yargs command completion script
|
|
@@ -46,4 +47,4 @@ _{{app_name}}_yargs_completions()
|
|
|
46
47
|
}
|
|
47
48
|
compdef _{{app_name}}_yargs_completions {{app_name}}
|
|
48
49
|
###-end-{{app_name}}-completions-###
|
|
49
|
-
|
|
50
|
+
`;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CommandInstance } from './command';
|
|
2
|
+
import { UsageInstance } from './usage';
|
|
3
|
+
import { YargsInstance } from './yargs';
|
|
4
|
+
import { Arguments, DetailedArguments } from 'yargs-parser';
|
|
5
|
+
export declare function completion(yargs: YargsInstance, usage: UsageInstance, command: CommandInstance): CompletionInstance;
|
|
6
|
+
/** Instance of the completion module. */
|
|
7
|
+
export interface CompletionInstance {
|
|
8
|
+
completionKey: string;
|
|
9
|
+
generateCompletionScript($0: string, cmd: string): string;
|
|
10
|
+
getCompletion(args: string[], done: (completions: string[]) => any): any;
|
|
11
|
+
registerFunction(fn: CompletionFunction): void;
|
|
12
|
+
setParsed(parsed: DetailedArguments): void;
|
|
13
|
+
}
|
|
14
|
+
export declare type CompletionFunction = SyncCompletionFunction | AsyncCompletionFunction;
|
|
15
|
+
interface SyncCompletionFunction {
|
|
16
|
+
(current: string, argv: Arguments): string[] | Promise<string[]>;
|
|
17
|
+
}
|
|
18
|
+
interface AsyncCompletionFunction {
|
|
19
|
+
(current: string, argv: Arguments, done: (completions: string[]) => any): any;
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.completion = void 0;
|
|
4
|
+
const command_1 = require("./command");
|
|
5
|
+
const templates = require("./completion-templates");
|
|
6
|
+
const is_promise_1 = require("./is-promise");
|
|
7
|
+
const parse_command_1 = require("./parse-command");
|
|
8
|
+
const path = require("path");
|
|
9
|
+
const common_types_1 = require("./common-types");
|
|
10
|
+
// add bash completions to your
|
|
11
|
+
// yargs-powered applications.
|
|
12
|
+
function completion(yargs, usage, command) {
|
|
13
|
+
const self = {
|
|
14
|
+
completionKey: 'get-yargs-completions'
|
|
15
|
+
};
|
|
16
|
+
let aliases;
|
|
17
|
+
self.setParsed = function setParsed(parsed) {
|
|
18
|
+
aliases = parsed.aliases;
|
|
19
|
+
};
|
|
20
|
+
const zshShell = (process.env.SHELL && process.env.SHELL.indexOf('zsh') !== -1) ||
|
|
21
|
+
(process.env.ZSH_NAME && process.env.ZSH_NAME.indexOf('zsh') !== -1);
|
|
22
|
+
// get a list of completion commands.
|
|
23
|
+
// 'args' is the array of strings from the line to be completed
|
|
24
|
+
self.getCompletion = function getCompletion(args, done) {
|
|
25
|
+
const completions = [];
|
|
26
|
+
const current = args.length ? args[args.length - 1] : '';
|
|
27
|
+
const argv = yargs.parse(args, true);
|
|
28
|
+
const parentCommands = yargs.getContext().commands;
|
|
29
|
+
// a custom completion function can be provided
|
|
30
|
+
// to completion().
|
|
31
|
+
function runCompletionFunction(argv) {
|
|
32
|
+
common_types_1.assertNotStrictEqual(completionFunction, null);
|
|
33
|
+
if (isSyncCompletionFunction(completionFunction)) {
|
|
34
|
+
const result = completionFunction(current, argv);
|
|
35
|
+
// promise based completion function.
|
|
36
|
+
if (is_promise_1.isPromise(result)) {
|
|
37
|
+
return result.then((list) => {
|
|
38
|
+
process.nextTick(() => { done(list); });
|
|
39
|
+
}).catch((err) => {
|
|
40
|
+
process.nextTick(() => { throw err; });
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// synchronous completion function.
|
|
44
|
+
return done(result);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// asynchronous completion function
|
|
48
|
+
return completionFunction(current, argv, (completions) => {
|
|
49
|
+
done(completions);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (completionFunction) {
|
|
54
|
+
return is_promise_1.isPromise(argv) ? argv.then(runCompletionFunction) : runCompletionFunction(argv);
|
|
55
|
+
}
|
|
56
|
+
const handlers = command.getCommandHandlers();
|
|
57
|
+
for (let i = 0, ii = args.length; i < ii; ++i) {
|
|
58
|
+
if (handlers[args[i]] && handlers[args[i]].builder) {
|
|
59
|
+
const builder = handlers[args[i]].builder;
|
|
60
|
+
if (command_1.isCommandBuilderCallback(builder)) {
|
|
61
|
+
const y = yargs.reset();
|
|
62
|
+
builder(y);
|
|
63
|
+
return y.argv;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (!current.match(/^-/) && parentCommands[parentCommands.length - 1] !== current) {
|
|
68
|
+
usage.getCommands().forEach((usageCommand) => {
|
|
69
|
+
const commandName = parse_command_1.parseCommand(usageCommand[0]).cmd;
|
|
70
|
+
if (args.indexOf(commandName) === -1) {
|
|
71
|
+
if (!zshShell) {
|
|
72
|
+
completions.push(commandName);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
const desc = usageCommand[1] || '';
|
|
76
|
+
completions.push(commandName.replace(/:/g, '\\:') + ':' + desc);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (current.match(/^-/) || (current === '' && completions.length === 0)) {
|
|
82
|
+
const descs = usage.getDescriptions();
|
|
83
|
+
const options = yargs.getOptions();
|
|
84
|
+
Object.keys(options.key).forEach((key) => {
|
|
85
|
+
const negable = !!options.configuration['boolean-negation'] && options.boolean.includes(key);
|
|
86
|
+
// If the key and its aliases aren't in 'args', add the key to 'completions'
|
|
87
|
+
let keyAndAliases = [key].concat(aliases[key] || []);
|
|
88
|
+
if (negable)
|
|
89
|
+
keyAndAliases = keyAndAliases.concat(keyAndAliases.map(key => `no-${key}`));
|
|
90
|
+
function completeOptionKey(key) {
|
|
91
|
+
const notInArgs = keyAndAliases.every(val => args.indexOf(`--${val}`) === -1);
|
|
92
|
+
if (notInArgs) {
|
|
93
|
+
const startsByTwoDashes = (s) => /^--/.test(s);
|
|
94
|
+
const isShortOption = (s) => /^[^0-9]$/.test(s);
|
|
95
|
+
const dashes = !startsByTwoDashes(current) && isShortOption(key) ? '-' : '--';
|
|
96
|
+
if (!zshShell) {
|
|
97
|
+
completions.push(dashes + key);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
const desc = descs[key] || '';
|
|
101
|
+
completions.push(dashes + `${key.replace(/:/g, '\\:')}:${desc.replace('__yargsString__:', '')}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
completeOptionKey(key);
|
|
106
|
+
if (negable && !!options.default[key])
|
|
107
|
+
completeOptionKey(`no-${key}`);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
done(completions);
|
|
111
|
+
};
|
|
112
|
+
// generate the completion script to add to your .bashrc.
|
|
113
|
+
self.generateCompletionScript = function generateCompletionScript($0, cmd) {
|
|
114
|
+
let script = zshShell ? templates.completionZshTemplate : templates.completionShTemplate;
|
|
115
|
+
const name = path.basename($0);
|
|
116
|
+
// add ./to applications not yet installed as bin.
|
|
117
|
+
if ($0.match(/\.js$/))
|
|
118
|
+
$0 = `./${$0}`;
|
|
119
|
+
script = script.replace(/{{app_name}}/g, name);
|
|
120
|
+
script = script.replace(/{{completion_command}}/g, cmd);
|
|
121
|
+
return script.replace(/{{app_path}}/g, $0);
|
|
122
|
+
};
|
|
123
|
+
// register a function to perform your own custom
|
|
124
|
+
// completions., this function can be either
|
|
125
|
+
// synchrnous or asynchronous.
|
|
126
|
+
let completionFunction = null;
|
|
127
|
+
self.registerFunction = (fn) => {
|
|
128
|
+
completionFunction = fn;
|
|
129
|
+
};
|
|
130
|
+
return self;
|
|
131
|
+
}
|
|
132
|
+
exports.completion = completion;
|
|
133
|
+
function isSyncCompletionFunction(completionFunction) {
|
|
134
|
+
return completionFunction.length < 3;
|
|
135
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isPromise<T>(maybePromise: T | Promise<T>): maybePromise is Promise<T>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isPromise = void 0;
|
|
4
|
+
function isPromise(maybePromise) {
|
|
5
|
+
return !!maybePromise &&
|
|
6
|
+
!!maybePromise.then &&
|
|
7
|
+
(typeof maybePromise.then === 'function');
|
|
8
|
+
}
|
|
9
|
+
exports.isPromise = isPromise;
|