Also, I was looking for an answer how to flatten (and automate) calls to rl.question(). In my solution I used Promises - chained - to display questions sequentially.
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const QUESTIONS = {
action1: ['A1: Question 1', 'A1: Question 2', 'A1: Question 3'],
action2: ['A2: Question 1', 'A2: Question 2', 'A2: Question 3']
}
let askQuestions = (actionKey) => {
return new Promise( (res, rej) => {
let questions = QUESTIONS[actionKey];
if(typeof questions === 'undefined') rej(`Wrong action key: ${actionKey}`);
let chainQ = Promise.resolve([]); // resolve to active 'then' chaining (empty array for answers)
questions.forEach(question => {
chainQ = chainQ.then( answers => new Promise( (resQ, rejQ) => {
rl.question(`${question}: `, answer => { answers.push(answer); resQ(answers); });
})
);
});
chainQ.then((answers) => {
rl.close();
res(answers);
})
});
};
let handleError = (err) => {
console.log(`ERROR: ${err}`);
}
let doSomethingwithAnswers = (answers) => {
return new Promise( (res, rej) => {
console.log('OUTPUT:');
console.dir(answers);
});
}
askQuestions('action1')
.then(doSomethingwithAnswers)
.catch(handleError);
Output:
A1: Question 1: a
A1: Question 2: b
A1: Question 3: c
OUTPUT:
[ 'a', 'b', 'c' ]
If you want the action to be chosen by the user, add these functions:
let showInterface = () => {
return new Promise( (res, rej) => {
console.log('Select action (enter action name):')
console.log('-'.repeat(30));
Object.keys(QUESTIONS).forEach(actionKey => {
console.log(`${actionKey}`);
});
console.log('-'.repeat(30));
res();
});
};
let askQuestionForActionKey = () => {
return new Promise( (res, rej) => {
rl.question('Action key: ', actionKey => res(actionKey));
});
}
And change main procedure to:
showInterface()
.then(askQuestionForActionKey)
.then(askQuestions)
.then(doSomethingwithAnswers)
.catch(handleError);
Now output shoud be like:
Select action (enter action name):
------------------------------
action1
action2
------------------------------
Action key: action1
A1: Question 1: a
A1: Question 2: b
A1: Question 3: c
OUTPUT:
[ 'a', 'b', 'c' ]
In case of error (e.g. enter non-existent action 'action3'):
Select action (enter action name):
------------------------------
action1
action2
------------------------------
Action key: action3
ERROR: Wrong action key: action3
It's very easy to apply this solution to your problem. Just define your questions as:
const QUESTIONS = {
sequence: ['Thing One', 'Thing Two', 'Thing Three']
};
Your callback with answers:
let doSomethingwithAnswers = (answers) => {
return new Promise( (res, rej) => {
console.log('Make stuff with answers:');
console.dir(answers);
});
}
And the procedure may be unchanged - when a user has the ability to select a set of questions (actions):
showInterface()
.then(askQuestionForActionKey)
.then(askQuestions)
.then(doSomethingwithAnswers)
.catch(handleError);
Output:
Select action (enter action name):
------------------------------
sequence
------------------------------
Action key: sequence
Thing One: a
Thing Two: b
Thing Three: c
Make stuff with answers:
[ 'a', 'b', 'c' ]
Or if you want to apply to concrete questions set just use:
askQuestions('sequence')
.then(doSomethingwithAnswers)
.catch(handleError);
Output:
Thing One: a
Thing Two: b
Thing Three: c
Make stuff with answers:
[ 'a', 'b', 'c' ]
I hope it will be useful :)
Enjoy!