1import inquirer, { Question } from 'inquirer'; 2 3import { ModuleConfiguration } from './ModuleConfiguration'; 4 5/** 6 * Generates CocoaPod name in format `Namepart1Namepart2Namepart3`. 7 * For these with `expo` as `partname1` would generate `EXNamepart2...`. 8 * @param {string} moduleName - provided module name, expects format: `namepart1-namepart2-namepart3` 9 */ 10const generateCocoaPodDefaultName = (moduleName: string) => { 11 const wordsToUpperCase = (s: string) => 12 s 13 .toLowerCase() 14 .split('-') 15 .map((s) => s.charAt(0).toUpperCase() + s.substring(1)) 16 .join(''); 17 18 if (moduleName.toLowerCase().startsWith('expo')) { 19 return `EX${wordsToUpperCase(moduleName.substring(4))}`; 20 } 21 return `EX${wordsToUpperCase(moduleName)}`; 22}; 23 24/** 25 * Generates java package name in format `namepart1.namepart2.namepart3`. 26 * @param moduleName - provided module name, expects format: `namepart1-namepart2-namepart3` 27 */ 28const generateJavaModuleDefaultName = (moduleName: string) => { 29 const wordsToJavaModule = (s: string) => s.toLowerCase().split('-').join(''); 30 31 if (moduleName.toLowerCase().startsWith('expo')) { 32 return `expo.modules.${wordsToJavaModule(moduleName.substring(4))}`; 33 } 34 return wordsToJavaModule(moduleName); 35}; 36 37/** 38 * Generates JS/TS module name in format `Namepart1Namepart2Namepart3`. 39 * @param moduleName - provided module name, expects format: `namepart1-namepart2-namepart3` 40 */ 41const generateInCodeModuleDefaultName = (moduleName: string) => { 42 return moduleName 43 .toLowerCase() 44 .split('-') 45 .map((s) => s.charAt(0).toUpperCase() + s.substring(1)) 46 .join(''); 47}; 48 49/** 50 * Generates questions 51 */ 52const generateQuestions = (suggestedModuleName: string): Question[] => [ 53 { 54 name: 'npmModuleName', 55 message: 'How would you like to call your module in JS/npm? (eg. expo-camera)', 56 default: suggestedModuleName, 57 validate: (answer: string) => { 58 return !answer.length 59 ? 'Module name cannot be empty' 60 : /[A-Z]/.test(answer) 61 ? 'Module name cannot contain any upper case characters' 62 : /\s/.test(answer) 63 ? 'Module name cannot contain any whitespaces' 64 : true; 65 }, 66 }, 67 { 68 name: 'podName', 69 message: 'How would you like to call your module in CocoaPods? (eg. EXCamera)', 70 default: ({ npmModuleName }) => generateCocoaPodDefaultName(npmModuleName), 71 validate: (answer: string) => 72 !answer.length 73 ? 'CocoaPod name cannot be empty' 74 : /\s/.test(answer) 75 ? 'CocoaPod name cannot contain any whitespaces' 76 : true, 77 }, 78 { 79 name: 'javaPackage', 80 message: 'How would you like to call your module in Java? (eg. expo.modules.camera)', 81 default: ({ npmModuleName }) => generateJavaModuleDefaultName(npmModuleName), 82 validate: (answer: string) => 83 !answer.length 84 ? 'Java Package name cannot be empty' 85 : /\s/.test(answer) 86 ? 'Java Package name cannot contain any whitespaces' 87 : true, 88 }, 89 { 90 name: 'jsPackageName', 91 message: 'How would you like to call your module in JS/TS codebase (eg. ExpoCamera)?', 92 default: ({ npmModuleName }) => generateInCodeModuleDefaultName(npmModuleName), 93 validate: (answer: string) => 94 !answer.length 95 ? 'Module name cannot be empty' 96 : /\s/.test(answer) 97 ? 'Module name cannot contain any whitespaces' 98 : true, 99 }, 100 { 101 name: 'viewManager', 102 message: 'Would you like to create a NativeViewManager?', 103 default: false, 104 type: 'confirm', 105 }, 106]; 107 108/** 109 * Prompt user about new module namings. 110 * @param suggestedModuleName - suggested module name that would be used to generate all suggestions for each question 111 */ 112export default async function promptQuestionsAsync( 113 suggestedModuleName: string 114): Promise<ModuleConfiguration> { 115 const questions = generateQuestions(suggestedModuleName); 116 // non interactive check 117 if (!process.stdin.isTTY) { 118 let message = `Input is required, but expotools is in a non-interactive shell.\n`; 119 const firstQuestion = (questions[0].message || '') as string; 120 message += `Required input:\n${firstQuestion.trim().replace(/^/gm, '> ')}`; 121 throw new Error(message); 122 } 123 // TODO: Migrate to prompts and remove inquirer 124 return (await inquirer.prompt(questions)) as ModuleConfiguration; 125} 126