baseUI.js 2.2 KB

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