| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 | 'use strict';/** * Base prompt implementation * Should be extended by prompt types. */var _ = {  assign: require('lodash/assign'),  defaults: require('lodash/defaults'),  clone: require('lodash/clone'),};var chalk = require('chalk');var runAsync = require('run-async');var { filter, flatMap, share, take, takeUntil } = require('rxjs/operators');var Choices = require('../objects/choices');var ScreenManager = require('../utils/screen-manager');class Prompt {  constructor(question, rl, answers) {    // Setup instance defaults property    _.assign(this, {      answers: answers,      status: 'pending',    });    // Set defaults prompt options    this.opt = _.defaults(_.clone(question), {      validate: () => true,      filter: (val) => val,      when: () => true,      suffix: '',      prefix: chalk.green('?'),    });    // Make sure name is present    if (!this.opt.name) {      this.throwParamError('name');    }    // Set default message if no message defined    if (!this.opt.message) {      this.opt.message = this.opt.name + ':';    }    // Normalize choices    if (Array.isArray(this.opt.choices)) {      this.opt.choices = new Choices(this.opt.choices, answers);    }    this.rl = rl;    this.screen = new ScreenManager(this.rl);  }  /**   * Start the Inquiry session and manage output value filtering   * @return {Promise}   */  run() {    return new Promise((resolve, reject) => {      this._run(        (value) => resolve(value),        (error) => reject(error)      );    });  }  // Default noop (this one should be overwritten in prompts)  _run(cb) {    cb();  }  /**   * Throw an error telling a required parameter is missing   * @param  {String} name Name of the missing param   * @return {Throw Error}   */  throwParamError(name) {    throw new Error('You must provide a `' + name + '` parameter');  }  /**   * Called when the UI closes. Override to do any specific cleanup necessary   */  close() {    this.screen.releaseCursor();  }  /**   * Run the provided validation method each time a submit event occur.   * @param  {Rx.Observable} submit - submit event flow   * @return {Object}        Object containing two observables: `success` and `error`   */  handleSubmitEvents(submit) {    var self = this;    var validate = runAsync(this.opt.validate);    var asyncFilter = runAsync(this.opt.filter);    var validation = submit.pipe(      flatMap((value) =>        asyncFilter(value, self.answers).then(          (filteredValue) =>            validate(filteredValue, self.answers).then(              (isValid) => ({ isValid: isValid, value: filteredValue }),              (err) => ({ isValid: err, value: filteredValue })            ),          (err) => ({ isValid: err })        )      ),      share()    );    var success = validation.pipe(      filter((state) => state.isValid === true),      take(1)    );    var error = validation.pipe(      filter((state) => state.isValid !== true),      takeUntil(success)    );    return {      success: success,      error: error,    };  }  /**   * Generate the prompt question string   * @return {String} prompt question string   */  getQuestion() {    var message =      this.opt.prefix +      ' ' +      chalk.bold(this.opt.message) +      this.opt.suffix +      chalk.reset(' ');    // Append the default if available, and if question isn't answered    if (this.opt.default != null && this.status !== 'answered') {      // If default password is supplied, hide it      if (this.opt.type === 'password') {        message += chalk.italic.dim('[hidden] ');      } else {        message += chalk.dim('(' + this.opt.default + ') ');      }    }    return message;  }}module.exports = Prompt;
 |