UNPKG

2.62 kBJavaScriptView Raw
1'use strict';
2/**
3 * `password` type prompt
4 */
5
6const chalk = require('chalk');
7const { map, takeUntil } = require('rxjs/operators');
8const Base = require('./base');
9const observe = require('../utils/events');
10
11function mask(input, maskChar) {
12 input = String(input);
13 maskChar = typeof maskChar === 'string' ? maskChar : '*';
14 if (input.length === 0) {
15 return '';
16 }
17
18 return new Array(input.length + 1).join(maskChar);
19}
20
21class PasswordPrompt extends Base {
22 /**
23 * Start the Inquiry session
24 * @param {Function} cb Callback when prompt is done
25 * @return {this}
26 */
27
28 _run(cb) {
29 this.done = cb;
30
31 const events = observe(this.rl);
32
33 // Once user confirm (enter key)
34 const submit = events.line.pipe(map(this.filterInput.bind(this)));
35
36 const validation = this.handleSubmitEvents(submit);
37 validation.success.forEach(this.onEnd.bind(this));
38 validation.error.forEach(this.onError.bind(this));
39
40 events.keypress
41 .pipe(takeUntil(validation.success))
42 .forEach(this.onKeypress.bind(this));
43
44 // Init
45 this.render();
46
47 return this;
48 }
49
50 /**
51 * Render the prompt to screen
52 * @return {PasswordPrompt} self
53 */
54
55 render(error) {
56 let message = this.getQuestion();
57 let bottomContent = '';
58
59 if (this.status === 'answered') {
60 message += this.getMaskedValue(this.answer);
61 } else {
62 message += this.getMaskedValue(this.rl.line || '');
63 }
64
65 if (error) {
66 bottomContent = '\n' + chalk.red('>> ') + error;
67 }
68
69 this.screen.render(message, bottomContent);
70 }
71
72 getMaskedValue(value) {
73 if (this.status === 'answered') {
74 return this.opt.mask
75 ? chalk.cyan(mask(value, this.opt.mask))
76 : chalk.italic.dim('[hidden]');
77 }
78 return this.opt.mask
79 ? mask(value, this.opt.mask)
80 : chalk.italic.dim('[input is hidden] ');
81 }
82
83 /**
84 * Mask value during async filter/validation.
85 */
86 getSpinningValue(value) {
87 return this.getMaskedValue(value);
88 }
89
90 /**
91 * When user press `enter` key
92 */
93
94 filterInput(input) {
95 if (!input) {
96 return this.opt.default == null ? '' : this.opt.default;
97 }
98
99 return input;
100 }
101
102 onEnd(state) {
103 this.status = 'answered';
104 this.answer = state.value;
105
106 // Re-render prompt
107 this.render();
108
109 this.screen.done();
110 this.done(state.value);
111 }
112
113 onError(state) {
114 this.render(state.isValid);
115 }
116
117 onKeypress() {
118 // If user press a key, just clear the default value
119 if (this.opt.default) {
120 this.opt.default = undefined;
121 }
122
123 this.render();
124 }
125}
126
127module.exports = PasswordPrompt;