expo-modules-core 0.9.2 → 0.11.1

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 (193) hide show
  1. package/CHANGELOG.md +33 -3
  2. package/README.md +3 -3
  3. package/android/CMakeLists.txt +163 -0
  4. package/android/build.gradle +343 -5
  5. package/android/src/main/cpp/CachedReferencesRegistry.cpp +65 -0
  6. package/android/src/main/cpp/CachedReferencesRegistry.h +80 -0
  7. package/android/src/main/cpp/Exceptions.cpp +22 -0
  8. package/android/src/main/cpp/Exceptions.h +38 -0
  9. package/android/src/main/cpp/ExpoModulesHostObject.cpp +47 -0
  10. package/android/src/main/cpp/ExpoModulesHostObject.h +32 -0
  11. package/android/src/main/cpp/JNIFunctionBody.cpp +44 -0
  12. package/android/src/main/cpp/JNIFunctionBody.h +50 -0
  13. package/android/src/main/cpp/JNIInjector.cpp +23 -0
  14. package/android/src/main/cpp/JSIInteropModuleRegistry.cpp +122 -0
  15. package/android/src/main/cpp/JSIInteropModuleRegistry.h +96 -0
  16. package/android/src/main/cpp/JSIObjectWrapper.h +33 -0
  17. package/android/src/main/cpp/JSITypeConverter.h +84 -0
  18. package/android/src/main/cpp/JavaScriptModuleObject.cpp +219 -0
  19. package/android/src/main/cpp/JavaScriptModuleObject.h +144 -0
  20. package/android/src/main/cpp/JavaScriptObject.cpp +125 -0
  21. package/android/src/main/cpp/JavaScriptObject.h +131 -0
  22. package/android/src/main/cpp/JavaScriptRuntime.cpp +127 -0
  23. package/android/src/main/cpp/JavaScriptRuntime.h +87 -0
  24. package/android/src/main/cpp/JavaScriptValue.cpp +172 -0
  25. package/android/src/main/cpp/JavaScriptValue.h +78 -0
  26. package/android/src/main/cpp/MethodMetadata.cpp +340 -0
  27. package/android/src/main/cpp/MethodMetadata.h +131 -0
  28. package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +2 -0
  29. package/android/src/main/java/expo/modules/core/errors/ContextDestroyedException.kt +7 -0
  30. package/android/src/main/java/expo/modules/interfaces/permissions/Permissions.java +30 -0
  31. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +98 -3
  32. package/android/src/main/java/expo/modules/kotlin/ConcatIterator.kt +18 -0
  33. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +15 -12
  34. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +45 -3
  35. package/android/src/main/java/expo/modules/kotlin/activityaware/AppCompatActivityAware.kt +49 -0
  36. package/android/src/main/java/expo/modules/kotlin/activityaware/AppCompatActivityAwareHelper.kt +43 -0
  37. package/android/src/main/java/expo/modules/kotlin/activityaware/OnActivityAvailableListener.kt +18 -0
  38. package/android/src/main/java/expo/modules/kotlin/activityresult/ActivityResultsManager.kt +99 -0
  39. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultCaller.kt +25 -0
  40. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultContract.kt +27 -0
  41. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultFallbackCallback.kt +17 -0
  42. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultLauncher.kt +30 -0
  43. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultRegistry.kt +358 -0
  44. package/android/src/main/java/expo/modules/kotlin/activityresult/DataPersistor.kt +135 -0
  45. package/android/src/main/java/expo/modules/kotlin/defaultmodules/ErrorManagerModule.kt +2 -2
  46. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +13 -0
  47. package/android/src/main/java/expo/modules/kotlin/exception/ExceptionDecorator.kt +2 -0
  48. package/android/src/main/java/expo/modules/kotlin/functions/AnyFunction.kt +53 -15
  49. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +35 -7
  50. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +13 -121
  51. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +21 -0
  52. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +21 -0
  53. package/android/src/main/java/expo/modules/kotlin/functions/SuspendFunctionComponent.kt +63 -0
  54. package/android/src/main/java/expo/modules/kotlin/functions/SyncFunctionComponent.kt +36 -0
  55. package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +19 -0
  56. package/android/src/main/java/expo/modules/kotlin/jni/JNIFunctionBody.kt +39 -0
  57. package/android/src/main/java/expo/modules/kotlin/jni/JSIInteropModuleRegistry.kt +89 -0
  58. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptModuleObject.kt +46 -0
  59. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptObject.kt +113 -0
  60. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +35 -0
  61. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +16 -6
  62. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +5 -500
  63. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +30 -5
  64. package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +271 -0
  65. package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionData.kt +21 -0
  66. package/android/src/main/java/expo/modules/kotlin/objects/PropertyComponent.kt +54 -0
  67. package/android/src/main/java/expo/modules/kotlin/objects/PropertyComponentBuilder.kt +32 -0
  68. package/android/src/main/java/expo/modules/kotlin/providers/AppContextProvider.kt +14 -0
  69. package/android/src/main/java/expo/modules/kotlin/providers/CurrentActivityProvider.kt +22 -0
  70. package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +19 -2
  71. package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +3 -2
  72. package/android/src/main/java/expo/modules/kotlin/types/AnyTypeConverter.kt +36 -0
  73. package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +7 -2
  74. package/android/src/main/java/expo/modules/kotlin/types/BasicTypeConverters.kt +68 -20
  75. package/android/src/main/java/expo/modules/kotlin/types/EnumTypeConverter.kt +50 -22
  76. package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +18 -2
  77. package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +18 -2
  78. package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +17 -2
  79. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +43 -3
  80. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +12 -0
  81. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +0 -41
  82. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +0 -33
  83. package/build/NativeModulesProxy.native.d.ts.map +1 -1
  84. package/build/NativeModulesProxy.native.js +9 -3
  85. package/build/NativeModulesProxy.native.js.map +1 -1
  86. package/build/PermissionsInterface.d.ts +29 -0
  87. package/build/PermissionsInterface.d.ts.map +1 -1
  88. package/build/PermissionsInterface.js +9 -0
  89. package/build/PermissionsInterface.js.map +1 -1
  90. package/ios/AppDelegates/EXAppDelegatesLoader.m +1 -2
  91. package/ios/ExpoModulesCore.podspec +3 -2
  92. package/ios/JSI/EXJSIConversions.mm +6 -0
  93. package/ios/JSI/EXJSIInstaller.h +15 -21
  94. package/ios/JSI/EXJSIInstaller.mm +39 -3
  95. package/ios/JSI/EXJSIUtils.h +48 -3
  96. package/ios/JSI/EXJSIUtils.mm +88 -4
  97. package/ios/JSI/EXJavaScriptObject.h +11 -18
  98. package/ios/JSI/EXJavaScriptObject.mm +37 -18
  99. package/ios/JSI/EXJavaScriptRuntime.h +43 -9
  100. package/ios/JSI/EXJavaScriptRuntime.mm +70 -27
  101. package/ios/JSI/EXJavaScriptTypedArray.h +30 -0
  102. package/ios/JSI/EXJavaScriptTypedArray.mm +29 -0
  103. package/ios/JSI/EXJavaScriptValue.h +3 -2
  104. package/ios/JSI/EXJavaScriptValue.mm +17 -20
  105. package/ios/JSI/EXJavaScriptWeakObject.h +23 -0
  106. package/ios/JSI/EXJavaScriptWeakObject.mm +53 -0
  107. package/ios/JSI/EXObjectDeallocator.h +27 -0
  108. package/ios/JSI/ExpoModulesHostObject.h +3 -3
  109. package/ios/JSI/ExpoModulesHostObject.mm +4 -4
  110. package/ios/JSI/JavaScriptRuntime.swift +38 -1
  111. package/ios/JSI/JavaScriptValue.swift +7 -0
  112. package/ios/JSI/TypedArray.cpp +67 -0
  113. package/ios/JSI/TypedArray.h +46 -0
  114. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +0 -11
  115. package/ios/NativeModulesProxy/EXNativeModulesProxy.h +17 -10
  116. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +86 -77
  117. package/ios/NativeModulesProxy/NativeModulesProxyModule.swift +17 -0
  118. package/ios/Services/EXReactNativeEventEmitter.h +2 -2
  119. package/ios/Services/EXReactNativeEventEmitter.m +11 -6
  120. package/ios/Swift/AppContext.swift +206 -28
  121. package/ios/Swift/Arguments/AnyArgument.swift +18 -0
  122. package/ios/Swift/Arguments/{Types/EnumArgumentType.swift → EnumArgument.swift} +2 -17
  123. package/ios/Swift/Classes/ClassComponent.swift +95 -0
  124. package/ios/Swift/Classes/ClassComponentElement.swift +33 -0
  125. package/ios/Swift/Classes/ClassComponentElementsBuilder.swift +34 -0
  126. package/ios/Swift/Classes/ClassComponentFactories.swift +96 -0
  127. package/ios/Swift/DynamicTypes/AnyDynamicType.swift +44 -0
  128. package/ios/Swift/DynamicTypes/DynamicArrayType.swift +56 -0
  129. package/ios/Swift/DynamicTypes/DynamicConvertibleType.swift +27 -0
  130. package/ios/Swift/DynamicTypes/DynamicEnumType.swift +27 -0
  131. package/ios/Swift/DynamicTypes/DynamicOptionalType.swift +63 -0
  132. package/ios/Swift/DynamicTypes/DynamicRawType.swift +33 -0
  133. package/ios/Swift/DynamicTypes/DynamicSharedObjectType.swift +37 -0
  134. package/ios/Swift/DynamicTypes/DynamicType.swift +39 -0
  135. package/ios/Swift/DynamicTypes/DynamicTypedArrayType.swift +46 -0
  136. package/ios/Swift/Exceptions/ChainableException.swift +3 -3
  137. package/ios/Swift/Exceptions/CodedError.swift +1 -1
  138. package/ios/Swift/Exceptions/Exception.swift +8 -6
  139. package/ios/Swift/Exceptions/UnexpectedException.swift +2 -1
  140. package/ios/Swift/ExpoBridgeModule.m +5 -0
  141. package/ios/Swift/ExpoBridgeModule.swift +79 -0
  142. package/ios/Swift/Functions/AnyFunction.swift +33 -31
  143. package/ios/Swift/Functions/AsyncFunctionComponent.swift +196 -59
  144. package/ios/Swift/Functions/SyncFunctionComponent.swift +142 -58
  145. package/ios/Swift/JavaScriptUtils.swift +32 -57
  146. package/ios/Swift/Logging/LogHandlers.swift +39 -0
  147. package/ios/Swift/Logging/LogType.swift +62 -0
  148. package/ios/Swift/Logging/Logger.swift +201 -0
  149. package/ios/Swift/ModuleHolder.swift +19 -54
  150. package/ios/Swift/ModuleRegistry.swift +7 -1
  151. package/ios/Swift/Modules/AnyModule.swift +3 -3
  152. package/ios/Swift/ModulesProvider.swift +2 -0
  153. package/ios/Swift/Objects/JavaScriptObjectBuilder.swift +37 -0
  154. package/ios/Swift/Objects/ObjectDefinition.swift +74 -1
  155. package/ios/Swift/Objects/ObjectDefinitionComponents.swift +77 -68
  156. package/ios/Swift/Objects/PropertyComponent.swift +147 -0
  157. package/ios/Swift/Promise.swift +17 -4
  158. package/ios/Swift/Records/Field.swift +2 -2
  159. package/ios/Swift/SharedObjects/SharedObject.swift +20 -0
  160. package/ios/Swift/SharedObjects/SharedObjectRegistry.swift +129 -0
  161. package/ios/Swift/TypedArrays/AnyTypedArray.swift +11 -0
  162. package/ios/Swift/TypedArrays/ConcreteTypedArrays.swift +56 -0
  163. package/ios/Swift/TypedArrays/GenericTypedArray.swift +49 -0
  164. package/ios/Swift/TypedArrays/TypedArray.swift +80 -0
  165. package/ios/Swift/Utilities.swift +28 -0
  166. package/ios/Swift/Views/ConcreteViewProp.swift +3 -3
  167. package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +2 -2
  168. package/ios/Tests/ClassComponentSpec.swift +210 -0
  169. package/ios/Tests/DynamicTypeSpec.swift +336 -0
  170. package/ios/Tests/EnumArgumentSpec.swift +48 -0
  171. package/ios/Tests/ExpoModulesSpec.swift +17 -3
  172. package/ios/Tests/FunctionSpec.swift +167 -118
  173. package/ios/Tests/Mocks/ModuleMocks.swift +1 -1
  174. package/ios/Tests/PropertyComponentSpec.swift +95 -0
  175. package/ios/Tests/SharedObjectRegistrySpec.swift +109 -0
  176. package/ios/Tests/TypedArraysSpec.swift +136 -0
  177. package/package.json +2 -2
  178. package/src/NativeModulesProxy.native.ts +13 -3
  179. package/src/PermissionsInterface.ts +29 -0
  180. package/src/ts-declarations/ExpoModules.d.ts +7 -0
  181. package/tsconfig.json +1 -1
  182. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromise.kt +0 -15
  183. package/android/src/main/java/expo/modules/kotlin/functions/AsyncSuspendFunction.kt +0 -36
  184. package/ios/Swift/Arguments/AnyArgumentType.swift +0 -13
  185. package/ios/Swift/Arguments/ArgumentType.swift +0 -28
  186. package/ios/Swift/Arguments/Types/ArrayArgumentType.swift +0 -42
  187. package/ios/Swift/Arguments/Types/ConvertibleArgumentType.swift +0 -16
  188. package/ios/Swift/Arguments/Types/OptionalArgumentType.swift +0 -49
  189. package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +0 -15
  190. package/ios/Swift/Arguments/Types/RawArgumentType.swift +0 -25
  191. package/ios/Swift/Functions/ConcreteFunction.swift +0 -103
  192. package/ios/Swift/SwiftInteropBridge.swift +0 -155
  193. package/ios/Tests/ArgumentTypeSpec.swift +0 -143
