1import { Podspec } from '../../../CocoaPods'; 2import { FileTransforms } from '../../../Transforms.types'; 3import { VersioningModuleConfig } from '../types'; 4 5const objcFilesPattern = '*.{h,m,mm,cpp}'; 6const swiftFilesPattern = '*.swift'; 7 8export function getCommonExpoModulesTransforms(prefix: string): FileTransforms { 9 return { 10 path: [ 11 // Here we prefix names of Objective-C/C++ files. 12 // There is no need to do the same for Swift files 13 // as we don't change the symbols inside. In Swift we don't use `EX` nor `UM` 14 // for symbols as the framework name takes part of the symbol signature, 15 // so there is no way we'll get duplicate symbols compilation errors. 16 // Files starting with `Expo` needs to be prefixed though, 17 // for umbrella headers (e.g. `ExpoModulesCore.h`). 18 { 19 find: /\b(Expo|EX|UM|EAS)([^/]*\.)(h|m|mm|cpp)\b/, 20 replaceWith: `${prefix}$1$2$3`, 21 }, 22 { 23 // versioning category files, e.g. RCTComponentData+Privates.h 24 find: /\b(RCT)([^/]*)\+([^/]*\.)(h|m|mm|cpp)\b/, 25 replaceWith: `${prefix}$1$2+$3$4`, 26 }, 27 { 28 // expo-gl 29 find: /\bEXWebGL([^/]*)\.def\b/, 30 replaceWith: `${prefix}EXWebGL$1.def`, 31 }, 32 ], 33 content: [ 34 { 35 find: /\bReact(?!Common)/g, 36 replaceWith: `${prefix}React`, 37 }, 38 { 39 // Prefix symbols and imports. 40 find: /\b(EX|UM|RCT|ExpoBridgeModule)/g, 41 replaceWith: `${prefix}$1`, 42 }, 43 44 // Only Swift 45 46 { 47 paths: swiftFilesPattern, 48 find: /\bimport (Expo|EX|EAS)(\w+)/g, 49 replaceWith: `import ${prefix}$1$2`, 50 }, 51 { 52 paths: swiftFilesPattern, 53 find: /@objc\((Expo|EX|EAS)/g, 54 replaceWith: `@objc(${prefix}$1`, 55 }, 56 { 57 paths: swiftFilesPattern, 58 find: /(for)?[rR](eactTag)/gi, 59 replaceWith: (_, p1, p2) => `${p1 ?? ''}${p1 ? prefix : prefix.toLowerCase()}R${p2}`, 60 }, 61 { 62 // Prefixes name of the Expo modules provider. 63 paths: swiftFilesPattern, 64 find: /"(ExpoModulesProvider)"/g, 65 replaceWith: `"${prefix}$1"`, 66 }, 67 68 // Only Objective-C 69 70 { 71 // Prefix `Expo*` frameworks in imports. 72 paths: objcFilesPattern, 73 find: /#(import |include |if __has_include\()<(Expo|EAS)(.*?)\//g, 74 replaceWith: `#$1<${prefix}$2$3/`, 75 }, 76 { 77 paths: objcFilesPattern, 78 find: /#(import |include |if __has_include\()<(.*?)\/(Expo|EAS)(.*?)\.h>/g, 79 replaceWith: `#$1<$2/${prefix}$3$4.h>`, 80 }, 81 { 82 // Rename Swift compatibility headers from frameworks starting with `Expo`. 83 paths: objcFilesPattern, 84 find: /#import "(Expo|EAS)(.+?)-Swift\.h"/g, 85 replaceWith: `#import "${prefix}$1$2-Swift.h"`, 86 }, 87 { 88 paths: objcFilesPattern, 89 find: /@import (Expo|EX|EAS)(\w+)/g, 90 replaceWith: `@import ${prefix}$1$2`, 91 }, 92 { 93 // Prefixes imports from other React Native libs 94 paths: objcFilesPattern, 95 find: new RegExp(`#(import|include) <(ReactCommon|jsi)/(${prefix})?`, 'g'), 96 replaceWith: `#$1 <${prefix}$2/${prefix}`, 97 }, 98 { 99 // Prefixes versionable namespaces 100 paths: objcFilesPattern, 101 find: /\bnamespace (expo|facebook)\b/g, 102 replaceWith: `namespace ${prefix}$1`, 103 }, 104 { 105 // Prefixes usages of versionable namespaces 106 paths: objcFilesPattern, 107 find: /\b(expo|facebook)::/g, 108 replaceWith: `${prefix}$1::`, 109 }, 110 111 // Prefixes versionable namespaces (react namespace is already prefixed with uppercased "R") 112 { 113 paths: objcFilesPattern, 114 find: /\busing namespace react;/g, 115 replaceWith: `using namespace ${prefix}React;`, 116 }, 117 { 118 paths: objcFilesPattern, 119 find: /::react(::|;)/g, 120 replaceWith: `::${prefix}React$1`, 121 }, 122 { 123 paths: objcFilesPattern, 124 find: /\bnamespace react(\s+[^=])/g, 125 replaceWith: `namespace ${prefix}React$1`, 126 }, 127 { 128 paths: objcFilesPattern, 129 find: /\b((include|import|__has_include).*\/)(JSCRuntime\.h)/g, 130 replaceWith: `$1${prefix}$3`, 131 }, 132 { 133 paths: 'EXGLImageUtils.cpp', 134 find: '#define STB_IMAGE_IMPLEMENTATION', 135 replaceWith: '', 136 }, 137 138 // Prefix umbrella header imports 139 { 140 paths: '*.h', 141 // Use negative look ahead regexp for `prefix` to prevent duplicated versioning 142 find: new RegExp(`[\b/](!?${prefix})(\w+-umbrella\.h)\b`, 'g'), 143 replaceWith: `${prefix}$1`, 144 }, 145 146 { 147 // Dynamically remove the prefix from the "moduleName" method in the view manager adapter. 148 paths: 'EXViewManagerAdapter.{m,mm}', 149 find: /return (NSStringFromClass\(self\));/g, 150 replaceWith: `NSString *className = $1;\n return [className hasPrefix:@"${prefix}"] ? [className substringFromIndex:${prefix.length}] : className;`, 151 }, 152 ], 153 }; 154} 155 156export function getVersioningExpoModuleConfig( 157 prefix: string, 158 moduleName: string 159): VersioningModuleConfig { 160 const config: Record<string, VersioningModuleConfig> = { 161 'expo-constants': { 162 mutatePodspec: removeScriptPhasesAndResourceBundles, 163 }, 164 'expo-updates': { 165 mutatePodspec: removeScriptPhasesAndResourceBundles, 166 }, 167 'expo-screen-orientation': { 168 // Versioned expo-screen-orientation shouldn't include its own registry, it should use the unversioned one instead. 169 transforms: { 170 path: [], 171 content: [ 172 { 173 paths: 'ScreenOrientationRegistry.swift', 174 find: /(.|\n)*/, 175 replaceWith: [ 176 '// The original implementations of `ScreenOrientationRegistry` and `ScreenOrientationController`', 177 '// were removed from this file as part of the versioning process to always use their "unversioned" version.', 178 'import ExpoScreenOrientation', 179 '', 180 'typealias ScreenOrientationRegistry = ExpoScreenOrientation.ScreenOrientationRegistry', 181 'typealias ScreenOrientationController = ExpoScreenOrientation.ScreenOrientationController', 182 '', 183 ].join('\n'), 184 }, 185 ], 186 }, 187 mutatePodspec(podspec: Podspec) { 188 // Versioned screen orientation must depend on unversioned copy to use unversioned singleton object. 189 addDependency(podspec, podspec.name.replace(prefix, '')); 190 }, 191 }, 192 }; 193 return config[moduleName] ?? {}; 194} 195 196function removeScriptPhasesAndResourceBundles(podspec: Podspec): void { 197 // For expo-updates and expo-constants in Expo Go, we don't need app.config and app.manifest in versioned code. 198 delete podspec['script_phases']; 199 delete podspec['resource_bundles']; 200} 201 202function addDependency(podspec: Podspec, dependencyName: string) { 203 if (!podspec.dependencies) { 204 podspec.dependencies = {}; 205 } 206 podspec.dependencies[dependencyName] = []; 207} 208