diff --git a/packages/react-native-gradle-plugin/build.gradle.kts b/packages/react-native-gradle-plugin/build.gradle.kts index 6d7458f2bb14..fb2b84368d19 100644 --- a/packages/react-native-gradle-plugin/build.gradle.kts +++ b/packages/react-native-gradle-plugin/build.gradle.kts @@ -54,8 +54,12 @@ java { targetCompatibility = JavaVersion.VERSION_11 } -tasks.withType { - kotlinOptions { jvmTarget = JavaVersion.VERSION_11.majorVersion } +tasks.withType { + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.majorVersion + apiVersion = "1.5" + languageVersion = "1.5" + } } tasks.withType().configureEach { diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt index 2e4e92340379..296d2a4800fd 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt @@ -9,6 +9,7 @@ package com.facebook.react import com.android.build.api.variant.Variant import com.facebook.react.tasks.BundleHermesCTask +import com.facebook.react.utils.KotlinStdlibCompatUtils.capitalizeCompat import com.facebook.react.utils.NdkConfiguratorUtils.configureJsEnginePackagingOptions import com.facebook.react.utils.NdkConfiguratorUtils.configureNewArchPackagingOptions import com.facebook.react.utils.ProjectUtils.isHermesEnabled @@ -19,7 +20,7 @@ import org.gradle.api.Project @Suppress("SpreadOperator", "UnstableApiUsage") internal fun Project.configureReactTasks(variant: Variant, config: ReactExtension) { - val targetName = variant.name.replaceFirstChar { it.uppercase() } + val targetName = variant.name.capitalizeCompat() val targetPath = variant.name // Resources: generated/assets/react//index.android.bundle diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/BundleHermesCTask.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/BundleHermesCTask.kt index 2eb989143b80..55eab602f4d0 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/BundleHermesCTask.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/BundleHermesCTask.kt @@ -133,35 +133,37 @@ abstract class BundleHermesCTask : DefaultTask() { } } - internal fun getBundleCommand(bundleFile: File, sourceMapFile: File): List = - windowsAwareCommandLine( - buildList { - val rootFile = root.get().asFile - addAll(nodeExecutableAndArgs.get()) - add(cliFile.get().asFile.cliPath(rootFile)) - add(bundleCommand.get()) - add("--platform") - add("android") - add("--dev") - add(devEnabled.get().toString()) - add("--reset-cache") - add("--entry-file") - add(entryFile.get().asFile.cliPath(rootFile)) - add("--bundle-output") - add(bundleFile.cliPath(rootFile)) - add("--assets-dest") - add(resourcesDir.get().asFile.cliPath(rootFile)) - add("--sourcemap-output") - add(sourceMapFile.cliPath(rootFile)) - if (bundleConfig.isPresent) { - add("--config") - add(bundleConfig.get().asFile.cliPath(rootFile)) - } - add("--minify") - add(minifyEnabled.get().toString()) - addAll(extraPackagerArgs.get()) - add("--verbose") - }) + internal fun getBundleCommand(bundleFile: File, sourceMapFile: File): List { + val rootFile = root.get().asFile + val commandLine = + mutableListOf().apply { + addAll(nodeExecutableAndArgs.get()) + add(cliFile.get().asFile.cliPath(rootFile)) + add(bundleCommand.get()) + add("--platform") + add("android") + add("--dev") + add(devEnabled.get().toString()) + add("--reset-cache") + add("--entry-file") + add(entryFile.get().asFile.cliPath(rootFile)) + add("--bundle-output") + add(bundleFile.cliPath(rootFile)) + add("--assets-dest") + add(resourcesDir.get().asFile.cliPath(rootFile)) + add("--sourcemap-output") + add(sourceMapFile.cliPath(rootFile)) + if (bundleConfig.isPresent) { + add("--config") + add(bundleConfig.get().asFile.cliPath(rootFile)) + } + add("--minify") + add(minifyEnabled.get().toString()) + addAll(extraPackagerArgs.get()) + add("--verbose") + } + return windowsAwareCommandLine(commandLine) + } internal fun getHermescCommand( hermesCommand: String, diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/KotlinStdlibCompatUtils.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/KotlinStdlibCompatUtils.kt new file mode 100644 index 000000000000..dd0df7c5cc24 --- /dev/null +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/KotlinStdlibCompatUtils.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.utils + +import java.util.Locale + +object KotlinStdlibCompatUtils { + @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") + fun String.lowercaseCompat(): String = (this as java.lang.String).toLowerCase(Locale.ROOT) + + fun String.capitalizeCompat(): String = + if (isNotEmpty()) { + val firstChar = this[0] + val uppercaseChar = Character.toUpperCase(firstChar) + val restString = this@capitalizeCompat.substring(1) + uppercaseChar + restString + } else { + this + } + + fun String.toBooleanStrictOrNullCompat(): Boolean? = + when (this) { + "true" -> true + "false" -> false + else -> null + } +} diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/Os.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/Os.kt index 4ca00699b841..6b3fa4a3e88b 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/Os.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/Os.kt @@ -7,18 +7,19 @@ package com.facebook.react.utils +import com.facebook.react.utils.KotlinStdlibCompatUtils.lowercaseCompat import java.io.File internal object Os { fun isWindows(): Boolean = - System.getProperty("os.name")?.lowercase()?.contains("windows") ?: false + System.getProperty("os.name")?.lowercaseCompat()?.contains("windows") ?: false - fun isMac(): Boolean = System.getProperty("os.name")?.lowercase()?.contains("mac") ?: false + fun isMac(): Boolean = System.getProperty("os.name")?.lowercaseCompat()?.contains("mac") ?: false fun isLinuxAmd64(): Boolean { - val osNameMatch = System.getProperty("os.name")?.lowercase()?.contains("linux") ?: false - val archMatch = System.getProperty("os.arch")?.lowercase()?.contains("amd64") ?: false + val osNameMatch = System.getProperty("os.name")?.lowercaseCompat()?.contains("linux") ?: false + val archMatch = System.getProperty("os.arch")?.lowercaseCompat()?.contains("amd64") ?: false return osNameMatch && archMatch } diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/PathUtils.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/PathUtils.kt index 391c6c2868f5..59a025d63783 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/PathUtils.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/PathUtils.kt @@ -11,6 +11,7 @@ package com.facebook.react.utils import com.facebook.react.ReactExtension import com.facebook.react.model.ModelPackageJson +import com.facebook.react.utils.KotlinStdlibCompatUtils.capitalizeCompat import com.facebook.react.utils.Os.cliPath import java.io.File import org.gradle.api.Project @@ -188,7 +189,7 @@ internal fun getHermesOSBin(): String { internal fun projectPathToLibraryName(projectPath: String): String = projectPath .split(':', '-', '_', '.') - .joinToString("") { token -> token.replaceFirstChar { it.uppercase() } } + .joinToString("") { token -> token.capitalizeCompat() } .plus("Spec") /** diff --git a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/ProjectUtils.kt b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/ProjectUtils.kt index e941da78b564..bf9bbd79b9f9 100644 --- a/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/ProjectUtils.kt +++ b/packages/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/utils/ProjectUtils.kt @@ -8,6 +8,8 @@ package com.facebook.react.utils import com.facebook.react.model.ModelPackageJson +import com.facebook.react.utils.KotlinStdlibCompatUtils.lowercaseCompat +import com.facebook.react.utils.KotlinStdlibCompatUtils.toBooleanStrictOrNullCompat import org.gradle.api.Project import org.gradle.api.file.DirectoryProperty @@ -22,13 +24,18 @@ internal object ProjectUtils { internal val Project.isHermesEnabled: Boolean get() = if (project.hasProperty("hermesEnabled")) { - project.property("hermesEnabled").toString().lowercase().toBooleanStrictOrNull() ?: true + project + .property("hermesEnabled") + .toString() + .lowercaseCompat() + .toBooleanStrictOrNullCompat() + ?: true } else if (project.extensions.extraProperties.has("react")) { @Suppress("UNCHECKED_CAST") val reactMap = project.extensions.extraProperties.get("react") as? Map when (val enableHermesKey = reactMap?.get("enableHermes")) { is Boolean -> enableHermesKey - is String -> enableHermesKey.lowercase().toBooleanStrictOrNull() ?: true + is String -> enableHermesKey.lowercaseCompat().toBooleanStrictOrNullCompat() ?: true else -> HERMES_FALLBACK } } else { diff --git a/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/KotlinStdlibCompatUtilsTest.kt b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/KotlinStdlibCompatUtilsTest.kt new file mode 100644 index 000000000000..50c18399bd7b --- /dev/null +++ b/packages/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/utils/KotlinStdlibCompatUtilsTest.kt @@ -0,0 +1,82 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.utils + +import com.facebook.react.utils.KotlinStdlibCompatUtils.capitalizeCompat +import com.facebook.react.utils.KotlinStdlibCompatUtils.lowercaseCompat +import com.facebook.react.utils.KotlinStdlibCompatUtils.toBooleanStrictOrNullCompat +import org.junit.Assert.assertEquals +import org.junit.Test + +class KotlinStdlibCompatUtilsTest { + + @Test + fun lowercaseCompat_withEmptyString() { + assertEquals("", "".lowercaseCompat()) + } + + @Test + fun lowercaseCompat_withLowercaseString() { + assertEquals("frodo", "frodo".lowercaseCompat()) + } + + @Test + fun lowercaseCompat_withTitlecaseString() { + assertEquals("frodo", "Frodo".lowercaseCompat()) + } + + @Test + fun lowercaseCompat_withUppercaseString() { + assertEquals("frodo", "FRODO".lowercaseCompat()) + } + + @Test + fun capitalizeCompat_withEmptyString() { + assertEquals("", "".capitalizeCompat()) + } + + @Test + fun capitalizeCompat_withLowercaseString() { + assertEquals("Bilbo", "bilbo".capitalizeCompat()) + } + + @Test + fun capitalizeCompat_withTitlecaseString() { + assertEquals("Bilbo", "Bilbo".capitalizeCompat()) + } + + @Test + fun capitalizeCompat_withUppercaseString() { + assertEquals("BILBO", "BILBO".capitalizeCompat()) + } + + @Test + fun toBooleanStrictOrNullCompat_withEmptyString() { + assertEquals(null, "".toBooleanStrictOrNullCompat()) + } + + @Test + fun toBooleanStrictOrNullCompat_withfalse() { + assertEquals(false, "false".toBooleanStrictOrNullCompat()) + } + + @Test + fun toBooleanStrictOrNullCompat_withCapitalTrue_returnsNull() { + assertEquals(null, "True".toBooleanStrictOrNullCompat()) + } + + @Test + fun toBooleanStrictOrNullCompat_withCapitalFalse_returnsNull() { + assertEquals(null, "False".toBooleanStrictOrNullCompat()) + } + + @Test + fun toBooleanStrictOrNullCompat_withRandomInput_returnsNull() { + assertEquals(null, "maybe".toBooleanStrictOrNullCompat()) + } +}