source: trip-planner-front/node_modules/inquirer/lib/prompts/base.js@ 8d391a1

Last change on this file since 8d391a1 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 4.3 KB
Line 
1'use strict';
2/**
3 * Base prompt implementation
4 * Should be extended by prompt types.
5 */
6const _ = {
7 assign: require('lodash/assign'),
8 defaults: require('lodash/defaults'),
9 clone: require('lodash/clone'),
10};
11const chalk = require('chalk');
12const runAsync = require('run-async');
13const { filter, flatMap, share, take, takeUntil } = require('rxjs/operators');
14const Choices = require('../objects/choices');
15const ScreenManager = require('../utils/screen-manager');
16
17class Prompt {
18 constructor(question, rl, answers) {
19 // Setup instance defaults property
20 _.assign(this, {
21 answers,
22 status: 'pending',
23 });
24
25 // Set defaults prompt options
26 this.opt = _.defaults(_.clone(question), {
27 validate: () => true,
28 validatingText: '',
29 filter: (val) => val,
30 filteringText: '',
31 when: () => true,
32 suffix: '',
33 prefix: chalk.green('?'),
34 });
35
36 // Make sure name is present
37 if (!this.opt.name) {
38 this.throwParamError('name');
39 }
40
41 // Set default message if no message defined
42 if (!this.opt.message) {
43 this.opt.message = this.opt.name + ':';
44 }
45
46 // Normalize choices
47 if (Array.isArray(this.opt.choices)) {
48 this.opt.choices = new Choices(this.opt.choices, answers);
49 }
50
51 this.rl = rl;
52 this.screen = new ScreenManager(this.rl);
53 }
54
55 /**
56 * Start the Inquiry session and manage output value filtering
57 * @return {Promise}
58 */
59
60 run() {
61 return new Promise((resolve, reject) => {
62 this._run(
63 (value) => resolve(value),
64 (error) => reject(error)
65 );
66 });
67 }
68
69 // Default noop (this one should be overwritten in prompts)
70 _run(cb) {
71 cb();
72 }
73
74 /**
75 * Throw an error telling a required parameter is missing
76 * @param {String} name Name of the missing param
77 * @return {Throw Error}
78 */
79
80 throwParamError(name) {
81 throw new Error('You must provide a `' + name + '` parameter');
82 }
83
84 /**
85 * Called when the UI closes. Override to do any specific cleanup necessary
86 */
87 close() {
88 this.screen.releaseCursor();
89 }
90
91 /**
92 * Run the provided validation method each time a submit event occur.
93 * @param {Rx.Observable} submit - submit event flow
94 * @return {Object} Object containing two observables: `success` and `error`
95 */
96 handleSubmitEvents(submit) {
97 const self = this;
98 const validate = runAsync(this.opt.validate);
99 const asyncFilter = runAsync(this.opt.filter);
100 const validation = submit.pipe(
101 flatMap((value) => {
102 this.startSpinner(value, this.opt.filteringText);
103 return asyncFilter(value, self.answers).then(
104 (filteredValue) => {
105 this.startSpinner(filteredValue, this.opt.validatingText);
106 return validate(filteredValue, self.answers).then(
107 (isValid) => ({ isValid, value: filteredValue }),
108 (err) => ({ isValid: err, value: filteredValue })
109 );
110 },
111 (err) => ({ isValid: err })
112 );
113 }),
114 share()
115 );
116
117 const success = validation.pipe(
118 filter((state) => state.isValid === true),
119 take(1)
120 );
121 const error = validation.pipe(
122 filter((state) => state.isValid !== true),
123 takeUntil(success)
124 );
125
126 return {
127 success,
128 error,
129 };
130 }
131
132 startSpinner(value, bottomContent) {
133 // If the question will spin, cut off the prefix (for layout purposes)
134 const content = bottomContent
135 ? this.getQuestion() + value
136 : this.getQuestion().slice(this.opt.prefix.length + 1) + value;
137
138 this.screen.renderWithSpinner(content, bottomContent);
139 }
140
141 /**
142 * Generate the prompt question string
143 * @return {String} prompt question string
144 */
145 getQuestion() {
146 let message =
147 this.opt.prefix +
148 ' ' +
149 chalk.bold(this.opt.message) +
150 this.opt.suffix +
151 chalk.reset(' ');
152
153 // Append the default if available, and if question isn't touched/answered
154 if (
155 this.opt.default != null &&
156 this.status !== 'touched' &&
157 this.status !== 'answered'
158 ) {
159 // If default password is supplied, hide it
160 if (this.opt.type === 'password') {
161 message += chalk.italic.dim('[hidden] ');
162 } else {
163 message += chalk.dim('(' + this.opt.default + ') ');
164 }
165 }
166
167 return message;
168 }
169}
170
171module.exports = Prompt;
Note: See TracBrowser for help on using the repository browser.