UNPKG

23.9 kBJavaScriptView Raw
1'use strict';
2
3function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
4
5var events = _interopDefault(require('events'));
6var path = _interopDefault(require('path'));
7
8var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
9
10function unwrapExports (x) {
11 return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x.default : x;
12}
13
14function createCommonjsModule(fn, module) {
15 return module = { exports: {} }, fn(module, module.exports), module.exports;
16}
17
18const EQQ = /\s|=/;
19const FLAG = /^-{1,2}/;
20const PREFIX = /^--no-/i;
21
22function isBool(any) {
23 return typeof any === 'boolean';
24}
25
26function toArr(any) {
27 return Array.isArray(any) ? any : any == null ? [] : [any];
28}
29
30function toString(any) {
31 return any == null || any === true ? '' : String(any);
32}
33
34function toBool(any) {
35 return any === 'false' ? false : Boolean(any);
36}
37
38function toNum(any) {
39 let x = Number(any);
40 return !isBool(any) && (x * 0 === 0) ? x : any;
41}
42
43function getAlibi(names, arr) {
44 if (arr.length === 0) return arr;
45 let k, i = 0, len = arr.length, vals = [];
46 for (; i < len; i++) {
47 k = arr[i];
48 vals.push(k);
49 if (names[k] !== void 0) {
50 vals = vals.concat(names[k]);
51 }
52 }
53 return vals;
54}
55
56function typecast(key, val, strings, booleans) {
57 if (strings.indexOf(key) !== -1) return toString(val);
58 if (booleans.indexOf(key) !== -1) return toBool(val);
59 return toNum(val);
60}
61
62var lib = function(args, opts) {
63 args = args || [];
64 opts = opts || {};
65
66 opts.string = toArr(opts.string);
67 opts.boolean = toArr(opts.boolean);
68
69 const aliases = {};
70 let k, i, j, x, y, len, type;
71
72 if (opts.alias !== void 0) {
73 for (k in opts.alias) {
74 aliases[k] = toArr(opts.alias[k]);
75 len = aliases[k].length; // save length
76 for (i = 0; i < len; i++) {
77 x = aliases[k][i]; // alias's key name
78 aliases[x] = [k]; // set initial array
79 for (j = 0; j < len; j++) {
80 if (x !== aliases[k][j]) {
81 aliases[x].push(aliases[k][j]);
82 }
83 }
84 }
85 }
86 }
87
88 if (opts.default !== void 0) {
89 for (k in opts.default) {
90 type = typeof opts.default[k];
91 opts[type] = (opts[type] || []).concat(k);
92 }
93 }
94
95 // apply to all aliases
96 opts.string = getAlibi(aliases, opts.string);
97 opts.boolean = getAlibi(aliases, opts.boolean);
98
99 let idx = 0;
100 const out = { _: [] };
101
102 while (args[idx] !== void 0) {
103 let incr = 1;
104 const val = args[idx];
105
106 if (val === '--') {
107 out._ = out._.concat(args.slice(idx + 1));
108 break;
109 } else if (!FLAG.test(val)) {
110 out._.push(val);
111 } else if (PREFIX.test(val)) {
112 out[val.replace(PREFIX, '')] = false;
113 } else {
114 let tmp;
115 const segs = val.split(EQQ);
116 const isGroup = segs[0].charCodeAt(1) !== 45; // '-'
117
118 const flag = segs[0].substr(isGroup ? 1 : 2);
119 len = flag.length;
120 const key = isGroup ? flag[len - 1] : flag;
121
122 if (opts.unknown !== void 0 && aliases[key] === void 0) {
123 return opts.unknown(segs[0]);
124 }
125
126 if (segs.length > 1) {
127 tmp = segs[1];
128 } else {
129 tmp = args[idx + 1] || true;
130 FLAG.test(tmp) ? (tmp = true) : (incr = 2);
131 }
132
133 if (isGroup && len > 1) {
134 for (i = len - 1; i--; ) {
135 k = flag[i]; // all but last key
136 out[k] = typecast(k, true, opts.string, opts.boolean);
137 }
138 }
139
140 const value = typecast(key, tmp, opts.string, opts.boolean);
141 out[key] = out[key] !== void 0 ? toArr(out[key]).concat(value) : value;
142
143 // handle discarded args when dealing with booleans
144 if (isBool(value) && !isBool(tmp) && tmp !== 'true' && tmp !== 'false') {
145 out._.push(tmp);
146 }
147 }
148
149 idx += incr;
150 }
151
152 if (opts.default !== void 0) {
153 for (k in opts.default) {
154 if (out[k] === void 0) {
155 out[k] = opts.default[k];
156 }
157 }
158 }
159
160 for (k in out) {
161 if (aliases[k] === void 0) continue;
162 y = out[k];
163 len = aliases[k].length;
164 for (i = 0; i < len; i++) {
165 out[aliases[k][i]] = y; // assign value
166 }
167 }
168
169 return out;
170};
171
172var utils = createCommonjsModule(function (module, exports) {
173Object.defineProperty(exports, "__esModule", { value: true });
174exports.removeBrackets = (v) => v.replace(/[<[].+/, '').trim();
175exports.findAllBrackets = (v) => {
176 const ANGLED_BRACKET_RE_GLOBAL = /<([^>]+)>/g;
177 const SQUARE_BRACKET_RE_GLOBAL = /\[([^\]]+)\]/g;
178 const res = [];
179 const parse = (match) => {
180 let variadic = false;
181 let value = match[1];
182 if (value.startsWith('...')) {
183 value = value.slice(3);
184 variadic = true;
185 }
186 return {
187 required: match[0].startsWith('<'),
188 value,
189 variadic
190 };
191 };
192 let angledMatch;
193 while ((angledMatch = ANGLED_BRACKET_RE_GLOBAL.exec(v))) {
194 res.push(parse(angledMatch));
195 }
196 let squareMatch;
197 while ((squareMatch = SQUARE_BRACKET_RE_GLOBAL.exec(v))) {
198 res.push(parse(squareMatch));
199 }
200 return res;
201};
202exports.getMriOptions = (options) => {
203 const result = { alias: {}, boolean: [] };
204 for (const [index, option] of options.entries()) {
205 // We do not set default values in mri options
206 // Since its type (typeof) will be used to cast parsed arguments.
207 // Which mean `--foo foo` will be parsed as `{foo: true}` if we have `{default:{foo: true}}`
208 // Set alias
209 if (option.names.length > 1) {
210 result.alias[option.names[0]] = option.names.slice(1);
211 }
212 // Set boolean
213 if (option.isBoolean) {
214 if (option.negated) {
215 // For negated option
216 // We only set it to `boolean` type when there's no string-type option with the same name
217 const hasStringTypeOption = options.some((o, i) => {
218 return (i !== index &&
219 o.names.some(name => option.names.includes(name)) &&
220 typeof o.required === 'boolean');
221 });
222 if (!hasStringTypeOption) {
223 result.boolean.push(option.names[0]);
224 }
225 }
226 else {
227 result.boolean.push(option.names[0]);
228 }
229 }
230 }
231 return result;
232};
233exports.findLongest = (arr) => {
234 return arr.sort((a, b) => {
235 return a.length > b.length ? -1 : 1;
236 })[0];
237};
238exports.padRight = (str, length) => {
239 return str.length >= length ? str : `${str}${' '.repeat(length - str.length)}`;
240};
241exports.camelcase = (input) => {
242 return input.replace(/([a-z])-([a-z])/g, (_, p1, p2) => {
243 return p1 + p2.toUpperCase();
244 });
245};
246exports.setDotProp = (obj, keys, val) => {
247 let i = 0;
248 let length = keys.length;
249 let t = obj;
250 let x;
251 for (; i < length; ++i) {
252 x = t[keys[i]];
253 t = t[keys[i]] =
254 i === length - 1
255 ? val
256 : x != null
257 ? x
258 : !!~keys[i + 1].indexOf('.') || !(+keys[i + 1] > -1)
259 ? {}
260 : [];
261 }
262};
263});
264
265unwrapExports(utils);
266var utils_1 = utils.removeBrackets;
267var utils_2 = utils.findAllBrackets;
268var utils_3 = utils.getMriOptions;
269var utils_4 = utils.findLongest;
270var utils_5 = utils.padRight;
271var utils_6 = utils.camelcase;
272var utils_7 = utils.setDotProp;
273
274var Option_1 = createCommonjsModule(function (module, exports) {
275Object.defineProperty(exports, "__esModule", { value: true });
276
277class Option {
278 constructor(rawName, description, config) {
279 this.rawName = rawName;
280 this.description = description;
281 this.config = Object.assign({}, config);
282 this.names = utils.removeBrackets(rawName)
283 .split(',')
284 .map((v) => {
285 let name = v.trim().replace(/^-{1,2}/, '');
286 if (name.startsWith('no-')) {
287 this.negated = true;
288 name = name.replace(/^no-/, '');
289 }
290 return name;
291 });
292 if (this.negated) {
293 this.config.default = true;
294 }
295 if (rawName.includes('<')) {
296 this.required = true;
297 }
298 else if (rawName.includes('[')) {
299 this.required = false;
300 }
301 else {
302 // No arg needed, it's boolean flag
303 this.isBoolean = true;
304 }
305 }
306}
307exports.default = Option;
308});
309
310unwrapExports(Option_1);
311
312var Command_1 = createCommonjsModule(function (module, exports) {
313var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
314 return (mod && mod.__esModule) ? mod : { "default": mod };
315};
316Object.defineProperty(exports, "__esModule", { value: true });
317const Option_1$$1 = __importDefault(Option_1);
318
319class Command {
320 constructor(rawName, description, config = {}, cli) {
321 this.rawName = rawName;
322 this.description = description;
323 this.config = config;
324 this.cli = cli;
325 this.options = [];
326 this.aliasNames = [];
327 this.name = utils.removeBrackets(rawName);
328 this.args = utils.findAllBrackets(rawName);
329 this.examples = [];
330 }
331 usage(text) {
332 this.usageText = text;
333 return this;
334 }
335 allowUnknownOptions() {
336 this.config.allowUnknownOptions = true;
337 return this;
338 }
339 ignoreOptionDefaultValue() {
340 this.config.ignoreOptionDefaultValue = true;
341 return this;
342 }
343 version(version, customFlags = '-v, --version') {
344 this.versionNumber = version;
345 this.option(customFlags, 'Display version number');
346 return this;
347 }
348 example(example) {
349 this.examples.push(example);
350 return this;
351 }
352 /**
353 * Add a option for this command
354 * @param rawName Raw option name(s)
355 * @param description Option description
356 * @param config Option config
357 */
358 option(rawName, description, config) {
359 const option = new Option_1$$1.default(rawName, description, config);
360 this.options.push(option);
361 return this;
362 }
363 alias(name) {
364 this.aliasNames.push(name);
365 return this;
366 }
367 action(callback) {
368 this.commandAction = callback;
369 return this;
370 }
371 /**
372 * Check if a command name is matched by this command
373 * @param name Command name
374 */
375 isMatched(name) {
376 return this.name === name || this.aliasNames.includes(name);
377 }
378 get isDefaultCommand() {
379 return this.name === '' || this.aliasNames.includes('!');
380 }
381 get isGlobalCommand() {
382 return this instanceof GlobalCommand;
383 }
384 /**
385 * Check if an option is registered in this command
386 * @param name Option name
387 */
388 hasOption(name) {
389 name = name.split('.')[0];
390 return this.options.find(option => {
391 return option.names.includes(name);
392 });
393 }
394 outputHelp() {
395 const { name, commands } = this.cli;
396 const { versionNumber, options: globalOptions, helpCallback } = this.cli.globalCommand;
397 const sections = [
398 {
399 body: `${name}${versionNumber ? ` v${versionNumber}` : ''}`
400 }
401 ];
402 sections.push({
403 title: 'Usage',
404 body: ` $ ${name} ${this.usageText || this.rawName}`
405 });
406 const showCommands = (this.isGlobalCommand || this.isDefaultCommand) && commands.length > 0;
407 if (showCommands) {
408 const longestCommandName = utils.findLongest(commands.map(command => command.rawName));
409 sections.push({
410 title: 'Commands',
411 body: commands
412 .map(command => {
413 return ` ${utils.padRight(command.rawName, longestCommandName.length)} ${command.description}`;
414 })
415 .join('\n')
416 });
417 sections.push({
418 title: `For more info, run any command with the \`--help\` flag`,
419 body: commands
420 .map(command => ` $ ${name}${command.name === '' ? '' : ` ${command.name}`} --help`)
421 .join('\n')
422 });
423 }
424 const options = this.isGlobalCommand
425 ? globalOptions
426 : [...this.options, ...(globalOptions || [])];
427 if (options.length > 0) {
428 const longestOptionName = utils.findLongest(options.map(option => option.rawName));
429 sections.push({
430 title: 'Options',
431 body: options
432 .map(option => {
433 return ` ${utils.padRight(option.rawName, longestOptionName.length)} ${option.description} ${option.config.default === undefined
434 ? ''
435 : `(default: ${option.config.default})`}`;
436 })
437 .join('\n')
438 });
439 }
440 if (this.examples.length > 0) {
441 sections.push({
442 title: 'Examples',
443 body: this.examples
444 .map(example => {
445 if (typeof example === 'function') {
446 return example(name);
447 }
448 return example;
449 })
450 .join('\n')
451 });
452 }
453 if (helpCallback) {
454 helpCallback(sections);
455 }
456 console.log(sections
457 .map(section => {
458 return section.title
459 ? `${section.title}:\n${section.body}`
460 : section.body;
461 })
462 .join('\n\n'));
463 process.exit(0);
464 }
465 outputVersion() {
466 const { name } = this.cli;
467 const { versionNumber } = this.cli.globalCommand;
468 if (versionNumber) {
469 console.log(`${name}/${versionNumber} ${process.platform}-${process.arch} node-${process.version}`);
470 }
471 process.exit(0);
472 }
473 /**
474 * Check if the parsed options contain any unknown options
475 *
476 * Exit and output error when true
477 */
478 checkUnknownOptions() {
479 const { rawOptions, globalCommand } = this.cli;
480 if (!this.config.allowUnknownOptions) {
481 for (const name of Object.keys(rawOptions)) {
482 if (name !== '--' &&
483 !this.hasOption(name) &&
484 !globalCommand.hasOption(name)) {
485 console.error(`error: Unknown option \`${name.length > 1 ? `--${name}` : `-${name}`}\``);
486 process.exit(1);
487 }
488 }
489 }
490 }
491 /**
492 * Check if the required string-type options exist
493 */
494 checkOptionValue() {
495 const { rawOptions, globalCommand } = this.cli;
496 const options = [...globalCommand.options, ...this.options];
497 for (const option of options) {
498 const value = rawOptions[option.names[0].split('.')[0]];
499 // Check required option value
500 if (option.required) {
501 if (typeof value === 'boolean') {
502 console.error(`error: option \`${option.rawName}\` value is missing`);
503 process.exit(1);
504 }
505 }
506 }
507 }
508}
509class GlobalCommand extends Command {
510 constructor(cli) {
511 super('@@global@@', '', {}, cli);
512 }
513}
514exports.GlobalCommand = GlobalCommand;
515exports.default = Command;
516});
517
518unwrapExports(Command_1);
519var Command_2 = Command_1.GlobalCommand;
520
521var CAC_1 = createCommonjsModule(function (module, exports) {
522var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
523 return (mod && mod.__esModule) ? mod : { "default": mod };
524};
525var __importStar = (commonjsGlobal && commonjsGlobal.__importStar) || function (mod) {
526 if (mod && mod.__esModule) return mod;
527 var result = {};
528 if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
529 result["default"] = mod;
530 return result;
531};
532Object.defineProperty(exports, "__esModule", { value: true });
533
534const path_1 = __importDefault(path);
535const mri_1 = __importDefault(lib);
536const Command_1$$1 = __importStar(Command_1);
537
538class CAC extends events.EventEmitter {
539 /**
540 * @param name The program name to display in help and version message
541 */
542 constructor(name = '') {
543 super();
544 this.name = name;
545 this.commands = [];
546 this.globalCommand = new Command_1$$1.GlobalCommand(this);
547 this.globalCommand.usage('<command> [options]');
548 }
549 /**
550 * Add a global usage text.
551 *
552 * This is not used by sub-commands.
553 */
554 usage(text) {
555 this.globalCommand.usage(text);
556 return this;
557 }
558 /**
559 * Add a sub-command
560 */
561 command(rawName, description, config) {
562 const command = new Command_1$$1.default(rawName, description || '', config, this);
563 command.globalCommand = this.globalCommand;
564 this.commands.push(command);
565 return command;
566 }
567 /**
568 * Add a global CLI option.
569 *
570 * Which is also applied to sub-commands.
571 */
572 option(rawName, description, config) {
573 this.globalCommand.option(rawName, description, config);
574 return this;
575 }
576 /**
577 * Show help message when `-h, --help` flags appear.
578 *
579 */
580 help(callback) {
581 this.globalCommand.option('-h, --help', 'Display this message');
582 this.globalCommand.helpCallback = callback;
583 this.showHelpOnExit = true;
584 return this;
585 }
586 /**
587 * Show version number when `-v, --version` flags appear.
588 *
589 */
590 version(version, customFlags = '-v, --version') {
591 this.globalCommand.version(version, customFlags);
592 this.showVersionOnExit = true;
593 return this;
594 }
595 /**
596 * Add a global example.
597 *
598 * This example added here will not be used by sub-commands.
599 */
600 example(example) {
601 this.globalCommand.example(example);
602 return this;
603 }
604 /**
605 * Output the corresponding help message
606 * When a sub-command is matched, output the help message for the command
607 * Otherwise output the global one.
608 *
609 * This will also call `process.exit(0)` to quit the process.
610 */
611 outputHelp() {
612 if (this.matchedCommand) {
613 this.matchedCommand.outputHelp();
614 }
615 else {
616 this.globalCommand.outputHelp();
617 }
618 }
619 /**
620 * Output the version number.
621 *
622 * This will also call `process.exit(0)` to quit the process.
623 */
624 outputVersion() {
625 this.globalCommand.outputVersion();
626 }
627 setParsedInfo({ args, options, rawOptions }, matchedCommand) {
628 this.args = args;
629 this.options = options;
630 this.rawOptions = rawOptions;
631 if (matchedCommand) {
632 this.matchedCommand = matchedCommand;
633 }
634 return this;
635 }
636 /**
637 * Parse argv
638 */
639 parse(argv = process.argv, {
640 /** Whether to run the action for matched command */
641 run = true } = {}) {
642 this.rawArgs = argv;
643 if (!this.name) {
644 this.name = argv[1] ? path_1.default.basename(argv[1]) : 'cli';
645 }
646 let shouldParse = true;
647 // Search sub-commands
648 for (const command of this.commands) {
649 const mriResult = this.mri(argv.slice(2), command);
650 const commandName = mriResult.args[0];
651 if (command.isMatched(commandName)) {
652 shouldParse = false;
653 const parsedInfo = Object.assign({}, mriResult, { args: mriResult.args.slice(1) });
654 this.setParsedInfo(parsedInfo, command);
655 this.emit(`command:${commandName}`, command);
656 }
657 }
658 if (shouldParse) {
659 // Search the default command
660 for (const command of this.commands) {
661 if (command.name === '') {
662 shouldParse = false;
663 const mriResult = this.mri(argv.slice(2), command);
664 this.setParsedInfo(mriResult, command);
665 this.emit(`command:!`, command);
666 }
667 }
668 }
669 if (shouldParse) {
670 const mriResult = this.mri(argv.slice(2));
671 this.setParsedInfo(mriResult);
672 }
673 if (this.options.help && this.showHelpOnExit) {
674 this.outputHelp();
675 }
676 if (this.options.version && this.showVersionOnExit) {
677 this.outputVersion();
678 }
679 const parsedArgv = { args: this.args, options: this.options };
680 if (run) {
681 this.runMatchedCommand();
682 }
683 if (!this.matchedCommand && this.args[0]) {
684 this.emit('command:*');
685 }
686 return parsedArgv;
687 }
688 mri(argv,
689 /** Matched command */ command) {
690 // All added options
691 const cliOptions = [
692 ...this.globalCommand.options,
693 ...(command ? command.options : [])
694 ];
695 const mriOptions = utils.getMriOptions(cliOptions);
696 // Extract everything after `--` since mri doesn't support it
697 let argsAfterDoubleDashes = [];
698 const doubleDashesIndex = argv.indexOf('--');
699 if (doubleDashesIndex > -1) {
700 argsAfterDoubleDashes = argv.slice(doubleDashesIndex + 1);
701 argv = argv.slice(0, doubleDashesIndex);
702 }
703 const parsed = mri_1.default(argv, mriOptions);
704 const args = parsed._;
705 delete parsed._;
706 const options = {
707 '--': argsAfterDoubleDashes
708 };
709 // Set option default value
710 const ignoreDefault = command && command.config.ignoreOptionDefaultValue
711 ? command.config.ignoreOptionDefaultValue
712 : this.globalCommand.config.ignoreOptionDefaultValue;
713 if (!ignoreDefault) {
714 for (const cliOption of cliOptions) {
715 if (cliOption.config.default !== undefined) {
716 for (const name of cliOption.names) {
717 options[name] = cliOption.config.default;
718 }
719 }
720 }
721 }
722 // Camelcase option names and set dot nested option values
723 for (const key of Object.keys(parsed)) {
724 const keys = key.split('.').map((v, i) => {
725 return i === 0 ? utils.camelcase(v) : v;
726 });
727 utils.setDotProp(options, keys, parsed[key]);
728 }
729 return {
730 args,
731 options,
732 rawOptions: parsed
733 };
734 }
735 runMatchedCommand() {
736 const { args, options, matchedCommand: command } = this;
737 if (!command || !command.commandAction)
738 return;
739 command.checkUnknownOptions();
740 command.checkOptionValue();
741 const minimalArgsCount = command.args.filter(arg => arg.required).length;
742 if (args.length < minimalArgsCount) {
743 console.error(`error: missing required args for command \`${command.rawName}\``);
744 process.exit(1);
745 }
746 const actionArgs = [];
747 command.args.forEach((arg, index) => {
748 if (arg.variadic) {
749 actionArgs.push(args.slice(index));
750 }
751 else {
752 actionArgs.push(args[index]);
753 }
754 });
755 actionArgs.push(options);
756 return command.commandAction.apply(this, actionArgs);
757 }
758}
759exports.default = CAC;
760});
761
762unwrapExports(CAC_1);
763
764var lib$1 = createCommonjsModule(function (module) {
765var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) {
766 return (mod && mod.__esModule) ? mod : { "default": mod };
767};
768const CAC_1$$1 = __importDefault(CAC_1);
769/**
770 * @param name The program name to display in help and version message
771 */
772const cac = (name = '') => new CAC_1$$1.default(name);
773module.exports = cac;
774});
775
776var index = unwrapExports(lib$1);
777
778module.exports = index;