4488 lines
120 KiB
JavaScript
Executable File
4488 lines
120 KiB
JavaScript
Executable File
import path, { join, dirname, resolve } from 'node:path';
|
||
import process$1 from 'node:process';
|
||
import require$$0 from 'readline';
|
||
import require$$2 from 'events';
|
||
import c from 'ansis';
|
||
import { detect as detect$1, AGENTS } from 'package-manager-detector';
|
||
import { x } from 'tinyexec';
|
||
import fs, { promises, existsSync } from 'node:fs';
|
||
import { INSTALL_PAGE } from 'package-manager-detector/constants';
|
||
import require$$0$1 from 'os';
|
||
import require$$1 from 'tty';
|
||
import os from 'node:os';
|
||
import require$$0$2 from 'fs';
|
||
import require$$1$1 from 'fs/promises';
|
||
import require$$1$2 from 'path';
|
||
import { COMMANDS, constructCommand } from 'package-manager-detector/commands';
|
||
|
||
function getDefaultExportFromCjs (x) {
|
||
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
||
}
|
||
|
||
var ini$1;
|
||
var hasRequiredIni;
|
||
|
||
function requireIni () {
|
||
if (hasRequiredIni) return ini$1;
|
||
hasRequiredIni = 1;
|
||
const { hasOwnProperty } = Object.prototype;
|
||
|
||
const encode = (obj, opt = {}) => {
|
||
if (typeof opt === 'string') {
|
||
opt = { section: opt };
|
||
}
|
||
opt.align = opt.align === true;
|
||
opt.newline = opt.newline === true;
|
||
opt.sort = opt.sort === true;
|
||
opt.whitespace = opt.whitespace === true || opt.align === true;
|
||
// The `typeof` check is required because accessing the `process` directly fails on browsers.
|
||
/* istanbul ignore next */
|
||
opt.platform = opt.platform || (typeof process !== 'undefined' && process.platform);
|
||
opt.bracketedArray = opt.bracketedArray !== false;
|
||
|
||
/* istanbul ignore next */
|
||
const eol = opt.platform === 'win32' ? '\r\n' : '\n';
|
||
const separator = opt.whitespace ? ' = ' : '=';
|
||
const children = [];
|
||
|
||
const keys = opt.sort ? Object.keys(obj).sort() : Object.keys(obj);
|
||
|
||
let padToChars = 0;
|
||
// If aligning on the separator, then padToChars is determined as follows:
|
||
// 1. Get the keys
|
||
// 2. Exclude keys pointing to objects unless the value is null or an array
|
||
// 3. Add `[]` to array keys
|
||
// 4. Ensure non empty set of keys
|
||
// 5. Reduce the set to the longest `safe` key
|
||
// 6. Get the `safe` length
|
||
if (opt.align) {
|
||
padToChars = safe(
|
||
(
|
||
keys
|
||
.filter(k => obj[k] === null || Array.isArray(obj[k]) || typeof obj[k] !== 'object')
|
||
.map(k => Array.isArray(obj[k]) ? `${k}[]` : k)
|
||
)
|
||
.concat([''])
|
||
.reduce((a, b) => safe(a).length >= safe(b).length ? a : b)
|
||
).length;
|
||
}
|
||
|
||
let out = '';
|
||
const arraySuffix = opt.bracketedArray ? '[]' : '';
|
||
|
||
for (const k of keys) {
|
||
const val = obj[k];
|
||
if (val && Array.isArray(val)) {
|
||
for (const item of val) {
|
||
out += safe(`${k}${arraySuffix}`).padEnd(padToChars, ' ') + separator + safe(item) + eol;
|
||
}
|
||
} else if (val && typeof val === 'object') {
|
||
children.push(k);
|
||
} else {
|
||
out += safe(k).padEnd(padToChars, ' ') + separator + safe(val) + eol;
|
||
}
|
||
}
|
||
|
||
if (opt.section && out.length) {
|
||
out = '[' + safe(opt.section) + ']' + (opt.newline ? eol + eol : eol) + out;
|
||
}
|
||
|
||
for (const k of children) {
|
||
const nk = splitSections(k, '.').join('\\.');
|
||
const section = (opt.section ? opt.section + '.' : '') + nk;
|
||
const child = encode(obj[k], {
|
||
...opt,
|
||
section,
|
||
});
|
||
if (out.length && child.length) {
|
||
out += eol;
|
||
}
|
||
|
||
out += child;
|
||
}
|
||
|
||
return out
|
||
};
|
||
|
||
function splitSections (str, separator) {
|
||
var lastMatchIndex = 0;
|
||
var lastSeparatorIndex = 0;
|
||
var nextIndex = 0;
|
||
var sections = [];
|
||
|
||
do {
|
||
nextIndex = str.indexOf(separator, lastMatchIndex);
|
||
|
||
if (nextIndex !== -1) {
|
||
lastMatchIndex = nextIndex + separator.length;
|
||
|
||
if (nextIndex > 0 && str[nextIndex - 1] === '\\') {
|
||
continue
|
||
}
|
||
|
||
sections.push(str.slice(lastSeparatorIndex, nextIndex));
|
||
lastSeparatorIndex = nextIndex + separator.length;
|
||
}
|
||
} while (nextIndex !== -1)
|
||
|
||
sections.push(str.slice(lastSeparatorIndex));
|
||
|
||
return sections
|
||
}
|
||
|
||
const decode = (str, opt = {}) => {
|
||
opt.bracketedArray = opt.bracketedArray !== false;
|
||
const out = Object.create(null);
|
||
let p = out;
|
||
let section = null;
|
||
// section |key = value
|
||
const re = /^\[([^\]]*)\]\s*$|^([^=]+)(=(.*))?$/i;
|
||
const lines = str.split(/[\r\n]+/g);
|
||
const duplicates = {};
|
||
|
||
for (const line of lines) {
|
||
if (!line || line.match(/^\s*[;#]/) || line.match(/^\s*$/)) {
|
||
continue
|
||
}
|
||
const match = line.match(re);
|
||
if (!match) {
|
||
continue
|
||
}
|
||
if (match[1] !== undefined) {
|
||
section = unsafe(match[1]);
|
||
if (section === '__proto__') {
|
||
// not allowed
|
||
// keep parsing the section, but don't attach it.
|
||
p = Object.create(null);
|
||
continue
|
||
}
|
||
p = out[section] = out[section] || Object.create(null);
|
||
continue
|
||
}
|
||
const keyRaw = unsafe(match[2]);
|
||
let isArray;
|
||
if (opt.bracketedArray) {
|
||
isArray = keyRaw.length > 2 && keyRaw.slice(-2) === '[]';
|
||
} else {
|
||
duplicates[keyRaw] = (duplicates?.[keyRaw] || 0) + 1;
|
||
isArray = duplicates[keyRaw] > 1;
|
||
}
|
||
const key = isArray && keyRaw.endsWith('[]')
|
||
? keyRaw.slice(0, -2) : keyRaw;
|
||
|
||
if (key === '__proto__') {
|
||
continue
|
||
}
|
||
const valueRaw = match[3] ? unsafe(match[4]) : true;
|
||
const value = valueRaw === 'true' ||
|
||
valueRaw === 'false' ||
|
||
valueRaw === 'null' ? JSON.parse(valueRaw)
|
||
: valueRaw;
|
||
|
||
// Convert keys with '[]' suffix to an array
|
||
if (isArray) {
|
||
if (!hasOwnProperty.call(p, key)) {
|
||
p[key] = [];
|
||
} else if (!Array.isArray(p[key])) {
|
||
p[key] = [p[key]];
|
||
}
|
||
}
|
||
|
||
// safeguard against resetting a previously defined
|
||
// array by accidentally forgetting the brackets
|
||
if (Array.isArray(p[key])) {
|
||
p[key].push(value);
|
||
} else {
|
||
p[key] = value;
|
||
}
|
||
}
|
||
|
||
// {a:{y:1},"a.b":{x:2}} --> {a:{y:1,b:{x:2}}}
|
||
// use a filter to return the keys that have to be deleted.
|
||
const remove = [];
|
||
for (const k of Object.keys(out)) {
|
||
if (!hasOwnProperty.call(out, k) ||
|
||
typeof out[k] !== 'object' ||
|
||
Array.isArray(out[k])) {
|
||
continue
|
||
}
|
||
|
||
// see if the parent section is also an object.
|
||
// if so, add it to that, and mark this one for deletion
|
||
const parts = splitSections(k, '.');
|
||
p = out;
|
||
const l = parts.pop();
|
||
const nl = l.replace(/\\\./g, '.');
|
||
for (const part of parts) {
|
||
if (part === '__proto__') {
|
||
continue
|
||
}
|
||
if (!hasOwnProperty.call(p, part) || typeof p[part] !== 'object') {
|
||
p[part] = Object.create(null);
|
||
}
|
||
p = p[part];
|
||
}
|
||
if (p === out && nl === l) {
|
||
continue
|
||
}
|
||
|
||
p[nl] = out[k];
|
||
remove.push(k);
|
||
}
|
||
for (const del of remove) {
|
||
delete out[del];
|
||
}
|
||
|
||
return out
|
||
};
|
||
|
||
const isQuoted = val => {
|
||
return (val.startsWith('"') && val.endsWith('"')) ||
|
||
(val.startsWith("'") && val.endsWith("'"))
|
||
};
|
||
|
||
const safe = val => {
|
||
if (
|
||
typeof val !== 'string' ||
|
||
val.match(/[=\r\n]/) ||
|
||
val.match(/^\[/) ||
|
||
(val.length > 1 && isQuoted(val)) ||
|
||
val !== val.trim()
|
||
) {
|
||
return JSON.stringify(val)
|
||
}
|
||
return val.split(';').join('\\;').split('#').join('\\#')
|
||
};
|
||
|
||
const unsafe = val => {
|
||
val = (val || '').trim();
|
||
if (isQuoted(val)) {
|
||
// remove the single quotes before calling JSON.parse
|
||
if (val.charAt(0) === "'") {
|
||
val = val.slice(1, -1);
|
||
}
|
||
try {
|
||
val = JSON.parse(val);
|
||
} catch {
|
||
// ignore errors
|
||
}
|
||
} else {
|
||
// walk the val to find the first not-escaped ; character
|
||
let esc = false;
|
||
let unesc = '';
|
||
for (let i = 0, l = val.length; i < l; i++) {
|
||
const c = val.charAt(i);
|
||
if (esc) {
|
||
if ('\\;#'.indexOf(c) !== -1) {
|
||
unesc += c;
|
||
} else {
|
||
unesc += '\\' + c;
|
||
}
|
||
|
||
esc = false;
|
||
} else if (';#'.indexOf(c) !== -1) {
|
||
break
|
||
} else if (c === '\\') {
|
||
esc = true;
|
||
} else {
|
||
unesc += c;
|
||
}
|
||
}
|
||
if (esc) {
|
||
unesc += '\\';
|
||
}
|
||
|
||
return unesc.trim()
|
||
}
|
||
return val
|
||
};
|
||
|
||
ini$1 = {
|
||
parse: decode,
|
||
decode,
|
||
stringify: encode,
|
||
encode,
|
||
safe,
|
||
unsafe,
|
||
};
|
||
return ini$1;
|
||
}
|
||
|
||
var iniExports = requireIni();
|
||
const ini = /*@__PURE__*/getDefaultExportFromCjs(iniExports);
|
||
|
||
var prompts$2 = {};
|
||
|
||
var kleur;
|
||
var hasRequiredKleur;
|
||
|
||
function requireKleur () {
|
||
if (hasRequiredKleur) return kleur;
|
||
hasRequiredKleur = 1;
|
||
|
||
let FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM, isTTY=true;
|
||
if (typeof process !== 'undefined') {
|
||
({ FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM } = process.env || {});
|
||
isTTY = process.stdout && process.stdout.isTTY;
|
||
}
|
||
|
||
const $ = {
|
||
enabled: !NODE_DISABLE_COLORS && NO_COLOR == null && TERM !== 'dumb' && (
|
||
FORCE_COLOR != null && FORCE_COLOR !== '0' || isTTY
|
||
),
|
||
|
||
// modifiers
|
||
reset: init(0, 0),
|
||
bold: init(1, 22),
|
||
dim: init(2, 22),
|
||
italic: init(3, 23),
|
||
underline: init(4, 24),
|
||
inverse: init(7, 27),
|
||
hidden: init(8, 28),
|
||
strikethrough: init(9, 29),
|
||
|
||
// colors
|
||
black: init(30, 39),
|
||
red: init(31, 39),
|
||
green: init(32, 39),
|
||
yellow: init(33, 39),
|
||
blue: init(34, 39),
|
||
magenta: init(35, 39),
|
||
cyan: init(36, 39),
|
||
white: init(37, 39),
|
||
gray: init(90, 39),
|
||
grey: init(90, 39),
|
||
|
||
// background colors
|
||
bgBlack: init(40, 49),
|
||
bgRed: init(41, 49),
|
||
bgGreen: init(42, 49),
|
||
bgYellow: init(43, 49),
|
||
bgBlue: init(44, 49),
|
||
bgMagenta: init(45, 49),
|
||
bgCyan: init(46, 49),
|
||
bgWhite: init(47, 49)
|
||
};
|
||
|
||
function run(arr, str) {
|
||
let i=0, tmp, beg='', end='';
|
||
for (; i < arr.length; i++) {
|
||
tmp = arr[i];
|
||
beg += tmp.open;
|
||
end += tmp.close;
|
||
if (!!~str.indexOf(tmp.close)) {
|
||
str = str.replace(tmp.rgx, tmp.close + tmp.open);
|
||
}
|
||
}
|
||
return beg + str + end;
|
||
}
|
||
|
||
function chain(has, keys) {
|
||
let ctx = { has, keys };
|
||
|
||
ctx.reset = $.reset.bind(ctx);
|
||
ctx.bold = $.bold.bind(ctx);
|
||
ctx.dim = $.dim.bind(ctx);
|
||
ctx.italic = $.italic.bind(ctx);
|
||
ctx.underline = $.underline.bind(ctx);
|
||
ctx.inverse = $.inverse.bind(ctx);
|
||
ctx.hidden = $.hidden.bind(ctx);
|
||
ctx.strikethrough = $.strikethrough.bind(ctx);
|
||
|
||
ctx.black = $.black.bind(ctx);
|
||
ctx.red = $.red.bind(ctx);
|
||
ctx.green = $.green.bind(ctx);
|
||
ctx.yellow = $.yellow.bind(ctx);
|
||
ctx.blue = $.blue.bind(ctx);
|
||
ctx.magenta = $.magenta.bind(ctx);
|
||
ctx.cyan = $.cyan.bind(ctx);
|
||
ctx.white = $.white.bind(ctx);
|
||
ctx.gray = $.gray.bind(ctx);
|
||
ctx.grey = $.grey.bind(ctx);
|
||
|
||
ctx.bgBlack = $.bgBlack.bind(ctx);
|
||
ctx.bgRed = $.bgRed.bind(ctx);
|
||
ctx.bgGreen = $.bgGreen.bind(ctx);
|
||
ctx.bgYellow = $.bgYellow.bind(ctx);
|
||
ctx.bgBlue = $.bgBlue.bind(ctx);
|
||
ctx.bgMagenta = $.bgMagenta.bind(ctx);
|
||
ctx.bgCyan = $.bgCyan.bind(ctx);
|
||
ctx.bgWhite = $.bgWhite.bind(ctx);
|
||
|
||
return ctx;
|
||
}
|
||
|
||
function init(open, close) {
|
||
let blk = {
|
||
open: `\x1b[${open}m`,
|
||
close: `\x1b[${close}m`,
|
||
rgx: new RegExp(`\\x1b\\[${close}m`, 'g')
|
||
};
|
||
return function (txt) {
|
||
if (this !== void 0 && this.has !== void 0) {
|
||
!!~this.has.indexOf(open) || (this.has.push(open),this.keys.push(blk));
|
||
return txt === void 0 ? this : $.enabled ? run(this.keys, txt+'') : txt+'';
|
||
}
|
||
return txt === void 0 ? chain([open], [blk]) : $.enabled ? run([blk], txt+'') : txt+'';
|
||
};
|
||
}
|
||
|
||
kleur = $;
|
||
return kleur;
|
||
}
|
||
|
||
var action;
|
||
var hasRequiredAction;
|
||
|
||
function requireAction () {
|
||
if (hasRequiredAction) return action;
|
||
hasRequiredAction = 1;
|
||
|
||
action = (key, isSelect) => {
|
||
if (key.meta && key.name !== 'escape') return;
|
||
|
||
if (key.ctrl) {
|
||
if (key.name === 'a') return 'first';
|
||
if (key.name === 'c') return 'abort';
|
||
if (key.name === 'd') return 'abort';
|
||
if (key.name === 'e') return 'last';
|
||
if (key.name === 'g') return 'reset';
|
||
if (key.name === 'n') return 'down';
|
||
if (key.name === 'p') return 'up';
|
||
// avoid any non-ascii characters
|
||
return
|
||
}
|
||
|
||
if (isSelect) {
|
||
if (key.name === 'j') return 'down';
|
||
if (key.name === 'k') return 'up';
|
||
}
|
||
|
||
if (key.name === 'return') return 'submit';
|
||
if (key.name === 'enter') return 'submit'; // ctrl + J
|
||
if (key.name === 'backspace') return 'delete';
|
||
if (key.name === 'delete') return 'deleteForward';
|
||
if (key.name === 'abort') return 'abort';
|
||
if (key.name === 'escape') return 'exit';
|
||
// TODO: shift tab for prev
|
||
if (key.name === 'tab') return 'next';
|
||
if (key.name === 'pagedown') return 'nextPage';
|
||
if (key.name === 'pageup') return 'prevPage';
|
||
// TODO create home() in prompt types (e.g. TextPrompt)
|
||
if (key.name === 'home') return 'home';
|
||
// TODO create end() in prompt types (e.g. TextPrompt)
|
||
if (key.name === 'end') return 'end';
|
||
|
||
if (key.name === 'up') return 'up';
|
||
if (key.name === 'down') return 'down';
|
||
if (key.name === 'right') return 'right';
|
||
if (key.name === 'left') return 'left';
|
||
|
||
return false;
|
||
};
|
||
return action;
|
||
}
|
||
|
||
var strip;
|
||
var hasRequiredStrip;
|
||
|
||
function requireStrip () {
|
||
if (hasRequiredStrip) return strip;
|
||
hasRequiredStrip = 1;
|
||
|
||
strip = str => {
|
||
const pattern = [
|
||
'[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
|
||
'(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))'
|
||
].join('|');
|
||
|
||
const RGX = new RegExp(pattern, 'g');
|
||
return typeof str === 'string' ? str.replace(RGX, '') : str;
|
||
};
|
||
return strip;
|
||
}
|
||
|
||
var src;
|
||
var hasRequiredSrc;
|
||
|
||
function requireSrc () {
|
||
if (hasRequiredSrc) return src;
|
||
hasRequiredSrc = 1;
|
||
|
||
const ESC = '\x1B';
|
||
const CSI = `${ESC}[`;
|
||
const beep = '\u0007';
|
||
|
||
const cursor = {
|
||
to(x, y) {
|
||
if (!y) return `${CSI}${x + 1}G`;
|
||
return `${CSI}${y + 1};${x + 1}H`;
|
||
},
|
||
move(x, y) {
|
||
let ret = '';
|
||
|
||
if (x < 0) ret += `${CSI}${-x}D`;
|
||
else if (x > 0) ret += `${CSI}${x}C`;
|
||
|
||
if (y < 0) ret += `${CSI}${-y}A`;
|
||
else if (y > 0) ret += `${CSI}${y}B`;
|
||
|
||
return ret;
|
||
},
|
||
up: (count = 1) => `${CSI}${count}A`,
|
||
down: (count = 1) => `${CSI}${count}B`,
|
||
forward: (count = 1) => `${CSI}${count}C`,
|
||
backward: (count = 1) => `${CSI}${count}D`,
|
||
nextLine: (count = 1) => `${CSI}E`.repeat(count),
|
||
prevLine: (count = 1) => `${CSI}F`.repeat(count),
|
||
left: `${CSI}G`,
|
||
hide: `${CSI}?25l`,
|
||
show: `${CSI}?25h`,
|
||
save: `${ESC}7`,
|
||
restore: `${ESC}8`
|
||
};
|
||
|
||
const scroll = {
|
||
up: (count = 1) => `${CSI}S`.repeat(count),
|
||
down: (count = 1) => `${CSI}T`.repeat(count)
|
||
};
|
||
|
||
const erase = {
|
||
screen: `${CSI}2J`,
|
||
up: (count = 1) => `${CSI}1J`.repeat(count),
|
||
down: (count = 1) => `${CSI}J`.repeat(count),
|
||
line: `${CSI}2K`,
|
||
lineEnd: `${CSI}K`,
|
||
lineStart: `${CSI}1K`,
|
||
lines(count) {
|
||
let clear = '';
|
||
for (let i = 0; i < count; i++)
|
||
clear += this.line + (i < count - 1 ? cursor.up() : '');
|
||
if (count)
|
||
clear += cursor.left;
|
||
return clear;
|
||
}
|
||
};
|
||
|
||
src = { cursor, scroll, erase, beep };
|
||
return src;
|
||
}
|
||
|
||
var clear;
|
||
var hasRequiredClear;
|
||
|
||
function requireClear () {
|
||
if (hasRequiredClear) return clear;
|
||
hasRequiredClear = 1;
|
||
|
||
const strip = requireStrip();
|
||
const { erase, cursor } = requireSrc();
|
||
|
||
const width = str => [...strip(str)].length;
|
||
|
||
/**
|
||
* @param {string} prompt
|
||
* @param {number} perLine
|
||
*/
|
||
clear = function(prompt, perLine) {
|
||
if (!perLine) return erase.line + cursor.to(0);
|
||
|
||
let rows = 0;
|
||
const lines = prompt.split(/\r?\n/);
|
||
for (let line of lines) {
|
||
rows += 1 + Math.floor(Math.max(width(line) - 1, 0) / perLine);
|
||
}
|
||
|
||
return erase.lines(rows);
|
||
};
|
||
return clear;
|
||
}
|
||
|
||
var figures_1;
|
||
var hasRequiredFigures;
|
||
|
||
function requireFigures () {
|
||
if (hasRequiredFigures) return figures_1;
|
||
hasRequiredFigures = 1;
|
||
|
||
const main = {
|
||
arrowUp: '↑',
|
||
arrowDown: '↓',
|
||
arrowLeft: '←',
|
||
arrowRight: '→',
|
||
radioOn: '◉',
|
||
radioOff: '◯',
|
||
tick: '✔',
|
||
cross: '✖',
|
||
ellipsis: '…',
|
||
pointerSmall: '›',
|
||
line: '─',
|
||
pointer: '❯'
|
||
};
|
||
const win = {
|
||
arrowUp: main.arrowUp,
|
||
arrowDown: main.arrowDown,
|
||
arrowLeft: main.arrowLeft,
|
||
arrowRight: main.arrowRight,
|
||
radioOn: '(*)',
|
||
radioOff: '( )',
|
||
tick: '√',
|
||
cross: '×',
|
||
ellipsis: '...',
|
||
pointerSmall: '»',
|
||
line: '─',
|
||
pointer: '>'
|
||
};
|
||
const figures = process.platform === 'win32' ? win : main;
|
||
|
||
figures_1 = figures;
|
||
return figures_1;
|
||
}
|
||
|
||
var style;
|
||
var hasRequiredStyle;
|
||
|
||
function requireStyle () {
|
||
if (hasRequiredStyle) return style;
|
||
hasRequiredStyle = 1;
|
||
|
||
const c = requireKleur();
|
||
const figures = requireFigures();
|
||
|
||
// rendering user input.
|
||
const styles = Object.freeze({
|
||
password: { scale: 1, render: input => '*'.repeat(input.length) },
|
||
emoji: { scale: 2, render: input => '😃'.repeat(input.length) },
|
||
invisible: { scale: 0, render: input => '' },
|
||
default: { scale: 1, render: input => `${input}` }
|
||
});
|
||
const render = type => styles[type] || styles.default;
|
||
|
||
// icon to signalize a prompt.
|
||
const symbols = Object.freeze({
|
||
aborted: c.red(figures.cross),
|
||
done: c.green(figures.tick),
|
||
exited: c.yellow(figures.cross),
|
||
default: c.cyan('?')
|
||
});
|
||
|
||
const symbol = (done, aborted, exited) =>
|
||
aborted ? symbols.aborted : exited ? symbols.exited : done ? symbols.done : symbols.default;
|
||
|
||
// between the question and the user's input.
|
||
const delimiter = completing =>
|
||
c.gray(completing ? figures.ellipsis : figures.pointerSmall);
|
||
|
||
const item = (expandable, expanded) =>
|
||
c.gray(expandable ? (expanded ? figures.pointerSmall : '+') : figures.line);
|
||
|
||
style = {
|
||
styles,
|
||
render,
|
||
symbols,
|
||
symbol,
|
||
delimiter,
|
||
item
|
||
};
|
||
return style;
|
||
}
|
||
|
||
var lines;
|
||
var hasRequiredLines;
|
||
|
||
function requireLines () {
|
||
if (hasRequiredLines) return lines;
|
||
hasRequiredLines = 1;
|
||
|
||
const strip = requireStrip();
|
||
|
||
/**
|
||
* @param {string} msg
|
||
* @param {number} perLine
|
||
*/
|
||
lines = function (msg, perLine) {
|
||
let lines = String(strip(msg) || '').split(/\r?\n/);
|
||
|
||
if (!perLine) return lines.length;
|
||
return lines.map(l => Math.ceil(l.length / perLine))
|
||
.reduce((a, b) => a + b);
|
||
};
|
||
return lines;
|
||
}
|
||
|
||
var wrap;
|
||
var hasRequiredWrap;
|
||
|
||
function requireWrap () {
|
||
if (hasRequiredWrap) return wrap;
|
||
hasRequiredWrap = 1;
|
||
|
||
/**
|
||
* @param {string} msg The message to wrap
|
||
* @param {object} opts
|
||
* @param {number|string} [opts.margin] Left margin
|
||
* @param {number} opts.width Maximum characters per line including the margin
|
||
*/
|
||
wrap = (msg, opts = {}) => {
|
||
const tab = Number.isSafeInteger(parseInt(opts.margin))
|
||
? new Array(parseInt(opts.margin)).fill(' ').join('')
|
||
: (opts.margin || '');
|
||
|
||
const width = opts.width;
|
||
|
||
return (msg || '').split(/\r?\n/g)
|
||
.map(line => line
|
||
.split(/\s+/g)
|
||
.reduce((arr, w) => {
|
||
if (w.length + tab.length >= width || arr[arr.length - 1].length + w.length + 1 < width)
|
||
arr[arr.length - 1] += ` ${w}`;
|
||
else arr.push(`${tab}${w}`);
|
||
return arr;
|
||
}, [ tab ])
|
||
.join('\n'))
|
||
.join('\n');
|
||
};
|
||
return wrap;
|
||
}
|
||
|
||
var entriesToDisplay;
|
||
var hasRequiredEntriesToDisplay;
|
||
|
||
function requireEntriesToDisplay () {
|
||
if (hasRequiredEntriesToDisplay) return entriesToDisplay;
|
||
hasRequiredEntriesToDisplay = 1;
|
||
|
||
/**
|
||
* Determine what entries should be displayed on the screen, based on the
|
||
* currently selected index and the maximum visible. Used in list-based
|
||
* prompts like `select` and `multiselect`.
|
||
*
|
||
* @param {number} cursor the currently selected entry
|
||
* @param {number} total the total entries available to display
|
||
* @param {number} [maxVisible] the number of entries that can be displayed
|
||
*/
|
||
entriesToDisplay = (cursor, total, maxVisible) => {
|
||
maxVisible = maxVisible || total;
|
||
|
||
let startIndex = Math.min(total- maxVisible, cursor - Math.floor(maxVisible / 2));
|
||
if (startIndex < 0) startIndex = 0;
|
||
|
||
let endIndex = Math.min(startIndex + maxVisible, total);
|
||
|
||
return { startIndex, endIndex };
|
||
};
|
||
return entriesToDisplay;
|
||
}
|
||
|
||
var util;
|
||
var hasRequiredUtil;
|
||
|
||
function requireUtil () {
|
||
if (hasRequiredUtil) return util;
|
||
hasRequiredUtil = 1;
|
||
|
||
util = {
|
||
action: requireAction(),
|
||
clear: requireClear(),
|
||
style: requireStyle(),
|
||
strip: requireStrip(),
|
||
figures: requireFigures(),
|
||
lines: requireLines(),
|
||
wrap: requireWrap(),
|
||
entriesToDisplay: requireEntriesToDisplay()
|
||
};
|
||
return util;
|
||
}
|
||
|
||
var prompt;
|
||
var hasRequiredPrompt;
|
||
|
||
function requirePrompt () {
|
||
if (hasRequiredPrompt) return prompt;
|
||
hasRequiredPrompt = 1;
|
||
|
||
const readline = require$$0;
|
||
const { action } = requireUtil();
|
||
const EventEmitter = require$$2;
|
||
const { beep, cursor } = requireSrc();
|
||
const color = requireKleur();
|
||
|
||
/**
|
||
* Base prompt skeleton
|
||
* @param {Stream} [opts.stdin] The Readable stream to listen to
|
||
* @param {Stream} [opts.stdout] The Writable stream to write readline data to
|
||
*/
|
||
class Prompt extends EventEmitter {
|
||
constructor(opts={}) {
|
||
super();
|
||
|
||
this.firstRender = true;
|
||
this.in = opts.stdin || process.stdin;
|
||
this.out = opts.stdout || process.stdout;
|
||
this.onRender = (opts.onRender || (() => void 0)).bind(this);
|
||
const rl = readline.createInterface({ input:this.in, escapeCodeTimeout:50 });
|
||
readline.emitKeypressEvents(this.in, rl);
|
||
|
||
if (this.in.isTTY) this.in.setRawMode(true);
|
||
const isSelect = [ 'SelectPrompt', 'MultiselectPrompt' ].indexOf(this.constructor.name) > -1;
|
||
const keypress = (str, key) => {
|
||
let a = action(key, isSelect);
|
||
if (a === false) {
|
||
this._ && this._(str, key);
|
||
} else if (typeof this[a] === 'function') {
|
||
this[a](key);
|
||
} else {
|
||
this.bell();
|
||
}
|
||
};
|
||
|
||
this.close = () => {
|
||
this.out.write(cursor.show);
|
||
this.in.removeListener('keypress', keypress);
|
||
if (this.in.isTTY) this.in.setRawMode(false);
|
||
rl.close();
|
||
this.emit(this.aborted ? 'abort' : this.exited ? 'exit' : 'submit', this.value);
|
||
this.closed = true;
|
||
};
|
||
|
||
this.in.on('keypress', keypress);
|
||
}
|
||
|
||
fire() {
|
||
this.emit('state', {
|
||
value: this.value,
|
||
aborted: !!this.aborted,
|
||
exited: !!this.exited
|
||
});
|
||
}
|
||
|
||
bell() {
|
||
this.out.write(beep);
|
||
}
|
||
|
||
render() {
|
||
this.onRender(color);
|
||
if (this.firstRender) this.firstRender = false;
|
||
}
|
||
}
|
||
|
||
prompt = Prompt;
|
||
return prompt;
|
||
}
|
||
|
||
var text;
|
||
var hasRequiredText;
|
||
|
||
function requireText () {
|
||
if (hasRequiredText) return text;
|
||
hasRequiredText = 1;
|
||
const color = requireKleur();
|
||
const Prompt = requirePrompt();
|
||
const { erase, cursor } = requireSrc();
|
||
const { style, clear, lines, figures } = requireUtil();
|
||
|
||
/**
|
||
* TextPrompt Base Element
|
||
* @param {Object} opts Options
|
||
* @param {String} opts.message Message
|
||
* @param {String} [opts.style='default'] Render style
|
||
* @param {String} [opts.initial] Default value
|
||
* @param {Function} [opts.validate] Validate function
|
||
* @param {Stream} [opts.stdin] The Readable stream to listen to
|
||
* @param {Stream} [opts.stdout] The Writable stream to write readline data to
|
||
* @param {String} [opts.error] The invalid error label
|
||
*/
|
||
class TextPrompt extends Prompt {
|
||
constructor(opts={}) {
|
||
super(opts);
|
||
this.transform = style.render(opts.style);
|
||
this.scale = this.transform.scale;
|
||
this.msg = opts.message;
|
||
this.initial = opts.initial || ``;
|
||
this.validator = opts.validate || (() => true);
|
||
this.value = ``;
|
||
this.errorMsg = opts.error || `Please Enter A Valid Value`;
|
||
this.cursor = Number(!!this.initial);
|
||
this.cursorOffset = 0;
|
||
this.clear = clear(``, this.out.columns);
|
||
this.render();
|
||
}
|
||
|
||
set value(v) {
|
||
if (!v && this.initial) {
|
||
this.placeholder = true;
|
||
this.rendered = color.gray(this.transform.render(this.initial));
|
||
} else {
|
||
this.placeholder = false;
|
||
this.rendered = this.transform.render(v);
|
||
}
|
||
this._value = v;
|
||
this.fire();
|
||
}
|
||
|
||
get value() {
|
||
return this._value;
|
||
}
|
||
|
||
reset() {
|
||
this.value = ``;
|
||
this.cursor = Number(!!this.initial);
|
||
this.cursorOffset = 0;
|
||
this.fire();
|
||
this.render();
|
||
}
|
||
|
||
exit() {
|
||
this.abort();
|
||
}
|
||
|
||
abort() {
|
||
this.value = this.value || this.initial;
|
||
this.done = this.aborted = true;
|
||
this.error = false;
|
||
this.red = false;
|
||
this.fire();
|
||
this.render();
|
||
this.out.write('\n');
|
||
this.close();
|
||
}
|
||
|
||
async validate() {
|
||
let valid = await this.validator(this.value);
|
||
if (typeof valid === `string`) {
|
||
this.errorMsg = valid;
|
||
valid = false;
|
||
}
|
||
this.error = !valid;
|
||
}
|
||
|
||
async submit() {
|
||
this.value = this.value || this.initial;
|
||
this.cursorOffset = 0;
|
||
this.cursor = this.rendered.length;
|
||
await this.validate();
|
||
if (this.error) {
|
||
this.red = true;
|
||
this.fire();
|
||
this.render();
|
||
return;
|
||
}
|
||
this.done = true;
|
||
this.aborted = false;
|
||
this.fire();
|
||
this.render();
|
||
this.out.write('\n');
|
||
this.close();
|
||
}
|
||
|
||
next() {
|
||
if (!this.placeholder) return this.bell();
|
||
this.value = this.initial;
|
||
this.cursor = this.rendered.length;
|
||
this.fire();
|
||
this.render();
|
||
}
|
||
|
||
moveCursor(n) {
|
||
if (this.placeholder) return;
|
||
this.cursor = this.cursor+n;
|
||
this.cursorOffset += n;
|
||
}
|
||
|
||
_(c, key) {
|
||
let s1 = this.value.slice(0, this.cursor);
|
||
let s2 = this.value.slice(this.cursor);
|
||
this.value = `${s1}${c}${s2}`;
|
||
this.red = false;
|
||
this.cursor = this.placeholder ? 0 : s1.length+1;
|
||
this.render();
|
||
}
|
||
|
||
delete() {
|
||
if (this.isCursorAtStart()) return this.bell();
|
||
let s1 = this.value.slice(0, this.cursor-1);
|
||
let s2 = this.value.slice(this.cursor);
|
||
this.value = `${s1}${s2}`;
|
||
this.red = false;
|
||
if (this.isCursorAtStart()) {
|
||
this.cursorOffset = 0;
|
||
} else {
|
||
this.cursorOffset++;
|
||
this.moveCursor(-1);
|
||
}
|
||
this.render();
|
||
}
|
||
|
||
deleteForward() {
|
||
if(this.cursor*this.scale >= this.rendered.length || this.placeholder) return this.bell();
|
||
let s1 = this.value.slice(0, this.cursor);
|
||
let s2 = this.value.slice(this.cursor+1);
|
||
this.value = `${s1}${s2}`;
|
||
this.red = false;
|
||
if (this.isCursorAtEnd()) {
|
||
this.cursorOffset = 0;
|
||
} else {
|
||
this.cursorOffset++;
|
||
}
|
||
this.render();
|
||
}
|
||
|
||
first() {
|
||
this.cursor = 0;
|
||
this.render();
|
||
}
|
||
|
||
last() {
|
||
this.cursor = this.value.length;
|
||
this.render();
|
||
}
|
||
|
||
left() {
|
||
if (this.cursor <= 0 || this.placeholder) return this.bell();
|
||
this.moveCursor(-1);
|
||
this.render();
|
||
}
|
||
|
||
right() {
|
||
if (this.cursor*this.scale >= this.rendered.length || this.placeholder) return this.bell();
|
||
this.moveCursor(1);
|
||
this.render();
|
||
}
|
||
|
||
isCursorAtStart() {
|
||
return this.cursor === 0 || (this.placeholder && this.cursor === 1);
|
||
}
|
||
|
||
isCursorAtEnd() {
|
||
return this.cursor === this.rendered.length || (this.placeholder && this.cursor === this.rendered.length + 1)
|
||
}
|
||
|
||
render() {
|
||
if (this.closed) return;
|
||
if (!this.firstRender) {
|
||
if (this.outputError)
|
||
this.out.write(cursor.down(lines(this.outputError, this.out.columns) - 1) + clear(this.outputError, this.out.columns));
|
||
this.out.write(clear(this.outputText, this.out.columns));
|
||
}
|
||
super.render();
|
||
this.outputError = '';
|
||
|
||
this.outputText = [
|
||
style.symbol(this.done, this.aborted),
|
||
color.bold(this.msg),
|
||
style.delimiter(this.done),
|
||
this.red ? color.red(this.rendered) : this.rendered
|
||
].join(` `);
|
||
|
||
if (this.error) {
|
||
this.outputError += this.errorMsg.split(`\n`)
|
||
.reduce((a, l, i) => a + `\n${i ? ' ' : figures.pointerSmall} ${color.red().italic(l)}`, ``);
|
||
}
|
||
|
||
this.out.write(erase.line + cursor.to(0) + this.outputText + cursor.save + this.outputError + cursor.restore + cursor.move(this.cursorOffset, 0));
|
||
}
|
||
}
|
||
|
||
text = TextPrompt;
|
||
return text;
|
||
}
|
||
|
||
var select;
|
||
var hasRequiredSelect;
|
||
|
||
function requireSelect () {
|
||
if (hasRequiredSelect) return select;
|
||
hasRequiredSelect = 1;
|
||
|
||
const color = requireKleur();
|
||
const Prompt = requirePrompt();
|
||
const { style, clear, figures, wrap, entriesToDisplay } = requireUtil();
|
||
const { cursor } = requireSrc();
|
||
|
||
/**
|
||
* SelectPrompt Base Element
|
||
* @param {Object} opts Options
|
||
* @param {String} opts.message Message
|
||
* @param {Array} opts.choices Array of choice objects
|
||
* @param {String} [opts.hint] Hint to display
|
||
* @param {Number} [opts.initial] Index of default value
|
||
* @param {Stream} [opts.stdin] The Readable stream to listen to
|
||
* @param {Stream} [opts.stdout] The Writable stream to write readline data to
|
||
* @param {Number} [opts.optionsPerPage=10] Max options to display at once
|
||
*/
|
||
class SelectPrompt extends Prompt {
|
||
constructor(opts={}) {
|
||
super(opts);
|
||
this.msg = opts.message;
|
||
this.hint = opts.hint || '- Use arrow-keys. Return to submit.';
|
||
this.warn = opts.warn || '- This option is disabled';
|
||
this.cursor = opts.initial || 0;
|
||
this.choices = opts.choices.map((ch, idx) => {
|
||
if (typeof ch === 'string')
|
||
ch = {title: ch, value: idx};
|
||
return {
|
||
title: ch && (ch.title || ch.value || ch),
|
||
value: ch && (ch.value === undefined ? idx : ch.value),
|
||
description: ch && ch.description,
|
||
selected: ch && ch.selected,
|
||
disabled: ch && ch.disabled
|
||
};
|
||
});
|
||
this.optionsPerPage = opts.optionsPerPage || 10;
|
||
this.value = (this.choices[this.cursor] || {}).value;
|
||
this.clear = clear('', this.out.columns);
|
||
this.render();
|
||
}
|
||
|
||
moveCursor(n) {
|
||
this.cursor = n;
|
||
this.value = this.choices[n].value;
|
||
this.fire();
|
||
}
|
||
|
||
reset() {
|
||
this.moveCursor(0);
|
||
this.fire();
|
||
this.render();
|
||
}
|
||
|
||
exit() {
|
||
this.abort();
|
||
}
|
||
|
||
abort() {
|
||
this.done = this.aborted = true;
|
||
this.fire();
|
||
this.render();
|
||
this.out.write('\n');
|
||
this.close();
|
||
}
|
||
|
||
submit() {
|
||
if (!this.selection.disabled) {
|
||
this.done = true;
|
||
this.aborted = false;
|
||
this.fire();
|
||
this.render();
|
||
this.out.write('\n');
|
||
this.close();
|
||
} else
|
||
this.bell();
|
||
}
|
||
|
||
first() {
|
||
this.moveCursor(0);
|
||
this.render();
|
||
}
|
||
|
||
last() {
|
||
this.moveCursor(this.choices.length - 1);
|
||
this.render();
|
||
}
|
||
|
||
up() {
|
||
if (this.cursor === 0) {
|
||
this.moveCursor(this.choices.length - 1);
|
||
} else {
|
||
this.moveCursor(this.cursor - 1);
|
||
}
|
||
this.render();
|
||
}
|
||
|
||
down() {
|
||
if (this.cursor === this.choices.length - 1) {
|
||
this.moveCursor(0);
|
||
} else {
|
||
this.moveCursor(this.cursor + 1);
|
||
}
|
||
this.render();
|
||
}
|
||
|
||
next() {
|
||
this.moveCursor((this.cursor + 1) % this.choices.length);
|
||
this.render();
|
||
}
|
||
|
||
_(c, key) {
|
||
if (c === ' ') return this.submit();
|
||
}
|
||
|
||
get selection() {
|
||
return this.choices[this.cursor];
|
||
}
|
||
|
||
render() {
|
||
if (this.closed) return;
|
||
if (this.firstRender) this.out.write(cursor.hide);
|
||
else this.out.write(clear(this.outputText, this.out.columns));
|
||
super.render();
|
||
|
||
let { startIndex, endIndex } = entriesToDisplay(this.cursor, this.choices.length, this.optionsPerPage);
|
||
|
||
// Print prompt
|
||
this.outputText = [
|
||
style.symbol(this.done, this.aborted),
|
||
color.bold(this.msg),
|
||
style.delimiter(false),
|
||
this.done ? this.selection.title : this.selection.disabled
|
||
? color.yellow(this.warn) : color.gray(this.hint)
|
||
].join(' ');
|
||
|
||
// Print choices
|
||
if (!this.done) {
|
||
this.outputText += '\n';
|
||
for (let i = startIndex; i < endIndex; i++) {
|
||
let title, prefix, desc = '', v = this.choices[i];
|
||
|
||
// Determine whether to display "more choices" indicators
|
||
if (i === startIndex && startIndex > 0) {
|
||
prefix = figures.arrowUp;
|
||
} else if (i === endIndex - 1 && endIndex < this.choices.length) {
|
||
prefix = figures.arrowDown;
|
||
} else {
|
||
prefix = ' ';
|
||
}
|
||
|
||
if (v.disabled) {
|
||
title = this.cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title);
|
||
prefix = (this.cursor === i ? color.bold().gray(figures.pointer) + ' ' : ' ') + prefix;
|
||
} else {
|
||
title = this.cursor === i ? color.cyan().underline(v.title) : v.title;
|
||
prefix = (this.cursor === i ? color.cyan(figures.pointer) + ' ' : ' ') + prefix;
|
||
if (v.description && this.cursor === i) {
|
||
desc = ` - ${v.description}`;
|
||
if (prefix.length + title.length + desc.length >= this.out.columns
|
||
|| v.description.split(/\r?\n/).length > 1) {
|
||
desc = '\n' + wrap(v.description, { margin: 3, width: this.out.columns });
|
||
}
|
||
}
|
||
}
|
||
|
||
this.outputText += `${prefix} ${title}${color.gray(desc)}\n`;
|
||
}
|
||
}
|
||
|
||
this.out.write(this.outputText);
|
||
}
|
||
}
|
||
|
||
select = SelectPrompt;
|
||
return select;
|
||
}
|
||
|
||
var toggle;
|
||
var hasRequiredToggle;
|
||
|
||
function requireToggle () {
|
||
if (hasRequiredToggle) return toggle;
|
||
hasRequiredToggle = 1;
|
||
const color = requireKleur();
|
||
const Prompt = requirePrompt();
|
||
const { style, clear } = requireUtil();
|
||
const { cursor, erase } = requireSrc();
|
||
|
||
/**
|
||
* TogglePrompt Base Element
|
||
* @param {Object} opts Options
|
||
* @param {String} opts.message Message
|
||
* @param {Boolean} [opts.initial=false] Default value
|
||
* @param {String} [opts.active='no'] Active label
|
||
* @param {String} [opts.inactive='off'] Inactive label
|
||
* @param {Stream} [opts.stdin] The Readable stream to listen to
|
||
* @param {Stream} [opts.stdout] The Writable stream to write readline data to
|
||
*/
|
||
class TogglePrompt extends Prompt {
|
||
constructor(opts={}) {
|
||
super(opts);
|
||
this.msg = opts.message;
|
||
this.value = !!opts.initial;
|
||
this.active = opts.active || 'on';
|
||
this.inactive = opts.inactive || 'off';
|
||
this.initialValue = this.value;
|
||
this.render();
|
||
}
|
||
|
||
reset() {
|
||
this.value = this.initialValue;
|
||
this.fire();
|
||
this.render();
|
||
}
|
||
|
||
exit() {
|
||
this.abort();
|
||
}
|
||
|
||
abort() {
|
||
this.done = this.aborted = true;
|
||
this.fire();
|
||
this.render();
|
||
this.out.write('\n');
|
||
this.close();
|
||
}
|
||
|
||
submit() {
|
||
this.done = true;
|
||
this.aborted = false;
|
||
this.fire();
|
||
this.render();
|
||
this.out.write('\n');
|
||
this.close();
|
||
}
|
||
|
||
deactivate() {
|
||
if (this.value === false) return this.bell();
|
||
this.value = false;
|
||
this.render();
|
||
}
|
||
|
||
activate() {
|
||
if (this.value === true) return this.bell();
|
||
this.value = true;
|
||
this.render();
|
||
}
|
||
|
||
delete() {
|
||
this.deactivate();
|
||
}
|
||
left() {
|
||
this.deactivate();
|
||
}
|
||
right() {
|
||
this.activate();
|
||
}
|
||
down() {
|
||
this.deactivate();
|
||
}
|
||
up() {
|
||
this.activate();
|
||
}
|
||
|
||
next() {
|
||
this.value = !this.value;
|
||
this.fire();
|
||
this.render();
|
||
}
|
||
|
||
_(c, key) {
|
||
if (c === ' ') {
|
||
this.value = !this.value;
|
||
} else if (c === '1') {
|
||
this.value = true;
|
||
} else if (c === '0') {
|
||
this.value = false;
|
||
} else return this.bell();
|
||
this.render();
|
||
}
|
||
|
||
render() {
|
||
if (this.closed) return;
|
||
if (this.firstRender) this.out.write(cursor.hide);
|
||
else this.out.write(clear(this.outputText, this.out.columns));
|
||
super.render();
|
||
|
||
this.outputText = [
|
||
style.symbol(this.done, this.aborted),
|
||
color.bold(this.msg),
|
||
style.delimiter(this.done),
|
||
this.value ? this.inactive : color.cyan().underline(this.inactive),
|
||
color.gray('/'),
|
||
this.value ? color.cyan().underline(this.active) : this.active
|
||
].join(' ');
|
||
|
||
this.out.write(erase.line + cursor.to(0) + this.outputText);
|
||
}
|
||
}
|
||
|
||
toggle = TogglePrompt;
|
||
return toggle;
|
||
}
|
||
|
||
var datepart;
|
||
var hasRequiredDatepart;
|
||
|
||
function requireDatepart () {
|
||
if (hasRequiredDatepart) return datepart;
|
||
hasRequiredDatepart = 1;
|
||
|
||
class DatePart {
|
||
constructor({token, date, parts, locales}) {
|
||
this.token = token;
|
||
this.date = date || new Date();
|
||
this.parts = parts || [this];
|
||
this.locales = locales || {};
|
||
}
|
||
|
||
up() {}
|
||
|
||
down() {}
|
||
|
||
next() {
|
||
const currentIdx = this.parts.indexOf(this);
|
||
return this.parts.find((part, idx) => idx > currentIdx && part instanceof DatePart);
|
||
}
|
||
|
||
setTo(val) {}
|
||
|
||
prev() {
|
||
let parts = [].concat(this.parts).reverse();
|
||
const currentIdx = parts.indexOf(this);
|
||
return parts.find((part, idx) => idx > currentIdx && part instanceof DatePart);
|
||
}
|
||
|
||
toString() {
|
||
return String(this.date);
|
||
}
|
||
}
|
||
|
||
datepart = DatePart;
|
||
return datepart;
|
||
}
|
||
|
||
var meridiem;
|
||
var hasRequiredMeridiem;
|
||
|
||
function requireMeridiem () {
|
||
if (hasRequiredMeridiem) return meridiem;
|
||
hasRequiredMeridiem = 1;
|
||
|
||
const DatePart = requireDatepart();
|
||
|
||
class Meridiem extends DatePart {
|
||
constructor(opts={}) {
|
||
super(opts);
|
||
}
|
||
|
||
up() {
|
||
this.date.setHours((this.date.getHours() + 12) % 24);
|
||
}
|
||
|
||
down() {
|
||
this.up();
|
||
}
|
||
|
||
toString() {
|
||
let meridiem = this.date.getHours() > 12 ? 'pm' : 'am';
|
||
return /\A/.test(this.token) ? meridiem.toUpperCase() : meridiem;
|
||
}
|
||
}
|
||
|
||
meridiem = Meridiem;
|
||
return meridiem;
|
||
}
|
||
|
||
var day;
|
||
var hasRequiredDay;
|
||
|
||
function requireDay () {
|
||
if (hasRequiredDay) return day;
|
||
hasRequiredDay = 1;
|
||
|
||
const DatePart = requireDatepart();
|
||
|
||
const pos = n => {
|
||
n = n % 10;
|
||
return n === 1 ? 'st'
|
||
: n === 2 ? 'nd'
|
||
: n === 3 ? 'rd'
|
||
: 'th';
|
||
};
|
||
|
||
class Day extends DatePart {
|
||
constructor(opts={}) {
|
||
super(opts);
|
||
}
|
||
|
||
up() {
|
||
this.date.setDate(this.date.getDate() + 1);
|
||
}
|
||
|
||
down() {
|
||
this.date.setDate(this.date.getDate() - 1);
|
||
}
|
||
|
||
setTo(val) {
|
||
this.date.setDate(parseInt(val.substr(-2)));
|
||
}
|
||
|
||
toString() {
|
||
let date = this.date.getDate();
|
||
let day = this.date.getDay();
|
||
return this.token === 'DD' ? String(date).padStart(2, '0')
|
||
: this.token === 'Do' ? date + pos(date)
|
||
: this.token === 'd' ? day + 1
|
||
: this.token === 'ddd' ? this.locales.weekdaysShort[day]
|
||
: this.token === 'dddd' ? this.locales.weekdays[day]
|
||
: date;
|
||
}
|
||
}
|
||
|
||
day = Day;
|
||
return day;
|
||
}
|
||
|
||
var hours;
|
||
var hasRequiredHours;
|
||
|
||
function requireHours () {
|
||
if (hasRequiredHours) return hours;
|
||
hasRequiredHours = 1;
|
||
|
||
const DatePart = requireDatepart();
|
||
|
||
class Hours extends DatePart {
|
||
constructor(opts={}) {
|
||
super(opts);
|
||
}
|
||
|
||
up() {
|
||
this.date.setHours(this.date.getHours() + 1);
|
||
}
|
||
|
||
down() {
|
||
this.date.setHours(this.date.getHours() - 1);
|
||
}
|
||
|
||
setTo(val) {
|
||
this.date.setHours(parseInt(val.substr(-2)));
|
||
}
|
||
|
||
toString() {
|
||
let hours = this.date.getHours();
|
||
if (/h/.test(this.token))
|
||
hours = (hours % 12) || 12;
|
||
return this.token.length > 1 ? String(hours).padStart(2, '0') : hours;
|
||
}
|
||
}
|
||
|
||
hours = Hours;
|
||
return hours;
|
||
}
|
||
|
||
var milliseconds;
|
||
var hasRequiredMilliseconds;
|
||
|
||
function requireMilliseconds () {
|
||
if (hasRequiredMilliseconds) return milliseconds;
|
||
hasRequiredMilliseconds = 1;
|
||
|
||
const DatePart = requireDatepart();
|
||
|
||
class Milliseconds extends DatePart {
|
||
constructor(opts={}) {
|
||
super(opts);
|
||
}
|
||
|
||
up() {
|
||
this.date.setMilliseconds(this.date.getMilliseconds() + 1);
|
||
}
|
||
|
||
down() {
|
||
this.date.setMilliseconds(this.date.getMilliseconds() - 1);
|
||
}
|
||
|
||
setTo(val) {
|
||
this.date.setMilliseconds(parseInt(val.substr(-(this.token.length))));
|
||
}
|
||
|
||
toString() {
|
||
return String(this.date.getMilliseconds()).padStart(4, '0')
|
||
.substr(0, this.token.length);
|
||
}
|
||
}
|
||
|
||
milliseconds = Milliseconds;
|
||
return milliseconds;
|
||
}
|
||
|
||
var minutes;
|
||
var hasRequiredMinutes;
|
||
|
||
function requireMinutes () {
|
||
if (hasRequiredMinutes) return minutes;
|
||
hasRequiredMinutes = 1;
|
||
|
||
const DatePart = requireDatepart();
|
||
|
||
class Minutes extends DatePart {
|
||
constructor(opts={}) {
|
||
super(opts);
|
||
}
|
||
|
||
up() {
|
||
this.date.setMinutes(this.date.getMinutes() + 1);
|
||
}
|
||
|
||
down() {
|
||
this.date.setMinutes(this.date.getMinutes() - 1);
|
||
}
|
||
|
||
setTo(val) {
|
||
this.date.setMinutes(parseInt(val.substr(-2)));
|
||
}
|
||
|
||
toString() {
|
||
let m = this.date.getMinutes();
|
||
return this.token.length > 1 ? String(m).padStart(2, '0') : m;
|
||
}
|
||
}
|
||
|
||
minutes = Minutes;
|
||
return minutes;
|
||
}
|
||
|
||
var month;
|
||
var hasRequiredMonth;
|
||
|
||
function requireMonth () {
|
||
if (hasRequiredMonth) return month;
|
||
hasRequiredMonth = 1;
|
||
|
||
const DatePart = requireDatepart();
|
||
|
||
class Month extends DatePart {
|
||
constructor(opts={}) {
|
||
super(opts);
|
||
}
|
||
|
||
up() {
|
||
this.date.setMonth(this.date.getMonth() + 1);
|
||
}
|
||
|
||
down() {
|
||
this.date.setMonth(this.date.getMonth() - 1);
|
||
}
|
||
|
||
setTo(val) {
|
||
val = parseInt(val.substr(-2)) - 1;
|
||
this.date.setMonth(val < 0 ? 0 : val);
|
||
}
|
||
|
||
toString() {
|
||
let month = this.date.getMonth();
|
||
let tl = this.token.length;
|
||
return tl === 2 ? String(month + 1).padStart(2, '0')
|
||
: tl === 3 ? this.locales.monthsShort[month]
|
||
: tl === 4 ? this.locales.months[month]
|
||
: String(month + 1);
|
||
}
|
||
}
|
||
|
||
month = Month;
|
||
return month;
|
||
}
|
||
|
||
var seconds;
|
||
var hasRequiredSeconds;
|
||
|
||
function requireSeconds () {
|
||
if (hasRequiredSeconds) return seconds;
|
||
hasRequiredSeconds = 1;
|
||
|
||
const DatePart = requireDatepart();
|
||
|
||
class Seconds extends DatePart {
|
||
constructor(opts={}) {
|
||
super(opts);
|
||
}
|
||
|
||
up() {
|
||
this.date.setSeconds(this.date.getSeconds() + 1);
|
||
}
|
||
|
||
down() {
|
||
this.date.setSeconds(this.date.getSeconds() - 1);
|
||
}
|
||
|
||
setTo(val) {
|
||
this.date.setSeconds(parseInt(val.substr(-2)));
|
||
}
|
||
|
||
toString() {
|
||
let s = this.date.getSeconds();
|
||
return this.token.length > 1 ? String(s).padStart(2, '0') : s;
|
||
}
|
||
}
|
||
|
||
seconds = Seconds;
|
||
return seconds;
|
||
}
|
||
|
||
var year;
|
||
var hasRequiredYear;
|
||
|
||
function requireYear () {
|
||
if (hasRequiredYear) return year;
|
||
hasRequiredYear = 1;
|
||
|
||
const DatePart = requireDatepart();
|
||
|
||
class Year extends DatePart {
|
||
constructor(opts={}) {
|
||
super(opts);
|
||
}
|
||
|
||
up() {
|
||
this.date.setFullYear(this.date.getFullYear() + 1);
|
||
}
|
||
|
||
down() {
|
||
this.date.setFullYear(this.date.getFullYear() - 1);
|
||
}
|
||
|
||
setTo(val) {
|
||
this.date.setFullYear(val.substr(-4));
|
||
}
|
||
|
||
toString() {
|
||
let year = String(this.date.getFullYear()).padStart(4, '0');
|
||
return this.token.length === 2 ? year.substr(-2) : year;
|
||
}
|
||
}
|
||
|
||
year = Year;
|
||
return year;
|
||
}
|
||
|
||
var dateparts;
|
||
var hasRequiredDateparts;
|
||
|
||
function requireDateparts () {
|
||
if (hasRequiredDateparts) return dateparts;
|
||
hasRequiredDateparts = 1;
|
||
|
||
dateparts = {
|
||
DatePart: requireDatepart(),
|
||
Meridiem: requireMeridiem(),
|
||
Day: requireDay(),
|
||
Hours: requireHours(),
|
||
Milliseconds: requireMilliseconds(),
|
||
Minutes: requireMinutes(),
|
||
Month: requireMonth(),
|
||
Seconds: requireSeconds(),
|
||
Year: requireYear(),
|
||
};
|
||
return dateparts;
|
||
}
|
||
|
||
var date;
|
||
var hasRequiredDate;
|
||
|
||
function requireDate () {
|
||
if (hasRequiredDate) return date;
|
||
hasRequiredDate = 1;
|
||
|
||
const color = requireKleur();
|
||
const Prompt = requirePrompt();
|
||
const { style, clear, figures } = requireUtil();
|
||
const { erase, cursor } = requireSrc();
|
||
const { DatePart, Meridiem, Day, Hours, Milliseconds, Minutes, Month, Seconds, Year } = requireDateparts();
|
||
|
||
const regex = /\\(.)|"((?:\\["\\]|[^"])+)"|(D[Do]?|d{3,4}|d)|(M{1,4})|(YY(?:YY)?)|([aA])|([Hh]{1,2})|(m{1,2})|(s{1,2})|(S{1,4})|./g;
|
||
const regexGroups = {
|
||
1: ({token}) => token.replace(/\\(.)/g, '$1'),
|
||
2: (opts) => new Day(opts), // Day // TODO
|
||
3: (opts) => new Month(opts), // Month
|
||
4: (opts) => new Year(opts), // Year
|
||
5: (opts) => new Meridiem(opts), // AM/PM // TODO (special)
|
||
6: (opts) => new Hours(opts), // Hours
|
||
7: (opts) => new Minutes(opts), // Minutes
|
||
8: (opts) => new Seconds(opts), // Seconds
|
||
9: (opts) => new Milliseconds(opts), // Fractional seconds
|
||
};
|
||
|
||
const dfltLocales = {
|
||
months: 'January,February,March,April,May,June,July,August,September,October,November,December'.split(','),
|
||
monthsShort: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
|
||
weekdays: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
|
||
weekdaysShort: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(',')
|
||
};
|
||
|
||
|
||
/**
|
||
* DatePrompt Base Element
|
||
* @param {Object} opts Options
|
||
* @param {String} opts.message Message
|
||
* @param {Number} [opts.initial] Index of default value
|
||
* @param {String} [opts.mask] The format mask
|
||
* @param {object} [opts.locales] The date locales
|
||
* @param {String} [opts.error] The error message shown on invalid value
|
||
* @param {Function} [opts.validate] Function to validate the submitted value
|
||
* @param {Stream} [opts.stdin] The Readable stream to listen to
|
||
* @param {Stream} [opts.stdout] The Writable stream to write readline data to
|
||
*/
|
||
class DatePrompt extends Prompt {
|
||
constructor(opts={}) {
|
||
super(opts);
|
||
this.msg = opts.message;
|
||
this.cursor = 0;
|
||
this.typed = '';
|
||
this.locales = Object.assign(dfltLocales, opts.locales);
|
||
this._date = opts.initial || new Date();
|
||
this.errorMsg = opts.error || 'Please Enter A Valid Value';
|
||
this.validator = opts.validate || (() => true);
|
||
this.mask = opts.mask || 'YYYY-MM-DD HH:mm:ss';
|
||
this.clear = clear('', this.out.columns);
|
||
this.render();
|
||
}
|
||
|
||
get value() {
|
||
return this.date
|
||
}
|
||
|
||
get date() {
|
||
return this._date;
|
||
}
|
||
|
||
set date(date) {
|
||
if (date) this._date.setTime(date.getTime());
|
||
}
|
||
|
||
set mask(mask) {
|
||
let result;
|
||
this.parts = [];
|
||
while(result = regex.exec(mask)) {
|
||
let match = result.shift();
|
||
let idx = result.findIndex(gr => gr != null);
|
||
this.parts.push(idx in regexGroups
|
||
? regexGroups[idx]({ token: result[idx] || match, date: this.date, parts: this.parts, locales: this.locales })
|
||
: result[idx] || match);
|
||
}
|
||
|
||
let parts = this.parts.reduce((arr, i) => {
|
||
if (typeof i === 'string' && typeof arr[arr.length - 1] === 'string')
|
||
arr[arr.length - 1] += i;
|
||
else arr.push(i);
|
||
return arr;
|
||
}, []);
|
||
|
||
this.parts.splice(0);
|
||
this.parts.push(...parts);
|
||
this.reset();
|
||
}
|
||
|
||
moveCursor(n) {
|
||
this.typed = '';
|
||
this.cursor = n;
|
||
this.fire();
|
||
}
|
||
|
||
reset() {
|
||
this.moveCursor(this.parts.findIndex(p => p instanceof DatePart));
|
||
this.fire();
|
||
this.render();
|
||
}
|
||
|
||
exit() {
|
||
this.abort();
|
||
}
|
||
|
||
abort() {
|
||
this.done = this.aborted = true;
|
||
this.error = false;
|
||
this.fire();
|
||
this.render();
|
||
this.out.write('\n');
|
||
this.close();
|
||
}
|
||
|
||
async validate() {
|
||
let valid = await this.validator(this.value);
|
||
if (typeof valid === 'string') {
|
||
this.errorMsg = valid;
|
||
valid = false;
|
||
}
|
||
this.error = !valid;
|
||
}
|
||
|
||
async submit() {
|
||
await this.validate();
|
||
if (this.error) {
|
||
this.color = 'red';
|
||
this.fire();
|
||
this.render();
|
||
return;
|
||
}
|
||
this.done = true;
|
||
this.aborted = false;
|
||
this.fire();
|
||
this.render();
|
||
this.out.write('\n');
|
||
this.close();
|
||
}
|
||
|
||
up() {
|
||
this.typed = '';
|
||
this.parts[this.cursor].up();
|
||
this.render();
|
||
}
|
||
|
||
down() {
|
||
this.typed = '';
|
||
this.parts[this.cursor].down();
|
||
this.render();
|
||
}
|
||
|
||
left() {
|
||
let prev = this.parts[this.cursor].prev();
|
||
if (prev == null) return this.bell();
|
||
this.moveCursor(this.parts.indexOf(prev));
|
||
this.render();
|
||
}
|
||
|
||
right() {
|
||
let next = this.parts[this.cursor].next();
|
||
if (next == null) return this.bell();
|
||
this.moveCursor(this.parts.indexOf(next));
|
||
this.render();
|
||
}
|
||
|
||
next() {
|
||
let next = this.parts[this.cursor].next();
|
||
this.moveCursor(next
|
||
? this.parts.indexOf(next)
|
||
: this.parts.findIndex((part) => part instanceof DatePart));
|
||
this.render();
|
||
}
|
||
|
||
_(c) {
|
||
if (/\d/.test(c)) {
|
||
this.typed += c;
|
||
this.parts[this.cursor].setTo(this.typed);
|
||
this.render();
|
||
}
|
||
}
|
||
|
||
render() {
|
||
if (this.closed) return;
|
||
if (this.firstRender) this.out.write(cursor.hide);
|
||
else this.out.write(clear(this.outputText, this.out.columns));
|
||
super.render();
|
||
|
||
// Print prompt
|
||
this.outputText = [
|
||
style.symbol(this.done, this.aborted),
|
||
color.bold(this.msg),
|
||
style.delimiter(false),
|
||
this.parts.reduce((arr, p, idx) => arr.concat(idx === this.cursor && !this.done ? color.cyan().underline(p.toString()) : p), [])
|
||
.join('')
|
||
].join(' ');
|
||
|
||
// Print error
|
||
if (this.error) {
|
||
this.outputText += this.errorMsg.split('\n').reduce(
|
||
(a, l, i) => a + `\n${i ? ` ` : figures.pointerSmall} ${color.red().italic(l)}`, ``);
|
||
}
|
||
|
||
this.out.write(erase.line + cursor.to(0) + this.outputText);
|
||
}
|
||
}
|
||
|
||
date = DatePrompt;
|
||
return date;
|
||
}
|
||
|
||
var number;
|
||
var hasRequiredNumber;
|
||
|
||
function requireNumber () {
|
||
if (hasRequiredNumber) return number;
|
||
hasRequiredNumber = 1;
|
||
const color = requireKleur();
|
||
const Prompt = requirePrompt();
|
||
const { cursor, erase } = requireSrc();
|
||
const { style, figures, clear, lines } = requireUtil();
|
||
|
||
const isNumber = /[0-9]/;
|
||
const isDef = any => any !== undefined;
|
||
const round = (number, precision) => {
|
||
let factor = Math.pow(10, precision);
|
||
return Math.round(number * factor) / factor;
|
||
};
|
||
|
||
/**
|
||
* NumberPrompt Base Element
|
||
* @param {Object} opts Options
|
||
* @param {String} opts.message Message
|
||
* @param {String} [opts.style='default'] Render style
|
||
* @param {Number} [opts.initial] Default value
|
||
* @param {Number} [opts.max=+Infinity] Max value
|
||
* @param {Number} [opts.min=-Infinity] Min value
|
||
* @param {Boolean} [opts.float=false] Parse input as floats
|
||
* @param {Number} [opts.round=2] Round floats to x decimals
|
||
* @param {Number} [opts.increment=1] Number to increment by when using arrow-keys
|
||
* @param {Function} [opts.validate] Validate function
|
||
* @param {Stream} [opts.stdin] The Readable stream to listen to
|
||
* @param {Stream} [opts.stdout] The Writable stream to write readline data to
|
||
* @param {String} [opts.error] The invalid error label
|
||
*/
|
||
class NumberPrompt extends Prompt {
|
||
constructor(opts={}) {
|
||
super(opts);
|
||
this.transform = style.render(opts.style);
|
||
this.msg = opts.message;
|
||
this.initial = isDef(opts.initial) ? opts.initial : '';
|
||
this.float = !!opts.float;
|
||
this.round = opts.round || 2;
|
||
this.inc = opts.increment || 1;
|
||
this.min = isDef(opts.min) ? opts.min : -Infinity;
|
||
this.max = isDef(opts.max) ? opts.max : Infinity;
|
||
this.errorMsg = opts.error || `Please Enter A Valid Value`;
|
||
this.validator = opts.validate || (() => true);
|
||
this.color = `cyan`;
|
||
this.value = ``;
|
||
this.typed = ``;
|
||
this.lastHit = 0;
|
||
this.render();
|
||
}
|
||
|
||
set value(v) {
|
||
if (!v && v !== 0) {
|
||
this.placeholder = true;
|
||
this.rendered = color.gray(this.transform.render(`${this.initial}`));
|
||
this._value = ``;
|
||
} else {
|
||
this.placeholder = false;
|
||
this.rendered = this.transform.render(`${round(v, this.round)}`);
|
||
this._value = round(v, this.round);
|
||
}
|
||
this.fire();
|
||
}
|
||
|
||
get value() {
|
||
return this._value;
|
||
}
|
||
|
||
parse(x) {
|
||
return this.float ? parseFloat(x) : parseInt(x);
|
||
}
|
||
|
||
valid(c) {
|
||
return c === `-` || c === `.` && this.float || isNumber.test(c)
|
||
}
|
||
|
||
reset() {
|
||
this.typed = ``;
|
||
this.value = ``;
|
||
this.fire();
|
||
this.render();
|
||
}
|
||
|
||
exit() {
|
||
this.abort();
|
||
}
|
||
|
||
abort() {
|
||
let x = this.value;
|
||
this.value = x !== `` ? x : this.initial;
|
||
this.done = this.aborted = true;
|
||
this.error = false;
|
||
this.fire();
|
||
this.render();
|
||
this.out.write(`\n`);
|
||
this.close();
|
||
}
|
||
|
||
async validate() {
|
||
let valid = await this.validator(this.value);
|
||
if (typeof valid === `string`) {
|
||
this.errorMsg = valid;
|
||
valid = false;
|
||
}
|
||
this.error = !valid;
|
||
}
|
||
|
||
async submit() {
|
||
await this.validate();
|
||
if (this.error) {
|
||
this.color = `red`;
|
||
this.fire();
|
||
this.render();
|
||
return;
|
||
}
|
||
let x = this.value;
|
||
this.value = x !== `` ? x : this.initial;
|
||
this.done = true;
|
||
this.aborted = false;
|
||
this.error = false;
|
||
this.fire();
|
||
this.render();
|
||
this.out.write(`\n`);
|
||
this.close();
|
||
}
|
||
|
||
up() {
|
||
this.typed = ``;
|
||
if(this.value === '') {
|
||
this.value = this.min - this.inc;
|
||
}
|
||
if (this.value >= this.max) return this.bell();
|
||
this.value += this.inc;
|
||
this.color = `cyan`;
|
||
this.fire();
|
||
this.render();
|
||
}
|
||
|
||
down() {
|
||
this.typed = ``;
|
||
if(this.value === '') {
|
||
this.value = this.min + this.inc;
|
||
}
|
||
if (this.value <= this.min) return this.bell();
|
||
this.value -= this.inc;
|
||
this.color = `cyan`;
|
||
this.fire();
|
||
this.render();
|
||
}
|
||
|
||
delete() {
|
||
let val = this.value.toString();
|
||
if (val.length === 0) return this.bell();
|
||
this.value = this.parse((val = val.slice(0, -1))) || ``;
|
||
if (this.value !== '' && this.value < this.min) {
|
||
this.value = this.min;
|
||
}
|
||
this.color = `cyan`;
|
||
this.fire();
|
||
this.render();
|
||
}
|
||
|
||
next() {
|
||
this.value = this.initial;
|
||
this.fire();
|
||
this.render();
|
||
}
|
||
|
||
_(c, key) {
|
||
if (!this.valid(c)) return this.bell();
|
||
|
||
const now = Date.now();
|
||
if (now - this.lastHit > 1000) this.typed = ``; // 1s elapsed
|
||
this.typed += c;
|
||
this.lastHit = now;
|
||
this.color = `cyan`;
|
||
|
||
if (c === `.`) return this.fire();
|
||
|
||
this.value = Math.min(this.parse(this.typed), this.max);
|
||
if (this.value > this.max) this.value = this.max;
|
||
if (this.value < this.min) this.value = this.min;
|
||
this.fire();
|
||
this.render();
|
||
}
|
||
|
||
render() {
|
||
if (this.closed) return;
|
||
if (!this.firstRender) {
|
||
if (this.outputError)
|
||
this.out.write(cursor.down(lines(this.outputError, this.out.columns) - 1) + clear(this.outputError, this.out.columns));
|
||
this.out.write(clear(this.outputText, this.out.columns));
|
||
}
|
||
super.render();
|
||
this.outputError = '';
|
||
|
||
// Print prompt
|
||
this.outputText = [
|
||
style.symbol(this.done, this.aborted),
|
||
color.bold(this.msg),
|
||
style.delimiter(this.done),
|
||
!this.done || (!this.done && !this.placeholder)
|
||
? color[this.color]().underline(this.rendered) : this.rendered
|
||
].join(` `);
|
||
|
||
// Print error
|
||
if (this.error) {
|
||
this.outputError += this.errorMsg.split(`\n`)
|
||
.reduce((a, l, i) => a + `\n${i ? ` ` : figures.pointerSmall} ${color.red().italic(l)}`, ``);
|
||
}
|
||
|
||
this.out.write(erase.line + cursor.to(0) + this.outputText + cursor.save + this.outputError + cursor.restore);
|
||
}
|
||
}
|
||
|
||
number = NumberPrompt;
|
||
return number;
|
||
}
|
||
|
||
var multiselect;
|
||
var hasRequiredMultiselect;
|
||
|
||
function requireMultiselect () {
|
||
if (hasRequiredMultiselect) return multiselect;
|
||
hasRequiredMultiselect = 1;
|
||
|
||
const color = requireKleur();
|
||
const { cursor } = requireSrc();
|
||
const Prompt = requirePrompt();
|
||
const { clear, figures, style, wrap, entriesToDisplay } = requireUtil();
|
||
|
||
/**
|
||
* MultiselectPrompt Base Element
|
||
* @param {Object} opts Options
|
||
* @param {String} opts.message Message
|
||
* @param {Array} opts.choices Array of choice objects
|
||
* @param {String} [opts.hint] Hint to display
|
||
* @param {String} [opts.warn] Hint shown for disabled choices
|
||
* @param {Number} [opts.max] Max choices
|
||
* @param {Number} [opts.cursor=0] Cursor start position
|
||
* @param {Number} [opts.optionsPerPage=10] Max options to display at once
|
||
* @param {Stream} [opts.stdin] The Readable stream to listen to
|
||
* @param {Stream} [opts.stdout] The Writable stream to write readline data to
|
||
*/
|
||
class MultiselectPrompt extends Prompt {
|
||
constructor(opts={}) {
|
||
super(opts);
|
||
this.msg = opts.message;
|
||
this.cursor = opts.cursor || 0;
|
||
this.scrollIndex = opts.cursor || 0;
|
||
this.hint = opts.hint || '';
|
||
this.warn = opts.warn || '- This option is disabled -';
|
||
this.minSelected = opts.min;
|
||
this.showMinError = false;
|
||
this.maxChoices = opts.max;
|
||
this.instructions = opts.instructions;
|
||
this.optionsPerPage = opts.optionsPerPage || 10;
|
||
this.value = opts.choices.map((ch, idx) => {
|
||
if (typeof ch === 'string')
|
||
ch = {title: ch, value: idx};
|
||
return {
|
||
title: ch && (ch.title || ch.value || ch),
|
||
description: ch && ch.description,
|
||
value: ch && (ch.value === undefined ? idx : ch.value),
|
||
selected: ch && ch.selected,
|
||
disabled: ch && ch.disabled
|
||
};
|
||
});
|
||
this.clear = clear('', this.out.columns);
|
||
if (!opts.overrideRender) {
|
||
this.render();
|
||
}
|
||
}
|
||
|
||
reset() {
|
||
this.value.map(v => !v.selected);
|
||
this.cursor = 0;
|
||
this.fire();
|
||
this.render();
|
||
}
|
||
|
||
selected() {
|
||
return this.value.filter(v => v.selected);
|
||
}
|
||
|
||
exit() {
|
||
this.abort();
|
||
}
|
||
|
||
abort() {
|
||
this.done = this.aborted = true;
|
||
this.fire();
|
||
this.render();
|
||
this.out.write('\n');
|
||
this.close();
|
||
}
|
||
|
||
submit() {
|
||
const selected = this.value
|
||
.filter(e => e.selected);
|
||
if (this.minSelected && selected.length < this.minSelected) {
|
||
this.showMinError = true;
|
||
this.render();
|
||
} else {
|
||
this.done = true;
|
||
this.aborted = false;
|
||
this.fire();
|
||
this.render();
|
||
this.out.write('\n');
|
||
this.close();
|
||
}
|
||
}
|
||
|
||
first() {
|
||
this.cursor = 0;
|
||
this.render();
|
||
}
|
||
|
||
last() {
|
||
this.cursor = this.value.length - 1;
|
||
this.render();
|
||
}
|
||
next() {
|
||
this.cursor = (this.cursor + 1) % this.value.length;
|
||
this.render();
|
||
}
|
||
|
||
up() {
|
||
if (this.cursor === 0) {
|
||
this.cursor = this.value.length - 1;
|
||
} else {
|
||
this.cursor--;
|
||
}
|
||
this.render();
|
||
}
|
||
|
||
down() {
|
||
if (this.cursor === this.value.length - 1) {
|
||
this.cursor = 0;
|
||
} else {
|
||
this.cursor++;
|
||
}
|
||
this.render();
|
||
}
|
||
|
||
left() {
|
||
this.value[this.cursor].selected = false;
|
||
this.render();
|
||
}
|
||
|
||
right() {
|
||
if (this.value.filter(e => e.selected).length >= this.maxChoices) return this.bell();
|
||
this.value[this.cursor].selected = true;
|
||
this.render();
|
||
}
|
||
|
||
handleSpaceToggle() {
|
||
const v = this.value[this.cursor];
|
||
|
||
if (v.selected) {
|
||
v.selected = false;
|
||
this.render();
|
||
} else if (v.disabled || this.value.filter(e => e.selected).length >= this.maxChoices) {
|
||
return this.bell();
|
||
} else {
|
||
v.selected = true;
|
||
this.render();
|
||
}
|
||
}
|
||
|
||
toggleAll() {
|
||
if (this.maxChoices !== undefined || this.value[this.cursor].disabled) {
|
||
return this.bell();
|
||
}
|
||
|
||
const newSelected = !this.value[this.cursor].selected;
|
||
this.value.filter(v => !v.disabled).forEach(v => v.selected = newSelected);
|
||
this.render();
|
||
}
|
||
|
||
_(c, key) {
|
||
if (c === ' ') {
|
||
this.handleSpaceToggle();
|
||
} else if (c === 'a') {
|
||
this.toggleAll();
|
||
} else {
|
||
return this.bell();
|
||
}
|
||
}
|
||
|
||
renderInstructions() {
|
||
if (this.instructions === undefined || this.instructions) {
|
||
if (typeof this.instructions === 'string') {
|
||
return this.instructions;
|
||
}
|
||
return '\nInstructions:\n'
|
||
+ ` ${figures.arrowUp}/${figures.arrowDown}: Highlight option\n`
|
||
+ ` ${figures.arrowLeft}/${figures.arrowRight}/[space]: Toggle selection\n`
|
||
+ (this.maxChoices === undefined ? ` a: Toggle all\n` : '')
|
||
+ ` enter/return: Complete answer`;
|
||
}
|
||
return '';
|
||
}
|
||
|
||
renderOption(cursor, v, i, arrowIndicator) {
|
||
const prefix = (v.selected ? color.green(figures.radioOn) : figures.radioOff) + ' ' + arrowIndicator + ' ';
|
||
let title, desc;
|
||
|
||
if (v.disabled) {
|
||
title = cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title);
|
||
} else {
|
||
title = cursor === i ? color.cyan().underline(v.title) : v.title;
|
||
if (cursor === i && v.description) {
|
||
desc = ` - ${v.description}`;
|
||
if (prefix.length + title.length + desc.length >= this.out.columns
|
||
|| v.description.split(/\r?\n/).length > 1) {
|
||
desc = '\n' + wrap(v.description, { margin: prefix.length, width: this.out.columns });
|
||
}
|
||
}
|
||
}
|
||
|
||
return prefix + title + color.gray(desc || '');
|
||
}
|
||
|
||
// shared with autocompleteMultiselect
|
||
paginateOptions(options) {
|
||
if (options.length === 0) {
|
||
return color.red('No matches for this query.');
|
||
}
|
||
|
||
let { startIndex, endIndex } = entriesToDisplay(this.cursor, options.length, this.optionsPerPage);
|
||
let prefix, styledOptions = [];
|
||
|
||
for (let i = startIndex; i < endIndex; i++) {
|
||
if (i === startIndex && startIndex > 0) {
|
||
prefix = figures.arrowUp;
|
||
} else if (i === endIndex - 1 && endIndex < options.length) {
|
||
prefix = figures.arrowDown;
|
||
} else {
|
||
prefix = ' ';
|
||
}
|
||
styledOptions.push(this.renderOption(this.cursor, options[i], i, prefix));
|
||
}
|
||
|
||
return '\n' + styledOptions.join('\n');
|
||
}
|
||
|
||
// shared with autocomleteMultiselect
|
||
renderOptions(options) {
|
||
if (!this.done) {
|
||
return this.paginateOptions(options);
|
||
}
|
||
return '';
|
||
}
|
||
|
||
renderDoneOrInstructions() {
|
||
if (this.done) {
|
||
return this.value
|
||
.filter(e => e.selected)
|
||
.map(v => v.title)
|
||
.join(', ');
|
||
}
|
||
|
||
const output = [color.gray(this.hint), this.renderInstructions()];
|
||
|
||
if (this.value[this.cursor].disabled) {
|
||
output.push(color.yellow(this.warn));
|
||
}
|
||
return output.join(' ');
|
||
}
|
||
|
||
render() {
|
||
if (this.closed) return;
|
||
if (this.firstRender) this.out.write(cursor.hide);
|
||
super.render();
|
||
|
||
// print prompt
|
||
let prompt = [
|
||
style.symbol(this.done, this.aborted),
|
||
color.bold(this.msg),
|
||
style.delimiter(false),
|
||
this.renderDoneOrInstructions()
|
||
].join(' ');
|
||
if (this.showMinError) {
|
||
prompt += color.red(`You must select a minimum of ${this.minSelected} choices.`);
|
||
this.showMinError = false;
|
||
}
|
||
prompt += this.renderOptions(this.value);
|
||
|
||
this.out.write(this.clear + prompt);
|
||
this.clear = clear(prompt, this.out.columns);
|
||
}
|
||
}
|
||
|
||
multiselect = MultiselectPrompt;
|
||
return multiselect;
|
||
}
|
||
|
||
var autocomplete;
|
||
var hasRequiredAutocomplete;
|
||
|
||
function requireAutocomplete () {
|
||
if (hasRequiredAutocomplete) return autocomplete;
|
||
hasRequiredAutocomplete = 1;
|
||
|
||
const color = requireKleur();
|
||
const Prompt = requirePrompt();
|
||
const { erase, cursor } = requireSrc();
|
||
const { style, clear, figures, wrap, entriesToDisplay } = requireUtil();
|
||
|
||
const getVal = (arr, i) => arr[i] && (arr[i].value || arr[i].title || arr[i]);
|
||
const getTitle = (arr, i) => arr[i] && (arr[i].title || arr[i].value || arr[i]);
|
||
const getIndex = (arr, valOrTitle) => {
|
||
const index = arr.findIndex(el => el.value === valOrTitle || el.title === valOrTitle);
|
||
return index > -1 ? index : undefined;
|
||
};
|
||
|
||
/**
|
||
* TextPrompt Base Element
|
||
* @param {Object} opts Options
|
||
* @param {String} opts.message Message
|
||
* @param {Array} opts.choices Array of auto-complete choices objects
|
||
* @param {Function} [opts.suggest] Filter function. Defaults to sort by title
|
||
* @param {Number} [opts.limit=10] Max number of results to show
|
||
* @param {Number} [opts.cursor=0] Cursor start position
|
||
* @param {String} [opts.style='default'] Render style
|
||
* @param {String} [opts.fallback] Fallback message - initial to default value
|
||
* @param {String} [opts.initial] Index of the default value
|
||
* @param {Boolean} [opts.clearFirst] The first ESCAPE keypress will clear the input
|
||
* @param {Stream} [opts.stdin] The Readable stream to listen to
|
||
* @param {Stream} [opts.stdout] The Writable stream to write readline data to
|
||
* @param {String} [opts.noMatches] The no matches found label
|
||
*/
|
||
class AutocompletePrompt extends Prompt {
|
||
constructor(opts={}) {
|
||
super(opts);
|
||
this.msg = opts.message;
|
||
this.suggest = opts.suggest;
|
||
this.choices = opts.choices;
|
||
this.initial = typeof opts.initial === 'number'
|
||
? opts.initial
|
||
: getIndex(opts.choices, opts.initial);
|
||
this.select = this.initial || opts.cursor || 0;
|
||
this.i18n = { noMatches: opts.noMatches || 'no matches found' };
|
||
this.fallback = opts.fallback || this.initial;
|
||
this.clearFirst = opts.clearFirst || false;
|
||
this.suggestions = [];
|
||
this.input = '';
|
||
this.limit = opts.limit || 10;
|
||
this.cursor = 0;
|
||
this.transform = style.render(opts.style);
|
||
this.scale = this.transform.scale;
|
||
this.render = this.render.bind(this);
|
||
this.complete = this.complete.bind(this);
|
||
this.clear = clear('', this.out.columns);
|
||
this.complete(this.render);
|
||
this.render();
|
||
}
|
||
|
||
set fallback(fb) {
|
||
this._fb = Number.isSafeInteger(parseInt(fb)) ? parseInt(fb) : fb;
|
||
}
|
||
|
||
get fallback() {
|
||
let choice;
|
||
if (typeof this._fb === 'number')
|
||
choice = this.choices[this._fb];
|
||
else if (typeof this._fb === 'string')
|
||
choice = { title: this._fb };
|
||
return choice || this._fb || { title: this.i18n.noMatches };
|
||
}
|
||
|
||
moveSelect(i) {
|
||
this.select = i;
|
||
if (this.suggestions.length > 0)
|
||
this.value = getVal(this.suggestions, i);
|
||
else this.value = this.fallback.value;
|
||
this.fire();
|
||
}
|
||
|
||
async complete(cb) {
|
||
const p = (this.completing = this.suggest(this.input, this.choices));
|
||
const suggestions = await p;
|
||
|
||
if (this.completing !== p) return;
|
||
this.suggestions = suggestions
|
||
.map((s, i, arr) => ({ title: getTitle(arr, i), value: getVal(arr, i), description: s.description }));
|
||
this.completing = false;
|
||
const l = Math.max(suggestions.length - 1, 0);
|
||
this.moveSelect(Math.min(l, this.select));
|
||
|
||
cb && cb();
|
||
}
|
||
|
||
reset() {
|
||
this.input = '';
|
||
this.complete(() => {
|
||
this.moveSelect(this.initial !== void 0 ? this.initial : 0);
|
||
this.render();
|
||
});
|
||
this.render();
|
||
}
|
||
|
||
exit() {
|
||
if (this.clearFirst && this.input.length > 0) {
|
||
this.reset();
|
||
} else {
|
||
this.done = this.exited = true;
|
||
this.aborted = false;
|
||
this.fire();
|
||
this.render();
|
||
this.out.write('\n');
|
||
this.close();
|
||
}
|
||
}
|
||
|
||
abort() {
|
||
this.done = this.aborted = true;
|
||
this.exited = false;
|
||
this.fire();
|
||
this.render();
|
||
this.out.write('\n');
|
||
this.close();
|
||
}
|
||
|
||
submit() {
|
||
this.done = true;
|
||
this.aborted = this.exited = false;
|
||
this.fire();
|
||
this.render();
|
||
this.out.write('\n');
|
||
this.close();
|
||
}
|
||
|
||
_(c, key) {
|
||
let s1 = this.input.slice(0, this.cursor);
|
||
let s2 = this.input.slice(this.cursor);
|
||
this.input = `${s1}${c}${s2}`;
|
||
this.cursor = s1.length+1;
|
||
this.complete(this.render);
|
||
this.render();
|
||
}
|
||
|
||
delete() {
|
||
if (this.cursor === 0) return this.bell();
|
||
let s1 = this.input.slice(0, this.cursor-1);
|
||
let s2 = this.input.slice(this.cursor);
|
||
this.input = `${s1}${s2}`;
|
||
this.complete(this.render);
|
||
this.cursor = this.cursor-1;
|
||
this.render();
|
||
}
|
||
|
||
deleteForward() {
|
||
if(this.cursor*this.scale >= this.rendered.length) return this.bell();
|
||
let s1 = this.input.slice(0, this.cursor);
|
||
let s2 = this.input.slice(this.cursor+1);
|
||
this.input = `${s1}${s2}`;
|
||
this.complete(this.render);
|
||
this.render();
|
||
}
|
||
|
||
first() {
|
||
this.moveSelect(0);
|
||
this.render();
|
||
}
|
||
|
||
last() {
|
||
this.moveSelect(this.suggestions.length - 1);
|
||
this.render();
|
||
}
|
||
|
||
up() {
|
||
if (this.select === 0) {
|
||
this.moveSelect(this.suggestions.length - 1);
|
||
} else {
|
||
this.moveSelect(this.select - 1);
|
||
}
|
||
this.render();
|
||
}
|
||
|
||
down() {
|
||
if (this.select === this.suggestions.length - 1) {
|
||
this.moveSelect(0);
|
||
} else {
|
||
this.moveSelect(this.select + 1);
|
||
}
|
||
this.render();
|
||
}
|
||
|
||
next() {
|
||
if (this.select === this.suggestions.length - 1) {
|
||
this.moveSelect(0);
|
||
} else this.moveSelect(this.select + 1);
|
||
this.render();
|
||
}
|
||
|
||
nextPage() {
|
||
this.moveSelect(Math.min(this.select + this.limit, this.suggestions.length - 1));
|
||
this.render();
|
||
}
|
||
|
||
prevPage() {
|
||
this.moveSelect(Math.max(this.select - this.limit, 0));
|
||
this.render();
|
||
}
|
||
|
||
left() {
|
||
if (this.cursor <= 0) return this.bell();
|
||
this.cursor = this.cursor-1;
|
||
this.render();
|
||
}
|
||
|
||
right() {
|
||
if (this.cursor*this.scale >= this.rendered.length) return this.bell();
|
||
this.cursor = this.cursor+1;
|
||
this.render();
|
||
}
|
||
|
||
renderOption(v, hovered, isStart, isEnd) {
|
||
let desc;
|
||
let prefix = isStart ? figures.arrowUp : isEnd ? figures.arrowDown : ' ';
|
||
let title = hovered ? color.cyan().underline(v.title) : v.title;
|
||
prefix = (hovered ? color.cyan(figures.pointer) + ' ' : ' ') + prefix;
|
||
if (v.description) {
|
||
desc = ` - ${v.description}`;
|
||
if (prefix.length + title.length + desc.length >= this.out.columns
|
||
|| v.description.split(/\r?\n/).length > 1) {
|
||
desc = '\n' + wrap(v.description, { margin: 3, width: this.out.columns });
|
||
}
|
||
}
|
||
return prefix + ' ' + title + color.gray(desc || '');
|
||
}
|
||
|
||
render() {
|
||
if (this.closed) return;
|
||
if (this.firstRender) this.out.write(cursor.hide);
|
||
else this.out.write(clear(this.outputText, this.out.columns));
|
||
super.render();
|
||
|
||
let { startIndex, endIndex } = entriesToDisplay(this.select, this.choices.length, this.limit);
|
||
|
||
this.outputText = [
|
||
style.symbol(this.done, this.aborted, this.exited),
|
||
color.bold(this.msg),
|
||
style.delimiter(this.completing),
|
||
this.done && this.suggestions[this.select]
|
||
? this.suggestions[this.select].title
|
||
: this.rendered = this.transform.render(this.input)
|
||
].join(' ');
|
||
|
||
if (!this.done) {
|
||
const suggestions = this.suggestions
|
||
.slice(startIndex, endIndex)
|
||
.map((item, i) => this.renderOption(item,
|
||
this.select === i + startIndex,
|
||
i === 0 && startIndex > 0,
|
||
i + startIndex === endIndex - 1 && endIndex < this.choices.length))
|
||
.join('\n');
|
||
this.outputText += `\n` + (suggestions || color.gray(this.fallback.title));
|
||
}
|
||
|
||
this.out.write(erase.line + cursor.to(0) + this.outputText);
|
||
}
|
||
}
|
||
|
||
autocomplete = AutocompletePrompt;
|
||
return autocomplete;
|
||
}
|
||
|
||
var autocompleteMultiselect;
|
||
var hasRequiredAutocompleteMultiselect;
|
||
|
||
function requireAutocompleteMultiselect () {
|
||
if (hasRequiredAutocompleteMultiselect) return autocompleteMultiselect;
|
||
hasRequiredAutocompleteMultiselect = 1;
|
||
|
||
const color = requireKleur();
|
||
const { cursor } = requireSrc();
|
||
const MultiselectPrompt = requireMultiselect();
|
||
const { clear, style, figures } = requireUtil();
|
||
/**
|
||
* MultiselectPrompt Base Element
|
||
* @param {Object} opts Options
|
||
* @param {String} opts.message Message
|
||
* @param {Array} opts.choices Array of choice objects
|
||
* @param {String} [opts.hint] Hint to display
|
||
* @param {String} [opts.warn] Hint shown for disabled choices
|
||
* @param {Number} [opts.max] Max choices
|
||
* @param {Number} [opts.cursor=0] Cursor start position
|
||
* @param {Stream} [opts.stdin] The Readable stream to listen to
|
||
* @param {Stream} [opts.stdout] The Writable stream to write readline data to
|
||
*/
|
||
class AutocompleteMultiselectPrompt extends MultiselectPrompt {
|
||
constructor(opts={}) {
|
||
opts.overrideRender = true;
|
||
super(opts);
|
||
this.inputValue = '';
|
||
this.clear = clear('', this.out.columns);
|
||
this.filteredOptions = this.value;
|
||
this.render();
|
||
}
|
||
|
||
last() {
|
||
this.cursor = this.filteredOptions.length - 1;
|
||
this.render();
|
||
}
|
||
next() {
|
||
this.cursor = (this.cursor + 1) % this.filteredOptions.length;
|
||
this.render();
|
||
}
|
||
|
||
up() {
|
||
if (this.cursor === 0) {
|
||
this.cursor = this.filteredOptions.length - 1;
|
||
} else {
|
||
this.cursor--;
|
||
}
|
||
this.render();
|
||
}
|
||
|
||
down() {
|
||
if (this.cursor === this.filteredOptions.length - 1) {
|
||
this.cursor = 0;
|
||
} else {
|
||
this.cursor++;
|
||
}
|
||
this.render();
|
||
}
|
||
|
||
left() {
|
||
this.filteredOptions[this.cursor].selected = false;
|
||
this.render();
|
||
}
|
||
|
||
right() {
|
||
if (this.value.filter(e => e.selected).length >= this.maxChoices) return this.bell();
|
||
this.filteredOptions[this.cursor].selected = true;
|
||
this.render();
|
||
}
|
||
|
||
delete() {
|
||
if (this.inputValue.length) {
|
||
this.inputValue = this.inputValue.substr(0, this.inputValue.length - 1);
|
||
this.updateFilteredOptions();
|
||
}
|
||
}
|
||
|
||
updateFilteredOptions() {
|
||
const currentHighlight = this.filteredOptions[this.cursor];
|
||
this.filteredOptions = this.value
|
||
.filter(v => {
|
||
if (this.inputValue) {
|
||
if (typeof v.title === 'string') {
|
||
if (v.title.toLowerCase().includes(this.inputValue.toLowerCase())) {
|
||
return true;
|
||
}
|
||
}
|
||
if (typeof v.value === 'string') {
|
||
if (v.value.toLowerCase().includes(this.inputValue.toLowerCase())) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
return true;
|
||
});
|
||
const newHighlightIndex = this.filteredOptions.findIndex(v => v === currentHighlight);
|
||
this.cursor = newHighlightIndex < 0 ? 0 : newHighlightIndex;
|
||
this.render();
|
||
}
|
||
|
||
handleSpaceToggle() {
|
||
const v = this.filteredOptions[this.cursor];
|
||
|
||
if (v.selected) {
|
||
v.selected = false;
|
||
this.render();
|
||
} else if (v.disabled || this.value.filter(e => e.selected).length >= this.maxChoices) {
|
||
return this.bell();
|
||
} else {
|
||
v.selected = true;
|
||
this.render();
|
||
}
|
||
}
|
||
|
||
handleInputChange(c) {
|
||
this.inputValue = this.inputValue + c;
|
||
this.updateFilteredOptions();
|
||
}
|
||
|
||
_(c, key) {
|
||
if (c === ' ') {
|
||
this.handleSpaceToggle();
|
||
} else {
|
||
this.handleInputChange(c);
|
||
}
|
||
}
|
||
|
||
renderInstructions() {
|
||
if (this.instructions === undefined || this.instructions) {
|
||
if (typeof this.instructions === 'string') {
|
||
return this.instructions;
|
||
}
|
||
return `
|
||
Instructions:
|
||
${figures.arrowUp}/${figures.arrowDown}: Highlight option
|
||
${figures.arrowLeft}/${figures.arrowRight}/[space]: Toggle selection
|
||
[a,b,c]/delete: Filter choices
|
||
enter/return: Complete answer
|
||
`;
|
||
}
|
||
return '';
|
||
}
|
||
|
||
renderCurrentInput() {
|
||
return `
|
||
Filtered results for: ${this.inputValue ? this.inputValue : color.gray('Enter something to filter')}\n`;
|
||
}
|
||
|
||
renderOption(cursor, v, i, arrowIndicator) {
|
||
const prefix = (v.selected ? color.green(figures.radioOn) : figures.radioOff) + ' ' + arrowIndicator + ' ';
|
||
let title;
|
||
if (v.disabled) title = cursor === i ? color.gray().underline(v.title) : color.strikethrough().gray(v.title);
|
||
else title = cursor === i ? color.cyan().underline(v.title) : v.title;
|
||
return prefix + title;
|
||
}
|
||
|
||
renderDoneOrInstructions() {
|
||
if (this.done) {
|
||
return this.value
|
||
.filter(e => e.selected)
|
||
.map(v => v.title)
|
||
.join(', ');
|
||
}
|
||
|
||
const output = [color.gray(this.hint), this.renderInstructions(), this.renderCurrentInput()];
|
||
|
||
if (this.filteredOptions.length && this.filteredOptions[this.cursor].disabled) {
|
||
output.push(color.yellow(this.warn));
|
||
}
|
||
return output.join(' ');
|
||
}
|
||
|
||
render() {
|
||
if (this.closed) return;
|
||
if (this.firstRender) this.out.write(cursor.hide);
|
||
super.render();
|
||
|
||
// print prompt
|
||
|
||
let prompt = [
|
||
style.symbol(this.done, this.aborted),
|
||
color.bold(this.msg),
|
||
style.delimiter(false),
|
||
this.renderDoneOrInstructions()
|
||
].join(' ');
|
||
|
||
if (this.showMinError) {
|
||
prompt += color.red(`You must select a minimum of ${this.minSelected} choices.`);
|
||
this.showMinError = false;
|
||
}
|
||
prompt += this.renderOptions(this.filteredOptions);
|
||
|
||
this.out.write(this.clear + prompt);
|
||
this.clear = clear(prompt, this.out.columns);
|
||
}
|
||
}
|
||
|
||
autocompleteMultiselect = AutocompleteMultiselectPrompt;
|
||
return autocompleteMultiselect;
|
||
}
|
||
|
||
var confirm;
|
||
var hasRequiredConfirm;
|
||
|
||
function requireConfirm () {
|
||
if (hasRequiredConfirm) return confirm;
|
||
hasRequiredConfirm = 1;
|
||
const color = requireKleur();
|
||
const Prompt = requirePrompt();
|
||
const { style, clear } = requireUtil();
|
||
const { erase, cursor } = requireSrc();
|
||
|
||
/**
|
||
* ConfirmPrompt Base Element
|
||
* @param {Object} opts Options
|
||
* @param {String} opts.message Message
|
||
* @param {Boolean} [opts.initial] Default value (true/false)
|
||
* @param {Stream} [opts.stdin] The Readable stream to listen to
|
||
* @param {Stream} [opts.stdout] The Writable stream to write readline data to
|
||
* @param {String} [opts.yes] The "Yes" label
|
||
* @param {String} [opts.yesOption] The "Yes" option when choosing between yes/no
|
||
* @param {String} [opts.no] The "No" label
|
||
* @param {String} [opts.noOption] The "No" option when choosing between yes/no
|
||
*/
|
||
class ConfirmPrompt extends Prompt {
|
||
constructor(opts={}) {
|
||
super(opts);
|
||
this.msg = opts.message;
|
||
this.value = opts.initial;
|
||
this.initialValue = !!opts.initial;
|
||
this.yesMsg = opts.yes || 'yes';
|
||
this.yesOption = opts.yesOption || '(Y/n)';
|
||
this.noMsg = opts.no || 'no';
|
||
this.noOption = opts.noOption || '(y/N)';
|
||
this.render();
|
||
}
|
||
|
||
reset() {
|
||
this.value = this.initialValue;
|
||
this.fire();
|
||
this.render();
|
||
}
|
||
|
||
exit() {
|
||
this.abort();
|
||
}
|
||
|
||
abort() {
|
||
this.done = this.aborted = true;
|
||
this.fire();
|
||
this.render();
|
||
this.out.write('\n');
|
||
this.close();
|
||
}
|
||
|
||
submit() {
|
||
this.value = this.value || false;
|
||
this.done = true;
|
||
this.aborted = false;
|
||
this.fire();
|
||
this.render();
|
||
this.out.write('\n');
|
||
this.close();
|
||
}
|
||
|
||
_(c, key) {
|
||
if (c.toLowerCase() === 'y') {
|
||
this.value = true;
|
||
return this.submit();
|
||
}
|
||
if (c.toLowerCase() === 'n') {
|
||
this.value = false;
|
||
return this.submit();
|
||
}
|
||
return this.bell();
|
||
}
|
||
|
||
render() {
|
||
if (this.closed) return;
|
||
if (this.firstRender) this.out.write(cursor.hide);
|
||
else this.out.write(clear(this.outputText, this.out.columns));
|
||
super.render();
|
||
|
||
this.outputText = [
|
||
style.symbol(this.done, this.aborted),
|
||
color.bold(this.msg),
|
||
style.delimiter(this.done),
|
||
this.done ? (this.value ? this.yesMsg : this.noMsg)
|
||
: color.gray(this.initialValue ? this.yesOption : this.noOption)
|
||
].join(' ');
|
||
|
||
this.out.write(erase.line + cursor.to(0) + this.outputText);
|
||
}
|
||
}
|
||
|
||
confirm = ConfirmPrompt;
|
||
return confirm;
|
||
}
|
||
|
||
var elements;
|
||
var hasRequiredElements;
|
||
|
||
function requireElements () {
|
||
if (hasRequiredElements) return elements;
|
||
hasRequiredElements = 1;
|
||
|
||
elements = {
|
||
TextPrompt: requireText(),
|
||
SelectPrompt: requireSelect(),
|
||
TogglePrompt: requireToggle(),
|
||
DatePrompt: requireDate(),
|
||
NumberPrompt: requireNumber(),
|
||
MultiselectPrompt: requireMultiselect(),
|
||
AutocompletePrompt: requireAutocomplete(),
|
||
AutocompleteMultiselectPrompt: requireAutocompleteMultiselect(),
|
||
ConfirmPrompt: requireConfirm()
|
||
};
|
||
return elements;
|
||
}
|
||
|
||
var hasRequiredPrompts$1;
|
||
|
||
function requirePrompts$1 () {
|
||
if (hasRequiredPrompts$1) return prompts$2;
|
||
hasRequiredPrompts$1 = 1;
|
||
(function (exports) {
|
||
const $ = exports;
|
||
const el = requireElements();
|
||
const noop = v => v;
|
||
|
||
function toPrompt(type, args, opts={}) {
|
||
return new Promise((res, rej) => {
|
||
const p = new el[type](args);
|
||
const onAbort = opts.onAbort || noop;
|
||
const onSubmit = opts.onSubmit || noop;
|
||
const onExit = opts.onExit || noop;
|
||
p.on('state', args.onState || noop);
|
||
p.on('submit', x => res(onSubmit(x)));
|
||
p.on('exit', x => res(onExit(x)));
|
||
p.on('abort', x => rej(onAbort(x)));
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Text prompt
|
||
* @param {string} args.message Prompt message to display
|
||
* @param {string} [args.initial] Default string value
|
||
* @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
|
||
* @param {function} [args.onState] On state change callback
|
||
* @param {function} [args.validate] Function to validate user input
|
||
* @param {Stream} [args.stdin] The Readable stream to listen to
|
||
* @param {Stream} [args.stdout] The Writable stream to write readline data to
|
||
* @returns {Promise} Promise with user input
|
||
*/
|
||
$.text = args => toPrompt('TextPrompt', args);
|
||
|
||
/**
|
||
* Password prompt with masked input
|
||
* @param {string} args.message Prompt message to display
|
||
* @param {string} [args.initial] Default string value
|
||
* @param {function} [args.onState] On state change callback
|
||
* @param {function} [args.validate] Function to validate user input
|
||
* @param {Stream} [args.stdin] The Readable stream to listen to
|
||
* @param {Stream} [args.stdout] The Writable stream to write readline data to
|
||
* @returns {Promise} Promise with user input
|
||
*/
|
||
$.password = args => {
|
||
args.style = 'password';
|
||
return $.text(args);
|
||
};
|
||
|
||
/**
|
||
* Prompt where input is invisible, like sudo
|
||
* @param {string} args.message Prompt message to display
|
||
* @param {string} [args.initial] Default string value
|
||
* @param {function} [args.onState] On state change callback
|
||
* @param {function} [args.validate] Function to validate user input
|
||
* @param {Stream} [args.stdin] The Readable stream to listen to
|
||
* @param {Stream} [args.stdout] The Writable stream to write readline data to
|
||
* @returns {Promise} Promise with user input
|
||
*/
|
||
$.invisible = args => {
|
||
args.style = 'invisible';
|
||
return $.text(args);
|
||
};
|
||
|
||
/**
|
||
* Number prompt
|
||
* @param {string} args.message Prompt message to display
|
||
* @param {number} args.initial Default number value
|
||
* @param {function} [args.onState] On state change callback
|
||
* @param {number} [args.max] Max value
|
||
* @param {number} [args.min] Min value
|
||
* @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
|
||
* @param {Boolean} [opts.float=false] Parse input as floats
|
||
* @param {Number} [opts.round=2] Round floats to x decimals
|
||
* @param {Number} [opts.increment=1] Number to increment by when using arrow-keys
|
||
* @param {function} [args.validate] Function to validate user input
|
||
* @param {Stream} [args.stdin] The Readable stream to listen to
|
||
* @param {Stream} [args.stdout] The Writable stream to write readline data to
|
||
* @returns {Promise} Promise with user input
|
||
*/
|
||
$.number = args => toPrompt('NumberPrompt', args);
|
||
|
||
/**
|
||
* Date prompt
|
||
* @param {string} args.message Prompt message to display
|
||
* @param {number} args.initial Default number value
|
||
* @param {function} [args.onState] On state change callback
|
||
* @param {number} [args.max] Max value
|
||
* @param {number} [args.min] Min value
|
||
* @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
|
||
* @param {Boolean} [opts.float=false] Parse input as floats
|
||
* @param {Number} [opts.round=2] Round floats to x decimals
|
||
* @param {Number} [opts.increment=1] Number to increment by when using arrow-keys
|
||
* @param {function} [args.validate] Function to validate user input
|
||
* @param {Stream} [args.stdin] The Readable stream to listen to
|
||
* @param {Stream} [args.stdout] The Writable stream to write readline data to
|
||
* @returns {Promise} Promise with user input
|
||
*/
|
||
$.date = args => toPrompt('DatePrompt', args);
|
||
|
||
/**
|
||
* Classic yes/no prompt
|
||
* @param {string} args.message Prompt message to display
|
||
* @param {boolean} [args.initial=false] Default value
|
||
* @param {function} [args.onState] On state change callback
|
||
* @param {Stream} [args.stdin] The Readable stream to listen to
|
||
* @param {Stream} [args.stdout] The Writable stream to write readline data to
|
||
* @returns {Promise} Promise with user input
|
||
*/
|
||
$.confirm = args => toPrompt('ConfirmPrompt', args);
|
||
|
||
/**
|
||
* List prompt, split intput string by `seperator`
|
||
* @param {string} args.message Prompt message to display
|
||
* @param {string} [args.initial] Default string value
|
||
* @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
|
||
* @param {string} [args.separator] String separator
|
||
* @param {function} [args.onState] On state change callback
|
||
* @param {Stream} [args.stdin] The Readable stream to listen to
|
||
* @param {Stream} [args.stdout] The Writable stream to write readline data to
|
||
* @returns {Promise} Promise with user input, in form of an `Array`
|
||
*/
|
||
$.list = args => {
|
||
const sep = args.separator || ',';
|
||
return toPrompt('TextPrompt', args, {
|
||
onSubmit: str => str.split(sep).map(s => s.trim())
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Toggle/switch prompt
|
||
* @param {string} args.message Prompt message to display
|
||
* @param {boolean} [args.initial=false] Default value
|
||
* @param {string} [args.active="on"] Text for `active` state
|
||
* @param {string} [args.inactive="off"] Text for `inactive` state
|
||
* @param {function} [args.onState] On state change callback
|
||
* @param {Stream} [args.stdin] The Readable stream to listen to
|
||
* @param {Stream} [args.stdout] The Writable stream to write readline data to
|
||
* @returns {Promise} Promise with user input
|
||
*/
|
||
$.toggle = args => toPrompt('TogglePrompt', args);
|
||
|
||
/**
|
||
* Interactive select prompt
|
||
* @param {string} args.message Prompt message to display
|
||
* @param {Array} args.choices Array of choices objects `[{ title, value }, ...]`
|
||
* @param {number} [args.initial] Index of default value
|
||
* @param {String} [args.hint] Hint to display
|
||
* @param {function} [args.onState] On state change callback
|
||
* @param {Stream} [args.stdin] The Readable stream to listen to
|
||
* @param {Stream} [args.stdout] The Writable stream to write readline data to
|
||
* @returns {Promise} Promise with user input
|
||
*/
|
||
$.select = args => toPrompt('SelectPrompt', args);
|
||
|
||
/**
|
||
* Interactive multi-select / autocompleteMultiselect prompt
|
||
* @param {string} args.message Prompt message to display
|
||
* @param {Array} args.choices Array of choices objects `[{ title, value, [selected] }, ...]`
|
||
* @param {number} [args.max] Max select
|
||
* @param {string} [args.hint] Hint to display user
|
||
* @param {Number} [args.cursor=0] Cursor start position
|
||
* @param {function} [args.onState] On state change callback
|
||
* @param {Stream} [args.stdin] The Readable stream to listen to
|
||
* @param {Stream} [args.stdout] The Writable stream to write readline data to
|
||
* @returns {Promise} Promise with user input
|
||
*/
|
||
$.multiselect = args => {
|
||
args.choices = [].concat(args.choices || []);
|
||
const toSelected = items => items.filter(item => item.selected).map(item => item.value);
|
||
return toPrompt('MultiselectPrompt', args, {
|
||
onAbort: toSelected,
|
||
onSubmit: toSelected
|
||
});
|
||
};
|
||
|
||
$.autocompleteMultiselect = args => {
|
||
args.choices = [].concat(args.choices || []);
|
||
const toSelected = items => items.filter(item => item.selected).map(item => item.value);
|
||
return toPrompt('AutocompleteMultiselectPrompt', args, {
|
||
onAbort: toSelected,
|
||
onSubmit: toSelected
|
||
});
|
||
};
|
||
|
||
const byTitle = (input, choices) => Promise.resolve(
|
||
choices.filter(item => item.title.slice(0, input.length).toLowerCase() === input.toLowerCase())
|
||
);
|
||
|
||
/**
|
||
* Interactive auto-complete prompt
|
||
* @param {string} args.message Prompt message to display
|
||
* @param {Array} args.choices Array of auto-complete choices objects `[{ title, value }, ...]`
|
||
* @param {Function} [args.suggest] Function to filter results based on user input. Defaults to sort by `title`
|
||
* @param {number} [args.limit=10] Max number of results to show
|
||
* @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
|
||
* @param {String} [args.initial] Index of the default value
|
||
* @param {boolean} [opts.clearFirst] The first ESCAPE keypress will clear the input
|
||
* @param {String} [args.fallback] Fallback message - defaults to initial value
|
||
* @param {function} [args.onState] On state change callback
|
||
* @param {Stream} [args.stdin] The Readable stream to listen to
|
||
* @param {Stream} [args.stdout] The Writable stream to write readline data to
|
||
* @returns {Promise} Promise with user input
|
||
*/
|
||
$.autocomplete = args => {
|
||
args.suggest = args.suggest || byTitle;
|
||
args.choices = [].concat(args.choices || []);
|
||
return toPrompt('AutocompletePrompt', args);
|
||
};
|
||
} (prompts$2));
|
||
return prompts$2;
|
||
}
|
||
|
||
var lib$1;
|
||
var hasRequiredLib$1;
|
||
|
||
function requireLib$1 () {
|
||
if (hasRequiredLib$1) return lib$1;
|
||
hasRequiredLib$1 = 1;
|
||
|
||
const prompts = requirePrompts$1();
|
||
|
||
const passOn = ['suggest', 'format', 'onState', 'validate', 'onRender', 'type'];
|
||
const noop = () => {};
|
||
|
||
/**
|
||
* Prompt for a series of questions
|
||
* @param {Array|Object} questions Single question object or Array of question objects
|
||
* @param {Function} [onSubmit] Callback function called on prompt submit
|
||
* @param {Function} [onCancel] Callback function called on cancel/abort
|
||
* @returns {Object} Object with values from user input
|
||
*/
|
||
async function prompt(questions=[], { onSubmit=noop, onCancel=noop }={}) {
|
||
const answers = {};
|
||
const override = prompt._override || {};
|
||
questions = [].concat(questions);
|
||
let answer, question, quit, name, type, lastPrompt;
|
||
|
||
const getFormattedAnswer = async (question, answer, skipValidation = false) => {
|
||
if (!skipValidation && question.validate && question.validate(answer) !== true) {
|
||
return;
|
||
}
|
||
return question.format ? await question.format(answer, answers) : answer
|
||
};
|
||
|
||
for (question of questions) {
|
||
({ name, type } = question);
|
||
|
||
// evaluate type first and skip if type is a falsy value
|
||
if (typeof type === 'function') {
|
||
type = await type(answer, { ...answers }, question);
|
||
question['type'] = type;
|
||
}
|
||
if (!type) continue;
|
||
|
||
// if property is a function, invoke it unless it's a special function
|
||
for (let key in question) {
|
||
if (passOn.includes(key)) continue;
|
||
let value = question[key];
|
||
question[key] = typeof value === 'function' ? await value(answer, { ...answers }, lastPrompt) : value;
|
||
}
|
||
|
||
lastPrompt = question;
|
||
|
||
if (typeof question.message !== 'string') {
|
||
throw new Error('prompt message is required');
|
||
}
|
||
|
||
// update vars in case they changed
|
||
({ name, type } = question);
|
||
|
||
if (prompts[type] === void 0) {
|
||
throw new Error(`prompt type (${type}) is not defined`);
|
||
}
|
||
|
||
if (override[question.name] !== undefined) {
|
||
answer = await getFormattedAnswer(question, override[question.name]);
|
||
if (answer !== undefined) {
|
||
answers[name] = answer;
|
||
continue;
|
||
}
|
||
}
|
||
|
||
try {
|
||
// Get the injected answer if there is one or prompt the user
|
||
answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : await prompts[type](question);
|
||
answers[name] = answer = await getFormattedAnswer(question, answer, true);
|
||
quit = await onSubmit(question, answer, answers);
|
||
} catch (err) {
|
||
quit = !(await onCancel(question, answers));
|
||
}
|
||
|
||
if (quit) return answers;
|
||
}
|
||
|
||
return answers;
|
||
}
|
||
|
||
function getInjectedAnswer(injected, deafultValue) {
|
||
const answer = injected.shift();
|
||
if (answer instanceof Error) {
|
||
throw answer;
|
||
}
|
||
|
||
return (answer === undefined) ? deafultValue : answer;
|
||
}
|
||
|
||
function inject(answers) {
|
||
prompt._injected = (prompt._injected || []).concat(answers);
|
||
}
|
||
|
||
function override(answers) {
|
||
prompt._override = Object.assign({}, answers);
|
||
}
|
||
|
||
lib$1 = Object.assign(prompt, { prompt, prompts, inject, override });
|
||
return lib$1;
|
||
}
|
||
|
||
var prompts$1;
|
||
var hasRequiredPrompts;
|
||
|
||
function requirePrompts () {
|
||
if (hasRequiredPrompts) return prompts$1;
|
||
hasRequiredPrompts = 1;
|
||
prompts$1 = requireLib$1();
|
||
return prompts$1;
|
||
}
|
||
|
||
var promptsExports = requirePrompts();
|
||
const prompts = /*@__PURE__*/getDefaultExportFromCjs(promptsExports);
|
||
|
||
/* globals WorkerGlobalScope, DedicatedWorkerGlobalScope, SharedWorkerGlobalScope, ServiceWorkerGlobalScope */
|
||
|
||
const isBrowser = globalThis.window?.document !== undefined;
|
||
|
||
globalThis.process?.versions?.node !== undefined;
|
||
|
||
globalThis.process?.versions?.bun !== undefined;
|
||
|
||
globalThis.Deno?.version?.deno !== undefined;
|
||
|
||
globalThis.process?.versions?.electron !== undefined;
|
||
|
||
globalThis.navigator?.userAgent?.includes('jsdom') === true;
|
||
|
||
typeof WorkerGlobalScope !== 'undefined' && globalThis instanceof WorkerGlobalScope;
|
||
|
||
typeof DedicatedWorkerGlobalScope !== 'undefined' && globalThis instanceof DedicatedWorkerGlobalScope;
|
||
|
||
typeof SharedWorkerGlobalScope !== 'undefined' && globalThis instanceof SharedWorkerGlobalScope;
|
||
|
||
typeof ServiceWorkerGlobalScope !== 'undefined' && globalThis instanceof ServiceWorkerGlobalScope;
|
||
|
||
// Note: I'm intentionally not DRYing up the other variables to keep them "lazy".
|
||
const platform = globalThis.navigator?.userAgentData?.platform;
|
||
|
||
platform === 'macOS'
|
||
|| globalThis.navigator?.platform === 'MacIntel' // Even on Apple silicon Macs.
|
||
|| globalThis.navigator?.userAgent?.includes(' Mac ') === true
|
||
|| globalThis.process?.platform === 'darwin';
|
||
|
||
platform === 'Windows'
|
||
|| globalThis.navigator?.platform === 'Win32'
|
||
|| globalThis.process?.platform === 'win32';
|
||
|
||
platform === 'Linux'
|
||
|| globalThis.navigator?.platform?.startsWith('Linux') === true
|
||
|| globalThis.navigator?.userAgent?.includes(' Linux ') === true
|
||
|| globalThis.process?.platform === 'linux';
|
||
|
||
platform === 'Android'
|
||
|| globalThis.navigator?.platform === 'Android'
|
||
|| globalThis.navigator?.userAgent?.includes(' Android ') === true
|
||
|| globalThis.process?.platform === 'android';
|
||
|
||
const OSC = '\u001B]';
|
||
const BEL = '\u0007';
|
||
const SEP = ';';
|
||
|
||
!isBrowser && process$1.env.TERM_PROGRAM === 'Apple_Terminal';
|
||
!isBrowser && process$1.platform === 'win32';
|
||
|
||
isBrowser ? () => {
|
||
throw new Error('`process.cwd()` only works in Node.js, not the browser.');
|
||
} : process$1.cwd;
|
||
|
||
const link = (text, url) => [
|
||
OSC,
|
||
'8',
|
||
SEP,
|
||
SEP,
|
||
url,
|
||
BEL,
|
||
text,
|
||
OSC,
|
||
'8',
|
||
SEP,
|
||
SEP,
|
||
BEL,
|
||
].join('');
|
||
|
||
var hasFlag;
|
||
var hasRequiredHasFlag;
|
||
|
||
function requireHasFlag () {
|
||
if (hasRequiredHasFlag) return hasFlag;
|
||
hasRequiredHasFlag = 1;
|
||
|
||
hasFlag = (flag, argv = process.argv) => {
|
||
const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--');
|
||
const position = argv.indexOf(prefix + flag);
|
||
const terminatorPosition = argv.indexOf('--');
|
||
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
||
};
|
||
return hasFlag;
|
||
}
|
||
|
||
var supportsColor_1;
|
||
var hasRequiredSupportsColor;
|
||
|
||
function requireSupportsColor () {
|
||
if (hasRequiredSupportsColor) return supportsColor_1;
|
||
hasRequiredSupportsColor = 1;
|
||
const os = require$$0$1;
|
||
const tty = require$$1;
|
||
const hasFlag = requireHasFlag();
|
||
|
||
const {env} = process;
|
||
|
||
let forceColor;
|
||
if (hasFlag('no-color') ||
|
||
hasFlag('no-colors') ||
|
||
hasFlag('color=false') ||
|
||
hasFlag('color=never')) {
|
||
forceColor = 0;
|
||
} else if (hasFlag('color') ||
|
||
hasFlag('colors') ||
|
||
hasFlag('color=true') ||
|
||
hasFlag('color=always')) {
|
||
forceColor = 1;
|
||
}
|
||
|
||
if ('FORCE_COLOR' in env) {
|
||
if (env.FORCE_COLOR === 'true') {
|
||
forceColor = 1;
|
||
} else if (env.FORCE_COLOR === 'false') {
|
||
forceColor = 0;
|
||
} else {
|
||
forceColor = env.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env.FORCE_COLOR, 10), 3);
|
||
}
|
||
}
|
||
|
||
function translateLevel(level) {
|
||
if (level === 0) {
|
||
return false;
|
||
}
|
||
|
||
return {
|
||
level,
|
||
hasBasic: true,
|
||
has256: level >= 2,
|
||
has16m: level >= 3
|
||
};
|
||
}
|
||
|
||
function supportsColor(haveStream, streamIsTTY) {
|
||
if (forceColor === 0) {
|
||
return 0;
|
||
}
|
||
|
||
if (hasFlag('color=16m') ||
|
||
hasFlag('color=full') ||
|
||
hasFlag('color=truecolor')) {
|
||
return 3;
|
||
}
|
||
|
||
if (hasFlag('color=256')) {
|
||
return 2;
|
||
}
|
||
|
||
if (haveStream && !streamIsTTY && forceColor === undefined) {
|
||
return 0;
|
||
}
|
||
|
||
const min = forceColor || 0;
|
||
|
||
if (env.TERM === 'dumb') {
|
||
return min;
|
||
}
|
||
|
||
if (process.platform === 'win32') {
|
||
// Windows 10 build 10586 is the first Windows release that supports 256 colors.
|
||
// Windows 10 build 14931 is the first release that supports 16m/TrueColor.
|
||
const osRelease = os.release().split('.');
|
||
if (
|
||
Number(osRelease[0]) >= 10 &&
|
||
Number(osRelease[2]) >= 10586
|
||
) {
|
||
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
if ('CI' in env) {
|
||
if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI', 'GITHUB_ACTIONS', 'BUILDKITE'].some(sign => sign in env) || env.CI_NAME === 'codeship') {
|
||
return 1;
|
||
}
|
||
|
||
return min;
|
||
}
|
||
|
||
if ('TEAMCITY_VERSION' in env) {
|
||
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
||
}
|
||
|
||
if (env.COLORTERM === 'truecolor') {
|
||
return 3;
|
||
}
|
||
|
||
if ('TERM_PROGRAM' in env) {
|
||
const version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10);
|
||
|
||
switch (env.TERM_PROGRAM) {
|
||
case 'iTerm.app':
|
||
return version >= 3 ? 3 : 2;
|
||
case 'Apple_Terminal':
|
||
return 2;
|
||
// No default
|
||
}
|
||
}
|
||
|
||
if (/-256(color)?$/i.test(env.TERM)) {
|
||
return 2;
|
||
}
|
||
|
||
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
||
return 1;
|
||
}
|
||
|
||
if ('COLORTERM' in env) {
|
||
return 1;
|
||
}
|
||
|
||
return min;
|
||
}
|
||
|
||
function getSupportLevel(stream) {
|
||
const level = supportsColor(stream, stream && stream.isTTY);
|
||
return translateLevel(level);
|
||
}
|
||
|
||
supportsColor_1 = {
|
||
supportsColor: getSupportLevel,
|
||
stdout: translateLevel(supportsColor(true, tty.isatty(1))),
|
||
stderr: translateLevel(supportsColor(true, tty.isatty(2)))
|
||
};
|
||
return supportsColor_1;
|
||
}
|
||
|
||
var supportsHyperlinks$1;
|
||
var hasRequiredSupportsHyperlinks;
|
||
|
||
function requireSupportsHyperlinks () {
|
||
if (hasRequiredSupportsHyperlinks) return supportsHyperlinks$1;
|
||
hasRequiredSupportsHyperlinks = 1;
|
||
const supportsColor = requireSupportsColor();
|
||
const hasFlag = requireHasFlag();
|
||
|
||
/**
|
||
@param {string} versionString
|
||
@returns {{ major: number, minor: number, patch: number }}
|
||
*/
|
||
function parseVersion(versionString) {
|
||
if (/^\d{3,4}$/.test(versionString)) {
|
||
// Env var doesn't always use dots. example: 4601 => 46.1.0
|
||
const m = /(\d{1,2})(\d{2})/.exec(versionString) || [];
|
||
return {
|
||
major: 0,
|
||
minor: parseInt(m[1], 10),
|
||
patch: parseInt(m[2], 10)
|
||
};
|
||
}
|
||
|
||
const versions = (versionString || '').split('.').map(n => parseInt(n, 10));
|
||
return {
|
||
major: versions[0],
|
||
minor: versions[1],
|
||
patch: versions[2]
|
||
};
|
||
}
|
||
|
||
/**
|
||
@param {{ isTTY?: boolean | undefined }} stream
|
||
@returns {boolean}
|
||
*/
|
||
// eslint-disable-next-line complexity
|
||
function supportsHyperlink(stream) {
|
||
const {
|
||
CI,
|
||
FORCE_HYPERLINK,
|
||
NETLIFY,
|
||
TEAMCITY_VERSION,
|
||
TERM_PROGRAM,
|
||
TERM_PROGRAM_VERSION,
|
||
VTE_VERSION,
|
||
TERM,
|
||
} = process.env;
|
||
|
||
if (FORCE_HYPERLINK) {
|
||
return !(FORCE_HYPERLINK.length > 0 && parseInt(FORCE_HYPERLINK, 10) === 0);
|
||
}
|
||
|
||
if (hasFlag('no-hyperlink') || hasFlag('no-hyperlinks') || hasFlag('hyperlink=false') || hasFlag('hyperlink=never')) {
|
||
return false;
|
||
}
|
||
|
||
if (hasFlag('hyperlink=true') || hasFlag('hyperlink=always')) {
|
||
return true;
|
||
}
|
||
|
||
// Netlify does not run a TTY, it does not need `supportsColor` check
|
||
if (NETLIFY) {
|
||
return true;
|
||
}
|
||
|
||
// If they specify no colors, they probably don't want hyperlinks.
|
||
if (!supportsColor.supportsColor(stream)) {
|
||
return false;
|
||
}
|
||
|
||
if (stream && !stream.isTTY) {
|
||
return false;
|
||
}
|
||
|
||
// Windows Terminal
|
||
if ('WT_SESSION' in process.env) {
|
||
return true;
|
||
}
|
||
|
||
if (process.platform === 'win32') {
|
||
return false;
|
||
}
|
||
|
||
if (CI) {
|
||
return false;
|
||
}
|
||
|
||
if (TEAMCITY_VERSION) {
|
||
return false;
|
||
}
|
||
|
||
if (TERM_PROGRAM) {
|
||
const version = parseVersion(TERM_PROGRAM_VERSION || '');
|
||
|
||
switch (TERM_PROGRAM) {
|
||
case 'iTerm.app':
|
||
if (version.major === 3) {
|
||
return version.minor >= 1;
|
||
}
|
||
|
||
return version.major > 3;
|
||
case 'WezTerm':
|
||
return version.major >= 20200620;
|
||
case 'vscode':
|
||
// eslint-disable-next-line no-mixed-operators
|
||
return version.major > 1 || version.major === 1 && version.minor >= 72;
|
||
case 'ghostty':
|
||
return true;
|
||
// No default
|
||
}
|
||
}
|
||
|
||
if (VTE_VERSION) {
|
||
// 0.50.0 was supposed to support hyperlinks, but throws a segfault
|
||
if (VTE_VERSION === '0.50.0') {
|
||
return false;
|
||
}
|
||
|
||
const version = parseVersion(VTE_VERSION);
|
||
return version.major > 0 || version.minor >= 50;
|
||
}
|
||
|
||
switch (TERM) {
|
||
case 'alacritty':
|
||
// Support added in v0.11 (2022-10-13)
|
||
return true;
|
||
// No default
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
supportsHyperlinks$1 = {
|
||
supportsHyperlink,
|
||
stdout: supportsHyperlink(process.stdout),
|
||
stderr: supportsHyperlink(process.stderr)
|
||
};
|
||
return supportsHyperlinks$1;
|
||
}
|
||
|
||
var supportsHyperlinksExports = /*@__PURE__*/ requireSupportsHyperlinks();
|
||
const supportsHyperlinks = /*@__PURE__*/getDefaultExportFromCjs(supportsHyperlinksExports);
|
||
|
||
function terminalLink(text, url, {target = 'stdout', ...options} = {}) {
|
||
if (!supportsHyperlinks[target]) {
|
||
// If the fallback has been explicitly disabled, don't modify the text itself.
|
||
if (options.fallback === false) {
|
||
return text;
|
||
}
|
||
|
||
return typeof options.fallback === 'function' ? options.fallback(text, url) : `${text} (\u200B${url}\u200B)`;
|
||
}
|
||
|
||
return link(text, url);
|
||
}
|
||
|
||
terminalLink.isSupported = supportsHyperlinks.stdout;
|
||
terminalLink.stderr = (text, url, options = {}) => terminalLink(text, url, {target: 'stderr', ...options});
|
||
terminalLink.stderr.isSupported = supportsHyperlinks.stderr;
|
||
|
||
var cjs = {};
|
||
|
||
var posix = {};
|
||
|
||
var hasRequiredPosix;
|
||
|
||
function requirePosix () {
|
||
if (hasRequiredPosix) return posix;
|
||
hasRequiredPosix = 1;
|
||
/**
|
||
* This is the Posix implementation of isexe, which uses the file
|
||
* mode and uid/gid values.
|
||
*
|
||
* @module
|
||
*/
|
||
Object.defineProperty(posix, "__esModule", { value: true });
|
||
posix.sync = posix.isexe = void 0;
|
||
const fs_1 = require$$0$2;
|
||
const promises_1 = require$$1$1;
|
||
/**
|
||
* Determine whether a path is executable according to the mode and
|
||
* current (or specified) user and group IDs.
|
||
*/
|
||
const isexe = async (path, options = {}) => {
|
||
const { ignoreErrors = false } = options;
|
||
try {
|
||
return checkStat(await (0, promises_1.stat)(path), options);
|
||
}
|
||
catch (e) {
|
||
const er = e;
|
||
if (ignoreErrors || er.code === 'EACCES')
|
||
return false;
|
||
throw er;
|
||
}
|
||
};
|
||
posix.isexe = isexe;
|
||
/**
|
||
* Synchronously determine whether a path is executable according to
|
||
* the mode and current (or specified) user and group IDs.
|
||
*/
|
||
const sync = (path, options = {}) => {
|
||
const { ignoreErrors = false } = options;
|
||
try {
|
||
return checkStat((0, fs_1.statSync)(path), options);
|
||
}
|
||
catch (e) {
|
||
const er = e;
|
||
if (ignoreErrors || er.code === 'EACCES')
|
||
return false;
|
||
throw er;
|
||
}
|
||
};
|
||
posix.sync = sync;
|
||
const checkStat = (stat, options) => stat.isFile() && checkMode(stat, options);
|
||
const checkMode = (stat, options) => {
|
||
const myUid = options.uid ?? process.getuid?.();
|
||
const myGroups = options.groups ?? process.getgroups?.() ?? [];
|
||
const myGid = options.gid ?? process.getgid?.() ?? myGroups[0];
|
||
if (myUid === undefined || myGid === undefined) {
|
||
throw new Error('cannot get uid or gid');
|
||
}
|
||
const groups = new Set([myGid, ...myGroups]);
|
||
const mod = stat.mode;
|
||
const uid = stat.uid;
|
||
const gid = stat.gid;
|
||
const u = parseInt('100', 8);
|
||
const g = parseInt('010', 8);
|
||
const o = parseInt('001', 8);
|
||
const ug = u | g;
|
||
return !!(mod & o ||
|
||
(mod & g && groups.has(gid)) ||
|
||
(mod & u && uid === myUid) ||
|
||
(mod & ug && myUid === 0));
|
||
};
|
||
|
||
return posix;
|
||
}
|
||
|
||
var win32 = {};
|
||
|
||
var hasRequiredWin32;
|
||
|
||
function requireWin32 () {
|
||
if (hasRequiredWin32) return win32;
|
||
hasRequiredWin32 = 1;
|
||
/**
|
||
* This is the Windows implementation of isexe, which uses the file
|
||
* extension and PATHEXT setting.
|
||
*
|
||
* @module
|
||
*/
|
||
Object.defineProperty(win32, "__esModule", { value: true });
|
||
win32.sync = win32.isexe = void 0;
|
||
const fs_1 = require$$0$2;
|
||
const promises_1 = require$$1$1;
|
||
/**
|
||
* Determine whether a path is executable based on the file extension
|
||
* and PATHEXT environment variable (or specified pathExt option)
|
||
*/
|
||
const isexe = async (path, options = {}) => {
|
||
const { ignoreErrors = false } = options;
|
||
try {
|
||
return checkStat(await (0, promises_1.stat)(path), path, options);
|
||
}
|
||
catch (e) {
|
||
const er = e;
|
||
if (ignoreErrors || er.code === 'EACCES')
|
||
return false;
|
||
throw er;
|
||
}
|
||
};
|
||
win32.isexe = isexe;
|
||
/**
|
||
* Synchronously determine whether a path is executable based on the file
|
||
* extension and PATHEXT environment variable (or specified pathExt option)
|
||
*/
|
||
const sync = (path, options = {}) => {
|
||
const { ignoreErrors = false } = options;
|
||
try {
|
||
return checkStat((0, fs_1.statSync)(path), path, options);
|
||
}
|
||
catch (e) {
|
||
const er = e;
|
||
if (ignoreErrors || er.code === 'EACCES')
|
||
return false;
|
||
throw er;
|
||
}
|
||
};
|
||
win32.sync = sync;
|
||
const checkPathExt = (path, options) => {
|
||
const { pathExt = process.env.PATHEXT || '' } = options;
|
||
const peSplit = pathExt.split(';');
|
||
if (peSplit.indexOf('') !== -1) {
|
||
return true;
|
||
}
|
||
for (let i = 0; i < peSplit.length; i++) {
|
||
const p = peSplit[i].toLowerCase();
|
||
const ext = path.substring(path.length - p.length).toLowerCase();
|
||
if (p && ext === p) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
};
|
||
const checkStat = (stat, path, options) => stat.isFile() && checkPathExt(path, options);
|
||
|
||
return win32;
|
||
}
|
||
|
||
var options = {};
|
||
|
||
var hasRequiredOptions;
|
||
|
||
function requireOptions () {
|
||
if (hasRequiredOptions) return options;
|
||
hasRequiredOptions = 1;
|
||
Object.defineProperty(options, "__esModule", { value: true });
|
||
|
||
return options;
|
||
}
|
||
|
||
var hasRequiredCjs;
|
||
|
||
function requireCjs () {
|
||
if (hasRequiredCjs) return cjs;
|
||
hasRequiredCjs = 1;
|
||
(function (exports) {
|
||
var __createBinding = (cjs && cjs.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||
if (k2 === undefined) k2 = k;
|
||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||
}
|
||
Object.defineProperty(o, k2, desc);
|
||
}) : (function(o, m, k, k2) {
|
||
if (k2 === undefined) k2 = k;
|
||
o[k2] = m[k];
|
||
}));
|
||
var __setModuleDefault = (cjs && cjs.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||
}) : function(o, v) {
|
||
o["default"] = v;
|
||
});
|
||
var __importStar = (cjs && cjs.__importStar) || function (mod) {
|
||
if (mod && mod.__esModule) return mod;
|
||
var result = {};
|
||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||
__setModuleDefault(result, mod);
|
||
return result;
|
||
};
|
||
var __exportStar = (cjs && cjs.__exportStar) || function(m, exports) {
|
||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||
};
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
exports.sync = exports.isexe = exports.posix = exports.win32 = void 0;
|
||
const posix = __importStar(requirePosix());
|
||
exports.posix = posix;
|
||
const win32 = __importStar(requireWin32());
|
||
exports.win32 = win32;
|
||
__exportStar(requireOptions(), exports);
|
||
const platform = process.env._ISEXE_TEST_PLATFORM_ || process.platform;
|
||
const impl = platform === 'win32' ? win32 : posix;
|
||
/**
|
||
* Determine whether a path is executable on the current platform.
|
||
*/
|
||
exports.isexe = impl.isexe;
|
||
/**
|
||
* Synchronously determine whether a path is executable on the
|
||
* current platform.
|
||
*/
|
||
exports.sync = impl.sync;
|
||
|
||
} (cjs));
|
||
return cjs;
|
||
}
|
||
|
||
var lib;
|
||
var hasRequiredLib;
|
||
|
||
function requireLib () {
|
||
if (hasRequiredLib) return lib;
|
||
hasRequiredLib = 1;
|
||
const { isexe, sync: isexeSync } = requireCjs();
|
||
const { join, delimiter, sep, posix } = require$$1$2;
|
||
|
||
const isWindows = process.platform === 'win32';
|
||
|
||
// used to check for slashed in commands passed in. always checks for the posix
|
||
// seperator on all platforms, and checks for the current separator when not on
|
||
// a posix platform. don't use the isWindows check for this since that is mocked
|
||
// in tests but we still need the code to actually work when called. that is also
|
||
// why it is ignored from coverage.
|
||
/* istanbul ignore next */
|
||
const rSlash = new RegExp(`[${posix.sep}${sep === posix.sep ? '' : sep}]`.replace(/(\\)/g, '\\$1'));
|
||
const rRel = new RegExp(`^\\.${rSlash.source}`);
|
||
|
||
const getNotFoundError = (cmd) =>
|
||
Object.assign(new Error(`not found: ${cmd}`), { code: 'ENOENT' });
|
||
|
||
const getPathInfo = (cmd, {
|
||
path: optPath = process.env.PATH,
|
||
pathExt: optPathExt = process.env.PATHEXT,
|
||
delimiter: optDelimiter = delimiter,
|
||
}) => {
|
||
// If it has a slash, then we don't bother searching the pathenv.
|
||
// just check the file itself, and that's it.
|
||
const pathEnv = cmd.match(rSlash) ? [''] : [
|
||
// windows always checks the cwd first
|
||
...(isWindows ? [process.cwd()] : []),
|
||
...(optPath || /* istanbul ignore next: very unusual */ '').split(optDelimiter),
|
||
];
|
||
|
||
if (isWindows) {
|
||
const pathExtExe = optPathExt ||
|
||
['.EXE', '.CMD', '.BAT', '.COM'].join(optDelimiter);
|
||
const pathExt = pathExtExe.split(optDelimiter).flatMap((item) => [item, item.toLowerCase()]);
|
||
if (cmd.includes('.') && pathExt[0] !== '') {
|
||
pathExt.unshift('');
|
||
}
|
||
return { pathEnv, pathExt, pathExtExe }
|
||
}
|
||
|
||
return { pathEnv, pathExt: [''] }
|
||
};
|
||
|
||
const getPathPart = (raw, cmd) => {
|
||
const pathPart = /^".*"$/.test(raw) ? raw.slice(1, -1) : raw;
|
||
const prefix = !pathPart && rRel.test(cmd) ? cmd.slice(0, 2) : '';
|
||
return prefix + join(pathPart, cmd)
|
||
};
|
||
|
||
const which = async (cmd, opt = {}) => {
|
||
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
|
||
const found = [];
|
||
|
||
for (const envPart of pathEnv) {
|
||
const p = getPathPart(envPart, cmd);
|
||
|
||
for (const ext of pathExt) {
|
||
const withExt = p + ext;
|
||
const is = await isexe(withExt, { pathExt: pathExtExe, ignoreErrors: true });
|
||
if (is) {
|
||
if (!opt.all) {
|
||
return withExt
|
||
}
|
||
found.push(withExt);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (opt.all && found.length) {
|
||
return found
|
||
}
|
||
|
||
if (opt.nothrow) {
|
||
return null
|
||
}
|
||
|
||
throw getNotFoundError(cmd)
|
||
};
|
||
|
||
const whichSync = (cmd, opt = {}) => {
|
||
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
|
||
const found = [];
|
||
|
||
for (const pathEnvPart of pathEnv) {
|
||
const p = getPathPart(pathEnvPart, cmd);
|
||
|
||
for (const ext of pathExt) {
|
||
const withExt = p + ext;
|
||
const is = isexeSync(withExt, { pathExt: pathExtExe, ignoreErrors: true });
|
||
if (is) {
|
||
if (!opt.all) {
|
||
return withExt
|
||
}
|
||
found.push(withExt);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (opt.all && found.length) {
|
||
return found
|
||
}
|
||
|
||
if (opt.nothrow) {
|
||
return null
|
||
}
|
||
|
||
throw getNotFoundError(cmd)
|
||
};
|
||
|
||
lib = which;
|
||
which.sync = whichSync;
|
||
return lib;
|
||
}
|
||
|
||
var libExports = requireLib();
|
||
const which = /*@__PURE__*/getDefaultExportFromCjs(libExports);
|
||
|
||
const CLI_TEMP_DIR = join(os.tmpdir(), "antfu-ni");
|
||
function remove(arr, v) {
|
||
const index = arr.indexOf(v);
|
||
if (index >= 0)
|
||
arr.splice(index, 1);
|
||
return arr;
|
||
}
|
||
function exclude(arr, ...v) {
|
||
return arr.slice().filter((item) => !v.includes(item));
|
||
}
|
||
function cmdExists(cmd) {
|
||
return which.sync(cmd, { nothrow: true }) !== null;
|
||
}
|
||
let counter = 0;
|
||
async function openTemp() {
|
||
if (!existsSync(CLI_TEMP_DIR))
|
||
await promises.mkdir(CLI_TEMP_DIR, { recursive: true });
|
||
const competitivePath = join(CLI_TEMP_DIR, `.${process$1.pid}.${counter}`);
|
||
counter += 1;
|
||
return promises.open(competitivePath, "wx").then((fd) => ({
|
||
fd,
|
||
path: competitivePath,
|
||
cleanup() {
|
||
fd.close().then(() => {
|
||
if (existsSync(competitivePath))
|
||
promises.unlink(competitivePath);
|
||
});
|
||
}
|
||
})).catch((error) => {
|
||
if (error && error.code === "EEXIST")
|
||
return openTemp();
|
||
else
|
||
return void 0;
|
||
});
|
||
}
|
||
async function writeFileSafe(path, data = "") {
|
||
const temp = await openTemp();
|
||
if (temp) {
|
||
promises.writeFile(temp.path, data).then(() => {
|
||
const directory = dirname(path);
|
||
if (!existsSync(directory))
|
||
promises.mkdir(directory, { recursive: true });
|
||
return promises.rename(temp.path, path).then(() => true).catch(() => false);
|
||
}).catch(() => false).finally(temp.cleanup);
|
||
}
|
||
return false;
|
||
}
|
||
function limitText(text, maxWidth) {
|
||
if (text.length <= maxWidth)
|
||
return text;
|
||
return `${text.slice(0, maxWidth)}${c.dim("\u2026")}`;
|
||
}
|
||
function formatPackageWithUrl(pkg, url, limits = 80) {
|
||
return url ? terminalLink(
|
||
pkg,
|
||
url,
|
||
{
|
||
fallback: (_, url2) => pkg.length + url2.length > limits ? pkg : pkg + c.dim` - ${url2}`
|
||
}
|
||
) : pkg;
|
||
}
|
||
|
||
async function detect({ autoInstall, programmatic, cwd } = {}) {
|
||
const {
|
||
name,
|
||
agent,
|
||
version
|
||
} = await detect$1({
|
||
cwd,
|
||
onUnknown: (packageManager) => {
|
||
if (!programmatic) {
|
||
console.warn("[ni] Unknown packageManager:", packageManager);
|
||
}
|
||
return void 0;
|
||
}
|
||
}) || {};
|
||
if (name && !cmdExists(name) && !programmatic) {
|
||
if (!autoInstall) {
|
||
console.warn(`[ni] Detected ${name} but it doesn't seem to be installed.
|
||
`);
|
||
if (process$1.env.CI)
|
||
process$1.exit(1);
|
||
const link = terminalLink(name, INSTALL_PAGE[name]);
|
||
const { tryInstall } = await prompts({
|
||
name: "tryInstall",
|
||
type: "confirm",
|
||
message: `Would you like to globally install ${link}?`
|
||
});
|
||
if (!tryInstall)
|
||
process$1.exit(1);
|
||
}
|
||
await x(
|
||
"npm",
|
||
["i", "-g", `${name}${version ? `@${version}` : ""}`],
|
||
{
|
||
nodeOptions: {
|
||
stdio: "inherit",
|
||
cwd
|
||
},
|
||
throwOnError: true
|
||
}
|
||
);
|
||
}
|
||
return agent;
|
||
}
|
||
|
||
const customRcPath = process$1.env.NI_CONFIG_FILE;
|
||
const home = process$1.platform === "win32" ? process$1.env.USERPROFILE : process$1.env.HOME;
|
||
const defaultRcPath = path.join(home || "~/", ".nirc");
|
||
const rcPath = customRcPath || defaultRcPath;
|
||
const defaultConfig = {
|
||
defaultAgent: "prompt",
|
||
globalAgent: "npm"
|
||
};
|
||
let config;
|
||
async function getConfig() {
|
||
if (!config) {
|
||
config = Object.assign(
|
||
{},
|
||
defaultConfig,
|
||
fs.existsSync(rcPath) ? ini.parse(fs.readFileSync(rcPath, "utf-8")) : null
|
||
);
|
||
if (process$1.env.NI_DEFAULT_AGENT)
|
||
config.defaultAgent = process$1.env.NI_DEFAULT_AGENT;
|
||
if (process$1.env.NI_GLOBAL_AGENT)
|
||
config.globalAgent = process$1.env.NI_GLOBAL_AGENT;
|
||
const agent = await detect({ programmatic: true });
|
||
if (agent)
|
||
config.defaultAgent = agent;
|
||
}
|
||
return config;
|
||
}
|
||
async function getDefaultAgent(programmatic) {
|
||
const { defaultAgent } = await getConfig();
|
||
if (defaultAgent === "prompt" && (programmatic || process$1.env.CI))
|
||
return "npm";
|
||
return defaultAgent;
|
||
}
|
||
async function getGlobalAgent() {
|
||
const { globalAgent } = await getConfig();
|
||
return globalAgent;
|
||
}
|
||
|
||
class UnsupportedCommand extends Error {
|
||
constructor({ agent, command }) {
|
||
super(`Command "${command}" is not support by agent "${agent}"`);
|
||
}
|
||
}
|
||
function getCommand(agent, command, args = []) {
|
||
if (!COMMANDS[agent])
|
||
throw new Error(`Unsupported agent "${agent}"`);
|
||
if (!COMMANDS[agent][command])
|
||
throw new UnsupportedCommand({ agent, command });
|
||
return constructCommand(COMMANDS[agent][command], args);
|
||
}
|
||
const parseNi = (agent, args, ctx) => {
|
||
if (agent === "bun")
|
||
args = args.map((i) => i === "-D" ? "-d" : i);
|
||
if (agent === "npm")
|
||
args = args.map((i) => i === "-P" ? "--omit=dev" : i);
|
||
if (args.includes("-P"))
|
||
args = args.map((i) => i === "-P" ? "--production" : i);
|
||
if (args.includes("-g"))
|
||
return getCommand(agent, "global", exclude(args, "-g"));
|
||
if (args.includes("--frozen-if-present")) {
|
||
args = exclude(args, "--frozen-if-present");
|
||
return getCommand(agent, ctx?.hasLock ? "frozen" : "install", args);
|
||
}
|
||
if (args.includes("--frozen"))
|
||
return getCommand(agent, "frozen", exclude(args, "--frozen"));
|
||
if (args.length === 0 || args.every((i) => i.startsWith("-")))
|
||
return getCommand(agent, "install", args);
|
||
return getCommand(agent, "add", args);
|
||
};
|
||
const parseNr = (agent, args) => {
|
||
if (args.length === 0)
|
||
args.push("start");
|
||
let hasIfPresent = false;
|
||
if (args.includes("--if-present")) {
|
||
args = exclude(args, "--if-present");
|
||
hasIfPresent = true;
|
||
}
|
||
const cmd = getCommand(agent, "run", args);
|
||
if (!cmd)
|
||
return cmd;
|
||
if (hasIfPresent)
|
||
cmd.args.splice(1, 0, "--if-present");
|
||
return cmd;
|
||
};
|
||
const parseNup = (agent, args) => {
|
||
if (args.includes("-i"))
|
||
return getCommand(agent, "upgrade-interactive", exclude(args, "-i"));
|
||
return getCommand(agent, "upgrade", args);
|
||
};
|
||
const parseNun = (agent, args) => {
|
||
if (args.includes("-g"))
|
||
return getCommand(agent, "global_uninstall", exclude(args, "-g"));
|
||
return getCommand(agent, "uninstall", args);
|
||
};
|
||
const parseNlx = (agent, args) => {
|
||
return getCommand(agent, "execute", args);
|
||
};
|
||
const parseNa = (agent, args) => {
|
||
return getCommand(agent, "agent", args);
|
||
};
|
||
function serializeCommand(command) {
|
||
if (!command)
|
||
return void 0;
|
||
if (command.args.length === 0)
|
||
return command.command;
|
||
return `${command.command} ${command.args.map((i) => i.includes(" ") ? `"${i}"` : i).join(" ")}`;
|
||
}
|
||
|
||
const version = "25.0.0";
|
||
|
||
const DEFAULT_ENVIRONMENT_OPTIONS = {
|
||
autoInstall: false
|
||
};
|
||
function getEnvironmentOptions() {
|
||
return {
|
||
...DEFAULT_ENVIRONMENT_OPTIONS,
|
||
autoInstall: process$1.env.NI_AUTO_INSTALL === "true"
|
||
};
|
||
}
|
||
|
||
const DEBUG_SIGN = "?";
|
||
async function runCli(fn, options = {}) {
|
||
options = {
|
||
...getEnvironmentOptions(),
|
||
...options
|
||
};
|
||
const {
|
||
args = process$1.argv.slice(2).filter(Boolean)
|
||
} = options;
|
||
try {
|
||
await run(fn, args, options);
|
||
} catch (error) {
|
||
if (error instanceof UnsupportedCommand && !options.programmatic)
|
||
console.log(c.red(`\u2717 ${error.message}`));
|
||
if (!options.programmatic)
|
||
process$1.exit(1);
|
||
throw error;
|
||
}
|
||
}
|
||
async function getCliCommand(fn, args, options = {}, cwd = options.cwd ?? process$1.cwd()) {
|
||
const isGlobal = args.includes("-g");
|
||
if (isGlobal)
|
||
return await fn(await getGlobalAgent(), args);
|
||
let agent = await detect({ ...options, cwd }) || await getDefaultAgent(options.programmatic);
|
||
if (agent === "prompt") {
|
||
agent = (await prompts({
|
||
name: "agent",
|
||
type: "select",
|
||
message: "Choose the agent",
|
||
choices: AGENTS.filter((i) => !i.includes("@")).map((value) => ({ title: value, value }))
|
||
})).agent;
|
||
if (!agent)
|
||
return;
|
||
}
|
||
return await fn(agent, args, {
|
||
programmatic: options.programmatic,
|
||
hasLock: Boolean(agent),
|
||
cwd
|
||
});
|
||
}
|
||
async function run(fn, args, options = {}) {
|
||
const {
|
||
detectVolta = true
|
||
} = options;
|
||
const debug = args.includes(DEBUG_SIGN);
|
||
if (debug)
|
||
remove(args, DEBUG_SIGN);
|
||
let cwd = options.cwd ?? process$1.cwd();
|
||
if (args[0] === "-C") {
|
||
cwd = resolve(cwd, args[1]);
|
||
args.splice(0, 2);
|
||
}
|
||
if (args.length === 1 && (args[0]?.toLowerCase() === "-v" || args[0] === "--version")) {
|
||
const getCmd = (a) => AGENTS.includes(a) ? getCommand(a, "agent", ["-v"]) : { command: a, args: ["-v"] };
|
||
const xVersionOptions = {
|
||
nodeOptions: {
|
||
cwd
|
||
},
|
||
throwOnError: true
|
||
};
|
||
const getV = (a) => {
|
||
const { command: command2, args: args2 } = getCmd(a);
|
||
return x(command2, args2, xVersionOptions).then((e) => e.stdout).then((e) => e.startsWith("v") ? e : `v${e}`);
|
||
};
|
||
const globalAgentPromise = getGlobalAgent();
|
||
const globalAgentVersionPromise = globalAgentPromise.then(getV);
|
||
const agentPromise = detect({ ...options, cwd }).then((a) => a || "");
|
||
const agentVersionPromise = agentPromise.then((a) => a && getV(a));
|
||
const nodeVersionPromise = getV("node");
|
||
console.log(`@antfu/ni ${c.cyan`v${version}`}`);
|
||
console.log(`node ${c.green(await nodeVersionPromise)}`);
|
||
const [agent, agentVersion] = await Promise.all([agentPromise, agentVersionPromise]);
|
||
if (agent)
|
||
console.log(`${agent.padEnd(10)} ${c.blue(agentVersion)}`);
|
||
else
|
||
console.log("agent no lock file");
|
||
const [globalAgent, globalAgentVersion] = await Promise.all([globalAgentPromise, globalAgentVersionPromise]);
|
||
console.log(`${`${globalAgent} -g`.padEnd(10)} ${c.blue(globalAgentVersion)}`);
|
||
return;
|
||
}
|
||
if (args.length === 1 && ["-h", "--help"].includes(args[0])) {
|
||
const dash = c.dim("-");
|
||
console.log(c.green.bold("@antfu/ni") + c.dim` use the right package manager v${version}\n`);
|
||
console.log(`ni ${dash} install`);
|
||
console.log(`nr ${dash} run`);
|
||
console.log(`nlx ${dash} execute`);
|
||
console.log(`nup ${dash} upgrade`);
|
||
console.log(`nun ${dash} uninstall`);
|
||
console.log(`nci ${dash} clean install`);
|
||
console.log(`na ${dash} agent alias`);
|
||
console.log(`ni -v ${dash} show used agent`);
|
||
console.log(`ni -i ${dash} interactive package management`);
|
||
console.log(c.yellow("\ncheck https://github.com/antfu/ni for more documentation."));
|
||
return;
|
||
}
|
||
const command = await getCliCommand(fn, args, options, cwd);
|
||
if (!command)
|
||
return;
|
||
if (detectVolta && cmdExists("volta")) {
|
||
command.args = ["run", command.command, ...command.args];
|
||
command.command = "volta";
|
||
}
|
||
if (debug) {
|
||
const commandStr = [command.command, ...command.args].join(" ");
|
||
console.log(commandStr);
|
||
return;
|
||
}
|
||
await x(
|
||
command.command,
|
||
command.args,
|
||
{
|
||
nodeOptions: {
|
||
stdio: "inherit",
|
||
cwd
|
||
},
|
||
throwOnError: true
|
||
}
|
||
);
|
||
}
|
||
|
||
export { CLI_TEMP_DIR as C, UnsupportedCommand as U, getDefaultAgent as a, getGlobalAgent as b, getCommand as c, detect as d, parseNr as e, parseNup as f, getConfig as g, parseNun as h, parseNlx as i, parseNa as j, getCliCommand as k, run as l, remove as m, exclude as n, cmdExists as o, parseNi as p, limitText as q, runCli as r, serializeCommand as s, formatPackageWithUrl as t, prompts as u, writeFileSafe as w };
|