@@ -1,16 +1,41 @@
1
1
  package expo.modules.kotlin.modules
2
2
 
3
+ import expo.modules.kotlin.ConcatIterator
4
+ import expo.modules.kotlin.ModuleHolder
3
5
  import expo.modules.kotlin.events.EventListener
4
6
  import expo.modules.kotlin.events.EventName
5
- import expo.modules.kotlin.events.EventsDefinition
6
- import expo.modules.kotlin.functions.AnyFunction
7
+ import expo.modules.kotlin.objects.ObjectDefinitionData
7
8
  import expo.modules.kotlin.views.ViewManagerDefinition
8
9
 
10
+ /**
11
+ * Intermediate data used to create a proper [ProcessedModuleDefinition].
12
+ * It contains all, unprocessed data from [ModuleDefinitionBuilder].
13
+ */
9
14
  class ModuleDefinitionData(
10
15
  val name: String,
11
- val constantsProvider: () -> Map<String, Any?>,
12
- val methods: Map<String, AnyFunction>,
16
+ val objectDefinition: ObjectDefinitionData,
13
17
  val viewManagerDefinition: ViewManagerDefinition? = null,
14
18
  val eventListeners: Map<EventName, EventListener> = emptyMap(),
15
- val eventsDefinition: EventsDefinition? = null
16
19
  )
