expo-modules-core 0.4.6 → 0.6.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.
- package/CHANGELOG.md +39 -0
- package/README.md +6 -6
- package/android/build.gradle +30 -2
- package/android/src/main/java/expo/modules/adapters/react/ModuleRegistryAdapter.java +27 -5
- package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +49 -5
- package/android/src/main/java/expo/modules/core/BasePackage.java +6 -0
- package/android/src/main/java/expo/modules/core/ModulePriorities.kt +25 -0
- package/android/src/main/java/expo/modules/core/interfaces/ActivityEventListener.java +3 -1
- package/android/src/main/java/expo/modules/core/interfaces/ApplicationLifecycleListener.java +10 -0
- package/android/src/main/java/expo/modules/core/interfaces/Package.java +4 -0
- package/android/src/main/java/expo/modules/core/interfaces/ReactActivityHandler.java +21 -0
- package/android/src/main/java/expo/modules/core/interfaces/ReactActivityLifecycleListener.java +14 -0
- package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.java +70 -0
- package/android/src/main/java/expo/modules/core/utilities/KotlinUtilities.kt +23 -0
- package/android/src/main/java/expo/modules/kotlin/AppContext.kt +166 -0
- package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +9 -0
- package/android/src/main/java/expo/modules/kotlin/ExpoModulesHelper.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +24 -0
- package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +98 -0
- package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +41 -0
- package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +56 -0
- package/android/src/main/java/expo/modules/kotlin/ModulesProvider.kt +7 -0
- package/android/src/main/java/expo/modules/kotlin/Promise.kt +13 -0
- package/android/src/main/java/expo/modules/kotlin/ReactLifecycleDelegate.kt +39 -0
- package/android/src/main/java/expo/modules/kotlin/ReadableArrayIterator.kt +14 -0
- package/android/src/main/java/expo/modules/kotlin/ReadableTypeExtensions.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/allocators/ObjectConstructor.kt +5 -0
- package/android/src/main/java/expo/modules/kotlin/allocators/ObjectConstructorFactory.kt +31 -0
- package/android/src/main/java/expo/modules/kotlin/allocators/UnsafeAllocator.kt +49 -0
- package/android/src/main/java/expo/modules/kotlin/events/EventListener.kt +39 -0
- package/android/src/main/java/expo/modules/kotlin/events/EventName.kt +31 -0
- package/android/src/main/java/expo/modules/kotlin/events/EventsDefinition.kt +3 -0
- package/android/src/main/java/expo/modules/kotlin/events/KEventEmitterWrapper.kt +26 -0
- package/android/src/main/java/expo/modules/kotlin/events/OnActivityResultPayload.kt +8 -0
- package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +70 -0
- package/android/src/main/java/expo/modules/kotlin/methods/AnyMethod.kt +50 -0
- package/android/src/main/java/expo/modules/kotlin/methods/Method.kt +14 -0
- package/android/src/main/java/expo/modules/kotlin/methods/PromiseMethod.kt +15 -0
- package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +24 -0
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +227 -0
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +16 -0
- package/android/src/main/java/expo/modules/kotlin/records/Field.kt +5 -0
- package/android/src/main/java/expo/modules/kotlin/records/Record.kt +3 -0
- package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +55 -0
- package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +14 -0
- package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +44 -0
- package/android/src/main/java/expo/modules/kotlin/types/BasicTypeConverters.kt +60 -0
- package/android/src/main/java/expo/modules/kotlin/types/EnumTypeConverter.kt +84 -0
- package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +25 -0
- package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +39 -0
- package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +28 -0
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +19 -0
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +107 -0
- package/android/src/main/java/expo/modules/kotlin/views/AnyViewProp.kt +10 -0
- package/android/src/main/java/expo/modules/kotlin/views/ConcreteViewProp.kt +17 -0
- package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +22 -0
- package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +21 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +41 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +40 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +21 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewWrapperDelegateHolder.kt +5 -0
- package/build/NativeModulesProxy.native.d.ts +4 -0
- package/build/NativeModulesProxy.native.js +14 -1
- package/build/NativeModulesProxy.native.js.map +1 -1
- package/build/NativeModulesProxy.types.d.ts +3 -0
- package/build/NativeModulesProxy.types.js.map +1 -1
- package/build/NativeViewManagerAdapter.native.js +1 -1
- package/build/NativeViewManagerAdapter.native.js.map +1 -1
- package/ios/AppDelegates/EXAppDelegateWrapper.h +19 -0
- package/ios/AppDelegates/EXAppDelegateWrapper.m +45 -0
- package/ios/AppDelegates/EXAppDelegatesLoader.h +15 -0
- package/ios/AppDelegates/EXAppDelegatesLoader.m +30 -0
- package/ios/AppDelegates/EXLegacyAppDelegateWrapper.h +16 -0
- package/ios/{EXAppDelegateWrapper.m → AppDelegates/EXLegacyAppDelegateWrapper.m} +2 -2
- package/ios/AppDelegates/ExpoAppDelegate.swift +282 -0
- package/ios/AppDelegates/ExpoAppDelegateSubscriber.swift +24 -0
- package/ios/EXAppDefines.h +26 -0
- package/ios/EXAppDefines.m +61 -0
- package/ios/ExpoModulesCore.podspec +8 -3
- package/ios/JSI/ExpoModulesProxySpec.h +24 -0
- package/ios/JSI/ExpoModulesProxySpec.mm +135 -0
- package/ios/JSI/JSIConversions.h +42 -0
- package/ios/JSI/JSIConversions.mm +164 -0
- package/ios/JSI/JSIInstaller.h +19 -0
- package/ios/JSI/JSIInstaller.mm +22 -0
- package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +1 -6
- package/ios/NativeModulesProxy/EXNativeModulesProxy.h +6 -0
- package/ios/NativeModulesProxy/{EXNativeModulesProxy.m → EXNativeModulesProxy.mm} +91 -18
- package/ios/ReactDelegates/EXRCTBridgeDelegateInterceptor.h +16 -0
- package/ios/ReactDelegates/EXRCTBridgeDelegateInterceptor.m +49 -0
- package/ios/ReactDelegates/EXReactDelegateWrapper+Private.h +18 -0
- package/ios/ReactDelegates/EXReactDelegateWrapper.h +25 -0
- package/ios/ReactDelegates/EXReactDelegateWrapper.m +40 -0
- package/ios/ReactDelegates/ExpoReactDelegate.swift +37 -0
- package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +52 -0
- package/ios/ReactDelegates/ModulePriorities.swift +20 -0
- package/ios/Services/EXReactNativeEventEmitter.h +6 -0
- package/ios/Services/EXReactNativeEventEmitter.m +15 -0
- package/ios/Swift/AppContext.swift +14 -1
- package/ios/Swift/Arguments/AnyArgument.swift +14 -0
- package/ios/Swift/Arguments/AnyArgumentType.swift +13 -0
- package/ios/Swift/Arguments/ArgumentType.swift +24 -0
- package/ios/Swift/Arguments/ConvertibleArgument.swift +15 -0
- package/ios/Swift/Arguments/Convertibles.swift +107 -0
- package/ios/Swift/Arguments/Types/ArrayArgumentType.swift +42 -0
- package/ios/Swift/Arguments/Types/ConvertibleArgumentType.swift +16 -0
- package/ios/Swift/Arguments/Types/EnumArgumentType.swift +105 -0
- package/ios/Swift/Arguments/Types/OptionalArgumentType.swift +49 -0
- package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +15 -0
- package/ios/Swift/Arguments/Types/RawArgumentType.swift +25 -0
- package/ios/Swift/Conversions.swift +199 -7
- package/ios/Swift/EventListener.swift +37 -5
- package/ios/Swift/Functions/AnyFunction.swift +42 -0
- package/ios/Swift/{Methods/ConcreteMethod.swift → Functions/ConcreteFunction.swift} +32 -34
- package/ios/Swift/ModuleHolder.swift +86 -20
- package/ios/Swift/ModuleRegistry.swift +19 -8
- package/ios/Swift/Modules/AnyModule.swift +8 -8
- package/ios/Swift/Modules/Module.swift +11 -0
- package/ios/Swift/Modules/ModuleDefinition.swift +55 -15
- package/ios/Swift/Modules/ModuleDefinitionBuilder.swift +1 -1
- package/ios/Swift/Modules/ModuleDefinitionComponents.swift +149 -54
- package/ios/Swift/ModulesProvider.swift +19 -0
- package/ios/Swift/Promise.swift +1 -1
- package/ios/Swift/Records/Field.swift +1 -1
- package/ios/Swift/Records/Record.swift +8 -1
- package/ios/Swift/SwiftInteropBridge.swift +46 -17
- package/ios/Swift/Views/AnyViewProp.swift +2 -2
- package/ios/Swift/Views/ConcreteViewProp.swift +37 -10
- package/ios/Swift/Views/ViewModuleWrapper.swift +9 -4
- package/ios/Swift.h +9 -0
- package/ios/Tests/ArgumentTypeSpec.swift +145 -0
- package/ios/Tests/ConstantsSpec.swift +36 -0
- package/ios/Tests/ConvertiblesSpec.swift +265 -0
- package/ios/Tests/EXAppDefinesTest.m +99 -0
- package/ios/Tests/{MethodSpec.swift → FunctionSpec.swift} +69 -54
- package/ios/Tests/FunctionWithConvertiblesSpec.swift +66 -0
- package/ios/Tests/Mocks/ModuleMocks.swift +21 -7
- package/ios/Tests/ModuleEventListenersSpec.swift +17 -16
- package/ios/Tests/ModuleRegistrySpec.swift +4 -7
- package/package.json +3 -3
- package/src/NativeModulesProxy.native.ts +22 -2
- package/src/NativeModulesProxy.types.ts +8 -0
- package/src/NativeViewManagerAdapter.native.tsx +1 -1
- package/android/src/main/java/expo/modules/core/interfaces/ApplicationLifecycleListener.kt +0 -9
- package/android/src/main/java/expo/modules/core/interfaces/ReactActivityLifecycleListener.kt +0 -11
- package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.kt +0 -51
- package/ios/EXAppDelegateWrapper.h +0 -13
- package/ios/Swift/Methods/AnyArgumentType.swift +0 -48
- package/ios/Swift/Methods/AnyMethod.swift +0 -31
- package/ios/Swift/Methods/AnyMethodArgument.swift +0 -13
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
package expo.modules.kotlin.events
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle
|
|
4
|
+
import expo.modules.core.interfaces.services.EventEmitter
|
|
5
|
+
import expo.modules.kotlin.ModuleHolder
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* In Swift, we check if the event is supported. Otherwise, we can't send such event through the bridge.
|
|
9
|
+
* However, in Kotlin this is unnecessary, but to make our API consistent, we added similar check.
|
|
10
|
+
* But because of that, we had to create a wrapper for EventEmitter.
|
|
11
|
+
*/
|
|
12
|
+
class KEventEmitterWrapper(
|
|
13
|
+
private val moduleHolder: ModuleHolder,
|
|
14
|
+
private val legacyEventEmitter: EventEmitter
|
|
15
|
+
) : EventEmitter by legacyEventEmitter {
|
|
16
|
+
override fun emit(eventName: String, eventBody: Bundle?) {
|
|
17
|
+
require(
|
|
18
|
+
moduleHolder
|
|
19
|
+
.definition
|
|
20
|
+
.eventsDefinition
|
|
21
|
+
?.names
|
|
22
|
+
?.contains(eventName) == true
|
|
23
|
+
) { "Unsupported event: $eventName." }
|
|
24
|
+
legacyEventEmitter.emit(eventName, eventBody)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
package expo.modules.kotlin.exception
|
|
2
|
+
|
|
3
|
+
import java.util.*
|
|
4
|
+
import kotlin.reflect.KType
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A class for errors specifying its `code` and providing the `description`.
|
|
8
|
+
*/
|
|
9
|
+
open class CodedException(
|
|
10
|
+
message: String?,
|
|
11
|
+
cause: Throwable?
|
|
12
|
+
) : Exception(message, cause) {
|
|
13
|
+
// We need that secondary property, cause we can't access
|
|
14
|
+
// the javaClass property in the constructor.
|
|
15
|
+
private var providedCode: String? = null
|
|
16
|
+
|
|
17
|
+
val code
|
|
18
|
+
get() = providedCode ?: inferCode(javaClass)
|
|
19
|
+
|
|
20
|
+
constructor(code: String, message: String, cause: Throwable?) : this(message, cause) {
|
|
21
|
+
providedCode = code
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
constructor(message: String) : this(message, null)
|
|
25
|
+
|
|
26
|
+
constructor(cause: Throwable) : this(cause.localizedMessage, cause)
|
|
27
|
+
|
|
28
|
+
constructor() : this(null, null)
|
|
29
|
+
|
|
30
|
+
companion object {
|
|
31
|
+
/**
|
|
32
|
+
* The code is inferred from the class name — e.g. the code of `ModuleNotFoundException` becomes `ERR_MODULE_NOT_FOUND`.
|
|
33
|
+
*/
|
|
34
|
+
private fun inferCode(clazz: Class<*>): String {
|
|
35
|
+
val name = requireNotNull(clazz.simpleName) { "Cannot infer code name from class name. We don't support anonymous classes." }
|
|
36
|
+
|
|
37
|
+
return "ERR_" + name
|
|
38
|
+
.replace("(Exception)$".toRegex(), "")
|
|
39
|
+
.replace("(.)([A-Z])".toRegex(), "$1_$2")
|
|
40
|
+
.toUpperCase(Locale.ROOT)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
internal class IncompatibleArgTypeException(
|
|
46
|
+
argumentType: KType,
|
|
47
|
+
desiredType: KType,
|
|
48
|
+
cause: Throwable? = null
|
|
49
|
+
) : CodedException(
|
|
50
|
+
message = "Argument type $argumentType is not compatible with expected type $desiredType.",
|
|
51
|
+
cause = cause
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
internal class MissingTypeConverter(
|
|
55
|
+
forType: KType
|
|
56
|
+
) : CodedException(
|
|
57
|
+
message = "Cannot find type converter for $forType.",
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
internal class InvalidArgsNumberException(received: Int, expected: Int) :
|
|
61
|
+
CodedException(message = "Received $received arguments, but $expected was expected.")
|
|
62
|
+
|
|
63
|
+
internal class MethodNotFoundException(methodName: String, moduleName: String) :
|
|
64
|
+
CodedException(message = "Cannot fund method $methodName in module $moduleName")
|
|
65
|
+
|
|
66
|
+
internal class NullArgumentException(desiredType: KType) :
|
|
67
|
+
CodedException(message = "Cannot assigned null to not nullable type $desiredType")
|
|
68
|
+
|
|
69
|
+
internal class UnexpectedException(val throwable: Throwable) :
|
|
70
|
+
CodedException(throwable)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
package expo.modules.kotlin.methods
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReadableArray
|
|
4
|
+
import expo.modules.kotlin.Promise
|
|
5
|
+
import expo.modules.kotlin.exception.CodedException
|
|
6
|
+
import expo.modules.kotlin.exception.InvalidArgsNumberException
|
|
7
|
+
import expo.modules.kotlin.exception.UnexpectedException
|
|
8
|
+
import expo.modules.kotlin.iterator
|
|
9
|
+
import expo.modules.kotlin.recycle
|
|
10
|
+
import expo.modules.kotlin.types.AnyType
|
|
11
|
+
import kotlin.jvm.Throws
|
|
12
|
+
|
|
13
|
+
abstract class AnyMethod(
|
|
14
|
+
protected val name: String,
|
|
15
|
+
private val desiredArgsTypes: Array<AnyType>
|
|
16
|
+
) {
|
|
17
|
+
fun call(args: ReadableArray, promise: Promise) {
|
|
18
|
+
if (desiredArgsTypes.size != args.size()) {
|
|
19
|
+
promise.reject(InvalidArgsNumberException(args.size(), desiredArgsTypes.size))
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
val convertedArgs = convertArgs(args)
|
|
24
|
+
callImplementation(convertedArgs, promise)
|
|
25
|
+
} catch (codedError: CodedException) {
|
|
26
|
+
promise.reject(codedError)
|
|
27
|
+
} catch (e: Throwable) {
|
|
28
|
+
promise.reject(UnexpectedException(e))
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@Throws(CodedException::class)
|
|
33
|
+
internal abstract fun callImplementation(args: Array<out Any?>, promise: Promise)
|
|
34
|
+
|
|
35
|
+
val argsCount get() = desiredArgsTypes.size
|
|
36
|
+
|
|
37
|
+
@Throws(CodedException::class)
|
|
38
|
+
private fun convertArgs(args: ReadableArray): Array<out Any?> {
|
|
39
|
+
val finalArgs = Array<Any?>(desiredArgsTypes.size) { null }
|
|
40
|
+
val argIterator = args.iterator()
|
|
41
|
+
desiredArgsTypes
|
|
42
|
+
.withIndex()
|
|
43
|
+
.forEach { (index, type) ->
|
|
44
|
+
argIterator.next().recycle {
|
|
45
|
+
finalArgs[index] = type.convert(this)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return finalArgs
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
package expo.modules.kotlin.methods
|
|
2
|
+
|
|
3
|
+
import expo.modules.kotlin.Promise
|
|
4
|
+
import expo.modules.kotlin.types.AnyType
|
|
5
|
+
|
|
6
|
+
class Method(
|
|
7
|
+
name: String,
|
|
8
|
+
argsType: Array<AnyType>,
|
|
9
|
+
private val body: (args: Array<out Any?>) -> Any?
|
|
10
|
+
) : AnyMethod(name, argsType) {
|
|
11
|
+
override fun callImplementation(args: Array<out Any?>, promise: Promise) {
|
|
12
|
+
promise.resolve(body(args))
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
package expo.modules.kotlin.methods
|
|
2
|
+
|
|
3
|
+
import expo.modules.kotlin.Promise
|
|
4
|
+
import expo.modules.kotlin.types.AnyType
|
|
5
|
+
|
|
6
|
+
class PromiseMethod(
|
|
7
|
+
name: String,
|
|
8
|
+
argsType: Array<AnyType>,
|
|
9
|
+
private val body: (args: Array<out Any?>, promise: Promise) -> Unit
|
|
10
|
+
) : AnyMethod(name, argsType) {
|
|
11
|
+
|
|
12
|
+
override fun callImplementation(args: Array<out Any?>, promise: Promise) {
|
|
13
|
+
body(args, promise)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
package expo.modules.kotlin.modules
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle
|
|
4
|
+
import expo.modules.kotlin.AppContext
|
|
5
|
+
|
|
6
|
+
abstract class Module {
|
|
7
|
+
internal var _appContext: AppContext? = null
|
|
8
|
+
|
|
9
|
+
private val moduleEventEmitter by lazy { appContext.eventEmitter(this) }
|
|
10
|
+
|
|
11
|
+
val appContext: AppContext
|
|
12
|
+
get() = requireNotNull(_appContext) { "The module wasn't created! You can't access the app context." }
|
|
13
|
+
|
|
14
|
+
fun sendEvent(name: String, body: Bundle?) {
|
|
15
|
+
moduleEventEmitter?.emit(name, body)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
abstract fun definition(): ModuleDefinitionData
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@Suppress("FunctionName")
|
|
22
|
+
inline fun ModuleDefinition(block: ModuleDefinitionBuilder.() -> Unit): ModuleDefinitionData {
|
|
23
|
+
return ModuleDefinitionBuilder().also(block).build()
|
|
24
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
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
|
+
|
|
14
|
+
package expo.modules.kotlin.modules
|
|
15
|
+
|
|
16
|
+
import android.app.Activity
|
|
17
|
+
import android.content.Intent
|
|
18
|
+
import expo.modules.kotlin.Promise
|
|
19
|
+
import expo.modules.kotlin.events.BasicEventListener
|
|
20
|
+
import expo.modules.kotlin.events.EventListener
|
|
21
|
+
import expo.modules.kotlin.events.EventListenerWithPayload
|
|
22
|
+
import expo.modules.kotlin.events.EventListenerWithSenderAndPayload
|
|
23
|
+
import expo.modules.kotlin.events.EventName
|
|
24
|
+
import expo.modules.kotlin.events.EventsDefinition
|
|
25
|
+
import expo.modules.kotlin.events.OnActivityResultPayload
|
|
26
|
+
import expo.modules.kotlin.methods.AnyMethod
|
|
27
|
+
import expo.modules.kotlin.methods.Method
|
|
28
|
+
import expo.modules.kotlin.methods.PromiseMethod
|
|
29
|
+
import expo.modules.kotlin.types.toAnyType
|
|
30
|
+
import expo.modules.kotlin.views.ViewManagerDefinition
|
|
31
|
+
import expo.modules.kotlin.views.ViewManagerDefinitionBuilder
|
|
32
|
+
import kotlin.reflect.typeOf
|
|
33
|
+
|
|
34
|
+
class ModuleDefinitionBuilder {
|
|
35
|
+
private var name: String? = null
|
|
36
|
+
private var constantsProvider = { emptyMap<String, Any?>() }
|
|
37
|
+
private var eventsDefinition: EventsDefinition? = null
|
|
38
|
+
|
|
39
|
+
@PublishedApi
|
|
40
|
+
internal var methods = mutableMapOf<String, AnyMethod>()
|
|
41
|
+
|
|
42
|
+
@PublishedApi
|
|
43
|
+
internal var viewManagerDefinition: ViewManagerDefinition? = null
|
|
44
|
+
|
|
45
|
+
@PublishedApi
|
|
46
|
+
internal val eventListeners = mutableMapOf<EventName, EventListener>()
|
|
47
|
+
|
|
48
|
+
fun build(): ModuleDefinitionData {
|
|
49
|
+
return ModuleDefinitionData(
|
|
50
|
+
requireNotNull(name),
|
|
51
|
+
constantsProvider,
|
|
52
|
+
methods,
|
|
53
|
+
viewManagerDefinition,
|
|
54
|
+
eventListeners,
|
|
55
|
+
eventsDefinition
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
fun name(name: String) {
|
|
60
|
+
this.name = name
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
fun constants(constantsProvider: () -> Map<String, Any?>) {
|
|
64
|
+
this.constantsProvider = constantsProvider
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@JvmName("methodWithoutArgs")
|
|
68
|
+
inline fun function(
|
|
69
|
+
name: String,
|
|
70
|
+
crossinline body: () -> Any?
|
|
71
|
+
) {
|
|
72
|
+
methods[name] = Method(name, arrayOf()) { body() }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
inline fun <reified R> function(
|
|
76
|
+
name: String,
|
|
77
|
+
crossinline body: () -> R
|
|
78
|
+
) {
|
|
79
|
+
methods[name] = Method(name, arrayOf()) { body() }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
inline fun <reified R, reified P0> function(
|
|
83
|
+
name: String,
|
|
84
|
+
crossinline body: (p0: P0) -> R
|
|
85
|
+
) {
|
|
86
|
+
methods[name] = if (P0::class == Promise::class) {
|
|
87
|
+
PromiseMethod(name, arrayOf()) { _, promise -> body(promise as P0) }
|
|
88
|
+
} else {
|
|
89
|
+
Method(name, arrayOf(typeOf<P0>().toAnyType())) { body(it[0] as P0) }
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
inline fun <reified R, reified P0, reified P1> function(
|
|
94
|
+
name: String,
|
|
95
|
+
crossinline body: (p0: P0, p1: P1) -> R
|
|
96
|
+
) {
|
|
97
|
+
methods[name] = if (P1::class == Promise::class) {
|
|
98
|
+
PromiseMethod(name, arrayOf(typeOf<P0>().toAnyType())) { args, promise -> body(args[0] as P0, promise as P1) }
|
|
99
|
+
} else {
|
|
100
|
+
Method(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType())) { body(it[0] as P0, it[1] as P1) }
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
inline fun <reified R, reified P0, reified P1, reified P2> function(
|
|
105
|
+
name: String,
|
|
106
|
+
crossinline body: (p0: P0, p1: P1, p2: P2) -> R
|
|
107
|
+
) {
|
|
108
|
+
methods[name] = if (P2::class == Promise::class) {
|
|
109
|
+
PromiseMethod(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType())) { args, promise -> body(args[0] as P0, args[1] as P1, promise as P2) }
|
|
110
|
+
} else {
|
|
111
|
+
Method(name, arrayOf(typeOf<P0>().toAnyType(), typeOf<P1>().toAnyType(), typeOf<P2>().toAnyType())) { body(it[0] as P0, it[1] as P1, it[2] as P2) }
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
inline fun <reified R, reified P0, reified P1, reified P2, reified P3> function(
|
|
116
|
+
name: String,
|
|
117
|
+
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3) -> R
|
|
118
|
+
) {
|
|
119
|
+
methods[name] = if (P3::class == Promise::class) {
|
|
120
|
+
PromiseMethod(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) }
|
|
121
|
+
} else {
|
|
122
|
+
Method(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) }
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4> function(
|
|
127
|
+
name: String,
|
|
128
|
+
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) -> R
|
|
129
|
+
) {
|
|
130
|
+
methods[name] = if (P4::class == Promise::class) {
|
|
131
|
+
PromiseMethod(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) }
|
|
132
|
+
} else {
|
|
133
|
+
Method(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) }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5> function(
|
|
138
|
+
name: String,
|
|
139
|
+
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) -> R
|
|
140
|
+
) {
|
|
141
|
+
methods[name] = if (P5::class == Promise::class) {
|
|
142
|
+
PromiseMethod(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) }
|
|
143
|
+
} else {
|
|
144
|
+
Method(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) }
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6> function(
|
|
149
|
+
name: String,
|
|
150
|
+
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) -> R
|
|
151
|
+
) {
|
|
152
|
+
methods[name] = if (P6::class == Promise::class) {
|
|
153
|
+
PromiseMethod(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) }
|
|
154
|
+
} else {
|
|
155
|
+
Method(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) }
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6, reified P7> function(
|
|
160
|
+
name: String,
|
|
161
|
+
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) -> R
|
|
162
|
+
) {
|
|
163
|
+
methods[name] = if (P7::class == Promise::class) {
|
|
164
|
+
PromiseMethod(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) }
|
|
165
|
+
} else {
|
|
166
|
+
Method(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) }
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
inline fun viewManager(body: ViewManagerDefinitionBuilder.() -> Unit) {
|
|
171
|
+
require(viewManagerDefinition == null) { "The module definition may have exported only one view manager." }
|
|
172
|
+
|
|
173
|
+
val viewManagerDefinitionBuilder = ViewManagerDefinitionBuilder()
|
|
174
|
+
body.invoke(viewManagerDefinitionBuilder)
|
|
175
|
+
viewManagerDefinition = viewManagerDefinitionBuilder.build()
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
inline fun onCreate(crossinline body: () -> Unit) {
|
|
179
|
+
eventListeners[EventName.MODULE_CREATE] = BasicEventListener(EventName.MODULE_CREATE) { body() }
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
inline fun onDestroy(crossinline body: () -> Unit) {
|
|
183
|
+
eventListeners[EventName.MODULE_DESTROY] = BasicEventListener(EventName.MODULE_DESTROY) { body() }
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
inline fun onActivityEntersForeground(crossinline body: () -> Unit) {
|
|
187
|
+
eventListeners[EventName.ACTIVITY_ENTERS_FOREGROUND] = BasicEventListener(EventName.ACTIVITY_ENTERS_FOREGROUND) { body() }
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
inline fun onActivityEntersBackground(crossinline body: () -> Unit) {
|
|
191
|
+
eventListeners[EventName.ACTIVITY_ENTERS_BACKGROUND] = BasicEventListener(EventName.ACTIVITY_ENTERS_BACKGROUND) { body() }
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
inline fun onActivityDestroys(crossinline body: () -> Unit) {
|
|
195
|
+
eventListeners[EventName.ACTIVITY_DESTROYS] = BasicEventListener(EventName.ACTIVITY_DESTROYS) { body() }
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Defines event names that this module can send to JavaScript.
|
|
200
|
+
*/
|
|
201
|
+
fun events(vararg events: String) {
|
|
202
|
+
eventsDefinition = EventsDefinition(events)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Method that is invoked when the first event listener is added.
|
|
207
|
+
*/
|
|
208
|
+
inline fun onStartObserving(crossinline body: () -> Unit) {
|
|
209
|
+
function("startObserving", body)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Method that is invoked when all event listeners are removed.
|
|
214
|
+
*/
|
|
215
|
+
inline fun onStopObserving(crossinline body: () -> Unit) {
|
|
216
|
+
function("stopObserving", body)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
inline fun onNewIntent(crossinline body: (Intent) -> Unit) {
|
|
220
|
+
eventListeners[EventName.ON_NEW_INTENT] = EventListenerWithPayload<Intent>(EventName.ON_NEW_INTENT) { body(it) }
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
inline fun onActivityResult(crossinline body: (Activity, OnActivityResultPayload) -> Unit) {
|
|
224
|
+
eventListeners[EventName.ON_ACTIVITY_RESULT] =
|
|
225
|
+
EventListenerWithSenderAndPayload<Activity, OnActivityResultPayload>(EventName.ON_ACTIVITY_RESULT) { sender, payload -> body(sender, payload) }
|
|
226
|
+
}
|
|
227
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package expo.modules.kotlin.modules
|
|
2
|
+
|
|
3
|
+
import expo.modules.kotlin.events.EventListener
|
|
4
|
+
import expo.modules.kotlin.events.EventName
|
|
5
|
+
import expo.modules.kotlin.events.EventsDefinition
|
|
6
|
+
import expo.modules.kotlin.methods.AnyMethod
|
|
7
|
+
import expo.modules.kotlin.views.ViewManagerDefinition
|
|
8
|
+
|
|
9
|
+
class ModuleDefinitionData(
|
|
10
|
+
val name: String,
|
|
11
|
+
val constantsProvider: () -> Map<String, Any?>,
|
|
12
|
+
val methods: Map<String, AnyMethod>,
|
|
13
|
+
val viewManagerDefinition: ViewManagerDefinition? = null,
|
|
14
|
+
val eventListeners: Map<EventName, EventListener> = emptyMap(),
|
|
15
|
+
val eventsDefinition: EventsDefinition? = null
|
|
16
|
+
)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
package expo.modules.kotlin.records
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Dynamic
|
|
4
|
+
import expo.modules.kotlin.allocators.ObjectConstructor
|
|
5
|
+
import expo.modules.kotlin.allocators.ObjectConstructorFactory
|
|
6
|
+
import expo.modules.kotlin.types.TypeConverter
|
|
7
|
+
import expo.modules.kotlin.types.TypeConverterProvider
|
|
8
|
+
import kotlin.reflect.KClass
|
|
9
|
+
import kotlin.reflect.KType
|
|
10
|
+
import kotlin.reflect.full.findAnnotation
|
|
11
|
+
import kotlin.reflect.full.memberProperties
|
|
12
|
+
import kotlin.reflect.jvm.javaField
|
|
13
|
+
|
|
14
|
+
// TODO(@lukmccall): create all converters during initialization
|
|
15
|
+
class RecordTypeConverter<T : Record>(
|
|
16
|
+
private val converterProvider: TypeConverterProvider,
|
|
17
|
+
val type: KType,
|
|
18
|
+
) : TypeConverter<T>(type.isMarkedNullable) {
|
|
19
|
+
private val objectConstructorFactory = ObjectConstructorFactory()
|
|
20
|
+
|
|
21
|
+
override fun convertNonOptional(value: Dynamic): T {
|
|
22
|
+
val jsMap = value.asMap()
|
|
23
|
+
|
|
24
|
+
val kClass = type.classifier as KClass<*>
|
|
25
|
+
val instance = getObjectConstructor(kClass.java).construct()
|
|
26
|
+
|
|
27
|
+
kClass
|
|
28
|
+
.memberProperties
|
|
29
|
+
.map { property ->
|
|
30
|
+
val filedInformation = property.findAnnotation<Field>() ?: return@map
|
|
31
|
+
val jsKey = filedInformation.key.takeUnless { it == "" } ?: property.name
|
|
32
|
+
|
|
33
|
+
if (!jsMap.hasKey(jsKey)) {
|
|
34
|
+
// TODO(@lukmccall): handle required keys
|
|
35
|
+
return@map
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
val value = jsMap.getDynamic(jsKey)
|
|
39
|
+
val javaField = property.javaField!!
|
|
40
|
+
|
|
41
|
+
val elementConverter = converterProvider.obtainTypeConverter(property.returnType)
|
|
42
|
+
val casted = elementConverter.convert(value)
|
|
43
|
+
|
|
44
|
+
javaField.isAccessible = true
|
|
45
|
+
javaField.set(instance, casted)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@Suppress("UNCHECKED_CAST")
|
|
49
|
+
return instance as T
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private fun <T> getObjectConstructor(clazz: Class<T>): ObjectConstructor<T> {
|
|
53
|
+
return objectConstructorFactory.get(clazz)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
package expo.modules.kotlin.types
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Dynamic
|
|
4
|
+
import kotlin.reflect.KType
|
|
5
|
+
|
|
6
|
+
fun KType.toAnyType(): AnyType = AnyType(this)
|
|
7
|
+
|
|
8
|
+
class AnyType(val kType: KType) {
|
|
9
|
+
private val converter: TypeConverter<*> by lazy {
|
|
10
|
+
TypeConverterProviderImpl.obtainTypeConverter(kType)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
fun convert(value: Dynamic): Any? = converter.convert(value)
|
|
14
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
package expo.modules.kotlin.types
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Dynamic
|
|
4
|
+
import expo.modules.kotlin.recycle
|
|
5
|
+
import kotlin.reflect.KClass
|
|
6
|
+
import kotlin.reflect.KType
|
|
7
|
+
|
|
8
|
+
class ArrayTypeConverter(
|
|
9
|
+
converterProvider: TypeConverterProvider,
|
|
10
|
+
private val type: KType,
|
|
11
|
+
) : TypeConverter<Array<*>>(type.isMarkedNullable) {
|
|
12
|
+
private val arrayElementConverter = converterProvider.obtainTypeConverter(
|
|
13
|
+
requireNotNull(type.arguments.first().type) {
|
|
14
|
+
"The array type should contain the type of the elements."
|
|
15
|
+
}
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
override fun convertNonOptional(value: Dynamic): Array<*> {
|
|
19
|
+
val jsArray = value.asArray()
|
|
20
|
+
val array = createTypedArray(jsArray.size())
|
|
21
|
+
for (i in 0 until jsArray.size()) {
|
|
22
|
+
array[i] = jsArray
|
|
23
|
+
.getDynamic(i)
|
|
24
|
+
.recycle {
|
|
25
|
+
arrayElementConverter.convert(this)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return array
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* We can't use a Array<Any?> here. We have to create a typed array.
|
|
33
|
+
* Otherwise, cast which is done before calling lambda provided by the user will always fail.
|
|
34
|
+
* For JVM, Array<String> is a different type than Array<Any?>.
|
|
35
|
+
* The first one is translated to `[Ljava.lang.String;` but the second one is translated to `[java.lang.Object;`.
|
|
36
|
+
*/
|
|
37
|
+
@Suppress("UNCHECKED_CAST")
|
|
38
|
+
private fun createTypedArray(size: Int): Array<Any?> {
|
|
39
|
+
return java.lang.reflect.Array.newInstance(
|
|
40
|
+
(type.arguments.first().type!!.classifier as KClass<*>).java,
|
|
41
|
+
size
|
|
42
|
+
) as Array<Any?>
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
package expo.modules.kotlin.types
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Dynamic
|
|
4
|
+
import com.facebook.react.bridge.ReadableArray
|
|
5
|
+
import com.facebook.react.bridge.ReadableMap
|
|
6
|
+
|
|
7
|
+
class IntTypeConverter(isOptional: Boolean) : TypeConverter<Int>(isOptional) {
|
|
8
|
+
override fun convertNonOptional(value: Dynamic): Int = value.asInt()
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
class DoubleTypeConverter(isOptional: Boolean) : TypeConverter<Double>(isOptional) {
|
|
12
|
+
override fun convertNonOptional(value: Dynamic): Double = value.asDouble()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class FloatTypeConverter(isOptional: Boolean) : TypeConverter<Float>(isOptional) {
|
|
16
|
+
override fun convertNonOptional(value: Dynamic): Float = value.asDouble().toFloat()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
class BoolTypeConverter(isOptional: Boolean) : TypeConverter<Boolean>(isOptional) {
|
|
20
|
+
override fun convertNonOptional(value: Dynamic): Boolean = value.asBoolean()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class StringTypeConverter(isOptional: Boolean) : TypeConverter<String>(isOptional) {
|
|
24
|
+
override fun convertNonOptional(value: Dynamic): String = value.asString()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
class ReadableArrayTypeConverter(isOptional: Boolean) : TypeConverter<ReadableArray>(isOptional) {
|
|
28
|
+
override fun convertNonOptional(value: Dynamic): ReadableArray = value.asArray()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class ReadableMapTypeConverter(isOptional: Boolean) : TypeConverter<ReadableMap>(isOptional) {
|
|
32
|
+
override fun convertNonOptional(value: Dynamic): ReadableMap = value.asMap()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
class PrimitiveIntArrayTypeConverter(isOptional: Boolean) : TypeConverter<IntArray>(isOptional) {
|
|
36
|
+
override fun convertNonOptional(value: Dynamic): IntArray {
|
|
37
|
+
val jsArray = value.asArray()
|
|
38
|
+
return IntArray(jsArray.size()) { index ->
|
|
39
|
+
jsArray.getInt(index)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
class PrimitiveDoubleArrayTypeConverter(isOptional: Boolean) : TypeConverter<DoubleArray>(isOptional) {
|
|
45
|
+
override fun convertNonOptional(value: Dynamic): DoubleArray {
|
|
46
|
+
val jsArray = value.asArray()
|
|
47
|
+
return DoubleArray(jsArray.size()) { index ->
|
|
48
|
+
jsArray.getDouble(index)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
class PrimitiveFloatArrayTypeConverter(isOptional: Boolean) : TypeConverter<FloatArray>(isOptional) {
|
|
54
|
+
override fun convertNonOptional(value: Dynamic): FloatArray {
|
|
55
|
+
val jsArray = value.asArray()
|
|
56
|
+
return FloatArray(jsArray.size()) { index ->
|
|
57
|
+
jsArray.getDouble(index).toFloat()
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|