Promise-based wrappers for Node.js core APIs that modernize callback-based methods to work with async/await patterns
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Create interactive command-line interfaces with promise-based question handling and completer support. Provides modern async/await compatibility for Node.js readline operations.
Create readline interfaces for interactive command-line input.
/**
* Create a readline interface
* @param input - Readable stream for input
* @param output - Writable stream for output
* @param completer - Auto-completion function
* @param terminal - Whether to treat streams as TTY
* @returns Enhanced Interface instance
*/
function createInterface(input, output, completer, terminal): Interface;
/**
* Create a readline interface with options object
* @param options - Interface configuration options
* @returns Enhanced Interface instance
*/
function createInterface(options): Interface;Promise-enabled Interface class with auto-completion support.
/**
* Enhanced readline Interface with promise support
*/
class Interface {
/**
* Ask a question and wait for response
* @param query - Question string to display
* @param callback - Optional callback for traditional usage
* @returns Promise resolving to user's answer
*/
question(query, callback): Promise<string>;
// All other Interface methods from native readline are available
}Enhanced completer function handling for sync, async, and promise-based completers.
/**
* Completer function types supported:
* - Synchronous: (line) => [completions, line]
* - Asynchronous: (line, callback) => void
* - Promise-based: (line) => Promise<[completions, line]>
*/
type CompleterFunction =
| ((line: string) => [string[], string])
| ((line: string, callback: (err: Error, result: [string[], string]) => void) => void)
| ((line: string) => Promise<[string[], string]>);Usage Examples:
const readline = require('mz/readline');
const { stdin: input, stdout: output } = process;
// Basic question and answer
async function askQuestions() {
const rl = readline.createInterface({ input, output });
try {
const name = await rl.question('What is your name? ');
console.log(`Hello, ${name}!`);
const age = await rl.question('How old are you? ');
console.log(`You are ${age} years old.`);
} finally {
rl.close();
}
}
// Interactive command-line application
async function commandLineApp() {
const rl = readline.createInterface({ input, output });
console.log('Enter commands (type "quit" to exit):');
try {
while (true) {
const command = await rl.question('> ');
if (command.toLowerCase() === 'quit') {
break;
}
// Process command
console.log(`You entered: ${command}`);
}
} finally {
rl.close();
console.log('Goodbye!');
}
}
// With auto-completion (synchronous)
async function withSyncCompleter() {
function completer(line) {
const completions = ['help', 'quit', 'save', 'load', 'status'];
const hits = completions.filter(c => c.startsWith(line));
return [hits.length ? hits : completions, line];
}
const rl = readline.createInterface({
input,
output,
completer,
terminal: true
});
try {
const command = await rl.question('Enter command (tab for completion): ');
console.log(`Command: ${command}`);
} finally {
rl.close();
}
}
// With auto-completion (promise-based)
async function withPromiseCompleter() {
async function completer(line) {
// Simulate async completion (e.g., from database or API)
await new Promise(resolve => setTimeout(resolve, 10));
const completions = ['apple', 'banana', 'cherry', 'date'];
const hits = completions.filter(c => c.startsWith(line));
return [hits.length ? hits : completions, line];
}
const rl = readline.createInterface({
input,
output,
completer,
terminal: true
});
try {
const fruit = await rl.question('Choose a fruit (tab for completion): ');
console.log(`You chose: ${fruit}`);
} finally {
rl.close();
}
}
// Callback support is still available
const rl = readline.createInterface({ input, output });
rl.question('What is your favorite color? ', (answer) => {
console.log(`Your favorite color is ${answer}`);
rl.close();
});
// Password input (hide characters)
async function passwordInput() {
const rl = readline.createInterface({
input,
output: process.stderr, // Use stderr to avoid logging
terminal: true
});
try {
// Note: This doesn't actually hide input in basic implementation
// For true password input, you'd need additional libraries
const password = await rl.question('Password: ');
console.log('Password entered (hidden from logs)');
} finally {
rl.close();
}
}
// Multi-step form
async function multiStepForm() {
const rl = readline.createInterface({ input, output });
const user = {};
try {
user.name = await rl.question('Name: ');
user.email = await rl.question('Email: ');
user.age = parseInt(await rl.question('Age: '));
console.log('\nUser information:');
console.log(JSON.stringify(user, null, 2));
} finally {
rl.close();
}
}The createInterface() function accepts an options object:
interface InterfaceOptions {
/** Readable stream for input */
input: NodeJS.ReadableStream;
/** Writable stream for output */
output?: NodeJS.WritableStream;
/** Auto-completion function */
completer?: CompleterFunction;
/** Whether to treat as TTY terminal */
terminal?: boolean;
/** History size limit */
historySize?: number;
/** String to use for prompt */
prompt?: string;
/** String to use for continuation prompt */
crlfDelay?: number;
/** Whether to remove ANSI escape codes */
removeHistoryDuplicates?: boolean;
/** Escape code timeout */
escapeCodeTimeout?: number;
/** Tab size for completion */
tabSize?: number;
}The library automatically wraps completer functions to handle different patterns:
// Synchronous completer
function syncCompleter(line) {
const completions = ['help', 'quit'];
const hits = completions.filter(c => c.startsWith(line));
return [hits, line];
}
// Asynchronous completer with callback
function asyncCompleter(line, callback) {
setTimeout(() => {
const completions = ['help', 'quit'];
const hits = completions.filter(c => c.startsWith(line));
callback(null, [hits, line]);
}, 10);
}
// Promise-based completer
async function promiseCompleter(line) {
const completions = ['help', 'quit'];
const hits = completions.filter(c => c.startsWith(line));
return [hits, line];
}Readline operations can fail for various reasons:
const readline = require('mz/readline');
async function handleReadlineErrors() {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
try {
const answer = await rl.question('Enter something: ');
console.log('You entered:', answer);
} catch (error) {
console.error('Readline error:', error);
} finally {
rl.close();
}
}async function askWithValidation(rl, question, validator) {
while (true) {
const answer = await rl.question(question);
if (validator(answer)) {
return answer;
}
console.log('Invalid input, please try again.');
}
}
// Usage
const rl = readline.createInterface({ input, output });
const email = await askWithValidation(
rl,
'Email: ',
(input) => input.includes('@')
);async function showMenu(rl, options) {
console.log('\nSelect an option:');
options.forEach((option, index) => {
console.log(`${index + 1}. ${option}`);
});
while (true) {
const choice = await rl.question('Choice (1-' + options.length + '): ');
const index = parseInt(choice) - 1;
if (index >= 0 && index < options.length) {
return index;
}
console.log('Invalid choice, please try again.');
}
}InterfaceAsPromised class that extends native Interfaceobject-assign to merge with native readline exports