1import { ExpoConfig, getConfig, ProjectConfig } from '@expo/config'; 2import assert from 'assert'; 3import util from 'util'; 4 5import * as Log from '../log'; 6import { CommandError } from '../utils/errors'; 7import { setNodeEnv } from '../utils/nodeEnv'; 8import { profile } from '../utils/profile'; 9 10type Options = { 11 type?: string; 12 full?: boolean; 13 json?: boolean; 14}; 15 16export function logConfig(config: ExpoConfig | ProjectConfig) { 17 const isObjStr = (str: string): boolean => /^\w+: {/g.test(str); 18 Log.log( 19 util.inspect(config, { 20 colors: true, 21 compact: false, 22 // Sort objects to the end so that smaller values aren't hidden between large objects. 23 sorted(a: string, b: string) { 24 if (isObjStr(a)) return 1; 25 if (isObjStr(b)) return -1; 26 return 0; 27 }, 28 showHidden: false, 29 depth: null, 30 }) 31 ); 32} 33 34export async function configAsync(projectRoot: string, options: Options) { 35 const loggingFunctions = { 36 log: console.log, 37 warn: console.warn, 38 error: console.error, 39 }; 40 // Disable logging for this command if the user wants to get JSON output. 41 // This will ensure that only the JSON is printed to stdout. 42 if (options.json) { 43 console.log = function () {}; 44 console.warn = function () {}; 45 console.error = function () {}; 46 } 47 setNodeEnv('development'); 48 require('@expo/env').load(projectRoot); 49 50 if (options.type) { 51 assert.match(options.type, /^(public|prebuild|introspect)$/); 52 } 53 54 let config: ProjectConfig; 55 56 if (options.type === 'prebuild') { 57 const { getPrebuildConfigAsync } = await import('@expo/prebuild-config'); 58 59 config = await profile(getPrebuildConfigAsync)(projectRoot, { 60 platforms: ['ios', 'android'], 61 }); 62 } else if (options.type === 'introspect') { 63 const { getPrebuildConfigAsync } = await import('@expo/prebuild-config'); 64 const { compileModsAsync } = await import('@expo/config-plugins/build/plugins/mod-compiler.js'); 65 66 config = await profile(getPrebuildConfigAsync)(projectRoot, { 67 platforms: ['ios', 'android'], 68 }); 69 70 await compileModsAsync(config.exp, { 71 projectRoot, 72 introspect: true, 73 platforms: ['ios', 'android'], 74 assertMissingModProviders: false, 75 }); 76 // @ts-ignore 77 delete config.modRequest; 78 // @ts-ignore 79 delete config.modResults; 80 } else if (options.type === 'public') { 81 config = profile(getConfig)(projectRoot, { 82 skipSDKVersionRequirement: true, 83 isPublicConfig: true, 84 }); 85 } else if (options.type) { 86 throw new CommandError( 87 `Invalid option: --type ${options.type}. Valid options are: public, prebuild` 88 ); 89 } else { 90 config = profile(getConfig)(projectRoot, { 91 skipSDKVersionRequirement: true, 92 }); 93 } 94 95 const configOutput = options.full ? config : config.exp; 96 97 if (!options.json) { 98 Log.log(); 99 logConfig(configOutput); 100 Log.log(); 101 } else { 102 process.stdout.write(JSON.stringify(configOutput)); 103 104 // Re-enable logging functions for testing. 105 console.log = loggingFunctions.log; 106 console.warn = loggingFunctions.warn; 107 console.error = loggingFunctions.error; 108 } 109} 110