From a0bbfcda15cc24818370b3c640a872aa0268c569 Mon Sep 17 00:00:00 2001 From: riteshshukla04 Date: Mon, 1 Dec 2025 17:31:03 +0530 Subject: [PATCH 1/3] fix: ambigous class name --- .../react/tasks/GeneratePackageListTask.kt | 91 +++++++++++-------- .../tasks/GeneratePackageListTaskTest.kt | 58 +++++------- 2 files changed, 76 insertions(+), 73 deletions(-) diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GeneratePackageListTask.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GeneratePackageListTask.kt index c3f260a02d06fe..6050f76b9511ec 100644 --- a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GeneratePackageListTask.kt +++ b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GeneratePackageListTask.kt @@ -34,24 +34,21 @@ abstract class GeneratePackageListTask : DefaultTask() { JsonUtils.fromAutolinkingConfigJson(autolinkInputFile.get().asFile) ?: error( """ - RNGP - Autolinking: Could not parse autolinking config file: - ${autolinkInputFile.get().asFile.absolutePath} - - The file is either missing or not containing valid JSON so the build won't succeed. - """ - .trimIndent() - ) + RNGP - Autolinking: Could not parse autolinking config file: + ${autolinkInputFile.get().asFile.absolutePath} + + The file is either missing or not containing valid JSON so the build won't succeed. + """ + .trimIndent()) val packageName = model.project?.android?.packageName ?: error( - "RNGP - Autolinking: Could not find project.android.packageName in react-native config output! Could not autolink packages without this field." - ) + "RNGP - Autolinking: Could not find project.android.packageName in react-native config output! Could not autolink packages without this field.") val androidPackages = filterAndroidPackages(model) - val packageImports = composePackageImports(packageName, androidPackages) val packageClassInstance = composePackageInstance(packageName, androidPackages) - val generatedFileContents = composeFileContent(packageImports, packageClassInstance) + val generatedFileContents = composeFileContent(packageClassInstance) val outputDir = generatedOutputDirectory.get().asFile outputDir.mkdirs() @@ -61,34 +58,54 @@ abstract class GeneratePackageListTask : DefaultTask() { } } - internal fun composePackageImports( - packageName: String, - packages: Map, - ) = - packages.entries.joinToString("\n") { (name, dep) -> - val packageImportPath = - requireNotNull(dep.packageImportPath) { - "RNGP - Autolinking: Missing `packageImportPath` in `config` for dependency $name. This is required to generate the autolinking package list." - } - "// $name\n${interpolateDynamicValues(packageImportPath, packageName)}" - } + /** + * Extracts the fully qualified class name from an import statement. E.g., "import + * com.foo.bar.MyClass;" -> "com.foo.bar.MyClass" + */ + internal fun extractFqcnFromImport(importStatement: String): String? { + val match = Regex("import\\s+([\\w.]+)\\s*;").find(importStatement) + return match?.groupValues?.get(1) + } internal fun composePackageInstance( packageName: String, packages: Map, - ) = - if (packages.isEmpty()) { - "" - } else { - ",\n " + - packages.entries.joinToString(",\n ") { (name, dep) -> - val packageInstance = - requireNotNull(dep.packageInstance) { - "RNGP - Autolinking: Missing `packageInstance` in `config` for dependency $name. This is required to generate the autolinking package list." - } - interpolateDynamicValues(packageInstance, packageName) - } - } + ): String { + if (packages.isEmpty()) { + return "" + } + + val instances = + packages.entries.map { (name, dep) -> + val packageInstance = + requireNotNull(dep.packageInstance) { + "RNGP - Autolinking: Missing `packageInstance` in `config` for dependency $name. This is required to generate the autolinking package list." + } + val packageImportPath = dep.packageImportPath + val interpolated = interpolateDynamicValues(packageInstance, packageName) + + // Use FQCN to avoid class name collisions between different packages + val fqcnInstance = + if (packageImportPath != null) { + val fqcn = + extractFqcnFromImport(interpolateDynamicValues(packageImportPath, packageName)) + if (fqcn != null) { + val className = fqcn.substringAfterLast('.') + // Replace the short class name with FQCN in the instance + interpolated.replace(Regex("\\b${Regex.escape(className)}\\b")) { fqcn } + } else { + interpolated + } + } else { + interpolated + } + + // Add comment with package name before each instance + "// $name\n $fqcnInstance" + } + + return ",\n " + instances.joinToString(",\n ") + } internal fun filterAndroidPackages( model: ModelAutolinkingConfigJson? @@ -101,9 +118,9 @@ abstract class GeneratePackageListTask : DefaultTask() { .associate { it.name to checkNotNull(it.platforms?.android) } } - internal fun composeFileContent(packageImports: String, packageClassInstance: String): String = + internal fun composeFileContent(packageClassInstance: String): String = generatedFileContentsTemplate - .replace("{{ packageImports }}", packageImports) + .replace("{{ packageImports }}", "") .replace("{{ packageClassInstances }}", packageClassInstance) companion object { diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GeneratePackageListTaskTest.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GeneratePackageListTaskTest.kt index 2cbf96febbffda..9074f0919f390b 100644 --- a/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GeneratePackageListTaskTest.kt +++ b/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GeneratePackageListTaskTest.kt @@ -43,29 +43,17 @@ class GeneratePackageListTaskTest { } @Test - fun composePackageImports_withNoPackages_returnsEmpty() { + fun extractFqcnFromImport_withValidImport_returnsClassName() { val task = createTestTask() - val packageName = "com.facebook.react" - val result = task.composePackageImports(packageName, emptyMap()) - assertThat(result).isEqualTo("") + val result = task.extractFqcnFromImport("import com.facebook.react.APackage;") + assertThat(result).isEqualTo("com.facebook.react.APackage") } @Test - fun composePackageImports_withPackages_returnsImportCorrectly() { + fun extractFqcnFromImport_withInvalidImport_returnsNull() { val task = createTestTask() - val packageName = "com.facebook.react" - - val result = task.composePackageImports(packageName, testDependencies) - assertThat(result) - .isEqualTo( - """ - // @react-native/a-package - import com.facebook.react.aPackage; - // @react-native/another-package - import com.facebook.react.anotherPackage; - """ - .trimIndent() - ) + val result = task.extractFqcnFromImport("invalid import statement") + assertThat(result).isNull() } @Test @@ -77,7 +65,7 @@ class GeneratePackageListTaskTest { } @Test - fun composePackageInstance_withPackages_returnsImportCorrectly() { + fun composePackageInstance_withPackages_returnsFqcnCorrectly() { val task = createTestTask() val packageName = "com.facebook.react" @@ -86,8 +74,10 @@ class GeneratePackageListTaskTest { .isEqualTo( """ , - new APackage(), - new AnotherPackage() + // @react-native/a-package + new com.facebook.react.APackage(), + // @react-native/another-package + new com.facebook.react.AnotherPackage() """ .trimIndent() ) @@ -226,10 +216,8 @@ class GeneratePackageListTaskTest { @Test fun composeFileContent_withNoPackages_returnsValidFile() { val task = createTestTask() - val packageName = "com.facebook.react" - val imports = task.composePackageImports(packageName, emptyMap()) - val instance = task.composePackageInstance(packageName, emptyMap()) - val result = task.composeFileContent(imports, instance) + val instance = task.composePackageInstance("com.facebook.react", emptyMap()) + val result = task.composeFileContent(instance) // language=java assertThat(result) .isEqualTo( @@ -246,7 +234,7 @@ class GeneratePackageListTaskTest { import java.util.Arrays; import java.util.ArrayList; - + @SuppressWarnings("deprecation") public class PackageList { @@ -305,9 +293,8 @@ class GeneratePackageListTaskTest { fun composeFileContent_withPackages_returnsValidFile() { val task = createTestTask() val packageName = "com.facebook.react" - val imports = task.composePackageImports(packageName, testDependencies) val instance = task.composePackageInstance(packageName, testDependencies) - val result = task.composeFileContent(imports, instance) + val result = task.composeFileContent(instance) // language=java assertThat(result) .isEqualTo( @@ -324,10 +311,7 @@ class GeneratePackageListTaskTest { import java.util.Arrays; import java.util.ArrayList; - // @react-native/a-package - import com.facebook.react.aPackage; - // @react-native/another-package - import com.facebook.react.anotherPackage; + @SuppressWarnings("deprecation") public class PackageList { @@ -374,8 +358,10 @@ class GeneratePackageListTaskTest { public ArrayList getPackages() { return new ArrayList<>(Arrays.asList( new MainReactPackage(mConfig), - new APackage(), - new AnotherPackage() + // @react-native/a-package + new com.facebook.react.APackage(), + // @react-native/another-package + new com.facebook.react.AnotherPackage() )); } } @@ -389,7 +375,7 @@ class GeneratePackageListTaskTest { "@react-native/a-package" to ModelAutolinkingDependenciesPlatformAndroidJson( sourceDir = "./a/directory", - packageImportPath = "import com.facebook.react.aPackage;", + packageImportPath = "import com.facebook.react.APackage;", packageInstance = "new APackage()", buildTypes = emptyList(), libraryName = "aPackage", @@ -399,7 +385,7 @@ class GeneratePackageListTaskTest { "@react-native/another-package" to ModelAutolinkingDependenciesPlatformAndroidJson( sourceDir = "./another/directory", - packageImportPath = "import com.facebook.react.anotherPackage;", + packageImportPath = "import com.facebook.react.AnotherPackage;", packageInstance = "new AnotherPackage()", buildTypes = emptyList(), libraryName = "anotherPackage", From adedfe1fd0dfa66f121e05271d51da95f95857c0 Mon Sep 17 00:00:00 2001 From: riteshshukla04 Date: Wed, 3 Dec 2025 17:31:31 +0530 Subject: [PATCH 2/3] fix: comments --- .../com/facebook/react/tasks/GeneratePackageListTask.kt | 6 +----- .../com/facebook/react/tasks/GeneratePackageListTaskTest.kt | 4 ---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GeneratePackageListTask.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GeneratePackageListTask.kt index 6050f76b9511ec..5d86392efa1b28 100644 --- a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GeneratePackageListTask.kt +++ b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GeneratePackageListTask.kt @@ -119,9 +119,7 @@ abstract class GeneratePackageListTask : DefaultTask() { } internal fun composeFileContent(packageClassInstance: String): String = - generatedFileContentsTemplate - .replace("{{ packageImports }}", "") - .replace("{{ packageClassInstances }}", packageClassInstance) + generatedFileContentsTemplate.replace("{{ packageClassInstances }}", packageClassInstance) companion object { const val GENERATED_FILENAME = "com/facebook/react/PackageList.java" @@ -165,8 +163,6 @@ abstract class GeneratePackageListTask : DefaultTask() { import java.util.Arrays; import java.util.ArrayList; - {{ packageImports }} - @SuppressWarnings("deprecation") public class PackageList { private Application application; diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GeneratePackageListTaskTest.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GeneratePackageListTaskTest.kt index 9074f0919f390b..f8e455356a5a46 100644 --- a/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GeneratePackageListTaskTest.kt +++ b/packages/gradle-plugin/react-native-gradle-plugin/src/test/kotlin/com/facebook/react/tasks/GeneratePackageListTaskTest.kt @@ -234,8 +234,6 @@ class GeneratePackageListTaskTest { import java.util.Arrays; import java.util.ArrayList; - - @SuppressWarnings("deprecation") public class PackageList { private Application application; @@ -311,8 +309,6 @@ class GeneratePackageListTaskTest { import java.util.Arrays; import java.util.ArrayList; - - @SuppressWarnings("deprecation") public class PackageList { private Application application; From 4ada047b2ffa5c15a4db56014c27287f3683f330 Mon Sep 17 00:00:00 2001 From: riteshshukla04 Date: Wed, 3 Dec 2025 17:41:37 +0530 Subject: [PATCH 3/3] fix: warnings --- .../react/tasks/GeneratePackageListTask.kt | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GeneratePackageListTask.kt b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GeneratePackageListTask.kt index 5d86392efa1b28..be2dce0247a2cf 100644 --- a/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GeneratePackageListTask.kt +++ b/packages/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks/GeneratePackageListTask.kt @@ -85,17 +85,13 @@ abstract class GeneratePackageListTask : DefaultTask() { val interpolated = interpolateDynamicValues(packageInstance, packageName) // Use FQCN to avoid class name collisions between different packages + val fqcn = + extractFqcnFromImport(interpolateDynamicValues(packageImportPath, packageName)) val fqcnInstance = - if (packageImportPath != null) { - val fqcn = - extractFqcnFromImport(interpolateDynamicValues(packageImportPath, packageName)) - if (fqcn != null) { - val className = fqcn.substringAfterLast('.') - // Replace the short class name with FQCN in the instance - interpolated.replace(Regex("\\b${Regex.escape(className)}\\b")) { fqcn } - } else { - interpolated - } + if (fqcn != null) { + val className = fqcn.substringAfterLast('.') + // Replace the short class name with FQCN in the instance + interpolated.replace(Regex("\\b${Regex.escape(className)}\\b")) { fqcn } } else { interpolated }