expo-modules-core 1.2.6 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/CHANGELOG.md +33 -4
  2. package/ExpoModulesCore.podspec +1 -0
  3. package/README.md +1 -1
  4. package/android/ExpoModulesCorePlugin.gradle +16 -0
  5. package/android/build.gradle +3 -2
  6. package/android/src/main/cpp/Exceptions.cpp +8 -0
  7. package/android/src/main/cpp/Exceptions.h +11 -0
  8. package/android/src/main/cpp/ExpoModulesHostObject.cpp +22 -5
  9. package/android/src/main/cpp/ExpoModulesHostObject.h +5 -0
  10. package/android/src/main/cpp/JNIInjector.cpp +2 -0
  11. package/android/src/main/cpp/JSIInteropModuleRegistry.cpp +25 -1
  12. package/android/src/main/cpp/JSIInteropModuleRegistry.h +14 -0
  13. package/android/src/main/cpp/JSIObjectWrapper.h +15 -4
  14. package/android/src/main/cpp/JSITypeConverter.h +3 -2
  15. package/android/src/main/cpp/JavaReferencesCache.cpp +2 -0
  16. package/android/src/main/cpp/JavaScriptFunction.cpp +56 -0
  17. package/android/src/main/cpp/JavaScriptFunction.h +54 -0
  18. package/android/src/main/cpp/JavaScriptModuleObject.cpp +225 -105
  19. package/android/src/main/cpp/JavaScriptModuleObject.h +67 -34
  20. package/android/src/main/cpp/JavaScriptObject.cpp +55 -1
  21. package/android/src/main/cpp/JavaScriptObject.h +17 -13
  22. package/android/src/main/cpp/JavaScriptRuntime.cpp +12 -3
  23. package/android/src/main/cpp/JavaScriptRuntime.h +9 -1
  24. package/android/src/main/cpp/JavaScriptValue.cpp +9 -0
  25. package/android/src/main/cpp/JavaScriptValue.h +4 -0
  26. package/android/src/main/cpp/MethodMetadata.cpp +66 -87
  27. package/android/src/main/cpp/MethodMetadata.h +18 -16
  28. package/android/src/main/cpp/ObjectDeallocator.h +25 -0
  29. package/android/src/main/cpp/WeakRuntimeHolder.cpp +7 -0
  30. package/android/src/main/cpp/WeakRuntimeHolder.h +4 -0
  31. package/android/src/main/cpp/types/CppType.h +4 -1
  32. package/android/src/main/cpp/types/FrontendConverter.cpp +58 -0
  33. package/android/src/main/cpp/types/FrontendConverter.h +45 -0
  34. package/android/src/main/cpp/types/FrontendConverterProvider.cpp +3 -0
  35. package/android/src/main/cpp/types/JNIToJSIConverter.cpp +88 -0
  36. package/android/src/main/cpp/types/JNIToJSIConverter.h +22 -0
  37. package/android/src/main/java/com/facebook/react/uimanager/ReactStylesDiffMapHelper.kt +10 -0
  38. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +18 -25
  39. package/android/src/main/java/expo/modules/kotlin/FilteredIterator.kt +37 -0
  40. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +1 -1
  41. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +34 -21
  42. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +13 -3
  43. package/android/src/main/java/expo/modules/kotlin/Utils.kt +21 -0
  44. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultCaller.kt +21 -1
  45. package/android/src/main/java/expo/modules/kotlin/classcomponent/ClassComponentBuilder.kt +112 -0
  46. package/android/src/main/java/expo/modules/kotlin/classcomponent/ClassDefinitionData.kt +10 -0
  47. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +21 -0
  48. package/android/src/main/java/expo/modules/kotlin/exception/CommonExceptions.kt +15 -0
  49. package/android/src/main/java/expo/modules/kotlin/functions/AnyFunction.kt +17 -4
  50. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +38 -8
  51. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +3 -2
  52. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +3 -2
  53. package/android/src/main/java/expo/modules/kotlin/functions/SuspendFunctionComponent.kt +1 -0
  54. package/android/src/main/java/expo/modules/kotlin/functions/SyncFunctionComponent.kt +18 -11
  55. package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +4 -1
  56. package/android/src/main/java/expo/modules/kotlin/jni/JNIDeallocator.kt +73 -0
  57. package/android/src/main/java/expo/modules/kotlin/jni/JSIInteropModuleRegistry.kt +28 -2
  58. package/android/src/main/java/expo/modules/kotlin/jni/JavaCallback.kt +8 -1
  59. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptFunction.kt +48 -0
  60. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptModuleObject.kt +40 -3
  61. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptObject.kt +23 -3
  62. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +26 -1
  63. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +0 -11
  64. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +26 -16
  65. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +3 -1
  66. package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObject.kt +12 -0
  67. package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObjectRegistry.kt +62 -0
  68. package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObjectTypeConverter.kt +27 -0
  69. package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +2 -1
  70. package/android/src/main/java/expo/modules/kotlin/types/EitherTypeConverter.kt +7 -6
  71. package/android/src/main/java/expo/modules/kotlin/types/JavaScriptFunctionTypeConverter.kt +22 -0
  72. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +30 -24
  73. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +45 -1
  74. package/android/src/main/java/expo/modules/kotlin/types/TypedArrayTypeConverter.kt +3 -2
  75. package/android/src/main/java/expo/modules/kotlin/views/AnyViewProp.kt +3 -1
  76. package/android/src/main/java/expo/modules/kotlin/views/ConcreteViewProp.kt +3 -3
  77. package/android/src/main/java/expo/modules/kotlin/views/FilteredReadableMap.kt +53 -0
  78. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +25 -5
  79. package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +25 -5
  80. package/android/src/main/java/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +161 -10
  81. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +0 -67
  82. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +7 -8
  83. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +40 -3
  84. package/android/src/main/java/expo/modules/kotlin/views/ViewTypeConverter.kt +44 -0
  85. package/android-annotation/build.gradle +45 -0
  86. package/android-annotation/src/main/java/expo/modules/annotation/Config.kt +7 -0
  87. package/android-annotation/src/main/java/expo/modules/annotation/ConverterBinder.kt +7 -0
  88. package/android-annotation-processor/build.gradle +51 -0
  89. package/android-annotation-processor/src/main/java/expo/modules/annotationprocessor/ExpoSymbolProcessor.kt +175 -0
  90. package/android-annotation-processor/src/main/java/expo/modules/annotationprocessor/ExpoSymbolProcessorProvider.kt +10 -0
  91. package/android-annotation-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider +1 -0
  92. package/build/NativeViewManagerAdapter.native.d.ts.map +1 -1
  93. package/build/NativeViewManagerAdapter.native.js +36 -23
  94. package/build/NativeViewManagerAdapter.native.js.map +1 -1
  95. package/build/requireNativeModule.js +2 -2
  96. package/build/requireNativeModule.js.map +1 -1
  97. package/common/cpp/fabric/ExpoViewProps.cpp +18 -3
  98. package/common/cpp/fabric/ExpoViewProps.h +4 -1
  99. package/ios/Fabric/ExpoFabricView.swift +10 -10
  100. package/ios/Fabric/ExpoFabricViewObjC.h +2 -0
  101. package/ios/Fabric/ExpoFabricViewObjC.mm +17 -2
  102. package/ios/JSI/EXJSIInstaller.mm +1 -1
  103. package/ios/JSI/EXJSIUtils.h +5 -0
  104. package/ios/JSI/EXJSIUtils.mm +17 -0
  105. package/ios/JSI/EXJavaScriptRuntime.h +5 -0
  106. package/ios/JSI/EXJavaScriptRuntime.mm +6 -0
  107. package/ios/JSI/EXJavaScriptValue.h +2 -0
  108. package/ios/JSI/EXJavaScriptValue.mm +8 -0
  109. package/ios/JSI/EXJavaScriptWeakObject.mm +29 -8
  110. package/ios/JSI/EXRawJavaScriptFunction.h +24 -0
  111. package/ios/JSI/EXRawJavaScriptFunction.mm +52 -0
  112. package/ios/JSI/ExpoModulesHostObject.mm +1 -1
  113. package/ios/JSI/JavaScriptValue.swift +28 -1
  114. package/ios/ModuleRegistry/EXModuleRegistry.h +0 -4
  115. package/ios/ModuleRegistry/EXModuleRegistry.m +0 -23
  116. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +0 -16
  117. package/ios/ModuleRegistryProvider/EXModuleRegistryProvider.m +0 -6
  118. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +1 -31
  119. package/ios/Swift/AppContext.swift +46 -6
  120. package/ios/Swift/Arguments/Convertible.swift +3 -3
  121. package/ios/Swift/Arguments/Convertibles.swift +5 -5
  122. package/ios/Swift/Classes/ClassComponent.swift +18 -12
  123. package/ios/Swift/Classes/ClassRegistry.swift +31 -0
  124. package/ios/Swift/Conversions.swift +19 -3
  125. package/ios/Swift/Convertibles/Convertibles+Color.swift +3 -3
  126. package/ios/Swift/Convertibles/Either.swift +6 -4
  127. package/ios/Swift/DynamicTypes/AnyDynamicType.swift +18 -2
  128. package/ios/Swift/DynamicTypes/DynamicArrayType.swift +3 -3
  129. package/ios/Swift/DynamicTypes/DynamicConvertibleType.swift +2 -2
  130. package/ios/Swift/DynamicTypes/DynamicEnumType.swift +1 -1
  131. package/ios/Swift/DynamicTypes/DynamicJavaScriptType.swift +27 -0
  132. package/ios/Swift/DynamicTypes/DynamicOptionalType.swift +9 -2
  133. package/ios/Swift/DynamicTypes/DynamicRawType.swift +1 -1
  134. package/ios/Swift/DynamicTypes/DynamicSharedObjectType.swift +16 -2
  135. package/ios/Swift/DynamicTypes/DynamicType.swift +6 -0
  136. package/ios/Swift/DynamicTypes/DynamicTypedArrayType.swift +15 -4
  137. package/ios/Swift/DynamicTypes/DynamicViewType.swift +68 -0
  138. package/ios/Swift/ExpoBridgeModule.swift +1 -1
  139. package/ios/Swift/Functions/AnyFunction.swift +5 -4
  140. package/ios/Swift/Functions/AsyncFunctionComponent.swift +22 -19
  141. package/ios/Swift/Functions/ConcurrentFunctionDefinition.swift +29 -13
  142. package/ios/Swift/Functions/SyncFunctionComponent.swift +26 -15
  143. package/ios/Swift/JavaScriptFunction.swift +68 -0
  144. package/ios/Swift/JavaScriptUtils.swift +57 -18
  145. package/ios/Swift/ModuleHolder.swift +22 -10
  146. package/ios/Swift/Modules/ModuleDefinition.swift +8 -2
  147. package/ios/Swift/Objects/JavaScriptObjectBuilder.swift +8 -8
  148. package/ios/Swift/Objects/ObjectDefinition.swift +17 -15
  149. package/ios/Swift/Objects/PropertyComponent.swift +23 -17
  150. package/ios/Swift/Records/AnyField.swift +1 -1
  151. package/ios/Swift/Records/Field.swift +2 -2
  152. package/ios/Swift/Records/Record.swift +5 -5
  153. package/ios/Swift/SharedObjects/SharedObjectRegistry.swift +4 -0
  154. package/ios/Swift/Views/AnyViewProp.swift +1 -1
  155. package/ios/Swift/Views/ComponentData.swift +37 -2
  156. package/ios/Swift/Views/ConcreteViewProp.swift +2 -2
  157. package/ios/Swift/Views/ViewDefinition.swift +39 -0
  158. package/ios/Swift/Views/ViewModuleWrapper.swift +0 -29
  159. package/ios/Tests/ClassComponentSpec.swift +39 -27
  160. package/ios/Tests/ConvertiblesSpec.swift +75 -49
  161. package/ios/Tests/DynamicTypeSpec.swift +29 -27
  162. package/ios/Tests/EitherSpec.swift +9 -7
  163. package/ios/Tests/ExpoModulesSpec.swift +13 -13
  164. package/ios/Tests/FunctionSpec.swift +38 -22
  165. package/ios/Tests/JavaScriptRuntimeSpec.swift +4 -0
  166. package/ios/Tests/PropertyComponentSpec.swift +33 -30
  167. package/ios/Tests/RecordSpec.swift +7 -5
  168. package/ios/Tests/SharedObjectRegistrySpec.swift +12 -12
  169. package/ios/Tests/TypedArraysSpec.swift +1 -1
  170. package/ios/Tests/ViewDefinitionSpec.swift +4 -2
  171. package/package.json +2 -2
  172. package/src/NativeViewManagerAdapter.native.tsx +33 -29
  173. package/src/requireNativeModule.ts +2 -2
  174. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +0 -132
  175. package/ios/EXViewManager.h +0 -21
  176. package/ios/EXViewManager.m +0 -128
  177. package/ios/ModuleRegistryAdapter/EXViewManagerAdapterClassesRegistry.h +0 -17
  178. package/ios/ModuleRegistryAdapter/EXViewManagerAdapterClassesRegistry.m +0 -67
  179. package/ios/ViewManagerAdapter/EXViewManagerAdapter.h +0 -17
  180. package/ios/ViewManagerAdapter/EXViewManagerAdapter.m +0 -45
