1082815dcSEvan Baconimport type { ExpoConfig } from '@expo/config-types';
2082815dcSEvan Baconimport type { JSONObject } from '@expo/json-file';
3082815dcSEvan Baconimport type { XcodeProject } from 'xcode';
4082815dcSEvan Bacon
5*8a424bebSJames Ideimport { withMod } from './withMod';
6082815dcSEvan Baconimport type { ConfigPlugin, Mod } from '../Plugin.types';
7082815dcSEvan Baconimport type { ExpoPlist, InfoPlist } from '../ios/IosConfig.types';
8082815dcSEvan Baconimport type { AppDelegateProjectFile } from '../ios/Paths';
9082815dcSEvan Baconimport { get } from '../utils/obj';
10082815dcSEvan Baconimport { addWarningIOS } from '../utils/warnings';
11082815dcSEvan Bacon
12082815dcSEvan Bacontype MutateInfoPlistAction = (
13082815dcSEvan Bacon  expo: ExpoConfig,
14082815dcSEvan Bacon  infoPlist: InfoPlist
15082815dcSEvan Bacon) => Promise<InfoPlist> | InfoPlist;
16082815dcSEvan Bacon
17082815dcSEvan Bacon/**
18082815dcSEvan Bacon * Helper method for creating mods from existing config functions.
19082815dcSEvan Bacon *
20082815dcSEvan Bacon * @param action
21082815dcSEvan Bacon */
22082815dcSEvan Baconexport function createInfoPlistPlugin(action: MutateInfoPlistAction, name?: string): ConfigPlugin {
23082815dcSEvan Bacon  const withUnknown: ConfigPlugin = (config) =>
24082815dcSEvan Bacon    withInfoPlist(config, async (config) => {
25082815dcSEvan Bacon      config.modResults = await action(config, config.modResults);
26082815dcSEvan Bacon      return config;
27082815dcSEvan Bacon    });
28082815dcSEvan Bacon  if (name) {
29082815dcSEvan Bacon    Object.defineProperty(withUnknown, 'name', {
30082815dcSEvan Bacon      value: name,
31082815dcSEvan Bacon    });
32082815dcSEvan Bacon  }
33082815dcSEvan Bacon  return withUnknown;
34082815dcSEvan Bacon}
35082815dcSEvan Bacon
36082815dcSEvan Baconexport function createInfoPlistPluginWithPropertyGuard(
37082815dcSEvan Bacon  action: MutateInfoPlistAction,
38082815dcSEvan Bacon  settings: {
39082815dcSEvan Bacon    infoPlistProperty: string;
40082815dcSEvan Bacon    expoConfigProperty: string;
41082815dcSEvan Bacon    expoPropertyGetter?: (config: ExpoConfig) => string;
42082815dcSEvan Bacon  },
43082815dcSEvan Bacon  name?: string
44082815dcSEvan Bacon): ConfigPlugin {
45082815dcSEvan Bacon  const withUnknown: ConfigPlugin = (config) =>
46082815dcSEvan Bacon    withInfoPlist(config, async (config) => {
47082815dcSEvan Bacon      const existingProperty = settings.expoPropertyGetter
48082815dcSEvan Bacon        ? settings.expoPropertyGetter(config)
49082815dcSEvan Bacon        : get(config, settings.expoConfigProperty);
50082815dcSEvan Bacon      // If the user explicitly sets a value in the infoPlist, we should respect that.
51082815dcSEvan Bacon      if (config.modRawConfig.ios?.infoPlist?.[settings.infoPlistProperty] === undefined) {
52082815dcSEvan Bacon        config.modResults = await action(config, config.modResults);
53082815dcSEvan Bacon      } else if (existingProperty !== undefined) {
54082815dcSEvan Bacon        // Only warn if there is a conflict.
55082815dcSEvan Bacon        addWarningIOS(
56082815dcSEvan Bacon          settings.expoConfigProperty,
57082815dcSEvan Bacon          `"ios.infoPlist.${settings.infoPlistProperty}" is set in the config. Ignoring abstract property "${settings.expoConfigProperty}": ${existingProperty}`
58082815dcSEvan Bacon        );
59082815dcSEvan Bacon      }
60082815dcSEvan Bacon
61082815dcSEvan Bacon      return config;
62082815dcSEvan Bacon    });
63082815dcSEvan Bacon  if (name) {
64082815dcSEvan Bacon    Object.defineProperty(withUnknown, 'name', {
65082815dcSEvan Bacon      value: name,
66082815dcSEvan Bacon    });
67082815dcSEvan Bacon  }
68082815dcSEvan Bacon  return withUnknown;
69082815dcSEvan Bacon}
70082815dcSEvan Bacon
71082815dcSEvan Bacontype MutateEntitlementsPlistAction = (expo: ExpoConfig, entitlements: JSONObject) => JSONObject;
72082815dcSEvan Bacon
73082815dcSEvan Bacon/**
74082815dcSEvan Bacon * Helper method for creating mods from existing config functions.
75082815dcSEvan Bacon *
76082815dcSEvan Bacon * @param action
77082815dcSEvan Bacon */
78082815dcSEvan Baconexport function createEntitlementsPlugin(
79082815dcSEvan Bacon  action: MutateEntitlementsPlistAction,
80082815dcSEvan Bacon  name: string
81082815dcSEvan Bacon): ConfigPlugin {
82082815dcSEvan Bacon  const withUnknown: ConfigPlugin = (config) =>
83082815dcSEvan Bacon    withEntitlementsPlist(config, async (config) => {
84082815dcSEvan Bacon      config.modResults = await action(config, config.modResults);
85082815dcSEvan Bacon      return config;
86082815dcSEvan Bacon    });
87082815dcSEvan Bacon  if (name) {
88082815dcSEvan Bacon    Object.defineProperty(withUnknown, 'name', {
89082815dcSEvan Bacon      value: name,
90082815dcSEvan Bacon    });
91082815dcSEvan Bacon  }
92082815dcSEvan Bacon  return withUnknown;
93082815dcSEvan Bacon}
94082815dcSEvan Bacon
95082815dcSEvan Bacon/**
96082815dcSEvan Bacon * Provides the AppDelegate file for modification.
97082815dcSEvan Bacon *
98082815dcSEvan Bacon * @param config
99082815dcSEvan Bacon * @param action
100082815dcSEvan Bacon */
101082815dcSEvan Baconexport const withAppDelegate: ConfigPlugin<Mod<AppDelegateProjectFile>> = (config, action) => {
102082815dcSEvan Bacon  return withMod(config, {
103082815dcSEvan Bacon    platform: 'ios',
104082815dcSEvan Bacon    mod: 'appDelegate',
105082815dcSEvan Bacon    action,
106082815dcSEvan Bacon  });
107082815dcSEvan Bacon};
108082815dcSEvan Bacon
109082815dcSEvan Bacon/**
110082815dcSEvan Bacon * Provides the Info.plist file for modification.
111082815dcSEvan Bacon * Keeps the config's expo.ios.infoPlist object in sync with the data.
112082815dcSEvan Bacon *
113082815dcSEvan Bacon * @param config
114082815dcSEvan Bacon * @param action
115082815dcSEvan Bacon */
116082815dcSEvan Baconexport const withInfoPlist: ConfigPlugin<Mod<InfoPlist>> = (config, action) => {
117082815dcSEvan Bacon  return withMod<InfoPlist>(config, {
118082815dcSEvan Bacon    platform: 'ios',
119082815dcSEvan Bacon    mod: 'infoPlist',
120082815dcSEvan Bacon    async action(config) {
121082815dcSEvan Bacon      config = await action(config);
122082815dcSEvan Bacon      if (!config.ios) {
123082815dcSEvan Bacon        config.ios = {};
124082815dcSEvan Bacon      }
125082815dcSEvan Bacon      config.ios.infoPlist = config.modResults;
126082815dcSEvan Bacon      return config;
127082815dcSEvan Bacon    },
128082815dcSEvan Bacon  });
129082815dcSEvan Bacon};
130082815dcSEvan Bacon
131082815dcSEvan Bacon/**
132082815dcSEvan Bacon * Provides the main .entitlements file for modification.
133082815dcSEvan Bacon * Keeps the config's expo.ios.entitlements object in sync with the data.
134082815dcSEvan Bacon *
135082815dcSEvan Bacon * @param config
136082815dcSEvan Bacon * @param action
137082815dcSEvan Bacon */
138082815dcSEvan Baconexport const withEntitlementsPlist: ConfigPlugin<Mod<JSONObject>> = (config, action) => {
139082815dcSEvan Bacon  return withMod<JSONObject>(config, {
140082815dcSEvan Bacon    platform: 'ios',
141082815dcSEvan Bacon    mod: 'entitlements',
142082815dcSEvan Bacon    async action(config) {
143082815dcSEvan Bacon      config = await action(config);
144082815dcSEvan Bacon      if (!config.ios) {
145082815dcSEvan Bacon        config.ios = {};
146082815dcSEvan Bacon      }
147082815dcSEvan Bacon      config.ios.entitlements = config.modResults;
148082815dcSEvan Bacon      return config;
149082815dcSEvan Bacon    },
150082815dcSEvan Bacon  });
151082815dcSEvan Bacon};
152082815dcSEvan Bacon
153082815dcSEvan Bacon/**
154082815dcSEvan Bacon * Provides the Expo.plist for modification.
155082815dcSEvan Bacon *
156082815dcSEvan Bacon * @param config
157082815dcSEvan Bacon * @param action
158082815dcSEvan Bacon */
159082815dcSEvan Baconexport const withExpoPlist: ConfigPlugin<Mod<ExpoPlist>> = (config, action) => {
160082815dcSEvan Bacon  return withMod(config, {
161082815dcSEvan Bacon    platform: 'ios',
162082815dcSEvan Bacon    mod: 'expoPlist',
163082815dcSEvan Bacon    action,
164082815dcSEvan Bacon  });
165082815dcSEvan Bacon};
166082815dcSEvan Bacon
167082815dcSEvan Bacon/**
168082815dcSEvan Bacon * Provides the main .xcodeproj for modification.
169082815dcSEvan Bacon *
170082815dcSEvan Bacon * @param config
171082815dcSEvan Bacon * @param action
172082815dcSEvan Bacon */
173082815dcSEvan Baconexport const withXcodeProject: ConfigPlugin<Mod<XcodeProject>> = (config, action) => {
174082815dcSEvan Bacon  return withMod(config, {
175082815dcSEvan Bacon    platform: 'ios',
176082815dcSEvan Bacon    mod: 'xcodeproj',
177082815dcSEvan Bacon    action,
178082815dcSEvan Bacon  });
179082815dcSEvan Bacon};
180082815dcSEvan Bacon
181082815dcSEvan Bacon/**
182082815dcSEvan Bacon * Provides the Podfile.properties.json for modification.
183082815dcSEvan Bacon *
184082815dcSEvan Bacon * @param config
185082815dcSEvan Bacon * @param action
186082815dcSEvan Bacon */
187082815dcSEvan Baconexport const withPodfileProperties: ConfigPlugin<Mod<Record<string, string>>> = (
188082815dcSEvan Bacon  config,
189082815dcSEvan Bacon  action
190082815dcSEvan Bacon) => {
191082815dcSEvan Bacon  return withMod(config, {
192082815dcSEvan Bacon    platform: 'ios',
193082815dcSEvan Bacon    mod: 'podfileProperties',
194082815dcSEvan Bacon    action,
195082815dcSEvan Bacon  });
196082815dcSEvan Bacon};
197