1import type { ExpoConfig } from '@expo/config-types'; 2 3import type { ConfigPlugin } from '../Plugin.types'; 4import { withGradleProperties } from '../plugins/android-plugins'; 5import { BuildPropertiesConfig, ConfigToPropertyRuleType } from '../utils/BuildProperties.types'; 6import type { PropertiesItem } from './Properties'; 7 8/** 9 * Creates a `withGradleProperties` config-plugin based on given config to property mapping rules. 10 * 11 * The factory supports two modes from generic type inference 12 * ```ts 13 * // config-plugin without `props`, it will implicitly use the expo config as source config. 14 * createBuildGradlePropsConfigPlugin<ExpoConfig>(): ConfigPlugin<void>; 15 * 16 * // config-plugin with a parameter `props: CustomType`, it will use the `props` as source config. 17 * createBuildGradlePropsConfigPlugin<CustomType>(): ConfigPlugin<CustomType>; 18 * ``` 19 * 20 * @param configToPropertyRules config to property mapping rules 21 * @param name the config plugin name 22 */ 23export function createBuildGradlePropsConfigPlugin<SourceConfigType extends BuildPropertiesConfig>( 24 configToPropertyRules: ConfigToPropertyRuleType<SourceConfigType>[], 25 name?: string 26) { 27 const withUnknown: ConfigPlugin<SourceConfigType extends ExpoConfig ? void : SourceConfigType> = ( 28 config, 29 sourceConfig 30 ) => 31 withGradleProperties(config, (config) => { 32 config.modResults = updateAndroidBuildPropertiesFromConfig( 33 (sourceConfig ?? config) as SourceConfigType, 34 config.modResults, 35 configToPropertyRules 36 ); 37 return config; 38 }); 39 if (name) { 40 Object.defineProperty(withUnknown, 'name', { 41 value: name, 42 }); 43 } 44 return withUnknown; 45} 46 47/** 48 * A config-plugin to update `android/gradle.properties` from the `jsEngine` in expo config 49 */ 50export const withJsEngineGradleProps = createBuildGradlePropsConfigPlugin<ExpoConfig>( 51 [ 52 { 53 propName: 'hermesEnabled', 54 propValueGetter: (config) => 55 ((config.android?.jsEngine ?? config.jsEngine ?? 'hermes') === 'hermes').toString(), 56 }, 57 ], 58 'withJsEngineGradleProps' 59); 60 61export function updateAndroidBuildPropertiesFromConfig< 62 SourceConfigType extends BuildPropertiesConfig 63>( 64 config: SourceConfigType, 65 gradleProperties: PropertiesItem[], 66 configToPropertyRules: ConfigToPropertyRuleType<SourceConfigType>[] 67) { 68 for (const configToProperty of configToPropertyRules) { 69 const value = configToProperty.propValueGetter(config); 70 updateAndroidBuildProperty(gradleProperties, configToProperty.propName, value); 71 } 72 73 return gradleProperties; 74} 75 76export function updateAndroidBuildProperty( 77 gradleProperties: PropertiesItem[], 78 name: string, 79 value: string | null | undefined, 80 options?: { removePropWhenValueIsNull?: boolean } 81) { 82 const oldPropIndex = gradleProperties.findIndex( 83 (prop) => prop.type === 'property' && prop.key === name 84 ); 85 86 if (value) { 87 // found the matched value, add or merge new property 88 const newProp: PropertiesItem = { 89 type: 'property', 90 key: name, 91 value, 92 }; 93 94 if (oldPropIndex >= 0) { 95 gradleProperties[oldPropIndex] = newProp; 96 } else { 97 gradleProperties.push(newProp); 98 } 99 } else if (options?.removePropWhenValueIsNull && oldPropIndex >= 0) { 100 gradleProperties.splice(oldPropIndex, 1); 101 } 102 103 return gradleProperties; 104} 105