3 isPlainObject: require('lodash/isPlainObject'),
4 clone: require('lodash/clone'),
5 isArray: require('lodash/isArray'),
6 set: require('lodash/set'),
7 isFunction: require('lodash/isFunction'),
9 var { defer, empty, from, of } = require('rxjs');
10 var { concatMap, filter, publish, reduce } = require('rxjs/operators');
11 var runAsync = require('run-async');
12 var utils = require('../utils/utils');
13 var Base = require('./baseUI');
16 * Base interface class other can inherits from
19 class PromptUI extends Base {
20 constructor(prompts, opt) {
22 this.prompts = prompts;
25 run(questions, answers) {
26 // Keep global reference to the answers
27 if (_.isPlainObject(answers)) {
28 this.answers = _.clone(answers);
33 // Make sure questions is an array.
34 if (_.isPlainObject(questions)) {
35 questions = [questions];
38 // Create an observable, unless we received one as parameter.
39 // Note: As this is a public interface, we cannot do an instanceof check as we won't
40 // be using the exact same object in memory.
41 var obs = _.isArray(questions) ? from(questions) : questions;
43 this.process = obs.pipe(
44 concatMap(this.processQuestion.bind(this)),
45 publish() // Creates a hot Observable. It prevents duplicating prompts.
48 this.process.connect();
52 reduce((answers, answer) => {
53 _.set(answers, answer.name, answer.answer);
58 .then(this.onCompletion.bind(this), this.onError.bind(this));
62 * Once all prompt are over
73 return Promise.reject(error);
76 processQuestion(question) {
77 question = _.clone(question);
79 var obs = of(question);
82 concatMap(this.setDefaultType.bind(this)),
83 concatMap(this.filterIfRunnable.bind(this)),
85 utils.fetchAsyncQuestionProperty(question, 'message', this.answers)
88 utils.fetchAsyncQuestionProperty(question, 'default', this.answers)
91 utils.fetchAsyncQuestionProperty(question, 'choices', this.answers)
93 concatMap(this.fetchAnswer.bind(this))
98 fetchAnswer(question) {
99 var Prompt = this.prompts[question.type];
100 this.activePrompt = new Prompt(question, this.rl, this.answers);
105 .then((answer) => ({ name: question.name, answer: answer }))
110 setDefaultType(question) {
111 // Default type to input
112 if (!this.prompts[question.type]) {
113 question.type = 'input';
116 return defer(() => of(question));
119 filterIfRunnable(question) {
120 if (question.askAnswered !== true && this.answers[question.name] !== undefined) {
124 if (question.when === false) {
128 if (!_.isFunction(question.when)) {
132 var answers = this.answers;
135 runAsync(question.when)(answers).then((shouldRun) => {
140 ).pipe(filter((val) => val != null))
145 module.exports = PromptUI;