1import escapeRegExp from 'lodash/escapeRegExp';
2import path from 'path';
3
4import { transformString } from '../../Transforms';
5import { FileTransform, FileTransforms, StringTransform } from '../../Transforms.types';
6import { baseCmakeTransforms } from './cmakeTransforms';
7import { JniLibNames } from './libraries';
8import { packagesToRename } from './packagesConfig';
9
10function pathFromPkg(pkg: string): string {
11  return pkg.replace(/\./g, '/');
12}
13
14export function reactNativeTransforms(
15  versionedReactNativeRoot: string,
16  abiVersion: string
17): FileTransforms {
18  return {
19    path: [],
20    content: [
21      // Update codegen folder to our customized folder
22      {
23        paths: './ReactAndroid/build.gradle',
24        find: /"REACT_GENERATED_SRC_DIR=.+?",/,
25        replaceWith: `"REACT_GENERATED_SRC_DIR=${versionedReactNativeRoot}",`,
26      },
27      // Add generated java to sourceSets
28      {
29        paths: './ReactAndroid/build.gradle',
30        find: /(\bsrcDirs = \["src\/main\/java",.+)(\])/,
31        replaceWith: `$1, "${path.join(versionedReactNativeRoot, 'codegen')}/java"$2`,
32      },
33      // Disable codegen plugin
34      {
35        paths: './ReactAndroid/build.gradle',
36        find: /(\bid\("com\.facebook\.react"\)$)/m,
37        replaceWith: '// $1',
38      },
39      {
40        paths: './ReactAndroid/build.gradle',
41        find: /(^react {[^]+?\n\})/m,
42        replaceWith: '/* $1 */',
43      },
44      {
45        paths: './ReactAndroid/build.gradle',
46        find: /(\bpreBuild\.dependsOn\("generateCodegenArtifactsFromSchema"\))/,
47        replaceWith: '// $1',
48      },
49      {
50        paths: './ReactAndroid/build.gradle',
51        find: /(externalNativeBuild\s*\{)([\s\S]*?)(\}\s)/g,
52        replaceWith: (_, p1, p2, p3) =>
53          [
54            p1,
55            transformString(
56              p2,
57              JniLibNames.map((lib: string) => ({
58                find: new RegExp(`"${escapeRegExp(lib)}"`, 'g'),
59                replaceWith: `"${lib}_${abiVersion}"`,
60              }))
61            ),
62            p3,
63          ].join(''),
64      },
65      ...packagesToRename.map((pkg: string) => ({
66        paths: ['./ReactCommon/**/*.{java,h,cpp}', './ReactAndroid/src/main/**/*.{java,h,cpp}'],
67        find: new RegExp(`${escapeRegExp(pathFromPkg(pkg))}`, 'g'),
68        replaceWith: `${abiVersion}/${pathFromPkg(pkg)}`,
69      })),
70      ...reactNativeCmakeTransforms(abiVersion),
71      {
72        paths: './ReactAndroid/hermes-engine/build.gradle',
73        find: 'libraryName "libhermes"',
74        replaceWith: `libraryName "libhermes_${abiVersion}"`,
75      },
76      {
77        paths: './ReactAndroid/hermes-engine/build.gradle',
78        find: /(prefab {\s+libhermes)/,
79        replaceWith: `$1_${abiVersion}`,
80      },
81      {
82        paths: './ReactAndroid/hermes-engine/build.gradle',
83        find: 'targets "libhermes"',
84        replaceWith: `targets "libhermes_${abiVersion}"`,
85      },
86      ...[...JniLibNames, 'fb', 'fbjni'].map((libName) => ({
87        paths: '*.java',
88        find: new RegExp(`SoLoader.loadLibrary\\\("${escapeRegExp(libName)}"\\\)`),
89        replaceWith: `SoLoader.loadLibrary("${libName}_${abiVersion}")`,
90      })),
91    ],
92  };
93}
94
95export function codegenTransforms(abiVersion: string): FileTransforms {
96  return {
97    path: [],
98    content: [
99      ...packagesToRename.map((pkg: string) => ({
100        paths: ['**/*.{java,h,cpp}'],
101        find: new RegExp(`${escapeRegExp(pathFromPkg(pkg))}`, 'g'),
102        replaceWith: `${abiVersion}/${pathFromPkg(pkg)}`,
103      })),
104      ...reactNativeCmakeTransforms(abiVersion),
105    ],
106  };
107}
108
109function reactNativeCmakeTransforms(abiVersion: string): FileTransform[] {
110  const libNames = JniLibNames.map((lib: string): string =>
111    lib.startsWith('lib') ? lib.slice(3) : lib
112  ).filter((lib: string) => !['fbjni'].includes(lib));
113  libNames.push('${HERMES_TARGET_NAME}'); // variable used in hermes-executor CMakeLists.txt
114  libNames.push('hermes-engine::libhermes');
115
116  return [
117    ...baseCmakeTransforms(abiVersion, libNames).map((transform: StringTransform) => ({
118      paths: 'CMakeLists.txt',
119      ...transform,
120    })),
121    {
122      paths: 'CMakeLists.txt',
123      find: 'add_react_android_subdir(build/generated/source/codegen/jni)',
124      replaceWith: 'add_react_android_subdir(../codegen/jni)',
125    },
126    {
127      paths: 'CMakeLists.txt',
128      find: /libhermes\.so/g,
129      replaceWith: `libhermes_${abiVersion}.so`,
130    },
131  ];
132}
133
134export function hermesTransforms(abiVersion: string): StringTransform[] {
135  return [
136    {
137      find: /OUTPUT_NAME hermes/g,
138      replaceWith: `OUTPUT_NAME hermes_${abiVersion}`,
139    },
140    {
141      find: /libhermes/g,
142      replaceWith: `libhermes_${abiVersion}`,
143    },
144    {
145      find: /jsi/g,
146      replaceWith: `jsi_${abiVersion}`,
147    },
148  ];
149}
150