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