1import type { ExpoConfig } from '@expo/config-types';
2
3import type { ConfigPlugin } from '../Plugin.types';
4import { withPodfileProperties } from '../plugins/ios-plugins';
5import { BuildPropertiesConfig, ConfigToPropertyRuleType } from '../utils/BuildProperties.types';
6
7/**
8 * Creates a `withPodfileProperties` config-plugin based on given config to property mapping rules.
9 *
10 * The factory supports two modes from generic type inference
11 * ```ts
12 * // config-plugin without `props`, it will implicitly use the expo config as source config.
13 * createBuildPodfilePropsConfigPlugin<ExpoConfig>(): ConfigPlugin<void>;
14 *
15 * // config-plugin with a parameter `props: CustomType`, it will use the `props` as source config.
16 * createBuildPodfilePropsConfigPlugin<CustomType>(): ConfigPlugin<CustomType>;
17 * ```
18 *
19 * @param configToPropertyRules config to property mapping rules
20 * @param name the config plugin name
21 */
22export function createBuildPodfilePropsConfigPlugin<SourceConfigType extends BuildPropertiesConfig>(
23  configToPropertyRules: ConfigToPropertyRuleType<SourceConfigType>[],
24  name?: string
25) {
26  const withUnknown: ConfigPlugin<SourceConfigType extends ExpoConfig ? void : SourceConfigType> = (
27    config,
28    sourceConfig
29  ) =>
30    withPodfileProperties(config, (config) => {
31      config.modResults = updateIosBuildPropertiesFromConfig(
32        (sourceConfig ?? config) as SourceConfigType,
33        config.modResults,
34        configToPropertyRules
35      );
36      return config;
37    });
38  if (name) {
39    Object.defineProperty(withUnknown, 'name', {
40      value: name,
41    });
42  }
43  return withUnknown;
44}
45
46/**
47 * A config-plugin to update `ios/Podfile.properties.json` from the `jsEngine` in expo config
48 */
49export const withJsEnginePodfileProps = createBuildPodfilePropsConfigPlugin<ExpoConfig>(
50  [
51    {
52      propName: 'expo.jsEngine',
53      propValueGetter: (config) => config.ios?.jsEngine ?? config.jsEngine ?? 'hermes',
54    },
55  ],
56  'withJsEnginePodfileProps'
57);
58
59export function updateIosBuildPropertiesFromConfig<SourceConfigType extends BuildPropertiesConfig>(
60  config: SourceConfigType,
61  podfileProperties: Record<string, string>,
62  configToPropertyRules: ConfigToPropertyRuleType<SourceConfigType>[]
63) {
64  for (const configToProperty of configToPropertyRules) {
65    const value = configToProperty.propValueGetter(config);
66    updateIosBuildProperty(podfileProperties, configToProperty.propName, value);
67  }
68  return podfileProperties;
69}
70
71export function updateIosBuildProperty(
72  podfileProperties: Record<string, string>,
73  name: string,
74  value: string | null | undefined,
75  options?: { removePropWhenValueIsNull?: boolean }
76) {
77  if (value) {
78    podfileProperties[name] = value;
79  } else if (options?.removePropWhenValueIsNull) {
80    delete podfileProperties[name];
81  }
82  return podfileProperties;
83}
84