A beautiful command-line prompt for node.js with validation, defaults, and password hiding capabilities
npx @tessl/cli install tessl/npm-prompt@1.3.0Prompt is a comprehensive command-line prompting library for Node.js applications that enables developers to interactively collect user input with built-in validation, default values, and password hiding capabilities. It offers a simple yet powerful API with methods like prompt.get() and prompt.addProperties() for gathering user input, supports complex property validation through revalidator integration, provides extensive customization options including colors and formatting, and includes robust error handling and async/await support for modern JavaScript development patterns.
npm install promptconst prompt = require('prompt');ESM import:
import prompt from 'prompt';const prompt = require('prompt');
// Start the prompt system
prompt.start();
// Get simple input
prompt.get(['username', 'email'], function (err, result) {
if (err) return console.error(err);
console.log('Username:', result.username);
console.log('Email:', result.email);
});
// Using Promises (modern approach)
async function getUserInfo() {
prompt.start();
try {
const result = await prompt.get(['username', 'email']);
console.log('Username:', result.username);
console.log('Email:', result.email);
} catch (err) {
console.error('Error:', err);
}
}Prompt supports both callback-based and Promise-based APIs for modern JavaScript development:
Callback Style (Traditional):
prompt.get(['username', 'email'], function(err, result) {
if (err) return console.error(err);
console.log('Result:', result);
});Promise Style (Modern/Async-Await):
// Using Promises
prompt.get(['username', 'email'])
.then(result => console.log('Result:', result))
.catch(err => console.error(err));
// Using async/await
async function getUserInfo() {
try {
const result = await prompt.get(['username', 'email']);
console.log('Result:', result);
} catch (err) {
console.error(err);
}
}Important Notes:
get, addProperties) support both patternsconfirm always requires a callback and does not return a PromisePrompt is built around several key components:
Initialize the prompt system with configuration options.
/**
* Starts the prompt by listening to the appropriate events on stdin/stdout
* @param {Object} options - Optional configuration options
* @param {ReadableStream} options.stdin - Input stream (default: process.stdin)
* @param {WritableStream} options.stdout - Output stream (default: process.stdout)
* @param {number} options.memory - Number of previous prompts to remember (default: 10)
* @param {boolean} options.allowEmpty - Allow empty responses globally (default: false)
* @param {string} options.message - Default message prefix (default: 'prompt')
* @param {string} options.delimiter - Default delimiter (default: ': ')
* @param {boolean} options.colors - Enable colors (default: true)
* @param {boolean} options.noHandleSIGINT - Disable SIGINT handling (default: false)
* @returns {Object} prompt object for chaining
*/
function start(options);Usage Example:
const prompt = require('prompt');
// Basic initialization
prompt.start();
// Custom configuration
prompt.start({
message: 'myapp',
delimiter: ' > ',
colors: false,
allowEmpty: true
});Get user input using simple property names or complex validation schemas.
/**
* Gets input from the user via stdin for specified message(s)
* @param {string|string[]|PropertySchema|FullSchema} schema - Set of variables to get input for
* @param {(err: Error|null, result?: Object) => void} callback - Optional callback function
* @returns {Promise<Object>|typeof prompt} Promise when no callback provided, otherwise prompt object
*/
function get(schema, callback);
/** Complete schema object with properties */
interface FullSchema {
properties: {
[propertyName: string]: PropertySchema;
};
}Schema Types:
Usage Examples:
// Simple property names
const result = await prompt.get(['name', 'age']);
// Array of properties
const result = await prompt.get(['username', 'password', 'email']);
// Complex validation schema
const schema = {
properties: {
name: {
pattern: /^[a-zA-Z\s\-]+$/,
message: 'Name must be only letters, spaces, or dashes',
required: true
},
password: {
hidden: true,
replace: '*'
},
age: {
type: 'integer',
minimum: 0,
maximum: 120,
message: 'Age must be between 0 and 120'
}
}
};
const result = await prompt.get(schema);Add missing properties to existing objects by prompting the user.
/**
* Prompts user for values of properties if obj doesn't already have them
* @param {Object} obj - Object to add properties to
* @param {Array} properties - List of properties to get values for
* @param {Function} callback - Callback function (err, updatedObj)
* @returns {Object} prompt object for chaining
*/
function addProperties(obj, properties, callback);Usage Example:
const config = {
host: 'localhost',
port: 3000
};
// Only prompt for missing properties
prompt.addProperties(config, ['host', 'port', 'username', 'password'], function(err, result) {
// Only prompts for 'username' and 'password' since host/port already exist
console.log('Complete config:', result);
});Prompt for yes/no confirmation with customizable validation.
/**
* Confirms a single or series of messages by prompting for Y/N response
* @param {string|ConfirmSchema|Array<string|ConfirmSchema>} msg - Set of messages to confirm
* @param {Object} options - Optional additional options to merge with each confirm schema
* @param {(err: Error|null, isConfirmed: boolean) => void} callback - Callback function
* @returns {void} Calls callback with true if ALL messages confirmed, otherwise false
*/
function confirm(msg, options, callback);
/** Confirmation schema with customizable validation */
interface ConfirmSchema {
/** Message to display for confirmation */
description: string;
/** Pattern for valid responses (default: /^[yntf]{1}/i) */
pattern?: RegExp;
/** Pattern for "yes" responses (default: /^[yt]{1}/i) */
yes?: RegExp;
/** Error message for invalid responses */
message?: string;
}Usage Examples:
// Simple confirmation
prompt.confirm('Are you sure?', function(err, result) {
console.log('User confirmed:', result);
});
// Custom validation
const confirmOptions = {
description: 'Delete all files?',
pattern: /^[yntf]{1}/i,
yes: /^[yt]{1}/i,
message: 'Please enter yes, y, no, n, true, t, false, or f'
};
prompt.confirm(confirmOptions, function(err, result) {
if (result) {
console.log('Proceeding with deletion...');
}
});Get single input with validation (used internally by get()).
/**
* Gets input from user via stdin for specified message with validation
* @param {Object|string} prop - Property schema or name
* @param {Function} callback - Callback function (err, input)
*/
function getInput(prop, callback);Control the prompt system lifecycle and state.
/**
* Pauses input coming in from stdin
* @returns {Object} prompt object for chaining
*/
function pause();
/**
* Resumes input coming in from stdin
* @returns {Object} prompt object for chaining
*/
function resume();
/**
* Stops input coming in from stdin and destroys it
* @returns {Object} prompt object for chaining
*/
function stop();Usage Example:
prompt.start();
// Pause during async operation
prompt.pause();
await someAsyncOperation();
prompt.resume();
// Later, stop completely
prompt.stop();Access previous prompt/answer pairs from memory.
/**
* Returns property:value pair from within the prompts history array
* @param {number|string} search - Index or property name to find
* @returns {Object|null} History entry object or null if not found
*/
function history(search);Usage Example:
// Get by index
const lastPrompt = prompt.history(0);
// Get by property name
const usernameEntry = prompt.history('username');
console.log('Previous username:', usernameEntry?.value);/** Indicates if prompt has been started */
boolean started;
/** Indicates if prompt is currently paused */
boolean paused;
/** Indicates if prompt has been stopped */
boolean stopped;/** Global setting to allow empty responses */
boolean allowEmpty;
/** Default message prefix for prompts */
string message;
/** Default delimiter between message and input */
string delimiter;
/** Enable/disable colored output */
boolean colors;
/** Number of previous prompt/answer pairs to remember */
number memory;/** Stored property schemas for reuse */
Object properties;
/** Property values to override during prompting */
Object override;/** Package version from package.json */
string version;
/** Winston logger instance for prompt output */
Object logger;Prompt uses JSON Schema-compatible validation with additional properties:
interface PropertySchema {
// Display Properties
/** Prompt text displayed to user */
description?: string;
/** Error message displayed on validation failure */
message?: string;
// Data Type Properties
/** Data type: 'string', 'boolean', 'number', 'integer', 'array' */
type?: 'string' | 'boolean' | 'number' | 'integer' | 'array';
/** Default value if no input provided */
default?: any;
/** Whether input is required (non-empty) */
required?: boolean;
// Validation Properties
/** Regular expression for validation */
pattern?: RegExp;
/** Custom validation function */
conform?: (value: any) => boolean;
/** Format validation (from revalidator) - 'email', 'url', 'date-time', etc. */
format?: string;
// Input Control Properties
/** Hide input characters (for passwords) */
hidden?: boolean;
/** Replacement character for hidden input (default: '*') */
replace?: string;
/** Transform input before validation */
before?: (value: any) => any;
/** Dynamic condition to show/skip prompt */
ask?: () => boolean;
// Array Type Properties
/** For array type - maximum number of items */
maxItems?: number;
/** For array type - minimum number of items */
minItems?: number;
// Numeric Type Properties (inherited from revalidator)
/** For number/integer types - minimum value */
minimum?: number;
/** For number/integer types - maximum value */
maximum?: number;
// String Type Properties (inherited from revalidator)
/** For string type - minimum length */
minLength?: number;
/** For string type - maximum length */
maxLength?: number;
}Type-Specific Behavior:
Prompt inherits from EventEmitter and emits the following events:
/**
* Emitted when prompt.start() is called successfully
* Fired after streams are configured and SIGINT handlers are set up
*/
event 'start'
/**
* Emitted when prompt.pause() is called
* Fired after stdin.pause() is executed and prompt is in paused state
*/
event 'pause'
/**
* Emitted when prompt.resume() is called
* Fired after stdin.resume() is executed and prompt is active again
*/
event 'resume'
/**
* Emitted when prompt.stop() is called
* Fired after stdin is destroyed and prompt is fully stopped
*/
event 'stop'
/**
* Emitted when getInput begins prompting for a specific property
* Fired before the actual input prompt is displayed to the user
* @param {Object} prop - Property object being prompted for
* @param {Array} prop.path - Property path array (e.g., ['username'])
* @param {Object} prop.schema - Validation schema for this property
*/
event 'prompt'
/**
* Emitted when user input fails validation
* Fired after validation fails but before re-prompting the user
* @param {Object} prop - Property object that failed validation
* @param {Array} prop.path - Property path array
* @param {Object} prop.schema - Validation schema that failed
* @param {any} input - The input value that failed validation
*/
event 'invalid'Usage Example:
prompt.on('prompt', function(prop) {
console.log('Prompting for:', prop.path);
});
prompt.on('invalid', function(prop, input) {
console.log('Invalid input:', input, 'for property:', prop.path);
});Validation is handled through the revalidator package:
// Validation errors cause re-prompting
const schema = {
properties: {
email: {
format: 'email',
message: 'Please enter a valid email address'
}
}
};
try {
const result = await prompt.get(schema);
} catch (err) {
// Handle system errors (not validation errors)
console.error('System error:', err);
}// Handle SIGINT (Ctrl+C)
process.on('SIGINT', function() {
console.log('Received SIGINT, exiting...');
process.exit(1);
});
// Handle stream errors
prompt.start({
stdin: customInputStream,
stdout: customOutputStream
});const schema = {
properties: {
username: {
conform: function(value) {
return value.length >= 3 && /^[a-zA-Z0-9_]+$/.test(value);
},
message: 'Username must be at least 3 characters and contain only letters, numbers, and underscores'
}
}
};const schema = {
properties: {
hasEmail: {
type: 'boolean',
description: 'Do you have an email?'
},
email: {
ask: function() {
return prompt.history('hasEmail')?.value === true;
},
format: 'email',
description: 'Enter your email'
}
}
};const schema = {
properties: {
password: {
hidden: true,
replace: '*',
description: 'Enter password'
},
confirmPassword: {
hidden: true,
replace: '*',
description: 'Confirm password',
conform: function(value) {
return value === prompt.history('password')?.value;
},
message: 'Passwords do not match'
}
}
};