expo-modules-core 0.7.0 → 0.8.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 (124) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +1 -1
  3. package/android/ExpoModulesCorePlugin.gradle +15 -0
  4. package/android/build.gradle +46 -32
  5. package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +5 -5
  6. package/android/src/main/java/expo/modules/adapters/react/services/UIManagerModuleWrapper.java +13 -0
  7. package/android/src/main/java/expo/modules/core/ViewManager.java +9 -0
  8. package/android/src/main/java/expo/modules/core/interfaces/JavaScriptContextProvider.java +4 -0
  9. package/android/src/main/java/expo/modules/core/interfaces/ReactActivityHandler.java +37 -1
  10. package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.java +19 -0
  11. package/android/src/main/java/expo/modules/core/interfaces/services/UIManager.java +2 -0
  12. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +13 -5
  13. package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +2 -13
  14. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +11 -5
  15. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +5 -1
  16. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +17 -0
  17. package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallback.kt +14 -3
  18. package/android/src/main/java/expo/modules/kotlin/events/EventEmitter.kt +13 -0
  19. package/android/src/main/java/expo/modules/kotlin/events/KModuleEventEmitterWrapper.kt +102 -0
  20. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +25 -1
  21. package/android/src/main/java/expo/modules/kotlin/{methods/AnyMethod.kt → functions/AnyFunction.kt} +6 -5
  22. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +15 -0
  23. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +61 -0
  24. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromise.kt +15 -0
  25. package/android/src/main/java/expo/modules/kotlin/functions/AsyncSuspendFunction.kt +36 -0
  26. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +14 -0
  27. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +176 -27
  28. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +2 -2
  29. package/android/src/main/java/expo/modules/kotlin/records/FieldValidator.kt +139 -0
  30. package/android/src/main/java/expo/modules/kotlin/records/Record.kt +0 -39
  31. package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +59 -10
  32. package/android/src/main/java/expo/modules/kotlin/records/Required.kt +5 -0
  33. package/android/src/main/java/expo/modules/kotlin/records/ValidationBinder.kt +110 -0
  34. package/android/src/main/java/expo/modules/kotlin/records/Validators.kt +61 -0
  35. package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverter.kt +35 -0
  36. package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverterHelper.kt +148 -0
  37. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +9 -1
  38. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +49 -0
  39. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinition.kt +18 -0
  40. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +64 -0
  41. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +4 -1
  42. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +15 -2
  43. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +3 -0
  44. package/build/NativeModulesProxy.native.d.ts +0 -4
  45. package/build/NativeModulesProxy.native.d.ts.map +1 -1
  46. package/build/NativeModulesProxy.native.js +1 -14
  47. package/build/NativeModulesProxy.native.js.map +1 -1
  48. package/build/NativeModulesProxy.types.d.ts +0 -3
  49. package/build/NativeModulesProxy.types.d.ts.map +1 -1
  50. package/build/NativeModulesProxy.types.js.map +1 -1
  51. package/build/NativeViewManagerAdapter.native.d.ts.map +1 -1
  52. package/build/NativeViewManagerAdapter.native.js +9 -33
  53. package/build/NativeViewManagerAdapter.native.js.map +1 -1
  54. package/build/sweet/NativeErrorManager.js +1 -1
  55. package/build/sweet/NativeErrorManager.js.map +1 -1
  56. package/ios/AppDelegates/EXAppDelegatesLoader.m +4 -8
  57. package/ios/AppDelegates/ExpoAppDelegate.swift +4 -10
  58. package/ios/EXAppDefines.h +1 -0
  59. package/ios/EXAppDefines.m +6 -0
  60. package/ios/EXUtilities.h +2 -0
  61. package/ios/EXUtilities.m +12 -0
  62. package/ios/ExpoModulesCore.h +4 -0
  63. package/ios/ExpoModulesCore.podspec +4 -2
  64. package/ios/Interfaces/FileSystem/EXFileSystemInterface.h +1 -1
  65. package/ios/Interfaces/TaskManager/EXTaskServiceInterface.h +1 -0
  66. package/ios/JSI/{JSIConversions.h → EXJSIConversions.h} +4 -1
  67. package/ios/JSI/{JSIConversions.mm → EXJSIConversions.mm} +16 -5
  68. package/ios/JSI/{JSIInstaller.h → EXJSIInstaller.h} +3 -3
  69. package/ios/JSI/EXJSIInstaller.mm +17 -0
  70. package/ios/JSI/{ExpoModulesProxySpec.h → EXJSIUtils.h} +0 -9
  71. package/ios/JSI/{ExpoModulesProxySpec.mm → EXJSIUtils.mm} +4 -48
  72. package/ios/JSI/EXJavaScriptObject.h +97 -0
  73. package/ios/JSI/EXJavaScriptObject.mm +121 -0
  74. package/ios/JSI/{JavaScriptRuntime.h → EXJavaScriptRuntime.h} +27 -8
  75. package/ios/JSI/EXJavaScriptRuntime.mm +153 -0
  76. package/ios/JSI/EXJavaScriptValue.h +57 -0
  77. package/ios/JSI/EXJavaScriptValue.mm +166 -0
  78. package/ios/JSI/ExpoModulesHostObject.mm +2 -1
  79. package/ios/JSI/JavaScriptRuntime.swift +32 -0
  80. package/ios/JSI/JavaScriptValue.swift +94 -0
  81. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +1 -11
  82. package/ios/NativeModulesProxy/EXNativeModulesProxy.h +2 -2
  83. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +24 -22
  84. package/ios/ReactDelegates/EXReactCompatibleHelpers.h +18 -0
  85. package/ios/ReactDelegates/EXReactCompatibleHelpers.m +19 -0
  86. package/ios/ReactDelegates/ExpoReactDelegate.swift +2 -2
  87. package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +1 -1
  88. package/ios/Swift/AppContext.swift +27 -1
  89. package/ios/Swift/Functions/AsyncFunction.swift +17 -0
  90. package/ios/Swift/Functions/ConcreteFunction.swift +6 -1
  91. package/ios/Swift/JavaScriptUtils.swift +11 -0
  92. package/ios/Swift/ModuleHolder.swift +14 -3
  93. package/ios/Swift/ModulesProvider.swift +3 -10
  94. package/ios/Swift/Objects/ObjectDefinitionComponents.swift +176 -0
  95. package/ios/Swift/SwiftInteropBridge.swift +14 -5
  96. package/ios/Swift/Views/ComponentData.swift +2 -1
  97. package/ios/Swift/Views/ExpoView.swift +8 -0
  98. package/ios/Swift.h +5 -0
  99. package/ios/Tests/ArgumentTypeSpec.swift +2 -3
  100. package/ios/Tests/ConstantsSpec.swift +2 -3
  101. package/ios/Tests/ConvertiblesSpec.swift +2 -3
  102. package/ios/Tests/ExceptionsSpec.swift +2 -3
  103. package/ios/Tests/ExpoModulesSpec.swift +76 -0
  104. package/ios/Tests/FunctionSpec.swift +2 -3
  105. package/ios/Tests/FunctionWithConvertiblesSpec.swift +2 -3
  106. package/ios/Tests/JavaScriptObjectSpec.swift +97 -0
  107. package/ios/Tests/JavaScriptRuntimeSpec.swift +94 -0
  108. package/ios/Tests/ModuleEventListenersSpec.swift +2 -3
  109. package/ios/Tests/ModuleRegistrySpec.swift +2 -3
  110. package/ios/Tests/RecordSpec.swift +2 -3
  111. package/package.json +2 -2
  112. package/src/NativeModulesProxy.native.ts +2 -22
  113. package/src/NativeModulesProxy.types.ts +0 -8
  114. package/src/NativeViewManagerAdapter.native.tsx +12 -28
  115. package/src/sweet/NativeErrorManager.ts +1 -1
  116. package/android/src/main/java/expo/modules/kotlin/events/KEventEmitterWrapper.kt +0 -26
  117. package/android/src/main/java/expo/modules/kotlin/methods/Method.kt +0 -14
  118. package/android/src/main/java/expo/modules/kotlin/methods/PromiseMethod.kt +0 -15
  119. package/ios/JSI/JSIInstaller.mm +0 -34
  120. package/ios/JSI/JavaScriptObject.h +0 -60
  121. package/ios/JSI/JavaScriptObject.mm +0 -93
  122. package/ios/JSI/JavaScriptRuntime.mm +0 -102
  123. package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.h +0 -16
  124. package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.m +0 -28
