1082815dcSEvan Baconimport { ExpoConfig } from '@expo/config-types';
2082815dcSEvan Baconimport { XcodeProject } from 'xcode';
3082815dcSEvan Bacon
4*8a424bebSJames Ideimport { isNotComment } from './utils/Xcodeproj';
5082815dcSEvan Baconimport { ConfigPlugin } from '../Plugin.types';
6082815dcSEvan Baconimport { withXcodeProject } from '../plugins/ios-plugins';
7082815dcSEvan Baconimport { addWarningIOS } from '../utils/warnings';
8082815dcSEvan Bacon
9082815dcSEvan Bacontype Bitcode = NonNullable<ExpoConfig['ios']>['bitcode'];
10082815dcSEvan Bacon
11082815dcSEvan Bacon/**
12082815dcSEvan Bacon * Plugin to set a bitcode preference for the Xcode project
13082815dcSEvan Bacon * based on the project's Expo config `ios.bitcode` value.
14082815dcSEvan Bacon */
15082815dcSEvan Baconexport const withBitcode: ConfigPlugin = (config) => {
16082815dcSEvan Bacon  return withXcodeProject(config, async (config) => {
17082815dcSEvan Bacon    config.modResults = await setBitcodeWithConfig(config, {
18082815dcSEvan Bacon      project: config.modResults,
19082815dcSEvan Bacon    });
20082815dcSEvan Bacon    return config;
21082815dcSEvan Bacon  });
22082815dcSEvan Bacon};
23082815dcSEvan Bacon
24082815dcSEvan Bacon/**
25082815dcSEvan Bacon * Plugin to set a custom bitcode preference for the Xcode project.
26082815dcSEvan Bacon * Does not read from the Expo config `ios.bitcode`.
27082815dcSEvan Bacon *
28082815dcSEvan Bacon * @param bitcode custom bitcode setting.
29082815dcSEvan Bacon */
30082815dcSEvan Baconexport const withCustomBitcode: ConfigPlugin<Bitcode> = (config, bitcode) => {
31082815dcSEvan Bacon  return withXcodeProject(config, async (config) => {
32082815dcSEvan Bacon    config.modResults = await setBitcode(bitcode, {
33082815dcSEvan Bacon      project: config.modResults,
34082815dcSEvan Bacon    });
35082815dcSEvan Bacon    return config;
36082815dcSEvan Bacon  });
37082815dcSEvan Bacon};
38082815dcSEvan Bacon
39082815dcSEvan Bacon/**
40082815dcSEvan Bacon * Get the bitcode preference from the Expo config.
41082815dcSEvan Bacon */
42082815dcSEvan Baconexport function getBitcode(config: Pick<ExpoConfig, 'ios'>): Bitcode {
43082815dcSEvan Bacon  return config.ios?.bitcode;
44082815dcSEvan Bacon}
45082815dcSEvan Bacon
46082815dcSEvan Bacon/**
47082815dcSEvan Bacon * Enable or disable the `ENABLE_BITCODE` property of the project configurations.
48082815dcSEvan Bacon */
49082815dcSEvan Baconexport function setBitcodeWithConfig(
50082815dcSEvan Bacon  config: Pick<ExpoConfig, 'ios'>,
51082815dcSEvan Bacon  { project }: { project: XcodeProject }
52082815dcSEvan Bacon): XcodeProject {
53082815dcSEvan Bacon  const bitcode = getBitcode(config);
54082815dcSEvan Bacon  return setBitcode(bitcode, { project });
55082815dcSEvan Bacon}
56082815dcSEvan Bacon
57082815dcSEvan Bacon/**
58082815dcSEvan Bacon * Enable or disable the `ENABLE_BITCODE` property.
59082815dcSEvan Bacon */
60082815dcSEvan Baconexport function setBitcode(bitcode: Bitcode, { project }: { project: XcodeProject }): XcodeProject {
61082815dcSEvan Bacon  const isDefaultBehavior = bitcode == null;
62082815dcSEvan Bacon  // If the value is undefined, then do nothing.
63082815dcSEvan Bacon  if (isDefaultBehavior) {
64082815dcSEvan Bacon    return project;
65082815dcSEvan Bacon  }
66082815dcSEvan Bacon
67082815dcSEvan Bacon  const targetName = typeof bitcode === 'string' ? bitcode : undefined;
68082815dcSEvan Bacon  const isBitcodeEnabled = !!bitcode;
69082815dcSEvan Bacon  if (targetName) {
70082815dcSEvan Bacon    // Assert if missing
71082815dcSEvan Bacon    const configs = Object.entries(project.pbxXCBuildConfigurationSection()).filter(isNotComment);
72082815dcSEvan Bacon    const hasConfiguration = configs.find(([, configuration]) => configuration.name === targetName);
73082815dcSEvan Bacon    if (hasConfiguration) {
74082815dcSEvan Bacon      // If targetName is defined then disable bitcode everywhere.
75082815dcSEvan Bacon      project.addBuildProperty('ENABLE_BITCODE', 'NO');
76082815dcSEvan Bacon    } else {
77082815dcSEvan Bacon      const names = [
78082815dcSEvan Bacon        // Remove duplicates, wrap in double quotes, and sort alphabetically.
79082815dcSEvan Bacon        ...new Set(configs.map(([, configuration]) => `"${configuration.name}"`)),
80082815dcSEvan Bacon      ].sort();
81082815dcSEvan Bacon      addWarningIOS(
82082815dcSEvan Bacon        'ios.bitcode',
83082815dcSEvan Bacon        `No configuration named "${targetName}". Expected one of: ${names.join(', ')}.`
84082815dcSEvan Bacon      );
85082815dcSEvan Bacon    }
86082815dcSEvan Bacon  }
87082815dcSEvan Bacon
88082815dcSEvan Bacon  project.addBuildProperty('ENABLE_BITCODE', isBitcodeEnabled ? 'YES' : 'NO', targetName);
89082815dcSEvan Bacon
90082815dcSEvan Bacon  return project;
91082815dcSEvan Bacon}
92