18d307f52SEvan Baconimport { ExpoConfig, getConfig, PackageJSONConfig } from '@expo/config'; 28d307f52SEvan Baconimport { ModPlatform } from '@expo/config-plugins'; 38d307f52SEvan Baconimport JsonFile, { JSONObject } from '@expo/json-file'; 48d307f52SEvan Baconimport path from 'path'; 58d307f52SEvan Bacon 68d307f52SEvan Baconimport * as Log from '../log'; 78d307f52SEvan Baconimport { CommandError } from '../utils/errors'; 88d307f52SEvan Baconimport { 98d307f52SEvan Bacon getOrPromptForBundleIdentifier, 108d307f52SEvan Bacon getOrPromptForPackage, 118d307f52SEvan Bacon} from '../utils/getOrPromptApplicationId'; 128d307f52SEvan Bacon 138d307f52SEvan Bacon/** 148d307f52SEvan Bacon * If an Expo config file does not exist, write a new one using the in-memory config. 158d307f52SEvan Bacon * 168d307f52SEvan Bacon * @param projectRoot 178d307f52SEvan Bacon */ 188d307f52SEvan Baconexport async function ensureConfigExistsAsync(projectRoot: string) { 198d307f52SEvan Bacon try { 208d307f52SEvan Bacon const config = getConfig(projectRoot, { skipSDKVersionRequirement: false }); 218d307f52SEvan Bacon // If no config exists in the file system then we should generate one so the process doesn't fail. 228d307f52SEvan Bacon if (!config.dynamicConfigPath && !config.staticConfigPath) { 238d307f52SEvan Bacon // Remove the internal object before writing. 248d307f52SEvan Bacon delete config.exp._internal; 258d307f52SEvan Bacon 268d307f52SEvan Bacon // Write the generated config. 278d307f52SEvan Bacon await JsonFile.writeAsync( 288d307f52SEvan Bacon path.join(projectRoot, 'app.json'), 298d307f52SEvan Bacon { expo: config.exp as unknown as JSONObject }, 308d307f52SEvan Bacon { json5: false } 318d307f52SEvan Bacon ); 328d307f52SEvan Bacon } 3329975bfdSEvan Bacon } catch (error: any) { 348d307f52SEvan Bacon // TODO(Bacon): Currently this is already handled in the command 358d307f52SEvan Bacon Log.log(); 368d307f52SEvan Bacon throw new CommandError(`${error.message}\n`); 378d307f52SEvan Bacon } 388d307f52SEvan Bacon} 398d307f52SEvan Bacon 40*4149568cSEvan Bacon/** Ensure config is written, and prompts for application identifiers. */ 418d307f52SEvan Baconexport async function ensureConfigAsync( 428d307f52SEvan Bacon projectRoot: string, 438d307f52SEvan Bacon { 448d307f52SEvan Bacon platforms, 458d307f52SEvan Bacon }: { 468d307f52SEvan Bacon platforms: ModPlatform[]; 478d307f52SEvan Bacon } 488d307f52SEvan Bacon): Promise<{ exp: ExpoConfig; pkg: PackageJSONConfig }> { 498d307f52SEvan Bacon await ensureConfigExistsAsync(projectRoot); 508d307f52SEvan Bacon 518d307f52SEvan Bacon // Prompt for the Android package first because it's more strict than the bundle identifier 528d307f52SEvan Bacon // this means you'll have a better chance at matching the bundle identifier with the package name. 538d307f52SEvan Bacon if (platforms.includes('android')) { 548d307f52SEvan Bacon await getOrPromptForPackage(projectRoot); 558d307f52SEvan Bacon } 568d307f52SEvan Bacon 578d307f52SEvan Bacon if (platforms.includes('ios')) { 588d307f52SEvan Bacon await getOrPromptForBundleIdentifier(projectRoot); 598d307f52SEvan Bacon } 608d307f52SEvan Bacon 618d307f52SEvan Bacon // Read config again because prompting for bundle id or package name may have mutated the results. 62f479be69SEvan Bacon return getConfig(projectRoot); 638d307f52SEvan Bacon} 64