1import { getConfig, Platform } from '@expo/config';
2
3import { getPlatformBundlers, PlatformBundlers } from '../start/server/platformBundlers';
4import { CommandError } from '../utils/errors';
5
6export type Options = {
7  outputDir: string;
8  platforms: Platform[];
9  maxWorkers?: number;
10  dev: boolean;
11  clear: boolean;
12  minify: boolean;
13  dumpAssetmap: boolean;
14  dumpSourcemap: boolean;
15};
16
17/** Returns an array of platforms based on the input platform identifier and runtime constraints. */
18export function resolvePlatformOption(
19  platformBundlers: PlatformBundlers,
20  platform: string = 'all'
21): Platform[] {
22  const platforms: Partial<PlatformBundlers> = Object.fromEntries(
23    Object.entries(platformBundlers).filter(([, bundler]) => bundler === 'metro')
24  );
25
26  if (!Object.keys(platforms).length) {
27    throw new CommandError(
28      `No platforms are configured to use the Metro bundler in the project Expo config.`
29    );
30  }
31
32  const assertPlatformBundler = (platform: Platform) => {
33    if (!platforms[platform]) {
34      throw new CommandError(
35        'BAD_ARGS',
36        `Platform "${platform}" is not configured to use the Metro bundler in the project Expo config.`
37      );
38    }
39  };
40
41  switch (platform) {
42    case 'ios':
43      assertPlatformBundler('ios');
44      return ['ios'];
45    case 'web':
46      assertPlatformBundler('web');
47      return ['web'];
48    case 'android':
49      assertPlatformBundler('android');
50      return ['android'];
51    case 'all':
52      return Object.keys(platforms) as Platform[];
53    default:
54      throw new CommandError(
55        `Unsupported platform "${platform}". Options are: ${Object.keys(platforms).join(',')}, all`
56      );
57  }
58}
59
60export async function resolveOptionsAsync(projectRoot: string, args: any): Promise<Options> {
61  const { exp } = getConfig(projectRoot, { skipPlugins: true, skipSDKVersionRequirement: true });
62  const platformBundlers = getPlatformBundlers(exp);
63  const platforms: Platform[] = resolvePlatformOption(
64    platformBundlers,
65    args['--platform'] ?? 'all'
66  );
67
68  return {
69    outputDir: args['--output-dir'] ?? 'dist',
70    platforms,
71    minify: !args['--no-minify'],
72    clear: !!args['--clear'],
73    dev: !!args['--dev'],
74    maxWorkers: args['--max-workers'],
75    dumpAssetmap: !!args['--dump-assetmap'],
76    dumpSourcemap: !!args['--dump-sourcemap'],
77  };
78}
79