import escapeRegExp from 'lodash/escapeRegExp'; import path from 'path'; import { transformString } from '../../Transforms'; import { FileTransform, FileTransforms, StringTransform } from '../../Transforms.types'; import { baseCmakeTransforms } from './cmakeTransforms'; import { JniLibNames } from './libraries'; import { packagesToRename } from './packagesConfig'; function pathFromPkg(pkg: string): string { return pkg.replace(/\./g, '/'); } export function reactNativeTransforms( versionedReactNativeRoot: string, abiVersion: string ): FileTransforms { return { path: [], content: [ // Add generated java to sourceSets { paths: './ReactAndroid/build.gradle', find: /(\bsrcDirs = \["src\/main\/java",.+)(\])/, replaceWith: `$1, "${path.join(versionedReactNativeRoot, 'codegen')}/java"$2`, }, // Disable codegen plugin { paths: './ReactAndroid/build.gradle', find: /(\bid\("com\.facebook\.react"\)$)/m, replaceWith: '// $1', }, { paths: './ReactAndroid/build.gradle', find: /(^react {[^]+?\n\})/m, replaceWith: '/* $1 */', }, { paths: './ReactAndroid/build.gradle', find: /(\b(preBuild\.)?dependsOn\("generateCodegenArtifactsFromSchema"\))/g, replaceWith: '// $1', }, { paths: './ReactAndroid/build.gradle', find: 'new File(buildDir, "generated/source/codegen/jni/").absolutePath', replaceWith: '"../codegen/jni/"', }, { paths: './ReactAndroid/build.gradle', find: /(externalNativeBuild\s*\{)([\s\S]*?)(\}\s)/g, replaceWith: (_, p1, p2, p3) => [ p1, transformString( p2, JniLibNames.map((lib: string) => ({ find: new RegExp(`"${escapeRegExp(lib)}"`, 'g'), replaceWith: `"${lib}_${abiVersion}"`, })) ), p3, ].join(''), }, { paths: './ReactAndroid/build.gradle', find: /( prefab\s*\{)([\s\S]*?)(^ \}\s)/gm, replaceWith: (_, p1, p2, p3) => [ p1, transformString( p2, JniLibNames.map((lib: string) => ({ find: new RegExp(`\\b${escapeRegExp(lib)}\\s+?\\{`, 'g'), replaceWith: `${lib}_${abiVersion} {`, })) ), p3, ].join(''), }, ...packagesToRename.map((pkg: string) => ({ paths: [ './ReactCommon/**/*.{java,kt,h,cpp}', './ReactAndroid/src/main/**/*.{java,kt,h,cpp}', ], find: new RegExp(`${escapeRegExp(pathFromPkg(pkg))}`, 'g'), replaceWith: `${abiVersion}/${pathFromPkg(pkg)}`, })), ...reactNativeCmakeTransforms(abiVersion), { paths: './ReactAndroid/hermes-engine/build.gradle', find: 'libraryName "libhermes"', replaceWith: `libraryName "libhermes_${abiVersion}"`, }, { paths: './ReactAndroid/hermes-engine/build.gradle', find: /(prefab {\s+libhermes)/, replaceWith: `$1_${abiVersion}`, }, { paths: './ReactAndroid/hermes-engine/build.gradle', find: 'targets "libhermes"', replaceWith: `targets "libhermes_${abiVersion}"`, }, ...[...JniLibNames, 'fb', 'fbjni'].map((libName) => ({ paths: '*.{java,kt}', find: new RegExp(`SoLoader.loadLibrary\\\("${escapeRegExp(libName)}"\\\)`), replaceWith: `SoLoader.loadLibrary("${libName}_${abiVersion}")`, })), // add HERMES_ENABLE_DEBUGGER for libhermes-executor-release.so { paths: './ReactAndroid/hermes-engine/build.gradle', find: /-DHERMES_ENABLE_DEBUGGER=False/, replaceWith: '-DHERMES_ENABLE_DEBUGGER=True', }, { paths: './ReactAndroid/hermes-engine/build.gradle', find: /\b((configureBuildForHermes|prepareHeadersForPrefab)\.dependsOn\(unzipHermes\))/g, replaceWith: '// $1', }, { paths: './ReactCommon/hermes/executor/CMakeLists.txt', find: /\bdebug (hermes-inspector_)/g, replaceWith: '$1', }, { paths: [ './ReactCommon/hermes/executor/CMakeLists.txt', './ReactCommon/hermes/inspector/CMakeLists.txt', ], find: /if\(\${CMAKE_BUILD_TYPE} MATCHES Debug\)(\n\s*target_compile_options)/g, replaceWith: 'if(true)$1', }, { paths: './ReactAndroid/src/main/jni/react/hermes/reactexecutor/CMakeLists.txt', find: '$<$:-DHERMES_ENABLE_DEBUGGER=1>', replaceWith: '-DHERMES_ENABLE_DEBUGGER=1', }, { // workaround build dependency issue to explicitly link hermes_executor_common to hermes_executor // originally, it's hermes_inspector -> hermes_executor_common -> hermes_executor paths: './ReactAndroid/src/main/jni/react/hermes/reactexecutor/CMakeLists.txt', find: /^(\s+hermes_executor_common.*)$/m, replaceWith: `$1\n hermes_inspector_${abiVersion}`, }, ], }; } export function codegenTransforms(abiVersion: string): FileTransforms { return { path: [], content: [ ...packagesToRename.map((pkg: string) => ({ paths: ['**/*.{java,kt,h,cpp}'], find: new RegExp(`${escapeRegExp(pathFromPkg(pkg))}`, 'g'), replaceWith: `${abiVersion}/${pathFromPkg(pkg)}`, })), ...reactNativeCmakeTransforms(abiVersion), ], }; } function reactNativeCmakeTransforms(abiVersion: string): FileTransform[] { const libNames = JniLibNames.map((lib: string): string => lib.startsWith('lib') ? lib.slice(3) : lib ).filter((lib: string) => !['fbjni'].includes(lib)); libNames.push('${HERMES_TARGET_NAME}'); // variable used in hermes-executor CMakeLists.txt libNames.push('hermes-engine::libhermes'); return [ ...baseCmakeTransforms(abiVersion, libNames).map((transform: StringTransform) => ({ paths: 'CMakeLists.txt', ...transform, })), { paths: 'CMakeLists.txt', find: 'add_react_build_subdir(generated/source/codegen/jni)', replaceWith: 'add_react_android_subdir(../codegen/jni)', }, { paths: 'CMakeLists.txt', find: /libhermes\.so/g, replaceWith: `libhermes_${abiVersion}.so`, }, ]; } export function hermesTransforms(abiVersion: string): StringTransform[] { return [ { find: /OUTPUT_NAME hermes/g, replaceWith: `OUTPUT_NAME hermes_${abiVersion}`, }, { find: /libhermes/g, replaceWith: `libhermes_${abiVersion}`, }, { find: /jsi/g, replaceWith: `jsi_${abiVersion}`, }, ]; }