prompt-bypass.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
  3. var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
  4. _Object$defineProperty(exports, "__esModule", {
  5. value: true
  6. });
  7. exports.default = _default;
  8. var _assign = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/assign"));
  9. var _isArray = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/array/is-array"));
  10. var _map = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/map"));
  11. var _some = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/some"));
  12. var _filter = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/filter"));
  13. var _find = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/find"));
  14. var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/includes"));
  15. /* ========================================================================
  16. * PROMPT BYPASSING
  17. * -----------------
  18. * this allows a user to bypass a prompt by supplying input before
  19. * the prompts are run. we handle input differently depending on the
  20. * type of prompt that's in play (ie "y" means "true" for a confirm prompt)
  21. * ======================================================================== */
  22. /////
  23. // HELPER FUNCTIONS
  24. //
  25. // pull the "value" out of a choice option
  26. const getChoiceValue = choice => {
  27. const isObject = typeof choice === 'object';
  28. if (isObject && choice.value != null) {
  29. return choice.value;
  30. }
  31. if (isObject && choice.name != null) {
  32. return choice.name;
  33. }
  34. if (isObject && choice.key != null) {
  35. return choice.key;
  36. }
  37. return choice;
  38. }; // check if the choice value matches the bypass value
  39. function checkChoiceValue(choiceValue, value) {
  40. return typeof choiceValue === 'string' && choiceValue.toLowerCase() === value.toLowerCase();
  41. } // check if a bypass value matches some aspect of
  42. // a particular choice option (index, value, key, etc)
  43. function choiceMatchesValue(choice, choiceIdx, value) {
  44. return checkChoiceValue(choice, value) || checkChoiceValue(choice.value, value) || checkChoiceValue(choice.key, value) || checkChoiceValue(choice.name, value) || checkChoiceValue(choiceIdx.toString(), value);
  45. } // check if a value matches a particular set of flagged input options
  46. const isFlag = (list, v) => (0, _includes.default)(list).call(list, v.toLowerCase()); // input values that represent different types of responses
  47. const flag = {
  48. isTrue: v => isFlag(['yes', 'y', 'true', 't'], v),
  49. isFalse: v => isFlag(['no', 'n', 'false', 'f'], v),
  50. isPrompt: v => /^_+$/.test(v)
  51. }; // generic list bypass function. used for all types of lists.
  52. // accepts value, index, or key as matching criteria
  53. const listTypeBypass = (v, prompt) => {
  54. var _context;
  55. const choice = (0, _find.default)(_context = prompt.choices).call(_context, (c, idx) => choiceMatchesValue(c, idx, v));
  56. if (choice != null) {
  57. return getChoiceValue(choice);
  58. }
  59. throw Error('invalid choice');
  60. }; /////
  61. // BYPASS FUNCTIONS
  62. //
  63. // list of prompt bypass functions by prompt type
  64. const typeBypass = {
  65. confirm(v) {
  66. if (flag.isTrue(v)) {
  67. return true;
  68. }
  69. if (flag.isFalse(v)) {
  70. return false;
  71. }
  72. throw Error('invalid input');
  73. },
  74. checkbox(v, prompt) {
  75. const valList = v.split(',');
  76. const valuesNoMatch = (0, _filter.default)(valList).call(valList, val => {
  77. var _context2;
  78. return !(0, _some.default)(_context2 = prompt.choices).call(_context2, (c, idx) => choiceMatchesValue(c, idx, val));
  79. });
  80. if (valuesNoMatch.length) {
  81. throw Error(`no match for "${valuesNoMatch.join('", "')}"`);
  82. }
  83. return (0, _map.default)(valList).call(valList, val => {
  84. var _context3;
  85. return getChoiceValue((0, _find.default)(_context3 = prompt.choices).call(_context3, (c, idx) => choiceMatchesValue(c, idx, val)));
  86. });
  87. },
  88. list: listTypeBypass,
  89. rawlist: listTypeBypass,
  90. expand: listTypeBypass
  91. }; /////
  92. // MAIN LOGIC
  93. //
  94. // returns new prompts, initial answers object, and any failures
  95. function _default(prompts, bypassArr, plop) {
  96. const noop = [prompts, {}, []]; // bail out if we don't have prompts or bypass data
  97. if (!(0, _isArray.default)(prompts)) {
  98. return noop;
  99. }
  100. if (bypassArr.length === 0) {
  101. return noop;
  102. } // pull registered prompts out of inquirer
  103. const {
  104. prompts: inqPrompts
  105. } = plop.inquirer.prompt;
  106. const answers = {};
  107. const bypassFailures = []; // generate a list of pompts that the user is bypassing
  108. const bypassedPrompts = (0, _filter.default)(prompts).call(prompts, function (p, idx) {
  109. // if the user didn't provide value for this prompt, skip it
  110. if (idx >= bypassArr.length) {
  111. return false;
  112. }
  113. const val = bypassArr[idx].toString(); // if the user asked to be given this prompt, skip it
  114. if (flag.isPrompt(val)) {
  115. return false;
  116. } // if this prompt is dynamic, throw error because we can't know if
  117. // the pompt bypass values given line up with the path this user
  118. // has taken through the prompt tree.
  119. if (typeof p.when === 'function') {
  120. bypassFailures.push(`You can not bypass conditional prompts: ${p.name}`);
  121. return false;
  122. }
  123. try {
  124. const inqPrompt = inqPrompts[p.type] || {}; // try to find a bypass function to run
  125. const bypass = p.bypass || inqPrompt.bypass || typeBypass[p.type] || null; // get the real answer data out of the bypass function and attach it
  126. // to the answer data object
  127. const bypassIsFunc = typeof bypass === 'function';
  128. const value = bypassIsFunc ? bypass.call(null, val, p) : val; // if inquirer prompt has a filter function - call it
  129. const answer = (0, _filter.default)(p) ? (0, _filter.default)(p).call(p, value, answers) : value; // if inquirer prompt has a validate function - call it
  130. if (p.validate) {
  131. const validation = p.validate(value, answers);
  132. if (validation !== true) {
  133. // if validation failed return validation error
  134. bypassFailures.push(validation);
  135. return false;
  136. }
  137. }
  138. answers[p.name] = answer;
  139. } catch (err) {
  140. // if we encounter an error above... assume the bypass value was invalid
  141. bypassFailures.push(`The "${p.name}" prompt did not recognize "${val}" as a valid ${p.type} value (ERROR: ${err.message})`);
  142. return false;
  143. } // if we got this far, we successfully bypassed this prompt
  144. return true;
  145. }); // rip out any prompts that have been bypassed
  146. const promptsAfterBypass = [// first prompt will copy the bypass answer data so it's available
  147. // for prompts and actions to use
  148. {
  149. when: data => ((0, _assign.default)(data, answers), false)
  150. }, // inlcude any prompts that were NOT bypassed
  151. ...(0, _filter.default)(prompts).call(prompts, p => !(0, _includes.default)(bypassedPrompts).call(bypassedPrompts, p))]; // if we have failures, throw the first one
  152. if (bypassFailures.length) {
  153. throw Error(bypassFailures[0]);
  154. } else {
  155. // return the prompts that still need to be run
  156. return [promptsAfterBypass, answers];
  157. } // BOOM!
  158. }