expo-modules-core 1.1.0 → 1.2.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 +29 -0
- package/android/CMakeLists.txt +9 -25
- package/android/ExpoModulesCorePlugin.gradle +0 -1
- package/android/build.gradle +29 -23
- package/android/legacy/CMakeLists.txt +2 -0
- package/android/src/fabric/CMakeLists.txt +12 -9
- package/android/src/main/cpp/JavaReferencesCache.cpp +6 -0
- package/android/src/main/cpp/JavaReferencesCache.h +20 -6
- package/android/src/main/cpp/JavaScriptModuleObject.cpp +9 -9
- package/android/src/main/cpp/JavaScriptModuleObject.h +5 -3
- package/android/src/main/cpp/JavaScriptRuntime.cpp +4 -0
- package/android/src/main/cpp/MethodMetadata.cpp +13 -2
- package/android/src/main/cpp/types/CppType.h +12 -11
- package/android/src/main/cpp/types/FrontendConverter.cpp +23 -0
- package/android/src/main/cpp/types/FrontendConverter.h +15 -0
- package/android/src/main/cpp/types/FrontendConverterProvider.cpp +1 -0
- package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +3 -0
- package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +8 -2
- package/android/src/main/java/expo/modules/kotlin/functions/AnyFunction.kt +35 -24
- package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +1 -0
- package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +4 -0
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +1 -4
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +30 -0
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionData.kt +5 -1
- package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverter.kt +1 -0
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +6 -0
- package/android/src/main/java/expo/modules/kotlin/views/AnyViewProp.kt +2 -0
- package/android/src/main/java/expo/modules/kotlin/views/ConcreteViewProp.kt +2 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +56 -6
- package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +73 -1
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +20 -16
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +2 -2
- package/build/NativeViewManagerAdapter.native.d.ts.map +1 -1
- package/build/NativeViewManagerAdapter.native.js +19 -1
- package/build/NativeViewManagerAdapter.native.js.map +1 -1
- package/build/SyntheticPlatformEmitter.d.ts +1 -1
- package/build/SyntheticPlatformEmitter.d.ts.map +1 -1
- package/build/SyntheticPlatformEmitter.js +1 -1
- package/build/SyntheticPlatformEmitter.js.map +1 -1
- package/ios/Fabric/ExpoFabricView.swift +6 -6
- package/ios/Fabric/ExpoFabricViewObjC.h +1 -1
- package/ios/Fabric/ExpoFabricViewObjC.mm +3 -9
- package/ios/Swift/Conversions.swift +5 -2
- package/ios/Swift/ExpoBridgeModule.swift +23 -2
- package/ios/Swift/Functions/AnyFunction.swift +4 -0
- package/ios/Swift/Functions/ConcurrentFunctionDefinition.swift +271 -0
- package/ios/Swift/Functions/SyncFunctionComponent.swift +8 -4
- package/ios/Swift/Objects/ObjectDefinitionBuilder.swift +25 -0
- package/ios/Swift/Objects/ObjectDefinitionComponents.swift +6 -0
- package/ios/Swift/Views/ViewModuleWrapper.swift +7 -9
- package/ios/Tests/FunctionSpec.swift +26 -2
- package/package.json +2 -2
- package/src/NativeViewManagerAdapter.native.tsx +23 -2
- package/src/SyntheticPlatformEmitter.ts +1 -1
- package/build/SyntheticPlatformEmitter.web.d.ts +0 -6
- package/build/SyntheticPlatformEmitter.web.d.ts.map +0 -1
- package/build/SyntheticPlatformEmitter.web.js +0 -6
- package/build/SyntheticPlatformEmitter.web.js.map +0 -1
- package/src/SyntheticPlatformEmitter.web.ts +0 -5
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
Represents a concurrent function that can only be called asynchronously, thus its JavaScript equivalent returns a Promise.
|
|
5
|
+
As opposed to `AsyncFunctionComponent`, it can leverage the new Swift's concurrency model and take the async/await closure.
|
|
6
|
+
*/
|
|
7
|
+
public final class ConcurrentFunctionDefinition<Args, FirstArgType, ReturnType>: AnyFunction {
|
|
8
|
+
typealias ClosureType = (Args) async throws -> ReturnType
|
|
9
|
+
|
|
10
|
+
let body: ClosureType
|
|
11
|
+
|
|
12
|
+
init(
|
|
13
|
+
_ name: String,
|
|
14
|
+
firstArgType: FirstArgType.Type,
|
|
15
|
+
dynamicArgumentTypes: [AnyDynamicType],
|
|
16
|
+
_ body: @escaping ClosureType
|
|
17
|
+
) {
|
|
18
|
+
self.name = name
|
|
19
|
+
self.body = body
|
|
20
|
+
self.dynamicArgumentTypes = dynamicArgumentTypes
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// MARK: - AnyFunction
|
|
24
|
+
|
|
25
|
+
let name: String
|
|
26
|
+
|
|
27
|
+
let dynamicArgumentTypes: [AnyDynamicType]
|
|
28
|
+
|
|
29
|
+
var takesOwner: Bool = false
|
|
30
|
+
|
|
31
|
+
func call(by owner: AnyObject?, withArguments args: [Any], callback: @escaping (FunctionCallResult) -> Void) {
|
|
32
|
+
let arguments: [Any]
|
|
33
|
+
|
|
34
|
+
do {
|
|
35
|
+
arguments = concat(
|
|
36
|
+
arguments: try cast(arguments: args, forFunction: self),
|
|
37
|
+
withOwner: owner,
|
|
38
|
+
forFunction: self
|
|
39
|
+
)
|
|
40
|
+
} catch let error as Exception {
|
|
41
|
+
callback(.failure(error))
|
|
42
|
+
return
|
|
43
|
+
} catch {
|
|
44
|
+
callback(.failure(UnexpectedException(error)))
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Switch from the synchronous context to asynchronous
|
|
49
|
+
Task { [arguments] in
|
|
50
|
+
let result: Result<Any, Exception>
|
|
51
|
+
|
|
52
|
+
do {
|
|
53
|
+
// TODO: Right now we force cast the tuple in all types of functions, but we should throw another exception here.
|
|
54
|
+
// swiftlint:disable force_cast
|
|
55
|
+
let argumentsTuple = try Conversions.toTuple(arguments) as! Args
|
|
56
|
+
let returnValue = try await body(argumentsTuple)
|
|
57
|
+
|
|
58
|
+
result = .success(returnValue)
|
|
59
|
+
} catch let error as Exception {
|
|
60
|
+
result = .failure(FunctionCallException(name).causedBy(error))
|
|
61
|
+
} catch {
|
|
62
|
+
result = .failure(UnexpectedException(error))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
callback(result)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// MARK: - JavaScriptObjectBuilder
|
|
70
|
+
|
|
71
|
+
func build(inRuntime runtime: JavaScriptRuntime) -> JavaScriptObject {
|
|
72
|
+
return runtime.createAsyncFunction(name, argsCount: argumentsCount) { [weak self, name] this, args, resolve, reject in
|
|
73
|
+
guard let self = self else {
|
|
74
|
+
let exception = NativeFunctionUnavailableException(name)
|
|
75
|
+
return reject(exception.code, exception.description, nil)
|
|
76
|
+
}
|
|
77
|
+
self.call(by: this, withArguments: args) { result in
|
|
78
|
+
switch result {
|
|
79
|
+
case .failure(let error):
|
|
80
|
+
reject(error.code, error.description, nil)
|
|
81
|
+
case .success(let value):
|
|
82
|
+
resolve(value)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
Concurrently-executing asynchronous function without arguments.
|
|
91
|
+
*/
|
|
92
|
+
public func AsyncFunction<R>(
|
|
93
|
+
_ name: String,
|
|
94
|
+
@_implicitSelfCapture _ closure: @escaping () async throws -> R
|
|
95
|
+
) -> ConcurrentFunctionDefinition<(), Void, R> {
|
|
96
|
+
return ConcurrentFunctionDefinition(
|
|
97
|
+
name,
|
|
98
|
+
firstArgType: Void.self,
|
|
99
|
+
dynamicArgumentTypes: [],
|
|
100
|
+
closure
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
Concurrently-executing asynchronous function with one argument.
|
|
106
|
+
*/
|
|
107
|
+
public func AsyncFunction<R, A0: AnyArgument>(
|
|
108
|
+
_ name: String,
|
|
109
|
+
@_implicitSelfCapture _ closure: @escaping (A0) async throws -> R
|
|
110
|
+
) -> ConcurrentFunctionDefinition<(A0), A0, R> {
|
|
111
|
+
return ConcurrentFunctionDefinition(
|
|
112
|
+
name,
|
|
113
|
+
firstArgType: A0.self,
|
|
114
|
+
dynamicArgumentTypes: [~A0.self],
|
|
115
|
+
closure
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
Concurrently-executing asynchronous function with two arguments.
|
|
121
|
+
*/
|
|
122
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument>(
|
|
123
|
+
_ name: String,
|
|
124
|
+
@_implicitSelfCapture _ closure: @escaping (A0, A1) async throws -> R
|
|
125
|
+
) -> ConcurrentFunctionDefinition<(A0, A1), A0, R> {
|
|
126
|
+
return ConcurrentFunctionDefinition(
|
|
127
|
+
name,
|
|
128
|
+
firstArgType: A0.self,
|
|
129
|
+
dynamicArgumentTypes: [~A0.self, ~A1.self],
|
|
130
|
+
closure
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
Concurrently-executing asynchronous function with three arguments.
|
|
136
|
+
*/
|
|
137
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument>(
|
|
138
|
+
_ name: String,
|
|
139
|
+
@_implicitSelfCapture _ closure: @escaping (A0, A1, A2) async throws -> R
|
|
140
|
+
) -> ConcurrentFunctionDefinition<(A0, A1, A2), A0, R> {
|
|
141
|
+
return ConcurrentFunctionDefinition(
|
|
142
|
+
name,
|
|
143
|
+
firstArgType: A0.self,
|
|
144
|
+
dynamicArgumentTypes: [
|
|
145
|
+
~A0.self,
|
|
146
|
+
~A1.self,
|
|
147
|
+
~A2.self
|
|
148
|
+
],
|
|
149
|
+
closure
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
Concurrently-executing asynchronous function with four arguments.
|
|
155
|
+
*/
|
|
156
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument>(
|
|
157
|
+
_ name: String,
|
|
158
|
+
@_implicitSelfCapture _ closure: @escaping (A0, A1, A2, A3) async throws -> R
|
|
159
|
+
) -> ConcurrentFunctionDefinition<(A0, A1, A2, A3), A0, R> {
|
|
160
|
+
return ConcurrentFunctionDefinition(
|
|
161
|
+
name,
|
|
162
|
+
firstArgType: A0.self,
|
|
163
|
+
dynamicArgumentTypes: [
|
|
164
|
+
~A0.self,
|
|
165
|
+
~A1.self,
|
|
166
|
+
~A2.self,
|
|
167
|
+
~A3.self
|
|
168
|
+
],
|
|
169
|
+
closure
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
Concurrently-executing asynchronous function with five arguments.
|
|
175
|
+
*/
|
|
176
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument>(
|
|
177
|
+
_ name: String,
|
|
178
|
+
@_implicitSelfCapture _ closure: @escaping (A0, A1, A2, A3, A4) async throws -> R
|
|
179
|
+
) -> ConcurrentFunctionDefinition<(A0, A1, A2, A3, A4), A0, R> {
|
|
180
|
+
return ConcurrentFunctionDefinition(
|
|
181
|
+
name,
|
|
182
|
+
firstArgType: A0.self,
|
|
183
|
+
dynamicArgumentTypes: [
|
|
184
|
+
~A0.self,
|
|
185
|
+
~A1.self,
|
|
186
|
+
~A2.self,
|
|
187
|
+
~A3.self,
|
|
188
|
+
~A4.self
|
|
189
|
+
],
|
|
190
|
+
closure
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
Concurrently-executing asynchronous function with six arguments.
|
|
196
|
+
*/
|
|
197
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument>(
|
|
198
|
+
_ name: String,
|
|
199
|
+
@_implicitSelfCapture _ closure: @escaping (A0, A1, A2, A3, A4, A5) async throws -> R
|
|
200
|
+
) -> ConcurrentFunctionDefinition<(A0, A1, A2, A3, A4, A5), A0, R> {
|
|
201
|
+
return ConcurrentFunctionDefinition(
|
|
202
|
+
name,
|
|
203
|
+
firstArgType: A0.self,
|
|
204
|
+
dynamicArgumentTypes: [
|
|
205
|
+
~A0.self,
|
|
206
|
+
~A1.self,
|
|
207
|
+
~A2.self,
|
|
208
|
+
~A3.self,
|
|
209
|
+
~A4.self,
|
|
210
|
+
~A5.self
|
|
211
|
+
],
|
|
212
|
+
closure
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
Concurrently-executing asynchronous function with seven arguments.
|
|
218
|
+
*/
|
|
219
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument, A6: AnyArgument>(
|
|
220
|
+
_ name: String,
|
|
221
|
+
@_implicitSelfCapture _ closure: @escaping (A0, A1, A2, A3, A4, A5, A6) async throws -> R
|
|
222
|
+
) -> ConcurrentFunctionDefinition<(A0, A1, A2, A3, A4, A5, A6), A0, R> {
|
|
223
|
+
return ConcurrentFunctionDefinition(
|
|
224
|
+
name,
|
|
225
|
+
firstArgType: A0.self,
|
|
226
|
+
dynamicArgumentTypes: [
|
|
227
|
+
~A0.self,
|
|
228
|
+
~A1.self,
|
|
229
|
+
~A2.self,
|
|
230
|
+
~A3.self,
|
|
231
|
+
~A4.self,
|
|
232
|
+
~A5.self,
|
|
233
|
+
~A6.self
|
|
234
|
+
],
|
|
235
|
+
closure
|
|
236
|
+
)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
Concurrently-executing asynchronous function with eight arguments.
|
|
241
|
+
*/
|
|
242
|
+
public func AsyncFunction<
|
|
243
|
+
R,
|
|
244
|
+
A0: AnyArgument,
|
|
245
|
+
A1: AnyArgument,
|
|
246
|
+
A2: AnyArgument,
|
|
247
|
+
A3: AnyArgument,
|
|
248
|
+
A4: AnyArgument,
|
|
249
|
+
A5: AnyArgument,
|
|
250
|
+
A6: AnyArgument,
|
|
251
|
+
A7: AnyArgument
|
|
252
|
+
>(
|
|
253
|
+
_ name: String,
|
|
254
|
+
@_implicitSelfCapture _ closure: @escaping (A0, A1, A2, A3, A4, A5, A6, A7) async throws -> R
|
|
255
|
+
) -> ConcurrentFunctionDefinition<(A0, A1, A2, A3, A4, A5, A6, A7), A0, R> {
|
|
256
|
+
return ConcurrentFunctionDefinition(
|
|
257
|
+
name,
|
|
258
|
+
firstArgType: A0.self,
|
|
259
|
+
dynamicArgumentTypes: [
|
|
260
|
+
~A0.self,
|
|
261
|
+
~A1.self,
|
|
262
|
+
~A2.self,
|
|
263
|
+
~A3.self,
|
|
264
|
+
~A4.self,
|
|
265
|
+
~A5.self,
|
|
266
|
+
~A6.self,
|
|
267
|
+
~A7.self
|
|
268
|
+
],
|
|
269
|
+
closure
|
|
270
|
+
)
|
|
271
|
+
}
|
|
@@ -82,12 +82,16 @@ public final class SyncFunctionComponent<Args, FirstArgType, ReturnType>: AnySyn
|
|
|
82
82
|
// MARK: - JavaScriptObjectBuilder
|
|
83
83
|
|
|
84
84
|
func build(inRuntime runtime: JavaScriptRuntime) -> JavaScriptObject {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
// We intentionally capture a strong reference to `self`, otherwise the "detached" objects would
|
|
86
|
+
// immediately lose the reference to the definition and thus the underlying native function.
|
|
87
|
+
// It may potentially cause memory leaks, but at the time of writing this comment,
|
|
88
|
+
// the native definition instance deallocates correctly when the JS VM triggers the garbage collector.
|
|
89
|
+
return runtime.createSyncFunction(name, argsCount: argumentsCount) { [weak runtime, self] this, args in
|
|
90
|
+
guard let runtime = runtime else {
|
|
91
|
+
throw Exceptions.RuntimeLost()
|
|
88
92
|
}
|
|
89
93
|
let result = try self.call(by: this, withArguments: args)
|
|
90
|
-
return Conversions.convertFunctionResult(result)
|
|
94
|
+
return Conversions.convertFunctionResult(result, runtime: runtime)
|
|
91
95
|
}
|
|
92
96
|
}
|
|
93
97
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
public protocol AnyObjectDefinitionElement: AnyDefinition {}
|
|
4
|
+
|
|
5
|
+
@resultBuilder
|
|
6
|
+
public struct ObjectDefinitionBuilder {
|
|
7
|
+
public static func buildBlock(_ elements: AnyObjectDefinitionElement...) -> [AnyObjectDefinitionElement] {
|
|
8
|
+
return elements
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
Default implementation without any constraints that just returns type-erased element.
|
|
13
|
+
*/
|
|
14
|
+
public static func buildExpression<ElementType: AnyObjectDefinitionElement>(_ element: ElementType) -> AnyObjectDefinitionElement {
|
|
15
|
+
return element
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
extension SyncFunctionComponent: AnyObjectDefinitionElement {}
|
|
20
|
+
|
|
21
|
+
extension AsyncFunctionComponent: AnyObjectDefinitionElement {}
|
|
22
|
+
|
|
23
|
+
extension PropertyComponent: AnyObjectDefinitionElement {}
|
|
24
|
+
|
|
25
|
+
extension ConstantsDefinition: AnyObjectDefinitionElement {}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/// This file implements definition components that are allowed in any object-based definition — `ObjectDefinition`.
|
|
2
2
|
/// So far only constants and functions belong to plain object.
|
|
3
3
|
|
|
4
|
+
// MARK: - Object
|
|
5
|
+
|
|
6
|
+
public func Object(@ObjectDefinitionBuilder @_implicitSelfCapture _ body: () -> [AnyDefinition]) -> ObjectDefinition {
|
|
7
|
+
return ObjectDefinition(definitions: body())
|
|
8
|
+
}
|
|
9
|
+
|
|
4
10
|
// MARK: - Constants
|
|
5
11
|
|
|
6
12
|
/**
|
|
@@ -109,15 +109,13 @@ public final class ViewModuleWrapper: RCTViewManager, DynamicModuleWrapperProtoc
|
|
|
109
109
|
}
|
|
110
110
|
let props = viewManager.propsDict()
|
|
111
111
|
|
|
112
|
-
for (key,
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
try? prop.set(value: value, onView: view)
|
|
120
|
-
}
|
|
112
|
+
for (key, prop) in props {
|
|
113
|
+
let newValue = json[key] as Any
|
|
114
|
+
|
|
115
|
+
// TODO: @tsapeta: Figure out better way to rethrow errors from here.
|
|
116
|
+
// Adding `throws` keyword to the function results in different
|
|
117
|
+
// method signature in Objective-C. Maybe just call `RCTLogError`?
|
|
118
|
+
try? prop.set(value: Conversions.fromNSObject(newValue), onView: view)
|
|
121
119
|
}
|
|
122
120
|
viewManager.callLifecycleMethods(withType: .didUpdateProps, forView: view)
|
|
123
121
|
}
|
|
@@ -249,18 +249,42 @@ class FunctionSpec: ExpoSpec {
|
|
|
249
249
|
Function("isArgNull") { (arg: Double?) -> Bool in
|
|
250
250
|
return arg == nil
|
|
251
251
|
}
|
|
252
|
+
|
|
253
|
+
Function("returnObjectDefinition") { (initial: Int) -> ObjectDefinition in
|
|
254
|
+
var foo = initial
|
|
255
|
+
|
|
256
|
+
return Object {
|
|
257
|
+
Function("increment") { () -> Int in
|
|
258
|
+
foo += 1
|
|
259
|
+
return foo
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
252
263
|
})
|
|
253
264
|
}
|
|
254
|
-
|
|
265
|
+
|
|
255
266
|
it("returns values") {
|
|
256
267
|
expect(try runtime?.eval("expo.modules.TestModule.returnPi()").asDouble()) == Double.pi
|
|
257
268
|
expect(try runtime?.eval("expo.modules.TestModule.returnNull()").isNull()) == true
|
|
258
269
|
}
|
|
259
|
-
|
|
270
|
+
|
|
260
271
|
it("accepts optional arguments") {
|
|
261
272
|
expect(try runtime?.eval("expo.modules.TestModule.isArgNull(3.14)").asBool()) == false
|
|
262
273
|
expect(try runtime?.eval("expo.modules.TestModule.isArgNull(null)").asBool()) == true
|
|
263
274
|
}
|
|
275
|
+
|
|
276
|
+
it("returns object made from definition") {
|
|
277
|
+
let initialValue = Int.random(in: 1..<100)
|
|
278
|
+
let object = try runtime?.eval("object = expo.modules.TestModule.returnObjectDefinition(\(initialValue))")
|
|
279
|
+
|
|
280
|
+
expect(object?.kind) == .object
|
|
281
|
+
expect(object?.getObject().hasProperty("increment")) == true
|
|
282
|
+
|
|
283
|
+
let result = try runtime?.eval("object.increment()")
|
|
284
|
+
|
|
285
|
+
expect(result?.kind) == .number
|
|
286
|
+
expect(result?.getInt()) == initialValue + 1
|
|
287
|
+
}
|
|
264
288
|
}
|
|
265
289
|
}
|
|
266
290
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-modules-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "The core of Expo Modules architecture",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"@testing-library/react-hooks": "^7.0.1",
|
|
43
43
|
"expo-module-scripts": "^3.0.0"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "1815e2eaad8c753588c7b1eb74420174a28e01f4"
|
|
46
46
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { NativeModules, requireNativeComponent } from 'react-native';
|
|
2
|
+
import { NativeModules, requireNativeComponent, HostComponent } from 'react-native';
|
|
3
3
|
|
|
4
4
|
// To make the transition from React Native's `requireNativeComponent` to Expo's
|
|
5
5
|
// `requireNativeViewManager` as easy as possible, `requireNativeViewManager` is a drop-in
|
|
@@ -14,6 +14,27 @@ type NativeExpoComponentProps = {
|
|
|
14
14
|
proxiedProperties: object;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* A map that caches registered native components.
|
|
19
|
+
*/
|
|
20
|
+
const nativeComponentsCache = new Map<string, HostComponent<any>>();
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Requires a React Native component from cache if possible. This prevents
|
|
24
|
+
* "Tried to register two views with the same name" errors on fast refresh, but
|
|
25
|
+
* also when there are multiple versions of the same package with native component.
|
|
26
|
+
*/
|
|
27
|
+
function requireCachedNativeComponent<Props>(viewName: string): HostComponent<Props> {
|
|
28
|
+
const cachedNativeComponent = nativeComponentsCache.get(viewName);
|
|
29
|
+
|
|
30
|
+
if (!cachedNativeComponent) {
|
|
31
|
+
const nativeComponent = requireNativeComponent<Props>(viewName);
|
|
32
|
+
nativeComponentsCache.set(viewName, nativeComponent);
|
|
33
|
+
return nativeComponent;
|
|
34
|
+
}
|
|
35
|
+
return cachedNativeComponent;
|
|
36
|
+
}
|
|
37
|
+
|
|
17
38
|
/**
|
|
18
39
|
* A drop-in replacement for `requireNativeComponent`.
|
|
19
40
|
*/
|
|
@@ -32,7 +53,7 @@ export function requireNativeViewManager<P>(viewName: string): React.ComponentTy
|
|
|
32
53
|
// manager
|
|
33
54
|
const reactNativeViewName = `ViewManagerAdapter_${viewName}`;
|
|
34
55
|
const ReactNativeComponent =
|
|
35
|
-
|
|
56
|
+
requireCachedNativeComponent<NativeExpoComponentProps>(reactNativeViewName);
|
|
36
57
|
const proxiedPropsNames = viewManagerConfig?.propsNames ?? [];
|
|
37
58
|
|
|
38
59
|
// Define a component for universal-module authors to access their native view manager
|
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* This emitter is used for sending synthetic native events to listeners
|
|
3
3
|
* registered in the API layer with `NativeEventEmitter`.
|
|
4
4
|
*/
|
|
5
|
-
export { default } from 'react-native
|
|
5
|
+
export { DeviceEventEmitter as default } from 'react-native';
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This emitter is used for sending synthetic native events to listeners
|
|
3
|
-
* registered in the API layer with `NativeEventEmitter`.
|
|
4
|
-
*/
|
|
5
|
-
export { default } from 'react-native-web/dist/vendor/react-native/NativeEventEmitter/RCTDeviceEventEmitter';
|
|
6
|
-
//# sourceMappingURL=SyntheticPlatformEmitter.web.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SyntheticPlatformEmitter.web.d.ts","sourceRoot":"","sources":["../src/SyntheticPlatformEmitter.web.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,oFAAoF,CAAC"}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This emitter is used for sending synthetic native events to listeners
|
|
3
|
-
* registered in the API layer with `NativeEventEmitter`.
|
|
4
|
-
*/
|
|
5
|
-
export { default } from 'react-native-web/dist/vendor/react-native/NativeEventEmitter/RCTDeviceEventEmitter';
|
|
6
|
-
//# sourceMappingURL=SyntheticPlatformEmitter.web.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SyntheticPlatformEmitter.web.js","sourceRoot":"","sources":["../src/SyntheticPlatformEmitter.web.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,oFAAoF,CAAC","sourcesContent":["/**\n * This emitter is used for sending synthetic native events to listeners\n * registered in the API layer with `NativeEventEmitter`.\n */\nexport { default } from 'react-native-web/dist/vendor/react-native/NativeEventEmitter/RCTDeviceEventEmitter';\n"]}
|