16d6b81f9SEvan Baconimport { getConfig, Platform } from '@expo/config';
2dc51e206SEvan Bacon
36d6b81f9SEvan Baconimport { getPlatformBundlers, PlatformBundlers } from '../start/server/platformBundlers';
46d6b81f9SEvan Baconimport { CommandError } from '../utils/errors';
5dc51e206SEvan Bacon
6dc51e206SEvan Baconexport type Options = {
7dc51e206SEvan Bacon  outputDir: string;
86d6b81f9SEvan Bacon  platforms: Platform[];
9dc51e206SEvan Bacon  maxWorkers?: number;
10dc51e206SEvan Bacon  dev: boolean;
11dc51e206SEvan Bacon  clear: boolean;
121a3d836eSEvan Bacon  minify: boolean;
13dc51e206SEvan Bacon  dumpAssetmap: boolean;
14dc51e206SEvan Bacon  dumpSourcemap: boolean;
15dc51e206SEvan Bacon};
16dc51e206SEvan Bacon
176d6b81f9SEvan Bacon/** Returns an array of platforms based on the input platform identifier and runtime constraints. */
186d6b81f9SEvan Baconexport function resolvePlatformOption(
196d6b81f9SEvan Bacon  platformBundlers: PlatformBundlers,
20*8eba27a6SCedric van Putten  platform: string[] = ['all']
216d6b81f9SEvan Bacon): Platform[] {
22*8eba27a6SCedric van Putten  const platformsAvailable: Partial<PlatformBundlers> = Object.fromEntries(
236d6b81f9SEvan Bacon    Object.entries(platformBundlers).filter(([, bundler]) => bundler === 'metro')
246d6b81f9SEvan Bacon  );
256d6b81f9SEvan Bacon
26*8eba27a6SCedric van Putten  if (!Object.keys(platformsAvailable).length) {
276d6b81f9SEvan Bacon    throw new CommandError(
286d6b81f9SEvan Bacon      `No platforms are configured to use the Metro bundler in the project Expo config.`
296d6b81f9SEvan Bacon    );
306d6b81f9SEvan Bacon  }
316d6b81f9SEvan Bacon
32*8eba27a6SCedric van Putten  const assertPlatformBundler = (platform: Platform): Platform => {
33*8eba27a6SCedric van Putten    if (!platformsAvailable[platform]) {
346d6b81f9SEvan Bacon      throw new CommandError(
356d6b81f9SEvan Bacon        'BAD_ARGS',
366d6b81f9SEvan Bacon        `Platform "${platform}" is not configured to use the Metro bundler in the project Expo config.`
376d6b81f9SEvan Bacon      );
386d6b81f9SEvan Bacon    }
39*8eba27a6SCedric van Putten
40*8eba27a6SCedric van Putten    return platform;
416d6b81f9SEvan Bacon  };
426d6b81f9SEvan Bacon
43*8eba27a6SCedric van Putten  const knownPlatforms = ['android', 'ios', 'web'] as Platform[];
44*8eba27a6SCedric van Putten  const assertPlatformIsKnown = (platform: string): Platform => {
45*8eba27a6SCedric van Putten    if (!knownPlatforms.includes(platform as Platform)) {
466d6b81f9SEvan Bacon      throw new CommandError(
47*8eba27a6SCedric van Putten        `Unsupported platform "${platform}". Options are: ${knownPlatforms.join(',')},all`
486d6b81f9SEvan Bacon      );
496d6b81f9SEvan Bacon    }
50*8eba27a6SCedric van Putten
51*8eba27a6SCedric van Putten    return platform as Platform;
52*8eba27a6SCedric van Putten  };
53*8eba27a6SCedric van Putten
54*8eba27a6SCedric van Putten  return (
55*8eba27a6SCedric van Putten    platform
56*8eba27a6SCedric van Putten      // Expand `all` to all available platforms.
57*8eba27a6SCedric van Putten      .map((platform) => (platform === 'all' ? Object.keys(platformsAvailable) : platform))
58*8eba27a6SCedric van Putten      .flat()
59*8eba27a6SCedric van Putten      // Remove duplicated platforms
60*8eba27a6SCedric van Putten      .filter((platform, index, list) => list.indexOf(platform) === index)
61*8eba27a6SCedric van Putten      // Assert platforms are valid
62*8eba27a6SCedric van Putten      .map((platform) => assertPlatformIsKnown(platform))
63*8eba27a6SCedric van Putten      .map((platform) => assertPlatformBundler(platform))
64*8eba27a6SCedric van Putten  );
656d6b81f9SEvan Bacon}
666d6b81f9SEvan Bacon
676d6b81f9SEvan Baconexport async function resolveOptionsAsync(projectRoot: string, args: any): Promise<Options> {
686d6b81f9SEvan Bacon  const { exp } = getConfig(projectRoot, { skipPlugins: true, skipSDKVersionRequirement: true });
696d6b81f9SEvan Bacon  const platformBundlers = getPlatformBundlers(exp);
70dc51e206SEvan Bacon
71dc51e206SEvan Bacon  return {
72*8eba27a6SCedric van Putten    platforms: resolvePlatformOption(platformBundlers, args['--platform']),
73dc51e206SEvan Bacon    outputDir: args['--output-dir'] ?? 'dist',
741a3d836eSEvan Bacon    minify: !args['--no-minify'],
75dc51e206SEvan Bacon    clear: !!args['--clear'],
76dc51e206SEvan Bacon    dev: !!args['--dev'],
77dc51e206SEvan Bacon    maxWorkers: args['--max-workers'],
78dc51e206SEvan Bacon    dumpAssetmap: !!args['--dump-assetmap'],
79dc51e206SEvan Bacon    dumpSourcemap: !!args['--dump-sourcemap'],
80dc51e206SEvan Bacon  };
81dc51e206SEvan Bacon}
82