expo-modules-core 0.7.0 → 0.9.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.
- package/CHANGELOG.md +49 -0
- package/README.md +1 -1
- package/android/ExpoModulesCorePlugin.gradle +15 -0
- package/android/build.gradle +46 -32
- package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +5 -5
- package/android/src/main/java/expo/modules/adapters/react/services/UIManagerModuleWrapper.java +13 -0
- package/android/src/main/java/expo/modules/core/ViewManager.java +9 -0
- package/android/src/main/java/expo/modules/core/interfaces/JavaScriptContextProvider.java +4 -0
- package/android/src/main/java/expo/modules/core/interfaces/ReactActivityHandler.java +37 -1
- package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.java +30 -0
- package/android/src/main/java/expo/modules/core/interfaces/services/UIManager.java +2 -0
- package/android/src/main/java/expo/modules/kotlin/AppContext.kt +13 -5
- package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +2 -13
- package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +11 -5
- package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +5 -1
- package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +17 -0
- package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallback.kt +14 -3
- package/android/src/main/java/expo/modules/kotlin/events/EventEmitter.kt +13 -0
- package/android/src/main/java/expo/modules/kotlin/events/KModuleEventEmitterWrapper.kt +102 -0
- package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +25 -1
- package/android/src/main/java/expo/modules/kotlin/{methods/AnyMethod.kt → functions/AnyFunction.kt} +6 -5
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +15 -0
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +170 -0
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromise.kt +15 -0
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncSuspendFunction.kt +36 -0
- package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +14 -0
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +374 -41
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +2 -2
- package/android/src/main/java/expo/modules/kotlin/records/FieldValidator.kt +139 -0
- package/android/src/main/java/expo/modules/kotlin/records/Record.kt +0 -39
- package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +59 -10
- package/android/src/main/java/expo/modules/kotlin/records/Required.kt +5 -0
- package/android/src/main/java/expo/modules/kotlin/records/ValidationBinder.kt +110 -0
- package/android/src/main/java/expo/modules/kotlin/records/Validators.kt +61 -0
- package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverter.kt +35 -0
- package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverterHelper.kt +148 -0
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +9 -1
- package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +49 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinition.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +114 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +4 -1
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +56 -5
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +3 -0
- package/build/NativeModulesProxy.native.d.ts +0 -4
- package/build/NativeModulesProxy.native.d.ts.map +1 -1
- package/build/NativeModulesProxy.native.js +1 -14
- package/build/NativeModulesProxy.native.js.map +1 -1
- package/build/NativeModulesProxy.types.d.ts +0 -3
- package/build/NativeModulesProxy.types.d.ts.map +1 -1
- package/build/NativeModulesProxy.types.js.map +1 -1
- package/build/NativeViewManagerAdapter.native.d.ts.map +1 -1
- package/build/NativeViewManagerAdapter.native.js +9 -33
- package/build/NativeViewManagerAdapter.native.js.map +1 -1
- package/build/sweet/NativeErrorManager.js +1 -1
- package/build/sweet/NativeErrorManager.js.map +1 -1
- package/ios/AppDelegates/EXAppDelegatesLoader.m +4 -8
- package/ios/AppDelegates/ExpoAppDelegate.swift +4 -10
- package/ios/EXAppDefines.h +1 -0
- package/ios/EXAppDefines.m +6 -0
- package/ios/EXUtilities.h +2 -0
- package/ios/EXUtilities.m +12 -0
- package/ios/ExpoModulesCore.h +4 -0
- package/ios/ExpoModulesCore.podspec +4 -2
- package/ios/Interfaces/FileSystem/EXFileSystemInterface.h +1 -1
- package/ios/Interfaces/TaskManager/EXTaskServiceInterface.h +1 -0
- package/ios/JSI/{JSIConversions.h → EXJSIConversions.h} +4 -1
- package/ios/JSI/{JSIConversions.mm → EXJSIConversions.mm} +16 -5
- package/ios/JSI/{JSIInstaller.h → EXJSIInstaller.h} +3 -3
- package/ios/JSI/EXJSIInstaller.mm +17 -0
- package/ios/JSI/{ExpoModulesProxySpec.h → EXJSIUtils.h} +0 -9
- package/ios/JSI/{ExpoModulesProxySpec.mm → EXJSIUtils.mm} +4 -48
- package/ios/JSI/EXJavaScriptObject.h +97 -0
- package/ios/JSI/EXJavaScriptObject.mm +121 -0
- package/ios/JSI/{JavaScriptRuntime.h → EXJavaScriptRuntime.h} +27 -8
- package/ios/JSI/EXJavaScriptRuntime.mm +153 -0
- package/ios/JSI/EXJavaScriptValue.h +57 -0
- package/ios/JSI/EXJavaScriptValue.mm +166 -0
- package/ios/JSI/ExpoModulesHostObject.mm +2 -1
- package/ios/JSI/JavaScriptRuntime.swift +32 -0
- package/ios/JSI/JavaScriptValue.swift +94 -0
- package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +1 -11
- package/ios/NativeModulesProxy/EXNativeModulesProxy.h +2 -2
- package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +24 -22
- package/ios/ReactDelegates/EXReactCompatibleHelpers.h +18 -0
- package/ios/ReactDelegates/EXReactCompatibleHelpers.m +19 -0
- package/ios/ReactDelegates/ExpoReactDelegate.swift +2 -2
- package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +1 -1
- package/ios/Swift/AppContext.swift +21 -2
- package/ios/Swift/Arguments/AnyArgumentType.swift +1 -1
- package/ios/Swift/Functions/AnyFunction.swift +5 -0
- package/ios/Swift/Functions/AsyncFunctionComponent.swift +182 -0
- package/ios/Swift/Functions/ConcreteFunction.swift +40 -68
- package/ios/Swift/Functions/SyncFunctionComponent.swift +181 -0
- package/ios/Swift/JavaScriptUtils.swift +56 -0
- package/ios/Swift/ModuleHolder.swift +17 -5
- package/ios/Swift/Modules/ModuleDefinitionComponents.swift +66 -44
- package/ios/Swift/ModulesProvider.swift +3 -10
- package/ios/Swift/Objects/ObjectDefinitionComponents.swift +49 -0
- package/ios/Swift/SwiftInteropBridge.swift +14 -5
- package/ios/Swift/Views/ComponentData.swift +2 -1
- package/ios/Swift/Views/ExpoView.swift +8 -0
- package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +23 -0
- package/ios/Swift.h +5 -0
- package/ios/Tests/ArgumentTypeSpec.swift +2 -3
- package/ios/Tests/ConstantsSpec.swift +6 -7
- package/ios/Tests/ConvertiblesSpec.swift +2 -3
- package/ios/Tests/ExceptionsSpec.swift +2 -3
- package/ios/Tests/ExpoModulesSpec.swift +75 -0
- package/ios/Tests/FunctionSpec.swift +13 -15
- package/ios/Tests/FunctionWithConvertiblesSpec.swift +4 -5
- package/ios/Tests/JavaScriptObjectSpec.swift +97 -0
- package/ios/Tests/JavaScriptRuntimeSpec.swift +94 -0
- package/ios/Tests/ModuleEventListenersSpec.swift +15 -16
- package/ios/Tests/ModuleRegistrySpec.swift +2 -3
- package/ios/Tests/RecordSpec.swift +2 -3
- package/package.json +2 -2
- package/src/NativeModulesProxy.native.ts +2 -22
- package/src/NativeModulesProxy.types.ts +0 -8
- package/src/NativeViewManagerAdapter.native.tsx +12 -28
- package/src/sweet/NativeErrorManager.ts +1 -1
- package/android/src/main/java/expo/modules/kotlin/events/KEventEmitterWrapper.kt +0 -26
- package/android/src/main/java/expo/modules/kotlin/methods/Method.kt +0 -14
- package/android/src/main/java/expo/modules/kotlin/methods/PromiseMethod.kt +0 -15
- package/ios/JSI/JSIInstaller.mm +0 -34
- package/ios/JSI/JavaScriptObject.h +0 -60
- package/ios/JSI/JavaScriptObject.mm +0 -93
- package/ios/JSI/JavaScriptRuntime.mm +0 -102
- package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.h +0 -16
- package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.m +0 -28
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
Represents a function that can only be called asynchronously, thus its JavaScript equivalent returns a Promise.
|
|
5
|
+
|
|
6
|
+
- ToDo: Move some asynchronous logic from `ConcreteFunction` (like `call(args:promise:)`) to this class and drop the `isAsync` property.
|
|
7
|
+
*/
|
|
8
|
+
internal final class AsyncFunctionComponent<Args, ReturnType>: ConcreteFunction<Args, ReturnType> {
|
|
9
|
+
override init(
|
|
10
|
+
_ name: String,
|
|
11
|
+
argTypes: [AnyArgumentType],
|
|
12
|
+
_ closure: @escaping ConcreteFunction<Args, ReturnType>.ClosureType
|
|
13
|
+
) {
|
|
14
|
+
super.init(name, argTypes: argTypes, closure)
|
|
15
|
+
self.isAsync = true
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
Asynchronous function without arguments.
|
|
21
|
+
*/
|
|
22
|
+
public func AsyncFunction<R>(
|
|
23
|
+
_ name: String,
|
|
24
|
+
_ closure: @escaping () throws -> R
|
|
25
|
+
) -> AnyFunction {
|
|
26
|
+
return AsyncFunctionComponent(
|
|
27
|
+
name,
|
|
28
|
+
argTypes: [],
|
|
29
|
+
closure
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
Asynchronous function with one argument.
|
|
35
|
+
*/
|
|
36
|
+
public func AsyncFunction<R, A0: AnyArgument>(
|
|
37
|
+
_ name: String,
|
|
38
|
+
_ closure: @escaping (A0) throws -> R
|
|
39
|
+
) -> AnyFunction {
|
|
40
|
+
return AsyncFunctionComponent(
|
|
41
|
+
name,
|
|
42
|
+
argTypes: [ArgumentType(A0.self)],
|
|
43
|
+
closure
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
Asynchronous function with two arguments.
|
|
49
|
+
*/
|
|
50
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument>(
|
|
51
|
+
_ name: String,
|
|
52
|
+
_ closure: @escaping (A0, A1) throws -> R
|
|
53
|
+
) -> AnyFunction {
|
|
54
|
+
return AsyncFunctionComponent(
|
|
55
|
+
name,
|
|
56
|
+
argTypes: [ArgumentType(A0.self), ArgumentType(A1.self)],
|
|
57
|
+
closure
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
Asynchronous function with three arguments.
|
|
63
|
+
*/
|
|
64
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument>(
|
|
65
|
+
_ name: String,
|
|
66
|
+
_ closure: @escaping (A0, A1, A2) throws -> R
|
|
67
|
+
) -> AnyFunction {
|
|
68
|
+
return AsyncFunctionComponent(
|
|
69
|
+
name,
|
|
70
|
+
argTypes: [
|
|
71
|
+
ArgumentType(A0.self),
|
|
72
|
+
ArgumentType(A1.self),
|
|
73
|
+
ArgumentType(A2.self)
|
|
74
|
+
],
|
|
75
|
+
closure
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
Asynchronous function with four arguments.
|
|
81
|
+
*/
|
|
82
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument>(
|
|
83
|
+
_ name: String,
|
|
84
|
+
_ closure: @escaping (A0, A1, A2, A3) throws -> R
|
|
85
|
+
) -> AnyFunction {
|
|
86
|
+
return AsyncFunctionComponent(
|
|
87
|
+
name,
|
|
88
|
+
argTypes: [
|
|
89
|
+
ArgumentType(A0.self),
|
|
90
|
+
ArgumentType(A1.self),
|
|
91
|
+
ArgumentType(A2.self),
|
|
92
|
+
ArgumentType(A3.self)
|
|
93
|
+
],
|
|
94
|
+
closure
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
Asynchronous function with five arguments.
|
|
100
|
+
*/
|
|
101
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument>(
|
|
102
|
+
_ name: String,
|
|
103
|
+
_ closure: @escaping (A0, A1, A2, A3, A4) throws -> R
|
|
104
|
+
) -> AnyFunction {
|
|
105
|
+
return AsyncFunctionComponent(
|
|
106
|
+
name,
|
|
107
|
+
argTypes: [
|
|
108
|
+
ArgumentType(A0.self),
|
|
109
|
+
ArgumentType(A1.self),
|
|
110
|
+
ArgumentType(A2.self),
|
|
111
|
+
ArgumentType(A3.self),
|
|
112
|
+
ArgumentType(A4.self)
|
|
113
|
+
],
|
|
114
|
+
closure
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
Asynchronous function with six arguments.
|
|
120
|
+
*/
|
|
121
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument>(
|
|
122
|
+
_ name: String,
|
|
123
|
+
_ closure: @escaping (A0, A1, A2, A3, A4, A5) throws -> R
|
|
124
|
+
) -> AnyFunction {
|
|
125
|
+
return AsyncFunctionComponent(
|
|
126
|
+
name,
|
|
127
|
+
argTypes: [
|
|
128
|
+
ArgumentType(A0.self),
|
|
129
|
+
ArgumentType(A1.self),
|
|
130
|
+
ArgumentType(A2.self),
|
|
131
|
+
ArgumentType(A3.self),
|
|
132
|
+
ArgumentType(A4.self),
|
|
133
|
+
ArgumentType(A5.self)
|
|
134
|
+
],
|
|
135
|
+
closure
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
Asynchronous function with seven arguments.
|
|
141
|
+
*/
|
|
142
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument, A6: AnyArgument>(
|
|
143
|
+
_ name: String,
|
|
144
|
+
_ closure: @escaping (A0, A1, A2, A3, A4, A5, A6) throws -> R
|
|
145
|
+
) -> AnyFunction {
|
|
146
|
+
return AsyncFunctionComponent(
|
|
147
|
+
name,
|
|
148
|
+
argTypes: [
|
|
149
|
+
ArgumentType(A0.self),
|
|
150
|
+
ArgumentType(A1.self),
|
|
151
|
+
ArgumentType(A2.self),
|
|
152
|
+
ArgumentType(A3.self),
|
|
153
|
+
ArgumentType(A4.self),
|
|
154
|
+
ArgumentType(A5.self),
|
|
155
|
+
ArgumentType(A6.self)
|
|
156
|
+
],
|
|
157
|
+
closure
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
Asynchronous function with eight arguments.
|
|
163
|
+
*/
|
|
164
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument, A6: AnyArgument, A7: AnyArgument>(
|
|
165
|
+
_ name: String,
|
|
166
|
+
_ closure: @escaping (A0, A1, A2, A3, A4, A5, A6, A7) throws -> R
|
|
167
|
+
) -> AnyFunction {
|
|
168
|
+
return AsyncFunctionComponent(
|
|
169
|
+
name,
|
|
170
|
+
argTypes: [
|
|
171
|
+
ArgumentType(A0.self),
|
|
172
|
+
ArgumentType(A1.self),
|
|
173
|
+
ArgumentType(A2.self),
|
|
174
|
+
ArgumentType(A3.self),
|
|
175
|
+
ArgumentType(A4.self),
|
|
176
|
+
ArgumentType(A5.self),
|
|
177
|
+
ArgumentType(A6.self),
|
|
178
|
+
ArgumentType(A7.self)
|
|
179
|
+
],
|
|
180
|
+
closure
|
|
181
|
+
)
|
|
182
|
+
}
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import Dispatch
|
|
2
2
|
|
|
3
|
-
public
|
|
3
|
+
public class ConcreteFunction<Args, ReturnType>: AnyFunction {
|
|
4
4
|
public typealias ClosureType = (Args) throws -> ReturnType
|
|
5
5
|
|
|
6
6
|
public let name: String
|
|
7
7
|
|
|
8
|
-
public var takesPromise: Bool
|
|
9
|
-
return argTypes.last is PromiseArgumentType
|
|
10
|
-
}
|
|
8
|
+
public var takesPromise: Bool
|
|
11
9
|
|
|
12
10
|
public var argumentsCount: Int {
|
|
13
|
-
return
|
|
11
|
+
return argumentTypes.count
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
public var queue: DispatchQueue?
|
|
@@ -19,7 +17,7 @@ public final class ConcreteFunction<Args, ReturnType>: AnyFunction {
|
|
|
19
17
|
|
|
20
18
|
let closure: ClosureType
|
|
21
19
|
|
|
22
|
-
let
|
|
20
|
+
public let argumentTypes: [AnyArgumentType]
|
|
23
21
|
|
|
24
22
|
init(
|
|
25
23
|
_ name: String,
|
|
@@ -27,23 +25,33 @@ public final class ConcreteFunction<Args, ReturnType>: AnyFunction {
|
|
|
27
25
|
_ closure: @escaping ClosureType
|
|
28
26
|
) {
|
|
29
27
|
self.name = name
|
|
30
|
-
self.
|
|
28
|
+
self.takesPromise = argTypes.last is PromiseArgumentType
|
|
31
29
|
self.closure = closure
|
|
30
|
+
|
|
31
|
+
// Drop the last argument type if it's the `Promise`.
|
|
32
|
+
self.argumentTypes = takesPromise ? argTypes.dropLast(1) : argTypes
|
|
33
|
+
|
|
34
|
+
// This is temporary solution to keep backwards compatibility for existing functions — they all end with "Async".
|
|
35
|
+
// `function` component that we've used so far was async by default, but we decided to replace it with `asyncFunction`
|
|
36
|
+
// and make `function`s synchronous. Introduced in SDK45, can be removed in SDK46 after migrating all modules.
|
|
37
|
+
self.isAsync = name.hasSuffix("Async")
|
|
32
38
|
}
|
|
33
39
|
|
|
40
|
+
/**
|
|
41
|
+
Calls the function with given arguments.
|
|
42
|
+
- Parameters:
|
|
43
|
+
- args: An array of arguments to pass to the function. The arguments must be of the same type as in the underlying ``closure``.
|
|
44
|
+
- promise: A promise to resolve or reject by the async ``closure`` when it finishes execution.
|
|
45
|
+
- ToDo: Make it internal.
|
|
46
|
+
*/
|
|
34
47
|
public func call(args: [Any], promise: Promise) {
|
|
35
|
-
|
|
48
|
+
// Add promise to the array of arguments if necessary.
|
|
49
|
+
let arguments = takesPromise ? args + [promise] : args
|
|
36
50
|
let returnedValue: ReturnType?
|
|
37
51
|
|
|
38
52
|
do {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if takesPromise {
|
|
42
|
-
finalArgs.append(promise)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
let tuple = try Conversions.toTuple(finalArgs) as! Args
|
|
46
|
-
returnedValue = try closure(tuple)
|
|
53
|
+
let argumentsTuple = try Conversions.toTuple(arguments) as! Args
|
|
54
|
+
returnedValue = try closure(argumentsTuple)
|
|
47
55
|
} catch let error as CodedError {
|
|
48
56
|
promise.reject(FunctionCallException(name).causedBy(error))
|
|
49
57
|
return
|
|
@@ -56,28 +64,24 @@ public final class ConcreteFunction<Args, ReturnType>: AnyFunction {
|
|
|
56
64
|
}
|
|
57
65
|
}
|
|
58
66
|
|
|
67
|
+
/**
|
|
68
|
+
Calls the function synchronously with given arguments.
|
|
69
|
+
- Parameters:
|
|
70
|
+
- args: An array of arguments to pass to the function. The arguments must be of the same type as in the underlying ``closure``.
|
|
71
|
+
- Returns: A value returned by the called function when succeeded or an error when it failed.
|
|
72
|
+
- ToDo: Make it internal.
|
|
73
|
+
*/
|
|
59
74
|
public func callSync(args: [Any]) -> Any {
|
|
60
75
|
if takesPromise {
|
|
61
|
-
|
|
62
|
-
let
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
call(args: args, promise: promise)
|
|
71
|
-
semaphore.wait()
|
|
72
|
-
return result as Any
|
|
73
|
-
} else {
|
|
74
|
-
do {
|
|
75
|
-
let finalArgs = try castArguments(args)
|
|
76
|
-
let tuple = try Conversions.toTuple(finalArgs) as! Args
|
|
77
|
-
return try closure(tuple)
|
|
78
|
-
} catch let error {
|
|
79
|
-
return error
|
|
80
|
-
}
|
|
76
|
+
// Using `Promise` in the synchronous function is prohibited. Probably should throw an exception here,
|
|
77
|
+
// but for now let's return nil until we split async and sync functions.
|
|
78
|
+
return Optional<Any>.none as Any
|
|
79
|
+
}
|
|
80
|
+
do {
|
|
81
|
+
let argumentsTuple = try Conversions.toTuple(args) as! Args
|
|
82
|
+
return try closure(argumentsTuple)
|
|
83
|
+
} catch let error {
|
|
84
|
+
return error
|
|
81
85
|
}
|
|
82
86
|
}
|
|
83
87
|
|
|
@@ -90,38 +94,6 @@ public final class ConcreteFunction<Args, ReturnType>: AnyFunction {
|
|
|
90
94
|
self.isAsync = false
|
|
91
95
|
return self
|
|
92
96
|
}
|
|
93
|
-
|
|
94
|
-
private func argumentType(atIndex index: Int) -> AnyArgumentType? {
|
|
95
|
-
return (0..<argTypes.count).contains(index) ? argTypes[index] : nil
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
private func castArguments(_ args: [Any]) throws -> [Any] {
|
|
99
|
-
if args.count != argumentsCount {
|
|
100
|
-
throw InvalidArgsNumberException((received: args.count, expected: argumentsCount))
|
|
101
|
-
}
|
|
102
|
-
return try args.enumerated().map { index, arg in
|
|
103
|
-
let expectedType = argumentType(atIndex: index)
|
|
104
|
-
|
|
105
|
-
do {
|
|
106
|
-
// It's safe to unwrap since the arguments count matches.
|
|
107
|
-
return try expectedType!.cast(arg)
|
|
108
|
-
} catch {
|
|
109
|
-
throw ArgumentCastException((index: index, type: expectedType!)).causedBy(error)
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
internal class InvalidArgsNumberException: GenericException<(received: Int, expected: Int)> {
|
|
116
|
-
override var reason: String {
|
|
117
|
-
"Received \(param.received) arguments, but \(param.expected) was expected"
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
internal class ArgumentCastException: GenericException<(index: Int, type: AnyArgumentType)> {
|
|
122
|
-
override var reason: String {
|
|
123
|
-
"Argument at index '\(param.index)' couldn't be cast to type \(param.type.description)"
|
|
124
|
-
}
|
|
125
97
|
}
|
|
126
98
|
|
|
127
99
|
internal class FunctionCallException: GenericException<String> {
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
Represents a function that can only be called synchronously.
|
|
5
|
+
- ToDo: Move some synchronous logic from `ConcreteFunction` (like `call(args:)`) to this class and drop the `isAsync` property.
|
|
6
|
+
*/
|
|
7
|
+
internal final class SyncFunctionComponent<Args, ReturnType>: ConcreteFunction<Args, ReturnType> {
|
|
8
|
+
override init(
|
|
9
|
+
_ name: String,
|
|
10
|
+
argTypes: [AnyArgumentType],
|
|
11
|
+
_ closure: @escaping ConcreteFunction<Args, ReturnType>.ClosureType
|
|
12
|
+
) {
|
|
13
|
+
super.init(name, argTypes: argTypes, closure)
|
|
14
|
+
self.isAsync = false
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
Synchronous function without arguments.
|
|
20
|
+
*/
|
|
21
|
+
public func Function<R>(
|
|
22
|
+
_ name: String,
|
|
23
|
+
_ closure: @escaping () throws -> R
|
|
24
|
+
) -> AnyFunction {
|
|
25
|
+
return SyncFunctionComponent(
|
|
26
|
+
name,
|
|
27
|
+
argTypes: [],
|
|
28
|
+
closure
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
Synchronous function with one argument.
|
|
34
|
+
*/
|
|
35
|
+
public func Function<R, A0: AnyArgument>(
|
|
36
|
+
_ name: String,
|
|
37
|
+
_ closure: @escaping (A0) throws -> R
|
|
38
|
+
) -> AnyFunction {
|
|
39
|
+
return SyncFunctionComponent(
|
|
40
|
+
name,
|
|
41
|
+
argTypes: [ArgumentType(A0.self)],
|
|
42
|
+
closure
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
Synchronous function with two arguments.
|
|
48
|
+
*/
|
|
49
|
+
public func Function<R, A0: AnyArgument, A1: AnyArgument>(
|
|
50
|
+
_ name: String,
|
|
51
|
+
_ closure: @escaping (A0, A1) throws -> R
|
|
52
|
+
) -> AnyFunction {
|
|
53
|
+
return SyncFunctionComponent(
|
|
54
|
+
name,
|
|
55
|
+
argTypes: [ArgumentType(A0.self), ArgumentType(A1.self)],
|
|
56
|
+
closure
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
Synchronous function with three arguments.
|
|
62
|
+
*/
|
|
63
|
+
public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument>(
|
|
64
|
+
_ name: String,
|
|
65
|
+
_ closure: @escaping (A0, A1, A2) throws -> R
|
|
66
|
+
) -> AnyFunction {
|
|
67
|
+
return SyncFunctionComponent(
|
|
68
|
+
name,
|
|
69
|
+
argTypes: [
|
|
70
|
+
ArgumentType(A0.self),
|
|
71
|
+
ArgumentType(A1.self),
|
|
72
|
+
ArgumentType(A2.self)
|
|
73
|
+
],
|
|
74
|
+
closure
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
Synchronous function with four arguments.
|
|
80
|
+
*/
|
|
81
|
+
public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument>(
|
|
82
|
+
_ name: String,
|
|
83
|
+
_ closure: @escaping (A0, A1, A2, A3) throws -> R
|
|
84
|
+
) -> AnyFunction {
|
|
85
|
+
return SyncFunctionComponent(
|
|
86
|
+
name,
|
|
87
|
+
argTypes: [
|
|
88
|
+
ArgumentType(A0.self),
|
|
89
|
+
ArgumentType(A1.self),
|
|
90
|
+
ArgumentType(A2.self),
|
|
91
|
+
ArgumentType(A3.self)
|
|
92
|
+
],
|
|
93
|
+
closure
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
Synchronous function with five arguments.
|
|
99
|
+
*/
|
|
100
|
+
public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument>(
|
|
101
|
+
_ name: String,
|
|
102
|
+
_ closure: @escaping (A0, A1, A2, A3, A4) throws -> R
|
|
103
|
+
) -> AnyFunction {
|
|
104
|
+
return SyncFunctionComponent(
|
|
105
|
+
name,
|
|
106
|
+
argTypes: [
|
|
107
|
+
ArgumentType(A0.self),
|
|
108
|
+
ArgumentType(A1.self),
|
|
109
|
+
ArgumentType(A2.self),
|
|
110
|
+
ArgumentType(A3.self),
|
|
111
|
+
ArgumentType(A4.self)
|
|
112
|
+
],
|
|
113
|
+
closure
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
Synchronous function with six arguments.
|
|
119
|
+
*/
|
|
120
|
+
public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument>(
|
|
121
|
+
_ name: String,
|
|
122
|
+
_ closure: @escaping (A0, A1, A2, A3, A4, A5) throws -> R
|
|
123
|
+
) -> AnyFunction {
|
|
124
|
+
return SyncFunctionComponent(
|
|
125
|
+
name,
|
|
126
|
+
argTypes: [
|
|
127
|
+
ArgumentType(A0.self),
|
|
128
|
+
ArgumentType(A1.self),
|
|
129
|
+
ArgumentType(A2.self),
|
|
130
|
+
ArgumentType(A3.self),
|
|
131
|
+
ArgumentType(A4.self),
|
|
132
|
+
ArgumentType(A5.self)
|
|
133
|
+
],
|
|
134
|
+
closure
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
Synchronous function with seven arguments.
|
|
140
|
+
*/
|
|
141
|
+
public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument, A6: AnyArgument>(
|
|
142
|
+
_ name: String,
|
|
143
|
+
_ closure: @escaping (A0, A1, A2, A3, A4, A5, A6) throws -> R
|
|
144
|
+
) -> AnyFunction {
|
|
145
|
+
return SyncFunctionComponent(
|
|
146
|
+
name,
|
|
147
|
+
argTypes: [
|
|
148
|
+
ArgumentType(A0.self),
|
|
149
|
+
ArgumentType(A1.self),
|
|
150
|
+
ArgumentType(A2.self),
|
|
151
|
+
ArgumentType(A3.self),
|
|
152
|
+
ArgumentType(A4.self),
|
|
153
|
+
ArgumentType(A5.self),
|
|
154
|
+
ArgumentType(A6.self)
|
|
155
|
+
],
|
|
156
|
+
closure
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
Synchronous function with eight arguments.
|
|
162
|
+
*/
|
|
163
|
+
public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument, A6: AnyArgument, A7: AnyArgument>(
|
|
164
|
+
_ name: String,
|
|
165
|
+
_ closure: @escaping (A0, A1, A2, A3, A4, A5, A6, A7) throws -> R
|
|
166
|
+
) -> AnyFunction {
|
|
167
|
+
return SyncFunctionComponent(
|
|
168
|
+
name,
|
|
169
|
+
argTypes: [
|
|
170
|
+
ArgumentType(A0.self),
|
|
171
|
+
ArgumentType(A1.self),
|
|
172
|
+
ArgumentType(A2.self),
|
|
173
|
+
ArgumentType(A3.self),
|
|
174
|
+
ArgumentType(A4.self),
|
|
175
|
+
ArgumentType(A5.self),
|
|
176
|
+
ArgumentType(A6.self),
|
|
177
|
+
ArgumentType(A7.self)
|
|
178
|
+
],
|
|
179
|
+
closure
|
|
180
|
+
)
|
|
181
|
+
}
|
|
@@ -36,6 +36,62 @@ internal func createSyncFunctionBlock(holder: ModuleHolder, name functionName: S
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
// MARK: - Arguments
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
Tries to cast given argument to the type that is wrapped by the argument type.
|
|
43
|
+
- Parameters:
|
|
44
|
+
- argument: A value to be cast. If it's a ``JavaScriptValue``, it's first unpacked to the raw value.
|
|
45
|
+
- argumentType: Something that implements ``AnyArgumentType`` and knows how to cast the argument.
|
|
46
|
+
- Returns: A new value converted according to the argument type.
|
|
47
|
+
- Throws: Rethrows various exceptions that could be thrown by the argument type wrappers.
|
|
48
|
+
*/
|
|
49
|
+
internal func castArgument(_ argument: Any, toType argumentType: AnyArgumentType) throws -> Any {
|
|
50
|
+
// TODO: Accept JavaScriptValue and JavaScriptObject as argument types.
|
|
51
|
+
if let argument = argument as? JavaScriptValue {
|
|
52
|
+
return try argumentType.cast(argument.getRaw())
|
|
53
|
+
}
|
|
54
|
+
return try argumentType.cast(argument)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
Same as ``castArgument(_:argumentType:)`` but for an array of arguments.
|
|
59
|
+
- Parameters:
|
|
60
|
+
- arguments: An array of arguments to be cast.
|
|
61
|
+
- argumentTypes: An array of argument types in the same order as the array of arguments.
|
|
62
|
+
- Returns: An array of arguments after casting. Its size is the same as the input arrays.
|
|
63
|
+
- Throws: ``InvalidArgsNumberException`` when the sizes of arrays passed as parameters are not equal.
|
|
64
|
+
Rethrows exceptions thrown by ``castArgument(_:argumentType:)``.
|
|
65
|
+
*/
|
|
66
|
+
internal func castArguments(_ arguments: [Any], toTypes argumentTypes: [AnyArgumentType]) throws -> [Any] {
|
|
67
|
+
if arguments.count != argumentTypes.count {
|
|
68
|
+
throw InvalidArgsNumberException((received: arguments.count, expected: argumentTypes.count))
|
|
69
|
+
}
|
|
70
|
+
return try arguments.enumerated().map { index, argument in
|
|
71
|
+
let argumentType = argumentTypes[index]
|
|
72
|
+
|
|
73
|
+
do {
|
|
74
|
+
return try castArgument(argument, toType: argumentType)
|
|
75
|
+
} catch {
|
|
76
|
+
throw ArgumentCastException((index: index, type: argumentType)).causedBy(error)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
internal class InvalidArgsNumberException: GenericException<(received: Int, expected: Int)> {
|
|
82
|
+
override var reason: String {
|
|
83
|
+
"Received \(param.received) arguments, but \(param.expected) was expected"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
internal class ArgumentCastException: GenericException<(index: Int, type: AnyArgumentType)> {
|
|
88
|
+
override var reason: String {
|
|
89
|
+
"Argument at index '\(param.index)' couldn't be cast to type \(param.type.description)"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// MARK: - Exceptions
|
|
94
|
+
|
|
39
95
|
private class ModuleUnavailableException: GenericException<String> {
|
|
40
96
|
override var reason: String {
|
|
41
97
|
"Module '\(param)' is no longer available"
|
|
@@ -70,8 +70,15 @@ public final class ModuleHolder {
|
|
|
70
70
|
}
|
|
71
71
|
let queue = function.queue ?? DispatchQueue.global(qos: .default)
|
|
72
72
|
|
|
73
|
+
// Given arguments can be:
|
|
74
|
+
// - Swift primitives when invoked through the bridge and in unit tests
|
|
75
|
+
// - `JavaScriptValue`s when the function is called through the JSI
|
|
76
|
+
// The latter need to be unpacked to Swift primitives on the JS thread,
|
|
77
|
+
// so we do the casting before the function call is scheduled on the queue.
|
|
78
|
+
let arguments = try castArguments(args, toTypes: function.argumentTypes)
|
|
79
|
+
|
|
73
80
|
queue.async {
|
|
74
|
-
function.call(args:
|
|
81
|
+
function.call(args: arguments, promise: promise)
|
|
75
82
|
}
|
|
76
83
|
} catch let error as CodedError {
|
|
77
84
|
promise.reject(error)
|
|
@@ -91,10 +98,15 @@ public final class ModuleHolder {
|
|
|
91
98
|
|
|
92
99
|
@discardableResult
|
|
93
100
|
func callSync(function functionName: String, args: [Any]) -> Any? {
|
|
94
|
-
|
|
95
|
-
return
|
|
101
|
+
guard let function = definition.functions[functionName] else {
|
|
102
|
+
return nil
|
|
103
|
+
}
|
|
104
|
+
do {
|
|
105
|
+
let arguments = try castArguments(args, toTypes: function.argumentTypes)
|
|
106
|
+
return function.callSync(args: arguments)
|
|
107
|
+
} catch {
|
|
108
|
+
return error
|
|
96
109
|
}
|
|
97
|
-
return nil
|
|
98
110
|
}
|
|
99
111
|
|
|
100
112
|
// MARK: JavaScript Module Object
|
|
@@ -113,7 +125,7 @@ public final class ModuleHolder {
|
|
|
113
125
|
|
|
114
126
|
// Fill in with constants
|
|
115
127
|
for (key, value) in getConstants() {
|
|
116
|
-
object
|
|
128
|
+
object.setProperty(key, value: value)
|
|
117
129
|
}
|
|
118
130
|
|
|
119
131
|
// Fill in with functions
|