1*01430c5eSTomasz Sapetaimport { Podspec } from '../../../CocoaPods';
2941f41afSTomasz Sapetaimport { FileTransforms } from '../../../Transforms.types';
3*01430c5eSTomasz Sapetaimport { VersioningModuleConfig } from '../types';
4941f41afSTomasz Sapeta
50e34784dSTomasz Sapetaconst objcFilesPattern = '*.{h,m,mm,cpp}';
6941f41afSTomasz Sapetaconst swiftFilesPattern = '*.swift';
7941f41afSTomasz Sapeta
8*01430c5eSTomasz Sapetaexport function getCommonExpoModulesTransforms(prefix: string): FileTransforms {
9941f41afSTomasz Sapeta  return {
10941f41afSTomasz Sapeta    path: [
11941f41afSTomasz Sapeta      // Here we prefix names of Objective-C/C++ files.
12941f41afSTomasz Sapeta      // There is no need to do the same for Swift files
13941f41afSTomasz Sapeta      // as we don't change the symbols inside. In Swift we don't use `EX` nor `UM`
14941f41afSTomasz Sapeta      // for symbols as the framework name takes part of the symbol signature,
15941f41afSTomasz Sapeta      // so there is no way we'll get duplicate symbols compilation errors.
16941f41afSTomasz Sapeta      // Files starting with `Expo` needs to be prefixed though,
17941f41afSTomasz Sapeta      // for umbrella headers (e.g. `ExpoModulesCore.h`).
18941f41afSTomasz Sapeta      {
192239438eSTomasz Sapeta        find: /\b(Expo|EX|UM|EAS)([^/]*\.)(h|m|mm|cpp)\b/,
20941f41afSTomasz Sapeta        replaceWith: `${prefix}$1$2$3`,
21941f41afSTomasz Sapeta      },
22370fa39dSKudo Chien      {
23370fa39dSKudo Chien        // versioning category files, e.g. RCTComponentData+Privates.h
24370fa39dSKudo Chien        find: /\b(RCT)([^/]*)\+([^/]*\.)(h|m|mm|cpp)\b/,
25370fa39dSKudo Chien        replaceWith: `${prefix}$1$2+$3$4`,
26370fa39dSKudo Chien      },
279caeeb0dSWojciech Kozyra      {
286297d8c7SWojciech Kozyra        // expo-gl
299caeeb0dSWojciech Kozyra        find: /\bEXWebGL([^/]*)\.def\b/,
309caeeb0dSWojciech Kozyra        replaceWith: `${prefix}EXWebGL$1.def`,
319caeeb0dSWojciech Kozyra      },
32941f41afSTomasz Sapeta    ],
33941f41afSTomasz Sapeta    content: [
34941f41afSTomasz Sapeta      {
35cdae24b7STomasz Sapeta        find: /\bReact(?!Common)/g,
36941f41afSTomasz Sapeta        replaceWith: `${prefix}React`,
37941f41afSTomasz Sapeta      },
38941f41afSTomasz Sapeta      {
39941f41afSTomasz Sapeta        // Prefix symbols and imports.
400e34784dSTomasz Sapeta        find: /\b(EX|UM|RCT|ExpoBridgeModule)/g,
41941f41afSTomasz Sapeta        replaceWith: `${prefix}$1`,
42941f41afSTomasz Sapeta      },
43941f41afSTomasz Sapeta
44941f41afSTomasz Sapeta      // Only Swift
45941f41afSTomasz Sapeta
46941f41afSTomasz Sapeta      {
47941f41afSTomasz Sapeta        paths: swiftFilesPattern,
482239438eSTomasz Sapeta        find: /\bimport (Expo|EX|EAS)(\w+)/g,
49941f41afSTomasz Sapeta        replaceWith: `import ${prefix}$1$2`,
50941f41afSTomasz Sapeta      },
51941f41afSTomasz Sapeta      {
52941f41afSTomasz Sapeta        paths: swiftFilesPattern,
530e34784dSTomasz Sapeta        find: /@objc\((Expo|EX|EAS)/g,
540e34784dSTomasz Sapeta        replaceWith: `@objc(${prefix}$1`,
55941f41afSTomasz Sapeta      },
56370fa39dSKudo Chien      {
57370fa39dSKudo Chien        paths: swiftFilesPattern,
58c01d02daSTomasz Sapeta        find: /(for)?[rR](eactTag)/gi,
59c01d02daSTomasz Sapeta        replaceWith: (_, p1, p2) => `${p1 ?? ''}${p1 ? prefix : prefix.toLowerCase()}R${p2}`,
60370fa39dSKudo Chien      },
6106b29f12STomasz Sapeta      {
6206b29f12STomasz Sapeta        // Prefixes name of the Expo modules provider.
6306b29f12STomasz Sapeta        paths: swiftFilesPattern,
6406b29f12STomasz Sapeta        find: /"(ExpoModulesProvider)"/g,
6506b29f12STomasz Sapeta        replaceWith: `"${prefix}$1"`,
6606b29f12STomasz Sapeta      },
67941f41afSTomasz Sapeta
68941f41afSTomasz Sapeta      // Only Objective-C
69941f41afSTomasz Sapeta
70941f41afSTomasz Sapeta      {
71941f41afSTomasz Sapeta        // Prefix `Expo*` frameworks in imports.
72941f41afSTomasz Sapeta        paths: objcFilesPattern,
73453643feSKudo Chien        find: /#(import |include |if __has_include\()<(Expo|EAS)(.*?)\//g,
746185d13dSKudo Chien        replaceWith: `#$1<${prefix}$2$3/`,
75941f41afSTomasz Sapeta      },
76941f41afSTomasz Sapeta      {
77941f41afSTomasz Sapeta        paths: objcFilesPattern,
78453643feSKudo Chien        find: /#(import |include |if __has_include\()<(.*?)\/(Expo|EAS)(.*?)\.h>/g,
79453643feSKudo Chien        replaceWith: `#$1<$2/${prefix}$3$4.h>`,
80941f41afSTomasz Sapeta      },
81941f41afSTomasz Sapeta      {
82941f41afSTomasz Sapeta        // Rename Swift compatibility headers from frameworks starting with `Expo`.
83941f41afSTomasz Sapeta        paths: objcFilesPattern,
842239438eSTomasz Sapeta        find: /#import "(Expo|EAS)(.+?)-Swift\.h"/g,
852239438eSTomasz Sapeta        replaceWith: `#import "${prefix}$1$2-Swift.h"`,
86941f41afSTomasz Sapeta      },
87941f41afSTomasz Sapeta      {
882239438eSTomasz Sapeta        paths: objcFilesPattern,
892239438eSTomasz Sapeta        find: /@import (Expo|EX|EAS)(\w+)/g,
902239438eSTomasz Sapeta        replaceWith: `@import ${prefix}$1$2`,
912239438eSTomasz Sapeta      },
922239438eSTomasz Sapeta      {
93cdae24b7STomasz Sapeta        // Prefixes imports from other React Native libs
94cdae24b7STomasz Sapeta        paths: objcFilesPattern,
950e34784dSTomasz Sapeta        find: new RegExp(`#(import|include) <(ReactCommon|jsi)/(${prefix})?`, 'g'),
960e34784dSTomasz Sapeta        replaceWith: `#$1 <${prefix}$2/${prefix}`,
97cdae24b7STomasz Sapeta      },
98cdae24b7STomasz Sapeta      {
99cdae24b7STomasz Sapeta        // Prefixes versionable namespaces
100cdae24b7STomasz Sapeta        paths: objcFilesPattern,
101cdae24b7STomasz Sapeta        find: /\bnamespace (expo|facebook)\b/g,
102cdae24b7STomasz Sapeta        replaceWith: `namespace ${prefix}$1`,
103cdae24b7STomasz Sapeta      },
104cdae24b7STomasz Sapeta      {
105cdae24b7STomasz Sapeta        // Prefixes usages of versionable namespaces
106cdae24b7STomasz Sapeta        paths: objcFilesPattern,
107cdae24b7STomasz Sapeta        find: /\b(expo|facebook)::/g,
108cdae24b7STomasz Sapeta        replaceWith: `${prefix}$1::`,
109cdae24b7STomasz Sapeta      },
110cdae24b7STomasz Sapeta
111cdae24b7STomasz Sapeta      // Prefixes versionable namespaces (react namespace is already prefixed with uppercased "R")
112cdae24b7STomasz Sapeta      {
113cdae24b7STomasz Sapeta        paths: objcFilesPattern,
114370fa39dSKudo Chien        find: /\busing namespace react;/g,
115370fa39dSKudo Chien        replaceWith: `using namespace ${prefix}React;`,
116cdae24b7STomasz Sapeta      },
117cdae24b7STomasz Sapeta      {
118cdae24b7STomasz Sapeta        paths: objcFilesPattern,
119370fa39dSKudo Chien        find: /::react(::|;)/g,
120370fa39dSKudo Chien        replaceWith: `::${prefix}React$1`,
121370fa39dSKudo Chien      },
122370fa39dSKudo Chien      {
123370fa39dSKudo Chien        paths: objcFilesPattern,
124370fa39dSKudo Chien        find: /\bnamespace react(\s+[^=])/g,
125370fa39dSKudo Chien        replaceWith: `namespace ${prefix}React$1`,
126cdae24b7STomasz Sapeta      },
1279caeeb0dSWojciech Kozyra      {
1286185d13dSKudo Chien        paths: objcFilesPattern,
1296185d13dSKudo Chien        find: /\b((include|import|__has_include).*\/)(JSCRuntime\.h)/g,
1306185d13dSKudo Chien        replaceWith: `$1${prefix}$3`,
1316185d13dSKudo Chien      },
1326185d13dSKudo Chien      {
1339caeeb0dSWojciech Kozyra        paths: 'EXGLImageUtils.cpp',
1349caeeb0dSWojciech Kozyra        find: '#define STB_IMAGE_IMPLEMENTATION',
1359caeeb0dSWojciech Kozyra        replaceWith: '',
1369caeeb0dSWojciech Kozyra      },
137cdae24b7STomasz Sapeta
138cdae24b7STomasz Sapeta      // Prefix umbrella header imports
139cdae24b7STomasz Sapeta      {
140cdae24b7STomasz Sapeta        paths: '*.h',
141370fa39dSKudo Chien        // Use negative look ahead regexp for `prefix` to prevent duplicated versioning
142453643feSKudo Chien        find: new RegExp(`[\b/](!?${prefix})(\w+-umbrella\.h)\b`, 'g'),
143cdae24b7STomasz Sapeta        replaceWith: `${prefix}$1`,
144a272999eSBartosz Kaszubowski      },
1459318cb9fSTomasz Sapeta
1469318cb9fSTomasz Sapeta      {
1479318cb9fSTomasz Sapeta        // Dynamically remove the prefix from the "moduleName" method in the view manager adapter.
1489318cb9fSTomasz Sapeta        paths: 'EXViewManagerAdapter.{m,mm}',
1499318cb9fSTomasz Sapeta        find: /return (NSStringFromClass\(self\));/g,
1509318cb9fSTomasz Sapeta        replaceWith: `NSString *className = $1;\n  return [className hasPrefix:@"${prefix}"] ? [className substringFromIndex:${prefix.length}] : className;`,
1519318cb9fSTomasz Sapeta      },
152941f41afSTomasz Sapeta    ],
153941f41afSTomasz Sapeta  };
154941f41afSTomasz Sapeta}
155*01430c5eSTomasz Sapeta
156*01430c5eSTomasz Sapetaexport function getVersioningExpoModuleConfig(
157*01430c5eSTomasz Sapeta  prefix: string,
158*01430c5eSTomasz Sapeta  moduleName: string
159*01430c5eSTomasz Sapeta): VersioningModuleConfig {
160*01430c5eSTomasz Sapeta  const config: Record<string, VersioningModuleConfig> = {
161*01430c5eSTomasz Sapeta    'expo-constants': {
162*01430c5eSTomasz Sapeta      mutatePodspec: removeScriptPhasesAndResourceBundles,
163*01430c5eSTomasz Sapeta    },
164*01430c5eSTomasz Sapeta    'expo-updates': {
165*01430c5eSTomasz Sapeta      mutatePodspec: removeScriptPhasesAndResourceBundles,
166*01430c5eSTomasz Sapeta    },
167*01430c5eSTomasz Sapeta    'expo-screen-orientation': {
168*01430c5eSTomasz Sapeta      // Versioned expo-screen-orientation shouldn't include its own registry, it should use the unversioned one instead.
169*01430c5eSTomasz Sapeta      transforms: {
170*01430c5eSTomasz Sapeta        path: [],
171*01430c5eSTomasz Sapeta        content: [
172*01430c5eSTomasz Sapeta          {
173*01430c5eSTomasz Sapeta            paths: 'ScreenOrientationRegistry.swift',
174*01430c5eSTomasz Sapeta            find: /(.|\n)*/,
175*01430c5eSTomasz Sapeta            replaceWith: [
176*01430c5eSTomasz Sapeta              '// The original implementations of `ScreenOrientationRegistry` and `ScreenOrientationController`',
177*01430c5eSTomasz Sapeta              '// were removed from this file as part of the versioning process to always use their "unversioned" version.',
178*01430c5eSTomasz Sapeta              'import ExpoScreenOrientation',
179*01430c5eSTomasz Sapeta              '',
180*01430c5eSTomasz Sapeta              'typealias ScreenOrientationRegistry = ExpoScreenOrientation.ScreenOrientationRegistry',
181*01430c5eSTomasz Sapeta              'typealias ScreenOrientationController = ExpoScreenOrientation.ScreenOrientationController',
182*01430c5eSTomasz Sapeta              '',
183*01430c5eSTomasz Sapeta            ].join('\n'),
184*01430c5eSTomasz Sapeta          },
185*01430c5eSTomasz Sapeta        ],
186*01430c5eSTomasz Sapeta      },
187*01430c5eSTomasz Sapeta      mutatePodspec(podspec: Podspec) {
188*01430c5eSTomasz Sapeta        // Versioned screen orientation must depend on unversioned copy to use unversioned singleton object.
189*01430c5eSTomasz Sapeta        addDependency(podspec, podspec.name.replace(prefix, ''));
190*01430c5eSTomasz Sapeta      },
191*01430c5eSTomasz Sapeta    },
192*01430c5eSTomasz Sapeta  };
193*01430c5eSTomasz Sapeta  return config[moduleName] ?? {};
194*01430c5eSTomasz Sapeta}
195*01430c5eSTomasz Sapeta
196*01430c5eSTomasz Sapetafunction removeScriptPhasesAndResourceBundles(podspec: Podspec): void {
197*01430c5eSTomasz Sapeta  // For expo-updates and expo-constants in Expo Go, we don't need app.config and app.manifest in versioned code.
198*01430c5eSTomasz Sapeta  delete podspec['script_phases'];
199*01430c5eSTomasz Sapeta  delete podspec['resource_bundles'];
200*01430c5eSTomasz Sapeta}
201*01430c5eSTomasz Sapeta
202*01430c5eSTomasz Sapetafunction addDependency(podspec: Podspec, dependencyName: string) {
203*01430c5eSTomasz Sapeta  if (!podspec.dependencies) {
204*01430c5eSTomasz Sapeta    podspec.dependencies = {};
205*01430c5eSTomasz Sapeta  }
206*01430c5eSTomasz Sapeta  podspec.dependencies[dependencyName] = [];
207*01430c5eSTomasz Sapeta}
208