Skip to content

Commit

Permalink
RNGP - Autolinking - Add model classes for parsing the config output
Browse files Browse the repository at this point in the history
Summary:
This diff is part of RFC0759
react-native-community/discussions-and-proposals#759

Here I'm creating data classes that will allow us to parse the `config` JSON output.
Code is pretty straightforward and follows the structure as the `config` command output.

Changelog:
[Internal] [Changed] - RNGP - Autolinking - Add model classes for parsing the `config` output

Reviewed By: cipolleschi, blakef

Differential Revision: D55475595

fbshipit-source-id: 3457c008ff0c5bce2b47fd637c7b10a5e7427c01
  • Loading branch information
cortinico authored and kosmydel committed Jun 11, 2024
1 parent dfda46a commit 63cc8d4
Show file tree
Hide file tree
Showing 9 changed files with 330 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* 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.model

data class ModelAutolinkingAndroidProjectJson(
val sourceDir: String,
val appName: String,
val packageName: String,
val applicationId: String,
val mainActivity: String,
val watchModeCommandParams: List<String>?,
val dependencyConfiguration: String?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* 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.model

data class ModelAutolinkingConfigJson(
val reactNativeVersion: String,
val dependencies: Map<String, ModelAutolinkingDependenciesJson>?,
val project: ModelAutolinkingProjectJson?,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* 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.model

data class ModelAutolinkingDependenciesJson(
val root: String,
val name: String,
val platforms: ModelAutolinkingDependenciesPlatformJson?
) {

val nameCleansed: String
get() = name.replace(Regex("[~*!'()]+"), "_").replace(Regex("^@([\\w-.]+)/"), "$1_")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* 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.model

data class ModelAutolinkingDependenciesPlatformAndroidJson(
val sourceDir: String,
val packageImportPath: String,
val packageInstance: String,
val buildTypes: List<String>,
val libraryName: String,
val componentDescriptors: List<String>,
val cmakeListsPath: String,
val cxxModuleCMakeListsModuleName: String?,
val cxxModuleCMakeListsPath: String?,
val cxxModuleHeaderName: String?,
val dependencyConfiguration: String?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* 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.model

data class ModelAutolinkingDependenciesPlatformJson(
val android: ModelAutolinkingDependenciesPlatformAndroidJson?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* 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.model

data class ModelAutolinkingProjectJson(val android: ModelAutolinkingAndroidProjectJson?)
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

package com.facebook.react.utils

import com.facebook.react.model.ModelAutolinkingConfigJson
import com.facebook.react.model.ModelPackageJson
import com.google.gson.Gson
import java.io.File
Expand All @@ -18,4 +19,10 @@ object JsonUtils {
input.bufferedReader().use {
runCatching { gsonConverter.fromJson(it, ModelPackageJson::class.java) }.getOrNull()
}

fun fromAutolinkingConfigJson(input: File): ModelAutolinkingConfigJson? =
input.bufferedReader().use {
runCatching { gsonConverter.fromJson(it, ModelAutolinkingConfigJson::class.java) }
.getOrNull()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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.model

import org.junit.Assert.assertEquals
import org.junit.Test

class ModelAutolinkingDependenciesJsonTest {

@Test
fun nameCleansed_withoutScope() {
assertEquals("name", ModelAutolinkingDependenciesJson("", "name", null).nameCleansed)
assertEquals(
"react_native", ModelAutolinkingDependenciesJson("", "react~native", null).nameCleansed)
assertEquals(
"react_native", ModelAutolinkingDependenciesJson("", "react*native", null).nameCleansed)
assertEquals(
"react_native", ModelAutolinkingDependenciesJson("", "react!native", null).nameCleansed)
assertEquals(
"react_native", ModelAutolinkingDependenciesJson("", "react'native", null).nameCleansed)
assertEquals(
"react_native", ModelAutolinkingDependenciesJson("", "react(native", null).nameCleansed)
assertEquals(
"react_native", ModelAutolinkingDependenciesJson("", "react)native", null).nameCleansed)
assertEquals(
"react_native",
ModelAutolinkingDependenciesJson("", "react~*!'()native", null).nameCleansed)
}

@Test
fun nameCleansed_withScope() {
assertEquals(
"react-native_package",
ModelAutolinkingDependenciesJson("", "@react-native/package", null).nameCleansed)
assertEquals(
"this_is_a_more_complicated_example_of_weird_packages",
ModelAutolinkingDependenciesJson(
"", "@this*is~a(more)complicated/example!of~weird)packages", null)
.nameCleansed)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ class JsonUtilsTest {
@get:Rule val tempFolder = TemporaryFolder()

@Test
fun withInvalidJson_returnsNull() {
fun fromPackageJson_withInvalidJson_returnsNull() {
val invalidJson = createJsonFile("""¯\_(ツ)_/¯""")

assertNull(JsonUtils.fromPackageJson(invalidJson))
}

@Test
fun withEmptyJson_returnsEmptyObject() {
fun fromPackageJson_withEmptyJson_returnsEmptyObject() {
val invalidJson = createJsonFile("""{}""")

val parsed = JsonUtils.fromPackageJson(invalidJson)
Expand All @@ -35,7 +35,7 @@ class JsonUtilsTest {
}

@Test
fun withOldJsonConfig_returnsAnEmptyLibrary() {
fun fromPackageJson_withOldJsonConfig_returnsAnEmptyLibrary() {
val oldJsonConfig =
createJsonFile(
"""
Expand All @@ -62,7 +62,7 @@ class JsonUtilsTest {
}

@Test
fun withValidJson_parsesCorrectly() {
fun fromPackageJson_withValidJson_parsesCorrectly() {
val validJson =
createJsonFile(
"""
Expand Down Expand Up @@ -121,6 +121,185 @@ class JsonUtilsTest {
assertEquals("1000.0.0", parsed.version)
}

@Test
fun fromAutolinkingConfigJson_withInvalidJson_returnsNull() {
val invalidJson = createJsonFile("""¯\_(ツ)_/¯""")

assertNull(JsonUtils.fromAutolinkingConfigJson(invalidJson))
}

@Test
fun fromAutolinkingConfigJson_withSimpleJson_returnsIt() {
val validJson =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0"
}
"""
.trimIndent())
val parsed = JsonUtils.fromAutolinkingConfigJson(validJson)!!

assertEquals("1000.0.0", parsed.reactNativeVersion)
}

@Test
fun fromAutolinkingConfigJson_withProjectSpecified_canParseIt() {
val validJson =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0",
"project": {
"ios": {
"sourceDir": "./packages/rn-tester",
"xcodeProject": {
"name": "RNTesterPods.xcworkspace",
"isWorkspace": true
},
"automaticPodsInstallation": false
},
"android": {
"sourceDir": "./packages/rn-tester",
"appName": "RN-Tester",
"packageName": "com.facebook.react.uiapp",
"applicationId": "com.facebook.react.uiapp",
"mainActivity": ".RNTesterActivity",
"watchModeCommandParams": [
"--mode HermesDebug"
],
"dependencyConfiguration": "implementation"
}
}
}
"""
.trimIndent())
val parsed = JsonUtils.fromAutolinkingConfigJson(validJson)!!

assertEquals("./packages/rn-tester", parsed.project!!.android!!.sourceDir)
assertEquals("RN-Tester", parsed.project!!.android!!.appName)
assertEquals("com.facebook.react.uiapp", parsed.project!!.android!!.packageName)
assertEquals("com.facebook.react.uiapp", parsed.project!!.android!!.applicationId)
assertEquals(".RNTesterActivity", parsed.project!!.android!!.mainActivity)
assertEquals("--mode HermesDebug", parsed.project!!.android!!.watchModeCommandParams!![0])
assertEquals("implementation", parsed.project!!.android!!.dependencyConfiguration)
}

@Test
fun fromAutolinkingConfigJson_withDependenciesSpecified_canParseIt() {
val validJson =
createJsonFile(
"""
{
"reactNativeVersion": "1000.0.0",
"dependencies": {
"@react-native/oss-library-example": {
"root": "./node_modules/@react-native/oss-library-example",
"name": "@react-native/oss-library-example",
"platforms": {
"ios": {
"podspecPath": "./node_modules/@react-native/oss-library-example/OSSLibraryExample.podspec",
"version": "0.0.1",
"configurations": [],
"scriptPhases": []
},
"android": {
"sourceDir": "./node_modules/@react-native/oss-library-example/android",
"packageImportPath": "import com.facebook.react.osslibraryexample.OSSLibraryExamplePackage;",
"packageInstance": "new OSSLibraryExamplePackage()",
"buildTypes": ["staging", "debug", "release"],
"libraryName": "OSSLibraryExampleSpec",
"componentDescriptors": [
"SampleNativeComponentComponentDescriptor"
],
"cmakeListsPath": "./node_modules/@react-native/oss-library-example/android/build/generated/source/codegen/jni/CMakeLists.txt",
"cxxModuleCMakeListsModuleName": null,
"cxxModuleCMakeListsPath": null,
"cxxModuleHeaderName": null,
"dependencyConfiguration": "implementation"
}
}
}
}
}
"""
.trimIndent())
val parsed = JsonUtils.fromAutolinkingConfigJson(validJson)!!

assertEquals(
"./node_modules/@react-native/oss-library-example",
parsed.dependencies!!["@react-native/oss-library-example"]!!.root)
assertEquals(
"@react-native/oss-library-example",
parsed.dependencies!!["@react-native/oss-library-example"]!!.name)
assertEquals(
"react-native_oss-library-example",
parsed.dependencies!!["@react-native/oss-library-example"]!!.nameCleansed)
assertEquals(
"./node_modules/@react-native/oss-library-example/android",
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.sourceDir)
assertEquals(
"import com.facebook.react.osslibraryexample.OSSLibraryExamplePackage;",
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.packageImportPath)
assertEquals(
"new OSSLibraryExamplePackage()",
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.packageInstance)
assertEquals(
listOf("staging", "debug", "release"),
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.buildTypes)
assertEquals(
"OSSLibraryExampleSpec",
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.libraryName)
assertEquals(
listOf("SampleNativeComponentComponentDescriptor"),
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.componentDescriptors)
assertEquals(
"./node_modules/@react-native/oss-library-example/android/build/generated/source/codegen/jni/CMakeLists.txt",
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.cmakeListsPath)
assertNull(
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.cxxModuleHeaderName)
assertNull(
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.cxxModuleCMakeListsPath)
assertNull(
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.cxxModuleCMakeListsModuleName)
assertEquals(
"implementation",
parsed.dependencies!!["@react-native/oss-library-example"]!!
.platforms!!
.android!!
.dependencyConfiguration)
}

private fun createJsonFile(@Language("JSON") input: String) =
tempFolder.newFile().apply { writeText(input) }
}

0 comments on commit 63cc8d4

Please sign in to comment.