Created
January 3, 2025 02:17
-
-
Save psenger/eefb95d72835e2a1fd828bdd4c4f5afc to your computer and use it in GitHub Desktop.
[Prompt with NodeJS] #JavaScript #prompt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const readline = require('readline') | |
/** | |
* Prompts the user with a question and returns their answer. | |
* | |
* @param {readline.Interface} rl - The readline interface instance | |
* @param {string} query - The question to ask the user | |
* @returns {Promise<string>} A promise that resolves with the user's answer | |
* | |
* @example | |
* const rl = readline.createInterface({ | |
* input: process.stdin, | |
* output: process.stdout | |
* }); | |
* const answer = await askQuestion(rl, 'What is your name? '); | |
*/ | |
const askQuestion = (rl, query) => new Promise((resolve) => rl.question(query, resolve)); | |
/** | |
* Presents a numbered list of options to the user and prompts them to select one. | |
* Continues prompting until a valid selection is made. | |
* | |
* @param {string} label - The text to display above the list of options | |
* @param {string[]} options - Array of options to present to the user | |
* @returns {Promise<string>} A promise that resolves with the selected option | |
* | |
* @throws {Error} Will not throw, but may never resolve if user never provides valid input | |
* | |
* @example | |
* // Basic usage | |
* const host = await promptOptions('Select a host', [ | |
* 'https://abc.com/', | |
* 'https://def.com/' | |
* ]); | |
* console.log(`Selected host: ${host}`); | |
* | |
* @example | |
* // Example output: | |
* // Select a host: | |
* // 1. https://abc.com/ | |
* // 2. https://def.com/ | |
* // Enter option number: 1 | |
* // Returns: 'https://abc.com/' | |
*/ | |
const promptOptions = async (label, options) => { | |
const rl = readline.createInterface({ | |
input: process.stdin, | |
output: process.stdout | |
}); | |
while (true) { // Infinite loop, will exit via return statements | |
console.log(`${label}:\n${options.map((host, index) => { | |
return `${index + 1}. ${host}`; | |
}).join('\n')}`); | |
const answer = await askQuestion(rl, 'Enter option number: '); | |
const index = Number.parseInt(answer.trim(), 10) - 1; | |
if (index >= 0 && index <= options.length - 1) { | |
rl.close(); | |
return options[index]; | |
} | |
} | |
} | |
/** | |
* Presents a numbered list of options to the user and returns both the selected value and label. | |
* Each option consists of a value-label pair provided as an object. | |
* | |
* @template T The type of the value in the value-label pair | |
* @param {string} label - The text to display above the list of options | |
* @param {Array<{value: T, label: string}>} options - Array of options, each with a value and display label | |
* @returns {Promise<{value: T, label: string}>} A promise that resolves with the selected option object | |
* | |
* @example | |
* // Basic usage with mixed value types | |
* const route = await promptWithValueLabel('Enter route', [ | |
* { value: 'A24', label: 'Highway A23' }, | |
* { value: 53, label: 'Route 53' }, | |
* { value: null, label: 'none' } | |
* ]); | |
* console.log(`Selected: ${route.label} (value: ${route.value})`); | |
* | |
* @example | |
* // Example output: | |
* // Enter route: | |
* // 1. Highway A23 | |
* // 2. Route 53 | |
* // 3. none | |
* // Enter option number: 1 | |
* // Returns: { value: 'A24', label: 'Highway A23' } | |
* | |
* @throws {Error} Will not throw, but may never resolve if user never provides valid input | |
*/ | |
const promptWithValueLabel = async (label, options) => { | |
const rl = readline.createInterface({ | |
input: process.stdin, | |
output: process.stdout | |
}); | |
while (true) { // Infinite loop, will exit via return statements | |
console.log(`${label}:\n${options.map(({value: optionValue, label: optionLabel}, index) => { | |
return `${index + 1}. ${optionLabel}`; | |
}).join('\n')}`); | |
const answer = await askQuestion(rl, 'Enter option number: '); | |
const index = Number.parseInt(answer.trim(), 10) - 1; | |
if (index >= 0 && index <= options.length - 1) { | |
rl.close(); | |
return { | |
value: options[index].value, | |
label: options[index].label | |
}; | |
} | |
} | |
}; | |
/** | |
* Prompts the user for input with a custom label and validates that the input is not empty. | |
* Continues prompting until valid input is received. | |
* | |
* @param {string} label - The prompt text to display to the user | |
* @returns {Promise<string>} A promise that resolves with the validated, trimmed user input | |
* | |
* @example | |
* // Basic usage | |
* async function main() { | |
* const name = await promptInput('Enter your name'); | |
* console.log(`Hello, ${name}!`); | |
* } | |
* | |
* @example | |
* // Example with validation loop | |
* // Enter your name: // User hits enter with no input | |
* // Invalid. Please try again. | |
* // Enter your name: John | |
* // Returns: "John" | |
* | |
* @example | |
* // Handling whitespace | |
* // Enter your name: John Smith | |
* // Returns: "John Smith" // Note: leading/trailing spaces removed | |
* | |
* @throws {Error} Will not throw, but may never resolve if user never provides valid input | |
*/ | |
const promptInput = async (label) => { | |
const rl = readline.createInterface({ | |
input: process.stdin, | |
output: process.stdout | |
}); | |
while (true) { // Infinite loop, will exit via return statements | |
const answer = await askQuestion(rl, `${label}: `); | |
if (answer.trim() !== '') { | |
rl.close(); | |
return answer.trim(); | |
} | |
console.log('Invalid. Please try again.'); | |
} | |
}; | |
const example = async () => { | |
const host = await promptOptions('Select a host', [ | |
'https://abc.com/', | |
'https://def.com/' | |
]) | |
const route = await promptWithValueLabel('Enter route', [ | |
{value: 'A24', label: 'Highway A23'}, | |
{value: 53, label: 'Route 53'}, | |
{value: null, label: 'none'}, | |
]) | |
const name = await promptInput('Enter your name') | |
return {host, route, name} | |
} | |
example() | |
.then((...args) => { | |
console.log(...args) | |
process.exit(0) | |
}) | |
.catch((err) => { | |
console.log(err) | |
process.exit(1) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment