UNPKG

30.1 kBJavaScriptView Raw
1// Copyright Joyent, Inc. and other Node contributors.
2
3var R = typeof Reflect === 'object' ? Reflect : null;
4var ReflectApply = R && typeof R.apply === 'function'
5 ? R.apply
6 : function ReflectApply(target, receiver, args) {
7 return Function.prototype.apply.call(target, receiver, args);
8 };
9
10var ReflectOwnKeys;
11if (R && typeof R.ownKeys === 'function') {
12 ReflectOwnKeys = R.ownKeys;
13} else if (Object.getOwnPropertySymbols) {
14 ReflectOwnKeys = function ReflectOwnKeys(target) {
15 return Object.getOwnPropertyNames(target)
16 .concat(Object.getOwnPropertySymbols(target));
17 };
18} else {
19 ReflectOwnKeys = function ReflectOwnKeys(target) {
20 return Object.getOwnPropertyNames(target);
21 };
22}
23
24function ProcessEmitWarning(warning) {
25 if (console && console.warn) console.warn(warning);
26}
27
28var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {
29 return value !== value;
30};
31
32function EventEmitter() {
33 EventEmitter.init.call(this);
34}
35var events = EventEmitter;
36
37// Backwards-compat with node 0.10.x
38EventEmitter.EventEmitter = EventEmitter;
39
40EventEmitter.prototype._events = undefined;
41EventEmitter.prototype._eventsCount = 0;
42EventEmitter.prototype._maxListeners = undefined;
43
44// By default EventEmitters will print a warning if more than 10 listeners are
45// added to it. This is a useful default which helps finding memory leaks.
46var defaultMaxListeners = 10;
47
48Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
49 enumerable: true,
50 get: function() {
51 return defaultMaxListeners;
52 },
53 set: function(arg) {
54 if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
55 throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.');
56 }
57 defaultMaxListeners = arg;
58 }
59});
60
61EventEmitter.init = function() {
62
63 if (this._events === undefined ||
64 this._events === Object.getPrototypeOf(this)._events) {
65 this._events = Object.create(null);
66 this._eventsCount = 0;
67 }
68
69 this._maxListeners = this._maxListeners || undefined;
70};
71
72// Obviously not all Emitters should be limited to 10. This function allows
73// that to be increased. Set to zero for unlimited.
74EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
75 if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
76 throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.');
77 }
78 this._maxListeners = n;
79 return this;
80};
81
82function $getMaxListeners(that) {
83 if (that._maxListeners === undefined)
84 return EventEmitter.defaultMaxListeners;
85 return that._maxListeners;
86}
87
88EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
89 return $getMaxListeners(this);
90};
91
92EventEmitter.prototype.emit = function emit(type) {
93 var args = [];
94 for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
95 var doError = (type === 'error');
96
97 var events = this._events;
98 if (events !== undefined)
99 doError = (doError && events.error === undefined);
100 else if (!doError)
101 return false;
102
103 // If there is no 'error' event listener then throw.
104 if (doError) {
105 var er;
106 if (args.length > 0)
107 er = args[0];
108 if (er instanceof Error) {
109 // Note: The comments on the `throw` lines are intentional, they show
110 // up in Node's output if this results in an unhandled exception.
111 throw er; // Unhandled 'error' event
112 }
113 // At least give some kind of context to the user
114 var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));
115 err.context = er;
116 throw err; // Unhandled 'error' event
117 }
118
119 var handler = events[type];
120
121 if (handler === undefined)
122 return false;
123
124 if (typeof handler === 'function') {
125 ReflectApply(handler, this, args);
126 } else {
127 var len = handler.length;
128 var listeners = arrayClone(handler, len);
129 for (var i = 0; i < len; ++i)
130 ReflectApply(listeners[i], this, args);
131 }
132
133 return true;
134};
135
136function _addListener(target, type, listener, prepend) {
137 var m;
138 var events;
139 var existing;
140
141 if (typeof listener !== 'function') {
142 throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
143 }
144
145 events = target._events;
146 if (events === undefined) {
147 events = target._events = Object.create(null);
148 target._eventsCount = 0;
149 } else {
150 // To avoid recursion in the case that type === "newListener"! Before
151 // adding it to the listeners, first emit "newListener".
152 if (events.newListener !== undefined) {
153 target.emit('newListener', type,
154 listener.listener ? listener.listener : listener);
155
156 // Re-assign `events` because a newListener handler could have caused the
157 // this._events to be assigned to a new object
158 events = target._events;
159 }
160 existing = events[type];
161 }
162
163 if (existing === undefined) {
164 // Optimize the case of one listener. Don't need the extra array object.
165 existing = events[type] = listener;
166 ++target._eventsCount;
167 } else {
168 if (typeof existing === 'function') {
169 // Adding the second element, need to change to array.
170 existing = events[type] =
171 prepend ? [listener, existing] : [existing, listener];
172 // If we've already got an array, just append.
173 } else if (prepend) {
174 existing.unshift(listener);
175 } else {
176 existing.push(listener);
177 }
178
179 // Check for listener leak
180 m = $getMaxListeners(target);
181 if (m > 0 && existing.length > m && !existing.warned) {
182 existing.warned = true;
183 // No error code for this since it is a Warning
184 // eslint-disable-next-line no-restricted-syntax
185 var w = new Error('Possible EventEmitter memory leak detected. ' +
186 existing.length + ' ' + String(type) + ' listeners ' +
187 'added. Use emitter.setMaxListeners() to ' +
188 'increase limit');
189 w.name = 'MaxListenersExceededWarning';
190 w.emitter = target;
191 w.type = type;
192 w.count = existing.length;
193 ProcessEmitWarning(w);
194 }
195 }
196
197 return target;
198}
199
200EventEmitter.prototype.addListener = function addListener(type, listener) {
201 return _addListener(this, type, listener, false);
202};
203
204EventEmitter.prototype.on = EventEmitter.prototype.addListener;
205
206EventEmitter.prototype.prependListener =
207 function prependListener(type, listener) {
208 return _addListener(this, type, listener, true);
209 };
210
211function onceWrapper() {
212 var args = [];
213 for (var i = 0; i < arguments.length; i++) args.push(arguments[i]);
214 if (!this.fired) {
215 this.target.removeListener(this.type, this.wrapFn);
216 this.fired = true;
217 ReflectApply(this.listener, this.target, args);
218 }
219}
220
221function _onceWrap(target, type, listener) {
222 var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
223 var wrapped = onceWrapper.bind(state);
224 wrapped.listener = listener;
225 state.wrapFn = wrapped;
226 return wrapped;
227}
228
229EventEmitter.prototype.once = function once(type, listener) {
230 if (typeof listener !== 'function') {
231 throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
232 }
233 this.on(type, _onceWrap(this, type, listener));
234 return this;
235};
236
237EventEmitter.prototype.prependOnceListener =
238 function prependOnceListener(type, listener) {
239 if (typeof listener !== 'function') {
240 throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
241 }
242 this.prependListener(type, _onceWrap(this, type, listener));
243 return this;
244 };
245
246// Emits a 'removeListener' event if and only if the listener was removed.
247EventEmitter.prototype.removeListener =
248 function removeListener(type, listener) {
249 var list, events, position, i, originalListener;
250
251 if (typeof listener !== 'function') {
252 throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
253 }
254
255 events = this._events;
256 if (events === undefined)
257 return this;
258
259 list = events[type];
260 if (list === undefined)
261 return this;
262
263 if (list === listener || list.listener === listener) {
264 if (--this._eventsCount === 0)
265 this._events = Object.create(null);
266 else {
267 delete events[type];
268 if (events.removeListener)
269 this.emit('removeListener', type, list.listener || listener);
270 }
271 } else if (typeof list !== 'function') {
272 position = -1;
273
274 for (i = list.length - 1; i >= 0; i--) {
275 if (list[i] === listener || list[i].listener === listener) {
276 originalListener = list[i].listener;
277 position = i;
278 break;
279 }
280 }
281
282 if (position < 0)
283 return this;
284
285 if (position === 0)
286 list.shift();
287 else {
288 spliceOne(list, position);
289 }
290
291 if (list.length === 1)
292 events[type] = list[0];
293
294 if (events.removeListener !== undefined)
295 this.emit('removeListener', type, originalListener || listener);
296 }
297
298 return this;
299 };
300
301EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
302
303EventEmitter.prototype.removeAllListeners =
304 function removeAllListeners(type) {
305 var listeners, events, i;
306
307 events = this._events;
308 if (events === undefined)
309 return this;
310
311 // not listening for removeListener, no need to emit
312 if (events.removeListener === undefined) {
313 if (arguments.length === 0) {
314 this._events = Object.create(null);
315 this._eventsCount = 0;
316 } else if (events[type] !== undefined) {
317 if (--this._eventsCount === 0)
318 this._events = Object.create(null);
319 else
320 delete events[type];
321 }
322 return this;
323 }
324
325 // emit removeListener for all listeners on all events
326 if (arguments.length === 0) {
327 var keys = Object.keys(events);
328 var key;
329 for (i = 0; i < keys.length; ++i) {
330 key = keys[i];
331 if (key === 'removeListener') continue;
332 this.removeAllListeners(key);
333 }
334 this.removeAllListeners('removeListener');
335 this._events = Object.create(null);
336 this._eventsCount = 0;
337 return this;
338 }
339
340 listeners = events[type];
341
342 if (typeof listeners === 'function') {
343 this.removeListener(type, listeners);
344 } else if (listeners !== undefined) {
345 // LIFO order
346 for (i = listeners.length - 1; i >= 0; i--) {
347 this.removeListener(type, listeners[i]);
348 }
349 }
350
351 return this;
352 };
353
354function _listeners(target, type, unwrap) {
355 var events = target._events;
356
357 if (events === undefined)
358 return [];
359
360 var evlistener = events[type];
361 if (evlistener === undefined)
362 return [];
363
364 if (typeof evlistener === 'function')
365 return unwrap ? [evlistener.listener || evlistener] : [evlistener];
366
367 return unwrap ?
368 unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
369}
370
371EventEmitter.prototype.listeners = function listeners(type) {
372 return _listeners(this, type, true);
373};
374
375EventEmitter.prototype.rawListeners = function rawListeners(type) {
376 return _listeners(this, type, false);
377};
378
379EventEmitter.listenerCount = function(emitter, type) {
380 if (typeof emitter.listenerCount === 'function') {
381 return emitter.listenerCount(type);
382 } else {
383 return listenerCount.call(emitter, type);
384 }
385};
386
387EventEmitter.prototype.listenerCount = listenerCount;
388function listenerCount(type) {
389 var events = this._events;
390
391 if (events !== undefined) {
392 var evlistener = events[type];
393
394 if (typeof evlistener === 'function') {
395 return 1;
396 } else if (evlistener !== undefined) {
397 return evlistener.length;
398 }
399 }
400
401 return 0;
402}
403
404EventEmitter.prototype.eventNames = function eventNames() {
405 return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
406};
407
408function arrayClone(arr, n) {
409 var copy = new Array(n);
410 for (var i = 0; i < n; ++i)
411 copy[i] = arr[i];
412 return copy;
413}
414
415function spliceOne(list, index) {
416 for (; index + 1 < list.length; index++)
417 list[index] = list[index + 1];
418 list.pop();
419}
420
421function unwrapListeners(arr) {
422 var ret = new Array(arr.length);
423 for (var i = 0; i < ret.length; ++i) {
424 ret[i] = arr[i].listener || arr[i];
425 }
426 return ret;
427}
428var events_1 = events.EventEmitter;
429
430function toArr(any) {
431 return any == null ? [] : Array.isArray(any) ? any : [any];
432}
433
434function toVal(out, key, val, opts) {
435 var x, old=out[key], nxt=(
436 !!~opts.string.indexOf(key) ? (val == null || val === true ? '' : String(val))
437 : typeof val === 'boolean' ? val
438 : !!~opts.boolean.indexOf(key) ? (val === 'false' ? false : val === 'true' || (out._.push((x = +val,x * 0 === 0) ? x : val),!!val))
439 : (x = +val,x * 0 === 0) ? x : val
440 );
441 out[key] = old == null ? nxt : (Array.isArray(old) ? old.concat(nxt) : [old, nxt]);
442}
443
444var lib = function (args, opts) {
445 args = args || [];
446 opts = opts || {};
447
448 var k, arr, arg, name, val, out={ _:[] };
449 var i=0, j=0, idx=0, len=args.length;
450
451 const alibi = opts.alias !== void 0;
452 const strict = opts.unknown !== void 0;
453 const defaults = opts.default !== void 0;
454
455 opts.alias = opts.alias || {};
456 opts.string = toArr(opts.string);
457 opts.boolean = toArr(opts.boolean);
458
459 if (alibi) {
460 for (k in opts.alias) {
461 arr = opts.alias[k] = toArr(opts.alias[k]);
462 for (i=0; i < arr.length; i++) {
463 (opts.alias[arr[i]] = arr.concat(k)).splice(i, 1);
464 }
465 }
466 }
467
468 opts.boolean.forEach(key => {
469 opts.boolean = opts.boolean.concat(opts.alias[key] = opts.alias[key] || []);
470 });
471
472 opts.string.forEach(key => {
473 opts.string = opts.string.concat(opts.alias[key] = opts.alias[key] || []);
474 });
475
476 if (defaults) {
477 for (k in opts.default) {
478 opts.alias[k] = opts.alias[k] || [];
479 (opts[typeof opts.default[k]] || []).push(k);
480 }
481 }
482
483 const keys = strict ? Object.keys(opts.alias) : [];
484
485 for (i=0; i < len; i++) {
486 arg = args[i];
487
488 if (arg === '--') {
489 out._ = out._.concat(args.slice(++i));
490 break;
491 }
492
493 for (j=0; j < arg.length; j++) {
494 if (arg.charCodeAt(j) !== 45) break; // "-"
495 }
496
497 if (j === 0) {
498 out._.push(arg);
499 } else if (arg.substring(j, j + 3) === 'no-') {
500 name = arg.substring(j + 3);
501 if (strict && !~keys.indexOf(name)) {
502 return opts.unknown(arg);
503 }
504 out[name] = false;
505 } else {
506 for (idx=j+1; idx < arg.length; idx++) {
507 if (arg.charCodeAt(idx) === 61) break; // "="
508 }
509
510 name = arg.substring(j, idx);
511 val = arg.substring(++idx) || (i+1 === len || (''+args[i+1]).charCodeAt(0) === 45 || args[++i]);
512 arr = (j === 2 ? [name] : name);
513
514 for (idx=0; idx < arr.length; idx++) {
515 name = arr[idx];
516 if (strict && !~keys.indexOf(name)) return opts.unknown('-'.repeat(j) + name);
517 toVal(out, name, (idx + 1 < arr.length) || val, opts);
518 }
519 }
520 }
521
522 if (defaults) {
523 for (k in opts.default) {
524 if (out[k] === void 0) {
525 out[k] = opts.default[k];
526 }
527 }
528 }
529
530 if (alibi) {
531 for (k in out) {
532 arr = opts.alias[k] || [];
533 while (arr.length > 0) {
534 out[arr.shift()] = out[k];
535 }
536 }
537 }
538
539 return out;
540};
541
542const removeBrackets = (v) => v.replace(/[<[].+/, "").trim();
543const findAllBrackets = (v) => {
544 const ANGLED_BRACKET_RE_GLOBAL = /<([^>]+)>/g;
545 const SQUARE_BRACKET_RE_GLOBAL = /\[([^\]]+)\]/g;
546 const res = [];
547 const parse = (match) => {
548 let variadic = false;
549 let value = match[1];
550 if (value.startsWith("...")) {
551 value = value.slice(3);
552 variadic = true;
553 }
554 return {
555 required: match[0].startsWith("<"),
556 value,
557 variadic
558 };
559 };
560 let angledMatch;
561 while (angledMatch = ANGLED_BRACKET_RE_GLOBAL.exec(v)) {
562 res.push(parse(angledMatch));
563 }
564 let squareMatch;
565 while (squareMatch = SQUARE_BRACKET_RE_GLOBAL.exec(v)) {
566 res.push(parse(squareMatch));
567 }
568 return res;
569};
570const getMriOptions = (options) => {
571 const result = {
572 alias: {},
573 boolean: []
574 };
575 for (const [index, option] of options.entries()) {
576 if (option.names.length > 1) {
577 result.alias[option.names[0]] = option.names.slice(1);
578 }
579 if (option.isBoolean) {
580 if (option.negated) {
581 const hasStringTypeOption = options.some((o, i) => {
582 return i !== index && o.names.some((name) => option.names.includes(name)) && typeof o.required === "boolean";
583 });
584 if (!hasStringTypeOption) {
585 result.boolean.push(option.names[0]);
586 }
587 } else {
588 result.boolean.push(option.names[0]);
589 }
590 }
591 }
592 return result;
593};
594const findLongest = (arr) => {
595 return arr.sort((a, b) => {
596 return a.length > b.length ? -1 : 1;
597 })[0];
598};
599const padRight = (str, length) => {
600 return str.length >= length ? str : `${str}${" ".repeat(length - str.length)}`;
601};
602const camelcase = (input) => {
603 return input.replace(/([a-z])-([a-z])/g, (_, p1, p2) => {
604 return p1 + p2.toUpperCase();
605 });
606};
607const setDotProp = (obj, keys, val) => {
608 let i = 0;
609 let length = keys.length;
610 let t = obj;
611 let x;
612 for (; i < length; ++i) {
613 x = t[keys[i]];
614 t = t[keys[i]] = i === length - 1 ? val : x != null ? x : !!~keys[i + 1].indexOf(".") || !(+keys[i + 1] > -1) ? {} : [];
615 }
616};
617const setByType = (obj, transforms) => {
618 for (const key of Object.keys(transforms)) {
619 const transform = transforms[key];
620 if (transform.shouldTransform) {
621 obj[key] = Array.prototype.concat.call([], obj[key]);
622 if (typeof transform.transformFunction === "function") {
623 obj[key] = obj[key].map(transform.transformFunction);
624 }
625 }
626 }
627};
628const getFileName = (input) => {
629 const m = /([^\\\/]+)$/.exec(input);
630 return m ? m[1] : "";
631};
632const camelcaseOptionName = (name) => {
633 return name.split(".").map((v, i) => {
634 return i === 0 ? camelcase(v) : v;
635 }).join(".");
636};
637class CACError extends Error {
638 constructor(message) {
639 super(message);
640 this.name = this.constructor.name;
641 if (typeof Error.captureStackTrace === "function") {
642 Error.captureStackTrace(this, this.constructor);
643 } else {
644 this.stack = new Error(message).stack;
645 }
646 }
647}
648
649class Option {
650 constructor(rawName, description, config) {
651 this.rawName = rawName;
652 this.description = description;
653 this.config = Object.assign({}, config);
654 rawName = rawName.replace(/\.\*/g, "");
655 this.negated = false;
656 this.names = removeBrackets(rawName).split(",").map((v) => {
657 let name = v.trim().replace(/^-{1,2}/, "");
658 if (name.startsWith("no-")) {
659 this.negated = true;
660 name = name.replace(/^no-/, "");
661 }
662 return camelcaseOptionName(name);
663 }).sort((a, b) => a.length > b.length ? 1 : -1);
664 this.name = this.names[this.names.length - 1];
665 if (this.negated) {
666 this.config.default = true;
667 }
668 if (rawName.includes("<")) {
669 this.required = true;
670 } else if (rawName.includes("[")) {
671 this.required = false;
672 } else {
673 this.isBoolean = true;
674 }
675 }
676}
677
678const deno = typeof window !== "undefined" && window.Deno;
679const processArgs = deno ? ["deno", "cli"].concat(Deno.args) : process.argv;
680const platformInfo = deno ? `${Deno.build.os}-${Deno.build.arch} deno-${Deno.version.deno}` : `${process.platform}-${process.arch} node-${process.version}`;
681
682class Command {
683 constructor(rawName, description, config = {}, cli) {
684 this.rawName = rawName;
685 this.description = description;
686 this.config = config;
687 this.cli = cli;
688 this.options = [];
689 this.aliasNames = [];
690 this.name = removeBrackets(rawName);
691 this.args = findAllBrackets(rawName);
692 this.examples = [];
693 }
694 usage(text) {
695 this.usageText = text;
696 return this;
697 }
698 allowUnknownOptions() {
699 this.config.allowUnknownOptions = true;
700 return this;
701 }
702 ignoreOptionDefaultValue() {
703 this.config.ignoreOptionDefaultValue = true;
704 return this;
705 }
706 version(version, customFlags = "-v, --version") {
707 this.versionNumber = version;
708 this.option(customFlags, "Display version number");
709 return this;
710 }
711 example(example) {
712 this.examples.push(example);
713 return this;
714 }
715 option(rawName, description, config) {
716 const option = new Option(rawName, description, config);
717 this.options.push(option);
718 return this;
719 }
720 alias(name) {
721 this.aliasNames.push(name);
722 return this;
723 }
724 action(callback) {
725 this.commandAction = callback;
726 return this;
727 }
728 isMatched(name) {
729 return this.name === name || this.aliasNames.includes(name);
730 }
731 get isDefaultCommand() {
732 return this.name === "" || this.aliasNames.includes("!");
733 }
734 get isGlobalCommand() {
735 return this instanceof GlobalCommand;
736 }
737 hasOption(name) {
738 name = name.split(".")[0];
739 return this.options.find((option) => {
740 return option.names.includes(name);
741 });
742 }
743 outputHelp() {
744 const {name, commands} = this.cli;
745 const {versionNumber, options: globalOptions, helpCallback} = this.cli.globalCommand;
746 const sections = [{
747 body: `${name}${versionNumber ? ` v${versionNumber}` : ""}`
748 }];
749 sections.push({
750 title: "Usage",
751 body: ` $ ${name} ${this.usageText || this.rawName}`
752 });
753 const showCommands = (this.isGlobalCommand || this.isDefaultCommand) && commands.length > 0;
754 if (showCommands) {
755 const longestCommandName = findLongest(commands.map((command) => command.rawName));
756 sections.push({
757 title: "Commands",
758 body: commands.map((command) => {
759 return ` ${padRight(command.rawName, longestCommandName.length)} ${command.description}`;
760 }).join("\n")
761 });
762 sections.push({
763 title: `For more info, run any command with the \`--help\` flag`,
764 body: commands.map((command) => ` $ ${name}${command.name === "" ? "" : ` ${command.name}`} --help`).join("\n")
765 });
766 }
767 const options = this.isGlobalCommand ? globalOptions : [...this.options, ...globalOptions || []];
768 if (options.length > 0) {
769 const longestOptionName = findLongest(options.map((option) => option.rawName));
770 sections.push({
771 title: "Options",
772 body: options.map((option) => {
773 return ` ${padRight(option.rawName, longestOptionName.length)} ${option.description} ${option.config.default === void 0 ? "" : `(default: ${option.config.default})`}`;
774 }).join("\n")
775 });
776 }
777 if (this.examples.length > 0) {
778 sections.push({
779 title: "Examples",
780 body: this.examples.map((example) => {
781 if (typeof example === "function") {
782 return example(name);
783 }
784 return example;
785 }).join("\n")
786 });
787 }
788 if (helpCallback) {
789 helpCallback(sections);
790 }
791 console.log(sections.map((section) => {
792 return section.title ? `${section.title}:
793${section.body}` : section.body;
794 }).join("\n\n"));
795 }
796 outputVersion() {
797 const {name} = this.cli;
798 const {versionNumber} = this.cli.globalCommand;
799 if (versionNumber) {
800 console.log(`${name}/${versionNumber} ${platformInfo}`);
801 }
802 }
803 checkRequiredArgs() {
804 const minimalArgsCount = this.args.filter((arg) => arg.required).length;
805 if (this.cli.args.length < minimalArgsCount) {
806 throw new CACError(`missing required args for command \`${this.rawName}\``);
807 }
808 }
809 checkUnknownOptions() {
810 const {options, globalCommand} = this.cli;
811 if (!this.config.allowUnknownOptions) {
812 for (const name of Object.keys(options)) {
813 if (name !== "--" && !this.hasOption(name) && !globalCommand.hasOption(name)) {
814 throw new CACError(`Unknown option \`${name.length > 1 ? `--${name}` : `-${name}`}\``);
815 }
816 }
817 }
818 }
819 checkOptionValue() {
820 const {options: parsedOptions, globalCommand} = this.cli;
821 const options = [...globalCommand.options, ...this.options];
822 for (const option of options) {
823 const value = parsedOptions[option.name.split(".")[0]];
824 if (option.required) {
825 const hasNegated = options.some((o) => o.negated && o.names.includes(option.name));
826 if (value === true || value === false && !hasNegated) {
827 throw new CACError(`option \`${option.rawName}\` value is missing`);
828 }
829 }
830 }
831 }
832}
833class GlobalCommand extends Command {
834 constructor(cli) {
835 super("@@global@@", "", {}, cli);
836 }
837}
838
839let __assign = Object.assign;
840class CAC extends events_1 {
841 constructor(name = "") {
842 super();
843 this.name = name;
844 this.commands = [];
845 this.globalCommand = new GlobalCommand(this);
846 this.globalCommand.usage("<command> [options]");
847 }
848 usage(text) {
849 this.globalCommand.usage(text);
850 return this;
851 }
852 command(rawName, description, config) {
853 const command = new Command(rawName, description || "", config, this);
854 command.globalCommand = this.globalCommand;
855 this.commands.push(command);
856 return command;
857 }
858 option(rawName, description, config) {
859 this.globalCommand.option(rawName, description, config);
860 return this;
861 }
862 help(callback) {
863 this.globalCommand.option("-h, --help", "Display this message");
864 this.globalCommand.helpCallback = callback;
865 this.showHelpOnExit = true;
866 return this;
867 }
868 version(version, customFlags = "-v, --version") {
869 this.globalCommand.version(version, customFlags);
870 this.showVersionOnExit = true;
871 return this;
872 }
873 example(example) {
874 this.globalCommand.example(example);
875 return this;
876 }
877 outputHelp() {
878 if (this.matchedCommand) {
879 this.matchedCommand.outputHelp();
880 } else {
881 this.globalCommand.outputHelp();
882 }
883 }
884 outputVersion() {
885 this.globalCommand.outputVersion();
886 }
887 setParsedInfo({args, options}, matchedCommand, matchedCommandName) {
888 this.args = args;
889 this.options = options;
890 if (matchedCommand) {
891 this.matchedCommand = matchedCommand;
892 }
893 if (matchedCommandName) {
894 this.matchedCommandName = matchedCommandName;
895 }
896 return this;
897 }
898 parse(argv = processArgs, {run = true} = {}) {
899 this.rawArgs = argv;
900 if (!this.name) {
901 this.name = argv[1] ? getFileName(argv[1]) : "cli";
902 }
903 let shouldParse = true;
904 for (const command of this.commands) {
905 const parsed = this.mri(argv.slice(2), command);
906 const commandName = parsed.args[0];
907 if (command.isMatched(commandName)) {
908 shouldParse = false;
909 const parsedInfo = __assign(__assign({}, parsed), {
910 args: parsed.args.slice(1)
911 });
912 this.setParsedInfo(parsedInfo, command, commandName);
913 this.emit(`command:${commandName}`, command);
914 }
915 }
916 if (shouldParse) {
917 for (const command of this.commands) {
918 if (command.name === "") {
919 shouldParse = false;
920 const parsed = this.mri(argv.slice(2), command);
921 this.setParsedInfo(parsed, command);
922 this.emit(`command:!`, command);
923 }
924 }
925 }
926 if (shouldParse) {
927 const parsed = this.mri(argv.slice(2));
928 this.setParsedInfo(parsed);
929 }
930 if (this.options.help && this.showHelpOnExit) {
931 this.outputHelp();
932 run = false;
933 }
934 if (this.options.version && this.showVersionOnExit) {
935 this.outputVersion();
936 run = false;
937 }
938 const parsedArgv = {
939 args: this.args,
940 options: this.options
941 };
942 if (run) {
943 this.runMatchedCommand();
944 }
945 if (!this.matchedCommand && this.args[0]) {
946 this.emit("command:*");
947 }
948 return parsedArgv;
949 }
950 mri(argv, command) {
951 const cliOptions = [...this.globalCommand.options, ...command ? command.options : []];
952 const mriOptions = getMriOptions(cliOptions);
953 let argsAfterDoubleDashes = [];
954 const doubleDashesIndex = argv.indexOf("--");
955 if (doubleDashesIndex > -1) {
956 argsAfterDoubleDashes = argv.slice(doubleDashesIndex + 1);
957 argv = argv.slice(0, doubleDashesIndex);
958 }
959 let parsed = lib(argv, mriOptions);
960 parsed = Object.keys(parsed).reduce((res, name) => {
961 return __assign(__assign({}, res), {
962 [camelcaseOptionName(name)]: parsed[name]
963 });
964 }, {
965 _: []
966 });
967 const args = parsed._;
968 delete parsed._;
969 const options = {
970 "--": argsAfterDoubleDashes
971 };
972 const ignoreDefault = command && command.config.ignoreOptionDefaultValue ? command.config.ignoreOptionDefaultValue : this.globalCommand.config.ignoreOptionDefaultValue;
973 let transforms = Object.create(null);
974 for (const cliOption of cliOptions) {
975 if (!ignoreDefault && cliOption.config.default !== void 0) {
976 for (const name of cliOption.names) {
977 options[name] = cliOption.config.default;
978 }
979 }
980 if (Array.isArray(cliOption.config.type)) {
981 if (transforms[cliOption.name] === void 0) {
982 transforms[cliOption.name] = Object.create(null);
983 transforms[cliOption.name]["shouldTransform"] = true;
984 transforms[cliOption.name]["transformFunction"] = cliOption.config.type[0];
985 }
986 }
987 }
988 for (const key of Object.keys(parsed)) {
989 const keys = key.split(".");
990 setDotProp(options, keys, parsed[key]);
991 setByType(options, transforms);
992 }
993 return {
994 args,
995 options
996 };
997 }
998 runMatchedCommand() {
999 const {args, options, matchedCommand: command} = this;
1000 if (!command || !command.commandAction)
1001 return;
1002 command.checkUnknownOptions();
1003 command.checkOptionValue();
1004 command.checkRequiredArgs();
1005 const actionArgs = [];
1006 command.args.forEach((arg, index) => {
1007 if (arg.variadic) {
1008 actionArgs.push(args.slice(index));
1009 } else {
1010 actionArgs.push(args[index]);
1011 }
1012 });
1013 actionArgs.push(options);
1014 return command.commandAction.apply(this, actionArgs);
1015 }
1016}
1017
1018const cac = (name = "") => new CAC(name);
1019if (typeof module !== "undefined") {
1020 module.exports = cac;
1021 module.exports.default = cac;
1022 module.exports.cac = cac;
1023}
1024
1025export default cac;
1026export { cac };