UNPKG

2.37 kBJavaScriptView Raw
1'use strict';
2const _ = {
3 extend: require('lodash/extend'),
4 omit: require('lodash/omit'),
5};
6const MuteStream = require('mute-stream');
7const readline = require('readline');
8
9/**
10 * Base interface class other can inherits from
11 */
12
13class UI {
14 constructor(opt) {
15 // Instantiate the Readline interface
16 // @Note: Don't reassign if already present (allow test to override the Stream)
17 if (!this.rl) {
18 this.rl = readline.createInterface(setupReadlineOptions(opt));
19 }
20
21 this.rl.resume();
22
23 this.onForceClose = this.onForceClose.bind(this);
24
25 // Make sure new prompt start on a newline when closing
26 process.on('exit', this.onForceClose);
27
28 // Terminate process on SIGINT (which will call process.on('exit') in return)
29 this.rl.on('SIGINT', this.onForceClose);
30 }
31
32 /**
33 * Handle the ^C exit
34 * @return {null}
35 */
36
37 onForceClose() {
38 this.close();
39 process.kill(process.pid, 'SIGINT');
40 console.log('');
41 }
42
43 /**
44 * Close the interface and cleanup listeners
45 */
46
47 close() {
48 // Remove events listeners
49 this.rl.removeListener('SIGINT', this.onForceClose);
50 process.removeListener('exit', this.onForceClose);
51
52 this.rl.output.unmute();
53
54 if (this.activePrompt && typeof this.activePrompt.close === 'function') {
55 this.activePrompt.close();
56 }
57
58 // Close the readline
59 this.rl.output.end();
60 this.rl.pause();
61 this.rl.close();
62 }
63}
64
65function setupReadlineOptions(opt) {
66 opt = opt || {};
67 // Inquirer 8.x:
68 // opt.skipTTYChecks = opt.skipTTYChecks === undefined ? opt.input !== undefined : opt.skipTTYChecks;
69 opt.skipTTYChecks = opt.skipTTYChecks === undefined ? true : opt.skipTTYChecks;
70
71 // Default `input` to stdin
72 const input = opt.input || process.stdin;
73
74 // Check if prompt is being called in TTY environment
75 // If it isn't return a failed promise
76 if (!opt.skipTTYChecks && !input.isTTY) {
77 const nonTtyError = new Error(
78 'Prompts can not be meaningfully rendered in non-TTY environments'
79 );
80 nonTtyError.isTtyError = true;
81 throw nonTtyError;
82 }
83
84 // Add mute capabilities to the output
85 const ms = new MuteStream();
86 ms.pipe(opt.output || process.stdout);
87 const output = ms;
88
89 return _.extend(
90 {
91 terminal: true,
92 input,
93 output,
94 },
95 _.omit(opt, ['input', 'output'])
96 );
97}
98
99module.exports = UI;