20
+
21
+ /**
22
+ * A final version of the ModuleDefinition.
23
+ * Most values are just copied from [ModuleDefinitionData].
24
+ * However some fields like `asyncFunctions` need to be processed or bound with the [ModuleHolder].
25
+ */
26
+ class ProcessedModuleDefinition(
27
+ data: ModuleDefinitionData,
28
+ moduleHolder: ModuleHolder
29
+ ) {
30
+ val name = data.name
31
+ val constantsProvider = data.objectDefinition.constantsProvider
32
+ val syncFunctions = data.objectDefinition.syncFunctions
33
+ val asyncFunctions = data.objectDefinition.asyncFunctions + data.objectDefinition.buildSuspendFunctions(moduleHolder)
34
+ val viewManagerDefinition = data.viewManagerDefinition
35
+ val eventListeners = data.eventListeners
36
+ val eventsDefinition = data.objectDefinition.eventsDefinition
37
+ val properties = data.objectDefinition.properties
38
+
39
+ val functions
40
+ get() = ConcatIterator(syncFunctions.values.iterator(), asyncFunctions.values.iterator())
41
+ }
@@ -0,0 +1,271 @@
1
+ /**
2
+ * We used a function from the experimental STD API - typeOf (see kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/type-of.html).
3
+ * We shouldn't have any problem with that function, cause it's widely used in other libraries created by JetBrains like kotlinx-serializer.
4
+ * This function is super handy if we want to receive a collection type.
5
+ * For example, it's very hard to obtain the generic parameter type from the list class.
6
+ * In plain Java, it's almost impossible. There is a trick to getting such information using something called TypeToken.
7
+ * For instance, the Gson library uses this workaround. But there still will be a problem with nullability.
8
+ * We didn't find a good solution to distinguish between List<Any?> and List<Any>.
9
+ * Mainly because from the JVM perspective it's the same type.
10
+ * That's why we used typeOf. It solves all problems described above.
11
+ */
12
+ @file:OptIn(ExperimentalStdlibApi::class)
13
+ @file:Suppress("FunctionName")
14
+
15
+ package expo.modules.kotlin.objects
16
+
17
+ import expo.modules.kotlin.Promise
18
+ import expo.modules.kotlin.events.EventsDefinition
19
+ import expo.modules.kotlin.functions.AsyncFunction
20
+ import expo.modules.kotlin.functions.AsyncFunctionBuilder
21
+ import expo.modules.kotlin.functions.AsyncFunctionComponent
22
+ import expo.modules.kotlin.functions.AsyncFunctionWithPromiseComponent
23
+ import expo.modules.kotlin.functions.SyncFunctionComponent
24
+ import expo.modules.kotlin.types.toAnyType
25
+ import kotlin.reflect.typeOf
26
+
27
+ /**
28
+ * Base class for other definitions representing an object, such as `ModuleDefinition`.
29
+ */
30
+ open class ObjectDefinitionBuilder {
31
+ private var constantsProvider = { emptyMap<String, Any?>() }
32
+ private var eventsDefinition: EventsDefinition? = null
33
+
34
+ @PublishedApi
35
+ internal var syncFunctions = mutableMapOf<String, SyncFunctionComponent>()
36
+
37
+ @PublishedApi
38
+ internal var asyncFunctions = mutableMapOf<String, AsyncFunction>()
39
+
40
+ private var functionBuilders = mutableMapOf<String, AsyncFunctionBuilder>()
41
+
42
+ @PublishedApi
43
+ internal var properties = mutableMapOf<String, PropertyComponentBuilder>()
44
+
45
+ fun buildObject(): ObjectDefinitionData {
46
+ return ObjectDefinitionData(
47
+ constantsProvider,
48
+ syncFunctions,
49
+ asyncFunctions,
50
+ functionBuilders.mapValues { (_, value) -> value.build() },
51
+ eventsDefinition,
52
+ properties.mapValues { (_, value) -> value.build() }
53
+ )
54
+ }
55
+
56
+ /**
57
+ * Definition function setting the module's constants to export.
58
+ */
59
+ fun Constants(constantsProvider: () -> Map<String, Any?>) {
60
+ this.constantsProvider = constantsProvider
61
+ }
62
+
63
+ /**
64
+ * Definition of the module's constants to export.
65
+ */
66
+ fun Constants(vararg constants: Pair<String, Any?>) {
67
+ constantsProvider = { constants.toMap() }
68
+ }
69
+
70
+ @JvmName("FunctionWithoutArgs")
71
+ inline fun Function(
72
+ name: String,
73
+ crossinline body: () -> Any?
74
+ ) {
75
+ SyncFunctionComponent(name, arrayOf()) { body() }.also {
76
+ syncFunctions[name] = it
77
+ }
78
+ }
79
+
80
+ inline fun <reified R> Function(
81
+ name: String,
82
+ crossinline body: () -> R
83
+ ) {
84
+ SyncFunctionComponent(name, arrayOf()) { body() }.also {
85
+ syncFunctions[name] = it
86
+ }
87
+ }
88
+
89
+ inline fun <reified R, reified P0> Function(
90
+ name: String,
91
+ crossinline body: (p0: P0) -> R
92
+ ) {
93
+ SyncFunctionComponent(name, arrayOf(typeOf<P0>().toAnyType())) { body(it[0] as P0) }.also {
94
+ syncFunctions[name] = it
95
+ }
96
+ }
97
+
98
+ inline fun <reified R, reified P0, reified P1> Function(
99
+ name: String,
100
+ crossinline body: (p0: P0, p1: P1) -> R
101
+ ) {
102
+ SyncFunctionComponent(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType())) { body(it[0] as P0, it[1] as P1) }.also {
103
+ syncFunctions[name] = it
104
+ }
105
+ }
106
+
107
+ inline fun <reified R, reified P0, reified P1, reified P2> Function(
108
+ name: String,
109
+ crossinline body: (p0: P0, p1: P1, p2: P2) -> R
110
+ ) {
111
+ SyncFunctionComponent(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType(), typeOf<P2>().toAnyType())) { body(it[0] as P0, it[1] as P1, it[2] as P2) }.also {
112
+ syncFunctions[name] = it
113
+ }
114
+ }
115
+
116
+ inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5> Function(
117
+ name: String,
118
+ crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) -> R
119
+ ) {
120
+ SyncFunctionComponent(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType(), typeOf<P2>().toAnyType(), typeOf<P3>().toAnyType(), typeOf<P4>().toAnyType(), typeOf<P5>().toAnyType())) { body(it[0] as P0, it[1] as P1, it[2] as P2, it[3] as P3, it[4] as P4, it[5] as P5) }.also {
121
+ syncFunctions[name] = it
122
+ }
123
+ }
124
+
125
+ @JvmName("AsyncFunctionWithoutArgs")
126
+ inline fun AsyncFunction(
127
+ name: String,
128
+ crossinline body: () -> Any?
129
+ ) {
130
+ asyncFunctions[name] = AsyncFunctionComponent(name, arrayOf()) { body() }
131
+ }
132
+
133
+ inline fun <reified R> AsyncFunction(
134
+ name: String,
135
+ crossinline body: () -> R
136
+ ) {
137
+ asyncFunctions[name] = AsyncFunctionComponent(name, arrayOf()) { body() }
138
+ }
139
+
140
+ inline fun <reified R, reified P0> AsyncFunction(
141
+ name: String,
142
+ crossinline body: (p0: P0) -> R
143
+ ) {
144
+ asyncFunctions[name] = if (P0::class == Promise::class) {
145
+ AsyncFunctionWithPromiseComponent(name, arrayOf()) { _, promise -> body(promise as P0) }
146
+ } else {
147
+ AsyncFunctionComponent(name, arrayOf(typeOf<P0>().toAnyType())) { body(it[0] as P0) }
148
+ }
149
+ }
150
+
151
+ inline fun <reified R, reified P0, reified P1> AsyncFunction(
152
+ name: String,
153
+ crossinline body: (p0: P0, p1: P1) -> R
154
+ ) {
155
+ asyncFunctions[name] = if (P1::class == Promise::class) {
156
+ AsyncFunctionWithPromiseComponent(name, arrayOf(typeOf<P0>().toAnyType())) { args, promise -> body(args[0] as P0, promise as P1) }
157
+ } else {
158
+ AsyncFunctionComponent(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType())) { body(it[0] as P0, it[1] as P1) }
159
+ }
160
+ }
161
+
162
+ inline fun <reified R, reified P0, reified P1, reified P2> AsyncFunction(
163
+ name: String,
164
+ crossinline body: (p0: P0, p1: P1, p2: P2) -> R
165
+ ) {
166
+ asyncFunctions[name] = if (P2::class == Promise::class) {
167
+ AsyncFunctionWithPromiseComponent(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType())) { args, promise -> body(args[0] as P0, args[1] as P1, promise as P2) }
168
+ } else {
169
+ AsyncFunctionComponent(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType(), typeOf<P2>().toAnyType())) { body(it[0] as P0, it[1] as P1, it[2] as P2) }
170
+ }
171
+ }
172
+
173
+ inline fun <reified R, reified P0, reified P1, reified P2, reified P3> AsyncFunction(
174
+ name: String,
175
+ crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3) -> R
176
+ ) {
177
+ asyncFunctions[name] = if (P3::class == Promise::class) {
178
+ AsyncFunctionWithPromiseComponent(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType(), typeOf<P2>().toAnyType())) { args, promise -> body(args[0] as P0, args[1] as P1, args[2] as P2, promise as P3) }
179
+ } else {
180
+ AsyncFunctionComponent(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType(), typeOf<P2>().toAnyType(), typeOf<P3>().toAnyType())) { body(it[0] as P0, it[1] as P1, it[2] as P2, it[3] as P3) }
181
+ }
182
+ }
183
+
184
+ inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4> AsyncFunction(
185
+ name: String,
186
+ crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) -> R
187
+ ) {
188
+ asyncFunctions[name] = if (P4::class == Promise::class) {
189
+ AsyncFunctionWithPromiseComponent(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType(), typeOf<P2>().toAnyType(), typeOf<P3>().toAnyType())) { args, promise -> body(args[0] as P0, args[1] as P1, args[2] as P2, args[3] as P3, promise as P4) }
190
+ } else {
191
+ AsyncFunctionComponent(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType(), typeOf<P2>().toAnyType(), typeOf<P3>().toAnyType(), typeOf<P4>().toAnyType())) { body(it[0] as P0, it[1] as P1, it[2] as P2, it[3] as P3, it[4] as P4) }
192
+ }
193
+ }
194
+
195
+ inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5> AsyncFunction(
196
+ name: String,
197
+ crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) -> R
198
+ ) {
199
+ asyncFunctions[name] = if (P5::class == Promise::class) {
200
+ AsyncFunctionWithPromiseComponent(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType(), typeOf<P2>().toAnyType(), typeOf<P3>().toAnyType(), typeOf<P4>().toAnyType())) { args, promise -> body(args[0] as P0, args[1] as P1, args[2] as P2, args[3] as P3, args[4] as P4, promise as P5) }
201
+ } else {
202
+ AsyncFunctionComponent(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType(), typeOf<P2>().toAnyType(), typeOf<P3>().toAnyType(), typeOf<P4>().toAnyType(), typeOf<P5>().toAnyType())) { body(it[0] as P0, it[1] as P1, it[2] as P2, it[3] as P3, it[4] as P4, it[5] as P5) }
203
+ }
204
+ }
205
+
206
+ inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6> AsyncFunction(
207
+ name: String,
208
+ crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) -> R
209
+ ) {
210
+ asyncFunctions[name] = if (P6::class == Promise::class) {
211
+ AsyncFunctionWithPromiseComponent(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType(), typeOf<P2>().toAnyType(), typeOf<P3>().toAnyType(), typeOf<P4>().toAnyType(), typeOf<P5>().toAnyType())) { args, promise -> body(args[0] as P0, args[1] as P1, args[2] as P2, args[3] as P3, args[4] as P4, args[5] as P5, promise as P6) }
212
+ } else {
213
+ AsyncFunctionComponent(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType(), typeOf<P2>().toAnyType(), typeOf<P3>().toAnyType(), typeOf<P4>().toAnyType(), typeOf<P5>().toAnyType(), typeOf<P6>().toAnyType())) { body(it[0] as P0, it[1] as P1, it[2] as P2, it[3] as P3, it[4] as P4, it[5] as P5, it[6] as P6) }
214
+ }
215
+ }
216
+
217
+ inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6, reified P7> AsyncFunction(
218
+ name: String,
219
+ crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) -> R
220
+ ) {
221
+ asyncFunctions[name] = if (P7::class == Promise::class) {
222
+ AsyncFunctionWithPromiseComponent(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType(), typeOf<P2>().toAnyType(), typeOf<P3>().toAnyType(), typeOf<P4>().toAnyType(), typeOf<P5>().toAnyType(), typeOf<P6>().toAnyType())) { args, promise -> body(args[0] as P0, args[1] as P1, args[2] as P2, args[3] as P3, args[4] as P4, args[5] as P5, args[6] as P6, promise as P7) }
223
+ } else {
224
+ AsyncFunctionComponent(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType(), typeOf<P2>().toAnyType(), typeOf<P3>().toAnyType(), typeOf<P4>().toAnyType(), typeOf<P5>().toAnyType(), typeOf<P6>().toAnyType(), typeOf<P7>().toAnyType())) { body(it[0] as P0, it[1] as P1, it[2] as P2, it[3] as P3, it[4] as P4, it[5] as P5, it[6] as P6, it[7] as P7) }
225
+ }
226
+ }
227
+
228
+ fun AsyncFunction(
229
+ name: String
230
+ ) = AsyncFunctionBuilder(name).also { functionBuilders[name] = it }
231
+
232
+ /**
233
+ * Defines event names that this module can send to JavaScript.
234
+ */
235
+ fun Events(vararg events: String) {
236
+ eventsDefinition = EventsDefinition(events)
237
+ }
238
+
239
+ /**
240
+ * Creates module's lifecycle listener that is called right after the first event listener is added.
241
+ */
242
+ inline fun OnStartObserving(crossinline body: () -> Unit) {
243
+ AsyncFunction("startObserving", body)
244
+ }
245
+
246
+ /**
247
+ * Creates module's lifecycle listener that is called right after all event listeners are removed.
248
+ */
249
+ inline fun OnStopObserving(crossinline body: () -> Unit) {
250
+ AsyncFunction("stopObserving", body)
251
+ }
252
+
253
+ /**
254
+ * Creates the property with given name. The component is basically no-op if you don't call `.get()` or `.set()` on it.
255
+ */
256
+ fun Property(name: String): PropertyComponentBuilder {
257
+ return PropertyComponentBuilder(name).also {
258
+ properties[name] = it
259
+ }
260
+ }
261
+
262
+ /**
263
+ * Creates the read-only property whose getter doesn't take the caller as an argument.
264
+ */
265
+ inline fun <T> Property(name: String, crossinline body: () -> T): PropertyComponentBuilder {
266
+ return PropertyComponentBuilder(name).also {
267
+ it.get(body)
268
+ properties[name] = it
269
+ }
270
+ }
271
+ }
@@ -0,0 +1,21 @@
1
+ package expo.modules.kotlin.objects
2
+
3
+ import expo.modules.kotlin.ModuleHolder
4
+ import expo.modules.kotlin.events.EventsDefinition
5
+ import expo.modules.kotlin.functions.AsyncFunction
6
+ import expo.modules.kotlin.functions.SuspendFunctionComponent
7
+ import expo.modules.kotlin.functions.SuspendFunctionComponentBuilder
8
+ import expo.modules.kotlin.functions.SyncFunctionComponent
9
+
10
+ class ObjectDefinitionData(
11
+ val constantsProvider: () -> Map<String, Any?>,
12
+ val syncFunctions: Map<String, SyncFunctionComponent>,
13
+ val asyncFunctions: Map<String, AsyncFunction>,
14
+ val suspendFunctionBuilders: Map<String, SuspendFunctionComponentBuilder>,
15
+ val eventsDefinition: EventsDefinition?,
16
+ val properties: Map<String, PropertyComponent>
17
+ ) {
18
+ fun buildSuspendFunctions(moduleHolder: ModuleHolder): Map<String, SuspendFunctionComponent> {
19
+ return suspendFunctionBuilders.mapValues { (_, value) -> value.build(moduleHolder) }
20
+ }
21
+ }
@@ -0,0 +1,54 @@
1
+ package expo.modules.kotlin.objects
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import expo.modules.kotlin.functions.SyncFunctionComponent
5
+ import expo.modules.kotlin.jni.CppType
6
+ import expo.modules.kotlin.jni.JNIFunctionBody
7
+ import expo.modules.kotlin.jni.JavaScriptModuleObject
8
+
9
+ class PropertyComponent(
10
+ /**
11
+ * Name of the property.
12
+ */
13
+ val name: String,
14
+
15
+ /**
16
+ * Synchronous function that is called when the property is being accessed.
17
+ */
18
+ val getter: SyncFunctionComponent? = null,
19
+
20
+ /**
21
+ * Synchronous function that is called when the property is being set.
22
+ */
23
+ val setter: SyncFunctionComponent? = null
24
+ ) {
25
+ /**
26
+ * Attaches property to the provided js object.
27
+ */
28
+ fun attachToJSObject(jsObject: JavaScriptModuleObject) {
29
+ val jniGetter = if (getter != null) {
30
+ JNIFunctionBody {
31
+ val result = getter.call(emptyArray())
32
+ return@JNIFunctionBody Arguments.fromJavaArgs(arrayOf(result))
33
+ }
34
+ } else {
35
+ null
36
+ }
37
+
38
+ val jniSetter = if (setter != null) {
39
+ JNIFunctionBody { args ->
40
+ setter.call(args)
41
+ return@JNIFunctionBody null
42
+ }
43
+ } else {
44
+ null
45
+ }
46
+
47
+ jsObject.registerProperty(
48
+ name,
49
+ setter?.getCppRequiredTypes()?.first() ?: CppType.NONE.value,
50
+ jniGetter,
51
+ jniSetter
52
+ )
53
+ }
54
+ }
@@ -0,0 +1,32 @@
1
+ @file:OptIn(ExperimentalStdlibApi::class)
2
+
3
+ package expo.modules.kotlin.objects
4
+
5
+ import expo.modules.kotlin.functions.SyncFunctionComponent
6
+ import expo.modules.kotlin.types.toAnyType
7
+ import kotlin.reflect.typeOf
8
+
9
+ class PropertyComponentBuilder(
10
+ val name: String
11
+ ) {
12
+ var getter: SyncFunctionComponent? = null
13
+ var setter: SyncFunctionComponent? = null
14
+
15
+ /**
16
+ * Modifier that sets property getter that has no arguments (the caller is not used).
17
+ */
18
+ inline fun <T> get(crossinline body: () -> T) = apply {
19
+ getter = SyncFunctionComponent("get", arrayOf()) { body() }
20
+ }
21
+
22
+ /**
23
+ * Modifier that sets property setter that receives only the new value as an argument.
24
+ */
25
+ inline fun <reified T> set(crossinline body: (newValue: T) -> Unit) = apply {
26
+ setter = SyncFunctionComponent("set", arrayOf(typeOf<T>().toAnyType())) { body(it[0] as T) }
27
+ }
28
+
29
+ fun build(): PropertyComponent {
30
+ return PropertyComponent(name, getter, setter)
31
+ }
32
+ }
@@ -0,0 +1,14 @@
1
+ package expo.modules.kotlin.providers
2
+
3
+ import expo.modules.kotlin.AppContext
4
+
5
+ /**
6
+ * Provider that allows accessing [AppContext] and all it's public parts (e.g. [AppContext.reactContext]).
7
+ */
8
+ interface AppContextProvider {
9
+ /**
10
+ * [AppContext] reference. If it's not possible to access the [AppContext], because it's null
11
+ * then it's an invalid situation and should result in throwing descriptive error.
12
+ */
13
+ val appContext: AppContext
14
+ }
@@ -0,0 +1,22 @@
1
+ package expo.modules.kotlin.providers
2
+
3
+ import com.facebook.react.ReactActivity
4
+ import androidx.appcompat.app.AppCompatActivity
5
+ import androidx.fragment.app.FragmentActivity
6
+ import androidx.core.app.ComponentActivity
7
+ import android.app.Activity
8
+
9
+ /**
10
+ * A class that provides the accessor to the [ReactActivity]. It enables accessing
11
+ * AndroidX/Android Jetpack features in Expo libraries coming from all subclassing chain:
12
+ * [AppCompatActivity], [FragmentActivity], [ComponentActivity], [Activity]
13
+ */
14
+ interface CurrentActivityProvider {
15
+ /**
16
+ * Returns the current [Activity] that should be an instance of [AppCompatActivity].
17
+ * This activity is most likely an instance of [ReactActivity], but it's been decided not to expose
18
+ * `react-native` symbols via `expo-module-core` public API.
19
+ * @returns null if the [Activity] is not yet available (eg. Application has not yet fully started)
20
+ */
21
+ val currentActivity: AppCompatActivity?
22
+ }
@@ -1,13 +1,16 @@
1
1
  package expo.modules.kotlin.records
