Socket
Socket
Sign inDemoInstall

enquirer

Package Overview
Dependencies
1
Maintainers
2
Versions
37
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.0.7 to 2.0.8

index.d.ts

29

CHANGELOG.md

@@ -36,5 +36,29 @@ # Release history

## 3.0.0 - 2018-11-14
### Fixed
- `validate` function now properly accepts `false` as a return value, thanks to [@g-plane](https://github.com/g-plane).
### Removed
- `hSelect` and `hMultiSelect` (horizontal select and multiselect) have been removed and moved over to the [recipes](recipes) folder. If you need these prompts and want to see how to re-create the functionality, you will find examples in [recipes/examples](recipes/examples).
### Changed
- `ctrl+d` is now mapped to `deleteForward` instead of `cancel`.
### Added
- Adds support for <kbd>ctrl</kbd>+<kbd>n</kbd> to add choices
- Adds support for `options.required` on all prompts. Uses the built-in `validate()` function, allowing this functionality to be overridden or customized.
- Adds support for `options.scroll` to disable scrolling in array prompts.
- Adds support for `options.onRun`, which is called when `prompt.run()` is called, after the readline instance is created.
- Adds support for `options.history` on the `Input` and `Text` prompts.
- Adds support for `options.term` to set the terminal, thanks to [@tunnckoCore](https://github.com/tunnckoCore). At the moment this is only used in a couple of edge cases with the `Survey` and `Scale` prompts to check if the terminal is Hyper.
- `options.skip` may now be a Boolean, thanks to [@tunnckoCore](https://github.com/tunnckoCore)
## 2.0.0 - 2018-11-07
**What changed in Enquirer 2.0?**
### Changed

@@ -47,5 +71,2 @@ Enquire 2.0 is a bottom-up complete re-write:

- Methods for registering "questions" have been removed. While it was nice to be able to preregister questions that could be called upon later, this is something that is better left to implementors, as it's relatively trivial to do with custom code.
### Changed
- `options.default` is now `options.initial`

@@ -52,0 +73,0 @@

48

index.js

@@ -23,3 +23,3 @@ 'use strict';

super();
this.options = { ...options };
this.options = utils.merge({}, options);
this.answers = { ...answers };

@@ -83,4 +83,8 @@ }

for (let question of [].concat(questions)) {
let opts = { ...this.options, ...question };
if (typeof question === 'function') {
question = await question.call(this);
}
let opts = utils.merge({}, this.options, question);
let { type, name } = question;

@@ -98,2 +102,3 @@ if (typeof type === 'function') type = await type.call(this, question);

this.emit('prompt', prompt, this.answers);
prompt.state.answers = this.answers;

@@ -107,13 +112,15 @@ if (opts.autofill && value != null) {

if (opts.skip && await opts.skip(state)) {
let skipped = typeof opts.skip === 'function'
? await opts.skip(state)
: opts.skip === true;
if (skipped) {
continue;
}
prompt.state.answers = this.answers;
// bubble events
let emit = prompt.emit.bind(prompt);
let emit = prompt.emit;
prompt.emit = (...args) => {
this.emit(...args.concat(state));
return emit(...args);
this.emit(...args);
return emit.call(prompt, ...args);
};

@@ -124,3 +131,2 @@

if (name) this.answers[name] = value;
cancel = opts.onSubmit && await opts.onSubmit(name, value, prompt);

@@ -161,13 +167,2 @@ } catch (err) {

submit(value, state) {
this.submitted = true;
this.emit('submit', value, state);
this.emit('answer', state.prompt.name, value, state);
}
cancel(error, state) {
this.cancelled = true;
this.emit('cancel', error, state);
}
state(prompt, question) {

@@ -219,4 +214,4 @@ let state = { prompt, question, answers: this.answers };

static get prompt() {
const fn = (questions, onSubmit, onCancel) => {
let enquirer = new this({ onSubmit, onCancel });
const fn = (questions, ...rest) => {
let enquirer = new this(...rest);
let emit = enquirer.emit.bind(enquirer);

@@ -249,2 +244,11 @@ enquirer.emit = (...args) => {

const exp = name => {
utils.defineExport(Enquirer, name, () => Enquirer.types[name]);
};
exp('ArrayPrompt');
exp('BooleanPrompt');
exp('NumberPrompt');
exp('StringPrompt');
module.exports = Enquirer;

@@ -11,10 +11,13 @@ 'use strict';

a: 'first',
b: 'left',
b: 'backward',
c: 'cancel',
d: 'cancel',
d: 'deleteForward',
e: 'last',
f: 'right',
f: 'forward',
g: 'reset',
i: 'tab',
k: 'cutForward',
l: 'reset',
n: 'newItem',
m: 'cancel',
j: 'submit',

@@ -24,3 +27,6 @@ p: 'search',

s: 'save',
u: 'undo'
u: 'undo',
w: 'cutLeft',
x: 'toggleCursor',
v: 'paste'
},

@@ -46,2 +52,6 @@

option: {
b: 'backward',
f: 'forward',
d: 'cutRight',
left: 'cutLeft',
up: 'altUp',

@@ -48,0 +58,0 @@ down: 'altDown'

@@ -154,3 +154,3 @@ 'use strict';

if (error === false) {
return 'Invalid fields ' + item.name;
return 'Invalid field ' + item.name;
}

@@ -182,4 +182,4 @@ return error;

let error = await validate(state.values[key], state, item, index);
if (error && typeof error === 'string') {
state.invalid.add(key);
if ((error && typeof error === 'string') || error === false) {
state.invalid.set(key, error);
continue;

@@ -204,5 +204,2 @@ }

} else if (submitted) {
value = '';
} else {

@@ -262,3 +259,2 @@ state.values[key] = void 0;

state.output = lines.join('\n');
return state.output;

@@ -273,7 +269,4 @@ };

}
if (typeof options[prop] === 'function') {
return options[prop].call(prompt, value, state, item, index);
}
return fallback || value;
return [fallback, value].find(v => prompt.isValue(v));
};
}

@@ -19,9 +19,15 @@ 'use strict';

module.exports = (prompt, input = '', initial = '', pos, showCursor = true, color) => {
module.exports = (prompt, options = {}) => {
prompt.cursorHide();
let { input = '', initial = '', pos, showCursor = true, color } = options;
let style = color || prompt.styles.placeholder;
let inverse = utils.inverse(prompt.styles.primary);
let reverse = str => inverse(colors.black(str));
let output = input;
if (showCursor && pos === 0 && (input === initial || input === '')) {
return reverse(initial[0]) + style(initial.slice(1));
}
initial = utils.isPrimitive(initial) ? `${initial}` : '';

@@ -31,6 +37,6 @@ input = utils.isPrimitive(input) ? `${input}` : '';

let placeholder = initial && initial.startsWith(input) && initial !== input;
let cursor = placeholder ? inverse(colors.black(initial[input.length])) : inverse(' ');
let cursor = placeholder ? reverse(initial[input.length]) : inverse(' ');
if (pos !== input.length && showCursor === true) {
output = input.slice(0, pos) + inverse(colors.black(input[pos])) + input.slice(pos + 1);
output = input.slice(0, pos) + reverse(input[pos]) + input.slice(pos + 1);
cursor = '';

@@ -37,0 +43,0 @@ }

@@ -34,13 +34,14 @@ 'use strict';

this.render = (this.options.render || this.render).bind(this);
this.term = process.env.TERM_PROGRAM;
this.term = this.options.term || process.env.TERM_PROGRAM;
this.setMaxListeners(0);
}
async keypress(ch, event = {}) {
let key = keypress.action(ch, keypress(ch, event), this.options.actions);
async keypress(char, event = {}) {
let key = keypress.action(char, keypress(char, event), this.options.actions);
this.state.keypress = key;
this.emit('keypress', char, key);
this.emit('state', this.state.clone());
let fn = this.options[key.action] || this[key.action] || this.dispatch;
if (typeof fn === 'function') {
return fn.call(this, ch, key);
return fn.call(this, char, key);
}

@@ -118,3 +119,10 @@ this.alert();

if (result !== true) {
let error = this.symbols.pointer + ' ' + (typeof result === 'string' ? result.trim() : 'Invalid input');
let error = '\n' + this.symbols.pointer + ' ';
if (typeof result === 'string') {
error += result.trim();
} else {
error += 'Invalid input';
}
this.state.error = '\n' + this.styles.danger(error);

@@ -130,3 +138,3 @@ this.state.submitted = false;

this.state.validating = false;
this.value = this.result(this.value);
this.value = await this.result(this.value);
await this.render();

@@ -137,7 +145,7 @@ await this.close();

async cancel() {
async cancel(err) {
this.state.cancelled = this.state.submitted = true;
await this.render();
await this.close();
this.emit('cancel', await this.error());
this.emit('cancel', await this.error(err));
}

@@ -181,5 +189,6 @@

return new Promise(async(resolve, reject) => {
this.once('submit', resolve);
this.once('cancel', reject);
this.once('submit', resolve);
await this.initialize();
if (this.options.onRun) await this.options.onRun.call(this);
this.emit('run');

@@ -198,5 +207,5 @@ });

let res = await utils.resolve(state, val, state, choice, i);
let res = await this.resolve(val, state, choice, i);
if (!res && choice && choice[name]) {
return utils.resolve(state, value, state, choice, i);
return this.resolve(value, state, choice, i);
}

@@ -233,3 +242,3 @@ return res;

let value = element[state.status] || element.pending || state.separator;
let ele = await utils.resolve(state, value, state);
let ele = await this.resolve(value, state);
if (utils.isObject(ele)) ele = ele[state.status] || ele.pending;

@@ -261,7 +270,5 @@ if (!utils.hasColor(ele)) {

let val = await this.element('indicator', choice, i);
if (typeof val === 'string' && utils.hasColor(val)) {
return val;
}
if (val) {

@@ -274,3 +281,2 @@ let styles = this.styles;

}
return '';

@@ -305,4 +311,4 @@ }

error() {
return !this.state.submitted ? this.state.error : '';
error(err) {
return !this.state.submitted ? (err || this.state.error) : '';
}

@@ -318,3 +324,6 @@

validate() {
validate(value) {
if (this.options.required === true) {
return this.isValue(value);
}
return true;

@@ -321,0 +330,0 @@ }

@@ -35,3 +35,3 @@ 'use strict';

let { cursor, input } = this.state;
this.state.input = input.slice(0, cursor) + ch + input.slice(cursor);
this.input = input.slice(0, cursor) + ch + input.slice(cursor);
this.moveCursor(1);

@@ -44,3 +44,3 @@ return this.complete();

if (!input) return this.alert();
this.state.input = input.slice(0, cursor - 1) + input.slice(cursor);
this.input = input.slice(0, cursor - 1) + input.slice(cursor);
this.moveCursor(-1);

@@ -53,3 +53,3 @@ return this.complete();

if (input[cursor] === void 0) return this.alert();
this.state.input = `${input}`.slice(0, cursor) + `${input}`.slice(cursor + 1);
this.input = `${input}`.slice(0, cursor) + `${input}`.slice(cursor + 1);
return this.complete();

@@ -60,3 +60,3 @@ }

this.completing = true;
this.choices = await this.suggest(this.state.input, this.state._choices);
this.choices = await this.suggest(this.input, this.state._choices);
this.state.limit = void 0; // allow getter/setter to reset limit

@@ -68,7 +68,8 @@ this.index = Math.min(Math.max(this.visible.length - 1, 0), this.index);

suggest(input = this.state.input, choices = this.state._choices) {
suggest(input = this.input, choices = this.state._choices) {
if (typeof this.options.suggest === 'function') {
return this.options.suggest.call(this, input, choices);
}
return choices.filter(ch => ch.message.toLowerCase().includes(input.toLowerCase()));
let str = input.toLowerCase();
return choices.filter(ch => ch.message.toLowerCase().includes(str));
}

@@ -86,6 +87,6 @@

if (this.state.submitted) {
let value = this.value = this.state.input = this.focused.value;
let value = this.value = this.input = this.focused.value;
return this.styles.primary(value);
}
return this.state.input;
return this.input;
}

@@ -96,3 +97,3 @@

let style = this.options.highlight || this.styles.placeholder;
let color = highlight(this.state.input, style);
let color = highlight(this.input, style);
let choices = this.choices;

@@ -99,0 +100,0 @@ this.choices = choices.map(ch => ({ ...ch, message: color(ch.message) }));

@@ -10,3 +10,3 @@ 'use strict';

super({ ...options, multiple: true });
this.align = this.options.align || 'left';
this.align = [this.options.align, 'left'].find(v => v != null);
this.emptyError = '';

@@ -46,3 +46,3 @@ this.values = {};

async indicator(choice, i) {
let symbol = choice.indicator || (choice.input ? '⦿' : '⊙');
let symbol = choice.indicator || '';
let value = choice.editable ? symbol : super.indicator(choice, i);

@@ -58,5 +58,3 @@ return await this.resolve(value, this.state, choice, i) || '';

choice.indent = '';
if (choice.editable) {
return form.renderChoice.call(this, choice, i);
}
if (choice.editable) return form.renderChoice.call(this, choice, i);
return super.renderChoice(choice, i);

@@ -66,3 +64,9 @@ }

submit() {
if (this.focused.newChoice === true) return super.submit();
if (this.choices.some(ch => ch.newChoice)) {
return this.alert();
}
this.value = {};
for (let choice of this.choices) {

@@ -69,0 +73,0 @@ let val = choice.parent ? this.value[choice.parent.name] : this.value;

@@ -12,3 +12,3 @@ 'use strict';

this.initial = this.options.initial;
this.align = this.options.align || 'right';
this.align = [this.options.align, 'right'].find(v => v != null);
this.emptyError = '';

@@ -27,12 +27,12 @@ this.values = {};

dispatch(ch) {
return !!ch && this.append(ch);
dispatch(char) {
return !!char && this.append(char);
}
append(s) {
let ch = this.focused;
if (!ch) return this.alert();
let { cursor, input } = ch;
ch.value = ch.input = input.slice(0, cursor) + s + input.slice(cursor);
ch.cursor++;
append(char) {
let choice = this.focused;
if (!choice) return this.alert();
let { cursor, input } = choice;
choice.value = choice.input = input.slice(0, cursor) + char + input.slice(cursor);
choice.cursor++;
return this.render();

@@ -42,7 +42,7 @@ }

delete() {
let ch = this.focused;
if (!ch || ch.cursor <= 0) return this.alert();
let { cursor, input } = ch;
ch.value = ch.input = input.slice(0, cursor - 1) + input.slice(cursor);
ch.cursor--;
let choice = this.focused;
if (!choice || choice.cursor <= 0) return this.alert();
let { cursor, input } = choice;
choice.value = choice.input = input.slice(0, cursor - 1) + input.slice(cursor);
choice.cursor--;
return this.render();

@@ -52,8 +52,8 @@ }

deleteForward() {
let ch = this.focused;
if (!ch) return this.alert();
let { cursor, input } = ch;
let choice = this.focused;
if (!choice) return this.alert();
let { cursor, input } = choice;
if (input[cursor] === void 0) return this.alert();
let str = `${input}`.slice(0, cursor) + `${input}`.slice(cursor + 1);
ch.value = ch.input = str;
choice.value = choice.input = str;
return this.render();

@@ -63,6 +63,6 @@ }

right() {
let ch = this.focused;
if (!ch) return this.alert();
if (ch.cursor >= ch.input.length) return this.alert();
ch.cursor++;
let choice = this.focused;
if (!choice) return this.alert();
if (choice.cursor >= choice.input.length) return this.alert();
choice.cursor++;
return this.render();

@@ -72,6 +72,6 @@ }

left() {
let ch = this.focused;
if (!ch) return this.alert();
if (ch.cursor <= 0) return this.alert();
ch.cursor--;
let choice = this.focused;
if (!choice) return this.alert();
if (choice.cursor <= 0) return this.alert();
choice.cursor--;
return this.render();

@@ -125,7 +125,12 @@ }

async choiceSeparator(choice, i) {
let sep = await this.resolve(choice.separator, this.state, choice, i) || ':';
return sep ? ' ' + this.styles.disabled(sep) : '';
}
async renderChoice(choice, i) {
await this.onChoice(choice, i);
let { state, styles, symbols } = this;
let { cursor, initial = '', name, hint, input = '', separator } = choice;
let { state, styles } = this;
let { cursor, initial = '', name, hint, input = '' } = choice;
let { muted, submitted, primary, danger } = styles;

@@ -136,13 +141,8 @@

let validate = choice.validate || (() => true);
let sep = separator || ' ' + this.styles.disabled(symbols.middot);
let sep = await this.choiceSeparator(choice, i);
let msg = choice.message;
if (this.align === 'right') {
msg = msg.padStart(this.longest + 1, ' ');
}
if (this.align === 'right') msg = msg.padStart(this.longest + 1, ' ');
if (this.align === 'left') msg = msg.padEnd(this.longest + 1, ' ');
if (this.align === 'left') {
msg = msg.padEnd(this.longest + 1, ' ');
}
// re-populate the form values (answers) object

@@ -159,6 +159,2 @@ let value = this.values[name] = (input || initial);

if (!input && initial) {
input = !state.submitted ? muted(initial) : initial;
}
let indent = this.indent(choice);

@@ -174,5 +170,18 @@ let line = () => [indent, indicator, msg + sep, input, help].filter(Boolean).join(' ');

input = placeholder(this, choice.input, initial, cursor, focused, this.styles.muted);
if (!input) input = this.styles.muted(this.symbols.ellipsis);
if (choice.format) {
input = await choice.format.call(this, input, choice, i);
} else {
let color = this.styles.muted;
let options = { input, initial, pos: cursor, showCursor: focused, color };
input = placeholder(this, options);
}
if (!this.isValue(input)) {
input = this.styles.muted(this.symbols.ellipsis);
}
if (choice.result) {
this.values[name] = await choice.result.call(this, value, choice, i);
}
if (focused) {

@@ -179,0 +188,0 @@ msg = primary(msg);

'use strict';
const utils = require('../utils');
const define = (key, fn) => {

@@ -11,8 +12,6 @@ utils.defineExport(exports, key, fn);

define('Confirm', () => require('./confirm'));
define('Editable', () => require('./editable'));
define('Form', () => require('./form'));
define('hMultiSelect', () => require('./hmultiselect'));
define('hSelect', () => require('./hselect'));
define('Input', () => require('./input'));
define('Invisible', () => require('./invisible'));
define('MultiScale', () => require('./multiscale'));
define('List', () => require('./list'));

@@ -22,2 +21,3 @@ define('MultiSelect', () => require('./multiselect'));

define('Password', () => require('./password'));
define('Scale', () => require('./scale'));
define('Select', () => require('./select'));

@@ -24,0 +24,0 @@ define('Snippet', () => require('./snippet'));

@@ -1,1 +0,55 @@

module.exports = require('../types/string');
'use strict';
const Prompt = require('../types/string');
const completer = require('../completer');
class Input extends Prompt {
constructor(options) {
super(options);
let history = this.options.history;
if (history && history.store) {
let initial = history.values || this.initial;
this.autosave = !!history.autosave;
this.store = history.store;
this.data = this.store.get('values') || { past: [], present: initial };
this.initial = this.data.present || this.data.past[this.data.past.length - 1];
}
}
completion(action) {
if (!this.store) return this.alert();
this.data = completer(action, this.data, this.input);
if (!this.data.present) return this.alert();
this.input = this.data.present;
this.cursor = this.input.length;
return this.render();
}
altUp() {
return this.completion('prev');
}
altDown() {
return this.completion('next');
}
prev() {
this.save();
return super.prev();
}
save() {
if (!this.store) return;
this.data = completer('save', this.data, this.input);
this.store.set('values', this.data);
}
submit() {
if (this.store && this.autosave === true) {
this.save();
}
return super.submit();
}
}
module.exports = Input;

@@ -19,7 +19,4 @@ 'use strict';

indicator(item, i) {
return this.multiple ? super.indicator(item, i) : '';
}
separator() {
if (this.options.separator) return super.separator();
let sep = this.styles.muted(this.symbols.ellipsis);

@@ -29,17 +26,32 @@ return this.state.submitted ? super.separator() : sep;

pointer(item, i) {
return (!this.multiple || this.options.pointer) ? super.pointer(item, i) : '';
pointer(choice, i) {
return (!this.multiple || this.options.pointer) ? super.pointer(choice, i) : '';
}
heading(msg, item, i) {
return this.styles.strong(msg);
indicator(choice, i) {
return this.multiple ? super.indicator(choice, i) : '';
}
async renderChoice(item, i) {
await this.onChoice(item, i);
heading(message, choice, i) {
if (typeof this.options.heading === 'function') {
return this.options.heading.call(this, message, choice, i);
}
return this.styles.strong(message);
}
choiceMessage(choice, i) {
return this.resolve(choice.message, this.state, choice, i);
}
choiceSeparator() {
return ':';
}
async renderChoice(choice, i) {
await this.onChoice(choice, i);
let focused = this.index === i;
let pointer = await this.pointer(item, i);
let check = await this.indicator(item, i) + (item.pad || '');
let hint = await item.hint;
let pointer = await this.pointer(choice, i);
let check = await this.indicator(choice, i) + (choice.pad || '');
let hint = await this.resolve(choice.hint, this.state, choice, i);

@@ -50,12 +62,12 @@ if (hint && !utils.hasColor(hint)) {

let ind = this.indent(item);
let msg = await this.resolve(item.message, this.state, item, i);
let ind = this.indent(choice);
let msg = await this.choiceMessage(choice, i);
let line = () => [ind + pointer + check, msg, hint].filter(Boolean).join(' ');
if (item.role === 'heading') {
msg = this.heading(msg, item, i);
if (choice.role === 'heading') {
msg = this.heading(msg, choice, i);
return line();
}
if (item.disabled) {
if (choice.disabled) {
msg = this.styles.disabled(msg);

@@ -83,3 +95,3 @@ return line();

if (Array.isArray(this.selected)) {
return this.selected.map(item => this.styles.primary(item.name)).join(', ');
return this.selected.map(choice => this.styles.primary(choice.name)).join(', ');
}

@@ -86,0 +98,0 @@ return this.styles.primary(this.selected.name);

@@ -21,8 +21,8 @@ 'use strict';

this.state.keys = [];
this.state.invalid = new Map();
this.state.missing = new Set();
this.state.invalid = new Set();
this.state.completed = 0;
this.state.values = {};
if (!first) {
if (first !== true) {
await this.initialize();

@@ -67,7 +67,7 @@ await this.render();

increment(i) {
return (i >= this.state.keys.length - 1 ? 0 : (i + 1));
return i >= this.state.keys.length - 1 ? 0 : i + 1;
}
decrement(i) {
return (i <= 0 ? this.state.keys.length - 1 : (i - 1));
return i <= 0 ? this.state.keys.length - 1 : i - 1;
}

@@ -128,2 +128,3 @@

let newline = [this.options.newline, '\n'].find(v => v != null);
let prefix = await this.prefix();

@@ -137,4 +138,4 @@ let separator = await this.separator();

let header = await this.header();
let error = await this.error() || '';
let hint = await this.hint() || '';
let error = (await this.error()) || '';
let hint = (await this.hint()) || '';
let body = submitted ? '' : await this.interpolate(this.state);

@@ -149,3 +150,4 @@

this.clear(size);
this.write([header, prompt, body, footer, error.trim()].filter(Boolean).join('\n'));
let lines = [header, prompt, body, footer, error.trim()];
this.write(lines.filter(Boolean).join(newline));
this.restore();

@@ -169,3 +171,5 @@ }

if (invalid.size) {
this.state.error = 'Invalid: ' + [...invalid.keys()].join(', ');
let err = '';
for (let [key, value] of invalid) err += `Invalid ${key}: ${value}\n`;
this.state.error = err;
return super.submit();

@@ -179,3 +183,4 @@ }

let result = colors.unstyle(output);
let lines = colors.unstyle(output).split('\n');
let result = lines.map(v => v.slice(1)).join('\n');
this.value = { values, result };

@@ -182,0 +187,0 @@ return super.submit();

@@ -16,2 +16,12 @@ 'use strict';

async renderChoice(choice, i) {
let str = await super.renderChoice(choice, i);
let pre = (this.index === i && this.sorting) ? this.styles.muted('≡ ') : ' ';
if (this.options.drag === false) pre = '';
if (this.options.numbered === true) {
return pre + `${i + 1} - ` + str;
}
return pre + str;
}
get selected() {

@@ -18,0 +28,0 @@ return this.choices;

@@ -9,2 +9,4 @@ 'use strict';

define(this, '_prompt', prompt);
this.type = prompt.type;
this.name = prompt.name;
this.message = '';

@@ -11,0 +13,0 @@ this.header = '';

@@ -42,5 +42,2 @@ 'use strict';

},
get em() {
return this.primary.italic;
},
get heading() {

@@ -47,0 +44,0 @@ return this.primary.underline;

@@ -46,3 +46,3 @@ 'use strict';

on: isWindows ? '(*)' : '◉',
disabled: isWindows ? '(|)' : 'Ⓘ'
disabled: isWindows ? '(|)' : 'Ⓘ' //㊀
},

@@ -49,0 +49,0 @@ numbers: ['⓪', '①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩', '⑪', '⑫', '⑬', '⑭', '⑮', '⑯', '⑰', '⑱', '⑲', '⑳', '㉑', '㉒', '㉓', '㉔', '㉕', '㉖', '㉗', '㉘', '㉙', '㉚', '㉛', '㉜', '㉝', '㉞', '㉟', '㊱', '㊲', '㊳', '㊴', '㊵', '㊶', '㊷', '㊸', '㊹', '㊺', '㊻', '㊼', '㊽', '㊾', '㊿']

@@ -6,2 +6,3 @@ 'use strict';

const Prompt = require('../prompt');
const roles = require('../roles');

@@ -21,2 +22,5 @@ class ArrayPrompt extends Prompt {

async initialize() {
if (typeof this.options.initial === 'function') {
this.initial = await this.options.initial.call(this);
}
await this.reset(true);

@@ -38,10 +42,14 @@ await super.initialize();

initial.forEach(v => this.enable(this.find(v)));
return this.render();
await this.render();
} else {
if (autofocus != null) initial = autofocus;
if (typeof initial === 'string') initial = this.findIndex(initial);
if (typeof initial === 'number' && initial > -1) {
this.index = Math.max(0, Math.min(initial, this.choices.length));
this.enable(this.find(this.index));
}
}
if (autofocus != null) initial = autofocus;
if (typeof initial === 'string') initial = this.findIndex(initial);
if (typeof initial === 'number' && initial > -1) {
this.index = Math.max(0, Math.min(initial, this.choices.length));
this.enable(this.find(this.index));
if (this.isDisabled(this.focused)) {
await this.down();
}

@@ -80,3 +88,4 @@ }

ele.role = ele.role || 'option';
let role = roles(ele.role, this.options);
ele = role(this, ele);

@@ -92,8 +101,2 @@ if (typeof ele.disabled === 'string') {

if (ele.role === 'separator') {
ele.disabled = true;
ele.indicator = [ele.indicator, ' '].find(v => v != null);
ele.message = ele.message || this.symbols.line.repeat(5);
}
if (ele.index != null) return ele;

@@ -138,2 +141,11 @@ ele.name = ele.name || ele.key || ele.title || ele.value || ele.message;

async newItem() {
let choices = this.choices.slice();
choices.push({ name: 'New choice name?', editable: true, newChoice: true });
this.choices = await this.toChoices(choices);
this.index = this.choices.length - 1;
this.limit = this.choices.length;
return this.render();
}
indent(choice) {

@@ -315,6 +327,10 @@ return choice.level > 1 ? ' '.repeat(choice.level - 1) : '';

let vis = this.visible.length;
if (len > vis && this.index === 0) {
let idx = this.index;
if (this.options.scroll === false && idx === 0) {
return this.alert();
}
if (len > vis && idx === 0) {
return this.scrollUp();
}
this.index = ((this.index - 1 % len) + len) % len;
this.index = ((idx - 1 % len) + len) % len;
if (this.isDisabled()) {

@@ -329,6 +345,10 @@ return this.up();

let vis = this.visible.length;
if (len > vis && this.index === vis - 1) {
let idx = this.index;
if (this.options.scroll === false && idx === vis - 1) {
return this.alert();
}
if (len > vis && idx === vis - 1) {
return this.scrollDown();
}
this.index = (this.index + 1) % len;
this.index = (idx + 1) % len;
if (this.isDisabled()) {

@@ -358,6 +378,9 @@ return this.down();

shiftUp() {
async shiftUp() {
if (this.options.sort === true) {
this.sorting = true;
this.swap(this.index - 1);
return this.up();
await this.up();
this.sorting = false;
return;
}

@@ -367,6 +390,9 @@ return this.scrollUp(this.index);

shiftDown() {
async shiftDown() {
if (this.options.sort === true) {
this.sorting = true;
this.swap(this.index + 1);
return this.down();
await this.down();
this.sorting = false;
return;
}

@@ -403,5 +429,7 @@ return this.scrollDown(this.index);

isDisabled(choice = this.focused) {
if (choice) {
return choice.disabled || choice.collapsed || choice.hidden || choice.completing;
let keys = ['disabled', 'collapsed', 'hidden', 'completing'];
if (choice && keys.some(key => choice[key] === true)) {
return true;
}
return choice && choice.role === 'heading';
}

@@ -454,3 +482,3 @@

map(names = [], prop = 'value') {
return names.reduce((acc, name) => {
return [].concat(names || []).reduce((acc, name) => {
acc[name] = this.find(name, prop);

@@ -462,2 +490,16 @@ return acc;

async submit() {
let choice = this.focused;
if (choice.newChoice) {
if (!choice.input) return this.alert();
delete choice.newChoice;
choice.name = choice.message = choice.input;
choice.input = '';
choice.cursor = 0;
return this.render();
}
if (this.choices.some(ch => ch.newChoice)) {
return this.alert();
}
if (this.options.reorder !== false && this.options.sort !== true) {

@@ -468,3 +510,3 @@ this.choices = reorder(this.choices);

let multi = this.multiple === true;
let value = multi ? this.selected : this.focused;
let value = this.selected;
if (value === void 0) {

@@ -471,0 +513,0 @@ return this.alert();

@@ -12,5 +12,18 @@ 'use strict';

if (this.initial) this.cursorHide();
this.prevKeypress = 0;
this.prevCursor = 0;
this.clipboard = [];
this.typed = false;
}
async keypress(char, key) {
this.typed = true;
let prev = this.prevKeypress;
this.prevKeypress = key;
if (this.options.multiline === true && key.name === 'return') {
if (!prev || prev.name !== 'return') return this.append('\n', key);
}
return super.keypress(char, key);
}
moveCursor(n = 0) {

@@ -23,7 +36,6 @@ this.cursor += n;

this.cursor = 0;
this.render();
return this.render();
}
dispatch(ch, key) {
if (key.ctrl && key.name === 'x') return this.toggleCursor();
if (!ch || key.ctrl || key.code) return this.alert();

@@ -40,2 +52,6 @@ this.append(ch);

insert(str) {
this.append(str);
}
delete() {

@@ -56,12 +72,29 @@ let { cursor, input } = this.state;

first() {
this.cursor = 0;
cutForward() {
let pos = this.cursor;
if (this.input.length <= pos) return this.alert();
this.clipboard.push(this.input.slice(pos));
this.input = this.input.slice(0, pos);
this.render();
}
last() {
this.cursor = this.input.length - 1;
cutLeft() {
let pos = this.cursor;
if (pos === 0) return this.alert();
let before = this.input.slice(0, pos);
let after = this.input.slice(pos);
let words = before.split(' ');
this.clipboard.push(words.pop());
this.input = words.join(' ');
this.cursor = this.input.length;
this.input += after;
this.render();
}
paste() {
if (!this.clipboard.length) return this.alert();
this.insert(this.clipboard.pop());
this.render();
}
toggleCursor() {

@@ -78,2 +111,12 @@ if (this.prevCursor) {

first() {
this.cursor = 0;
this.render();
}
last() {
this.cursor = this.input.length - 1;
this.render();
}
next() {

@@ -92,2 +135,10 @@ let init = this.initial != null ? String(this.initial) : '';

backward() {
return this.left();
}
forward() {
return this.right();
}
right() {

@@ -109,5 +160,5 @@ if (this.cursor >= this.input.length) return this.alert();

format(input = this.input) {
format(input = this.value) {
if (!this.state.submitted) {
return placeholder(this, input, this.initial, this.cursor);
return placeholder(this, { input, initial: this.initial, pos: this.cursor });
}

@@ -114,0 +165,0 @@ return this.styles.submitted(input || this.initial);

'use strict';
const colors = require('ansi-colors');
const strip = str => str.replace(/\\(?=\.)/g, '');
const split = str => str.split(/(?<!\\)\./).map(strip);
let called = false;

@@ -24,6 +22,3 @@ let fns = [];

exports.hasColor = str => {
/* eslint-disable no-control-regex */
return !!str && /\u001b\[\d+m/.test(str);
};
exports.hasColor = str => !!str && colors.hasColor(str);

@@ -93,2 +88,4 @@ const isObject = exports.isObject = val => {

let { indent = '', newline = ('\n' + indent), width = 80 } = options;
let spaces = (newline + indent).match(/[^\S\n]/g) || [];
width -= spaces.length;
let source = `.{1,${width}}([\\s\\u200B]+|$)|[^\\s\\u200B]+?([\\s\\u200B]+|$)`;

@@ -98,3 +95,6 @@ let output = str.trim();

let lines = output.match(regex) || [];
return indent + lines.map(line => line.replace(/\n$/, '')).join(newline);
lines = lines.map(line => line.replace(/\n$/, ''));
if (options.padEnd) lines = lines.map(line => line.padEnd(width, ' '));
if (options.padStart) lines = lines.map(line => line.padStart(width, ' '));
return indent + lines.join(newline);
};

@@ -164,3 +164,3 @@

exports.set = (obj = {}, prop = '', val) => {
return split(prop).reduce((acc, k, i, arr) => {
return prop.split('.').reduce((acc, k, i, arr) => {
let value = arr.length - 1 > i ? (acc[k] || {}) : val;

@@ -180,3 +180,3 @@ if (!exports.isObject(value) && i < arr.length - 1) value = {};

let value = obj[prop] == null
? split(prop).reduce((acc, k) => acc && acc[strip(k)], obj)
? prop.split('.').reduce((acc, k) => acc && acc[k], obj)
: obj[prop];

@@ -183,0 +183,0 @@ return value == null ? fallback : value;

{
"name": "enquirer",
"description": "Stylish, intuitive and user-friendly prompt system. Fast and lightweight enough for small projects, powerful and extensible enough for the most advanced use cases.",
"version": "2.0.7",
"version": "2.0.8",
"homepage": "https://github.com/enquirer/enquirer",

@@ -18,2 +18,3 @@ "author": "Jon Schlinkert (https://github.com/jonschlinkert)",

"index.js",
"index.d.ts",
"lib"

@@ -34,13 +35,9 @@ ],

"@types/node": "^8",
"cli-spinners": "^1.3.1",
"data-store": "^3.1.0",
"gulp-format-md": "^1.0.0",
"gulp-format-md": "^2.0.0",
"inquirer": "^6.2.0",
"mocha": "^5.2.0",
"nyc": "^12.0.2",
"prompts": "^1.1.1",
"semver": "^5.6.0",
"nyc": "^13.1.0",
"prompts": "^1.2.1",
"time-require": "github:jonschlinkert/time-require",
"typescript": "^3.1.6",
"yosay": "^2.0.2"
"typescript": "^3.1.6"
},

@@ -47,0 +44,0 @@ "keywords": [

@@ -20,3 +20,3 @@ <h1 align="center">Enquirer</h1>

<b>Stylish CLI prompts that are user-friendly, intuitive and easy to create.</b><br>
<sub>>_ Prompts should be more like conversations than inquisitions▌<sub>
<sub>>_ Prompts should be more like conversations than inquisitions▌</sub>
</p>

@@ -27,3 +27,6 @@

<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/survey-prompt.gif" alt="Enquirer Survey Prompt" width="750">
<sub>(Example shows Enquirer's <a href="#survey-prompt">Survey Prompt</a>)</a></sub>
<img src="https://raw.githubusercontent.com/enquirer/enquirer/master/media/survey-prompt.gif" alt="Enquirer Survey Prompt" width="750"><br>
<sub>The terminal in all examples is <a href="https://hyper.is/">Hyper</a>, theme is <a href="https://github.com/jonschlinkert/hyper-monokai-extended">hyper-monokai-extended</a>.</sub><br><br>
<a href="#built-in-prompts"><strong>See more prompt examples</strong></a>
</p>

@@ -34,4 +37,2 @@

Please consider starting or tweeting about this project to show your support. Thanks!
Created by [jonschlinkert](https://github.com/jonschlinkert) and [doowb](https://github.com/doowb), Enquirer is fast, easy to use, and lightweight enough for small projects, while also being powerful and customizable enough for the most advanced use cases.

@@ -42,3 +43,3 @@

* **Easy to implement** - Uses promises and async/await and sensible defaults to make prompts easy to create and implement.
* **Easy to use** - Thrill your users with a better experience! Navigating around input and choices is a breeze. You can even create [quizzes](recipes/quiz.js), or [record](recipes/record.js) and [playback](recipes/play.js) keypresses to aid with tutorials and videos.
* **Easy to use** - Thrill your users with a better experience! Navigating around input and choices is a breeze. You can even create [quizzes](examples/fun/countdown.js), or [record](examples/fun/record.js) and [playback](examples/fun/play.js) key bindings to aid with tutorials and videos.
* **Intuitive** - Keypress combos are available to simplify usage.

@@ -51,5 +52,5 @@ * **Flexible** - All prompts can be used standalone or chained together.

* **Well tested** - All prompts are well-tested, and tests are easy to create without having to use brittle, hacky solutions to spy on prompts or "inject" values.
* **Examples** - There are numerous [examples](examples) and [recipes](recipes) available to help you get started.
* **Examples** - There are numerous [examples](examples) and [examples](examples) available to help you get started.
_(If you like Enquirer, you might also like [micromatch](https://github.com/micromatch/micromatch), created by [Jon Schlinkert](https://github.com/jonschlinkert), author of Enquirer)_.
If you like Enquirer, please consider starring or tweeting about this project to show your support. Thanks!

@@ -59,4 +60,4 @@ <br>

<p align="center">
<b>Ready to start making prompts your users will love?</b><br>
<img src="https://github.com/enquirer/enquirer/raw/master/media/heartbeat.gif" alt="Enquirer Select Prompt with heartbeat example" width="750">
<b>>_ Ready to start making prompts your users will love? ▌</b><br>
<img src="https://raw.githubusercontent.com/enquirer/enquirer/master/media/heartbeat.gif" alt="Enquirer Select Prompt with heartbeat example" width="750">
</p>

@@ -74,5 +75,6 @@

* [Enquirer](#-enquirer)
* [Built-in Prompts](#-prompts)
* [Custom Prompts](#-custom-prompts)
* [Keypresses](#-keypresses)
* [Prompts](#-prompts)
- [Built-in Prompts](#-prompts)
- [Custom Prompts](#-custom-prompts)
* [Key Bindings](#-key-bindings)
* [Options](#-options)

@@ -94,3 +96,3 @@ * [Release History](#-release-history)

<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/npm-install.gif" alt="Install Enquirer with NPM" width="750">
<img src="https://raw.githubusercontent.com/enquirer/enquirer/master/media/npm-install.gif" alt="Install Enquirer with NPM" width="750">
</p>

@@ -145,7 +147,7 @@

**Jump to**: [Getting Started](#-getting-started) · [Prompts](#-prompts) · [Options](#-options) · [Keypresses](#-keypresses)
**Jump to**: [Getting Started](#-getting-started) · [Prompts](#-prompts) · [Options](#-options) · [Key Bindings](#-key-bindings)
<br>
## TODO
### Todo

@@ -158,2 +160,3 @@ We're currently working on documentation for the following items. Please star and watch the repository for updates!

* [ ] Customizing returned values
* [ ] Customizing key bindings
* [ ] Question validation

@@ -163,4 +166,4 @@ * [ ] Choice validation

* [ ] Async choices
* [ ] Async loaders, spinners and other timers
* [ ] Links to recipes
* [ ] Async timers: loaders, spinners and other animations
* [ ] Links to examples

@@ -284,3 +287,3 @@ <br>

### [use](index.js#L151)
### [use](index.js#L157)

@@ -305,3 +308,3 @@ Use an enquirer plugin.

### [Enquirer#prompt](index.js#L212)
### [Enquirer#prompt](index.js#L207)

@@ -329,16 +332,80 @@ Prompt function that takes a "question" object or array of question objects, and returns an object with responses from the user.

* [Prompt](#prompt) - The base `Prompt` class used by other prompts
- [Prompt Options](#prompt-options)
- [Prompt Types](#prompt-types) - The base `Prompt` class used by other prompts
* [Built-in prompts](#built-in-prompts)
* [Prompt Options](#options)
### Prompt
The base `Prompt` class is used to create all other prompts.
```js
const { Prompt } = require('enquirer');
class MyCustomPrompt extends Prompt {}
```
See the documentation for [creating custom prompts](#-custom-prompts) to learn more about how this works.
### Prompt Options
Each prompt takes an options object (aka "question" object), that implements the following interface:
```js
{
// required
type: string | function,
name: string | function,
message: string | function | async function,
// optional
skip: boolean | function | async function
initial: string | function | async function
format: function | async function,
result: function | async function,
validate: function | async function
}
```
### General options
All prompts take the following options.
| **Property** | **Required?** | **Type** | **Description** |
| --- | --- | --- | --- |
| `type` | Yes | `string\|function` | Enquirer uses this value to determine the type of prompt to run, but it's optional when prompts are run directly. |
| `name` | Yes | `string\|function` | Used as the key for the answer on the returned values (answers) object. |
| `message` | Yes | `string\|function` | The message to display when the prompt is rendered in the terminal. |
| `skip` | no | `boolean\|function` | If `true` it will not ask that prompt. |
| `initial` | no | `string\|function` | The default value to return if the user does not supply a value. |
| `format` | no | `function` | Function to format user input in the terminal. |
| `result` | no | `function` | Function to format the final submitted value before it's returned. |
| `validate` | no | `function` | Function to validate the submitted value before it's returned. This function may return a boolean or a string. If a string is returned it will be used as the validation error message. |
**Example usage**
```js
const { prompt } = require('enquirer');
const question = {
type: 'input',
name: 'username',
message: 'What is your username?'
};
prompt(question)
.then(answer => console.log('Answer:', answer))
.catch(console.error);
```
<br>
### Built-in prompts
* [Prompt](#prompt) - The base `Prompt` class used by other prompts
* [AutoComplete](#autocomplete-prompt)
* [Confirm](#confirm-prompt)
* [Form](#form-prompt)
* [hSelect](#hselect-prompt) (horizontal select)
* [hMultiSelect](#hmultiselect-prompt) (horizontal multiselect)
* [Input](#input-prompt)
* [Invisible](#invisible-prompt)
* [List](#list-prompt)
* [Scale](#scale-prompt)
* [MultiSelect](#multiselect-prompt)

@@ -353,13 +420,2 @@ * [Number](#number-prompt)

### Prompt
The base `Prompt` class is used to create all other prompts.
```js
const { Prompt } = require('enquirer');
class MyCustomPrompt extends Prompt {}
```
See the documentation for [creating custom prompts](#-custom-prompts) to learn more about how this works.
### AutoComplete Prompt

@@ -370,5 +426,11 @@

<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/autocomplete-prompt.gif" alt="Enquirer AutoComplete Prompt" width="750">
<img src="https://raw.githubusercontent.com/enquirer/enquirer/master/media/autocomplete-prompt.gif" alt="Enquirer AutoComplete Prompt" width="750">
</p>
**Related prompts**
* [Select](#select-prompt)
* [MultiSelect](#multiselect-prompt)
* [Survey](#survey-prompt)
**Example Usage**

@@ -404,8 +466,2 @@

**Related prompts**
* [Select](#select-prompt)
* [MultiSelect](#multiselect-prompt)
* [Survey](#survey-prompt)
**↑ back to:** [Getting Started](#-getting-started) · [Prompts](#-prompts)

@@ -421,3 +477,3 @@

<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/confirm-prompt.gif" alt="Enquirer Confirm Prompt" width="750">
<img src="https://raw.githubusercontent.com/enquirer/enquirer/master/media/confirm-prompt.gif" alt="Enquirer Confirm Prompt" width="750">
</p>

@@ -441,3 +497,3 @@

<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/form-prompt.gif" alt="Enquirer Form Prompt" width="750">
<img src="https://raw.githubusercontent.com/enquirer/enquirer/master/media/form-prompt.gif" alt="Enquirer Form Prompt" width="750">
</p>

@@ -455,40 +511,2 @@

### hSelect Prompt
The `hSelect` (Horizontal Select) allows the user to select from a horizontal list of choices.
<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/hselect-prompt.gif" alt="Enquirer Horizontal Select / hSelect Prompt" width="750">
</p>
**Related prompts**
* [Select](#select-prompt)
* [MultiSelect](#multiselect-prompt)
* [Hmultiselect](#hmultiselect-prompt)
**↑ back to:** [Getting Started](#-getting-started) · [Prompts](#-prompts)
<br>
<br>
### hMultiSelect Prompt
The `hMultiSelect` (Horizontal MultiSelect) allows the user to select multiple items from a horizontal list of choices.
<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/hmultiselect-prompt.gif" alt="Enquirer Horizontal MultiSelect / hMultiSelect Prompt" width="750">
</p>
**Related prompts**
* [Select](#select-prompt)
* [Hselect](#hselect-prompt)
* [MultiSelect](#multiselect-prompt)
**↑ back to:** [Getting Started](#-getting-started) · [Prompts](#-prompts)
<br>
<br>
### Input Prompt

@@ -499,3 +517,3 @@

<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/input-prompt.gif" alt="Enquirer Input Prompt" width="750">
<img src="https://raw.githubusercontent.com/enquirer/enquirer/master/media/input-prompt.gif" alt="Enquirer Input Prompt" width="750">
</p>

@@ -505,6 +523,3 @@

Usage with Enquirer.
```js
const { prompt } = require('enquirer');
const question = {

@@ -515,20 +530,4 @@ type: 'input',

};
let answers = await prompt(question);
console.log('Username:', answers.username);
```
Usage as a standalone prompt. Use this approach if you need to modify the prompt instance, or listen for events on the prompt.
```js
const { Input } = require('enquirer');
const prompt = new Input({
name: 'username',
message: 'What is your username?'
});
let answer = await prompt.run();
console.log('Username:', answer);
```
**Related prompts**

@@ -550,3 +549,3 @@

<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/invisible-prompt.gif" alt="Enquirer Invisible Prompt" width="750">
<img src="https://raw.githubusercontent.com/enquirer/enquirer/master/media/invisible-prompt.gif" alt="Enquirer Invisible Prompt" width="750">
</p>

@@ -569,3 +568,3 @@

<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/list-prompt.gif" alt="Enquirer List Prompt" width="750">
<img src="https://raw.githubusercontent.com/enquirer/enquirer/master/media/list-prompt.gif" alt="Enquirer List Prompt" width="750">
</p>

@@ -583,3 +582,3 @@

### MultiScale Prompt
### Scale Prompt

@@ -589,3 +588,3 @@ Prompt that allows the user to quickly provide feedback using a [Likert Scale](https://en.wikipedia.org/wiki/Likert_scale).

<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/multiscale-prompt.gif" alt="Enquirer MultiScale Prompt" width="750">
<img src="https://raw.githubusercontent.com/enquirer/enquirer/master/media/scale-prompt.gif" alt="Enquirer Scale Prompt" width="750">
</p>

@@ -609,3 +608,3 @@

<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/multiselect-prompt.gif" alt="Enquirer MultiSelect Prompt" width="750">
<img src="https://raw.githubusercontent.com/enquirer/enquirer/master/media/multiselect-prompt.gif" alt="Enquirer MultiSelect Prompt" width="750">
</p>

@@ -615,4 +614,5 @@

* [AutoComplete](#autocomplete-prompt)
* [Select](#select-prompt)
* [AutoComplete](#autocomplete-prompt)
* [Survey](#survey-prompt)

@@ -629,3 +629,3 @@ **↑ back to:** [Getting Started](#-getting-started) · [Prompts](#-prompts)

<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/numeral-prompt.gif" alt="Enquirer Numeral Prompt" width="750">
<img src="https://raw.githubusercontent.com/enquirer/enquirer/master/media/numeral-prompt.gif" alt="Enquirer Numeral Prompt" width="750">
</p>

@@ -648,3 +648,3 @@

<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/password-prompt.gif" alt="Enquirer Password Prompt" width="750">
<img src="https://raw.githubusercontent.com/enquirer/enquirer/master/media/password-prompt.gif" alt="Enquirer Password Prompt" width="750">
</p>

@@ -667,3 +667,3 @@

<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/select-prompt.gif" alt="Enquirer Select Prompt" width="750">
<img src="https://raw.githubusercontent.com/enquirer/enquirer/master/media/select-prompt.gif" alt="Enquirer Select Prompt" width="750">
</p>

@@ -686,3 +686,3 @@

<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/snippet-prompt.gif" alt="Prompts" width="750">
<img src="https://raw.githubusercontent.com/enquirer/enquirer/master/media/snippet-prompt.gif" alt="Prompts" width="750">
</p>

@@ -709,3 +709,3 @@

<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/sort-prompt.gif" alt="Enquirer Sort Prompt" width="750">
<img src="https://raw.githubusercontent.com/enquirer/enquirer/master/media/sort-prompt.gif" alt="Enquirer Sort Prompt" width="750">
</p>

@@ -728,3 +728,3 @@

<p align="center">
<img src="https://github.com/enquirer/enquirer/raw/master/media/survey-prompt.gif" alt="Enquirer Survey Prompt" width="750">
<img src="https://raw.githubusercontent.com/enquirer/enquirer/master/media/survey-prompt.gif" alt="Enquirer Survey Prompt" width="750">
</p>

@@ -734,3 +734,3 @@

* [MultiScale](#multiscale-prompt)
* [Scale](#scale-prompt)
* [Snippet](#snippet-prompt)

@@ -742,3 +742,3 @@ * [Select](#select-prompt)

## ❯ Types
## ❯ Prompt Types

@@ -849,14 +849,16 @@ Enquirer 2.0 introduced the concept of prompt "types", with the goal of making custom prompts easier than ever to create and use. There are 4 (soon to be 5!) type classes:

};
```
// Normalizes to the following when the prompt is run:
//
// const question = {
// name: 'fruit',
// message: 'Favorite fruit?'
// choices: [
// { name: 'Apple', message: 'Apple', value: 'Apple' },
// { name: 'Orange', message: 'Orange', value: 'Orange' },
// { name: 'Raspberry', message: 'Raspberry', value: 'Raspberry' }
// ]
// }
Normalizes to the following when the prompt is run:
```js
const question = {
name: 'fruit',
message: 'Favorite fruit?'
choices: [
{ name: 'Apple', message: 'Apple', value: 'Apple' },
{ name: 'Orange', message: 'Orange', value: 'Orange' },
{ name: 'Raspberry', message: 'Raspberry', value: 'Raspberry' }
]
};
```

@@ -949,6 +951,5 @@

.catch(console.error);
```
To register a custom prompt, you must first instantiate `Enquirer`.
If you want to be able to specify your prompt by `type` so that it may be used alongside other prompts, you will need to first create an instance of `Enquirer`.

@@ -984,20 +985,21 @@ ```js

## ❯ Keypresses
## ❯ Key Bindings
### All prompts
Key combinations that may be used with all prompts.
These key combinations may be used with all prompts.
| **command** | **description** |
| ---: | --- |
| <kbd>ctrl</kbd>+<kbd>a</kdb> | Move the cursor to the first character in user input. |
| --- | --- |
| <kbd>ctrl</kbd>+<kbd>c</kbd> | Cancel the prompt. |
| <kbd>ctrl</kbd>+<kbd>g</kdb> | Reset the prompt to its initial state. |
<br>
### Move cursor
Key combinations that may be used on prompts that support user input, such as the [input prompt](#input-prompt), [password prompt](#password-prompt), and [invisible prompt](#invisible-prompt)).
These combinations may be used on prompts that support user input, such as the [input prompt](#input-prompt), [password prompt](#password-prompt), and [invisible prompt](#invisible-prompt)).
| **command** | **description** |
| ---: | --- |
| --- | --- |
| <kbd>left</kbd> | Move the cursor forward one character. |

@@ -1011,8 +1013,42 @@ | <kbd>right</kbd> | Move the cursor back one character. |

## Select choices
<br>
### Edit Input
These key combinations may be used on prompts that support user input, such as the [input prompt](#input-prompt), [password prompt](#password-prompt), and [invisible prompt](#invisible-prompt)).
| **command** | **description** |
| --- | --- |
| <kbd>ctrl</kbd>+<kbd>a</kbd> | Move cursor to the start of the line |
| <kbd>ctrl</kbd>+<kbd>e</kbd> | Move cursor to the end of the line |
| <kbd>ctrl</kbd>+<kbd>b</kbd> | Move cursor back one character |
| <kbd>ctrl</kbd>+<kbd>f</kbd> | Move cursor forward one character |
| <kbd>ctrl</kbd>+<kbd>x</kbd> | Toggle between first and cursor position |
#### Mac
| **command** | **description** |
| --- | --- |
| <kbd>delete</kbd> | Delete one character to the left. |
| <kbd>fn</kbd>+<kbd>delete</kbd> | Delete one character to the right. |
| <kbd>option</kbd>+<kbd>up</kbd> | Scroll to the previous item in history ([Input prompt](#input-prompt) only, when [history is enabled](examples/input/option-history.js)). |
| <kbd>option</kbd>+<kbd>down</kbd> | Scroll to the next item in history ([Input prompt](#input-prompt) only, when [history is enabled](examples/input/option-history.js)). |
#### Windows
| **command** | **description** |
| --- | --- |
| <kbd>backspace</kbd> | Delete one character to the left. |
| <kbd>delete</kbd> | Delete one character to the right (forward). |
| <kbd>alt</kbd>+<kbd>up</kbd> | Scroll to the previous item in history ([Input prompt](#input-prompt) only, when [history is enabled](examples/input/option-history.js)). |
| <kbd>alt</kbd>+<kbd>down</kbd> | Scroll to the next item in history ([Input prompt](#input-prompt) only, when [history is enabled](examples/input/option-history.js)). |
<br>
### Select choices
These key combinations may be used on prompts that support _multiple_ choices, such as the [multiselect prompt](#multiselect-prompt), or the [select prompt](#select-prompt) when the `multiple` options is true.
| **command** | **description** |
| ---: | --- |
| --- | --- |
| <kbd>space</kbd> | Toggle the currently selected choice when `options.multiple` is true. |

@@ -1024,13 +1060,17 @@ | <kbd>number</kbd> | Move the pointer to the choice at the given index. Also toggles the selected choice when `options.multiple` is true. |

<br>
### Hide/show choices
| **command** | **description** |
| ---: | --- |
| --- | --- |
| <kbd>fn</kbd>+<kbd>up</kbd> | Decrease the number of visible choices by one. |
| <kbd>fn</kbd>+<kbd>down</kbd> | Increase the number of visible choices by one. |
<br>
### Move/lock Pointer
| **command** | **description** |
| ---: | --- |
| --- | --- |
| <kbd>number</kbd> | Move the pointer to the choice at the given index. Also toggles the selected choice when `options.multiple` is true. |

@@ -1041,59 +1081,21 @@ | <kbd>up</kbd> | Move the pointer up. |

| <kbd>ctrl</kbd>+<kbd>e</kbd> | Move the pointer to the last _visible_ choice. |
| (mac) <kbd>fn</kbd>+<kbd>left</kbd> / (win) <kbd>home</kbd> | Move the pointer to the first choice in the choices array. |
| (mac) <kbd>fn</kbd>+<kbd>right</kbd> / (win) <kbd>end</kbd> | Move the pointer to the last choice in the choices array. |
| <kbd>shift</kbd>+<kbd>up</kbd> | Scroll up one choice without changing pointer position (locks the pointer while scrolling). |
| <kbd>shift</kbd>+<kbd>down</kbd> | Scroll down one choice without changing pointer position (locks the pointer while scrolling). |
<br>
#### Mac
## ❯ Options
| **command** | **description** |
| --- | --- |
| <kbd>fn</kbd>+<kbd>left</kbd> | Move the pointer to the first choice in the choices array. |
| <kbd>fn</kbd>+<kbd>right</kbd> | Move the pointer to the last choice in the choices array. |
Each prompt takes an options object (aka "question" object), that implements the following interface:
#### Windows
```js
{
// required
type: string | function,
name: string | function,
message: string | function | async function,
| **command** | **description** |
| --- | --- |
| <kbd>home</kbd> | Move the pointer to the first choice in the choices array. |
| <kbd>end</kbd> | Move the pointer to the last choice in the choices array. |
// optional
initial: string | function | async function
format: function | async function,
result: function | async function,
validate: function | async function
}
```
### General options
All prompts take the following options.
| **Property** | **Required?** | **Type** | **Description** |
| --- | --- | --- | --- |
| `type` | Yes | `string\|function` | Enquirer uses this value to determine the type of prompt to run, but it's optional when prompts are run directly. |
| `name` | Yes | `string\|function` | Used as the key for the answer on the returned values (answers) object. |
| `message` | Yes | `string\|function` | The message to display when the prompt is rendered in the terminal. |
| `initial` | no | `string\|function` | The default value to return if the user does not supply a value. |
| `format` | no | `function` | Function to format user input in the terminal. |
| `result` | no | `function` | Function to format the final submitted value before it's returned. |
| `validate` | no | `function` | Function to validate the submitted value before it's returned. This function may return a boolean or a string. If a string is returned it will be used as the validation error message. |
**Example usage**
```js
const { prompt } = require('enquirer');
const question = {
type: 'input',
name: 'username',
message: 'What is your username?'
};
prompt(question)
.then(answer => console.log('Answer:', answer))
.catch(console.error);
```
<br>
<br>

@@ -1156,6 +1158,15 @@ ## ❯ Release History

| --- | --- |
| 72 | [jonschlinkert](https://github.com/jonschlinkert) |
| 12 | [doowb](https://github.com/doowb) |
| 1 | [mischah](https://github.com/mischah) |
| 1 | [skellock](https://github.com/skellock) |
| 238 | [jonschlinkert](https://github.com/jonschlinkert) |
| 24 | [doowb](https://github.com/doowb) |
| 8 | [g-plane](https://github.com/g-plane) |
| 3 | [tunnckoCore](https://github.com/tunnckoCore) |
| 2 | [DanielRuf](https://github.com/DanielRuf) |
| 1 | [gabel0287](https://github.com/gabel0287) |
| 1 | [ImgBotApp](https://github.com/ImgBotApp) |
| 1 | [jsonkao](https://github.com/jsonkao) |
| 1 | [knpwrs](https://github.com/knpwrs) |
| 1 | [yeskunall](https://github.com/yeskunall) |
| 1 | [mischah](https://github.com/mischah) |
| 1 | [sbugert](https://github.com/sbugert) |
| 1 | [skellock](https://github.com/skellock) |

@@ -1176,3 +1187,3 @@ ### Author

Copyright © 2018, [Jon Schlinkert](https://github.com/jonschlinkert).
Copyright © 2018-present, [Jon Schlinkert](https://github.com/jonschlinkert).
Released under the [MIT License](LICENSE).
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc