18d307f52SEvan Baconimport { ExpoConfig, getConfig, ProjectConfig } from '@expo/config';
28d307f52SEvan Baconimport assert from 'assert';
38d307f52SEvan Baconimport util from 'util';
48d307f52SEvan Bacon
58d307f52SEvan Baconimport * as Log from '../log';
68d307f52SEvan Baconimport { CommandError } from '../utils/errors';
72dd43328SEvan Baconimport { setNodeEnv } from '../utils/nodeEnv';
88d307f52SEvan Baconimport { profile } from '../utils/profile';
98d307f52SEvan Bacon
108d307f52SEvan Bacontype Options = {
118d307f52SEvan Bacon  type?: string;
1229975bfdSEvan Bacon  full?: boolean;
138d307f52SEvan Bacon  json?: boolean;
148d307f52SEvan Bacon};
158d307f52SEvan Bacon
168d307f52SEvan Baconexport function logConfig(config: ExpoConfig | ProjectConfig) {
178d307f52SEvan Bacon  const isObjStr = (str: string): boolean => /^\w+: {/g.test(str);
188d307f52SEvan Bacon  Log.log(
198d307f52SEvan Bacon    util.inspect(config, {
208d307f52SEvan Bacon      colors: true,
218d307f52SEvan Bacon      compact: false,
228d307f52SEvan Bacon      // Sort objects to the end so that smaller values aren't hidden between large objects.
238d307f52SEvan Bacon      sorted(a: string, b: string) {
248d307f52SEvan Bacon        if (isObjStr(a)) return 1;
258d307f52SEvan Bacon        if (isObjStr(b)) return -1;
268d307f52SEvan Bacon        return 0;
278d307f52SEvan Bacon      },
288d307f52SEvan Bacon      showHidden: false,
298d307f52SEvan Bacon      depth: null,
308d307f52SEvan Bacon    })
318d307f52SEvan Bacon  );
328d307f52SEvan Bacon}
338d307f52SEvan Bacon
348d307f52SEvan Baconexport async function configAsync(projectRoot: string, options: Options) {
35aaa8033fSEvan Bacon  const loggingFunctions = {
36aaa8033fSEvan Bacon    log: console.log,
37aaa8033fSEvan Bacon    warn: console.warn,
38aaa8033fSEvan Bacon    error: console.error,
39aaa8033fSEvan Bacon  };
40aaa8033fSEvan Bacon  // Disable logging for this command if the user wants to get JSON output.
41aaa8033fSEvan Bacon  // This will ensure that only the JSON is printed to stdout.
42aaa8033fSEvan Bacon  if (options.json) {
43aaa8033fSEvan Bacon    console.log = function () {};
44aaa8033fSEvan Bacon    console.warn = function () {};
45aaa8033fSEvan Bacon    console.error = function () {};
46aaa8033fSEvan Bacon  }
472dd43328SEvan Bacon  setNodeEnv('development');
486a750d06SEvan Bacon  require('@expo/env').load(projectRoot);
492dd43328SEvan Bacon
508d307f52SEvan Bacon  if (options.type) {
518d307f52SEvan Bacon    assert.match(options.type, /^(public|prebuild|introspect)$/);
528d307f52SEvan Bacon  }
538d307f52SEvan Bacon
548d307f52SEvan Bacon  let config: ProjectConfig;
558d307f52SEvan Bacon
568d307f52SEvan Bacon  if (options.type === 'prebuild') {
578d307f52SEvan Bacon    const { getPrebuildConfigAsync } = await import('@expo/prebuild-config');
588d307f52SEvan Bacon
598d307f52SEvan Bacon    config = await profile(getPrebuildConfigAsync)(projectRoot, {
608d307f52SEvan Bacon      platforms: ['ios', 'android'],
618d307f52SEvan Bacon    });
628d307f52SEvan Bacon  } else if (options.type === 'introspect') {
638d307f52SEvan Bacon    const { getPrebuildConfigAsync } = await import('@expo/prebuild-config');
64*1a3a1db5SEvan Bacon    const { compileModsAsync } = await import('@expo/config-plugins/build/plugins/mod-compiler.js');
658d307f52SEvan Bacon
668d307f52SEvan Bacon    config = await profile(getPrebuildConfigAsync)(projectRoot, {
678d307f52SEvan Bacon      platforms: ['ios', 'android'],
688d307f52SEvan Bacon    });
698d307f52SEvan Bacon
708d307f52SEvan Bacon    await compileModsAsync(config.exp, {
718d307f52SEvan Bacon      projectRoot,
728d307f52SEvan Bacon      introspect: true,
738d307f52SEvan Bacon      platforms: ['ios', 'android'],
748d307f52SEvan Bacon      assertMissingModProviders: false,
758d307f52SEvan Bacon    });
768d307f52SEvan Bacon    // @ts-ignore
778d307f52SEvan Bacon    delete config.modRequest;
788d307f52SEvan Bacon    // @ts-ignore
798d307f52SEvan Bacon    delete config.modResults;
808d307f52SEvan Bacon  } else if (options.type === 'public') {
818d307f52SEvan Bacon    config = profile(getConfig)(projectRoot, {
828d307f52SEvan Bacon      skipSDKVersionRequirement: true,
838d307f52SEvan Bacon      isPublicConfig: true,
848d307f52SEvan Bacon    });
858d307f52SEvan Bacon  } else if (options.type) {
868d307f52SEvan Bacon    throw new CommandError(
878d307f52SEvan Bacon      `Invalid option: --type ${options.type}. Valid options are: public, prebuild`
888d307f52SEvan Bacon    );
898d307f52SEvan Bacon  } else {
908d307f52SEvan Bacon    config = profile(getConfig)(projectRoot, {
918d307f52SEvan Bacon      skipSDKVersionRequirement: true,
928d307f52SEvan Bacon    });
938d307f52SEvan Bacon  }
948d307f52SEvan Bacon
958d307f52SEvan Bacon  const configOutput = options.full ? config : config.exp;
968d307f52SEvan Bacon
978d307f52SEvan Bacon  if (!options.json) {
988d307f52SEvan Bacon    Log.log();
998d307f52SEvan Bacon    logConfig(configOutput);
1008d307f52SEvan Bacon    Log.log();
1018d307f52SEvan Bacon  } else {
102aaa8033fSEvan Bacon    process.stdout.write(JSON.stringify(configOutput));
103aaa8033fSEvan Bacon
104aaa8033fSEvan Bacon    // Re-enable logging functions for testing.
105aaa8033fSEvan Bacon    console.log = loggingFunctions.log;
106aaa8033fSEvan Bacon    console.warn = loggingFunctions.warn;
107aaa8033fSEvan Bacon    console.error = loggingFunctions.error;
1088d307f52SEvan Bacon  }
1098d307f52SEvan Bacon}
110