@@ -0,0 +1,102 @@
1
+ package expo.modules.kotlin.events
2
+
3
+ import android.os.Bundle
4
+ import com.facebook.react.bridge.ReactApplicationContext
5
+ import com.facebook.react.bridge.WritableMap
6
+ import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter
7
+ import com.facebook.react.uimanager.UIManagerModule
8
+ import com.facebook.react.uimanager.events.EventDispatcher
9
+ import com.facebook.react.uimanager.events.RCTEventEmitter
10
+ import expo.modules.kotlin.ModuleHolder
11
+ import expo.modules.kotlin.records.Record
12
+ import expo.modules.kotlin.types.JSTypeConverter
13
+ import java.lang.ref.WeakReference
14
+
15
+ /**
16
+ * In Swift, we check if the event is supported. Otherwise, we can't send such event through the bridge.
17
+ * However, in Kotlin this is unnecessary, but to make our API consistent, we added similar check.
18
+ * But because of that, we had to create a wrapper for EventEmitter.
19
+ */
20
+ class KModuleEventEmitterWrapper(
21
+ private val moduleHolder: ModuleHolder,
22
+ legacyEventEmitter: expo.modules.core.interfaces.services.EventEmitter,
23
+ reactContextHolder: WeakReference<ReactApplicationContext>
24
+ ) : KEventEmitterWrapper(legacyEventEmitter, reactContextHolder) {
25
+ override fun emit(eventName: String, eventBody: Bundle?) {
26
+ checkIfEventWasExported(eventName)
27
+ super.emit(eventName, eventBody)
28
+ }
29
+
30
+ override fun emit(eventName: String, eventBody: WritableMap?) {
31
+ checkIfEventWasExported(eventName)
32
+ super.emit(eventName, eventBody)
33
+ }
34
+
35
+ override fun emit(eventName: String, eventBody: Record?) {
36
+ checkIfEventWasExported(eventName)
37
+ super.emit(eventName, eventBody)
38
+ }
39
+
40
+ override fun emit(eventName: String, eventBody: Map<*, *>?) {
41
+ checkIfEventWasExported(eventName)
42
+ super.emit(eventName, eventBody)
43
+ }
44
+
45
+ private fun checkIfEventWasExported(eventName: String) {
46
+ require(
47
+ moduleHolder
48
+ .definition
49
+ .eventsDefinition
50
+ ?.names
51
+ ?.contains(eventName) == true
52
+ ) { "Unsupported event: $eventName." }
53
+ }
54
+ }
55
+
56
+ open class KEventEmitterWrapper(
57
+ private val legacyEventEmitter: expo.modules.core.interfaces.services.EventEmitter,
58
+ private val reactContextHolder: WeakReference<ReactApplicationContext>
59
+ ) : EventEmitter, expo.modules.core.interfaces.services.EventEmitter by legacyEventEmitter {
60
+ private val deviceEventEmitter: RCTDeviceEventEmitter?
61
+ get() = reactContextHolder
62
+ .get()
63
+ ?.getJSModule(RCTDeviceEventEmitter::class.java)
64
+
65
+ private val uiEventDispatcher: EventDispatcher?
66
+ get() = reactContextHolder
67
+ .get()
68
+ ?.getNativeModule(UIManagerModule::class.java)
69
+ ?.eventDispatcher
70
+
71
+ override fun emit(eventName: String, eventBody: WritableMap?) {
72
+ deviceEventEmitter
73
+ ?.emit(eventName, eventBody)
74
+ }
75
+ override fun emit(eventName: String, eventBody: Record?) {
76
+ deviceEventEmitter
77
+ ?.emit(eventName, JSTypeConverter.convertToJSValue(eventBody))
78
+ }
79
+
80
+ override fun emit(eventName: String, eventBody: Map<*, *>?) {
81
+ deviceEventEmitter
82
+ ?.emit(eventName, JSTypeConverter.convertToJSValue(eventBody))
83
+ }
84
+
85
+ override fun emit(viewId: Int, eventName: String, eventBody: WritableMap?) {
86
+ uiEventDispatcher
87
+ ?.dispatchEvent(UIEvent(viewId, eventName, eventBody))
88
+ }
89
+
90
+ private class UIEvent(
91
+ private val viewId: Int,
92
+ private val eventName: String,
93
+ private val eventBody: WritableMap?
94
+ ) : com.facebook.react.uimanager.events.Event<UIEvent>(viewId) {
95
+ override fun getEventName(): String = eventName
96
+ override fun canCoalesce(): Boolean = false
97
+ override fun getCoalescingKey(): Short = 0
98
+ override fun dispatch(rctEventEmitter: RCTEventEmitter) {
99
+ rctEventEmitter.receiveEvent(viewId, eventName, eventBody)
100
+ }
101
+ }
102
+ }
@@ -2,6 +2,7 @@ package expo.modules.kotlin.exception
2
2
 
