prompts.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. 'use strict';
  2. const $ = exports;
  3. const el = require('./elements');
  4. const noop = v => v;
  5. function toPrompt(type, args, opts = {}) {
  6. return new Promise((res, rej) => {
  7. const p = new el[type](args);
  8. const onAbort = opts.onAbort || noop;
  9. const onSubmit = opts.onSubmit || noop;
  10. const onExit = opts.onExit || noop;
  11. p.on('state', args.onState || noop);
  12. p.on('submit', x => res(onSubmit(x)));
  13. p.on('exit', x => res(onExit(x)));
  14. p.on('abort', x => rej(onAbort(x)));
  15. });
  16. }
  17. /**
  18. * Text prompt
  19. * @param {string} args.message Prompt message to display
  20. * @param {string} [args.initial] Default string value
  21. * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
  22. * @param {function} [args.onState] On state change callback
  23. * @param {function} [args.validate] Function to validate user input
  24. * @param {Stream} [args.stdin] The Readable stream to listen to
  25. * @param {Stream} [args.stdout] The Writable stream to write readline data to
  26. * @returns {Promise} Promise with user input
  27. */
  28. $.text = args => toPrompt('TextPrompt', args);
  29. /**
  30. * Password prompt with masked input
  31. * @param {string} args.message Prompt message to display
  32. * @param {string} [args.initial] Default string value
  33. * @param {function} [args.onState] On state change callback
  34. * @param {function} [args.validate] Function to validate user input
  35. * @param {Stream} [args.stdin] The Readable stream to listen to
  36. * @param {Stream} [args.stdout] The Writable stream to write readline data to
  37. * @returns {Promise} Promise with user input
  38. */
  39. $.password = args => {
  40. args.style = 'password';
  41. return $.text(args);
  42. };
  43. /**
  44. * Prompt where input is invisible, like sudo
  45. * @param {string} args.message Prompt message to display
  46. * @param {string} [args.initial] Default string value
  47. * @param {function} [args.onState] On state change callback
  48. * @param {function} [args.validate] Function to validate user input
  49. * @param {Stream} [args.stdin] The Readable stream to listen to
  50. * @param {Stream} [args.stdout] The Writable stream to write readline data to
  51. * @returns {Promise} Promise with user input
  52. */
  53. $.invisible = args => {
  54. args.style = 'invisible';
  55. return $.text(args);
  56. };
  57. /**
  58. * Number prompt
  59. * @param {string} args.message Prompt message to display
  60. * @param {number} args.initial Default number value
  61. * @param {function} [args.onState] On state change callback
  62. * @param {number} [args.max] Max value
  63. * @param {number} [args.min] Min value
  64. * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
  65. * @param {Boolean} [opts.float=false] Parse input as floats
  66. * @param {Number} [opts.round=2] Round floats to x decimals
  67. * @param {Number} [opts.increment=1] Number to increment by when using arrow-keys
  68. * @param {function} [args.validate] Function to validate user input
  69. * @param {Stream} [args.stdin] The Readable stream to listen to
  70. * @param {Stream} [args.stdout] The Writable stream to write readline data to
  71. * @returns {Promise} Promise with user input
  72. */
  73. $.number = args => toPrompt('NumberPrompt', args);
  74. /**
  75. * Date prompt
  76. * @param {string} args.message Prompt message to display
  77. * @param {number} args.initial Default number value
  78. * @param {function} [args.onState] On state change callback
  79. * @param {number} [args.max] Max value
  80. * @param {number} [args.min] Min value
  81. * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
  82. * @param {Boolean} [opts.float=false] Parse input as floats
  83. * @param {Number} [opts.round=2] Round floats to x decimals
  84. * @param {Number} [opts.increment=1] Number to increment by when using arrow-keys
  85. * @param {function} [args.validate] Function to validate user input
  86. * @param {Stream} [args.stdin] The Readable stream to listen to
  87. * @param {Stream} [args.stdout] The Writable stream to write readline data to
  88. * @returns {Promise} Promise with user input
  89. */
  90. $.date = args => toPrompt('DatePrompt', args);
  91. /**
  92. * Classic yes/no prompt
  93. * @param {string} args.message Prompt message to display
  94. * @param {boolean} [args.initial=false] Default value
  95. * @param {function} [args.onState] On state change callback
  96. * @param {Stream} [args.stdin] The Readable stream to listen to
  97. * @param {Stream} [args.stdout] The Writable stream to write readline data to
  98. * @returns {Promise} Promise with user input
  99. */
  100. $.confirm = args => toPrompt('ConfirmPrompt', args);
  101. /**
  102. * List prompt, split intput string by `seperator`
  103. * @param {string} args.message Prompt message to display
  104. * @param {string} [args.initial] Default string value
  105. * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
  106. * @param {string} [args.separator] String separator
  107. * @param {function} [args.onState] On state change callback
  108. * @param {Stream} [args.stdin] The Readable stream to listen to
  109. * @param {Stream} [args.stdout] The Writable stream to write readline data to
  110. * @returns {Promise} Promise with user input, in form of an `Array`
  111. */
  112. $.list = args => {
  113. const sep = args.separator || ',';
  114. return toPrompt('TextPrompt', args, {
  115. onSubmit: str => str.split(sep).map(s => s.trim())
  116. });
  117. };
  118. /**
  119. * Toggle/switch prompt
  120. * @param {string} args.message Prompt message to display
  121. * @param {boolean} [args.initial=false] Default value
  122. * @param {string} [args.active="on"] Text for `active` state
  123. * @param {string} [args.inactive="off"] Text for `inactive` state
  124. * @param {function} [args.onState] On state change callback
  125. * @param {Stream} [args.stdin] The Readable stream to listen to
  126. * @param {Stream} [args.stdout] The Writable stream to write readline data to
  127. * @returns {Promise} Promise with user input
  128. */
  129. $.toggle = args => toPrompt('TogglePrompt', args);
  130. /**
  131. * Interactive select prompt
  132. * @param {string} args.message Prompt message to display
  133. * @param {Array} args.choices Array of choices objects `[{ title, value }, ...]`
  134. * @param {number} [args.initial] Index of default value
  135. * @param {String} [args.hint] Hint to display
  136. * @param {function} [args.onState] On state change callback
  137. * @param {Stream} [args.stdin] The Readable stream to listen to
  138. * @param {Stream} [args.stdout] The Writable stream to write readline data to
  139. * @returns {Promise} Promise with user input
  140. */
  141. $.select = args => toPrompt('SelectPrompt', args);
  142. /**
  143. * Interactive multi-select / autocompleteMultiselect prompt
  144. * @param {string} args.message Prompt message to display
  145. * @param {Array} args.choices Array of choices objects `[{ title, value, [selected] }, ...]`
  146. * @param {number} [args.max] Max select
  147. * @param {string} [args.hint] Hint to display user
  148. * @param {Number} [args.cursor=0] Cursor start position
  149. * @param {function} [args.onState] On state change callback
  150. * @param {Stream} [args.stdin] The Readable stream to listen to
  151. * @param {Stream} [args.stdout] The Writable stream to write readline data to
  152. * @returns {Promise} Promise with user input
  153. */
  154. $.multiselect = args => {
  155. args.choices = [].concat(args.choices || []);
  156. const toSelected = items => items.filter(item => item.selected).map(item => item.value);
  157. return toPrompt('MultiselectPrompt', args, {
  158. onAbort: toSelected,
  159. onSubmit: toSelected
  160. });
  161. };
  162. $.autocompleteMultiselect = args => {
  163. args.choices = [].concat(args.choices || []);
  164. const toSelected = items => items.filter(item => item.selected).map(item => item.value);
  165. return toPrompt('AutocompleteMultiselectPrompt', args, {
  166. onAbort: toSelected,
  167. onSubmit: toSelected
  168. });
  169. };
  170. const byTitle = (input, choices) => Promise.resolve(choices.filter(item => item.title.slice(0, input.length).toLowerCase() === input.toLowerCase()));
  171. /**
  172. * Interactive auto-complete prompt
  173. * @param {string} args.message Prompt message to display
  174. * @param {Array} args.choices Array of auto-complete choices objects `[{ title, value }, ...]`
  175. * @param {Function} [args.suggest] Function to filter results based on user input. Defaults to sort by `title`
  176. * @param {number} [args.limit=10] Max number of results to show
  177. * @param {string} [args.style="default"] Render style ('default', 'password', 'invisible')
  178. * @param {String} [args.initial] Index of the default value
  179. * @param {boolean} [opts.clearFirst] The first ESCAPE keypress will clear the input
  180. * @param {String} [args.fallback] Fallback message - defaults to initial value
  181. * @param {function} [args.onState] On state change callback
  182. * @param {Stream} [args.stdin] The Readable stream to listen to
  183. * @param {Stream} [args.stdout] The Writable stream to write readline data to
  184. * @returns {Promise} Promise with user input
  185. */
  186. $.autocomplete = args => {
  187. args.suggest = args.suggest || byTitle;
  188. args.choices = [].concat(args.choices || []);
  189. return toPrompt('AutocompletePrompt', args);
  190. };