UNPKG

147 kBJavaScriptView Raw
1'use strict';
2
3var fs = require('fs');
4var path = require('path');
5var index = require('./index-688c5d50.js');
6var os = require('os');
7var assert = require('assert');
8var Events = require('events');
9var readline = require('readline');
10require('stream');
11require('string_decoder');
12require('buffer');
13require('zlib');
14require('util');
15require('crypto');
16require('tty');
17require('constants');
18require('https');
19require('child_process');
20require('url');
21require('net');
22require('tls');
23
24function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
25
26var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
27var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
28var os__default = /*#__PURE__*/_interopDefaultLegacy(os);
29var assert__default = /*#__PURE__*/_interopDefaultLegacy(assert);
30var Events__default = /*#__PURE__*/_interopDefaultLegacy(Events);
31var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline);
32
33function toArr(any) {
34 return any == null ? [] : Array.isArray(any) ? any : [any];
35}
36
37function toVal(out, key, val, opts) {
38 var x, old=out[key], nxt=(
39 !!~opts.string.indexOf(key) ? (val == null || val === true ? '' : String(val))
40 : typeof val === 'boolean' ? val
41 : !!~opts.boolean.indexOf(key) ? (val === 'false' ? false : val === 'true' || (out._.push((x = +val,x * 0 === 0) ? x : val),!!val))
42 : (x = +val,x * 0 === 0) ? x : val
43 );
44 out[key] = old == null ? nxt : (Array.isArray(old) ? old.concat(nxt) : [old, nxt]);
45}
46
47function mri (args, opts) {
48 args = args || [];
49 opts = opts || {};
50
51 var k, arr, arg, name, val, out={ _:[] };
52 var i=0, j=0, idx=0, len=args.length;
53
54 const alibi = opts.alias !== void 0;
55 const strict = opts.unknown !== void 0;
56 const defaults = opts.default !== void 0;
57
58 opts.alias = opts.alias || {};
59 opts.string = toArr(opts.string);
60 opts.boolean = toArr(opts.boolean);
61
62 if (alibi) {
63 for (k in opts.alias) {
64 arr = opts.alias[k] = toArr(opts.alias[k]);
65 for (i=0; i < arr.length; i++) {
66 (opts.alias[arr[i]] = arr.concat(k)).splice(i, 1);
67 }
68 }
69 }
70
71 for (i=opts.boolean.length; i-- > 0;) {
72 arr = opts.alias[opts.boolean[i]] || [];
73 for (j=arr.length; j-- > 0;) opts.boolean.push(arr[j]);
74 }
75
76 for (i=opts.string.length; i-- > 0;) {
77 arr = opts.alias[opts.string[i]] || [];
78 for (j=arr.length; j-- > 0;) opts.string.push(arr[j]);
79 }
80
81 if (defaults) {
82 for (k in opts.default) {
83 name = typeof opts.default[k];
84 arr = opts.alias[k] = opts.alias[k] || [];
85 if (opts[name] !== void 0) {
86 opts[name].push(k);
87 for (i=0; i < arr.length; i++) {
88 opts[name].push(arr[i]);
89 }
90 }
91 }
92 }
93
94 const keys = strict ? Object.keys(opts.alias) : [];
95
96 for (i=0; i < len; i++) {
97 arg = args[i];
98
99 if (arg === '--') {
100 out._ = out._.concat(args.slice(++i));
101 break;
102 }
103
104 for (j=0; j < arg.length; j++) {
105 if (arg.charCodeAt(j) !== 45) break; // "-"
106 }
107
108 if (j === 0) {
109 out._.push(arg);
110 } else if (arg.substring(j, j + 3) === 'no-') {
111 name = arg.substring(j + 3);
112 if (strict && !~keys.indexOf(name)) {
113 return opts.unknown(arg);
114 }
115 out[name] = false;
116 } else {
117 for (idx=j+1; idx < arg.length; idx++) {
118 if (arg.charCodeAt(idx) === 61) break; // "="
119 }
120
121 name = arg.substring(j, idx);
122 val = arg.substring(++idx) || (i+1 === len || (''+args[i+1]).charCodeAt(0) === 45 || args[++i]);
123 arr = (j === 2 ? [name] : name);
124
125 for (idx=0; idx < arr.length; idx++) {
126 name = arr[idx];
127 if (strict && !~keys.indexOf(name)) return opts.unknown('-'.repeat(j) + name);
128 toVal(out, name, (idx + 1 < arr.length) || val, opts);
129 }
130 }
131 }
132
133 if (defaults) {
134 for (k in opts.default) {
135 if (out[k] === void 0) {
136 out[k] = opts.default[k];
137 }
138 }
139 }
140
141 if (alibi) {
142 for (k in out) {
143 arr = opts.alias[k] || [];
144 while (arr.length > 0) {
145 out[arr.shift()] = out[k];
146 }
147 }
148 }
149
150 return out;
151}
152
153const isWin$1 = process.platform === 'win32';
154const SEP = isWin$1 ? `\\\\+` : `\\/`;
155const SEP_ESC = isWin$1 ? `\\\\` : `/`;
156const GLOBSTAR = `((?:[^/]*(?:/|$))*)`;
157const WILDCARD = `([^/]*)`;
158const GLOBSTAR_SEGMENT = `((?:[^${SEP_ESC}]*(?:${SEP_ESC}|$))*)`;
159const WILDCARD_SEGMENT = `([^${SEP_ESC}]*)`;
160
161/**
162 * Convert any glob pattern to a JavaScript Regexp object
163 * @param {String} glob Glob pattern to convert
164 * @param {Object} opts Configuration object
165 * @param {Boolean} [opts.extended=false] Support advanced ext globbing
166 * @param {Boolean} [opts.globstar=false] Support globstar
167 * @param {Boolean} [opts.strict=true] be laissez faire about mutiple slashes
168 * @param {Boolean} [opts.filepath=''] Parse as filepath for extra path related features
169 * @param {String} [opts.flags=''] RegExp globs
170 * @returns {Object} converted object with string, segments and RegExp object
171 */
172function globrex(glob, {extended = false, globstar = false, strict = false, filepath = false, flags = ''} = {}) {
173 let regex = '';
174 let segment = '';
175 let path = { regex: '', segments: [] };
176
177 // If we are doing extended matching, this boolean is true when we are inside
178 // a group (eg {*.html,*.js}), and false otherwise.
179 let inGroup = false;
180 let inRange = false;
181
182 // extglob stack. Keep track of scope
183 const ext = [];
184
185 // Helper function to build string and segments
186 function add(str, {split, last, only}={}) {
187 if (only !== 'path') regex += str;
188 if (filepath && only !== 'regex') {
189 path.regex += (str === '\\/' ? SEP : str);
190 if (split) {
191 if (last) segment += str;
192 if (segment !== '') {
193 if (!flags.includes('g')) segment = `^${segment}$`; // change it 'includes'
194 path.segments.push(new RegExp(segment, flags));
195 }
196 segment = '';
197 } else {
198 segment += str;
199 }
200 }
201 }
202
203 let c, n;
204 for (let i = 0; i < glob.length; i++) {
205 c = glob[i];
206 n = glob[i + 1];
207
208 if (['\\', '$', '^', '.', '='].includes(c)) {
209 add(`\\${c}`);
210 continue;
211 }
212
213 if (c === '/') {
214 add(`\\${c}`, {split: true});
215 if (n === '/' && !strict) regex += '?';
216 continue;
217 }
218
219 if (c === '(') {
220 if (ext.length) {
221 add(c);
222 continue;
223 }
224 add(`\\${c}`);
225 continue;
226 }
227
228 if (c === ')') {
229 if (ext.length) {
230 add(c);
231 let type = ext.pop();
232 if (type === '@') {
233 add('{1}');
234 } else if (type === '!') {
235 add('([^\/]*)');
236 } else {
237 add(type);
238 }
239 continue;
240 }
241 add(`\\${c}`);
242 continue;
243 }
244
245 if (c === '|') {
246 if (ext.length) {
247 add(c);
248 continue;
249 }
250 add(`\\${c}`);
251 continue;
252 }
253
254 if (c === '+') {
255 if (n === '(' && extended) {
256 ext.push(c);
257 continue;
258 }
259 add(`\\${c}`);
260 continue;
261 }
262
263 if (c === '@' && extended) {
264 if (n === '(') {
265 ext.push(c);
266 continue;
267 }
268 }
269
270 if (c === '!') {
271 if (extended) {
272 if (inRange) {
273 add('^');
274 continue
275 }
276 if (n === '(') {
277 ext.push(c);
278 add('(?!');
279 i++;
280 continue;
281 }
282 add(`\\${c}`);
283 continue;
284 }
285 add(`\\${c}`);
286 continue;
287 }
288
289 if (c === '?') {
290 if (extended) {
291 if (n === '(') {
292 ext.push(c);
293 } else {
294 add('.');
295 }
296 continue;
297 }
298 add(`\\${c}`);
299 continue;
300 }
301
302 if (c === '[') {
303 if (inRange && n === ':') {
304 i++; // skip [
305 let value = '';
306 while(glob[++i] !== ':') value += glob[i];
307 if (value === 'alnum') add('(\\w|\\d)');
308 else if (value === 'space') add('\\s');
309 else if (value === 'digit') add('\\d');
310 i++; // skip last ]
311 continue;
312 }
313 if (extended) {
314 inRange = true;
315 add(c);
316 continue;
317 }
318 add(`\\${c}`);
319 continue;
320 }
321
322 if (c === ']') {
323 if (extended) {
324 inRange = false;
325 add(c);
326 continue;
327 }
328 add(`\\${c}`);
329 continue;
330 }
331
332 if (c === '{') {
333 if (extended) {
334 inGroup = true;
335 add('(');
336 continue;
337 }
338 add(`\\${c}`);
339 continue;
340 }
341
342 if (c === '}') {
343 if (extended) {
344 inGroup = false;
345 add(')');
346 continue;
347 }
348 add(`\\${c}`);
349 continue;
350 }
351
352 if (c === ',') {
353 if (inGroup) {
354 add('|');
355 continue;
356 }
357 add(`\\${c}`);
358 continue;
359 }
360
361 if (c === '*') {
362 if (n === '(' && extended) {
363 ext.push(c);
364 continue;
365 }
366 // Move over all consecutive "*"'s.
367 // Also store the previous and next characters
368 let prevChar = glob[i - 1];
369 let starCount = 1;
370 while (glob[i + 1] === '*') {
371 starCount++;
372 i++;
373 }
374 let nextChar = glob[i + 1];
375 if (!globstar) {
376 // globstar is disabled, so treat any number of "*" as one
377 add('.*');
378 } else {
379 // globstar is enabled, so determine if this is a globstar segment
380 let isGlobstar =
381 starCount > 1 && // multiple "*"'s
382 (prevChar === '/' || prevChar === undefined) && // from the start of the segment
383 (nextChar === '/' || nextChar === undefined); // to the end of the segment
384 if (isGlobstar) {
385 // it's a globstar, so match zero or more path segments
386 add(GLOBSTAR, {only:'regex'});
387 add(GLOBSTAR_SEGMENT, {only:'path', last:true, split:true});
388 i++; // move over the "/"
389 } else {
390 // it's not a globstar, so only match one path segment
391 add(WILDCARD, {only:'regex'});
392 add(WILDCARD_SEGMENT, {only:'path'});
393 }
394 }
395 continue;
396 }
397
398 add(c);
399 }
400
401
402 // When regexp 'g' flag is specified don't
403 // constrain the regular expression with ^ & $
404 if (!flags.includes('g')) {
405 regex = `^${regex}$`;
406 segment = `^${segment}$`;
407 if (filepath) path.regex = `^${path.regex}$`;
408 }
409
410 const result = {regex: new RegExp(regex, flags)};
411
412 // Push the last segment
413 if (filepath) {
414 path.segments.push(new RegExp(segment, flags));
415 path.regex = new RegExp(path.regex, flags);
416 path.globstar = new RegExp(!flags.includes('g') ? `^${GLOBSTAR_SEGMENT}$` : GLOBSTAR_SEGMENT, flags);
417 result.path = path;
418 }
419
420 return result;
421}
422
423var globrex_1 = globrex;
424
425const isWin = os__default['default'].platform() === 'win32';
426
427const CHARS = { '{': '}', '(': ')', '[': ']'};
428const STRICT = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\)|(\\).|([@?!+*]\(.*\)))/;
429const RELAXED = /\\(.)|(^!|[*?{}()[\]]|\(\?)/;
430
431/**
432 * Detect if a string cointains glob
433 * @param {String} str Input string
434 * @param {Object} [options] Configuration object
435 * @param {Boolean} [options.strict=true] Use relaxed regex if true
436 * @returns {Boolean} true if string contains glob
437 */
438function isglob(str, { strict = true } = {}) {
439 if (str === '') return false;
440 let match, rgx = strict ? STRICT : RELAXED;
441
442 while ((match = rgx.exec(str))) {
443 if (match[2]) return true;
444 let idx = match.index + match[0].length;
445
446 // if an open bracket/brace/paren is escaped,
447 // set the index to the next closing character
448 let open = match[1];
449 let close = open ? CHARS[open] : null;
450 if (open && close) {
451 let n = str.indexOf(close, idx);
452 if (n !== -1) idx = n + 1;
453 }
454
455 str = str.slice(idx);
456 }
457 return false;
458}
459
460
461/**
462 * Find the static part of a glob-path,
463 * split path and return path part
464 * @param {String} str Path/glob string
465 * @returns {String} static path section of glob
466 */
467function parent(str, { strict = false } = {}) {
468 if (isWin && str.includes('/'))
469 str = str.split('\\').join('/');
470
471 // special case for strings ending in enclosure containing path separator
472 if (/[\{\[].*[\/]*.*[\}\]]$/.test(str)) str += '/';
473
474 // preserves full path in case of trailing path separator
475 str += 'a';
476
477 do {str = path__default['default'].dirname(str);}
478 while (isglob(str, {strict}) || /(^|[^\\])([\{\[]|\([^\)]+$)/.test(str));
479
480 // remove escape chars and return result
481 return str.replace(/\\([\*\?\|\[\]\(\)\{\}])/g, '$1');
482}
483
484/**
485 * Parse a glob path, and split it by static/glob part
486 * @param {String} pattern String path
487 * @param {Object} [opts] Options
488 * @param {Object} [opts.strict=false] Use strict parsing
489 * @returns {Object} object with parsed path
490 */
491function globalyzer(pattern, opts = {}) {
492 let base = parent(pattern, opts);
493 let isGlob = isglob(pattern, opts);
494 let glob;
495
496 if (base != '.') {
497 glob = pattern.substr(base.length);
498 if (glob.startsWith('/')) glob = glob.substr(1);
499 } else {
500 glob = pattern;
501 }
502
503 if (!isGlob) {
504 base = path__default['default'].dirname(pattern);
505 glob = base !== '.' ? pattern.substr(base.length) : pattern;
506 }
507
508 if (glob.startsWith('./')) glob = glob.substr(2);
509 if (glob.startsWith('/')) glob = glob.substr(1);
510
511 return { base, glob, isGlob };
512}
513
514
515var src$1 = globalyzer;
516
517const { join, resolve, relative } = path__default['default'];
518const isHidden = /(^|[\\\/])\.[^\\\/\.]/g;
519
520let CACHE = {};
521
522function walk(output, prefix, lexer, opts, dirname='', level=0) {
523 const rgx = lexer.segments[level];
524 const dir = resolve(opts.cwd, prefix, dirname);
525 const files = fs__default['default'].readdirSync(dir);
526 const { dot, filesOnly } = opts;
527
528 let i=0, len=files.length, file;
529 let fullpath, relpath, stats, isMatch;
530
531 for (; i < len; i++) {
532 fullpath = join(dir, file=files[i]);
533 relpath = dirname ? join(dirname, file) : file;
534 if (!dot && isHidden.test(relpath)) continue;
535 isMatch = lexer.regex.test(relpath);
536
537 if ((stats=CACHE[relpath]) === void 0) {
538 CACHE[relpath] = stats = fs__default['default'].lstatSync(fullpath);
539 }
540
541 if (!stats.isDirectory()) {
542 isMatch && output.push(relative(opts.cwd, fullpath));
543 continue;
544 }
545
546 if (rgx && !rgx.test(file)) continue;
547 !filesOnly && isMatch && output.push(join(prefix, relpath));
548
549 walk(output, prefix, lexer, opts, relpath, rgx && rgx.toString() !== lexer.globstar && level + 1);
550 }
551}
552
553/**
554 * Find files using bash-like globbing.
555 * All paths are normalized compared to node-glob.
556 * @param {String} str Glob string
557 * @param {String} [options.cwd='.'] Current working directory
558 * @param {Boolean} [options.dot=false] Include dotfile matches
559 * @param {Boolean} [options.absolute=false] Return absolute paths
560 * @param {Boolean} [options.filesOnly=false] Do not include folders if true
561 * @param {Boolean} [options.flush=false] Reset cache object
562 * @returns {Array} array containing matching files
563 */
564var sync = function (str, opts={}) {
565 if (!str) return [];
566
567 let glob = src$1(str);
568
569 opts.cwd = opts.cwd || '.';
570
571 if (!glob.isGlob) {
572 try {
573 let resolved = resolve(opts.cwd, str);
574 let dirent = fs__default['default'].statSync(resolved);
575 if (opts.filesOnly && !dirent.isFile()) return [];
576
577 return opts.absolute ? [resolved] : [str];
578 } catch (err) {
579 if (err.code != 'ENOENT') throw err;
580
581 return [];
582 }
583 }
584
585 if (opts.flush) CACHE = {};
586
587 let matches = [];
588 const { path } = globrex_1(glob.glob, { filepath:true, globstar:true, extended:true });
589
590 path.globstar = path.globstar.toString();
591 walk(matches, glob.base, path, opts, '.', 0);
592
593 return opts.absolute ? matches.map(x => resolve(opts.cwd, x)) : matches;
594};
595
596function fuzzysearch (needle, haystack) {
597 var tlen = haystack.length;
598 var qlen = needle.length;
599 if (qlen > tlen) {
600 return false;
601 }
602 if (qlen === tlen) {
603 return needle === haystack;
604 }
605 outer: for (var i = 0, j = 0; i < qlen; i++) {
606 var nch = needle.charCodeAt(i);
607 while (j < tlen) {
608 if (haystack.charCodeAt(j++) === nch) {
609 continue outer;
610 }
611 }
612 return false;
613 }
614 return true;
615}
616
617var fuzzysearch_1 = fuzzysearch;
618
619var symbols$1 = index.createCommonjsModule(function (module) {
620
621const isHyper = process.env.TERM_PROGRAM === 'Hyper';
622const isWindows = process.platform === 'win32';
623const isLinux = process.platform === 'linux';
624
625const common = {
626 ballotDisabled: '☒',
627 ballotOff: '☐',
628 ballotOn: '☑',
629 bullet: '•',
630 bulletWhite: '◦',
631 fullBlock: '█',
632 heart: '❤',
633 identicalTo: '≡',
634 line: '─',
635 mark: '※',
636 middot: '·',
637 minus: '-',
638 multiplication: '×',
639 obelus: '÷',
640 pencilDownRight: '✎',
641 pencilRight: '✏',
642 pencilUpRight: '✐',
643 percent: '%',
644 pilcrow2: '❡',
645 pilcrow: '¶',
646 plusMinus: '±',
647 section: '§',
648 starsOff: '☆',
649 starsOn: '★',
650 upDownArrow: '↕'
651};
652
653const windows = Object.assign({}, common, {
654 check: '√',
655 cross: '×',
656 ellipsisLarge: '...',
657 ellipsis: '...',
658 info: 'i',
659 question: '?',
660 questionSmall: '?',
661 pointer: '>',
662 pointerSmall: '»',
663 radioOff: '( )',
664 radioOn: '(*)',
665 warning: '‼'
666});
667
668const other = Object.assign({}, common, {
669 ballotCross: '✘',
670 check: '✔',
671 cross: '✖',
672 ellipsisLarge: '⋯',
673 ellipsis: '…',
674 info: 'ℹ',
675 question: '?',
676 questionFull: '?',
677 questionSmall: '﹖',
678 pointer: isLinux ? '▸' : '❯',
679 pointerSmall: isLinux ? '‣' : '›',
680 radioOff: '◯',
681 radioOn: '◉',
682 warning: '⚠'
683});
684
685module.exports = (isWindows && !isHyper) ? windows : other;
686Reflect.defineProperty(module.exports, 'common', { enumerable: false, value: common });
687Reflect.defineProperty(module.exports, 'windows', { enumerable: false, value: windows });
688Reflect.defineProperty(module.exports, 'other', { enumerable: false, value: other });
689});
690
691const isObject$1 = val => val !== null && typeof val === 'object' && !Array.isArray(val);
692
693/* eslint-disable no-control-regex */
694// this is a modified version of https://github.com/chalk/ansi-regex (MIT License)
695const ANSI_REGEX = /[\u001b\u009b][[\]#;?()]*(?:(?:(?:[^\W_]*;?[^\W_]*)\u0007)|(?:(?:[0-9]{1,4}(;[0-9]{0,4})*)?[~0-9=<>cf-nqrtyA-PRZ]))/g;
696
697const create$1 = () => {
698 const colors = { enabled: true, visible: true, styles: {}, keys: {} };
699
700 if ('FORCE_COLOR' in process.env) {
701 colors.enabled = process.env.FORCE_COLOR !== '0';
702 }
703
704 const ansi = style => {
705 let open = style.open = `\u001b[${style.codes[0]}m`;
706 let close = style.close = `\u001b[${style.codes[1]}m`;
707 let regex = style.regex = new RegExp(`\\u001b\\[${style.codes[1]}m`, 'g');
708 style.wrap = (input, newline) => {
709 if (input.includes(close)) input = input.replace(regex, close + open);
710 let output = open + input + close;
711 // see https://github.com/chalk/chalk/pull/92, thanks to the
712 // chalk contributors for this fix. However, we've confirmed that
713 // this issue is also present in Windows terminals
714 return newline ? output.replace(/\r*\n/g, `${close}$&${open}`) : output;
715 };
716 return style;
717 };
718
719 const wrap = (style, input, newline) => {
720 return typeof style === 'function' ? style(input) : style.wrap(input, newline);
721 };
722
723 const style = (input, stack) => {
724 if (input === '' || input == null) return '';
725 if (colors.enabled === false) return input;
726 if (colors.visible === false) return '';
727 let str = '' + input;
728 let nl = str.includes('\n');
729 let n = stack.length;
730 if (n > 0 && stack.includes('unstyle')) {
731 stack = [...new Set(['unstyle', ...stack])].reverse();
732 }
733 while (n-- > 0) str = wrap(colors.styles[stack[n]], str, nl);
734 return str;
735 };
736
737 const define = (name, codes, type) => {
738 colors.styles[name] = ansi({ name, codes });
739 let keys = colors.keys[type] || (colors.keys[type] = []);
740 keys.push(name);
741
742 Reflect.defineProperty(colors, name, {
743 configurable: true,
744 enumerable: true,
745 set(value) {
746 colors.alias(name, value);
747 },
748 get() {
749 let color = input => style(input, color.stack);
750 Reflect.setPrototypeOf(color, colors);
751 color.stack = this.stack ? this.stack.concat(name) : [name];
752 return color;
753 }
754 });
755 };
756
757 define('reset', [0, 0], 'modifier');
758 define('bold', [1, 22], 'modifier');
759 define('dim', [2, 22], 'modifier');
760 define('italic', [3, 23], 'modifier');
761 define('underline', [4, 24], 'modifier');
762 define('inverse', [7, 27], 'modifier');
763 define('hidden', [8, 28], 'modifier');
764 define('strikethrough', [9, 29], 'modifier');
765
766 define('black', [30, 39], 'color');
767 define('red', [31, 39], 'color');
768 define('green', [32, 39], 'color');
769 define('yellow', [33, 39], 'color');
770 define('blue', [34, 39], 'color');
771 define('magenta', [35, 39], 'color');
772 define('cyan', [36, 39], 'color');
773 define('white', [37, 39], 'color');
774 define('gray', [90, 39], 'color');
775 define('grey', [90, 39], 'color');
776
777 define('bgBlack', [40, 49], 'bg');
778 define('bgRed', [41, 49], 'bg');
779 define('bgGreen', [42, 49], 'bg');
780 define('bgYellow', [43, 49], 'bg');
781 define('bgBlue', [44, 49], 'bg');
782 define('bgMagenta', [45, 49], 'bg');
783 define('bgCyan', [46, 49], 'bg');
784 define('bgWhite', [47, 49], 'bg');
785
786 define('blackBright', [90, 39], 'bright');
787 define('redBright', [91, 39], 'bright');
788 define('greenBright', [92, 39], 'bright');
789 define('yellowBright', [93, 39], 'bright');
790 define('blueBright', [94, 39], 'bright');
791 define('magentaBright', [95, 39], 'bright');
792 define('cyanBright', [96, 39], 'bright');
793 define('whiteBright', [97, 39], 'bright');
794
795 define('bgBlackBright', [100, 49], 'bgBright');
796 define('bgRedBright', [101, 49], 'bgBright');
797 define('bgGreenBright', [102, 49], 'bgBright');
798 define('bgYellowBright', [103, 49], 'bgBright');
799 define('bgBlueBright', [104, 49], 'bgBright');
800 define('bgMagentaBright', [105, 49], 'bgBright');
801 define('bgCyanBright', [106, 49], 'bgBright');
802 define('bgWhiteBright', [107, 49], 'bgBright');
803
804 colors.ansiRegex = ANSI_REGEX;
805 colors.hasColor = colors.hasAnsi = str => {
806 colors.ansiRegex.lastIndex = 0;
807 return typeof str === 'string' && str !== '' && colors.ansiRegex.test(str);
808 };
809
810 colors.alias = (name, color) => {
811 let fn = typeof color === 'string' ? colors[color] : color;
812
813 if (typeof fn !== 'function') {
814 throw new TypeError('Expected alias to be the name of an existing color (string) or a function');
815 }
816
817 if (!fn.stack) {
818 Reflect.defineProperty(fn, 'name', { value: name });
819 colors.styles[name] = fn;
820 fn.stack = [name];
821 }
822
823 Reflect.defineProperty(colors, name, {
824 configurable: true,
825 enumerable: true,
826 set(value) {
827 colors.alias(name, value);
828 },
829 get() {
830 let color = input => style(input, color.stack);
831 Reflect.setPrototypeOf(color, colors);
832 color.stack = this.stack ? this.stack.concat(fn.stack) : fn.stack;
833 return color;
834 }
835 });
836 };
837
838 colors.theme = custom => {
839 if (!isObject$1(custom)) throw new TypeError('Expected theme to be an object');
840 for (let name of Object.keys(custom)) {
841 colors.alias(name, custom[name]);
842 }
843 return colors;
844 };
845
846 colors.alias('unstyle', str => {
847 if (typeof str === 'string' && str !== '') {
848 colors.ansiRegex.lastIndex = 0;
849 return str.replace(colors.ansiRegex, '');
850 }
851 return '';
852 });
853
854 colors.alias('noop', str => str);
855 colors.none = colors.clear = colors.noop;
856
857 colors.stripColor = colors.unstyle;
858 colors.symbols = symbols$1;
859 colors.define = define;
860 return colors;
861};
862
863var ansiColors = create$1();
864var create_1 = create$1;
865ansiColors.create = create_1;
866
867var utils = index.createCommonjsModule(function (module, exports) {
868
869const toString = Object.prototype.toString;
870
871let called = false;
872let fns = [];
873
874const complements = {
875 'yellow': 'blue',
876 'cyan': 'red',
877 'green': 'magenta',
878 'black': 'white',
879 'blue': 'yellow',
880 'red': 'cyan',
881 'magenta': 'green',
882 'white': 'black'
883};
884
885exports.longest = (arr, prop) => {
886 return arr.reduce((a, v) => Math.max(a, prop ? v[prop].length : v.length), 0);
887};
888
889exports.hasColor = str => !!str && ansiColors.hasColor(str);
890
891const isObject = exports.isObject = val => {
892 return val !== null && typeof val === 'object' && !Array.isArray(val);
893};
894
895exports.nativeType = val => {
896 return toString.call(val).slice(8, -1).toLowerCase().replace(/\s/g, '');
897};
898
899exports.isAsyncFn = val => {
900 return exports.nativeType(val) === 'asyncfunction';
901};
902
903exports.isPrimitive = val => {
904 return val != null && typeof val !== 'object' && typeof val !== 'function';
905};
906
907exports.resolve = (context, value, ...rest) => {
908 if (typeof value === 'function') {
909 return value.call(context, ...rest);
910 }
911 return value;
912};
913
914exports.scrollDown = (choices = []) => [...choices.slice(1), choices[0]];
915exports.scrollUp = (choices = []) => [choices.pop(), ...choices];
916
917exports.reorder = (arr = []) => {
918 let res = arr.slice();
919 res.sort((a, b) => {
920 if (a.index > b.index) return 1;
921 if (a.index < b.index) return -1;
922 return 0;
923 });
924 return res;
925};
926
927exports.swap = (arr, index, pos) => {
928 let len = arr.length;
929 let idx = pos === len ? 0 : pos < 0 ? len - 1 : pos;
930 let choice = arr[index];
931 arr[index] = arr[idx];
932 arr[idx] = choice;
933};
934
935exports.width = (stream, fallback = 80) => {
936 let columns = (stream && stream.columns) ? stream.columns : fallback;
937 if (stream && typeof stream.getWindowSize === 'function') {
938 columns = stream.getWindowSize()[0];
939 }
940 if (process.platform === 'win32') {
941 return columns - 1;
942 }
943 return columns;
944};
945
946exports.height = (stream, fallback = 20) => {
947 let rows = (stream && stream.rows) ? stream.rows : fallback;
948 if (stream && typeof stream.getWindowSize === 'function') {
949 rows = stream.getWindowSize()[1];
950 }
951 return rows;
952};
953
954exports.wordWrap = (str, options = {}) => {
955 if (!str) return str;
956
957 if (typeof options === 'number') {
958 options = { width: options };
959 }
960
961 let { indent = '', newline = ('\n' + indent), width = 80 } = options;
962 let spaces = (newline + indent).match(/[^\S\n]/g) || [];
963 width -= spaces.length;
964 let source = `.{1,${width}}([\\s\\u200B]+|$)|[^\\s\\u200B]+?([\\s\\u200B]+|$)`;
965 let output = str.trim();
966 let regex = new RegExp(source, 'g');
967 let lines = output.match(regex) || [];
968 lines = lines.map(line => line.replace(/\n$/, ''));
969 if (options.padEnd) lines = lines.map(line => line.padEnd(width, ' '));
970 if (options.padStart) lines = lines.map(line => line.padStart(width, ' '));
971 return indent + lines.join(newline);
972};
973
974exports.unmute = color => {
975 let name = color.stack.find(n => ansiColors.keys.color.includes(n));
976 if (name) {
977 return ansiColors[name];
978 }
979 let bg = color.stack.find(n => n.slice(2) === 'bg');
980 if (bg) {
981 return ansiColors[name.slice(2)];
982 }
983 return str => str;
984};
985
986exports.pascal = str => str ? str[0].toUpperCase() + str.slice(1) : '';
987
988exports.inverse = color => {
989 if (!color || !color.stack) return color;
990 let name = color.stack.find(n => ansiColors.keys.color.includes(n));
991 if (name) {
992 let col = ansiColors['bg' + exports.pascal(name)];
993 return col ? col.black : color;
994 }
995 let bg = color.stack.find(n => n.slice(0, 2) === 'bg');
996 if (bg) {
997 return ansiColors[bg.slice(2).toLowerCase()] || color;
998 }
999 return ansiColors.none;
1000};
1001
1002exports.complement = color => {
1003 if (!color || !color.stack) return color;
1004 let name = color.stack.find(n => ansiColors.keys.color.includes(n));
1005 let bg = color.stack.find(n => n.slice(0, 2) === 'bg');
1006 if (name && !bg) {
1007 return ansiColors[complements[name] || name];
1008 }
1009 if (bg) {
1010 let lower = bg.slice(2).toLowerCase();
1011 let comp = complements[lower];
1012 if (!comp) return color;
1013 return ansiColors['bg' + exports.pascal(comp)] || color;
1014 }
1015 return ansiColors.none;
1016};
1017
1018exports.meridiem = date => {
1019 let hours = date.getHours();
1020 let minutes = date.getMinutes();
1021 let ampm = hours >= 12 ? 'pm' : 'am';
1022 hours = hours % 12;
1023 let hrs = hours === 0 ? 12 : hours;
1024 let min = minutes < 10 ? '0' + minutes : minutes;
1025 return hrs + ':' + min + ' ' + ampm;
1026};
1027
1028/**
1029 * Set a value on the given object.
1030 * @param {Object} obj
1031 * @param {String} prop
1032 * @param {any} value
1033 */
1034
1035exports.set = (obj = {}, prop = '', val) => {
1036 return prop.split('.').reduce((acc, k, i, arr) => {
1037 let value = arr.length - 1 > i ? (acc[k] || {}) : val;
1038 if (!exports.isObject(value) && i < arr.length - 1) value = {};
1039 return (acc[k] = value);
1040 }, obj);
1041};
1042
1043/**
1044 * Get a value from the given object.
1045 * @param {Object} obj
1046 * @param {String} prop
1047 */
1048
1049exports.get = (obj = {}, prop = '', fallback) => {
1050 let value = obj[prop] == null
1051 ? prop.split('.').reduce((acc, k) => acc && acc[k], obj)
1052 : obj[prop];
1053 return value == null ? fallback : value;
1054};
1055
1056exports.mixin = (target, b) => {
1057 if (!isObject(target)) return b;
1058 if (!isObject(b)) return target;
1059 for (let key of Object.keys(b)) {
1060 let desc = Object.getOwnPropertyDescriptor(b, key);
1061 if (desc.hasOwnProperty('value')) {
1062 if (target.hasOwnProperty(key) && isObject(desc.value)) {
1063 let existing = Object.getOwnPropertyDescriptor(target, key);
1064 if (isObject(existing.value)) {
1065 target[key] = exports.merge({}, target[key], b[key]);
1066 } else {
1067 Reflect.defineProperty(target, key, desc);
1068 }
1069 } else {
1070 Reflect.defineProperty(target, key, desc);
1071 }
1072 } else {
1073 Reflect.defineProperty(target, key, desc);
1074 }
1075 }
1076 return target;
1077};
1078
1079exports.merge = (...args) => {
1080 let target = {};
1081 for (let ele of args) exports.mixin(target, ele);
1082 return target;
1083};
1084
1085exports.mixinEmitter = (obj, emitter) => {
1086 let proto = emitter.constructor.prototype;
1087 for (let key of Object.keys(proto)) {
1088 let val = proto[key];
1089 if (typeof val === 'function') {
1090 exports.define(obj, key, val.bind(emitter));
1091 } else {
1092 exports.define(obj, key, val);
1093 }
1094 }
1095};
1096
1097exports.onExit = callback => {
1098 const onExit = (quit, code) => {
1099 if (called) return;
1100
1101 called = true;
1102 fns.forEach(fn => fn());
1103
1104 if (quit === true) {
1105 process.exit(128 + code);
1106 }
1107 };
1108
1109 if (fns.length === 0) {
1110 process.once('SIGTERM', onExit.bind(null, true, 15));
1111 process.once('SIGINT', onExit.bind(null, true, 2));
1112 process.once('exit', onExit);
1113 }
1114
1115 fns.push(callback);
1116};
1117
1118exports.define = (obj, key, value) => {
1119 Reflect.defineProperty(obj, key, { value });
1120};
1121
1122exports.defineExport = (obj, key, fn) => {
1123 let custom;
1124 Reflect.defineProperty(obj, key, {
1125 enumerable: true,
1126 configurable: true,
1127 set(val) {
1128 custom = val;
1129 },
1130 get() {
1131 return custom ? custom() : fn();
1132 }
1133 });
1134};
1135});
1136
1137/**
1138 * Actions are mappings from keypress event names to method names
1139 * in the prompts.
1140 */
1141
1142var ctrl = {
1143 a: 'first',
1144 b: 'backward',
1145 c: 'cancel',
1146 d: 'deleteForward',
1147 e: 'last',
1148 f: 'forward',
1149 g: 'reset',
1150 i: 'tab',
1151 k: 'cutForward',
1152 l: 'reset',
1153 n: 'newItem',
1154 m: 'cancel',
1155 j: 'submit',
1156 p: 'search',
1157 r: 'remove',
1158 s: 'save',
1159 u: 'undo',
1160 w: 'cutLeft',
1161 x: 'toggleCursor',
1162 v: 'paste'
1163};
1164
1165var shift = {
1166 up: 'shiftUp',
1167 down: 'shiftDown',
1168 left: 'shiftLeft',
1169 right: 'shiftRight',
1170 tab: 'prev'
1171};
1172
1173var fn = {
1174 up: 'pageUp',
1175 down: 'pageDown',
1176 left: 'pageLeft',
1177 right: 'pageRight',
1178 delete: 'deleteForward'
1179};
1180
1181// <alt> on Windows
1182var option = {
1183 b: 'backward',
1184 f: 'forward',
1185 d: 'cutRight',
1186 left: 'cutLeft',
1187 up: 'altUp',
1188 down: 'altDown'
1189};
1190
1191var keys = {
1192 pageup: 'pageUp', // <fn>+<up> (mac), <Page Up> (windows)
1193 pagedown: 'pageDown', // <fn>+<down> (mac), <Page Down> (windows)
1194 home: 'home', // <fn>+<left> (mac), <home> (windows)
1195 end: 'end', // <fn>+<right> (mac), <end> (windows)
1196 cancel: 'cancel',
1197 delete: 'deleteForward',
1198 backspace: 'delete',
1199 down: 'down',
1200 enter: 'submit',
1201 escape: 'cancel',
1202 left: 'left',
1203 space: 'space',
1204 number: 'number',
1205 return: 'submit',
1206 right: 'right',
1207 tab: 'next',
1208 up: 'up'
1209};
1210
1211var combos = {
1212 ctrl: ctrl,
1213 shift: shift,
1214 fn: fn,
1215 option: option,
1216 keys: keys
1217};
1218
1219/* eslint-disable no-control-regex */
1220const metaKeyCodeRe = /^(?:\x1b)([a-zA-Z0-9])$/;
1221const fnKeyRe = /^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/;
1222const keyName = {
1223 /* xterm/gnome ESC O letter */
1224 'OP': 'f1',
1225 'OQ': 'f2',
1226 'OR': 'f3',
1227 'OS': 'f4',
1228 /* xterm/rxvt ESC [ number ~ */
1229 '[11~': 'f1',
1230 '[12~': 'f2',
1231 '[13~': 'f3',
1232 '[14~': 'f4',
1233 /* from Cygwin and used in libuv */
1234 '[[A': 'f1',
1235 '[[B': 'f2',
1236 '[[C': 'f3',
1237 '[[D': 'f4',
1238 '[[E': 'f5',
1239 /* common */
1240 '[15~': 'f5',
1241 '[17~': 'f6',
1242 '[18~': 'f7',
1243 '[19~': 'f8',
1244 '[20~': 'f9',
1245 '[21~': 'f10',
1246 '[23~': 'f11',
1247 '[24~': 'f12',
1248 /* xterm ESC [ letter */
1249 '[A': 'up',
1250 '[B': 'down',
1251 '[C': 'right',
1252 '[D': 'left',
1253 '[E': 'clear',
1254 '[F': 'end',
1255 '[H': 'home',
1256 /* xterm/gnome ESC O letter */
1257 'OA': 'up',
1258 'OB': 'down',
1259 'OC': 'right',
1260 'OD': 'left',
1261 'OE': 'clear',
1262 'OF': 'end',
1263 'OH': 'home',
1264 /* xterm/rxvt ESC [ number ~ */
1265 '[1~': 'home',
1266 '[2~': 'insert',
1267 '[3~': 'delete',
1268 '[4~': 'end',
1269 '[5~': 'pageup',
1270 '[6~': 'pagedown',
1271 /* putty */
1272 '[[5~': 'pageup',
1273 '[[6~': 'pagedown',
1274 /* rxvt */
1275 '[7~': 'home',
1276 '[8~': 'end',
1277 /* rxvt keys with modifiers */
1278 '[a': 'up',
1279 '[b': 'down',
1280 '[c': 'right',
1281 '[d': 'left',
1282 '[e': 'clear',
1283
1284 '[2$': 'insert',
1285 '[3$': 'delete',
1286 '[5$': 'pageup',
1287 '[6$': 'pagedown',
1288 '[7$': 'home',
1289 '[8$': 'end',
1290
1291 'Oa': 'up',
1292 'Ob': 'down',
1293 'Oc': 'right',
1294 'Od': 'left',
1295 'Oe': 'clear',
1296
1297 '[2^': 'insert',
1298 '[3^': 'delete',
1299 '[5^': 'pageup',
1300 '[6^': 'pagedown',
1301 '[7^': 'home',
1302 '[8^': 'end',
1303 /* misc. */
1304 '[Z': 'tab',
1305};
1306
1307function isShiftKey(code) {
1308 return ['[a', '[b', '[c', '[d', '[e', '[2$', '[3$', '[5$', '[6$', '[7$', '[8$', '[Z'].includes(code)
1309}
1310
1311function isCtrlKey(code) {
1312 return [ 'Oa', 'Ob', 'Oc', 'Od', 'Oe', '[2^', '[3^', '[5^', '[6^', '[7^', '[8^'].includes(code)
1313}
1314
1315const keypress = (s = '', event = {}) => {
1316 let parts;
1317 let key = {
1318 name: event.name,
1319 ctrl: false,
1320 meta: false,
1321 shift: false,
1322 option: false,
1323 sequence: s,
1324 raw: s,
1325 ...event
1326 };
1327
1328 if (Buffer.isBuffer(s)) {
1329 if (s[0] > 127 && s[1] === void 0) {
1330 s[0] -= 128;
1331 s = '\x1b' + String(s);
1332 } else {
1333 s = String(s);
1334 }
1335 } else if (s !== void 0 && typeof s !== 'string') {
1336 s = String(s);
1337 } else if (!s) {
1338 s = key.sequence || '';
1339 }
1340
1341 key.sequence = key.sequence || s || key.name;
1342
1343 if (s === '\r') {
1344 // carriage return
1345 key.raw = void 0;
1346 key.name = 'return';
1347 } else if (s === '\n') {
1348 // enter, should have been called linefeed
1349 key.name = 'enter';
1350 } else if (s === '\t') {
1351 // tab
1352 key.name = 'tab';
1353 } else if (s === '\b' || s === '\x7f' || s === '\x1b\x7f' || s === '\x1b\b') {
1354 // backspace or ctrl+h
1355 key.name = 'backspace';
1356 key.meta = s.charAt(0) === '\x1b';
1357 } else if (s === '\x1b' || s === '\x1b\x1b') {
1358 // escape key
1359 key.name = 'escape';
1360 key.meta = s.length === 2;
1361 } else if (s === ' ' || s === '\x1b ') {
1362 key.name = 'space';
1363 key.meta = s.length === 2;
1364 } else if (s <= '\x1a') {
1365 // ctrl+letter
1366 key.name = String.fromCharCode(s.charCodeAt(0) + 'a'.charCodeAt(0) - 1);
1367 key.ctrl = true;
1368 } else if (s.length === 1 && s >= '0' && s <= '9') {
1369 // number
1370 key.name = 'number';
1371 } else if (s.length === 1 && s >= 'a' && s <= 'z') {
1372 // lowercase letter
1373 key.name = s;
1374 } else if (s.length === 1 && s >= 'A' && s <= 'Z') {
1375 // shift+letter
1376 key.name = s.toLowerCase();
1377 key.shift = true;
1378 } else if ((parts = metaKeyCodeRe.exec(s))) {
1379 // meta+character key
1380 key.meta = true;
1381 key.shift = /^[A-Z]$/.test(parts[1]);
1382 } else if ((parts = fnKeyRe.exec(s))) {
1383 let segs = [...s];
1384
1385 if (segs[0] === '\u001b' && segs[1] === '\u001b') {
1386 key.option = true;
1387 }
1388
1389 // ansi escape sequence
1390 // reassemble the key code leaving out leading \x1b's,
1391 // the modifier key bitflag and any meaningless "1;" sequence
1392 let code = [parts[1], parts[2], parts[4], parts[6]].filter(Boolean).join('');
1393 let modifier = (parts[3] || parts[5] || 1) - 1;
1394
1395 // Parse the key modifier
1396 key.ctrl = !!(modifier & 4);
1397 key.meta = !!(modifier & 10);
1398 key.shift = !!(modifier & 1);
1399 key.code = code;
1400
1401 key.name = keyName[code];
1402 key.shift = isShiftKey(code) || key.shift;
1403 key.ctrl = isCtrlKey(code) || key.ctrl;
1404 }
1405 return key;
1406};
1407
1408keypress.listen = (options = {}, onKeypress) => {
1409 let { stdin } = options;
1410
1411 if (!stdin || (stdin !== process.stdin && !stdin.isTTY)) {
1412 throw new Error('Invalid stream passed');
1413 }
1414
1415 let rl = readline__default['default'].createInterface({ terminal: true, input: stdin });
1416 readline__default['default'].emitKeypressEvents(stdin, rl);
1417
1418 let on = (buf, key) => onKeypress(buf, keypress(buf, key), rl);
1419 let isRaw = stdin.isRaw;
1420
1421 if (stdin.isTTY) stdin.setRawMode(true);
1422 stdin.on('keypress', on);
1423 rl.resume();
1424
1425 let off = () => {
1426 if (stdin.isTTY) stdin.setRawMode(isRaw);
1427 stdin.removeListener('keypress', on);
1428 rl.pause();
1429 rl.close();
1430 };
1431
1432 return off;
1433};
1434
1435keypress.action = (buf, key, customActions) => {
1436 let obj = { ...combos, ...customActions };
1437 if (key.ctrl) {
1438 key.action = obj.ctrl[key.name];
1439 return key;
1440 }
1441
1442 if (key.option && obj.option) {
1443 key.action = obj.option[key.name];
1444 return key;
1445 }
1446
1447 if (key.shift) {
1448 key.action = obj.shift[key.name];
1449 return key;
1450 }
1451
1452 key.action = obj.keys[key.name];
1453 return key;
1454};
1455
1456var keypress_1 = keypress;
1457
1458var timer = prompt => {
1459 prompt.timers = prompt.timers || {};
1460
1461 let timers = prompt.options.timers;
1462 if (!timers) return;
1463
1464 for (let key of Object.keys(timers)) {
1465 let opts = timers[key];
1466 if (typeof opts === 'number') {
1467 opts = { interval: opts };
1468 }
1469 create(prompt, key, opts);
1470 }
1471};
1472
1473function create(prompt, name, options = {}) {
1474 let timer = prompt.timers[name] = { name, start: Date.now(), ms: 0, tick: 0 };
1475 let ms = options.interval || 120;
1476 timer.frames = options.frames || [];
1477 timer.loading = true;
1478
1479 let interval = setInterval(() => {
1480 timer.ms = Date.now() - timer.start;
1481 timer.tick++;
1482 prompt.render();
1483 }, ms);
1484
1485 timer.stop = () => {
1486 timer.loading = false;
1487 clearInterval(interval);
1488 };
1489
1490 Reflect.defineProperty(timer, 'interval', { value: interval });
1491 prompt.once('close', () => timer.stop());
1492 return timer.stop;
1493}
1494
1495const { define, width } = utils;
1496
1497class State {
1498 constructor(prompt) {
1499 let options = prompt.options;
1500 define(this, '_prompt', prompt);
1501 this.type = prompt.type;
1502 this.name = prompt.name;
1503 this.message = '';
1504 this.header = '';
1505 this.footer = '';
1506 this.error = '';
1507 this.hint = '';
1508 this.input = '';
1509 this.cursor = 0;
1510 this.index = 0;
1511 this.lines = 0;
1512 this.tick = 0;
1513 this.prompt = '';
1514 this.buffer = '';
1515 this.width = width(options.stdout || process.stdout);
1516 Object.assign(this, options);
1517 this.name = this.name || this.message;
1518 this.message = this.message || this.name;
1519 this.symbols = prompt.symbols;
1520 this.styles = prompt.styles;
1521 this.required = new Set();
1522 this.cancelled = false;
1523 this.submitted = false;
1524 }
1525
1526 clone() {
1527 let state = { ...this };
1528 state.status = this.status;
1529 state.buffer = Buffer.from(state.buffer);
1530 delete state.clone;
1531 return state;
1532 }
1533
1534 set color(val) {
1535 this._color = val;
1536 }
1537 get color() {
1538 let styles = this.prompt.styles;
1539 if (this.cancelled) return styles.cancelled;
1540 if (this.submitted) return styles.submitted;
1541 let color = this._color || styles[this.status];
1542 return typeof color === 'function' ? color : styles.pending;
1543 }
1544
1545 set loading(value) {
1546 this._loading = value;
1547 }
1548 get loading() {
1549 if (typeof this._loading === 'boolean') return this._loading;
1550 if (this.loadingChoices) return 'choices';
1551 return false;
1552 }
1553
1554 get status() {
1555 if (this.cancelled) return 'cancelled';
1556 if (this.submitted) return 'submitted';
1557 return 'pending';
1558 }
1559}
1560
1561var state = State;
1562
1563const styles = {
1564 default: ansiColors.noop,
1565 noop: ansiColors.noop,
1566
1567 /**
1568 * Modifiers
1569 */
1570
1571 set inverse(custom) {
1572 this._inverse = custom;
1573 },
1574 get inverse() {
1575 return this._inverse || utils.inverse(this.primary);
1576 },
1577
1578 set complement(custom) {
1579 this._complement = custom;
1580 },
1581 get complement() {
1582 return this._complement || utils.complement(this.primary);
1583 },
1584
1585 /**
1586 * Main color
1587 */
1588
1589 primary: ansiColors.cyan,
1590
1591 /**
1592 * Main palette
1593 */
1594
1595 success: ansiColors.green,
1596 danger: ansiColors.magenta,
1597 strong: ansiColors.bold,
1598 warning: ansiColors.yellow,
1599 muted: ansiColors.dim,
1600 disabled: ansiColors.gray,
1601 dark: ansiColors.dim.gray,
1602 underline: ansiColors.underline,
1603
1604 set info(custom) {
1605 this._info = custom;
1606 },
1607 get info() {
1608 return this._info || this.primary;
1609 },
1610
1611 set em(custom) {
1612 this._em = custom;
1613 },
1614 get em() {
1615 return this._em || this.primary.underline;
1616 },
1617
1618 set heading(custom) {
1619 this._heading = custom;
1620 },
1621 get heading() {
1622 return this._heading || this.muted.underline;
1623 },
1624
1625 /**
1626 * Statuses
1627 */
1628
1629 set pending(custom) {
1630 this._pending = custom;
1631 },
1632 get pending() {
1633 return this._pending || this.primary;
1634 },
1635
1636 set submitted(custom) {
1637 this._submitted = custom;
1638 },
1639 get submitted() {
1640 return this._submitted || this.success;
1641 },
1642
1643 set cancelled(custom) {
1644 this._cancelled = custom;
1645 },
1646 get cancelled() {
1647 return this._cancelled || this.danger;
1648 },
1649
1650 /**
1651 * Special styling
1652 */
1653
1654 set typing(custom) {
1655 this._typing = custom;
1656 },
1657 get typing() {
1658 return this._typing || this.dim;
1659 },
1660
1661 set placeholder(custom) {
1662 this._placeholder = custom;
1663 },
1664 get placeholder() {
1665 return this._placeholder || this.primary.dim;
1666 },
1667
1668 set highlight(custom) {
1669 this._highlight = custom;
1670 },
1671 get highlight() {
1672 return this._highlight || this.inverse;
1673 }
1674};
1675
1676styles.merge = (options = {}) => {
1677 if (options.styles && typeof options.styles.enabled === 'boolean') {
1678 ansiColors.enabled = options.styles.enabled;
1679 }
1680 if (options.styles && typeof options.styles.visible === 'boolean') {
1681 ansiColors.visible = options.styles.visible;
1682 }
1683
1684 let result = utils.merge({}, styles, options.styles);
1685 delete result.merge;
1686
1687 for (let key of Object.keys(ansiColors)) {
1688 if (!result.hasOwnProperty(key)) {
1689 Reflect.defineProperty(result, key, { get: () => ansiColors[key] });
1690 }
1691 }
1692
1693 for (let key of Object.keys(ansiColors.styles)) {
1694 if (!result.hasOwnProperty(key)) {
1695 Reflect.defineProperty(result, key, { get: () => ansiColors[key] });
1696 }
1697 }
1698 return result;
1699};
1700
1701var styles_1 = styles;
1702
1703const isWindows = process.platform === 'win32';
1704
1705
1706
1707const symbols = {
1708 ...ansiColors.symbols,
1709 upDownDoubleArrow: '⇕',
1710 upDownDoubleArrow2: '⬍',
1711 upDownArrow: '↕',
1712 asterisk: '*',
1713 asterism: '⁂',
1714 bulletWhite: '◦',
1715 electricArrow: '⌁',
1716 ellipsisLarge: '⋯',
1717 ellipsisSmall: '…',
1718 fullBlock: '█',
1719 identicalTo: '≡',
1720 indicator: ansiColors.symbols.check,
1721 leftAngle: '‹',
1722 mark: '※',
1723 minus: '−',
1724 multiplication: '×',
1725 obelus: '÷',
1726 percent: '%',
1727 pilcrow: '¶',
1728 pilcrow2: '❡',
1729 pencilUpRight: '✐',
1730 pencilDownRight: '✎',
1731 pencilRight: '✏',
1732 plus: '+',
1733 plusMinus: '±',
1734 pointRight: '☞',
1735 rightAngle: '›',
1736 section: '§',
1737 hexagon: { off: '⬡', on: '⬢', disabled: '⬢' },
1738 ballot: { on: '☑', off: '☐', disabled: '☒' },
1739 stars: { on: '★', off: '☆', disabled: '☆' },
1740 folder: { on: '▼', off: '▶', disabled: '▶' },
1741 prefix: {
1742 pending: ansiColors.symbols.question,
1743 submitted: ansiColors.symbols.check,
1744 cancelled: ansiColors.symbols.cross
1745 },
1746 separator: {
1747 pending: ansiColors.symbols.pointerSmall,
1748 submitted: ansiColors.symbols.middot,
1749 cancelled: ansiColors.symbols.middot
1750 },
1751 radio: {
1752 off: isWindows ? '( )' : '◯',
1753 on: isWindows ? '(*)' : '◉',
1754 disabled: isWindows ? '(|)' : 'Ⓘ'
1755 },
1756 numbers: ['⓪', '①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩', '⑪', '⑫', '⑬', '⑭', '⑮', '⑯', '⑰', '⑱', '⑲', '⑳', '㉑', '㉒', '㉓', '㉔', '㉕', '㉖', '㉗', '㉘', '㉙', '㉚', '㉛', '㉜', '㉝', '㉞', '㉟', '㊱', '㊲', '㊳', '㊴', '㊵', '㊶', '㊷', '㊸', '㊹', '㊺', '㊻', '㊼', '㊽', '㊾', '㊿']
1757};
1758
1759symbols.merge = options => {
1760 let result = utils.merge({}, ansiColors.symbols, symbols, options.symbols);
1761 delete result.merge;
1762 return result;
1763};
1764
1765var symbols_1 = symbols;
1766
1767var theme = prompt => {
1768 prompt.options = utils.merge({}, prompt.options.theme, prompt.options);
1769 prompt.symbols = symbols_1.merge(prompt.options);
1770 prompt.styles = styles_1.merge(prompt.options);
1771};
1772
1773var ansi_1 = index.createCommonjsModule(function (module, exports) {
1774
1775const isTerm = process.env.TERM_PROGRAM === 'Apple_Terminal';
1776
1777
1778const ansi = module.exports = exports;
1779const ESC = '\u001b[';
1780const BEL = '\u0007';
1781let hidden = false;
1782
1783const code = ansi.code = {
1784 bell: BEL,
1785 beep: BEL,
1786 beginning: `${ESC}G`,
1787 down: `${ESC}J`,
1788 esc: ESC,
1789 getPosition: `${ESC}6n`,
1790 hide: `${ESC}?25l`,
1791 line: `${ESC}2K`,
1792 lineEnd: `${ESC}K`,
1793 lineStart: `${ESC}1K`,
1794 restorePosition: ESC + (isTerm ? '8' : 'u'),
1795 savePosition: ESC + (isTerm ? '7' : 's'),
1796 screen: `${ESC}2J`,
1797 show: `${ESC}?25h`,
1798 up: `${ESC}1J`
1799};
1800
1801const cursor = ansi.cursor = {
1802 get hidden() {
1803 return hidden;
1804 },
1805
1806 hide() {
1807 hidden = true;
1808 return code.hide;
1809 },
1810 show() {
1811 hidden = false;
1812 return code.show;
1813 },
1814
1815 forward: (count = 1) => `${ESC}${count}C`,
1816 backward: (count = 1) => `${ESC}${count}D`,
1817 nextLine: (count = 1) => `${ESC}E`.repeat(count),
1818 prevLine: (count = 1) => `${ESC}F`.repeat(count),
1819
1820 up: (count = 1) => count ? `${ESC}${count}A` : '',
1821 down: (count = 1) => count ? `${ESC}${count}B` : '',
1822 right: (count = 1) => count ? `${ESC}${count}C` : '',
1823 left: (count = 1) => count ? `${ESC}${count}D` : '',
1824
1825 to(x, y) {
1826 return y ? `${ESC}${y + 1};${x + 1}H` : `${ESC}${x + 1}G`;
1827 },
1828
1829 move(x = 0, y = 0) {
1830 let res = '';
1831 res += (x < 0) ? cursor.left(-x) : (x > 0) ? cursor.right(x) : '';
1832 res += (y < 0) ? cursor.up(-y) : (y > 0) ? cursor.down(y) : '';
1833 return res;
1834 },
1835
1836 restore(state = {}) {
1837 let { after, cursor, initial, input, prompt, size, value } = state;
1838 initial = utils.isPrimitive(initial) ? String(initial) : '';
1839 input = utils.isPrimitive(input) ? String(input) : '';
1840 value = utils.isPrimitive(value) ? String(value) : '';
1841
1842 if (size) {
1843 let codes = ansi.cursor.up(size) + ansi.cursor.to(prompt.length);
1844 let diff = input.length - cursor;
1845 if (diff > 0) {
1846 codes += ansi.cursor.left(diff);
1847 }
1848 return codes;
1849 }
1850
1851 if (value || after) {
1852 let pos = (!input && !!initial) ? -initial.length : -input.length + cursor;
1853 if (after) pos -= after.length;
1854 if (input === '' && initial && !prompt.includes(initial)) {
1855 pos += initial.length;
1856 }
1857 return ansi.cursor.move(pos);
1858 }
1859 }
1860};
1861
1862const erase = ansi.erase = {
1863 screen: code.screen,
1864 up: code.up,
1865 down: code.down,
1866 line: code.line,
1867 lineEnd: code.lineEnd,
1868 lineStart: code.lineStart,
1869 lines(n) {
1870 let str = '';
1871 for (let i = 0; i < n; i++) {
1872 str += ansi.erase.line + (i < n - 1 ? ansi.cursor.up(1) : '');
1873 }
1874 if (n) str += ansi.code.beginning;
1875 return str;
1876 }
1877};
1878
1879ansi.clear = (input = '', columns = process.stdout.columns) => {
1880 if (!columns) return erase.line + cursor.to(0);
1881 let width = str => [...ansiColors.unstyle(str)].length;
1882 let lines = input.split(/\r?\n/);
1883 let rows = 0;
1884 for (let line of lines) {
1885 rows += 1 + Math.floor(Math.max(width(line) - 1, 0) / columns);
1886 }
1887 return (erase.line + cursor.prevLine()).repeat(rows - 1) + erase.line + cursor.to(0);
1888};
1889});
1890
1891/**
1892 * Base class for creating a new Prompt.
1893 * @param {Object} `options` Question object.
1894 */
1895
1896class Prompt extends Events__default['default'] {
1897 constructor(options = {}) {
1898 super();
1899 this.name = options.name;
1900 this.type = options.type;
1901 this.options = options;
1902 theme(this);
1903 timer(this);
1904 this.state = new state(this);
1905 this.initial = [options.initial, options.default].find(v => v != null);
1906 this.stdout = options.stdout || process.stdout;
1907 this.stdin = options.stdin || process.stdin;
1908 this.scale = options.scale || 1;
1909 this.term = this.options.term || process.env.TERM_PROGRAM;
1910 this.margin = margin(this.options.margin);
1911 this.setMaxListeners(0);
1912 setOptions(this);
1913 }
1914
1915 async keypress(input, event = {}) {
1916 this.keypressed = true;
1917 let key = keypress_1.action(input, keypress_1(input, event), this.options.actions);
1918 this.state.keypress = key;
1919 this.emit('keypress', input, key);
1920 this.emit('state', this.state.clone());
1921 let fn = this.options[key.action] || this[key.action] || this.dispatch;
1922 if (typeof fn === 'function') {
1923 return await fn.call(this, input, key);
1924 }
1925 this.alert();
1926 }
1927
1928 alert() {
1929 delete this.state.alert;
1930 if (this.options.show === false) {
1931 this.emit('alert');
1932 } else {
1933 this.stdout.write(ansi_1.code.beep);
1934 }
1935 }
1936
1937 cursorHide() {
1938 this.stdout.write(ansi_1.cursor.hide());
1939 utils.onExit(() => this.cursorShow());
1940 }
1941
1942 cursorShow() {
1943 this.stdout.write(ansi_1.cursor.show());
1944 }
1945
1946 write(str) {
1947 if (!str) return;
1948 if (this.stdout && this.state.show !== false) {
1949 this.stdout.write(str);
1950 }
1951 this.state.buffer += str;
1952 }
1953
1954 clear(lines = 0) {
1955 let buffer = this.state.buffer;
1956 this.state.buffer = '';
1957 if ((!buffer && !lines) || this.options.show === false) return;
1958 this.stdout.write(ansi_1.cursor.down(lines) + ansi_1.clear(buffer, this.width));
1959 }
1960
1961 restore() {
1962 if (this.state.closed || this.options.show === false) return;
1963
1964 let { prompt, after, rest } = this.sections();
1965 let { cursor, initial = '', input = '', value = '' } = this;
1966
1967 let size = this.state.size = rest.length;
1968 let state = { after, cursor, initial, input, prompt, size, value };
1969 let codes = ansi_1.cursor.restore(state);
1970 if (codes) {
1971 this.stdout.write(codes);
1972 }
1973 }
1974
1975 sections() {
1976 let { buffer, input, prompt } = this.state;
1977 prompt = ansiColors.unstyle(prompt);
1978 let buf = ansiColors.unstyle(buffer);
1979 let idx = buf.indexOf(prompt);
1980 let header = buf.slice(0, idx);
1981 let rest = buf.slice(idx);
1982 let lines = rest.split('\n');
1983 let first = lines[0];
1984 let last = lines[lines.length - 1];
1985 let promptLine = prompt + (input ? ' ' + input : '');
1986 let len = promptLine.length;
1987 let after = len < first.length ? first.slice(len + 1) : '';
1988 return { header, prompt: first, after, rest: lines.slice(1), last };
1989 }
1990
1991 async submit() {
1992 this.state.submitted = true;
1993 this.state.validating = true;
1994
1995 // this will only be called when the prompt is directly submitted
1996 // without initializing, i.e. when the prompt is skipped, etc. Otherwize,
1997 // "options.onSubmit" is will be handled by the "initialize()" method.
1998 if (this.options.onSubmit) {
1999 await this.options.onSubmit.call(this, this.name, this.value, this);
2000 }
2001
2002 let result = this.state.error || await this.validate(this.value, this.state);
2003 if (result !== true) {
2004 let error = '\n' + this.symbols.pointer + ' ';
2005
2006 if (typeof result === 'string') {
2007 error += result.trim();
2008 } else {
2009 error += 'Invalid input';
2010 }
2011
2012 this.state.error = '\n' + this.styles.danger(error);
2013 this.state.submitted = false;
2014 await this.render();
2015 await this.alert();
2016 this.state.validating = false;
2017 this.state.error = void 0;
2018 return;
2019 }
2020
2021 this.state.validating = false;
2022 await this.render();
2023 await this.close();
2024
2025 this.value = await this.result(this.value);
2026 this.emit('submit', this.value);
2027 }
2028
2029 async cancel(err) {
2030 this.state.cancelled = this.state.submitted = true;
2031
2032 await this.render();
2033 await this.close();
2034
2035 if (typeof this.options.onCancel === 'function') {
2036 await this.options.onCancel.call(this, this.name, this.value, this);
2037 }
2038
2039 this.emit('cancel', await this.error(err));
2040 }
2041
2042 async close() {
2043 this.state.closed = true;
2044
2045 try {
2046 let sections = this.sections();
2047 let lines = Math.ceil(sections.prompt.length / this.width);
2048 if (sections.rest) {
2049 this.write(ansi_1.cursor.down(sections.rest.length));
2050 }
2051 this.write('\n'.repeat(lines));
2052 } catch (err) { /* do nothing */ }
2053
2054 this.emit('close');
2055 }
2056
2057 start() {
2058 if (!this.stop && this.options.show !== false) {
2059 this.stop = keypress_1.listen(this, this.keypress.bind(this));
2060 this.once('close', this.stop);
2061 }
2062 }
2063
2064 async skip() {
2065 this.skipped = this.options.skip === true;
2066 if (typeof this.options.skip === 'function') {
2067 this.skipped = await this.options.skip.call(this, this.name, this.value);
2068 }
2069 return this.skipped;
2070 }
2071
2072 async initialize() {
2073 let { format, options, result } = this;
2074
2075 this.format = () => format.call(this, this.value);
2076 this.result = () => result.call(this, this.value);
2077
2078 if (typeof options.initial === 'function') {
2079 this.initial = await options.initial.call(this, this);
2080 }
2081
2082 if (typeof options.onRun === 'function') {
2083 await options.onRun.call(this, this);
2084 }
2085
2086 // if "options.onSubmit" is defined, we wrap the "submit" method to guarantee
2087 // that "onSubmit" will always called first thing inside the submit
2088 // method, regardless of how it's handled in inheriting prompts.
2089 if (typeof options.onSubmit === 'function') {
2090 let onSubmit = options.onSubmit.bind(this);
2091 let submit = this.submit.bind(this);
2092 delete this.options.onSubmit;
2093 this.submit = async() => {
2094 await onSubmit(this.name, this.value, this);
2095 return submit();
2096 };
2097 }
2098
2099 await this.start();
2100 await this.render();
2101 }
2102
2103 render() {
2104 throw new Error('expected prompt to have a custom render method');
2105 }
2106
2107 run() {
2108 return new Promise(async(resolve, reject) => {
2109 this.once('submit', resolve);
2110 this.once('cancel', reject);
2111 if (await this.skip()) {
2112 this.render = () => {};
2113 return this.submit();
2114 }
2115 await this.initialize();
2116 this.emit('run');
2117 });
2118 }
2119
2120 async element(name, choice, i) {
2121 let { options, state, symbols, timers } = this;
2122 let timer = timers && timers[name];
2123 state.timer = timer;
2124 let value = options[name] || state[name] || symbols[name];
2125 let val = choice && choice[name] != null ? choice[name] : await value;
2126 if (val === '') return val;
2127
2128 let res = await this.resolve(val, state, choice, i);
2129 if (!res && choice && choice[name]) {
2130 return this.resolve(value, state, choice, i);
2131 }
2132 return res;
2133 }
2134
2135 async prefix() {
2136 let element = await this.element('prefix') || this.symbols;
2137 let timer = this.timers && this.timers.prefix;
2138 let state = this.state;
2139 state.timer = timer;
2140 if (utils.isObject(element)) element = element[state.status] || element.pending;
2141 if (!utils.hasColor(element)) {
2142 let style = this.styles[state.status] || this.styles.pending;
2143 return style(element);
2144 }
2145 return element;
2146 }
2147
2148 async message() {
2149 let message = await this.element('message');
2150 if (!utils.hasColor(message)) {
2151 return this.styles.strong(message);
2152 }
2153 return message;
2154 }
2155
2156 async separator() {
2157 let element = await this.element('separator') || this.symbols;
2158 let timer = this.timers && this.timers.separator;
2159 let state = this.state;
2160 state.timer = timer;
2161 let value = element[state.status] || element.pending || state.separator;
2162 let ele = await this.resolve(value, state);
2163 if (utils.isObject(ele)) ele = ele[state.status] || ele.pending;
2164 if (!utils.hasColor(ele)) {
2165 return this.styles.muted(ele);
2166 }
2167 return ele;
2168 }
2169
2170 async pointer(choice, i) {
2171 let val = await this.element('pointer', choice, i);
2172
2173 if (typeof val === 'string' && utils.hasColor(val)) {
2174 return val;
2175 }
2176
2177 if (val) {
2178 let styles = this.styles;
2179 let focused = this.index === i;
2180 let style = focused ? styles.primary : val => val;
2181 let ele = await this.resolve(val[focused ? 'on' : 'off'] || val, this.state);
2182 let styled = !utils.hasColor(ele) ? style(ele) : ele;
2183 return focused ? styled : ' '.repeat(ele.length);
2184 }
2185 }
2186
2187 async indicator(choice, i) {
2188 let val = await this.element('indicator', choice, i);
2189 if (typeof val === 'string' && utils.hasColor(val)) {
2190 return val;
2191 }
2192 if (val) {
2193 let styles = this.styles;
2194 let enabled = choice.enabled === true;
2195 let style = enabled ? styles.success : styles.dark;
2196 let ele = val[enabled ? 'on' : 'off'] || val;
2197 return !utils.hasColor(ele) ? style(ele) : ele;
2198 }
2199 return '';
2200 }
2201
2202 body() {
2203 return null;
2204 }
2205
2206 footer() {
2207 if (this.state.status === 'pending') {
2208 return this.element('footer');
2209 }
2210 }
2211
2212 header() {
2213 if (this.state.status === 'pending') {
2214 return this.element('header');
2215 }
2216 }
2217
2218 async hint() {
2219 if (this.state.status === 'pending' && !this.isValue(this.state.input)) {
2220 let hint = await this.element('hint');
2221 if (!utils.hasColor(hint)) {
2222 return this.styles.muted(hint);
2223 }
2224 return hint;
2225 }
2226 }
2227
2228 error(err) {
2229 return !this.state.submitted ? (err || this.state.error) : '';
2230 }
2231
2232 format(value) {
2233 return value;
2234 }
2235
2236 result(value) {
2237 return value;
2238 }
2239
2240 validate(value) {
2241 if (this.options.required === true) {
2242 return this.isValue(value);
2243 }
2244 return true;
2245 }
2246
2247 isValue(value) {
2248 return value != null && value !== '';
2249 }
2250
2251 resolve(value, ...args) {
2252 return utils.resolve(this, value, ...args);
2253 }
2254
2255 get base() {
2256 return Prompt.prototype;
2257 }
2258
2259 get style() {
2260 return this.styles[this.state.status];
2261 }
2262
2263 get height() {
2264 return this.options.rows || utils.height(this.stdout, 25);
2265 }
2266 get width() {
2267 return this.options.columns || utils.width(this.stdout, 80);
2268 }
2269 get size() {
2270 return { width: this.width, height: this.height };
2271 }
2272
2273 set cursor(value) {
2274 this.state.cursor = value;
2275 }
2276 get cursor() {
2277 return this.state.cursor;
2278 }
2279
2280 set input(value) {
2281 this.state.input = value;
2282 }
2283 get input() {
2284 return this.state.input;
2285 }
2286
2287 set value(value) {
2288 this.state.value = value;
2289 }
2290 get value() {
2291 let { input, value } = this.state;
2292 let result = [value, input].find(this.isValue.bind(this));
2293 return this.isValue(result) ? result : this.initial;
2294 }
2295
2296 static get prompt() {
2297 return options => new this(options).run();
2298 }
2299}
2300
2301function setOptions(prompt) {
2302 let isValidKey = key => {
2303 return prompt[key] === void 0 || typeof prompt[key] === 'function';
2304 };
2305
2306 let ignore = [
2307 'actions',
2308 'choices',
2309 'initial',
2310 'margin',
2311 'roles',
2312 'styles',
2313 'symbols',
2314 'theme',
2315 'timers',
2316 'value'
2317 ];
2318
2319 let ignoreFn = [
2320 'body',
2321 'footer',
2322 'error',
2323 'header',
2324 'hint',
2325 'indicator',
2326 'message',
2327 'prefix',
2328 'separator',
2329 'skip'
2330 ];
2331
2332 for (let key of Object.keys(prompt.options)) {
2333 if (ignore.includes(key)) continue;
2334 if (/^on[A-Z]/.test(key)) continue;
2335 let option = prompt.options[key];
2336 if (typeof option === 'function' && isValidKey(key)) {
2337 if (!ignoreFn.includes(key)) {
2338 prompt[key] = option.bind(prompt);
2339 }
2340 } else if (typeof prompt[key] !== 'function') {
2341 prompt[key] = option;
2342 }
2343 }
2344}
2345
2346function margin(value) {
2347 if (typeof value === 'number') {
2348 value = [value, value, value, value];
2349 }
2350 let arr = [].concat(value || []);
2351 let pad = i => i % 2 === 0 ? '\n' : ' ';
2352 let res = [];
2353 for (let i = 0; i < 4; i++) {
2354 let char = pad(i);
2355 if (arr[i]) {
2356 res.push(char.repeat(arr[i]));
2357 } else {
2358 res.push('');
2359 }
2360 }
2361 return res;
2362}
2363
2364var prompt = Prompt;
2365
2366const roles = {
2367 default(prompt, choice) {
2368 return choice;
2369 },
2370 checkbox(prompt, choice) {
2371 throw new Error('checkbox role is not implemented yet');
2372 },
2373 editable(prompt, choice) {
2374 throw new Error('editable role is not implemented yet');
2375 },
2376 expandable(prompt, choice) {
2377 throw new Error('expandable role is not implemented yet');
2378 },
2379 heading(prompt, choice) {
2380 choice.disabled = '';
2381 choice.indicator = [choice.indicator, ' '].find(v => v != null);
2382 choice.message = choice.message || '';
2383 return choice;
2384 },
2385 input(prompt, choice) {
2386 throw new Error('input role is not implemented yet');
2387 },
2388 option(prompt, choice) {
2389 return roles.default(prompt, choice);
2390 },
2391 radio(prompt, choice) {
2392 throw new Error('radio role is not implemented yet');
2393 },
2394 separator(prompt, choice) {
2395 choice.disabled = '';
2396 choice.indicator = [choice.indicator, ' '].find(v => v != null);
2397 choice.message = choice.message || prompt.symbols.line.repeat(5);
2398 return choice;
2399 },
2400 spacer(prompt, choice) {
2401 return choice;
2402 }
2403};
2404
2405var roles_1 = (name, options = {}) => {
2406 let role = utils.merge({}, roles, options.roles);
2407 return role[name] || role.default;
2408};
2409
2410const { reorder, scrollUp, scrollDown, isObject, swap } = utils;
2411
2412class ArrayPrompt extends prompt {
2413 constructor(options) {
2414 super(options);
2415 this.cursorHide();
2416 this.maxSelected = options.maxSelected || Infinity;
2417 this.multiple = options.multiple || false;
2418 this.initial = options.initial || 0;
2419 this.delay = options.delay || 0;
2420 this.longest = 0;
2421 this.num = '';
2422 }
2423
2424 async initialize() {
2425 if (typeof this.options.initial === 'function') {
2426 this.initial = await this.options.initial.call(this);
2427 }
2428 await this.reset(true);
2429 await super.initialize();
2430 }
2431
2432 async reset() {
2433 let { choices, initial, autofocus, suggest } = this.options;
2434 this.state._choices = [];
2435 this.state.choices = [];
2436
2437 this.choices = await Promise.all(await this.toChoices(choices));
2438 this.choices.forEach(ch => (ch.enabled = false));
2439
2440 if (typeof suggest !== 'function' && this.selectable.length === 0) {
2441 throw new Error('At least one choice must be selectable');
2442 }
2443
2444 if (isObject(initial)) initial = Object.keys(initial);
2445 if (Array.isArray(initial)) {
2446 if (autofocus != null) this.index = this.findIndex(autofocus);
2447 initial.forEach(v => this.enable(this.find(v)));
2448 await this.render();
2449 } else {
2450 if (autofocus != null) initial = autofocus;
2451 if (typeof initial === 'string') initial = this.findIndex(initial);
2452 if (typeof initial === 'number' && initial > -1) {
2453 this.index = Math.max(0, Math.min(initial, this.choices.length));
2454 this.enable(this.find(this.index));
2455 }
2456 }
2457
2458 if (this.isDisabled(this.focused)) {
2459 await this.down();
2460 }
2461 }
2462
2463 async toChoices(value, parent) {
2464 this.state.loadingChoices = true;
2465 let choices = [];
2466 let index = 0;
2467
2468 let toChoices = async(items, parent) => {
2469 if (typeof items === 'function') items = await items.call(this);
2470 if (items instanceof Promise) items = await items;
2471
2472 for (let i = 0; i < items.length; i++) {
2473 let choice = items[i] = await this.toChoice(items[i], index++, parent);
2474 choices.push(choice);
2475
2476 if (choice.choices) {
2477 await toChoices(choice.choices, choice);
2478 }
2479 }
2480 return choices;
2481 };
2482
2483 return toChoices(value, parent)
2484 .then(choices => {
2485 this.state.loadingChoices = false;
2486 return choices;
2487 });
2488 }
2489
2490 async toChoice(ele, i, parent) {
2491 if (typeof ele === 'function') ele = await ele.call(this, this);
2492 if (ele instanceof Promise) ele = await ele;
2493 if (typeof ele === 'string') ele = { name: ele };
2494
2495 if (ele.normalized) return ele;
2496 ele.normalized = true;
2497
2498 let origVal = ele.value;
2499 let role = roles_1(ele.role, this.options);
2500 ele = role(this, ele);
2501
2502 if (typeof ele.disabled === 'string' && !ele.hint) {
2503 ele.hint = ele.disabled;
2504 ele.disabled = true;
2505 }
2506
2507 if (ele.disabled === true && ele.hint == null) {
2508 ele.hint = '(disabled)';
2509 }
2510
2511 // if the choice was already normalized, return it
2512 if (ele.index != null) return ele;
2513 ele.name = ele.name || ele.key || ele.title || ele.value || ele.message;
2514 ele.message = ele.message || ele.name || '';
2515 ele.value = [ele.value, ele.name].find(this.isValue.bind(this));
2516
2517 ele.input = '';
2518 ele.index = i;
2519 ele.cursor = 0;
2520
2521 utils.define(ele, 'parent', parent);
2522 ele.level = parent ? parent.level + 1 : 1;
2523 if (ele.indent == null) {
2524 ele.indent = parent ? parent.indent + ' ' : (ele.indent || '');
2525 }
2526
2527 ele.path = parent ? parent.path + '.' + ele.name : ele.name;
2528 ele.enabled = !!(this.multiple && !this.isDisabled(ele) && (ele.enabled || this.isSelected(ele)));
2529
2530 if (!this.isDisabled(ele)) {
2531 this.longest = Math.max(this.longest, ansiColors.unstyle(ele.message).length);
2532 }
2533
2534 // shallow clone the choice first
2535 let choice = { ...ele };
2536
2537 // then allow the choice to be reset using the "original" values
2538 ele.reset = (input = choice.input, value = choice.value) => {
2539 for (let key of Object.keys(choice)) ele[key] = choice[key];
2540 ele.input = input;
2541 ele.value = value;
2542 };
2543
2544 if (origVal == null && typeof ele.initial === 'function') {
2545 ele.input = await ele.initial.call(this, this.state, ele, i);
2546 }
2547
2548 return ele;
2549 }
2550
2551 async onChoice(choice, i) {
2552 this.emit('choice', choice, i, this);
2553
2554 if (typeof choice.onChoice === 'function') {
2555 await choice.onChoice.call(this, this.state, choice, i);
2556 }
2557 }
2558
2559 async addChoice(ele, i, parent) {
2560 let choice = await this.toChoice(ele, i, parent);
2561 this.choices.push(choice);
2562 this.index = this.choices.length - 1;
2563 this.limit = this.choices.length;
2564 return choice;
2565 }
2566
2567 async newItem(item, i, parent) {
2568 let ele = { name: 'New choice name?', editable: true, newChoice: true, ...item };
2569 let choice = await this.addChoice(ele, i, parent);
2570
2571 choice.updateChoice = () => {
2572 delete choice.newChoice;
2573 choice.name = choice.message = choice.input;
2574 choice.input = '';
2575 choice.cursor = 0;
2576 };
2577
2578 return this.render();
2579 }
2580
2581 indent(choice) {
2582 if (choice.indent == null) {
2583 return choice.level > 1 ? ' '.repeat(choice.level - 1) : '';
2584 }
2585 return choice.indent;
2586 }
2587
2588 dispatch(s, key) {
2589 if (this.multiple && this[key.name]) return this[key.name]();
2590 this.alert();
2591 }
2592
2593 focus(choice, enabled) {
2594 if (typeof enabled !== 'boolean') enabled = choice.enabled;
2595 if (enabled && !choice.enabled && this.selected.length >= this.maxSelected) {
2596 return this.alert();
2597 }
2598 this.index = choice.index;
2599 choice.enabled = enabled && !this.isDisabled(choice);
2600 return choice;
2601 }
2602
2603 space() {
2604 if (!this.multiple) return this.alert();
2605 this.toggle(this.focused);
2606 return this.render();
2607 }
2608
2609 a() {
2610 if (this.maxSelected < this.choices.length) return this.alert();
2611 let enabled = this.selectable.every(ch => ch.enabled);
2612 this.choices.forEach(ch => (ch.enabled = !enabled));
2613 return this.render();
2614 }
2615
2616 i() {
2617 // don't allow choices to be inverted if it will result in
2618 // more than the maximum number of allowed selected items.
2619 if (this.choices.length - this.selected.length > this.maxSelected) {
2620 return this.alert();
2621 }
2622 this.choices.forEach(ch => (ch.enabled = !ch.enabled));
2623 return this.render();
2624 }
2625
2626 g(choice = this.focused) {
2627 if (!this.choices.some(ch => !!ch.parent)) return this.a();
2628 this.toggle((choice.parent && !choice.choices) ? choice.parent : choice);
2629 return this.render();
2630 }
2631
2632 toggle(choice, enabled) {
2633 if (!choice.enabled && this.selected.length >= this.maxSelected) {
2634 return this.alert();
2635 }
2636
2637 if (typeof enabled !== 'boolean') enabled = !choice.enabled;
2638 choice.enabled = enabled;
2639
2640 if (choice.choices) {
2641 choice.choices.forEach(ch => this.toggle(ch, enabled));
2642 }
2643
2644 let parent = choice.parent;
2645 while (parent) {
2646 let choices = parent.choices.filter(ch => this.isDisabled(ch));
2647 parent.enabled = choices.every(ch => ch.enabled === true);
2648 parent = parent.parent;
2649 }
2650
2651 reset(this, this.choices);
2652 this.emit('toggle', choice, this);
2653 return choice;
2654 }
2655
2656 enable(choice) {
2657 if (this.selected.length >= this.maxSelected) return this.alert();
2658 choice.enabled = !this.isDisabled(choice);
2659 choice.choices && choice.choices.forEach(this.enable.bind(this));
2660 return choice;
2661 }
2662
2663 disable(choice) {
2664 choice.enabled = false;
2665 choice.choices && choice.choices.forEach(this.disable.bind(this));
2666 return choice;
2667 }
2668
2669 number(n) {
2670 this.num += n;
2671
2672 let number = num => {
2673 let i = Number(num);
2674 if (i > this.choices.length - 1) return this.alert();
2675
2676 let focused = this.focused;
2677 let choice = this.choices.find(ch => i === ch.index);
2678
2679 if (!choice.enabled && this.selected.length >= this.maxSelected) {
2680 return this.alert();
2681 }
2682
2683 if (this.visible.indexOf(choice) === -1) {
2684 let choices = reorder(this.choices);
2685 let actualIdx = choices.indexOf(choice);
2686
2687 if (focused.index > actualIdx) {
2688 let start = choices.slice(actualIdx, actualIdx + this.limit);
2689 let end = choices.filter(ch => !start.includes(ch));
2690 this.choices = start.concat(end);
2691 } else {
2692 let pos = actualIdx - this.limit + 1;
2693 this.choices = choices.slice(pos).concat(choices.slice(0, pos));
2694 }
2695 }
2696
2697 this.index = this.choices.indexOf(choice);
2698 this.toggle(this.focused);
2699 return this.render();
2700 };
2701
2702 clearTimeout(this.numberTimeout);
2703
2704 return new Promise(resolve => {
2705 let len = this.choices.length;
2706 let num = this.num;
2707
2708 let handle = (val = false, res) => {
2709 clearTimeout(this.numberTimeout);
2710 if (val) res = number(num);
2711 this.num = '';
2712 resolve(res);
2713 };
2714
2715 if (num === '0' || (num.length === 1 && Number(num + '0') > len)) {
2716 return handle(true);
2717 }
2718
2719 if (Number(num) > len) {
2720 return handle(false, this.alert());
2721 }
2722
2723 this.numberTimeout = setTimeout(() => handle(true), this.delay);
2724 });
2725 }
2726
2727 home() {
2728 this.choices = reorder(this.choices);
2729 this.index = 0;
2730 return this.render();
2731 }
2732
2733 end() {
2734 let pos = this.choices.length - this.limit;
2735 let choices = reorder(this.choices);
2736 this.choices = choices.slice(pos).concat(choices.slice(0, pos));
2737 this.index = this.limit - 1;
2738 return this.render();
2739 }
2740
2741 first() {
2742 this.index = 0;
2743 return this.render();
2744 }
2745
2746 last() {
2747 this.index = this.visible.length - 1;
2748 return this.render();
2749 }
2750
2751 prev() {
2752 if (this.visible.length <= 1) return this.alert();
2753 return this.up();
2754 }
2755
2756 next() {
2757 if (this.visible.length <= 1) return this.alert();
2758 return this.down();
2759 }
2760
2761 right() {
2762 if (this.cursor >= this.input.length) return this.alert();
2763 this.cursor++;
2764 return this.render();
2765 }
2766
2767 left() {
2768 if (this.cursor <= 0) return this.alert();
2769 this.cursor--;
2770 return this.render();
2771 }
2772
2773 up() {
2774 let len = this.choices.length;
2775 let vis = this.visible.length;
2776 let idx = this.index;
2777 if (this.options.scroll === false && idx === 0) {
2778 return this.alert();
2779 }
2780 if (len > vis && idx === 0) {
2781 return this.scrollUp();
2782 }
2783 this.index = ((idx - 1 % len) + len) % len;
2784 if (this.isDisabled()) {
2785 return this.up();
2786 }
2787 return this.render();
2788 }
2789
2790 down() {
2791 let len = this.choices.length;
2792 let vis = this.visible.length;
2793 let idx = this.index;
2794 if (this.options.scroll === false && idx === vis - 1) {
2795 return this.alert();
2796 }
2797 if (len > vis && idx === vis - 1) {
2798 return this.scrollDown();
2799 }
2800 this.index = (idx + 1) % len;
2801 if (this.isDisabled()) {
2802 return this.down();
2803 }
2804 return this.render();
2805 }
2806
2807 scrollUp(i = 0) {
2808 this.choices = scrollUp(this.choices);
2809 this.index = i;
2810 if (this.isDisabled()) {
2811 return this.up();
2812 }
2813 return this.render();
2814 }
2815
2816 scrollDown(i = this.visible.length - 1) {
2817 this.choices = scrollDown(this.choices);
2818 this.index = i;
2819 if (this.isDisabled()) {
2820 return this.down();
2821 }
2822 return this.render();
2823 }
2824
2825 async shiftUp() {
2826 if (this.options.sort === true) {
2827 this.sorting = true;
2828 this.swap(this.index - 1);
2829 await this.up();
2830 this.sorting = false;
2831 return;
2832 }
2833 return this.scrollUp(this.index);
2834 }
2835
2836 async shiftDown() {
2837 if (this.options.sort === true) {
2838 this.sorting = true;
2839 this.swap(this.index + 1);
2840 await this.down();
2841 this.sorting = false;
2842 return;
2843 }
2844 return this.scrollDown(this.index);
2845 }
2846
2847 pageUp() {
2848 if (this.visible.length <= 1) return this.alert();
2849 this.limit = Math.max(this.limit - 1, 0);
2850 this.index = Math.min(this.limit - 1, this.index);
2851 this._limit = this.limit;
2852 if (this.isDisabled()) {
2853 return this.up();
2854 }
2855 return this.render();
2856 }
2857
2858 pageDown() {
2859 if (this.visible.length >= this.choices.length) return this.alert();
2860 this.index = Math.max(0, this.index);
2861 this.limit = Math.min(this.limit + 1, this.choices.length);
2862 this._limit = this.limit;
2863 if (this.isDisabled()) {
2864 return this.down();
2865 }
2866 return this.render();
2867 }
2868
2869 swap(pos) {
2870 swap(this.choices, this.index, pos);
2871 }
2872
2873 isDisabled(choice = this.focused) {
2874 let keys = ['disabled', 'collapsed', 'hidden', 'completing', 'readonly'];
2875 if (choice && keys.some(key => choice[key] === true)) {
2876 return true;
2877 }
2878 return choice && choice.role === 'heading';
2879 }
2880
2881 isEnabled(choice = this.focused) {
2882 if (Array.isArray(choice)) return choice.every(ch => this.isEnabled(ch));
2883 if (choice.choices) {
2884 let choices = choice.choices.filter(ch => !this.isDisabled(ch));
2885 return choice.enabled && choices.every(ch => this.isEnabled(ch));
2886 }
2887 return choice.enabled && !this.isDisabled(choice);
2888 }
2889
2890 isChoice(choice, value) {
2891 return choice.name === value || choice.index === Number(value);
2892 }
2893
2894 isSelected(choice) {
2895 if (Array.isArray(this.initial)) {
2896 return this.initial.some(value => this.isChoice(choice, value));
2897 }
2898 return this.isChoice(choice, this.initial);
2899 }
2900
2901 map(names = [], prop = 'value') {
2902 return [].concat(names || []).reduce((acc, name) => {
2903 acc[name] = this.find(name, prop);
2904 return acc;
2905 }, {});
2906 }
2907
2908 filter(value, prop) {
2909 let isChoice = (ele, i) => [ele.name, i].includes(value);
2910 let fn = typeof value === 'function' ? value : isChoice;
2911 let choices = this.options.multiple ? this.state._choices : this.choices;
2912 let result = choices.filter(fn);
2913 if (prop) {
2914 return result.map(ch => ch[prop]);
2915 }
2916 return result;
2917 }
2918
2919 find(value, prop) {
2920 if (isObject(value)) return prop ? value[prop] : value;
2921 let isChoice = (ele, i) => [ele.name, i].includes(value);
2922 let fn = typeof value === 'function' ? value : isChoice;
2923 let choice = this.choices.find(fn);
2924 if (choice) {
2925 return prop ? choice[prop] : choice;
2926 }
2927 }
2928
2929 findIndex(value) {
2930 return this.choices.indexOf(this.find(value));
2931 }
2932
2933 async submit() {
2934 let choice = this.focused;
2935 if (!choice) return this.alert();
2936
2937 if (choice.newChoice) {
2938 if (!choice.input) return this.alert();
2939 choice.updateChoice();
2940 return this.render();
2941 }
2942
2943 if (this.choices.some(ch => ch.newChoice)) {
2944 return this.alert();
2945 }
2946
2947 let { reorder, sort } = this.options;
2948 let multi = this.multiple === true;
2949 let value = this.selected;
2950 if (value === void 0) {
2951 return this.alert();
2952 }
2953
2954 // re-sort choices to original order
2955 if (Array.isArray(value) && reorder !== false && sort !== true) {
2956 value = utils.reorder(value);
2957 }
2958
2959 this.value = multi ? value.map(ch => ch.name) : value.name;
2960 return super.submit();
2961 }
2962
2963 set choices(choices = []) {
2964 this.state._choices = this.state._choices || [];
2965 this.state.choices = choices;
2966
2967 for (let choice of choices) {
2968 if (!this.state._choices.some(ch => ch.name === choice.name)) {
2969 this.state._choices.push(choice);
2970 }
2971 }
2972
2973 if (!this._initial && this.options.initial) {
2974 this._initial = true;
2975 let init = this.initial;
2976 if (typeof init === 'string' || typeof init === 'number') {
2977 let choice = this.find(init);
2978 if (choice) {
2979 this.initial = choice.index;
2980 this.focus(choice, true);
2981 }
2982 }
2983 }
2984 }
2985 get choices() {
2986 return reset(this, this.state.choices || []);
2987 }
2988
2989 set visible(visible) {
2990 this.state.visible = visible;
2991 }
2992 get visible() {
2993 return (this.state.visible || this.choices).slice(0, this.limit);
2994 }
2995
2996 set limit(num) {
2997 this.state.limit = num;
2998 }
2999 get limit() {
3000 let { state, options, choices } = this;
3001 let limit = state.limit || this._limit || options.limit || choices.length;
3002 return Math.min(limit, this.height);
3003 }
3004
3005 set value(value) {
3006 super.value = value;
3007 }
3008 get value() {
3009 if (typeof super.value !== 'string' && super.value === this.initial) {
3010 return this.input;
3011 }
3012 return super.value;
3013 }
3014
3015 set index(i) {
3016 this.state.index = i;
3017 }
3018 get index() {
3019 return Math.max(0, this.state ? this.state.index : 0);
3020 }
3021
3022 get enabled() {
3023 return this.filter(this.isEnabled.bind(this));
3024 }
3025
3026 get focused() {
3027 let choice = this.choices[this.index];
3028 if (choice && this.state.submitted && this.multiple !== true) {
3029 choice.enabled = true;
3030 }
3031 return choice;
3032 }
3033
3034 get selectable() {
3035 return this.choices.filter(choice => !this.isDisabled(choice));
3036 }
3037
3038 get selected() {
3039 return this.multiple ? this.enabled : this.focused;
3040 }
3041}
3042
3043function reset(prompt, choices) {
3044 if (choices instanceof Promise) return choices;
3045 if (typeof choices === 'function') {
3046 if (utils.isAsyncFn(choices)) return choices;
3047 choices = choices.call(prompt, prompt);
3048 }
3049 for (let choice of choices) {
3050 if (Array.isArray(choice.choices)) {
3051 let items = choice.choices.filter(ch => !prompt.isDisabled(ch));
3052 choice.enabled = items.every(ch => ch.enabled === true);
3053 }
3054 if (prompt.isDisabled(choice) === true) {
3055 delete choice.enabled;
3056 }
3057 }
3058 return choices;
3059}
3060
3061var array = ArrayPrompt;
3062
3063class SelectPrompt extends array {
3064 constructor(options) {
3065 super(options);
3066 this.emptyError = this.options.emptyError || 'No items were selected';
3067 }
3068
3069 async dispatch(s, key) {
3070 if (this.multiple) {
3071 return this[key.name] ? await this[key.name](s, key) : await super.dispatch(s, key);
3072 }
3073 this.alert();
3074 }
3075
3076 separator() {
3077 if (this.options.separator) return super.separator();
3078 let sep = this.styles.muted(this.symbols.ellipsis);
3079 return this.state.submitted ? super.separator() : sep;
3080 }
3081
3082 pointer(choice, i) {
3083 return (!this.multiple || this.options.pointer) ? super.pointer(choice, i) : '';
3084 }
3085
3086 indicator(choice, i) {
3087 return this.multiple ? super.indicator(choice, i) : '';
3088 }
3089
3090 choiceMessage(choice, i) {
3091 let message = this.resolve(choice.message, this.state, choice, i);
3092 if (choice.role === 'heading' && !utils.hasColor(message)) {
3093 message = this.styles.strong(message);
3094 }
3095 return this.resolve(message, this.state, choice, i);
3096 }
3097
3098 choiceSeparator() {
3099 return ':';
3100 }
3101
3102 async renderChoice(choice, i) {
3103 await this.onChoice(choice, i);
3104
3105 let focused = this.index === i;
3106 let pointer = await this.pointer(choice, i);
3107 let check = await this.indicator(choice, i) + (choice.pad || '');
3108 let hint = await this.resolve(choice.hint, this.state, choice, i);
3109
3110 if (hint && !utils.hasColor(hint)) {
3111 hint = this.styles.muted(hint);
3112 }
3113
3114 let ind = this.indent(choice);
3115 let msg = await this.choiceMessage(choice, i);
3116 let line = () => [this.margin[3], ind + pointer + check, msg, this.margin[1], hint].filter(Boolean).join(' ');
3117
3118 if (choice.role === 'heading') {
3119 return line();
3120 }
3121
3122 if (choice.disabled) {
3123 if (!utils.hasColor(msg)) {
3124 msg = this.styles.disabled(msg);
3125 }
3126 return line();
3127 }
3128
3129 if (focused) {
3130 msg = this.styles.em(msg);
3131 }
3132
3133 return line();
3134 }
3135
3136 async renderChoices() {
3137 if (this.state.loading === 'choices') {
3138 return this.styles.warning('Loading choices');
3139 }
3140
3141 if (this.state.submitted) return '';
3142 let choices = this.visible.map(async(ch, i) => await this.renderChoice(ch, i));
3143 let visible = await Promise.all(choices);
3144 if (!visible.length) visible.push(this.styles.danger('No matching choices'));
3145 let result = this.margin[0] + visible.join('\n');
3146 let header;
3147
3148 if (this.options.choicesHeader) {
3149 header = await this.resolve(this.options.choicesHeader, this.state);
3150 }
3151
3152 return [header, result].filter(Boolean).join('\n');
3153 }
3154
3155 format() {
3156 if (!this.state.submitted || this.state.cancelled) return '';
3157 if (Array.isArray(this.selected)) {
3158 return this.selected.map(choice => this.styles.primary(choice.name)).join(', ');
3159 }
3160 return this.styles.primary(this.selected.name);
3161 }
3162
3163 async render() {
3164 let { submitted, size } = this.state;
3165
3166 let prompt = '';
3167 let header = await this.header();
3168 let prefix = await this.prefix();
3169 let separator = await this.separator();
3170 let message = await this.message();
3171
3172 if (this.options.promptLine !== false) {
3173 prompt = [prefix, message, separator, ''].join(' ');
3174 this.state.prompt = prompt;
3175 }
3176
3177 let output = await this.format();
3178 let help = (await this.error()) || (await this.hint());
3179 let body = await this.renderChoices();
3180 let footer = await this.footer();
3181
3182 if (output) prompt += output;
3183 if (help && !prompt.includes(help)) prompt += ' ' + help;
3184
3185 if (submitted && !output && !body.trim() && this.multiple && this.emptyError != null) {
3186 prompt += this.styles.danger(this.emptyError);
3187 }
3188
3189 this.clear(size);
3190 this.write([header, prompt, body, footer].filter(Boolean).join('\n'));
3191 this.write(this.margin[2]);
3192 this.restore();
3193 }
3194}
3195
3196var select = SelectPrompt;
3197
3198const highlight = (input, color) => {
3199 let val = input.toLowerCase();
3200 return str => {
3201 let s = str.toLowerCase();
3202 let i = s.indexOf(val);
3203 let colored = color(str.slice(i, i + val.length));
3204 return i >= 0 ? str.slice(0, i) + colored + str.slice(i + val.length) : str;
3205 };
3206};
3207
3208class AutoComplete extends select {
3209 constructor(options) {
3210 super(options);
3211 this.cursorShow();
3212 }
3213
3214 moveCursor(n) {
3215 this.state.cursor += n;
3216 }
3217
3218 dispatch(ch) {
3219 return this.append(ch);
3220 }
3221
3222 space(ch) {
3223 return this.options.multiple ? super.space(ch) : this.append(ch);
3224 }
3225
3226 append(ch) {
3227 let { cursor, input } = this.state;
3228 this.input = input.slice(0, cursor) + ch + input.slice(cursor);
3229 this.moveCursor(1);
3230 return this.complete();
3231 }
3232
3233 delete() {
3234 let { cursor, input } = this.state;
3235 if (!input) return this.alert();
3236 this.input = input.slice(0, cursor - 1) + input.slice(cursor);
3237 this.moveCursor(-1);
3238 return this.complete();
3239 }
3240
3241 deleteForward() {
3242 let { cursor, input } = this.state;
3243 if (input[cursor] === void 0) return this.alert();
3244 this.input = `${input}`.slice(0, cursor) + `${input}`.slice(cursor + 1);
3245 return this.complete();
3246 }
3247
3248 number(ch) {
3249 return this.append(ch);
3250 }
3251
3252 async complete() {
3253 this.completing = true;
3254 this.choices = await this.suggest(this.input, this.state._choices);
3255 this.state.limit = void 0; // allow getter/setter to reset limit
3256 this.index = Math.min(Math.max(this.visible.length - 1, 0), this.index);
3257 await this.render();
3258 this.completing = false;
3259 }
3260
3261 suggest(input = this.input, choices = this.state._choices) {
3262 if (typeof this.options.suggest === 'function') {
3263 return this.options.suggest.call(this, input, choices);
3264 }
3265 let str = input.toLowerCase();
3266 return choices.filter(ch => ch.message.toLowerCase().includes(str));
3267 }
3268
3269 pointer() {
3270 return '';
3271 }
3272
3273 format() {
3274 if (!this.focused) return this.input;
3275 if (this.options.multiple && this.state.submitted) {
3276 return this.selected.map(ch => this.styles.primary(ch.message)).join(', ');
3277 }
3278 if (this.state.submitted) {
3279 let value = this.value = this.input = this.focused.value;
3280 return this.styles.primary(value);
3281 }
3282 return this.input;
3283 }
3284
3285 async render() {
3286 if (this.state.status !== 'pending') return super.render();
3287 let style = this.options.highlight
3288 ? this.options.highlight.bind(this)
3289 : this.styles.placeholder;
3290
3291 let color = highlight(this.input, style);
3292 let choices = this.choices;
3293 this.choices = choices.map(ch => ({ ...ch, message: color(ch.message) }));
3294 await super.render();
3295 this.choices = choices;
3296 }
3297
3298 submit() {
3299 if (this.options.multiple) {
3300 this.value = this.selected.map(ch => ch.name);
3301 }
3302 return super.submit();
3303 }
3304}
3305
3306var autocomplete = AutoComplete;
3307
3308/**
3309 * Render a placeholder value with cursor and styling based on the
3310 * position of the cursor.
3311 *
3312 * @param {Object} `prompt` Prompt instance.
3313 * @param {String} `input` Input string.
3314 * @param {String} `initial` The initial user-provided value.
3315 * @param {Number} `pos` Current cursor position.
3316 * @param {Boolean} `showCursor` Render a simulated cursor using the inverse primary style.
3317 * @return {String} Returns the styled placeholder string.
3318 * @api public
3319 */
3320
3321var placeholder = (prompt, options = {}) => {
3322 prompt.cursorHide();
3323
3324 let { input = '', initial = '', pos, showCursor = true, color } = options;
3325 let style = color || prompt.styles.placeholder;
3326 let inverse = utils.inverse(prompt.styles.primary);
3327 let blinker = str => inverse(prompt.styles.black(str));
3328 let output = input;
3329 let char = ' ';
3330 let reverse = blinker(char);
3331
3332 if (prompt.blink && prompt.blink.off === true) {
3333 blinker = str => str;
3334 reverse = '';
3335 }
3336
3337 if (showCursor && pos === 0 && initial === '' && input === '') {
3338 return blinker(char);
3339 }
3340
3341 if (showCursor && pos === 0 && (input === initial || input === '')) {
3342 return blinker(initial[0]) + style(initial.slice(1));
3343 }
3344
3345 initial = utils.isPrimitive(initial) ? `${initial}` : '';
3346 input = utils.isPrimitive(input) ? `${input}` : '';
3347
3348 let placeholder = initial && initial.startsWith(input) && initial !== input;
3349 let cursor = placeholder ? blinker(initial[input.length]) : reverse;
3350
3351 if (pos !== input.length && showCursor === true) {
3352 output = input.slice(0, pos) + blinker(input[pos]) + input.slice(pos + 1);
3353 cursor = '';
3354 }
3355
3356 if (showCursor === false) {
3357 cursor = '';
3358 }
3359
3360 if (placeholder) {
3361 let raw = prompt.styles.unstyle(output + cursor);
3362 return output + cursor + style(initial.slice(raw.length));
3363 }
3364
3365 return output + cursor;
3366};
3367
3368class FormPrompt extends select {
3369 constructor(options) {
3370 super({ ...options, multiple: true });
3371 this.type = 'form';
3372 this.initial = this.options.initial;
3373 this.align = [this.options.align, 'right'].find(v => v != null);
3374 this.emptyError = '';
3375 this.values = {};
3376 }
3377
3378 async reset(first) {
3379 await super.reset();
3380 if (first === true) this._index = this.index;
3381 this.index = this._index;
3382 this.values = {};
3383 this.choices.forEach(choice => choice.reset && choice.reset());
3384 return this.render();
3385 }
3386
3387 dispatch(char) {
3388 return !!char && this.append(char);
3389 }
3390
3391 append(char) {
3392 let choice = this.focused;
3393 if (!choice) return this.alert();
3394 let { cursor, input } = choice;
3395 choice.value = choice.input = input.slice(0, cursor) + char + input.slice(cursor);
3396 choice.cursor++;
3397 return this.render();
3398 }
3399
3400 delete() {
3401 let choice = this.focused;
3402 if (!choice || choice.cursor <= 0) return this.alert();
3403 let { cursor, input } = choice;
3404 choice.value = choice.input = input.slice(0, cursor - 1) + input.slice(cursor);
3405 choice.cursor--;
3406 return this.render();
3407 }
3408
3409 deleteForward() {
3410 let choice = this.focused;
3411 if (!choice) return this.alert();
3412 let { cursor, input } = choice;
3413 if (input[cursor] === void 0) return this.alert();
3414 let str = `${input}`.slice(0, cursor) + `${input}`.slice(cursor + 1);
3415 choice.value = choice.input = str;
3416 return this.render();
3417 }
3418
3419 right() {
3420 let choice = this.focused;
3421 if (!choice) return this.alert();
3422 if (choice.cursor >= choice.input.length) return this.alert();
3423 choice.cursor++;
3424 return this.render();
3425 }
3426
3427 left() {
3428 let choice = this.focused;
3429 if (!choice) return this.alert();
3430 if (choice.cursor <= 0) return this.alert();
3431 choice.cursor--;
3432 return this.render();
3433 }
3434
3435 space(ch, key) {
3436 return this.dispatch(ch, key);
3437 }
3438
3439 number(ch, key) {
3440 return this.dispatch(ch, key);
3441 }
3442
3443 next() {
3444 let ch = this.focused;
3445 if (!ch) return this.alert();
3446 let { initial, input } = ch;
3447 if (initial && initial.startsWith(input) && input !== initial) {
3448 ch.value = ch.input = initial;
3449 ch.cursor = ch.value.length;
3450 return this.render();
3451 }
3452 return super.next();
3453 }
3454
3455 prev() {
3456 let ch = this.focused;
3457 if (!ch) return this.alert();
3458 if (ch.cursor === 0) return super.prev();
3459 ch.value = ch.input = '';
3460 ch.cursor = 0;
3461 return this.render();
3462 }
3463
3464 separator() {
3465 return '';
3466 }
3467
3468 format(value) {
3469 return !this.state.submitted ? super.format(value) : '';
3470 }
3471
3472 pointer() {
3473 return '';
3474 }
3475
3476 indicator(choice) {
3477 return choice.input ? '⦿' : '⊙';
3478 }
3479
3480 async choiceSeparator(choice, i) {
3481 let sep = await this.resolve(choice.separator, this.state, choice, i) || ':';
3482 return sep ? ' ' + this.styles.disabled(sep) : '';
3483 }
3484
3485 async renderChoice(choice, i) {
3486 await this.onChoice(choice, i);
3487
3488 let { state, styles } = this;
3489 let { cursor, initial = '', name, hint, input = '' } = choice;
3490 let { muted, submitted, primary, danger } = styles;
3491
3492 let help = hint;
3493 let focused = this.index === i;
3494 let validate = choice.validate || (() => true);
3495 let sep = await this.choiceSeparator(choice, i);
3496 let msg = choice.message;
3497
3498 if (this.align === 'right') msg = msg.padStart(this.longest + 1, ' ');
3499 if (this.align === 'left') msg = msg.padEnd(this.longest + 1, ' ');
3500
3501 // re-populate the form values (answers) object
3502 let value = this.values[name] = (input || initial);
3503 let color = input ? 'success' : 'dark';
3504
3505 if ((await validate.call(choice, value, this.state)) !== true) {
3506 color = 'danger';
3507 }
3508
3509 let style = styles[color];
3510 let indicator = style(await this.indicator(choice, i)) + (choice.pad || '');
3511
3512 let indent = this.indent(choice);
3513 let line = () => [indent, indicator, msg + sep, input, help].filter(Boolean).join(' ');
3514
3515 if (state.submitted) {
3516 msg = ansiColors.unstyle(msg);
3517 input = submitted(input);
3518 help = '';
3519 return line();
3520 }
3521
3522 if (choice.format) {
3523 input = await choice.format.call(this, input, choice, i);
3524 } else {
3525 let color = this.styles.muted;
3526 let options = { input, initial, pos: cursor, showCursor: focused, color };
3527 input = placeholder(this, options);
3528 }
3529
3530 if (!this.isValue(input)) {
3531 input = this.styles.muted(this.symbols.ellipsis);
3532 }
3533
3534 if (choice.result) {
3535 this.values[name] = await choice.result.call(this, value, choice, i);
3536 }
3537
3538 if (focused) {
3539 msg = primary(msg);
3540 }
3541
3542 if (choice.error) {
3543 input += (input ? ' ' : '') + danger(choice.error.trim());
3544 } else if (choice.hint) {
3545 input += (input ? ' ' : '') + muted(choice.hint.trim());
3546 }
3547
3548 return line();
3549 }
3550
3551 async submit() {
3552 this.value = this.values;
3553 return super.base.submit.call(this);
3554 }
3555}
3556
3557var form$1 = FormPrompt;
3558
3559const defaultAuthenticate$1 = () => {
3560 throw new Error('expected prompt to have a custom authenticate method');
3561};
3562
3563const factory$1 = (authenticate = defaultAuthenticate$1) => {
3564
3565 class AuthPrompt extends form$1 {
3566 constructor(options) {
3567 super(options);
3568 }
3569
3570 async submit() {
3571 this.value = await authenticate.call(this, this.values, this.state);
3572 super.base.submit.call(this);
3573 }
3574
3575 static create(authenticate) {
3576 return factory$1(authenticate);
3577 }
3578 }
3579
3580 return AuthPrompt;
3581};
3582
3583var auth = factory$1();
3584
3585function defaultAuthenticate(value, state) {
3586 if (value.username === this.options.username && value.password === this.options.password) {
3587 return true;
3588 }
3589 return false;
3590}
3591
3592const factory = (authenticate = defaultAuthenticate) => {
3593 const choices = [
3594 { name: 'username', message: 'username' },
3595 {
3596 name: 'password',
3597 message: 'password',
3598 format(input) {
3599 if (this.options.showPassword) {
3600 return input;
3601 }
3602 let color = this.state.submitted ? this.styles.primary : this.styles.muted;
3603 return color(this.symbols.asterisk.repeat(input.length));
3604 }
3605 }
3606 ];
3607
3608 class BasicAuthPrompt extends auth.create(authenticate) {
3609 constructor(options) {
3610 super({ ...options, choices });
3611 }
3612
3613 static create(authenticate) {
3614 return factory(authenticate);
3615 }
3616 }
3617
3618 return BasicAuthPrompt;
3619};
3620
3621var basicauth = factory();
3622
3623const { isPrimitive: isPrimitive$1, hasColor } = utils;
3624
3625class BooleanPrompt extends prompt {
3626 constructor(options) {
3627 super(options);
3628 this.cursorHide();
3629 }
3630
3631 async initialize() {
3632 let initial = await this.resolve(this.initial, this.state);
3633 this.input = await this.cast(initial);
3634 await super.initialize();
3635 }
3636
3637 dispatch(ch) {
3638 if (!this.isValue(ch)) return this.alert();
3639 this.input = ch;
3640 return this.submit();
3641 }
3642
3643 format(value) {
3644 let { styles, state } = this;
3645 return !state.submitted ? styles.primary(value) : styles.success(value);
3646 }
3647
3648 cast(input) {
3649 return this.isTrue(input);
3650 }
3651
3652 isTrue(input) {
3653 return /^[ty1]/i.test(input);
3654 }
3655
3656 isFalse(input) {
3657 return /^[fn0]/i.test(input);
3658 }
3659
3660 isValue(value) {
3661 return isPrimitive$1(value) && (this.isTrue(value) || this.isFalse(value));
3662 }
3663
3664 async hint() {
3665 if (this.state.status === 'pending') {
3666 let hint = await this.element('hint');
3667 if (!hasColor(hint)) {
3668 return this.styles.muted(hint);
3669 }
3670 return hint;
3671 }
3672 }
3673
3674 async render() {
3675 let { input, size } = this.state;
3676
3677 let prefix = await this.prefix();
3678 let sep = await this.separator();
3679 let msg = await this.message();
3680 let hint = this.styles.muted(this.default);
3681
3682 let promptLine = [prefix, msg, hint, sep].filter(Boolean).join(' ');
3683 this.state.prompt = promptLine;
3684
3685 let header = await this.header();
3686 let value = this.value = this.cast(input);
3687 let output = await this.format(value);
3688 let help = (await this.error()) || (await this.hint());
3689 let footer = await this.footer();
3690
3691 if (help && !promptLine.includes(help)) output += ' ' + help;
3692 promptLine += ' ' + output;
3693
3694 this.clear(size);
3695 this.write([header, promptLine, footer].filter(Boolean).join('\n'));
3696 this.restore();
3697 }
3698
3699 set value(value) {
3700 super.value = value;
3701 }
3702 get value() {
3703 return this.cast(super.value);
3704 }
3705}
3706
3707var boolean = BooleanPrompt;
3708
3709class ConfirmPrompt extends boolean {
3710 constructor(options) {
3711 super(options);
3712 this.default = this.options.default || (this.initial ? '(Y/n)' : '(y/N)');
3713 }
3714}
3715
3716var confirm = ConfirmPrompt;
3717
3718const form = form$1.prototype;
3719
3720class Editable extends select {
3721 constructor(options) {
3722 super({ ...options, multiple: true });
3723 this.align = [this.options.align, 'left'].find(v => v != null);
3724 this.emptyError = '';
3725 this.values = {};
3726 }
3727
3728 dispatch(char, key) {
3729 let choice = this.focused;
3730 let parent = choice.parent || {};
3731 if (!choice.editable && !parent.editable) {
3732 if (char === 'a' || char === 'i') return super[char]();
3733 }
3734 return form.dispatch.call(this, char, key);
3735 }
3736
3737 append(char, key) {
3738 return form.append.call(this, char, key);
3739 }
3740
3741 delete(char, key) {
3742 return form.delete.call(this, char, key);
3743 }
3744
3745 space(char) {
3746 return this.focused.editable ? this.append(char) : super.space();
3747 }
3748
3749 number(char) {
3750 return this.focused.editable ? this.append(char) : super.number(char);
3751 }
3752
3753 next() {
3754 return this.focused.editable ? form.next.call(this) : super.next();
3755 }
3756
3757 prev() {
3758 return this.focused.editable ? form.prev.call(this) : super.prev();
3759 }
3760
3761 async indicator(choice, i) {
3762 let symbol = choice.indicator || '';
3763 let value = choice.editable ? symbol : super.indicator(choice, i);
3764 return await this.resolve(value, this.state, choice, i) || '';
3765 }
3766
3767 indent(choice) {
3768 return choice.role === 'heading' ? '' : (choice.editable ? ' ' : ' ');
3769 }
3770
3771 async renderChoice(choice, i) {
3772 choice.indent = '';
3773 if (choice.editable) return form.renderChoice.call(this, choice, i);
3774 return super.renderChoice(choice, i);
3775 }
3776
3777 error() {
3778 return '';
3779 }
3780
3781 footer() {
3782 return this.state.error;
3783 }
3784
3785 async validate() {
3786 let result = true;
3787
3788 for (let choice of this.choices) {
3789 if (typeof choice.validate !== 'function') {
3790 continue;
3791 }
3792
3793 if (choice.role === 'heading') {
3794 continue;
3795 }
3796
3797 let val = choice.parent ? this.value[choice.parent.name] : this.value;
3798
3799 if (choice.editable) {
3800 val = choice.value === choice.name ? choice.initial || '' : choice.value;
3801 } else if (!this.isDisabled(choice)) {
3802 val = choice.enabled === true;
3803 }
3804
3805 result = await choice.validate(val, this.state);
3806
3807 if (result !== true) {
3808 break;
3809 }
3810 }
3811
3812 if (result !== true) {
3813 this.state.error = typeof result === 'string' ? result : 'Invalid Input';
3814 }
3815
3816 return result;
3817 }
3818
3819 submit() {
3820 if (this.focused.newChoice === true) return super.submit();
3821 if (this.choices.some(ch => ch.newChoice)) {
3822 return this.alert();
3823 }
3824
3825 this.value = {};
3826
3827 for (let choice of this.choices) {
3828 let val = choice.parent ? this.value[choice.parent.name] : this.value;
3829
3830 if (choice.role === 'heading') {
3831 this.value[choice.name] = {};
3832 continue;
3833 }
3834
3835 if (choice.editable) {
3836 val[choice.name] = choice.value === choice.name
3837 ? (choice.initial || '')
3838 : choice.value;
3839
3840 } else if (!this.isDisabled(choice)) {
3841 val[choice.name] = choice.enabled === true;
3842 }
3843 }
3844
3845 return this.base.submit.call(this);
3846 }
3847}
3848
3849var editable = Editable;
3850
3851const { isPrimitive } = utils;
3852
3853class StringPrompt extends prompt {
3854 constructor(options) {
3855 super(options);
3856 this.initial = isPrimitive(this.initial) ? String(this.initial) : '';
3857 if (this.initial) this.cursorHide();
3858 this.state.prevCursor = 0;
3859 this.state.clipboard = [];
3860 }
3861
3862 async keypress(input, key = {}) {
3863 let prev = this.state.prevKeypress;
3864 this.state.prevKeypress = key;
3865 if (this.options.multiline === true && key.name === 'return') {
3866 if (!prev || prev.name !== 'return') {
3867 return this.append('\n', key);
3868 }
3869 }
3870 return super.keypress(input, key);
3871 }
3872
3873 moveCursor(n) {
3874 this.cursor += n;
3875 }
3876
3877 reset() {
3878 this.input = this.value = '';
3879 this.cursor = 0;
3880 return this.render();
3881 }
3882
3883 dispatch(ch, key) {
3884 if (!ch || key.ctrl || key.code) return this.alert();
3885 this.append(ch);
3886 }
3887
3888 append(ch) {
3889 let { cursor, input } = this.state;
3890 this.input = `${input}`.slice(0, cursor) + ch + `${input}`.slice(cursor);
3891 this.moveCursor(String(ch).length);
3892 this.render();
3893 }
3894
3895 insert(str) {
3896 this.append(str);
3897 }
3898
3899 delete() {
3900 let { cursor, input } = this.state;
3901 if (cursor <= 0) return this.alert();
3902 this.input = `${input}`.slice(0, cursor - 1) + `${input}`.slice(cursor);
3903 this.moveCursor(-1);
3904 this.render();
3905 }
3906
3907 deleteForward() {
3908 let { cursor, input } = this.state;
3909 if (input[cursor] === void 0) return this.alert();
3910 this.input = `${input}`.slice(0, cursor) + `${input}`.slice(cursor + 1);
3911 this.render();
3912 }
3913
3914 cutForward() {
3915 let pos = this.cursor;
3916 if (this.input.length <= pos) return this.alert();
3917 this.state.clipboard.push(this.input.slice(pos));
3918 this.input = this.input.slice(0, pos);
3919 this.render();
3920 }
3921
3922 cutLeft() {
3923 let pos = this.cursor;
3924 if (pos === 0) return this.alert();
3925 let before = this.input.slice(0, pos);
3926 let after = this.input.slice(pos);
3927 let words = before.split(' ');
3928 this.state.clipboard.push(words.pop());
3929 this.input = words.join(' ');
3930 this.cursor = this.input.length;
3931 this.input += after;
3932 this.render();
3933 }
3934
3935 paste() {
3936 if (!this.state.clipboard.length) return this.alert();
3937 this.insert(this.state.clipboard.pop());
3938 this.render();
3939 }
3940
3941 toggleCursor() {
3942 if (this.state.prevCursor) {
3943 this.cursor = this.state.prevCursor;
3944 this.state.prevCursor = 0;
3945 } else {
3946 this.state.prevCursor = this.cursor;
3947 this.cursor = 0;
3948 }
3949 this.render();
3950 }
3951
3952 first() {
3953 this.cursor = 0;
3954 this.render();
3955 }
3956
3957 last() {
3958 this.cursor = this.input.length - 1;
3959 this.render();
3960 }
3961
3962 next() {
3963 let init = this.initial != null ? String(this.initial) : '';
3964 if (!init || !init.startsWith(this.input)) return this.alert();
3965 this.input = this.initial;
3966 this.cursor = this.initial.length;
3967 this.render();
3968 }
3969
3970 prev() {
3971 if (!this.input) return this.alert();
3972 this.reset();
3973 }
3974
3975 backward() {
3976 return this.left();
3977 }
3978
3979 forward() {
3980 return this.right();
3981 }
3982
3983 right() {
3984 if (this.cursor >= this.input.length) return this.alert();
3985 this.moveCursor(1);
3986 return this.render();
3987 }
3988
3989 left() {
3990 if (this.cursor <= 0) return this.alert();
3991 this.moveCursor(-1);
3992 return this.render();
3993 }
3994
3995 isValue(value) {
3996 return !!value;
3997 }
3998
3999 async format(input = this.value) {
4000 let initial = await this.resolve(this.initial, this.state);
4001 if (!this.state.submitted) {
4002 return placeholder(this, { input, initial, pos: this.cursor });
4003 }
4004 return this.styles.submitted(input || initial);
4005 }
4006
4007 async render() {
4008 let size = this.state.size;
4009
4010 let prefix = await this.prefix();
4011 let separator = await this.separator();
4012 let message = await this.message();
4013
4014 let prompt = [prefix, message, separator].filter(Boolean).join(' ');
4015 this.state.prompt = prompt;
4016
4017 let header = await this.header();
4018 let output = await this.format();
4019 let help = (await this.error()) || (await this.hint());
4020 let footer = await this.footer();
4021
4022 if (help && !output.includes(help)) output += ' ' + help;
4023 prompt += ' ' + output;
4024
4025 this.clear(size);
4026 this.write([header, prompt, footer].filter(Boolean).join('\n'));
4027 this.restore();
4028 }
4029}
4030
4031var string = StringPrompt;
4032
4033const unique = arr => arr.filter((v, i) => arr.lastIndexOf(v) === i);
4034const compact = arr => unique(arr).filter(Boolean);
4035
4036var completer = (action, data = {}, value = '') => {
4037 let { past = [], present = '' } = data;
4038 let rest, prev;
4039
4040 switch (action) {
4041 case 'prev':
4042 case 'undo':
4043 rest = past.slice(0, past.length - 1);
4044 prev = past[past.length - 1] || '';
4045 return {
4046 past: compact([value, ...rest]),
4047 present: prev
4048 };
4049
4050 case 'next':
4051 case 'redo':
4052 rest = past.slice(1);
4053 prev = past[0] || '';
4054 return {
4055 past: compact([...rest, value]),
4056 present: prev
4057 };
4058
4059 case 'save':
4060 return {
4061 past: compact([...past, value]),
4062 present: ''
4063 };
4064
4065 case 'remove':
4066 prev = compact(past.filter(v => v !== value));
4067 present = '';
4068
4069 if (prev.length) {
4070 present = prev.pop();
4071 }
4072
4073 return {
4074 past: prev,
4075 present
4076 };
4077
4078 default: {
4079 throw new Error(`Invalid action: "${action}"`);
4080 }
4081 }
4082};
4083
4084class Input extends string {
4085 constructor(options) {
4086 super(options);
4087 let history = this.options.history;
4088 if (history && history.store) {
4089 let initial = history.values || this.initial;
4090 this.autosave = !!history.autosave;
4091 this.store = history.store;
4092 this.data = this.store.get('values') || { past: [], present: initial };
4093 this.initial = this.data.present || this.data.past[this.data.past.length - 1];
4094 }
4095 }
4096
4097 completion(action) {
4098 if (!this.store) return this.alert();
4099 this.data = completer(action, this.data, this.input);
4100 if (!this.data.present) return this.alert();
4101 this.input = this.data.present;
4102 this.cursor = this.input.length;
4103 return this.render();
4104 }
4105
4106 altUp() {
4107 return this.completion('prev');
4108 }
4109
4110 altDown() {
4111 return this.completion('next');
4112 }
4113
4114 prev() {
4115 this.save();
4116 return super.prev();
4117 }
4118
4119 save() {
4120 if (!this.store) return;
4121 this.data = completer('save', this.data, this.input);
4122 this.store.set('values', this.data);
4123 }
4124
4125 submit() {
4126 if (this.store && this.autosave === true) {
4127 this.save();
4128 }
4129 return super.submit();
4130 }
4131}
4132
4133var input = Input;
4134
4135class InvisiblePrompt extends string {
4136 format() {
4137 return '';
4138 }
4139}
4140
4141var invisible = InvisiblePrompt;
4142
4143class ListPrompt extends string {
4144 constructor(options = {}) {
4145 super(options);
4146 this.sep = this.options.separator || /, */;
4147 this.initial = options.initial || '';
4148 }
4149
4150 split(input = this.value) {
4151 return input ? String(input).split(this.sep) : [];
4152 }
4153
4154 format() {
4155 let style = this.state.submitted ? this.styles.primary : val => val;
4156 return this.list.map(style).join(', ');
4157 }
4158
4159 async submit(value) {
4160 let result = this.state.error || await this.validate(this.list, this.state);
4161 if (result !== true) {
4162 this.state.error = result;
4163 return super.submit();
4164 }
4165 this.value = this.list;
4166 return super.submit();
4167 }
4168
4169 get list() {
4170 return this.split();
4171 }
4172}
4173
4174var list = ListPrompt;
4175
4176class MultiSelect extends select {
4177 constructor(options) {
4178 super({ ...options, multiple: true });
4179 }
4180}
4181
4182var multiselect = MultiSelect;
4183
4184class NumberPrompt extends string {
4185 constructor(options = {}) {
4186 super({ style: 'number', ...options });
4187 this.min = this.isValue(options.min) ? this.toNumber(options.min) : -Infinity;
4188 this.max = this.isValue(options.max) ? this.toNumber(options.max) : Infinity;
4189 this.delay = options.delay != null ? options.delay : 1000;
4190 this.float = options.float !== false;
4191 this.round = options.round === true || options.float === false;
4192 this.major = options.major || 10;
4193 this.minor = options.minor || 1;
4194 this.initial = options.initial != null ? options.initial : '';
4195 this.input = String(this.initial);
4196 this.cursor = this.input.length;
4197 this.cursorShow();
4198 }
4199
4200 append(ch) {
4201 if (!/[-+.]/.test(ch) || (ch === '.' && this.input.includes('.'))) {
4202 return this.alert('invalid number');
4203 }
4204 return super.append(ch);
4205 }
4206
4207 number(ch) {
4208 return super.append(ch);
4209 }
4210
4211 next() {
4212 if (this.input && this.input !== this.initial) return this.alert();
4213 if (!this.isValue(this.initial)) return this.alert();
4214 this.input = this.initial;
4215 this.cursor = String(this.initial).length;
4216 return this.render();
4217 }
4218
4219 up(number) {
4220 let step = number || this.minor;
4221 let num = this.toNumber(this.input);
4222 if (num > this.max + step) return this.alert();
4223 this.input = `${num + step}`;
4224 return this.render();
4225 }
4226
4227 down(number) {
4228 let step = number || this.minor;
4229 let num = this.toNumber(this.input);
4230 if (num < this.min - step) return this.alert();
4231 this.input = `${num - step}`;
4232 return this.render();
4233 }
4234
4235 shiftDown() {
4236 return this.down(this.major);
4237 }
4238
4239 shiftUp() {
4240 return this.up(this.major);
4241 }
4242
4243 format(input = this.input) {
4244 if (typeof this.options.format === 'function') {
4245 return this.options.format.call(this, input);
4246 }
4247 return this.styles.info(input);
4248 }
4249
4250 toNumber(value = '') {
4251 return this.float ? +value : Math.round(+value);
4252 }
4253
4254 isValue(value) {
4255 return /^[-+]?[0-9]+((\.)|(\.[0-9]+))?$/.test(value);
4256 }
4257
4258 submit() {
4259 let value = [this.input, this.initial].find(v => this.isValue(v));
4260 this.value = this.toNumber(value || 0);
4261 return super.submit();
4262 }
4263}
4264
4265var number = NumberPrompt;
4266
4267var numeral = number;
4268
4269class PasswordPrompt extends string {
4270 constructor(options) {
4271 super(options);
4272 this.cursorShow();
4273 }
4274
4275 format(input = this.input) {
4276 if (!this.keypressed) return '';
4277 let color = this.state.submitted ? this.styles.primary : this.styles.muted;
4278 return color(this.symbols.asterisk.repeat(input.length));
4279 }
4280}
4281
4282var password = PasswordPrompt;
4283
4284class LikertScale extends array {
4285 constructor(options = {}) {
4286 super(options);
4287 this.widths = [].concat(options.messageWidth || 50);
4288 this.align = [].concat(options.align || 'left');
4289 this.linebreak = options.linebreak || false;
4290 this.edgeLength = options.edgeLength || 3;
4291 this.newline = options.newline || '\n ';
4292 let start = options.startNumber || 1;
4293 if (typeof this.scale === 'number') {
4294 this.scaleKey = false;
4295 this.scale = Array(this.scale).fill(0).map((v, i) => ({ name: i + start }));
4296 }
4297 }
4298
4299 async reset() {
4300 this.tableized = false;
4301 await super.reset();
4302 return this.render();
4303 }
4304
4305 tableize() {
4306 if (this.tableized === true) return;
4307 this.tableized = true;
4308 let longest = 0;
4309
4310 for (let ch of this.choices) {
4311 longest = Math.max(longest, ch.message.length);
4312 ch.scaleIndex = ch.initial || 2;
4313 ch.scale = [];
4314
4315 for (let i = 0; i < this.scale.length; i++) {
4316 ch.scale.push({ index: i });
4317 }
4318 }
4319 this.widths[0] = Math.min(this.widths[0], longest + 3);
4320 }
4321
4322 async dispatch(s, key) {
4323 if (this.multiple) {
4324 return this[key.name] ? await this[key.name](s, key) : await super.dispatch(s, key);
4325 }
4326 this.alert();
4327 }
4328
4329 heading(msg, item, i) {
4330 return this.styles.strong(msg);
4331 }
4332
4333 separator() {
4334 return this.styles.muted(this.symbols.ellipsis);
4335 }
4336
4337 right() {
4338 let choice = this.focused;
4339 if (choice.scaleIndex >= this.scale.length - 1) return this.alert();
4340 choice.scaleIndex++;
4341 return this.render();
4342 }
4343
4344 left() {
4345 let choice = this.focused;
4346 if (choice.scaleIndex <= 0) return this.alert();
4347 choice.scaleIndex--;
4348 return this.render();
4349 }
4350
4351 indent() {
4352 return '';
4353 }
4354
4355 format() {
4356 if (this.state.submitted) {
4357 let values = this.choices.map(ch => this.styles.info(ch.index));
4358 return values.join(', ');
4359 }
4360 return '';
4361 }
4362
4363 pointer() {
4364 return '';
4365 }
4366
4367 /**
4368 * Render the scale "Key". Something like:
4369 * @return {String}
4370 */
4371
4372 renderScaleKey() {
4373 if (this.scaleKey === false) return '';
4374 if (this.state.submitted) return '';
4375 let scale = this.scale.map(item => ` ${item.name} - ${item.message}`);
4376 let key = ['', ...scale].map(item => this.styles.muted(item));
4377 return key.join('\n');
4378 }
4379
4380 /**
4381 * Render the heading row for the scale.
4382 * @return {String}
4383 */
4384
4385 renderScaleHeading(max) {
4386 let keys = this.scale.map(ele => ele.name);
4387 if (typeof this.options.renderScaleHeading === 'function') {
4388 keys = this.options.renderScaleHeading.call(this, max);
4389 }
4390 let diff = this.scaleLength - keys.join('').length;
4391 let spacing = Math.round(diff / (keys.length - 1));
4392 let names = keys.map(key => this.styles.strong(key));
4393 let headings = names.join(' '.repeat(spacing));
4394 let padding = ' '.repeat(this.widths[0]);
4395 return this.margin[3] + padding + this.margin[1] + headings;
4396 }
4397
4398 /**
4399 * Render a scale indicator => ◯ or ◉ by default
4400 */
4401
4402 scaleIndicator(choice, item, i) {
4403 if (typeof this.options.scaleIndicator === 'function') {
4404 return this.options.scaleIndicator.call(this, choice, item, i);
4405 }
4406 let enabled = choice.scaleIndex === item.index;
4407 if (item.disabled) return this.styles.hint(this.symbols.radio.disabled);
4408 if (enabled) return this.styles.success(this.symbols.radio.on);
4409 return this.symbols.radio.off;
4410 }
4411
4412 /**
4413 * Render the actual scale => ◯────◯────◉────◯────◯
4414 */
4415
4416 renderScale(choice, i) {
4417 let scale = choice.scale.map(item => this.scaleIndicator(choice, item, i));
4418 let padding = this.term === 'Hyper' ? '' : ' ';
4419 return scale.join(padding + this.symbols.line.repeat(this.edgeLength));
4420 }
4421
4422 /**
4423 * Render a choice, including scale =>
4424 * "The website is easy to navigate. ◯───◯───◉───◯───◯"
4425 */
4426
4427 async renderChoice(choice, i) {
4428 await this.onChoice(choice, i);
4429
4430 let focused = this.index === i;
4431 let pointer = await this.pointer(choice, i);
4432 let hint = await choice.hint;
4433
4434 if (hint && !utils.hasColor(hint)) {
4435 hint = this.styles.muted(hint);
4436 }
4437
4438 let pad = str => this.margin[3] + str.replace(/\s+$/, '').padEnd(this.widths[0], ' ');
4439 let newline = this.newline;
4440 let ind = this.indent(choice);
4441 let message = await this.resolve(choice.message, this.state, choice, i);
4442 let scale = await this.renderScale(choice, i);
4443 let margin = this.margin[1] + this.margin[3];
4444 this.scaleLength = ansiColors.unstyle(scale).length;
4445 this.widths[0] = Math.min(this.widths[0], this.width - this.scaleLength - margin.length);
4446 let msg = utils.wordWrap(message, { width: this.widths[0], newline });
4447 let lines = msg.split('\n').map(line => pad(line) + this.margin[1]);
4448
4449 if (focused) {
4450 scale = this.styles.info(scale);
4451 lines = lines.map(line => this.styles.info(line));
4452 }
4453
4454 lines[0] += scale;
4455
4456 if (this.linebreak) lines.push('');
4457 return [ind + pointer, lines.join('\n')].filter(Boolean);
4458 }
4459
4460 async renderChoices() {
4461 if (this.state.submitted) return '';
4462 this.tableize();
4463 let choices = this.visible.map(async(ch, i) => await this.renderChoice(ch, i));
4464 let visible = await Promise.all(choices);
4465 let heading = await this.renderScaleHeading();
4466 return this.margin[0] + [heading, ...visible.map(v => v.join(' '))].join('\n');
4467 }
4468
4469 async render() {
4470 let { submitted, size } = this.state;
4471
4472 let prefix = await this.prefix();
4473 let separator = await this.separator();
4474 let message = await this.message();
4475
4476 let prompt = '';
4477 if (this.options.promptLine !== false) {
4478 prompt = [prefix, message, separator, ''].join(' ');
4479 this.state.prompt = prompt;
4480 }
4481
4482 let header = await this.header();
4483 let output = await this.format();
4484 let key = await this.renderScaleKey();
4485 let help = await this.error() || await this.hint();
4486 let body = await this.renderChoices();
4487 let footer = await this.footer();
4488 let err = this.emptyError;
4489
4490 if (output) prompt += output;
4491 if (help && !prompt.includes(help)) prompt += ' ' + help;
4492
4493 if (submitted && !output && !body.trim() && this.multiple && err != null) {
4494 prompt += this.styles.danger(err);
4495 }
4496
4497 this.clear(size);
4498 this.write([header, prompt, key, body, footer].filter(Boolean).join('\n'));
4499 if (!this.state.submitted) {
4500 this.write(this.margin[2]);
4501 }
4502 this.restore();
4503 }
4504
4505 submit() {
4506 this.value = {};
4507 for (let choice of this.choices) {
4508 this.value[choice.name] = choice.scaleIndex;
4509 }
4510 return this.base.submit.call(this);
4511 }
4512}
4513
4514var scale = LikertScale;
4515
4516const clean = (str = '') => {
4517 return typeof str === 'string' ? str.replace(/^['"]|['"]$/g, '') : '';
4518};
4519
4520/**
4521 * This file contains the interpolation and rendering logic for
4522 * the Snippet prompt.
4523 */
4524
4525class Item {
4526 constructor(token) {
4527 this.name = token.key;
4528 this.field = token.field || {};
4529 this.value = clean(token.initial || this.field.initial || '');
4530 this.message = token.message || this.name;
4531 this.cursor = 0;
4532 this.input = '';
4533 this.lines = [];
4534 }
4535}
4536
4537const tokenize = async(options = {}, defaults = {}, fn = token => token) => {
4538 let unique = new Set();
4539 let fields = options.fields || [];
4540 let input = options.template;
4541 let tabstops = [];
4542 let items = [];
4543 let keys = [];
4544 let line = 1;
4545
4546 if (typeof input === 'function') {
4547 input = await input();
4548 }
4549
4550 let i = -1;
4551 let next = () => input[++i];
4552 let peek = () => input[i + 1];
4553 let push = token => {
4554 token.line = line;
4555 tabstops.push(token);
4556 };
4557
4558 push({ type: 'bos', value: '' });
4559
4560 while (i < input.length - 1) {
4561 let value = next();
4562
4563 if (/^[^\S\n ]$/.test(value)) {
4564 push({ type: 'text', value });
4565 continue;
4566 }
4567
4568 if (value === '\n') {
4569 push({ type: 'newline', value });
4570 line++;
4571 continue;
4572 }
4573
4574 if (value === '\\') {
4575 value += next();
4576 push({ type: 'text', value });
4577 continue;
4578 }
4579
4580 if ((value === '$' || value === '#' || value === '{') && peek() === '{') {
4581 let n = next();
4582 value += n;
4583
4584 let token = { type: 'template', open: value, inner: '', close: '', value };
4585 let ch;
4586
4587 while ((ch = next())) {
4588 if (ch === '}') {
4589 if (peek() === '}') ch += next();
4590 token.value += ch;
4591 token.close = ch;
4592 break;
4593 }
4594
4595 if (ch === ':') {
4596 token.initial = '';
4597 token.key = token.inner;
4598 } else if (token.initial !== void 0) {
4599 token.initial += ch;
4600 }
4601
4602 token.value += ch;
4603 token.inner += ch;
4604 }
4605
4606 token.template = token.open + (token.initial || token.inner) + token.close;
4607 token.key = token.key || token.inner;
4608
4609 if (defaults.hasOwnProperty(token.key)) {
4610 token.initial = defaults[token.key];
4611 }
4612
4613 token = fn(token);
4614 push(token);
4615
4616 keys.push(token.key);
4617 unique.add(token.key);
4618
4619 let item = items.find(item => item.name === token.key);
4620 token.field = fields.find(ch => ch.name === token.key);
4621
4622 if (!item) {
4623 item = new Item(token);
4624 items.push(item);
4625 }
4626
4627 item.lines.push(token.line - 1);
4628 continue;
4629 }
4630
4631 let last = tabstops[tabstops.length - 1];
4632 if (last.type === 'text' && last.line === line) {
4633 last.value += value;
4634 } else {
4635 push({ type: 'text', value });
4636 }
4637 }
4638
4639 push({ type: 'eos', value: '' });
4640 return { input, tabstops, unique, keys, items };
4641};
4642
4643var interpolate = async prompt => {
4644 let options = prompt.options;
4645 let required = new Set(options.required === true ? [] : (options.required || []));
4646 let defaults = { ...options.values, ...options.initial };
4647 let { tabstops, items, keys } = await tokenize(options, defaults);
4648
4649 let result = createFn('result', prompt);
4650 let format = createFn('format', prompt);
4651 let isValid = createFn('validate', prompt, options, true);
4652 let isVal = prompt.isValue.bind(prompt);
4653
4654 return async(state = {}, submitted = false) => {
4655 let index = 0;
4656
4657 state.required = required;
4658 state.items = items;
4659 state.keys = keys;
4660 state.output = '';
4661
4662 let validate = async(value, state, item, index) => {
4663 let error = await isValid(value, state, item, index);
4664 if (error === false) {
4665 return 'Invalid field ' + item.name;
4666 }
4667 return error;
4668 };
4669
4670 for (let token of tabstops) {
4671 let value = token.value;
4672 let key = token.key;
4673
4674 if (token.type !== 'template') {
4675 if (value) state.output += value;
4676 continue;
4677 }
4678
4679 if (token.type === 'template') {
4680 let item = items.find(ch => ch.name === key);
4681
4682 if (options.required === true) {
4683 state.required.add(item.name);
4684 }
4685
4686 let val = [item.input, state.values[item.value], item.value, value].find(isVal);
4687 let field = item.field || {};
4688 let message = field.message || token.inner;
4689
4690 if (submitted) {
4691 let error = await validate(state.values[key], state, item, index);
4692 if ((error && typeof error === 'string') || error === false) {
4693 state.invalid.set(key, error);
4694 continue;
4695 }
4696
4697 state.invalid.delete(key);
4698 let res = await result(state.values[key], state, item, index);
4699 state.output += ansiColors.unstyle(res);
4700 continue;
4701 }
4702
4703 item.placeholder = false;
4704
4705 let before = value;
4706 value = await format(value, state, item, index);
4707
4708 if (val !== value) {
4709 state.values[key] = val;
4710 value = prompt.styles.typing(val);
4711 state.missing.delete(message);
4712
4713 } else {
4714 state.values[key] = void 0;
4715 val = `<${message}>`;
4716 value = prompt.styles.primary(val);
4717 item.placeholder = true;
4718
4719 if (state.required.has(key)) {
4720 state.missing.add(message);
4721 }
4722 }
4723
4724 if (state.missing.has(message) && state.validating) {
4725 value = prompt.styles.warning(val);
4726 }
4727
4728 if (state.invalid.has(key) && state.validating) {
4729 value = prompt.styles.danger(val);
4730 }
4731
4732 if (index === state.index) {
4733 if (before !== value) {
4734 value = prompt.styles.underline(value);
4735 } else {
4736 value = prompt.styles.heading(ansiColors.unstyle(value));
4737 }
4738 }
4739
4740 index++;
4741 }
4742
4743 if (value) {
4744 state.output += value;
4745 }
4746 }
4747
4748 let lines = state.output.split('\n').map(l => ' ' + l);
4749 let len = items.length;
4750 let done = 0;
4751
4752 for (let item of items) {
4753 if (state.invalid.has(item.name)) {
4754 item.lines.forEach(i => {
4755 if (lines[i][0] !== ' ') return;
4756 lines[i] = state.styles.danger(state.symbols.bullet) + lines[i].slice(1);
4757 });
4758 }
4759
4760 if (prompt.isValue(state.values[item.name])) {
4761 done++;
4762 }
4763 }
4764
4765 state.completed = ((done / len) * 100).toFixed(0);
4766 state.output = lines.join('\n');
4767 return state.output;
4768 };
4769};
4770
4771function createFn(prop, prompt, options, fallback) {
4772 return (value, state, item, index) => {
4773 if (typeof item.field[prop] === 'function') {
4774 return item.field[prop].call(prompt, value, state, item, index);
4775 }
4776 return [fallback, value].find(v => prompt.isValue(v));
4777 };
4778}
4779
4780class SnippetPrompt extends prompt {
4781 constructor(options) {
4782 super(options);
4783 this.cursorHide();
4784 this.reset(true);
4785 }
4786
4787 async initialize() {
4788 this.interpolate = await interpolate(this);
4789 await super.initialize();
4790 }
4791
4792 async reset(first) {
4793 this.state.keys = [];
4794 this.state.invalid = new Map();
4795 this.state.missing = new Set();
4796 this.state.completed = 0;
4797 this.state.values = {};
4798
4799 if (first !== true) {
4800 await this.initialize();
4801 await this.render();
4802 }
4803 }
4804
4805 moveCursor(n) {
4806 let item = this.getItem();
4807 this.cursor += n;
4808 item.cursor += n;
4809 }
4810
4811 dispatch(ch, key) {
4812 if (!key.code && !key.ctrl && ch != null && this.getItem()) {
4813 this.append(ch, key);
4814 return;
4815 }
4816 this.alert();
4817 }
4818
4819 append(ch, key) {
4820 let item = this.getItem();
4821 let prefix = item.input.slice(0, this.cursor);
4822 let suffix = item.input.slice(this.cursor);
4823 this.input = item.input = `${prefix}${ch}${suffix}`;
4824 this.moveCursor(1);
4825 this.render();
4826 }
4827
4828 delete() {
4829 let item = this.getItem();
4830 if (this.cursor <= 0 || !item.input) return this.alert();
4831 let suffix = item.input.slice(this.cursor);
4832 let prefix = item.input.slice(0, this.cursor - 1);
4833 this.input = item.input = `${prefix}${suffix}`;
4834 this.moveCursor(-1);
4835 this.render();
4836 }
4837
4838 increment(i) {
4839 return i >= this.state.keys.length - 1 ? 0 : i + 1;
4840 }
4841
4842 decrement(i) {
4843 return i <= 0 ? this.state.keys.length - 1 : i - 1;
4844 }
4845
4846 first() {
4847 this.state.index = 0;
4848 this.render();
4849 }
4850
4851 last() {
4852 this.state.index = this.state.keys.length - 1;
4853 this.render();
4854 }
4855
4856 right() {
4857 if (this.cursor >= this.input.length) return this.alert();
4858 this.moveCursor(1);
4859 this.render();
4860 }
4861
4862 left() {
4863 if (this.cursor <= 0) return this.alert();
4864 this.moveCursor(-1);
4865 this.render();
4866 }
4867
4868 prev() {
4869 this.state.index = this.decrement(this.state.index);
4870 this.getItem();
4871 this.render();
4872 }
4873
4874 next() {
4875 this.state.index = this.increment(this.state.index);
4876 this.getItem();
4877 this.render();
4878 }
4879
4880 up() {
4881 this.prev();
4882 }
4883
4884 down() {
4885 this.next();
4886 }
4887
4888 format(value) {
4889 let color = this.state.completed < 100 ? this.styles.warning : this.styles.success;
4890 if (this.state.submitted === true && this.state.completed !== 100) {
4891 color = this.styles.danger;
4892 }
4893 return color(`${this.state.completed}% completed`);
4894 }
4895
4896 async render() {
4897 let { index, keys = [], submitted, size } = this.state;
4898
4899 let newline = [this.options.newline, '\n'].find(v => v != null);
4900 let prefix = await this.prefix();
4901 let separator = await this.separator();
4902 let message = await this.message();
4903
4904 let prompt = [prefix, message, separator].filter(Boolean).join(' ');
4905 this.state.prompt = prompt;
4906
4907 let header = await this.header();
4908 let error = (await this.error()) || '';
4909 let hint = (await this.hint()) || '';
4910 let body = submitted ? '' : await this.interpolate(this.state);
4911
4912 let key = this.state.key = keys[index] || '';
4913 let input = await this.format(key);
4914 let footer = await this.footer();
4915 if (input) prompt += ' ' + input;
4916 if (hint && !input && this.state.completed === 0) prompt += ' ' + hint;
4917
4918 this.clear(size);
4919 let lines = [header, prompt, body, footer, error.trim()];
4920 this.write(lines.filter(Boolean).join(newline));
4921 this.restore();
4922 }
4923
4924 getItem(name) {
4925 let { items, keys, index } = this.state;
4926 let item = items.find(ch => ch.name === keys[index]);
4927 if (item && item.input != null) {
4928 this.input = item.input;
4929 this.cursor = item.cursor;
4930 }
4931 return item;
4932 }
4933
4934 async submit() {
4935 if (typeof this.interpolate !== 'function') await this.initialize();
4936 await this.interpolate(this.state, true);
4937
4938 let { invalid, missing, output, values } = this.state;
4939 if (invalid.size) {
4940 let err = '';
4941 for (let [key, value] of invalid) err += `Invalid ${key}: ${value}\n`;
4942 this.state.error = err;
4943 return super.submit();
4944 }
4945
4946 if (missing.size) {
4947 this.state.error = 'Required: ' + [...missing.keys()].join(', ');
4948 return super.submit();
4949 }
4950
4951 let lines = ansiColors.unstyle(output).split('\n');
4952 let result = lines.map(v => v.slice(1)).join('\n');
4953 this.value = { values, result };
4954 return super.submit();
4955 }
4956}
4957
4958var snippet = SnippetPrompt;
4959
4960const hint = '(Use <shift>+<up/down> to sort)';
4961
4962
4963class Sort extends select {
4964 constructor(options) {
4965 super({ ...options, reorder: false, sort: true, multiple: true });
4966 this.state.hint = [this.options.hint, hint].find(this.isValue.bind(this));
4967 }
4968
4969 indicator() {
4970 return '';
4971 }
4972
4973 async renderChoice(choice, i) {
4974 let str = await super.renderChoice(choice, i);
4975 let sym = this.symbols.identicalTo + ' ';
4976 let pre = (this.index === i && this.sorting) ? this.styles.muted(sym) : ' ';
4977 if (this.options.drag === false) pre = '';
4978 if (this.options.numbered === true) {
4979 return pre + `${i + 1} - ` + str;
4980 }
4981 return pre + str;
4982 }
4983
4984 get selected() {
4985 return this.choices;
4986 }
4987
4988 submit() {
4989 this.value = this.choices.map(choice => choice.value);
4990 return super.submit();
4991 }
4992}
4993
4994var sort = Sort;
4995
4996class Survey extends array {
4997 constructor(options = {}) {
4998 super(options);
4999 this.emptyError = options.emptyError || 'No items were selected';
5000 this.term = process.env.TERM_PROGRAM;
5001
5002 if (!this.options.header) {
5003 let header = ['', '4 - Strongly Agree', '3 - Agree', '2 - Neutral', '1 - Disagree', '0 - Strongly Disagree', ''];
5004 header = header.map(ele => this.styles.muted(ele));
5005 this.state.header = header.join('\n ');
5006 }
5007 }
5008
5009 async toChoices(...args) {
5010 if (this.createdScales) return false;
5011 this.createdScales = true;
5012 let choices = await super.toChoices(...args);
5013 for (let choice of choices) {
5014 choice.scale = createScale(5, this.options);
5015 choice.scaleIdx = 2;
5016 }
5017 return choices;
5018 }
5019
5020 dispatch() {
5021 this.alert();
5022 }
5023
5024 space() {
5025 let choice = this.focused;
5026 let ele = choice.scale[choice.scaleIdx];
5027 let selected = ele.selected;
5028 choice.scale.forEach(e => (e.selected = false));
5029 ele.selected = !selected;
5030 return this.render();
5031 }
5032
5033 indicator() {
5034 return '';
5035 }
5036
5037 pointer() {
5038 return '';
5039 }
5040
5041 separator() {
5042 return this.styles.muted(this.symbols.ellipsis);
5043 }
5044
5045 right() {
5046 let choice = this.focused;
5047 if (choice.scaleIdx >= choice.scale.length - 1) return this.alert();
5048 choice.scaleIdx++;
5049 return this.render();
5050 }
5051
5052 left() {
5053 let choice = this.focused;
5054 if (choice.scaleIdx <= 0) return this.alert();
5055 choice.scaleIdx--;
5056 return this.render();
5057 }
5058
5059 indent() {
5060 return ' ';
5061 }
5062
5063 async renderChoice(item, i) {
5064 await this.onChoice(item, i);
5065 let focused = this.index === i;
5066 let isHyper = this.term === 'Hyper';
5067 let n = !isHyper ? 8 : 9;
5068 let s = !isHyper ? ' ' : '';
5069 let ln = this.symbols.line.repeat(n);
5070 let sp = ' '.repeat(n + (isHyper ? 0 : 1));
5071 let dot = enabled => (enabled ? this.styles.success('◉') : '◯') + s;
5072
5073 let num = i + 1 + '.';
5074 let color = focused ? this.styles.heading : this.styles.noop;
5075 let msg = await this.resolve(item.message, this.state, item, i);
5076 let indent = this.indent(item);
5077 let scale = indent + item.scale.map((e, i) => dot(i === item.scaleIdx)).join(ln);
5078 let val = i => i === item.scaleIdx ? color(i) : i;
5079 let next = indent + item.scale.map((e, i) => val(i)).join(sp);
5080
5081 let line = () => [num, msg].filter(Boolean).join(' ');
5082 let lines = () => [line(), scale, next, ' '].filter(Boolean).join('\n');
5083
5084 if (focused) {
5085 scale = this.styles.cyan(scale);
5086 next = this.styles.cyan(next);
5087 }
5088
5089 return lines();
5090 }
5091
5092 async renderChoices() {
5093 if (this.state.submitted) return '';
5094 let choices = this.visible.map(async(ch, i) => await this.renderChoice(ch, i));
5095 let visible = await Promise.all(choices);
5096 if (!visible.length) visible.push(this.styles.danger('No matching choices'));
5097 return visible.join('\n');
5098 }
5099
5100 format() {
5101 if (this.state.submitted) {
5102 let values = this.choices.map(ch => this.styles.info(ch.scaleIdx));
5103 return values.join(', ');
5104 }
5105 return '';
5106 }
5107
5108 async render() {
5109 let { submitted, size } = this.state;
5110
5111 let prefix = await this.prefix();
5112 let separator = await this.separator();
5113 let message = await this.message();
5114
5115 let prompt = [prefix, message, separator].filter(Boolean).join(' ');
5116 this.state.prompt = prompt;
5117
5118 let header = await this.header();
5119 let output = await this.format();
5120 let help = await this.error() || await this.hint();
5121 let body = await this.renderChoices();
5122 let footer = await this.footer();
5123
5124 if (output || !help) prompt += ' ' + output;
5125 if (help && !prompt.includes(help)) prompt += ' ' + help;
5126
5127 if (submitted && !output && !body && this.multiple && this.type !== 'form') {
5128 prompt += this.styles.danger(this.emptyError);
5129 }
5130
5131 this.clear(size);
5132 this.write([prompt, header, body, footer].filter(Boolean).join('\n'));
5133 this.restore();
5134 }
5135
5136 submit() {
5137 this.value = {};
5138 for (let choice of this.choices) {
5139 this.value[choice.name] = choice.scaleIdx;
5140 }
5141 return this.base.submit.call(this);
5142 }
5143}
5144
5145function createScale(n, options = {}) {
5146 if (Array.isArray(options.scale)) {
5147 return options.scale.map(ele => ({ ...ele }));
5148 }
5149 let scale = [];
5150 for (let i = 1; i < n + 1; i++) scale.push({ i, selected: false });
5151 return scale;
5152}
5153
5154var survey = Survey;
5155
5156var text = input;
5157
5158class TogglePrompt extends boolean {
5159 async initialize() {
5160 await super.initialize();
5161 this.value = this.initial = !!this.options.initial;
5162 this.disabled = this.options.disabled || 'no';
5163 this.enabled = this.options.enabled || 'yes';
5164 await this.render();
5165 }
5166
5167 reset() {
5168 this.value = this.initial;
5169 this.render();
5170 }
5171
5172 delete() {
5173 this.alert();
5174 }
5175
5176 toggle() {
5177 this.value = !this.value;
5178 this.render();
5179 }
5180
5181 enable() {
5182 if (this.value === true) return this.alert();
5183 this.value = true;
5184 this.render();
5185 }
5186 disable() {
5187 if (this.value === false) return this.alert();
5188 this.value = false;
5189 this.render();
5190 }
5191
5192 up() {
5193 this.toggle();
5194 }
5195 down() {
5196 this.toggle();
5197 }
5198 right() {
5199 this.toggle();
5200 }
5201 left() {
5202 this.toggle();
5203 }
5204 next() {
5205 this.toggle();
5206 }
5207 prev() {
5208 this.toggle();
5209 }
5210
5211 dispatch(ch = '', key) {
5212 switch (ch.toLowerCase()) {
5213 case ' ':
5214 return this.toggle();
5215 case '1':
5216 case 'y':
5217 case 't':
5218 return this.enable();
5219 case '0':
5220 case 'n':
5221 case 'f':
5222 return this.disable();
5223 default: {
5224 return this.alert();
5225 }
5226 }
5227 }
5228
5229 format() {
5230 let active = str => this.styles.primary.underline(str);
5231 let value = [
5232 this.value ? this.disabled : active(this.disabled),
5233 this.value ? active(this.enabled) : this.enabled
5234 ];
5235 return value.join(this.styles.muted(' / '));
5236 }
5237
5238 async render() {
5239 let { size } = this.state;
5240
5241 let header = await this.header();
5242 let prefix = await this.prefix();
5243 let separator = await this.separator();
5244 let message = await this.message();
5245
5246 let output = await this.format();
5247 let help = (await this.error()) || (await this.hint());
5248 let footer = await this.footer();
5249
5250 let prompt = [prefix, message, separator, output].join(' ');
5251 this.state.prompt = prompt;
5252
5253 if (help && !prompt.includes(help)) prompt += ' ' + help;
5254
5255 this.clear(size);
5256 this.write([header, prompt, footer].filter(Boolean).join('\n'));
5257 this.write(this.margin[2]);
5258 this.restore();
5259 }
5260}
5261
5262var toggle = TogglePrompt;
5263
5264class Quiz extends select {
5265 constructor(options) {
5266 super(options);
5267 if (typeof this.options.correctChoice !== 'number' || this.options.correctChoice < 0) {
5268 throw new Error('Please specify the index of the correct answer from the list of choices');
5269 }
5270 }
5271
5272 async toChoices(value, parent) {
5273 let choices = await super.toChoices(value, parent);
5274 if (choices.length < 2) {
5275 throw new Error('Please give at least two choices to the user');
5276 }
5277 if (this.options.correctChoice > choices.length) {
5278 throw new Error('Please specify the index of the correct answer from the list of choices');
5279 }
5280 return choices;
5281 }
5282
5283 check(state) {
5284 return state.index === this.options.correctChoice;
5285 }
5286
5287 async result(selected) {
5288 return {
5289 selectedAnswer: selected,
5290 correctAnswer: this.options.choices[this.options.correctChoice].value,
5291 correct: await this.check(this.state)
5292 };
5293 }
5294}
5295
5296var quiz = Quiz;
5297
5298var prompts$1 = index.createCommonjsModule(function (module, exports) {
5299
5300
5301
5302const define = (key, fn) => {
5303 utils.defineExport(exports, key, fn);
5304 utils.defineExport(exports, key.toLowerCase(), fn);
5305};
5306
5307define('AutoComplete', () => autocomplete);
5308define('BasicAuth', () => basicauth);
5309define('Confirm', () => confirm);
5310define('Editable', () => editable);
5311define('Form', () => form$1);
5312define('Input', () => input);
5313define('Invisible', () => invisible);
5314define('List', () => list);
5315define('MultiSelect', () => multiselect);
5316define('Numeral', () => numeral);
5317define('Password', () => password);
5318define('Scale', () => scale);
5319define('Select', () => select);
5320define('Snippet', () => snippet);
5321define('Sort', () => sort);
5322define('Survey', () => survey);
5323define('Text', () => text);
5324define('Toggle', () => toggle);
5325define('Quiz', () => quiz);
5326});
5327
5328var types = {
5329 ArrayPrompt: array,
5330 AuthPrompt: auth,
5331 BooleanPrompt: boolean,
5332 NumberPrompt: number,
5333 StringPrompt: string
5334};
5335
5336/**
5337 * Create an instance of `Enquirer`.
5338 *
5339 * ```js
5340 * const Enquirer = require('enquirer');
5341 * const enquirer = new Enquirer();
5342 * ```
5343 * @name Enquirer
5344 * @param {Object} `options` (optional) Options to use with all prompts.
5345 * @param {Object} `answers` (optional) Answers object to initialize with.
5346 * @api public
5347 */
5348
5349class Enquirer extends Events__default['default'] {
5350 constructor(options, answers) {
5351 super();
5352 this.options = utils.merge({}, options);
5353 this.answers = { ...answers };
5354 }
5355
5356 /**
5357 * Register a custom prompt type.
5358 *
5359 * ```js
5360 * const Enquirer = require('enquirer');
5361 * const enquirer = new Enquirer();
5362 * enquirer.register('customType', require('./custom-prompt'));
5363 * ```
5364 * @name register()
5365 * @param {String} `type`
5366 * @param {Function|Prompt} `fn` `Prompt` class, or a function that returns a `Prompt` class.
5367 * @return {Object} Returns the Enquirer instance
5368 * @api public
5369 */
5370
5371 register(type, fn) {
5372 if (utils.isObject(type)) {
5373 for (let key of Object.keys(type)) this.register(key, type[key]);
5374 return this;
5375 }
5376 assert__default['default'].equal(typeof fn, 'function', 'expected a function');
5377 let name = type.toLowerCase();
5378 if (fn.prototype instanceof this.Prompt) {
5379 this.prompts[name] = fn;
5380 } else {
5381 this.prompts[name] = fn(this.Prompt, this);
5382 }
5383 return this;
5384 }
5385
5386 /**
5387 * Prompt function that takes a "question" object or array of question objects,
5388 * and returns an object with responses from the user.
5389 *
5390 * ```js
5391 * const Enquirer = require('enquirer');
5392 * const enquirer = new Enquirer();
5393 *
5394 * const response = await enquirer.prompt({
5395 * type: 'input',
5396 * name: 'username',
5397 * message: 'What is your username?'
5398 * });
5399 * console.log(response);
5400 * ```
5401 * @name prompt()
5402 * @param {Array|Object} `questions` Options objects for one or more prompts to run.
5403 * @return {Promise} Promise that returns an "answers" object with the user's responses.
5404 * @api public
5405 */
5406
5407 async prompt(questions = []) {
5408 for (let question of [].concat(questions)) {
5409 try {
5410 if (typeof question === 'function') question = await question.call(this);
5411 await this.ask(utils.merge({}, this.options, question));
5412 } catch (err) {
5413 return Promise.reject(err);
5414 }
5415 }
5416 return this.answers;
5417 }
5418
5419 async ask(question) {
5420 if (typeof question === 'function') {
5421 question = await question.call(this);
5422 }
5423
5424 let opts = utils.merge({}, this.options, question);
5425 let { type, name } = question;
5426 let { set, get } = utils;
5427
5428 if (typeof type === 'function') {
5429 type = await type.call(this, question, this.answers);
5430 }
5431
5432 if (!type) return this.answers[name];
5433
5434 assert__default['default'](this.prompts[type], `Prompt "${type}" is not registered`);
5435
5436 let prompt = new this.prompts[type](opts);
5437 let value = get(this.answers, name);
5438
5439 prompt.state.answers = this.answers;
5440 prompt.enquirer = this;
5441
5442 if (name) {
5443 prompt.on('submit', value => {
5444 this.emit('answer', name, value, prompt);
5445 set(this.answers, name, value);
5446 });
5447 }
5448
5449 // bubble events
5450 let emit = prompt.emit.bind(prompt);
5451 prompt.emit = (...args) => {
5452 this.emit.call(this, ...args);
5453 return emit(...args);
5454 };
5455
5456 this.emit('prompt', prompt, this);
5457
5458 if (opts.autofill && value != null) {
5459 prompt.value = prompt.input = value;
5460
5461 // if "autofill=show" render the prompt, otherwise stay "silent"
5462 if (opts.autofill === 'show') {
5463 await prompt.submit();
5464 }
5465 } else {
5466 value = prompt.value = await prompt.run();
5467 }
5468
5469 return value;
5470 }
5471
5472 /**
5473 * Use an enquirer plugin.
5474 *
5475 * ```js
5476 * const Enquirer = require('enquirer');
5477 * const enquirer = new Enquirer();
5478 * const plugin = enquirer => {
5479 * // do stuff to enquire instance
5480 * };
5481 * enquirer.use(plugin);
5482 * ```
5483 * @name use()
5484 * @param {Function} `plugin` Plugin function that takes an instance of Enquirer.
5485 * @return {Object} Returns the Enquirer instance.
5486 * @api public
5487 */
5488
5489 use(plugin) {
5490 plugin.call(this, this);
5491 return this;
5492 }
5493
5494 set Prompt(value) {
5495 this._Prompt = value;
5496 }
5497 get Prompt() {
5498 return this._Prompt || this.constructor.Prompt;
5499 }
5500
5501 get prompts() {
5502 return this.constructor.prompts;
5503 }
5504
5505 static set Prompt(value) {
5506 this._Prompt = value;
5507 }
5508 static get Prompt() {
5509 return this._Prompt || prompt;
5510 }
5511
5512 static get prompts() {
5513 return prompts$1;
5514 }
5515
5516 static get types() {
5517 return types;
5518 }
5519
5520 /**
5521 * Prompt function that takes a "question" object or array of question objects,
5522 * and returns an object with responses from the user.
5523 *
5524 * ```js
5525 * const { prompt } = require('enquirer');
5526 * const response = await prompt({
5527 * type: 'input',
5528 * name: 'username',
5529 * message: 'What is your username?'
5530 * });
5531 * console.log(response);
5532 * ```
5533 * @name Enquirer#prompt
5534 * @param {Array|Object} `questions` Options objects for one or more prompts to run.
5535 * @return {Promise} Promise that returns an "answers" object with the user's responses.
5536 * @api public
5537 */
5538
5539 static get prompt() {
5540 const fn = (questions, ...rest) => {
5541 let enquirer = new this(...rest);
5542 let emit = enquirer.emit.bind(enquirer);
5543 enquirer.emit = (...args) => {
5544 fn.emit(...args);
5545 return emit(...args);
5546 };
5547 return enquirer.prompt(questions);
5548 };
5549 utils.mixinEmitter(fn, new Events__default['default']());
5550 return fn;
5551 }
5552}
5553
5554utils.mixinEmitter(Enquirer, new Events__default['default']());
5555const prompts = Enquirer.prompts;
5556
5557for (let name of Object.keys(prompts)) {
5558 let key = name.toLowerCase();
5559
5560 let run = options => new prompts[name](options).run();
5561 Enquirer.prompt[key] = run;
5562 Enquirer[key] = run;
5563
5564 if (!Enquirer[name]) {
5565 Reflect.defineProperty(Enquirer, name, { get: () => prompts[name] });
5566 }
5567}
5568
5569const exp = name => {
5570 utils.defineExport(Enquirer, name, () => Enquirer.types[name]);
5571};
5572
5573exp('ArrayPrompt');
5574exp('AuthPrompt');
5575exp('BooleanPrompt');
5576exp('NumberPrompt');
5577exp('StringPrompt');
5578
5579var enquirer = Enquirer;
5580
5581const args = mri(process.argv.slice(2), {
5582 alias: {
5583 f: 'force',
5584 c: 'cache',
5585 v: 'verbose',
5586 m: 'mode'
5587 },
5588 boolean: ['force', 'cache', 'verbose']
5589});
5590
5591const [src, dest = '.'] = args._;
5592
5593async function main() {
5594 if (args.help) {
5595 const help = fs__default['default']
5596 .readFileSync(path__default['default'].join(__dirname, 'help.md'), 'utf-8')
5597 .replace(/^(\s*)#+ (.+)/gm, (m, s, _) => s + index.source.bold(_))
5598 .replace(/_([^_]+)_/g, (m, _) => index.source.underline(_))
5599 .replace(/`([^`]+)`/g, (m, _) => index.source.cyan(_));
5600
5601 process.stdout.write(`\n${help}\n`);
5602 } else if (!src) {
5603 // interactive mode
5604
5605 const accessLookup = new Map();
5606
5607 sync(`**/access.json`, { cwd: index.base }).forEach(file => {
5608 const [host, user, repo] = file.split(path__default['default'].sep);
5609
5610 const json = fs__default['default'].readFileSync(`${index.base}/${file}`, 'utf-8');
5611 const logs = JSON.parse(json);
5612
5613 Object.entries(logs).forEach(([ref, timestamp]) => {
5614 const id = `${host}:${user}/${repo}#${ref}`;
5615 accessLookup.set(id, new Date(timestamp).getTime());
5616 });
5617 });
5618
5619 const getChoice = file => {
5620 const [host, user, repo] = file.split(path__default['default'].sep);
5621
5622 return Object.entries(index.tryRequire(`${index.base}/${file}`)).map(
5623 ([ref, hash]) => ({
5624 name: hash,
5625 message: `${host}:${user}/${repo}#${ref}`,
5626 value: `${host}:${user}/${repo}#${ref}`
5627 })
5628 );
5629 };
5630
5631 const choices = sync(`**/map.json`, { cwd: index.base })
5632 .map(getChoice)
5633 .reduce(
5634 (accumulator, currentValue) => accumulator.concat(currentValue),
5635 []
5636 )
5637 .sort((a, b) => {
5638 const aTime = accessLookup.get(a.value) || 0;
5639 const bTime = accessLookup.get(b.value) || 0;
5640
5641 return bTime - aTime;
5642 });
5643
5644 const options = await enquirer.prompt([
5645 {
5646 type: 'autocomplete',
5647 name: 'src',
5648 message: 'Repo to clone?',
5649 suggest: (input, choices) =>
5650 choices.filter(({ value }) => fuzzysearch_1(input, value)),
5651 choices
5652 },
5653 {
5654 type: 'input',
5655 name: 'dest',
5656 message: 'Destination directory?',
5657 initial: '.'
5658 },
5659 {
5660 type: 'toggle',
5661 name: 'cache',
5662 message: 'Use cached version?'
5663 }
5664 ]);
5665
5666 const empty =
5667 !fs__default['default'].existsSync(options.dest) || fs__default['default'].readdirSync(options.dest).length === 0;
5668
5669 if (!empty) {
5670 const { force } = await enquirer.prompt([
5671 {
5672 type: 'toggle',
5673 name: 'force',
5674 message: 'Overwrite existing files?'
5675 }
5676 ]);
5677
5678 if (!force) {
5679 console.error(index.source.magenta(`! Directory not empty — aborting`));
5680 return;
5681 }
5682 }
5683
5684 run(options.src, options.dest, {
5685 force: true,
5686 cache: options.cache
5687 });
5688 } else {
5689 run(src, dest, args);
5690 }
5691}
5692
5693function run(src, dest, args) {
5694 const d = index.degit(src, args);
5695
5696 d.on('info', event => {
5697 console.error(index.source.cyan(`> ${event.message.replace('options.', '--')}`));
5698 });
5699
5700 d.on('warn', event => {
5701 console.error(
5702 index.source.magenta(`! ${event.message.replace('options.', '--')}`)
5703 );
5704 });
5705
5706 d.clone(dest).catch(err => {
5707 console.error(index.source.red(`! ${err.message.replace('options.', '--')}`));
5708 process.exit(1);
5709 });
5710}
5711
5712main();
5713//# sourceMappingURL=bin.js.map