1082815dcSEvan Baconimport type { ExpoConfig } from '@expo/config-types';
2082815dcSEvan Bacon
3*8a424bebSJames Ideimport type { PropertiesItem } from './Properties';
4082815dcSEvan Baconimport type { ConfigPlugin } from '../Plugin.types';
5082815dcSEvan Baconimport { withGradleProperties } from '../plugins/android-plugins';
6082815dcSEvan Baconimport { BuildPropertiesConfig, ConfigToPropertyRuleType } from '../utils/BuildProperties.types';
7082815dcSEvan Bacon
8082815dcSEvan Bacon/**
9082815dcSEvan Bacon * Creates a `withGradleProperties` config-plugin based on given config to property mapping rules.
10082815dcSEvan Bacon *
11082815dcSEvan Bacon * The factory supports two modes from generic type inference
12082815dcSEvan Bacon * ```ts
13082815dcSEvan Bacon * // config-plugin without `props`, it will implicitly use the expo config as source config.
14082815dcSEvan Bacon * createBuildGradlePropsConfigPlugin<ExpoConfig>(): ConfigPlugin<void>;
15082815dcSEvan Bacon *
16082815dcSEvan Bacon * // config-plugin with a parameter `props: CustomType`, it will use the `props` as source config.
17082815dcSEvan Bacon * createBuildGradlePropsConfigPlugin<CustomType>(): ConfigPlugin<CustomType>;
18082815dcSEvan Bacon * ```
19082815dcSEvan Bacon *
20082815dcSEvan Bacon * @param configToPropertyRules config to property mapping rules
21082815dcSEvan Bacon * @param name the config plugin name
22082815dcSEvan Bacon */
23082815dcSEvan Baconexport function createBuildGradlePropsConfigPlugin<SourceConfigType extends BuildPropertiesConfig>(
24082815dcSEvan Bacon  configToPropertyRules: ConfigToPropertyRuleType<SourceConfigType>[],
25082815dcSEvan Bacon  name?: string
26082815dcSEvan Bacon) {
27082815dcSEvan Bacon  const withUnknown: ConfigPlugin<SourceConfigType extends ExpoConfig ? void : SourceConfigType> = (
28082815dcSEvan Bacon    config,
29082815dcSEvan Bacon    sourceConfig
30082815dcSEvan Bacon  ) =>
31082815dcSEvan Bacon    withGradleProperties(config, (config) => {
32082815dcSEvan Bacon      config.modResults = updateAndroidBuildPropertiesFromConfig(
33082815dcSEvan Bacon        (sourceConfig ?? config) as SourceConfigType,
34082815dcSEvan Bacon        config.modResults,
35082815dcSEvan Bacon        configToPropertyRules
36082815dcSEvan Bacon      );
37082815dcSEvan Bacon      return config;
38082815dcSEvan Bacon    });
39082815dcSEvan Bacon  if (name) {
40082815dcSEvan Bacon    Object.defineProperty(withUnknown, 'name', {
41082815dcSEvan Bacon      value: name,
42082815dcSEvan Bacon    });
43082815dcSEvan Bacon  }
44082815dcSEvan Bacon  return withUnknown;
45082815dcSEvan Bacon}
46082815dcSEvan Bacon
47082815dcSEvan Bacon/**
48082815dcSEvan Bacon * A config-plugin to update `android/gradle.properties` from the `jsEngine` in expo config
49082815dcSEvan Bacon */
50082815dcSEvan Baconexport const withJsEngineGradleProps = createBuildGradlePropsConfigPlugin<ExpoConfig>(
51082815dcSEvan Bacon  [
52082815dcSEvan Bacon    {
530e8f799bSKudo Chien      propName: 'hermesEnabled',
540e8f799bSKudo Chien      propValueGetter: (config) =>
550e8f799bSKudo Chien        ((config.android?.jsEngine ?? config.jsEngine ?? 'hermes') === 'hermes').toString(),
56082815dcSEvan Bacon    },
57082815dcSEvan Bacon  ],
58082815dcSEvan Bacon  'withJsEngineGradleProps'
59082815dcSEvan Bacon);
60082815dcSEvan Bacon
61082815dcSEvan Baconexport function updateAndroidBuildPropertiesFromConfig<
62*8a424bebSJames Ide  SourceConfigType extends BuildPropertiesConfig,
63082815dcSEvan Bacon>(
64082815dcSEvan Bacon  config: SourceConfigType,
65082815dcSEvan Bacon  gradleProperties: PropertiesItem[],
66082815dcSEvan Bacon  configToPropertyRules: ConfigToPropertyRuleType<SourceConfigType>[]
67082815dcSEvan Bacon) {
68082815dcSEvan Bacon  for (const configToProperty of configToPropertyRules) {
69082815dcSEvan Bacon    const value = configToProperty.propValueGetter(config);
70082815dcSEvan Bacon    updateAndroidBuildProperty(gradleProperties, configToProperty.propName, value);
71082815dcSEvan Bacon  }
72082815dcSEvan Bacon
73082815dcSEvan Bacon  return gradleProperties;
74082815dcSEvan Bacon}
75082815dcSEvan Bacon
76082815dcSEvan Baconexport function updateAndroidBuildProperty(
77082815dcSEvan Bacon  gradleProperties: PropertiesItem[],
78082815dcSEvan Bacon  name: string,
79082815dcSEvan Bacon  value: string | null | undefined,
80082815dcSEvan Bacon  options?: { removePropWhenValueIsNull?: boolean }
81082815dcSEvan Bacon) {
82082815dcSEvan Bacon  const oldPropIndex = gradleProperties.findIndex(
83082815dcSEvan Bacon    (prop) => prop.type === 'property' && prop.key === name
84082815dcSEvan Bacon  );
85082815dcSEvan Bacon
86082815dcSEvan Bacon  if (value) {
87082815dcSEvan Bacon    // found the matched value, add or merge new property
88082815dcSEvan Bacon    const newProp: PropertiesItem = {
89082815dcSEvan Bacon      type: 'property',
90082815dcSEvan Bacon      key: name,
91082815dcSEvan Bacon      value,
92082815dcSEvan Bacon    };
93082815dcSEvan Bacon
94082815dcSEvan Bacon    if (oldPropIndex >= 0) {
95082815dcSEvan Bacon      gradleProperties[oldPropIndex] = newProp;
96082815dcSEvan Bacon    } else {
97082815dcSEvan Bacon      gradleProperties.push(newProp);
98082815dcSEvan Bacon    }
99082815dcSEvan Bacon  } else if (options?.removePropWhenValueIsNull && oldPropIndex >= 0) {
100082815dcSEvan Bacon    gradleProperties.splice(oldPropIndex, 1);
101082815dcSEvan Bacon  }
102082815dcSEvan Bacon
103082815dcSEvan Bacon  return gradleProperties;
104082815dcSEvan Bacon}
105