import JsonFile , { JSONObject , JSONValue } from '@expo/json-file' ; import plist from '@expo/plist' ; import assert from 'assert' ; import { promises } from 'fs' ; import path from 'path' ; import xcode , { XcodeProject } from 'xcode' ; import { ExportedConfig , ModConfig } from '../Plugin.types' ; import { Entitlements , Paths } from '../ios' ; import { InfoPlist } from '../ios/IosConfig.types' ; import { getPbxproj } from '../ios/utils/Xcodeproj' ; import { getInfoPlistPathFromPbxproj } from '../ios/utils/getInfoPlistPath' ; import { fileExists } from '../utils/modules' ; import { sortObject } from '../utils/sortObject' ; import { addWarningIOS } from '../utils/warnings' ; import { ForwardedBaseModOptions , provider , withGeneratedBaseMods } from './createBaseMod' ; const { readFile , writeFile } = promises ; type IosModName = keyof Required < ModConfig > [ 'ios' ] ; function getEntitlementsPlistTemplate ( ) { return { } ; } function getInfoPlistTemplate ( ) { return { CFBundleDevelopmentRegion : '$(DEVELOPMENT_LANGUAGE)' , CFBundleExecutable : '$(EXECUTABLE_NAME)' , CFBundleIdentifier : '$(PRODUCT_BUNDLE_IDENTIFIER)' , CFBundleName : '$(PRODUCT_NAME)' , CFBundlePackageType : '$(PRODUCT_BUNDLE_PACKAGE_TYPE)' , CFBundleInfoDictionaryVersion : '6.0' , CFBundleSignature : '????' , LSRequiresIPhoneOS : true , NSAppTransportSecurity : { NSAllowsArbitraryLoads : true , NSExceptionDomains : { localhost : { NSExceptionAllowsInsecureHTTPLoads : true } } } , UILaunchStoryboardName : 'SplashScreen' , UIRequiredDeviceCapabilities : [ 'armv7' ] , UIViewControllerBasedStatusBarAppearance : false , UIStatusBarStyle : 'UIStatusBarStyleDefault' } ; } const defaultProviders = { dangerous : provider < unknown > ( { getFilePath ( ) { return '' ; } , async read ( ) { return { } ; } , async write ( ) { } } ) , appDelegate : provider < Paths . AppDelegateProjectFile > ( { getFilePath ( { modRequest : { projectRoot } } ) { return Paths . getAppDelegateFilePath ( projectRoot ) ; } , async read ( filePath ) { return Paths . getFileInfo ( filePath ) ; } , async write ( filePath , { modResults : { contents } } ) { await writeFile ( filePath , contents ) ; } } ) , expoPlist : provider < JSONObject > ( { isIntrospective : true , getFilePath ( { modRequest : { platformProjectRoot , projectName } } ) { const supportingDirectory = path . join ( platformProjectRoot , projectName ! , 'Supporting' ) ; return path . resolve ( supportingDirectory , 'Expo.plist' ) ; } , async read ( filePath , { modRequest : { introspect } } ) { try { return plist . parse ( await readFile ( filePath , 'utf8' ) ) ; } catch ( error ) { if ( introspect ) { return { } ; } throw error ; } } , async write ( filePath , { modResults , modRequest : { introspect } } ) { if ( introspect ) { return ; } await writeFile ( filePath , plist . build ( sortObject ( modResults ) ) ) ; } } ) , xcodeproj : provider < XcodeProject > ( { getFilePath ( { modRequest : { projectRoot } } ) { return Paths . getPBXProjectPath ( projectRoot ) ; } , async read ( filePath ) { const project = xcode . project ( filePath ) ; project . parseSync ( ) ; return project ; } , async write ( filePath , { modResults } ) { await writeFile ( filePath , modResults . writeSync ( ) ) ; } } ) , infoPlist : provider < InfoPlist , ForwardedBaseModOptions > ( { isIntrospective : true , async getFilePath ( config ) { let project = null ; try { project = getPbxproj ( config . modRequest . projectRoot ) ; } catch { } if ( project ) { const infoPlistBuildProperty = getInfoPlistPathFromPbxproj ( project ) ; if ( infoPlistBuildProperty ) { const infoPlistPath = path . join ( config . modRequest . platformProjectRoot , infoPlistBuildProperty ) ; if ( fileExists ( infoPlistPath ) ) { return infoPlistPath ; } addWarningIOS ( 'mods.ios.infoPlist' , `Info.plist file linked to Xcode project does not exist: ${ infoPlistPath }` ) ; } else { addWarningIOS ( 'mods.ios.infoPlist' , 'Failed to find Info.plist linked to Xcode project.' ) ; } } try { return await Paths . getInfoPlistPath ( config . modRequest . projectRoot ) ; } catch ( error ) { if ( config . modRequest . introspect ) { return '' ; } throw error ; } } , async read ( filePath , config ) { if ( ! config . ios ) config . ios = { } ; if ( ! config . ios . infoPlist ) config . ios . infoPlist = { } ; let modResults ; try { const contents = await readFile ( filePath , 'utf8' ) ; assert ( contents , 'Info.plist is empty' ) ; modResults = plist . parse ( contents ) as InfoPlist ; } catch ( error ) { if ( ! config . modRequest . introspect ) { throw error ; } modResults = getInfoPlistTemplate ( ) ; } config . ios . infoPlist = { ... ( modResults || { } ) , ... config . ios . infoPlist } ; return config . ios . infoPlist ! ; } , async write ( filePath , config ) { if ( ! config . ios ) { config . ios = { } ; } config . ios . infoPlist = config . modResults ; if ( config . modRequest . introspect ) { return ; } await writeFile ( filePath , plist . build ( sortObject ( config . modResults ) ) ) ; } } ) , entitlements : provider < JSONObject , ForwardedBaseModOptions > ( { isIntrospective : true , async getFilePath ( config ) { try { return await Entitlements . getEntitlementsPath ( config . modRequest . projectRoot ) ; } catch ( error ) { if ( config . modRequest . introspect ) { return '' ; } throw error ; } } , async read ( filePath , config ) { let modResults ; try { const contents = await readFile ( filePath , 'utf8' ) ; assert ( contents , 'Entitlements plist is empty' ) ; modResults = plist . parse ( contents ) ; } catch ( error ) { if ( ! config . modRequest . introspect ) { throw error ; } modResults = getEntitlementsPlistTemplate ( ) ; } if ( ! config . ios ) config . ios = { } ; if ( ! config . ios . entitlements ) config . ios . entitlements = { } ; config . ios . entitlements = { ... ( modResults || { } ) , ... config . ios . entitlements } ; return config . ios . entitlements ! ; } , async write ( filePath , config ) { if ( ! config . ios ) { config . ios = { } ; } config . ios . entitlements = config . modResults ; if ( config . modRequest . introspect ) { return ; } await writeFile ( filePath , plist . build ( sortObject ( config . modResults ) ) ) ; } } ) , podfileProperties : provider < Record < string , JSONValue > > ( { isIntrospective : true , getFilePath ( { modRequest : { platformProjectRoot } } ) { return path . resolve ( platformProjectRoot , 'Podfile.properties.json' ) ; } , async read ( filePath ) { let results = { } ; try { results = await JsonFile . readAsync ( filePath ) ; } catch ( e ) { } return results ; } , async write ( filePath , { modResults , modRequest : { introspect } } ) { if ( introspect ) { return ; } await JsonFile . writeAsync ( filePath , modResults ) ; } } ) } ; type IosDefaultProviders = typeof defaultProviders ; export function withIosBaseMods ( config , { providers , ... props } = { } ) { return withGeneratedBaseMods < IosModName > ( config , { ... props , platform : 'ios' , providers : providers ?? getIosModFileProviders ( ) } ) ; } export function getIosModFileProviders ( ) { return defaultProviders ; }