Leo Lamprecht
7 years ago
52 changed files with 107 additions and 587 deletions
@ -1,4 +1,4 @@ |
|||
const error = require('../output/error') |
|||
const error = require('../../../../util/output/error') |
|||
|
|||
module.exports = function(err) { |
|||
switch (err.code) { |
@ -1,79 +0,0 @@ |
|||
const inquirer = require('inquirer') |
|||
const stripAnsi = require('strip-ansi') |
|||
|
|||
// eslint-disable-next-line import/no-unassigned-import
|
|||
require('./patch-inquirer') |
|||
|
|||
function getLength(string) { |
|||
let biggestLength = 0 |
|||
string.split('\n').map(str => { |
|||
str = stripAnsi(str) |
|||
if (str.length > biggestLength) { |
|||
biggestLength = str.length |
|||
} |
|||
return undefined |
|||
}) |
|||
return biggestLength |
|||
} |
|||
|
|||
module.exports = async function({ |
|||
message = 'the question', |
|||
// eslint-disable-line no-unused-vars
|
|||
choices = [ |
|||
{ |
|||
name: 'something\ndescription\ndetails\netc', |
|||
value: 'something unique', |
|||
short: 'generally the first line of `name`' |
|||
} |
|||
], |
|||
pageSize = 15, // Show 15 lines without scrolling (~4 credit cards)
|
|||
separator = true, // Puts a blank separator between each choice
|
|||
abort = 'end' // Wether the `abort` option will be at the `start` or the `end`
|
|||
}) { |
|||
let biggestLength = 0 |
|||
|
|||
choices = choices.map(choice => { |
|||
if (choice.name) { |
|||
const length = getLength(choice.name) |
|||
if (length > biggestLength) { |
|||
biggestLength = length |
|||
} |
|||
return choice |
|||
} |
|||
throw new Error('Invalid choice') |
|||
}) |
|||
|
|||
if (separator === true) { |
|||
choices = choices.reduce( |
|||
(prev, curr) => prev.concat(new inquirer.Separator(' '), curr), |
|||
[] |
|||
) |
|||
} |
|||
|
|||
const abortSeparator = new inquirer.Separator('─'.repeat(biggestLength)) |
|||
const _abort = { |
|||
name: 'Abort', |
|||
value: undefined |
|||
} |
|||
|
|||
if (abort === 'start') { |
|||
const blankSep = choices.shift() |
|||
choices.unshift(abortSeparator) |
|||
choices.unshift(_abort) |
|||
choices.unshift(blankSep) |
|||
} else { |
|||
choices.push(abortSeparator) |
|||
choices.push(_abort) |
|||
} |
|||
|
|||
const nonce = Date.now() |
|||
const answer = await inquirer.prompt({ |
|||
name: nonce, |
|||
type: 'list', |
|||
message, |
|||
choices, |
|||
pageSize |
|||
}) |
|||
|
|||
return answer[nonce] |
|||
} |
@ -1,20 +0,0 @@ |
|||
const inquirer = require('inquirer') |
|||
const chalk = require('chalk') |
|||
|
|||
// Here we patch inquirer to use a `>` instead of the ugly green `?`
|
|||
|
|||
/* eslint-disable no-multiple-empty-lines, no-var, no-undef, no-eq-null, eqeqeq, semi */ |
|||
const getQuestion = function() { |
|||
var message = chalk.bold('> ' + this.opt.message) + ' ' |
|||
|
|||
// Append the default if available, and if question isn't answered
|
|||
if (this.opt.default != null && this.status !== 'answered') { |
|||
message += chalk.dim('(' + this.opt.default + ') ') |
|||
} |
|||
|
|||
return message |
|||
} |
|||
/* eslint-enable */ |
|||
|
|||
inquirer.prompt.prompts.input.prototype.getQuestion = getQuestion |
|||
inquirer.prompt.prompts.list.prototype.getQuestion = getQuestion |
@ -1,58 +0,0 @@ |
|||
const chalk = require('chalk') |
|||
|
|||
module.exports = ( |
|||
label, |
|||
{ |
|||
defaultValue = false, |
|||
abortSequences = new Set(['\u0003']), |
|||
resolveChars = new Set(['\r']), |
|||
yesChar = 'y', |
|||
noChar = 'n', |
|||
stdin = process.stdin, |
|||
stdout = process.stdout, |
|||
trailing = '' |
|||
} = {} |
|||
) => { |
|||
return new Promise(resolve => { |
|||
const isRaw = stdin.isRaw |
|||
|
|||
stdin.setRawMode(true) |
|||
stdin.resume() |
|||
|
|||
function restore() { |
|||
stdout.write(trailing) |
|||
stdin.setRawMode(isRaw) |
|||
stdin.pause() |
|||
stdin.removeListener('data', onData) |
|||
} |
|||
|
|||
function onData(buffer) { |
|||
const data = buffer.toString() |
|||
|
|||
if (data[0].toLowerCase() === yesChar) { |
|||
restore() |
|||
resolve(true) |
|||
} else if (data[0].toLowerCase() === noChar) { |
|||
restore() |
|||
resolve(false) |
|||
} else if (abortSequences.has(data)) { |
|||
restore() |
|||
resolve(false) |
|||
} else if (resolveChars.has(data[0])) { |
|||
restore() |
|||
resolve(defaultValue) |
|||
} else { |
|||
// ignore extraneous input
|
|||
} |
|||
} |
|||
|
|||
const defaultText = |
|||
defaultValue === null |
|||
? `[${yesChar}|${noChar}]` |
|||
: defaultValue |
|||
? `[${chalk.bold(yesChar.toUpperCase())}|${noChar}]` |
|||
: `[${yesChar}|${chalk.bold(noChar.toUpperCase())}]` |
|||
stdout.write(`${chalk.gray('>')} ${label} ${chalk.gray(defaultText)} `) |
|||
stdin.on('data', onData) |
|||
}) |
|||
} |
@ -1,262 +0,0 @@ |
|||
// Packages
|
|||
const ansiEscapes = require('ansi-escapes') |
|||
const ansiRegex = require('ansi-regex') |
|||
const chalk = require('chalk') |
|||
const stripAnsi = require('strip-ansi') |
|||
|
|||
// Utilities
|
|||
const eraseLines = require('../output/erase-lines') |
|||
|
|||
const ESCAPES = { |
|||
LEFT: '\u001B[D', |
|||
RIGHT: '\u001B[C', |
|||
CTRL_C: '\u0003', |
|||
BACKSPACE: '\u0008', |
|||
CTRL_H: '\u007F', |
|||
CARRIAGE: '\r' |
|||
} |
|||
|
|||
const formatCC = data => { |
|||
return data.replace(/\s/g, '').replace(/(.{4})/g, '$1 ').trim() |
|||
} |
|||
|
|||
module.exports = function( |
|||
{ |
|||
label = '', |
|||
initialValue = '', |
|||
// If false, the `- label` will be printed as `✖ label` in red
|
|||
// Until the first keypress
|
|||
valid = true, |
|||
// Can be:
|
|||
// - `false`, which does nothing
|
|||
// - `cc`, for credit cards
|
|||
// - `date`, for dates in the mm / yyyy format
|
|||
mask = false, |
|||
placeholder = '', |
|||
abortSequences = new Set(['\x03']), |
|||
eraseSequences = new Set([ESCAPES.BACKSPACE, ESCAPES.CTRL_H]), |
|||
resolveChars = new Set([ESCAPES.CARRIAGE]), |
|||
stdin = process.stdin, |
|||
stdout = process.stdout, |
|||
// Char to print before resolving/rejecting the promise
|
|||
// If `false`, nothing will be printed
|
|||
trailing = ansiEscapes.eraseLines(1), |
|||
// Gets called on each keypress;
|
|||
// `data` contains the current keypress;
|
|||
// `futureValue` contains the current value + the
|
|||
// Keypress in the correct place
|
|||
validateKeypress = (data, futureValue) => true, // eslint-disable-line no-unused-vars
|
|||
// Get's called before the promise is resolved
|
|||
// Returning `false` here will prevent the user from submiting the value
|
|||
validateValue = data => true, // eslint-disable-line no-unused-vars
|
|||
// Receives the value of the input and should return a string
|
|||
// Or false if no autocomplion is available
|
|||
autoComplete = value => false, // eslint-disable-line no-unused-vars
|
|||
// Tab
|
|||
// Right arrow
|
|||
autoCompleteChars = new Set(['\t', '\x1b[C']), |
|||
// If true, converts everything the user types to to lowercase
|
|||
forceLowerCase = false |
|||
} = {} |
|||
) { |
|||
return new Promise((resolve, reject) => { |
|||
const isRaw = process.stdin.isRaw |
|||
|
|||
let value |
|||
let caretOffset = 0 |
|||
let regex |
|||
let suggestion = '' |
|||
|
|||
if (valid) { |
|||
stdout.write(label) |
|||
} else { |
|||
const _label = label.replace('-', '✖') |
|||
stdout.write(chalk.red(_label)) |
|||
} |
|||
|
|||
value = initialValue |
|||
stdout.write(initialValue) |
|||
|
|||
if (mask) { |
|||
if (!value) { |
|||
value = chalk.gray(placeholder) |
|||
caretOffset = 0 - stripAnsi(value).length |
|||
stdout.write(value) |
|||
stdout.write(ansiEscapes.cursorBackward(Math.abs(caretOffset))) |
|||
} |
|||
|
|||
regex = placeholder |
|||
.split('') |
|||
.reduce((prev, curr) => { |
|||
if (curr !== ' ' && !prev.includes(curr)) { |
|||
if (curr === '/') { |
|||
prev.push(' / ') |
|||
} else { |
|||
prev.push(curr) |
|||
} |
|||
} |
|||
return prev |
|||
}, []) |
|||
.join('|') |
|||
regex = new RegExp(`(${regex})`, 'g') |
|||
} |
|||
|
|||
stdin.setRawMode(true) |
|||
stdin.resume() |
|||
|
|||
function restore() { |
|||
stdin.setRawMode(isRaw) |
|||
stdin.pause() |
|||
stdin.removeListener('data', onData) |
|||
if (trailing) { |
|||
stdout.write(trailing) |
|||
} |
|||
} |
|||
|
|||
async function onData(buffer) { |
|||
let data = buffer.toString() |
|||
|
|||
value = stripAnsi(value) |
|||
|
|||
if (abortSequences.has(data)) { |
|||
restore() |
|||
return reject(new Error('USER_ABORT')) |
|||
} |
|||
|
|||
if (forceLowerCase) { |
|||
data = data.toLowerCase() |
|||
} |
|||
|
|||
if (suggestion !== '' && !caretOffset && autoCompleteChars.has(data)) { |
|||
value += stripAnsi(suggestion) |
|||
suggestion = '' |
|||
} else if (data === ESCAPES.LEFT) { |
|||
if (value.length > Math.abs(caretOffset)) { |
|||
caretOffset-- |
|||
} |
|||
} else if (data === ESCAPES.RIGHT) { |
|||
if (caretOffset < 0) { |
|||
caretOffset++ |
|||
} |
|||
} else if (eraseSequences.has(data)) { |
|||
let char |
|||
if (mask && value.length > Math.abs(caretOffset)) { |
|||
if (value[value.length + caretOffset - 1] === ' ') { |
|||
if (value[value.length + caretOffset - 2] === '/') { |
|||
caretOffset -= 1 |
|||
} |
|||
char = placeholder[value.length + caretOffset] |
|||
value = |
|||
value.substr(0, value.length + caretOffset - 2) + |
|||
char + |
|||
value.substr(value.length + caretOffset - 1) |
|||
caretOffset-- |
|||
} else { |
|||
char = placeholder[value.length + caretOffset - 1] |
|||
value = |
|||
value.substr(0, value.length + caretOffset - 1) + |
|||
char + |
|||
value.substr(value.length + caretOffset) |
|||
} |
|||
caretOffset-- |
|||
} else { |
|||
value = |
|||
value.substr(0, value.length + caretOffset - 1) + |
|||
value.substr(value.length + caretOffset) |
|||
} |
|||
suggestion = '' |
|||
} else if (resolveChars.has(data)) { |
|||
if (validateValue(value)) { |
|||
restore() |
|||
resolve(value) |
|||
} else { |
|||
if (mask === 'cc' || mask === 'ccv') { |
|||
value = formatCC(value) |
|||
value = value.replace(regex, chalk.gray('$1')) |
|||
} else if (mask === 'expDate') { |
|||
value = value.replace(regex, chalk.gray('$1')) |
|||
} |
|||
|
|||
const l = chalk.red(label.replace('-', '✖')) |
|||
eraseLines(1) |
|||
stdout.write(l + value + ansiEscapes.beep) |
|||
if (caretOffset) { |
|||
process.stdout.write( |
|||
ansiEscapes.cursorBackward(Math.abs(caretOffset)) |
|||
) |
|||
} |
|||
} |
|||
return |
|||
} else if (!ansiRegex().test(data)) { |
|||
let tmp = |
|||
value.substr(0, value.length + caretOffset) + |
|||
data + |
|||
value.substr(value.length + caretOffset) |
|||
|
|||
if (mask) { |
|||
if (/\d/.test(data) && caretOffset !== 0) { |
|||
let formattedData = data |
|||
|
|||
if (mask === 'cc' || mask === 'ccv') { |
|||
formattedData = formatCC(data) |
|||
} |
|||
|
|||
if (value[value.length + caretOffset + 1] === ' ') { |
|||
tmp = |
|||
value.substr(0, value.length + caretOffset) + |
|||
formattedData + |
|||
value.substr(value.length + caretOffset + formattedData.length) |
|||
|
|||
caretOffset += formattedData.length + 1 |
|||
|
|||
if (value[value.length + caretOffset] === '/') { |
|||
caretOffset += formattedData.length + 1 |
|||
} |
|||
} else { |
|||
tmp = |
|||
value.substr(0, value.length + caretOffset) + |
|||
formattedData + |
|||
value.substr(value.length + caretOffset + formattedData.length) |
|||
|
|||
caretOffset += formattedData.length |
|||
} |
|||
} else if (/\s/.test(data) && caretOffset < 0) { |
|||
caretOffset++ |
|||
tmp = value |
|||
} else { |
|||
return stdout.write(ansiEscapes.beep) |
|||
} |
|||
value = tmp |
|||
} else if (validateKeypress(data, value)) { |
|||
value = tmp |
|||
if (caretOffset === 0) { |
|||
const completion = await autoComplete(value) |
|||
if (completion) { |
|||
suggestion = chalk.gray(completion) |
|||
suggestion += ansiEscapes.cursorBackward(completion.length) |
|||
} else { |
|||
suggestion = '' |
|||
} |
|||
} |
|||
} else { |
|||
return stdout.write(ansiEscapes.beep) |
|||
} |
|||
} |
|||
|
|||
if (mask === 'cc' || mask === 'ccv') { |
|||
value = formatCC(value) |
|||
value = value.replace(regex, chalk.gray('$1')) |
|||
} else if (mask === 'expDate') { |
|||
value = value.replace(regex, chalk.gray('$1')) |
|||
} |
|||
|
|||
eraseLines(1) |
|||
stdout.write(label + value + suggestion) |
|||
if (caretOffset) { |
|||
process.stdout.write(ansiEscapes.cursorBackward(Math.abs(caretOffset))) |
|||
} |
|||
} |
|||
|
|||
stdin.on('data', onData) |
|||
}) |
|||
} |
@ -1,3 +0,0 @@ |
|||
module.exports = { |
|||
tick: '✓' |
|||
} |
@ -1,6 +0,0 @@ |
|||
const chalk = require('chalk') |
|||
|
|||
// The equivalent of <code>, for embedding a cmd
|
|||
// eg: Please run ${cmd(woot)}
|
|||
|
|||
module.exports = cmd => `${chalk.gray('`')}${chalk.cyan(cmd)}${chalk.gray('`')}` |
@ -1,3 +0,0 @@ |
|||
const ansiEscapes = require('ansi-escapes') |
|||
|
|||
module.exports = n => process.stdout.write(ansiEscapes.eraseLines(n)) |
@ -1,9 +0,0 @@ |
|||
const chalk = require('chalk') |
|||
|
|||
// Prints an error message
|
|||
module.exports = msg => { |
|||
if (msg.message) { |
|||
msg = msg.message |
|||
} |
|||
console.error(`${chalk.red('> Error!')} ${msg}`) |
|||
} |
@ -1,6 +0,0 @@ |
|||
const chalk = require('chalk') |
|||
|
|||
// Prints an informational message
|
|||
module.exports = msg => { |
|||
console.log(`${chalk.gray('>')} ${msg}`) |
|||
} |
@ -1 +0,0 @@ |
|||
module.exports = process.platform === 'win32' ? 'Δ' : '𝚫' |
@ -1,6 +0,0 @@ |
|||
const chalk = require('chalk') |
|||
|
|||
// Prints a note
|
|||
module.exports = msg => { |
|||
console.log(`${chalk.yellow('> NOTE:')} ${msg}`) |
|||
} |
@ -1,7 +0,0 @@ |
|||
const chalk = require('chalk') |
|||
|
|||
// Returns a user param in a nice formatting
|
|||
// e.g.: google.com -> "google.com" (in bold)
|
|||
|
|||
module.exports = param => |
|||
chalk.bold(`${chalk.gray('"')}${chalk.bold(param)}${chalk.gray('"')}`) |
@ -1,6 +0,0 @@ |
|||
const chalk = require('chalk') |
|||
|
|||
// Prints a success message
|
|||
module.exports = msg => { |
|||
console.log(`${chalk.cyan('> Success!')} ${msg}`) |
|||
} |
@ -1,15 +0,0 @@ |
|||
const ora = require('ora') |
|||
const chalk = require('chalk') |
|||
const { eraseLine } = require('ansi-escapes') |
|||
|
|||
// Prints a spinner followed by the given text
|
|||
module.exports = msg => { |
|||
const spinner = ora(chalk.gray(msg)) |
|||
spinner.color = 'gray' |
|||
spinner.start() |
|||
|
|||
return () => { |
|||
spinner.stop() |
|||
process.stdout.write(eraseLine) |
|||
} |
|||
} |
@ -1,3 +1,4 @@ |
|||
// Packages
|
|||
const chalk = require('chalk') |
|||
|
|||
// The equivalent of <code>, for embedding anything
|
Loading…
Reference in new issue