@@ -7,6 +7,9 @@ import com.facebook.react.common.MapBuilder
7
7
  import expo.modules.core.utilities.ifNull
8
8
  import expo.modules.kotlin.ModuleHolder
9
9
  import expo.modules.kotlin.events.normalizeEventName
10
+ import expo.modules.kotlin.exception.CodedException
11
+ import expo.modules.kotlin.exception.OnViewDidUpdatePropsException
12
+ import expo.modules.kotlin.exception.exceptionDecorator
10
13
  import expo.modules.kotlin.logger
11
14
  import expo.modules.kotlin.viewevent.ViewEventDelegate
12
15
  import kotlin.reflect.full.declaredMemberProperties
@@ -22,6 +25,9 @@ class ViewManagerWrapperDelegate(internal var moduleHolder: ModuleHolder) {
22
25
  val name: String
23
26
  get() = moduleHolder.name
24
27
 
28
+ val props: Map<String, AnyViewProp>
29
+ get() = definition.props
30
+
25
31
  fun createView(context: Context): View {
26
32
  return definition
27
33
  .createView(context, moduleHolder.module.appContext)
@@ -30,9 +36,40 @@ class ViewManagerWrapperDelegate(internal var moduleHolder: ModuleHolder) {
30
36
  }
31
37
  }
32
38
 
33
- fun setProxiedProperties(view: View, proxiedProperties: ReadableMap) {
34
- definition.setProps(proxiedProperties, view)
35
- definition.onViewDidUpdateProps?.invoke(view)
39
+ fun onViewDidUpdateProps(view: View) {
40
+ definition.onViewDidUpdateProps?.let {
41
+ try {
42
+ exceptionDecorator({ OnViewDidUpdatePropsException(view.javaClass.kotlin, it) }) {
43
+ it.invoke(view)
44
+ }
45
+ } catch (exception: CodedException) {
46
+ logger.error("❌ Error occurred when invoking 'onViewDidUpdateProps' on '${view.javaClass.simpleName}'", exception)
47
+ definition.handleException(view, exception)
48
+ }
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Updates the expo related properties of a given View based on a ReadableMap of property values.
54
+ *
55
+ * @param view The View whose properties should be updated.
56
+ * @param propsMap A ReadableMap of property values.
57
+ *
58
+ * @return A List of property names that were successfully updated.
59
+ */
60
+ fun updateProperties(view: View, propsMap: ReadableMap): List<String> {
61
+ val expoProps = props
62
+ val handledProps = mutableListOf<String>()
63
+ val iterator = propsMap.keySetIterator()
64
+
65
+ while (iterator.hasNextKey()) {
66
+ val key = iterator.nextKey()
67
+ expoProps[key]?.let { expoProp ->
68
+ expoProp.set(propsMap.getDynamic(key), view)
69
+ handledProps.add(key)
70
+ }
71
+ }
72
+ return handledProps
36
73
  }
37
74
 
38
75
  fun onDestroy(view: View) =
@@ -0,0 +1,44 @@
1
+ package expo.modules.kotlin.views
2
+
3
+ import android.view.View
4
+ import expo.modules.kotlin.AppContext
5
+ import expo.modules.kotlin.Utils
6
+ import expo.modules.kotlin.exception.Exceptions
7
+ import expo.modules.kotlin.exception.NullArgumentException
8
+ import expo.modules.kotlin.jni.CppType
9
+ import expo.modules.kotlin.jni.ExpectedType
10
+ import expo.modules.kotlin.toStrongReference
11
+ import expo.modules.kotlin.types.TypeConverter
12
+ import kotlin.reflect.KClass
13
+ import kotlin.reflect.KType
14
+
15
+ class ViewTypeConverter<T : View>(
16
+ val type: KType
17
+ ) : TypeConverter<T>() {
18
+
19
+ override fun convert(value: Any?, context: AppContext?): T? {
20
+ Utils.assertMainThread()
21
+ if (value == null) {
22
+ if (type.isMarkedNullable) {
23
+ return null
24
+ }
25
+ throw NullArgumentException()
26
+ }
27
+
28
+ val appContext = context.toStrongReference()
29
+ val viewTag = value as Int
30
+ val view = appContext.findView<T>(viewTag)
31
+ if (!type.isMarkedNullable && view == null) {
32
+ throw Exceptions.ViewNotFound(type.classifier as KClass<*>, viewTag)
33
+ }
34
+
35
+ return view
36
+ }
37
+
38
+ override fun getCppRequiredTypes(): ExpectedType = ExpectedType(
39
+ CppType.INT,
40
+ CppType.VIEW_TAG
41
+ )
42
+
43
+ override fun isTrivial(): Boolean = false
44
+ }
@@ -0,0 +1,45 @@
1
+ apply plugin: 'java-library'
2
+ apply plugin: 'org.jetbrains.kotlin.jvm'
3
+ apply plugin: 'kotlin'
4
+
5
+ group = 'host.exp.exponent'
6
+ version = '1.1.1'
7
+
8
+ buildscript {
9
+ def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
10
+ if (expoModulesCorePlugin.exists()) {
11
+ apply from: expoModulesCorePlugin
12
+ applyKotlinExpoModulesCorePlugin()
13
+ }
14
+
15
+ // Simple helper that allows the root project to override versions declared by this library.
16
+ ext.safeExtGet = { prop, fallback ->
17
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
18
+ }
19
+
20
+ // Ensures backward compatibility
21
+ ext.getKotlinVersion = {
22
+ if (ext.has("kotlinVersion")) {
23
+ ext.kotlinVersion()
24
+ } else {
25
+ ext.safeExtGet("kotlinVersion", "1.6.10")
26
+ }
27
+ }
28
+
29
+ repositories {
30
+ mavenCentral()
31
+ }
32
+
33
+ dependencies {
34
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getKotlinVersion()}")
35
+ }
36
+ }
37
+
38
+ java {
39
+ sourceCompatibility = JavaVersion.VERSION_1_8
40
+ targetCompatibility = JavaVersion.VERSION_1_8
41
+ }
42
+
43
+ dependencies {
44
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
45
+ }
@@ -0,0 +1,7 @@
1
+ package expo.modules.annotation
2
+
3
+ object Config {
4
+ const val packageNamePrefix = "expo.modules.generated."
5
+ const val classNameSuffix = "_ExpoTypeConverterProvider"
6
+ const val converterProviderFunctionName = "converter"
7
+ }
@@ -0,0 +1,7 @@
1
+ package expo.modules.annotation
2
+
3
+ import kotlin.reflect.KClass
4
+
5
+ @Retention(AnnotationRetention.SOURCE)
6
+ @Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
7
+ annotation class ConverterBinder(val clazz: KClass<*> = Nothing::class)
@@ -0,0 +1,51 @@
1
+ apply plugin: 'java-library'
2
+ apply plugin: 'org.jetbrains.kotlin.jvm'
3
+ apply plugin: 'kotlin'
4
+
5
+ group = 'host.exp.exponent'
6
+ version = '1.1.1'
7
+
8
+ buildscript {
9
+ def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
10
+ if (expoModulesCorePlugin.exists()) {
11
+ apply from: expoModulesCorePlugin
12
+ applyKotlinExpoModulesCorePlugin()
13
+ }
14
+
15
+ // Simple helper that allows the root project to override versions declared by this library.
16
+ ext.safeExtGet = { prop, fallback ->
17
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
18
+ }
19
+
20
+ // Ensures backward compatibility
21
+ ext.getKotlinVersion = {
22
+ if (ext.has("kotlinVersion")) {
23
+ ext.kotlinVersion()
24
+ } else {
25
+ ext.safeExtGet("kotlinVersion", "1.6.10")
26
+ }
27
+ }
28
+
29
+ repositories {
30
+ mavenCentral()
31
+ }
32
+
33
+ dependencies {
34
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getKotlinVersion()}")
35
+ }
36
+ }
37
+
38
+ java {
39
+ sourceCompatibility = JavaVersion.VERSION_1_8
40
+ targetCompatibility = JavaVersion.VERSION_1_8
41
+ }
42
+
43
+ dependencies {
44
+ implementation project(':expo-modules-core$android-annotation')
45
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
46
+
47
+ implementation "com.google.devtools.ksp:symbol-processing-api:${kspVersion()}"
48
+
49
+ implementation 'com.squareup:kotlinpoet:1.12.0'
50
+ implementation 'com.squareup:kotlinpoet-ksp:1.12.0'
51
+ }
@@ -0,0 +1,175 @@
1
+ package expo.modules.annotationprocessor
2
+
3
+ import com.google.devtools.ksp.getVisibility
4
+ import com.google.devtools.ksp.processing.CodeGenerator
5
+ import com.google.devtools.ksp.processing.Dependencies
6
+ import com.google.devtools.ksp.processing.KSPLogger
7
+ import com.google.devtools.ksp.processing.Resolver
8
+ import com.google.devtools.ksp.processing.SymbolProcessor
9
+ import com.google.devtools.ksp.symbol.FunctionKind
10
+ import com.google.devtools.ksp.symbol.KSAnnotated
11
+ import com.google.devtools.ksp.symbol.KSFunctionDeclaration
12
+ import com.google.devtools.ksp.symbol.KSType
13
+ import com.google.devtools.ksp.symbol.KSVisitorVoid
14
+ import com.google.devtools.ksp.symbol.Visibility
15
+ import com.squareup.kotlinpoet.ClassName
16
+ import com.squareup.kotlinpoet.FileSpec
17
+ import com.squareup.kotlinpoet.FunSpec
18
+ import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
19
+ import com.squareup.kotlinpoet.TypeSpec
20
+ import com.squareup.kotlinpoet.ksp.toClassName
21
+ import expo.modules.annotation.Config
22
+ import expo.modules.annotation.ConverterBinder
23
+ import java.io.OutputStreamWriter
24
+ import java.nio.charset.StandardCharsets
25
+
26
+ class ExpoSymbolProcessor(
27
+ private val codeGenerator: CodeGenerator,
28
+ private val logger: KSPLogger,
29
+ ) : SymbolProcessor {
30
+ override fun process(resolver: Resolver): List<KSAnnotated> {
31
+ val symbols = resolver
32
+ .getSymbolsWithAnnotation(ConverterBinder::class.java.name)
33
+ .filterIsInstance<KSFunctionDeclaration>()
34
+
35
+ if (symbols.iterator().hasNext().not()) {
36
+ return emptyList()
37
+ }
38
+
39
+ symbols.forEach { symbol ->
40
+ val clazz = symbol.annotations.find {
41
+ it.shortName.asString() == ConverterBinder::class.java.simpleName
42
+ }!!.arguments[0].value as KSType
43
+
44
+ val parsedClazz = if (clazz.toString() == "Void") {
45
+ null
46
+ } else {
47
+ clazz.toClassName()
48
+ }
49
+
50
+ symbol.accept(ConverterBinderVisitor(parsedClazz, codeGenerator, logger), Unit)
51
+ }
52
+
53
+ return emptyList()
54
+ }
55
+ }
56
+
57
+ class ConverterBinderVisitor(
58
+ private val clazz: ClassName?,
59
+ private val codeGenerator: CodeGenerator,
60
+ private val logger: KSPLogger,
61
+ ) : KSVisitorVoid() {
62
+
63
+ override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
64
+ if (function.functionKind != FunctionKind.TOP_LEVEL ||
65
+ function.getVisibility() != Visibility.PUBLIC
66
+ ) {
67
+ logger.error("ConverterBinder has to be a public top-level function", function)
68
+ return
69
+ }
70
+
71
+ val resolvedType = resolveConverterType(function) ?: return
72
+ val shouldReceiveType = shouldReceiveType(function) ?: return
73
+
74
+ val packageName = "${Config.packageNamePrefix}${resolvedType.packageName}"
75
+ val className = "${resolvedType.simpleName}${Config.classNameSuffix}"
76
+
77
+ val content = generateConverterProvider(
78
+ packageName,
79
+ className,
80
+ function,
81
+ resolvedType,
82
+ shouldReceiveType
83
+ )
84
+
85
+ logger.info("Generating: $packageName.$className")
86
+
87
+ val file = codeGenerator.createNewFile(
88
+ createFileDependencies(function),
89
+ packageName,
90
+ className
91
+ )
92
+ OutputStreamWriter(file, StandardCharsets.UTF_8).use {
93
+ content.writeTo(it)
94
+ }
95
+ }
96
+
97
+ private fun shouldReceiveType(function: KSFunctionDeclaration): Boolean? {
98
+ val argsNumber = function.parameters.size
99
+ if (argsNumber != 0 && argsNumber != 1) {
100
+ logger.error("ConverterBinder cannot receive more then one argument", function)
101
+ return null
102
+ }
103
+
104
+ return function.parameters.firstOrNull()?.type?.toString() == "KType"
105
+ }
106
+
107
+ private fun createFileDependencies(function: KSFunctionDeclaration): Dependencies {
108
+ val containingFile = function.containingFile
109
+ return if (containingFile == null) {
110
+ Dependencies(false)
111
+ } else {
112
+ Dependencies(false, containingFile)
113
+ }
114
+ }
115
+
116
+ private fun resolveConverterType(function: KSFunctionDeclaration): ClassName? {
117
+ if (clazz != null) {
118
+ return clazz
119
+ }
120
+
121
+ val returnType = function.returnType?.resolve()
122
+ if (returnType == null) {
123
+ logger.error("Cannot resolve return type", function)
124
+ return null
125
+ }
126
+
127
+ if (returnType.arguments.size != 1) {
128
+ logger.error("Incorrect return type", function)
129
+ return null
130
+ }
131
+
132
+ val type = returnType.arguments.first().type?.resolve()
133
+ if (type == null) {
134
+ logger.error("Cannot resolve converter inner type", function)
135
+ return null
136
+ }
137
+
138
+ return type.toClassName()
139
+ }
140
+
141
+ private fun generateConverterProvider(
142
+ packageName: String,
143
+ className: String,
144
+ function: KSFunctionDeclaration,
145
+ forType: ClassName,
146
+ receivesType: Boolean
147
+ ): FileSpec {
148
+ val typeConverter = ClassName("expo.modules.kotlin.types", "TypeConverter")
149
+ .parameterizedBy(forType)
150
+ val kType = ClassName("kotlin.reflect", "KType")
151
+
152
+ return FileSpec
153
+ .builder(packageName, className)
154
+ .addType(
155
+ TypeSpec
156
+ .classBuilder(className)
157
+ .addFunction(
158
+ FunSpec
159
+ .builder(Config.converterProviderFunctionName)
160
+ .addParameter("type", kType)
161
+ .returns(typeConverter)
162
+ .apply {
163
+ if (receivesType) {
164
+ addStatement("return ${function.packageName.asString()}.${function.simpleName.asString()}(type)")
165
+ } else {
166
+ addStatement("return ${function.packageName.asString()}.${function.simpleName.asString()}()")
167
+ }
168
+ }
169
+ .build()
170
+ )
171
+ .build()
172
+ )
173
+ .build()
174
+ }
175
+ }
@@ -0,0 +1,10 @@
1
+ package expo.modules.annotationprocessor
2
+
3
+ import com.google.devtools.ksp.processing.SymbolProcessor
4
+ import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
5
+ import com.google.devtools.ksp.processing.SymbolProcessorProvider
6
+
7
+ class ExpoSymbolProcessorProvider : SymbolProcessorProvider {
8
+ override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor =
9
+ ExpoSymbolProcessor(environment.codeGenerator, environment.logger)
10
+ }
@@ -0,0 +1 @@
1
+ expo.modules.annotationprocessor.ExpoSymbolProcessorProvider
@@ -1 +1 @@
1
- {"version":3,"file":"NativeViewManagerAdapter.native.d.ts","sourceRoot":"","sources":["../src/NativeViewManagerAdapter.native.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAqC1B;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CA0BpF"}
1
+ {"version":3,"file":"NativeViewManagerAdapter.native.d.ts","sourceRoot":"","sources":["../src/NativeViewManagerAdapter.native.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAmC1B;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAiDpF"}
@@ -1,5 +1,14 @@
1
1
  import React from 'react';
2
- import { NativeModules, requireNativeComponent } from 'react-native';
2
+ import { findNodeHandle, NativeModules, requireNativeComponent } from 'react-native';
3
+ import { requireNativeModule } from './requireNativeModule';
4
+ // To make the transition from React Native's `requireNativeComponent` to Expo's
5
+ // `requireNativeViewManager` as easy as possible, `requireNativeViewManager` is a drop-in
6
+ // replacement for `requireNativeComponent`.
7
+ //
8
+ // For each view manager, we create a wrapper component that accepts all of the props available to
9
+ // the author of the universal module. This wrapper component splits the props into two sets: props
10
+ // passed to React Native's View (ex: style, testID) and custom view props, which are passed to the
11
+ // adapter view component in a prop called `proxiedProperties`.
3
12
  /**
4
13
  * A map that caches registered native components.
5
14
  */
@@ -32,29 +41,33 @@ export function requireNativeViewManager(viewName) {
32
41
  // manager
33
42
  const reactNativeViewName = `ViewManagerAdapter_${viewName}`;
34
43
  const ReactNativeComponent = requireCachedNativeComponent(reactNativeViewName);
35
- const proxiedPropsNames = viewManagerConfig?.propsNames ?? [];
36
- // Define a component for universal-module authors to access their native view manager
37
- const NativeComponentAdapter = React.forwardRef((props, ref) => {
38
- const nativeProps = omit(props, proxiedPropsNames);
39
- const proxiedProps = pick(props, proxiedPropsNames);
40
- return React.createElement(ReactNativeComponent, { ...nativeProps, proxiedProperties: proxiedProps, ref: ref });
41
- });
42
- NativeComponentAdapter.displayName = `Adapter<${viewName}>`;
43
- return NativeComponentAdapter;
44
- }
45
- function omit(props, propNames) {
46
- const copied = { ...props };
47
- for (const propName of propNames) {
48
- delete copied[propName];
44
+ class NativeComponent extends React.PureComponent {
45
+ static displayName = viewName;
46
+ // This will be accessed from native when the prototype functions are called,
47
+ // in order to find the associated native view.
48
+ nativeTag = null;
49
+ componentDidMount() {
50
+ this.nativeTag = findNodeHandle(this);
51
+ }
52
+ render() {
53
+ return React.createElement(ReactNativeComponent, { ...this.props });
54
+ }
49
55
  }
50
- return copied;
51
- }
52
- function pick(props, propNames) {
53
- return propNames.reduce((prev, curr) => {
54
- if (curr in props) {
55
- prev[curr] = props[curr];
56
+ try {
57
+ const nativeModule = requireNativeModule(viewName);
58
+ const nativeViewPrototype = nativeModule.ViewPrototype;
59
+ if (nativeViewPrototype) {
60
+ // Assign native view functions to the component prototype so they can be accessed from the ref.
61
+ Object.assign(NativeComponent.prototype, nativeViewPrototype);
56
62
  }
57
- return prev;
58
- }, {});
63
+ }
64
+ catch {
65
+ // `requireNativeModule` may throw an error when the native module cannot be found.
66
+ // In some tests we don't mock the entire modules, but we do want to mock native views. For now,
67
+ // until we still have to support the legacy modules proxy and don't have better ways to mock,
68
+ // let's just gracefully skip assigning the prototype functions.
69
+ // See: https://github.com/expo/expo/blob/main/packages/expo-modules-core/src/__tests__/NativeViewManagerAdapter-test.native.tsx
70
+ }
71
+ return NativeComponent;
59
72
  }
60
73
  //# sourceMappingURL=NativeViewManagerAdapter.native.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"NativeViewManagerAdapter.native.js","sourceRoot":"","sources":["../src/NativeViewManagerAdapter.native.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAiB,MAAM,cAAc,CAAC;AAepF;;GAEG;AACH,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAA8B,CAAC;AAEpE;;;;GAIG;AACH,SAAS,4BAA4B,CAAQ,QAAgB;IAC3D,MAAM,qBAAqB,GAAG,qBAAqB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAElE,IAAI,CAAC,qBAAqB,EAAE;QAC1B,MAAM,eAAe,GAAG,sBAAsB,CAAQ,QAAQ,CAAC,CAAC;QAChE,qBAAqB,CAAC,GAAG,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;QACrD,OAAO,eAAe,CAAC;KACxB;IACD,OAAO,qBAAqB,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAI,QAAgB;IAC1D,MAAM,EAAE,oBAAoB,EAAE,GAAG,aAAa,CAAC,oBAAoB,CAAC;IACpE,MAAM,iBAAiB,GAAG,oBAAoB,EAAE,CAAC,QAAQ,CAAC,CAAC;IAE3D,IAAI,OAAO,IAAI,CAAC,iBAAiB,EAAE;QACjC,MAAM,wBAAwB,GAAG,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9E,OAAO,CAAC,IAAI,CACV,6CAA6C,QAAQ,8IAA8I,wBAAwB,IAAI,CAChO,CAAC;KACH;IAED,+FAA+F;IAC/F,UAAU;IACV,MAAM,mBAAmB,GAAG,sBAAsB,QAAQ,EAAE,CAAC;IAC7D,MAAM,oBAAoB,GACxB,4BAA4B,CAA2B,mBAAmB,CAAC,CAAC;IAC9E,MAAM,iBAAiB,GAAG,iBAAiB,EAAE,UAAU,IAAI,EAAE,CAAC;IAE9D,sFAAsF;IACtF,MAAM,sBAAsB,GAAG,KAAK,CAAC,UAAU,CAAM,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAClE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC;QACnD,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC;QACpD,OAAO,oBAAC,oBAAoB,OAAK,WAAW,EAAE,iBAAiB,EAAE,YAAY,EAAE,GAAG,EAAE,GAAG,GAAI,CAAC;IAC9F,CAAC,CAA2B,CAAC;IAC7B,sBAAsB,CAAC,WAAW,GAAG,WAAW,QAAQ,GAAG,CAAC;IAC5D,OAAO,sBAAsB,CAAC;AAChC,CAAC;AAED,SAAS,IAAI,CAAC,KAA0B,EAAE,SAAmB;IAC3D,MAAM,MAAM,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;IAC5B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;QAChC,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC;KACzB;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,IAAI,CAAC,KAA0B,EAAE,SAAmB;IAC3D,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE;QACrC,IAAI,IAAI,IAAI,KAAK,EAAE;YACjB,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;SAC1B;QACD,OAAO,IAAI,CAAC;IACd,CAAC,EAAE,EAAE,CAAC,CAAC;AACT,CAAC","sourcesContent":["import React from 'react';\nimport { NativeModules, requireNativeComponent, HostComponent } from 'react-native';\n\n// To make the transition from React Native's `requireNativeComponent` to Expo's\n// `requireNativeViewManager` as easy as possible, `requireNativeViewManager` is a drop-in\n// replacement for `requireNativeComponent`.\n//\n// For each view manager, we create a wrapper component that accepts all of the props available to\n// the author of the universal module. This wrapper component splits the props into two sets: props\n// passed to React Native's View (ex: style, testID) and custom view props, which are passed to the\n// adapter view component in a prop called `proxiedProperties`.\n\ntype NativeExpoComponentProps = {\n proxiedProperties: object;\n};\n\n/**\n * A map that caches registered native components.\n */\nconst nativeComponentsCache = new Map<string, HostComponent<any>>();\n\n/**\n * Requires a React Native component from cache if possible. This prevents\n * \"Tried to register two views with the same name\" errors on fast refresh, but\n * also when there are multiple versions of the same package with native component.\n */\nfunction requireCachedNativeComponent<Props>(viewName: string): HostComponent<Props> {\n const cachedNativeComponent = nativeComponentsCache.get(viewName);\n\n if (!cachedNativeComponent) {\n const nativeComponent = requireNativeComponent<Props>(viewName);\n nativeComponentsCache.set(viewName, nativeComponent);\n return nativeComponent;\n }\n return cachedNativeComponent;\n}\n\n/**\n * A drop-in replacement for `requireNativeComponent`.\n */\nexport function requireNativeViewManager<P>(viewName: string): React.ComponentType<P> {\n const { viewManagersMetadata } = NativeModules.NativeUnimoduleProxy;\n const viewManagerConfig = viewManagersMetadata?.[viewName];\n\n if (__DEV__ && !viewManagerConfig) {\n const exportedViewManagerNames = Object.keys(viewManagersMetadata).join(', ');\n console.warn(\n `The native view manager required by name (${viewName}) from NativeViewManagerAdapter isn't exported by expo-modules-core. Views of this type may not render correctly. Exported view managers: [${exportedViewManagerNames}].`\n );\n }\n\n // Set up the React Native native component, which is an adapter to the universal module's view\n // manager\n const reactNativeViewName = `ViewManagerAdapter_${viewName}`;\n const ReactNativeComponent =\n requireCachedNativeComponent<NativeExpoComponentProps>(reactNativeViewName);\n const proxiedPropsNames = viewManagerConfig?.propsNames ?? [];\n\n // Define a component for universal-module authors to access their native view manager\n const NativeComponentAdapter = React.forwardRef<any>((props, ref) => {\n const nativeProps = omit(props, proxiedPropsNames);\n const proxiedProps = pick(props, proxiedPropsNames);\n return <ReactNativeComponent {...nativeProps} proxiedProperties={proxiedProps} ref={ref} />;\n }) as React.ComponentType<P>;\n NativeComponentAdapter.displayName = `Adapter<${viewName}>`;\n return NativeComponentAdapter;\n}\n\nfunction omit(props: Record<string, any>, propNames: string[]) {\n const copied = { ...props };\n for (const propName of propNames) {\n delete copied[propName];\n }\n return copied;\n}\n\nfunction pick(props: Record<string, any>, propNames: string[]) {\n return propNames.reduce((prev, curr) => {\n if (curr in props) {\n prev[curr] = props[curr];\n }\n return prev;\n }, {});\n}\n"]}
1
+ {"version":3,"file":"NativeViewManagerAdapter.native.js","sourceRoot":"","sources":["../src/NativeViewManagerAdapter.native.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,sBAAsB,EAAiB,MAAM,cAAc,CAAC;AAEpG,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,gFAAgF;AAChF,0FAA0F;AAC1F,4CAA4C;AAC5C,EAAE;AACF,kGAAkG;AAClG,mGAAmG;AACnG,mGAAmG;AACnG,+DAA+D;AAE/D;;GAEG;AACH,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAA8B,CAAC;AAEpE;;;;GAIG;AACH,SAAS,4BAA4B,CAAQ,QAAgB;IAC3D,MAAM,qBAAqB,GAAG,qBAAqB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAElE,IAAI,CAAC,qBAAqB,EAAE;QAC1B,MAAM,eAAe,GAAG,sBAAsB,CAAQ,QAAQ,CAAC,CAAC;QAChE,qBAAqB,CAAC,GAAG,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;QACrD,OAAO,eAAe,CAAC;KACxB;IACD,OAAO,qBAAqB,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAI,QAAgB;IAC1D,MAAM,EAAE,oBAAoB,EAAE,GAAG,aAAa,CAAC,oBAAoB,CAAC;IACpE,MAAM,iBAAiB,GAAG,oBAAoB,EAAE,CAAC,QAAQ,CAAC,CAAC;IAE3D,IAAI,OAAO,IAAI,CAAC,iBAAiB,EAAE;QACjC,MAAM,wBAAwB,GAAG,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9E,OAAO,CAAC,IAAI,CACV,6CAA6C,QAAQ,8IAA8I,wBAAwB,IAAI,CAChO,CAAC;KACH;IAED,+FAA+F;IAC/F,UAAU;IACV,MAAM,mBAAmB,GAAG,sBAAsB,QAAQ,EAAE,CAAC;IAC7D,MAAM,oBAAoB,GAAG,4BAA4B,CAAC,mBAAmB,CAAC,CAAC;IAE/E,MAAM,eAAgB,SAAQ,KAAK,CAAC,aAAgB;QAClD,MAAM,CAAC,WAAW,GAAG,QAAQ,CAAC;QAE9B,6EAA6E;QAC7E,+CAA+C;QAC/C,SAAS,GAAkB,IAAI,CAAC;QAEhC,iBAAiB;YACf,IAAI,CAAC,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACxC,CAAC;QAED,MAAM;YACJ,OAAO,oBAAC,oBAAoB,OAAK,IAAI,CAAC,KAAK,GAAI,CAAC;QAClD,CAAC;;IAGH,IAAI;QACF,MAAM,YAAY,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,mBAAmB,GAAG,YAAY,CAAC,aAAa,CAAC;QAEvD,IAAI,mBAAmB,EAAE;YACvB,gGAAgG;YAChG,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;SAC/D;KACF;IAAC,MAAM;QACN,mFAAmF;QACnF,gGAAgG;QAChG,8FAA8F;QAC9F,gEAAgE;QAChE,gIAAgI;KACjI;IAED,OAAO,eAAe,CAAC;AACzB,CAAC","sourcesContent":["import React from 'react';\nimport { findNodeHandle, NativeModules, requireNativeComponent, HostComponent } from 'react-native';\n\nimport { requireNativeModule } from './requireNativeModule';\n\n// To make the transition from React Native's `requireNativeComponent` to Expo's\n// `requireNativeViewManager` as easy as possible, `requireNativeViewManager` is a drop-in\n// replacement for `requireNativeComponent`.\n//\n// For each view manager, we create a wrapper component that accepts all of the props available to\n// the author of the universal module. This wrapper component splits the props into two sets: props\n// passed to React Native's View (ex: style, testID) and custom view props, which are passed to the\n// adapter view component in a prop called `proxiedProperties`.\n\n/**\n * A map that caches registered native components.\n */\nconst nativeComponentsCache = new Map<string, HostComponent<any>>();\n\n/**\n * Requires a React Native component from cache if possible. This prevents\n * \"Tried to register two views with the same name\" errors on fast refresh, but\n * also when there are multiple versions of the same package with native component.\n */\nfunction requireCachedNativeComponent<Props>(viewName: string): HostComponent<Props> {\n const cachedNativeComponent = nativeComponentsCache.get(viewName);\n\n if (!cachedNativeComponent) {\n const nativeComponent = requireNativeComponent<Props>(viewName);\n nativeComponentsCache.set(viewName, nativeComponent);\n return nativeComponent;\n }\n return cachedNativeComponent;\n}\n\n/**\n * A drop-in replacement for `requireNativeComponent`.\n */\nexport function requireNativeViewManager<P>(viewName: string): React.ComponentType<P> {\n const { viewManagersMetadata } = NativeModules.NativeUnimoduleProxy;\n const viewManagerConfig = viewManagersMetadata?.[viewName];\n\n if (__DEV__ && !viewManagerConfig) {\n const exportedViewManagerNames = Object.keys(viewManagersMetadata).join(', ');\n console.warn(\n `The native view manager required by name (${viewName}) from NativeViewManagerAdapter isn't exported by expo-modules-core. Views of this type may not render correctly. Exported view managers: [${exportedViewManagerNames}].`\n );\n }\n\n // Set up the React Native native component, which is an adapter to the universal module's view\n // manager\n const reactNativeViewName = `ViewManagerAdapter_${viewName}`;\n const ReactNativeComponent = requireCachedNativeComponent(reactNativeViewName);\n\n class NativeComponent extends React.PureComponent<P> {\n static displayName = viewName;\n\n // This will be accessed from native when the prototype functions are called,\n // in order to find the associated native view.\n nativeTag: number | null = null;\n\n componentDidMount(): void {\n this.nativeTag = findNodeHandle(this);\n }\n\n render(): React.ReactNode {\n return <ReactNativeComponent {...this.props} />;\n }\n }\n\n try {\n const nativeModule = requireNativeModule(viewName);\n const nativeViewPrototype = nativeModule.ViewPrototype;\n\n if (nativeViewPrototype) {\n // Assign native view functions to the component prototype so they can be accessed from the ref.\n Object.assign(NativeComponent.prototype, nativeViewPrototype);\n }\n } catch {\n // `requireNativeModule` may throw an error when the native module cannot be found.\n // In some tests we don't mock the entire modules, but we do want to mock native views. For now,\n // until we still have to support the legacy modules proxy and don't have better ways to mock,\n // let's just gracefully skip assigning the prototype functions.\n // See: https://github.com/expo/expo/blob/main/packages/expo-modules-core/src/__tests__/NativeViewManagerAdapter-test.native.tsx\n }\n\n return NativeComponent;\n}\n"]}
@@ -9,8 +9,8 @@ import NativeModulesProxy from './NativeModulesProxy';
9
9
  * @throws Error when there is no native module with given name.
10
10
  */
11
11
  export function requireNativeModule(moduleName) {
12
- const nativeModule = global.expo?.modules?.[moduleName] ??
13
- global.ExpoModules?.[moduleName] ??
12
+ const nativeModule = globalThis.expo?.modules?.[moduleName] ??
13
+ globalThis.ExpoModules?.[moduleName] ??
14
14
  NativeModulesProxy[moduleName];
15
15
  if (!nativeModule) {
16
16
  throw new Error(`Cannot find native module '${moduleName}'`);
@@ -1 +1 @@
1
- {"version":3,"file":"requireNativeModule.js","sourceRoot":"","sources":["../src/requireNativeModule.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,MAAM,sBAAsB,CAAC;AAyBtD;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAmB,UAAkB;IACtE,MAAM,YAAY,GAChB,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,UAAU,CAAC;QAClC,MAAM,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC;QAChC,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAEjC,IAAI,CAAC,YAAY,EAAE;QACjB,MAAM,IAAI,KAAK,CAAC,8BAA8B,UAAU,GAAG,CAAC,CAAC;KAC9D;IACD,OAAO,YAAY,CAAC;AACtB,CAAC","sourcesContent":["import NativeModulesProxy from './NativeModulesProxy';\n\ntype ExpoObject = {\n modules:\n | undefined\n | {\n [key: string]: any;\n };\n};\n\ndeclare global {\n // eslint-disable-next-line no-var\n var expo: ExpoObject | undefined;\n\n /**\n * @deprecated `global.ExpoModules` is deprecated, use `global.expo.modules` instead.\n */\n // eslint-disable-next-line no-var\n var ExpoModules:\n | undefined\n | {\n [key: string]: any;\n };\n}\n\n/**\n * Imports the native module registered with given name. In the first place it tries to load\n * the module installed through the JSI host object and then falls back to the bridge proxy module.\n * Notice that the modules loaded from the proxy may not support some features like synchronous functions.\n *\n * @param moduleName Name of the requested native module.\n * @returns Object representing the native module.\n * @throws Error when there is no native module with given name.\n */\nexport function requireNativeModule<ModuleType = any>(moduleName: string): ModuleType {\n const nativeModule: ModuleType =\n global.expo?.modules?.[moduleName] ??\n global.ExpoModules?.[moduleName] ??\n NativeModulesProxy[moduleName];\n\n if (!nativeModule) {\n throw new Error(`Cannot find native module '${moduleName}'`);\n }\n return nativeModule;\n}\n"]}
1
+ {"version":3,"file":"requireNativeModule.js","sourceRoot":"","sources":["../src/requireNativeModule.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,MAAM,sBAAsB,CAAC;AAyBtD;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAmB,UAAkB;IACtE,MAAM,YAAY,GAChB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,UAAU,CAAC;QACtC,UAAU,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC;QACpC,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAEjC,IAAI,CAAC,YAAY,EAAE;QACjB,MAAM,IAAI,KAAK,CAAC,8BAA8B,UAAU,GAAG,CAAC,CAAC;KAC9D;IACD,OAAO,YAAY,CAAC;AACtB,CAAC","sourcesContent":["import NativeModulesProxy from './NativeModulesProxy';\n\ntype ExpoObject = {\n modules:\n | undefined\n | {\n [key: string]: any;\n };\n};\n\ndeclare global {\n // eslint-disable-next-line no-var\n var expo: ExpoObject | undefined;\n\n /**\n * @deprecated `global.ExpoModules` is deprecated, use `global.expo.modules` instead.\n */\n // eslint-disable-next-line no-var\n var ExpoModules:\n | undefined\n | {\n [key: string]: any;\n };\n}\n\n/**\n * Imports the native module registered with given name. In the first place it tries to load\n * the module installed through the JSI host object and then falls back to the bridge proxy module.\n * Notice that the modules loaded from the proxy may not support some features like synchronous functions.\n *\n * @param moduleName Name of the requested native module.\n * @returns Object representing the native module.\n * @throws Error when there is no native module with given name.\n */\nexport function requireNativeModule<ModuleType = any>(moduleName: string): ModuleType {\n const nativeModule: ModuleType =\n globalThis.expo?.modules?.[moduleName] ??\n globalThis.ExpoModules?.[moduleName] ??\n NativeModulesProxy[moduleName];\n\n if (!nativeModule) {\n throw new Error(`Cannot find native module '${moduleName}'`);\n }\n return nativeModule;\n}\n"]}
@@ -7,12 +7,27 @@ namespace react = facebook::react;
7
7
 
8
8
  namespace expo {
9
9
 
10
+ /**
11
+ Borrows the props map from the source props and applies the update given in the raw props.
12
+ */
13
+ std::unordered_map<std::string, folly::dynamic> propsMapFromProps(const ExpoViewProps &sourceProps, const react::RawProps &rawProps) {
14
+ // Move the contents of the source props map – the source props instance will not be used anymore.
15
+ std::unordered_map<std::string, folly::dynamic> propsMap = std::move(sourceProps.propsMap);
16
+
17
+ // Iterate over values in the raw props object.
18
+ // Note that it contains only updated props.
19
+ rawProps.iterateOverValues([&propsMap](react::RawPropsPropNameHash hash, const char *name, const react::RawValue &value) {
20
+ std::string propName(name);
21
+ propsMap[propName] = (folly::dynamic)value;
22
+ });
23
+
24
+ return propsMap;
25
+ }
26
+
10
27
  ExpoViewProps::ExpoViewProps(const react::PropsParserContext &context,
11
28
  const ExpoViewProps &sourceProps,
12
29
  const react::RawProps &rawProps)
13
30
  : ViewProps(context, sourceProps, rawProps),
14
- proxiedProperties(
15
- facebook::react::convertRawProp(context, rawProps, "proxiedProperties", sourceProps.proxiedProperties, {})) {
16
- }
31
+ propsMap(propsMapFromProps(sourceProps, rawProps)) {}
17
32
 
18
33
  } // namespace expo
@@ -19,7 +19,10 @@ public:
19
19
 
20
20
  #pragma mark - Props
21
21
 
22
- const folly::dynamic proxiedProperties;
22
+ /**
23
+ A map with props stored as `folly::dynamic` objects.
24
+ */
25
+ std::unordered_map<std::string, folly::dynamic> propsMap;
23
26
  };
24
27
 
25
28
  } // namespace expo
@@ -21,13 +21,6 @@ public class ExpoFabricView: ExpoFabricViewObjC {
21
21
  return appContext?.moduleRegistry.get(moduleHolderForName: moduleName)
22
22
  }
23
23
 
24
- /**
25
- The view manager of the associated legacy module.
26
- Not available if the module is registered in the new module registry.
27
- */
28
- lazy var legacyViewManager = appContext?.legacyModuleRegistry?.getAllViewManagers()
29
- .filter { $0.viewName() == moduleName }
30
- .first
31
24
 
32
25
  /**
33
26
  A dictionary of prop objects that contain prop setters.
@@ -52,7 +45,7 @@ public class ExpoFabricView: ExpoFabricViewObjC {
52
45
  // MARK: - ExpoFabricViewInterface
53
46
 
54
47
  public override func updateProps(_ props: [String: Any]) {
55
- guard let view = contentView, let propsDict = viewManagerPropDict else {
48
+ guard let view = contentView, let context = appContext, let propsDict = viewManagerPropDict else {
56
49
  return
57
50
  }
58
51
  for (key, prop) in propsDict {
@@ -61,7 +54,7 @@ public class ExpoFabricView: ExpoFabricViewObjC {
61
54
  // TODO: @tsapeta: Figure out better way to rethrow errors from here.
62
55
  // Adding `throws` keyword to the function results in different
63
56
  // method signature in Objective-C. Maybe just call `RCTLogError`?
64
- try? prop.set(value: Conversions.fromNSObject(newValue), onView: view)
57
+ try? prop.set(value: Conversions.fromNSObject(newValue), onView: view, appContext: context)
65
58
  }
66
59
  }
67
60
 
@@ -75,6 +68,13 @@ public class ExpoFabricView: ExpoFabricViewObjC {
75
68
  viewManager.callLifecycleMethods(withType: .didUpdateProps, forView: view)
76
69
  }
77
70
 
71
+ /**
72
+ Returns a bool value whether the view supports prop with the given name.
73
+ */
74
+ public override func supportsProp(withName name: String) -> Bool {
75
+ return viewManagerPropDict?.index(forKey: name) != nil
76
+ }
77
+
78
78
  /**
79
79
  The function that is called by Fabric when the view is unmounted and is being enqueued for recycling.
80
80
  It can also be called on app reload, so be careful to wipe out any dependencies specific to the currently running AppContext.
@@ -110,7 +110,7 @@ public class ExpoFabricView: ExpoFabricViewObjC {
110
110
  guard let appContext = appContext else {
111
111
  fatalError(Exceptions.AppContextLost().reason)
112
112
  }
113
- guard let view = moduleHolder?.definition.viewManager?.createView(appContext: appContext) ?? legacyViewManager?.view() else {
113
+ guard let view = moduleHolder?.definition.viewManager?.createView(appContext: appContext) else {
114
114
  fatalError("Cannot create a view from module '\(moduleName)'")
115
115
  }
116
116
  // Setting the content view automatically adds the view as a subview.
@@ -37,6 +37,8 @@
37
37
 
38
38
  - (void)viewDidUpdateProps;
39
39
 
40
+ - (BOOL)supportsPropWithName:(nonnull NSString *)name;
41
+
40
42
  - (void)prepareForRecycle;
41
43
 
42
44
  #pragma mark - Methods injected to the class in runtime