3
3
  import com.facebook.react.bridge.ReadableType
4
4
  import java.util.*
5
+ import kotlin.reflect.KProperty1
5
6
  import kotlin.reflect.KType
6
7
 
7
8
  /**
@@ -32,9 +33,11 @@ open class CodedException(
32
33
  /**
33
34
  * The code is inferred from the class name — e.g. the code of `ModuleNotFoundException` becomes `ERR_MODULE_NOT_FOUND`.
34
35
  */
35
- private fun inferCode(clazz: Class<*>): String {
36
+ @PublishedApi
37
+ internal fun inferCode(clazz: Class<*>): String {
36
38
  val name = requireNotNull(clazz.simpleName) { "Cannot infer code name from class name. We don't support anonymous classes." }
37
39
 
40
+ @Suppress("Deprecation")
38
41
  return "ERR_" + name
39
42
  .replace("(Exception)$".toRegex(), "")
40
43
  .replace("(.)([A-Z])".toRegex(), "$1_$2")
@@ -43,6 +46,21 @@ open class CodedException(
43
46
  }
44
47
  }
45
48
 
49
+ /**
50
+ * Infers error code from the exception class name -
51
+ * e.g. the code of `ModuleNotFoundException` becomes `ERR_MODULE_NOT_FOUND`.
52
+ *
53
+ * Example:
54
+ * ```kt
55
+ * class NoPermissionException : CodedException()
56
+ * val errorCode = errorCodeOf<NoPermissionException>() // ERR_NO_PERMISSION
57
+ * ```
58
+ *
59
+ * **Note**: This works only if the exception class didn't overwrite the error code manually.
60
+ */
61
+ inline fun <reified T : CodedException> errorCodeOf(): String =
62
+ CodedException.inferCode(T::class.java)
63
+
46
64
  internal class IncompatibleArgTypeException(
47
65
  argumentType: KType,
48
66
  desiredType: KType,
@@ -67,9 +85,15 @@ internal class MethodNotFoundException :
67
85
  internal class NullArgumentException :
68
86
  CodedException(message = "Cannot assigned null to not nullable type.")
69
87
 
88
+ internal class FieldRequiredException(property: KProperty1<*, *>) :
89
+ CodedException(message = "Value for field '$property' is required, got nil")
90
+
70
91
  internal class UnexpectedException(val throwable: Throwable) :
71
92
  CodedException(message = throwable.toString(), throwable)
72
93
 
94
+ internal class ValidationException(message: String) :
95
+ CodedException(message = message)
96
+
73
97
  /**
74
98
  * A base class for all exceptions used in `exceptionDecorator` function.
75
99
  */
@@ -1,6 +1,7 @@
1
- package expo.modules.kotlin.methods
1
+ package expo.modules.kotlin.functions
2
2
 
3
3
  import com.facebook.react.bridge.ReadableArray
4
+ import expo.modules.kotlin.ModuleHolder
4
5
  import expo.modules.kotlin.Promise
5
6
  import expo.modules.kotlin.exception.ArgumentCastException
6
7
  import expo.modules.kotlin.exception.CodedException
@@ -10,22 +11,22 @@ import expo.modules.kotlin.iterator
10
11
  import expo.modules.kotlin.recycle
11
12
  import expo.modules.kotlin.types.AnyType
12
13
 
13
- abstract class AnyMethod(
14
+ abstract class AnyFunction(
14
15
  protected val name: String,
15
16
  private val desiredArgsTypes: Array<AnyType>
16
17
  ) {
17
18
  @Throws(CodedException::class)
18
- fun call(args: ReadableArray, promise: Promise) {
19
+ fun call(module: ModuleHolder, args: ReadableArray, promise: Promise) {
19
20
  if (desiredArgsTypes.size != args.size()) {
20
21
  throw InvalidArgsNumberException(args.size(), desiredArgsTypes.size)
21
22
  }
22
23
 
23
24
  val convertedArgs = convertArgs(args)
24
- callImplementation(convertedArgs, promise)
25
+ callImplementation(module, convertedArgs, promise)
25
26
  }
26
27
 
27
28
  @Throws(CodedException::class)
28
- internal abstract fun callImplementation(args: Array<out Any?>, promise: Promise)
29
+ internal abstract fun callImplementation(holder: ModuleHolder, args: Array<out Any?>, promise: Promise)
29
30
 
30
31
  val argsCount get() = desiredArgsTypes.size
31
32
 
@@ -0,0 +1,15 @@
1
+ package expo.modules.kotlin.functions
2
+
3
+ import expo.modules.kotlin.ModuleHolder
4
+ import expo.modules.kotlin.Promise
5
+ import expo.modules.kotlin.types.AnyType
6
+
7
+ class AsyncFunction(
8
+ name: String,
9
+ argsType: Array<AnyType>,
10
+ private val body: (args: Array<out Any?>) -> Any?
11
+ ) : AnyFunction(name, argsType) {
12
+ override fun callImplementation(holder: ModuleHolder, args: Array<out Any?>, promise: Promise) {
13
+ promise.resolve(body(args))
14
+ }
15
+ }
@@ -0,0 +1,61 @@
1
+ @file:OptIn(ExperimentalStdlibApi::class)
2
+
3
+ package expo.modules.kotlin.functions
4
+
5
+ import expo.modules.kotlin.types.toAnyType
6
+ import kotlin.reflect.typeOf
7
+
8
+ class AsyncFunctionBuilder(val name: String) {
9
+ @PublishedApi
10
+ internal var function: AnyFunction? = null
11
+
12
+ inline fun <reified R> suspendBody(crossinline block: suspend () -> R) {
13
+ function = AsyncSuspendFunction(name, arrayOf()) { block() }
14
+ }
15
+
16
+ inline fun <reified R, reified P0> suspendBody(crossinline block: suspend (p0: P0) -> R) {
17
+ function = AsyncSuspendFunction(name, arrayOf(typeOf<P0>().toAnyType())) { block(it[0] as P0) }
18
+ }
19
+
20
+ inline fun <reified R, reified P0, reified P1> suspendBody(crossinline block: suspend (p0: P0, p1: P1) -> R) {
21
+ function = AsyncSuspendFunction(name, arrayOf(typeOf<P0>().toAnyType())) { block(it[0] as P0, it[0] as P1) }
22
+ }
23
+
24
+ inline fun <reified R, reified P0, reified P1, reified P2> suspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2) -> R) {
25
+ function = AsyncSuspendFunction(name, arrayOf(typeOf<P0>().toAnyType())) { block(it[0] as P0, it[1] as P1, it[2] as P2) }
26
+ }
27
+
28
+ inline fun <reified R, reified P0, reified P1, reified P2, reified P3> suspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2, p3: P3) -> R) {
29
+ function = AsyncSuspendFunction(name, arrayOf(typeOf<P0>().toAnyType())) { block(it[0] as P0, it[1] as P1, it[2] as P2, it[3] as P3) }
30
+ }
31
+
32
+ inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4> suspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) -> R) {
33
+ function = AsyncSuspendFunction(name, arrayOf(typeOf<P0>().toAnyType())) { block(it[0] as P0, it[1] as P1, it[2] as P2, it[3] as P3, it[4] as P4) }
34
+ }
35
+
36
+ inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5> suspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) -> R) {
37
+ function = AsyncSuspendFunction(name, arrayOf(typeOf<P0>().toAnyType())) { block(it[0] as P0, it[1] as P1, it[2] as P2, it[3] as P3, it[4] as P4, it[5] as P5) }
38
+ }
39
+
40
+ inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6> suspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) -> R) {
41
+ function = AsyncSuspendFunction(name, arrayOf(typeOf<P0>().toAnyType())) { block(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) }
42
+ }
43
+
44
+ inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6, reified P7> suspendBody(crossinline block: suspend (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) -> R) {
45
+ function = AsyncSuspendFunction(name, arrayOf(typeOf<P0>().toAnyType())) { block(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) }
46
+ }
47
+
48
+ internal fun build(): Pair<String, AnyFunction> {
49
+ return name to requireNotNull(function)
50
+ }
51
+ }
52
+
53
+ inline infix fun <reified R> AsyncFunctionBuilder.coroutine(crossinline block: suspend () -> R) = suspendBody(block)
54
+ inline infix fun <reified R, reified P0> AsyncFunctionBuilder.coroutine(crossinline block: suspend (P0) -> R) = suspendBody(block)
55
+ inline infix fun <reified R, reified P0, reified P1> AsyncFunctionBuilder.coroutine(crossinline block: suspend (P0, P1) -> R) = suspendBody(block)
56
+ inline infix fun <reified R, reified P0, reified P1, reified P2> AsyncFunctionBuilder.coroutine(crossinline block: suspend (P0, P1, P2) -> R) = suspendBody(block)
57
+ inline infix fun <reified R, reified P0, reified P1, reified P2, reified P3> AsyncFunctionBuilder.coroutine(crossinline block: suspend (P0, P1, P2, P3) -> R) = suspendBody(block)
58
+ inline infix fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4> AsyncFunctionBuilder.coroutine(crossinline block: suspend (P0, P1, P2, P3, P4) -> R) = suspendBody(block)
59
+ inline infix fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5> AsyncFunctionBuilder.coroutine(crossinline block: suspend (P0, P1, P2, P3, P4, P5) -> R) = suspendBody(block)
60
+ inline infix fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6> AsyncFunctionBuilder.coroutine(crossinline block: suspend (P0, P1, P2, P3, P4, P5, P6) -> R) = suspendBody(block)
61
+ inline infix fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6, reified P7> AsyncFunctionBuilder.coroutine(crossinline block: suspend (P0, P1, P2, P3, P4, P5, P6, P7) -> R) = suspendBody(block)
@@ -0,0 +1,15 @@
1
+ package expo.modules.kotlin.functions
2
+
3
+ import expo.modules.kotlin.ModuleHolder
4
+ import expo.modules.kotlin.Promise
5
+ import expo.modules.kotlin.types.AnyType
6
+
7
+ class AsyncFunctionWithPromise(
8
+ name: String,
9
+ argsType: Array<AnyType>,
10
+ private val body: (args: Array<out Any?>, promise: Promise) -> Unit
11
+ ) : AnyFunction(name, argsType) {
12
+ override fun callImplementation(holder: ModuleHolder, args: Array<out Any?>, promise: Promise) {
13
+ body(args, promise)
14
+ }
15
+ }
@@ -0,0 +1,36 @@
1
+ package expo.modules.kotlin.functions
2
+
3
+ import expo.modules.kotlin.ModuleHolder
4
+ import expo.modules.kotlin.Promise
5
+ import expo.modules.kotlin.exception.CodedException
6
+ import expo.modules.kotlin.exception.FunctionCallException
7
+ import expo.modules.kotlin.exception.UnexpectedException
8
+ import expo.modules.kotlin.exception.exceptionDecorator
9
+ import expo.modules.kotlin.types.AnyType
10
+ import kotlinx.coroutines.CoroutineScope
11
+ import kotlinx.coroutines.isActive
12
+ import kotlinx.coroutines.launch
13
+
14
+ class AsyncSuspendFunction(
15
+ name: String,
16
+ argsType: Array<AnyType>,
17
+ private val body: suspend CoroutineScope.(args: Array<out Any?>) -> Any?
18
+ ) : AnyFunction(name, argsType) {
19
+ override fun callImplementation(holder: ModuleHolder, args: Array<out Any?>, promise: Promise) {
20
+ val scope = holder.module.coroutineScopeDelegate.value
21
+ scope.launch {
22
+ try {
23
+ val result = exceptionDecorator({ cause -> FunctionCallException(name, holder.name, cause) }) {
24
+ body.invoke(scope, args)
25
+ }
26
+ if (isActive) {
27
+ promise.resolve(result)
28
+ }
29
+ } catch (e: CodedException) {
30
+ promise.reject(e)
31
+ } catch (e: Throwable) {
32
+ promise.reject(UnexpectedException(e))
33
+ }
34
+ }
35
+ }
36
+ }
@@ -1,7 +1,10 @@
1
1
  package expo.modules.kotlin.modules
