baseUI.js 2.3 KB

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