2
2
 
3
3
  import com.facebook.react.bridge.Dynamic
4
+ import com.facebook.react.bridge.ReadableMap
4
5
  import expo.modules.kotlin.allocators.ObjectConstructor
5
6
  import expo.modules.kotlin.allocators.ObjectConstructorFactory
6
7
  import expo.modules.kotlin.exception.FieldCastException
7
8
  import expo.modules.kotlin.exception.FieldRequiredException
8
9
  import expo.modules.kotlin.exception.RecordCastException
9
10
  import expo.modules.kotlin.exception.exceptionDecorator
11
+ import expo.modules.kotlin.jni.CppType
10
12
  import expo.modules.kotlin.recycle
13
+ import expo.modules.kotlin.types.DynamicAwareTypeConverters
11
14
  import expo.modules.kotlin.types.TypeConverter
12
15
  import expo.modules.kotlin.types.TypeConverterProvider
13
16
  import kotlin.reflect.KClass
@@ -21,7 +24,7 @@ import kotlin.reflect.jvm.javaField
21
24
  class RecordTypeConverter<T : Record>(
22
25
  private val converterProvider: TypeConverterProvider,
23
26
  val type: KType,
24
- ) : TypeConverter<T>(type.isMarkedNullable) {
27
+ ) : DynamicAwareTypeConverters<T>(type.isMarkedNullable) {
25
28
  private val objectConstructorFactory = ObjectConstructorFactory()
26
29
  private val propertyDescriptors: Map<KProperty1<out Any, *>, PropertyDescriptor> =
27
30
  (type.classifier as KClass<*>)
@@ -40,9 +43,23 @@ class RecordTypeConverter<T : Record>(
40
43
  .filterNotNull()
41
44
  .toMap()
42
45
 
43
- override fun convertNonOptional(value: Dynamic): T = exceptionDecorator({ cause -> RecordCastException(type, cause) }) {
46
+ override fun convertFromDynamic(value: Dynamic): T = exceptionDecorator({ cause -> RecordCastException(type, cause) }) {
44
47
  val jsMap = value.asMap()
48
+ return convertFromReadableMap(jsMap)
49
+ }
50
+
51
+ override fun convertFromAny(value: Any): T {
52
+ if (value is ReadableMap) {
53
+ return convertFromReadableMap(value)
54
+ }
55
+
56
+ @Suppress("UNCHECKED_CAST")
57
+ return value as T
58
+ }
59
+
60
+ override fun getCppRequiredTypes(): List<CppType> = listOf(CppType.READABLE_MAP)
45
61
 
62
+ private fun convertFromReadableMap(jsMap: ReadableMap): T {
46
63
  val kClass = type.classifier as KClass<*>
47
64
  val instance = getObjectConstructor(kClass.java).construct()
48
65
 
@@ -1,6 +1,5 @@
1
1
  package expo.modules.kotlin.types
2
2
 
3
- import com.facebook.react.bridge.Dynamic
4
3
  import kotlin.reflect.KType
5
4
 
6
5
  fun KType.toAnyType(): AnyType = AnyType(this)
@@ -10,5 +9,7 @@ class AnyType(val kType: KType) {
10
9
  TypeConverterProviderImpl.obtainTypeConverter(kType)
11
10
  }
12
11
 
13
- fun convert(value: Dynamic): Any? = converter.convert(value)
12
+ fun convert(value: Any?): Any? = converter.convert(value)
13
+
14
+ fun getCppRequiredTypes(): Int = converter.getCppRequiredTypes().fold(0) { acc, current -> acc or current.value }
14
15
  }
@@ -0,0 +1,36 @@
1
+ package expo.modules.kotlin.types
2
+
3
+ import com.facebook.react.bridge.Dynamic
4
+ import com.facebook.react.bridge.ReadableType
5
+ import expo.modules.kotlin.jni.CppType
6
+
7
+ /**
8
+ * Type converter that handles conversion from [Any] or [Dynamic] to [Any].
9
+ * In the first case, it will just pass provided value.
10
+ * In case when it receives [Dynamic], it will unpack the provided value.
11
+ * In that way, we produce the same output for JSI and bridge implementation.
12
+ */
13
+ class AnyTypeConverter(isOptional: Boolean) : DynamicAwareTypeConverters<Any>(isOptional) {
14
+ override fun convertFromDynamic(value: Dynamic): Any {
15
+ return when (value.type) {
16
+ ReadableType.Boolean -> value.asBoolean()
17
+ ReadableType.Number -> value.asDouble()
18
+ ReadableType.String -> value.asString()
19
+ ReadableType.Map -> value.asMap()
20
+ ReadableType.Array -> value.asArray()
21
+ else -> error("Unknown dynamic type: ${value.type}")
22
+ }
23
+ }
24
+
25
+ override fun convertFromAny(value: Any): Any {
26
+ return value
27
+ }
28
+
29
+ override fun getCppRequiredTypes(): List<CppType> = listOf(
30
+ CppType.READABLE_MAP,
31
+ CppType.READABLE_ARRAY,
32
+ CppType.STRING,
33
+ CppType.BOOLEAN,
34
+ CppType.DOUBLE
35
+ )
36
+ }
@@ -3,6 +3,7 @@ package expo.modules.kotlin.types
3
3
  import com.facebook.react.bridge.Dynamic
4
4
  import expo.modules.kotlin.exception.CollectionElementCastException
5
5
  import expo.modules.kotlin.exception.exceptionDecorator
6
+ import expo.modules.kotlin.jni.CppType
6
7
  import expo.modules.kotlin.recycle
7
8
  import kotlin.reflect.KClass
8
9
  import kotlin.reflect.KType
@@ -10,14 +11,14 @@ import kotlin.reflect.KType
10
11
  class ArrayTypeConverter(
11
12
  converterProvider: TypeConverterProvider,
12
13
  private val arrayType: KType,
13
- ) : TypeConverter<Array<*>>(arrayType.isMarkedNullable) {
14
+ ) : DynamicAwareTypeConverters<Array<*>>(arrayType.isMarkedNullable) {
14
15
  private val arrayElementConverter = converterProvider.obtainTypeConverter(
15
16
  requireNotNull(arrayType.arguments.first().type) {
16
17
  "The array type should contain the type of the elements."
17
18
  }
18
19
  )
19
20
 
20
- override fun convertNonOptional(value: Dynamic): Array<*> {
21
+ override fun convertFromDynamic(value: Dynamic): Array<*> {
21
22
  val jsArray = value.asArray()
22
23
  val array = createTypedArray(jsArray.size())
23
24
  for (i in 0 until jsArray.size()) {
@@ -34,6 +35,8 @@ class ArrayTypeConverter(
34
35
  return array
35
36
  }
36
37
 
38
+ override fun convertFromAny(value: Any): Array<*> = value as Array<*>
39
+
37
40
  /**
38
41
  * We can't use a Array<Any?> here. We have to create a typed array.
39
42
  * Otherwise, cast which is done before calling lambda provided by the user will always fail.
@@ -47,4 +50,6 @@ class ArrayTypeConverter(
47
50
  size
48
51
  ) as Array<Any?>
49
52
  }
53
+
54
+ override fun getCppRequiredTypes(): List<CppType> = listOf(CppType.READABLE_ARRAY)
50
55
  }