2
2
 
3
3
  import android.os.Bundle
4
+ import expo.modules.core.errors.ModuleDestroyedException
4
5
  import expo.modules.kotlin.AppContext
6
+ import kotlinx.coroutines.CoroutineScope
7
+ import kotlinx.coroutines.cancel
5
8
 
6
9
  abstract class Module {
7
10
  @Suppress("PropertyName")
@@ -12,11 +15,22 @@ abstract class Module {
12
15
  val appContext: AppContext
13
16
  get() = requireNotNull(_appContext) { "The module wasn't created! You can't access the app context." }
14
17
 
18
+ @Suppress("PropertyName")
19
+ @PublishedApi
20
+ internal lateinit var coroutineScopeDelegate: Lazy<CoroutineScope>
21
+ val coroutineScope get() = coroutineScopeDelegate.value
22
+
15
23
  fun sendEvent(name: String, body: Bundle?) {
16
24
  moduleEventEmitter?.emit(name, body)
17
25
  }
18
26
 
19
27
  abstract fun definition(): ModuleDefinitionData
28
+
29
+ internal fun cleanUp() {
30
+ if (coroutineScopeDelegate.isInitialized()) {
31
+ coroutineScope.cancel(ModuleDestroyedException())
32
+ }
33
+ }
20
34
  }
21
35
 
22
36
  @Suppress("FunctionName")