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: 'expo.jsEngine', 54 propValueGetter: (config) => config.android?.jsEngine ?? config.jsEngine ?? 'jsc', 55 }, 56 ], 57 'withJsEngineGradleProps' 58); 59 60export function updateAndroidBuildPropertiesFromConfig< 61 SourceConfigType extends BuildPropertiesConfig 62>( 63 config: SourceConfigType, 64 gradleProperties: PropertiesItem[], 65 configToPropertyRules: ConfigToPropertyRuleType<SourceConfigType>[] 66) { 67 for (const configToProperty of configToPropertyRules) { 68 const value = configToProperty.propValueGetter(config); 69 updateAndroidBuildProperty(gradleProperties, configToProperty.propName, value); 70 } 71 72 return gradleProperties; 73} 74 75export function updateAndroidBuildProperty( 76 gradleProperties: PropertiesItem[], 77 name: string, 78 value: string | null | undefined, 79 options?: { removePropWhenValueIsNull?: boolean } 80) { 81 const oldPropIndex = gradleProperties.findIndex( 82 (prop) => prop.type === 'property' && prop.key === name 83 ); 84 85 if (value) { 86 // found the matched value, add or merge new property 87 const newProp: PropertiesItem = { 88 type: 'property', 89 key: name, 90 value, 91 }; 92 93 if (oldPropIndex >= 0) { 94 gradleProperties[oldPropIndex] = newProp; 95 } else { 96 gradleProperties.push(newProp); 97 } 98 } else if (options?.removePropWhenValueIsNull && oldPropIndex >= 0) { 99 gradleProperties.splice(oldPropIndex, 1); 100 } 101 102 return gradleProperties; 103} 104