You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							189 lines
						
					
					
						
							5.9 KiB
						
					
					
				
			
		
		
	
	
							189 lines
						
					
					
						
							5.9 KiB
						
					
					
				"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! | 
						|
 | 
						|
} |