"use strict";
|
|
Object.defineProperty(exports, "__esModule", {
|
value: true
|
});
|
exports.default = _default;
|
|
/* ========================================================================
|
* PROMPT BYPASSING
|
* -----------------
|
* this allows a user to bypass a prompt by supplying input before
|
* the prompts are run. we handle input differently depending on the
|
* type of prompt that's in play (ie "y" means "true" for a confirm prompt)
|
* ======================================================================== */
|
/////
|
// HELPER FUNCTIONS
|
//
|
// pull the "value" out of a choice option
|
const getChoiceValue = choice => {
|
const isObject = typeof choice === 'object';
|
|
if (isObject && choice.value != null) {
|
return choice.value;
|
}
|
|
if (isObject && choice.name != null) {
|
return choice.name;
|
}
|
|
if (isObject && choice.key != null) {
|
return choice.key;
|
}
|
|
return choice;
|
}; // check if a bypass value matches some aspect of
|
// a particular choice option (index, value, key, etc)
|
|
|
const choiceMatchesValue = (choice, choiceIdx, value) => {
|
const choiceValue = getChoiceValue(choice);
|
const valueMatchesChoice = choiceValue && choiceValue.toLowerCase() === value.toLowerCase();
|
const valueMatchesChoiceKey = typeof choice.key === 'string' && choice.key.toLowerCase() === value.toLowerCase();
|
const valueMatchesChoiceName = typeof choice.name === 'string' && choice.name.toLowerCase() === value.toLowerCase();
|
const valueMatchesChoiceIndex = choiceIdx.toString() === value;
|
return valueMatchesChoice || valueMatchesChoiceKey || valueMatchesChoiceName || valueMatchesChoiceIndex;
|
}; // check if a value matches a particular set of flagged input options
|
|
|
const isFlag = (list, v) => list.includes(v.toLowerCase()); // input values that represent different types of responses
|
|
|
const flag = {
|
isTrue: v => isFlag(['yes', 'y', 'true', 't'], v),
|
isFalse: v => isFlag(['no', 'n', 'false', 'f'], v),
|
isPrompt: v => /^_+$/.test(v)
|
}; // generic list bypass function. used for all types of lists.
|
// accepts value, index, or key as matching criteria
|
|
const listTypeBypass = (v, prompt) => {
|
const choice = prompt.choices.find((c, idx) => choiceMatchesValue(c, idx, v));
|
|
if (choice != null) {
|
return getChoiceValue(choice);
|
}
|
|
throw Error('invalid choice');
|
}; /////
|
// BYPASS FUNCTIONS
|
//
|
// list of prompt bypass functions by prompt type
|
|
|
const typeBypass = {
|
confirm(v) {
|
if (flag.isTrue(v)) {
|
return true;
|
}
|
|
if (flag.isFalse(v)) {
|
return false;
|
}
|
|
throw Error('invalid input');
|
},
|
|
checkbox(v, prompt) {
|
const valList = v.split(',');
|
const valuesNoMatch = valList.filter(val => !prompt.choices.some((c, idx) => choiceMatchesValue(c, idx, val)));
|
|
if (valuesNoMatch.length) {
|
throw Error(`no match for "${valuesNoMatch.join('", "')}"`);
|
}
|
|
return valList.map(val => getChoiceValue(prompt.choices.find((c, idx) => choiceMatchesValue(c, idx, val))));
|
},
|
|
list: listTypeBypass,
|
rawlist: listTypeBypass,
|
expand: listTypeBypass
|
}; /////
|
// MAIN LOGIC
|
//
|
// returns new prompts, initial answers object, and any failures
|
|
function _default(prompts, bypassArr, plop) {
|
const noop = [prompts, {}, []]; // bail out if we don't have prompts or bypass data
|
|
if (!Array.isArray(prompts)) {
|
return noop;
|
}
|
|
if (bypassArr.length === 0) {
|
return noop;
|
} // pull registered prompts out of inquirer
|
|
|
const {
|
prompts: inqPrompts
|
} = plop.inquirer.prompt;
|
const answers = {};
|
const bypassFailures = []; // generate a list of pompts that the user is bypassing
|
|
const bypassedPrompts = prompts.filter(function (p, idx) {
|
// if the user didn't provide value for this prompt, skip it
|
if (idx >= bypassArr.length) {
|
return false;
|
}
|
|
const val = bypassArr[idx].toString(); // if the user asked to be given this prompt, skip it
|
|
if (flag.isPrompt(val)) {
|
return false;
|
} // if this prompt is dynamic, throw error because we can't know if
|
// the pompt bypass values given line up with the path this user
|
// has taken through the prompt tree.
|
|
|
if (typeof p.when === 'function') {
|
bypassFailures.push(`You can not bypass conditional prompts: ${p.name}`);
|
return false;
|
}
|
|
try {
|
const inqPrompt = inqPrompts[p.type] || {}; // try to find a bypass function to run
|
|
const bypass = p.bypass || inqPrompt.bypass || typeBypass[p.type] || null; // get the real answer data out of the bypass function and attach it
|
// to the answer data object
|
|
const bypassIsFunc = typeof bypass === 'function';
|
const value = bypassIsFunc ? bypass.call(null, val, p) : val; // if inquirer prompt has a filter function - call it
|
|
const answer = p.filter ? p.filter(value) : value; // if inquirer prompt has a validate function - call it
|
|
if (p.validate) {
|
const validation = p.validate(value);
|
|
if (validation !== true) {
|
// if validation failed return validation error
|
bypassFailures.push(validation);
|
return false;
|
}
|
}
|
|
answers[p.name] = answer;
|
} catch (err) {
|
// if we encounter an error above... assume the bypass value was invalid
|
bypassFailures.push(`The "${p.name}" prompt did not recognize "${val}" as a valid ${p.type} value (ERROR: ${err.message})`);
|
return false;
|
} // if we got this far, we successfully bypassed this prompt
|
|
|
return true;
|
}); // rip out any prompts that have been bypassed
|
|
const promptsAfterBypass = [// first prompt will copy the bypass answer data so it's available
|
// for prompts and actions to use
|
{
|
when: data => (Object.assign(data, answers), false)
|
}, // inlcude any prompts that were NOT bypassed
|
...prompts.filter(p => !bypassedPrompts.includes(p))]; // if we have failures, throw the first one
|
|
if (bypassFailures.length) {
|
throw Error(bypassFailures[0]);
|
} else {
|
// return the prompts that still need to be run
|
return [promptsAfterBypass, answers];
|
} // BOOM!
|
|
}
|