expo-modules-core 1.0.4 → 1.1.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 +26 -6
- package/ExpoModulesCore.podspec +38 -4
- package/android/CMakeLists.txt +21 -71
- package/android/ExpoModulesCorePlugin.gradle +200 -0
- package/android/build.gradle +42 -205
- package/android/legacy/CMakeLists.txt +194 -0
- package/android/{src → legacy}/fabric/Android-prebuilt.cmake +2 -0
- package/android/legacy/fabric/CMakeLists.txt +40 -0
- package/android/proguard-rules.pro +13 -0
- package/android/src/fabric/CMakeLists.txt +23 -16
- package/android/src/main/java/expo/modules/kotlin/AppContext.kt +7 -0
- package/android/src/main/java/expo/modules/kotlin/exception/CommonExceptions.kt +5 -0
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +44 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +9 -1
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +46 -0
- package/build/EventEmitter.d.ts +2 -2
- package/build/EventEmitter.d.ts.map +1 -1
- package/build/NativeModulesProxy.types.d.ts +1 -1
- package/build/NativeModulesProxy.types.d.ts.map +1 -1
- package/build/NativeViewManagerAdapter.native.d.ts +1 -1
- package/build/NativeViewManagerAdapter.native.d.ts.map +1 -1
- package/build/NativeViewManagerAdapter.native.js +3 -3
- package/build/NativeViewManagerAdapter.native.js.map +1 -1
- package/build/PermissionsHook.d.ts +4 -4
- package/build/PermissionsHook.d.ts.map +1 -1
- package/build/PermissionsInterface.d.ts +1 -1
- package/build/PermissionsInterface.d.ts.map +1 -1
- package/build/Platform.d.ts +2 -2
- package/build/Platform.d.ts.map +1 -1
- package/build/TypedArrays.types.d.ts +9 -0
- package/build/TypedArrays.types.d.ts.map +1 -0
- package/build/TypedArrays.types.js +2 -0
- package/build/TypedArrays.types.js.map +1 -0
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/build/requireNativeModule.d.ts +1 -1
- package/build/requireNativeModule.d.ts.map +1 -1
- package/common/cpp/fabric/ExpoViewProps.cpp +2 -0
- package/ios/AppDelegates/EXAppDelegateWrapper.h +22 -0
- package/ios/AppDelegates/EXAppDelegateWrapper.mm +100 -0
- package/ios/JSI/EXJavaScriptRuntime.mm +5 -5
- package/ios/ReactDelegates/EXReactCompatibleHelpers.h +1 -1
- package/ios/ReactDelegates/EXReactCompatibleHelpers.m +8 -2
- package/ios/ReactDelegates/EXReactDelegateWrapper.h +5 -0
- package/ios/ReactDelegates/EXReactDelegateWrapper.m +14 -1
- package/ios/ReactDelegates/ExpoReactDelegate.swift +7 -2
- package/ios/Swift/AppContext.swift +9 -0
- package/ios/Swift/Arguments/Enumerable.swift +2 -16
- package/ios/Swift/Classes/ClassComponentElement.swift +1 -1
- package/ios/Swift/Convertibles/Either.swift +5 -14
- package/ios/Swift/DynamicTypes/DynamicEnumType.swift +1 -1
- package/ios/Swift/DynamicTypes/DynamicSharedObjectType.swift +4 -0
- package/ios/Swift/DynamicTypes/DynamicType.swift +1 -1
- package/ios/Swift/Functions/AnyFunction.swift +18 -0
- package/ios/Swift/JavaScriptUtils.swift +25 -8
- package/ios/Swift/Objects/ObjectDefinition.swift +4 -4
- package/ios/Swift/Objects/ObjectDefinitionComponents.swift +7 -0
- package/ios/Swift/Objects/PropertyComponent.swift +138 -48
- package/ios/Swift/SharedObjects/SharedObject.swift +5 -0
- package/ios/Tests/ClassComponentSpec.swift +15 -0
- package/ios/Tests/EitherSpec.swift +28 -0
- package/ios/Tests/FunctionSpec.swift +31 -0
- package/ios/Tests/PropertyComponentSpec.swift +131 -33
- package/package.json +2 -2
- package/src/NativeViewManagerAdapter.native.tsx +4 -4
- package/src/TypedArrays.types.ts +11 -0
- package/src/index.ts +1 -0
- package/ios/AppDelegates/EXAppDelegateWrapper.m +0 -45
|
@@ -22,10 +22,15 @@ public class ExpoReactDelegate: NSObject {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
@objc
|
|
25
|
-
public func createRootView(
|
|
25
|
+
public func createRootView(
|
|
26
|
+
bridge: RCTBridge,
|
|
27
|
+
moduleName: String,
|
|
28
|
+
initialProperties: [AnyHashable: Any]?,
|
|
29
|
+
fabricEnabled: Bool = EXAppDefines.APP_NEW_ARCH_ENABLED
|
|
30
|
+
) -> UIView {
|
|
26
31
|
return self.handlers.lazy
|
|
27
32
|
.compactMap { $0.createRootView(reactDelegate: self, bridge: bridge, moduleName: moduleName, initialProperties: initialProperties) }
|
|
28
|
-
.first(where: { _ in true }) ?? EXAppSetupDefaultRootView(bridge, moduleName, initialProperties)
|
|
33
|
+
.first(where: { _ in true }) ?? EXAppSetupDefaultRootView(bridge, moduleName, initialProperties, fabricEnabled)
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
@objc
|
|
@@ -91,6 +91,15 @@ public final class AppContext: NSObject {
|
|
|
91
91
|
return view as? ViewType
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
// MARK: - Running on specific queues
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
Runs a code block on the JavaScript thread.
|
|
98
|
+
*/
|
|
99
|
+
public func executeOnJavaScriptThread(runBlock: @escaping (() -> Void)) {
|
|
100
|
+
reactBridge?.dispatchBlock(runBlock, queue: RCTJSThread)
|
|
101
|
+
}
|
|
102
|
+
|
|
94
103
|
// MARK: - Legacy modules
|
|
95
104
|
|
|
96
105
|
/**
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
/**
|
|
4
4
|
A protocol that allows converting raw values to enum cases.
|
|
5
5
|
*/
|
|
6
|
-
public protocol Enumerable: AnyArgument {
|
|
6
|
+
public protocol Enumerable: AnyArgument, CaseIterable {
|
|
7
7
|
/**
|
|
8
8
|
Tries to create an enum case using given raw value.
|
|
9
9
|
May throw errors, e.g. when the raw value doesn't match any case.
|
|
@@ -44,21 +44,7 @@ public extension Enumerable where Self: RawRepresentable, Self: Hashable {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
static var allRawValues: [Any] {
|
|
47
|
-
|
|
48
|
-
let sequence = AnySequence { () -> AnyIterator<RawValue> in
|
|
49
|
-
var raw = 0
|
|
50
|
-
return AnyIterator {
|
|
51
|
-
let current: Self? = withUnsafePointer(to: &raw) { ptr in
|
|
52
|
-
ptr.withMemoryRebound(to: Self.self, capacity: 1) { $0.pointee }
|
|
53
|
-
}
|
|
54
|
-
guard let value = current?.rawValue else {
|
|
55
|
-
return nil
|
|
56
|
-
}
|
|
57
|
-
raw += 1
|
|
58
|
-
return value
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return Array(sequence)
|
|
47
|
+
return allCases.map { $0.rawValue }
|
|
62
48
|
}
|
|
63
49
|
}
|
|
64
50
|
|
|
@@ -25,7 +25,7 @@ extension AsyncFunctionComponent: ClassComponentElement {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
extension PropertyComponent: ClassComponentElement {
|
|
28
|
-
|
|
28
|
+
// It already has the `OwnerType`
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
extension ConstantsDefinition: ClassComponentElement {
|
|
@@ -51,8 +51,11 @@ open class Either<FirstType, SecondType>: Convertible {
|
|
|
51
51
|
// MARK: - Convertible
|
|
52
52
|
|
|
53
53
|
public class func convert(from value: Any?) throws -> Self {
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
for type in dynamicTypes() {
|
|
55
|
+
// Initialize the "either" when the current type can cast given value.
|
|
56
|
+
if let value = try? type.cast(value) {
|
|
57
|
+
return Self(value)
|
|
58
|
+
}
|
|
56
59
|
}
|
|
57
60
|
throw NeitherTypeException(Self.dynamicTypes())
|
|
58
61
|
}
|
|
@@ -79,12 +82,6 @@ open class EitherOfThree<FirstType, SecondType, ThirdType>: Either<FirstType, Se
|
|
|
79
82
|
public func get() -> ThirdType? {
|
|
80
83
|
return value as? ThirdType
|
|
81
84
|
}
|
|
82
|
-
|
|
83
|
-
// MARK: - Convertible
|
|
84
|
-
|
|
85
|
-
public override class func convert(from value: Any?) throws -> Self {
|
|
86
|
-
return value is ThirdType ? Self(value) : try super.convert(from: value)
|
|
87
|
-
}
|
|
88
85
|
}
|
|
89
86
|
|
|
90
87
|
/*
|
|
@@ -108,12 +105,6 @@ open class EitherOfFour<FirstType, SecondType, ThirdType, FourthType>: EitherOfT
|
|
|
108
105
|
public func get() -> FourthType? {
|
|
109
106
|
return value as? FourthType
|
|
110
107
|
}
|
|
111
|
-
|
|
112
|
-
// MARK: - Convertible
|
|
113
|
-
|
|
114
|
-
public override class func convert(from value: Any?) throws -> Self {
|
|
115
|
-
return value is FourthType ? Self(value) : try super.convert(from: value)
|
|
116
|
-
}
|
|
117
108
|
}
|
|
118
109
|
|
|
119
110
|
// MARK: - Exceptions
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
A dynamic type representing an enum that conforms to `Enumerable`.
|
|
5
5
|
*/
|
|
6
6
|
internal struct DynamicEnumType: AnyDynamicType {
|
|
7
|
-
let innerType: Enumerable.Type
|
|
7
|
+
let innerType: any Enumerable.Type
|
|
8
8
|
|
|
9
9
|
func wraps<InnerType>(_ type: InnerType.Type) -> Bool {
|
|
10
10
|
return innerType == InnerType.self
|
|
@@ -18,6 +18,10 @@ internal struct DynamicSharedObjectType: AnyDynamicType {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
func cast<ValueType>(_ value: ValueType) throws -> Any {
|
|
21
|
+
if let value = value as? SharedObject, type(of: value) == innerType {
|
|
22
|
+
// Given value is a shared object already
|
|
23
|
+
return value
|
|
24
|
+
}
|
|
21
25
|
if let jsObject = try (value as? JavaScriptValue)?.asObject(),
|
|
22
26
|
let nativeSharedObject = SharedObjectRegistry.toNativeObject(jsObject) {
|
|
23
27
|
return nativeSharedObject
|
|
@@ -18,7 +18,7 @@ internal func DynamicType<T>(_ type: T.Type) -> AnyDynamicType {
|
|
|
18
18
|
if let ConvertibleType = T.self as? Convertible.Type {
|
|
19
19
|
return DynamicConvertibleType(innerType: ConvertibleType)
|
|
20
20
|
}
|
|
21
|
-
if let EnumType = T.self as? Enumerable.Type {
|
|
21
|
+
if let EnumType = T.self as? any Enumerable.Type {
|
|
22
22
|
return DynamicEnumType(innerType: EnumType)
|
|
23
23
|
}
|
|
24
24
|
if let SharedObjectType = T.self as? SharedObject.Type {
|
|
@@ -23,6 +23,11 @@ internal protocol AnyFunction: AnyDefinition, JavaScriptObjectBuilder {
|
|
|
23
23
|
*/
|
|
24
24
|
var argumentsCount: Int { get }
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
A minimum number of arguments the functions needs which equals to `argumentsCount` reduced by the number of trailing optional arguments.
|
|
28
|
+
*/
|
|
29
|
+
var requiredArgumentsCount: Int { get }
|
|
30
|
+
|
|
26
31
|
/**
|
|
27
32
|
Indicates whether the function's arguments starts from the owner that calls this function.
|
|
28
33
|
*/
|
|
@@ -42,6 +47,19 @@ internal protocol AnyFunction: AnyDefinition, JavaScriptObjectBuilder {
|
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
extension AnyFunction {
|
|
50
|
+
var requiredArgumentsCount: Int {
|
|
51
|
+
var trailingOptionalArgumentsCount: Int = 0
|
|
52
|
+
|
|
53
|
+
for dynamicArgumentType in dynamicArgumentTypes.reversed() {
|
|
54
|
+
if dynamicArgumentType is DynamicOptionalType {
|
|
55
|
+
trailingOptionalArgumentsCount += 1
|
|
56
|
+
} else {
|
|
57
|
+
break
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return argumentsCount - trailingOptionalArgumentsCount
|
|
61
|
+
}
|
|
62
|
+
|
|
45
63
|
/**
|
|
46
64
|
Calls the function just like `call(by:withArguments:callback:)`, but without an owner
|
|
47
65
|
and with an empty callback. Might be useful when you only want to call the function,
|
|
@@ -28,10 +28,16 @@ internal func cast(_ value: Any, toType type: AnyDynamicType) throws -> Any {
|
|
|
28
28
|
of function's arguments (without an owner and promise). Rethrows exceptions thrown by `cast(_:toType:)`.
|
|
29
29
|
*/
|
|
30
30
|
internal func cast(arguments: [Any], forFunction function: AnyFunction) throws -> [Any] {
|
|
31
|
-
|
|
32
|
-
throw InvalidArgsNumberException((received: arguments.count, expected: function.argumentsCount))
|
|
33
|
-
}
|
|
31
|
+
let requiredArgumentsCount = function.requiredArgumentsCount
|
|
34
32
|
let argumentTypeOffset = function.takesOwner ? 1 : 0
|
|
33
|
+
|
|
34
|
+
if arguments.count < requiredArgumentsCount || arguments.count > function.argumentsCount {
|
|
35
|
+
throw InvalidArgsNumberException((
|
|
36
|
+
received: arguments.count,
|
|
37
|
+
expected: function.argumentsCount,
|
|
38
|
+
required: requiredArgumentsCount
|
|
39
|
+
))
|
|
40
|
+
}
|
|
35
41
|
return try arguments.enumerated().map { index, argument in
|
|
36
42
|
let argumentType = function.dynamicArgumentTypes[index + argumentTypeOffset]
|
|
37
43
|
|
|
@@ -44,20 +50,31 @@ internal func cast(arguments: [Any], forFunction function: AnyFunction) throws -
|
|
|
44
50
|
}
|
|
45
51
|
|
|
46
52
|
/**
|
|
47
|
-
|
|
53
|
+
Ensures the provided array of arguments matches the number of arguments expected by the function.
|
|
54
|
+
- If the function takes the owner, it's added to the beginning.
|
|
55
|
+
- If the array is still too small, missing arguments are very likely to be optional so it puts `nil` in their place.
|
|
48
56
|
*/
|
|
49
57
|
internal func concat(arguments: [Any], withOwner owner: AnyObject?, forFunction function: AnyFunction) -> [Any] {
|
|
58
|
+
var result = arguments
|
|
59
|
+
|
|
50
60
|
if function.takesOwner, let owner = try? function.dynamicArgumentTypes.first?.cast(owner) {
|
|
51
|
-
|
|
61
|
+
result = [owner] + arguments
|
|
62
|
+
}
|
|
63
|
+
if arguments.count < function.argumentsCount {
|
|
64
|
+
result += Array(repeating: Any?.none as Any, count: function.argumentsCount - arguments.count)
|
|
52
65
|
}
|
|
53
|
-
return
|
|
66
|
+
return result
|
|
54
67
|
}
|
|
55
68
|
|
|
56
69
|
// MARK: - Exceptions
|
|
57
70
|
|
|
58
|
-
internal class InvalidArgsNumberException: GenericException<(received: Int, expected: Int)> {
|
|
71
|
+
internal class InvalidArgsNumberException: GenericException<(received: Int, expected: Int, required: Int)> {
|
|
59
72
|
override var reason: String {
|
|
60
|
-
|
|
73
|
+
if param.required < param.expected {
|
|
74
|
+
return "Received \(param.received) arguments, but \(param.expected) was expected and at least \(param.required) is required"
|
|
75
|
+
} else {
|
|
76
|
+
return "Received \(param.received) arguments, but \(param.expected) was expected"
|
|
77
|
+
}
|
|
61
78
|
}
|
|
62
79
|
}
|
|
63
80
|
|
|
@@ -17,7 +17,7 @@ public class ObjectDefinition: AnyDefinition, JavaScriptObjectBuilder {
|
|
|
17
17
|
/**
|
|
18
18
|
A map of dynamic properties defined by the object.
|
|
19
19
|
*/
|
|
20
|
-
let properties: [String:
|
|
20
|
+
let properties: [String: AnyPropertyComponent]
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
A map of classes defined within the object.
|
|
@@ -38,8 +38,8 @@ public class ObjectDefinition: AnyDefinition, JavaScriptObjectBuilder {
|
|
|
38
38
|
.compactMap { $0 as? ConstantsDefinition }
|
|
39
39
|
|
|
40
40
|
self.properties = definitions
|
|
41
|
-
.compactMap { $0 as?
|
|
42
|
-
.reduce(into: [String:
|
|
41
|
+
.compactMap { $0 as? AnyPropertyComponent }
|
|
42
|
+
.reduce(into: [String: AnyPropertyComponent]()) { dict, property in
|
|
43
43
|
dict[property.name] = property
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -90,7 +90,7 @@ public class ObjectDefinition: AnyDefinition, JavaScriptObjectBuilder {
|
|
|
90
90
|
|
|
91
91
|
internal func decorateWithProperties(runtime: JavaScriptRuntime, object: JavaScriptObject) {
|
|
92
92
|
for property in properties.values {
|
|
93
|
-
let descriptor = property.buildDescriptor(inRuntime: runtime
|
|
93
|
+
let descriptor = property.buildDescriptor(inRuntime: runtime)
|
|
94
94
|
object.defineProperty(property.name, descriptor: descriptor)
|
|
95
95
|
}
|
|
96
96
|
}
|
|
@@ -26,6 +26,13 @@ public func Events(_ names: String...) -> EventsDefinition {
|
|
|
26
26
|
return EventsDefinition(names: names)
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
Defines event names that the object can send to JavaScript.
|
|
31
|
+
*/
|
|
32
|
+
public func Events(_ names: [String]) -> EventsDefinition {
|
|
33
|
+
return EventsDefinition(names: names)
|
|
34
|
+
}
|
|
35
|
+
|
|
29
36
|
/**
|
|
30
37
|
Function that is invoked when the first event listener is added.
|
|
31
38
|
*/
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
protocol AnyPropertyComponent {
|
|
4
|
+
/**
|
|
5
|
+
Name of the property.
|
|
6
|
+
*/
|
|
7
|
+
var name: String { get }
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
Creates the JavaScript object representing the property descriptor.
|
|
11
|
+
*/
|
|
12
|
+
func buildDescriptor(inRuntime runtime: JavaScriptRuntime) -> JavaScriptObject
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public final class PropertyComponent<OwnerType>: AnyDefinition, AnyPropertyComponent {
|
|
4
16
|
/**
|
|
5
17
|
Name of the property.
|
|
6
18
|
*/
|
|
@@ -16,135 +28,213 @@ public final class PropertyComponent: AnyDefinition {
|
|
|
16
28
|
*/
|
|
17
29
|
var setter: AnySyncFunctionComponent?
|
|
18
30
|
|
|
31
|
+
/**
|
|
32
|
+
Initializes an unowned PropertyComponent without getter and setter functions.
|
|
33
|
+
*/
|
|
19
34
|
init(name: String) {
|
|
20
35
|
self.name = name
|
|
21
36
|
}
|
|
22
37
|
|
|
38
|
+
/**
|
|
39
|
+
Initializes an unowned PropertyComponent with a getter without arguments.
|
|
40
|
+
*/
|
|
41
|
+
init<ReturnType>(name: String, getter: @escaping () -> ReturnType) {
|
|
42
|
+
self.name = name
|
|
43
|
+
|
|
44
|
+
// Set the getter right away
|
|
45
|
+
self.get(getter)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
Initializes an owned PropertyComponent with a getter that takes the owner as its first argument.
|
|
50
|
+
*/
|
|
51
|
+
init<ReturnType>(name: String, getter: @escaping (_ this: OwnerType) -> ReturnType) {
|
|
52
|
+
self.name = name
|
|
53
|
+
|
|
54
|
+
// Set the getter right away
|
|
55
|
+
self.get(getter)
|
|
56
|
+
}
|
|
57
|
+
|
|
23
58
|
// MARK: - Modifiers
|
|
24
59
|
|
|
25
60
|
/**
|
|
26
|
-
Modifier that sets property getter that has no arguments (the
|
|
61
|
+
Modifier that sets property getter that has no arguments (the owner is not used).
|
|
27
62
|
*/
|
|
28
|
-
|
|
63
|
+
@discardableResult
|
|
64
|
+
public func get<ReturnType>(_ getter: @escaping () -> ReturnType) -> Self {
|
|
29
65
|
self.getter = SyncFunctionComponent(
|
|
30
66
|
"get",
|
|
31
67
|
firstArgType: Void.self,
|
|
32
|
-
dynamicArgumentTypes: [
|
|
33
|
-
|
|
68
|
+
dynamicArgumentTypes: [],
|
|
69
|
+
getter
|
|
34
70
|
)
|
|
35
71
|
return self
|
|
36
72
|
}
|
|
37
73
|
|
|
38
74
|
/**
|
|
39
|
-
Modifier that sets property
|
|
75
|
+
Modifier that sets property getter that receives the owner as an argument.
|
|
76
|
+
The owner is an object on which the function is called, like `this` in JavaScript.
|
|
40
77
|
*/
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
78
|
+
@discardableResult
|
|
79
|
+
public func get<ReturnType>(_ getter: @escaping (_ this: OwnerType) -> ReturnType) -> Self {
|
|
80
|
+
self.getter = SyncFunctionComponent(
|
|
81
|
+
"get",
|
|
82
|
+
firstArgType: OwnerType.self,
|
|
83
|
+
dynamicArgumentTypes: [~OwnerType.self],
|
|
84
|
+
getter
|
|
47
85
|
)
|
|
86
|
+
self.getter?.takesOwner = true
|
|
48
87
|
return self
|
|
49
88
|
}
|
|
50
89
|
|
|
51
90
|
/**
|
|
52
|
-
Modifier that sets property
|
|
53
|
-
The caller is an object on which the function is called, like `this` in JavaScript.
|
|
91
|
+
Modifier that sets property setter that receives only the new value as an argument.
|
|
54
92
|
*/
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
93
|
+
@discardableResult
|
|
94
|
+
public func set<ValueType>(_ setter: @escaping (_ newValue: ValueType) -> Void) -> Self {
|
|
95
|
+
self.setter = SyncFunctionComponent(
|
|
96
|
+
"set",
|
|
97
|
+
firstArgType: ValueType.self,
|
|
98
|
+
dynamicArgumentTypes: [~ValueType.self],
|
|
99
|
+
setter
|
|
61
100
|
)
|
|
62
101
|
return self
|
|
63
102
|
}
|
|
64
103
|
|
|
65
104
|
/**
|
|
66
|
-
Modifier that sets property setter that receives the
|
|
67
|
-
The
|
|
105
|
+
Modifier that sets property setter that receives the owner and the new value as arguments.
|
|
106
|
+
The owner is an object on which the function is called, like `this` in JavaScript.
|
|
68
107
|
*/
|
|
69
|
-
|
|
108
|
+
@discardableResult
|
|
109
|
+
public func set<ValueType>(_ setter: @escaping (_ this: OwnerType, _ newValue: ValueType) -> Void) -> Self {
|
|
70
110
|
self.setter = SyncFunctionComponent(
|
|
71
111
|
"set",
|
|
72
|
-
firstArgType:
|
|
73
|
-
dynamicArgumentTypes: [~
|
|
112
|
+
firstArgType: OwnerType.self,
|
|
113
|
+
dynamicArgumentTypes: [~OwnerType.self, ~ValueType.self],
|
|
74
114
|
setter
|
|
75
115
|
)
|
|
116
|
+
self.setter?.takesOwner = true
|
|
76
117
|
return self
|
|
77
118
|
}
|
|
78
119
|
|
|
79
120
|
// MARK: - Internals
|
|
80
121
|
|
|
81
|
-
internal func getValue<
|
|
82
|
-
let
|
|
83
|
-
|
|
122
|
+
internal func getValue<ValueType>(owner: OwnerType? = nil) throws -> ValueType? {
|
|
123
|
+
let owner = owner as? AnyObject
|
|
124
|
+
let value = try getter?.call(by: owner, withArguments: [])
|
|
125
|
+
return value as? ValueType
|
|
84
126
|
}
|
|
85
127
|
|
|
86
|
-
internal func setValue(_ value: Any,
|
|
87
|
-
let
|
|
128
|
+
internal func setValue(_ value: Any, owner: OwnerType? = nil) {
|
|
129
|
+
let owner = owner as? AnyObject
|
|
130
|
+
_ = try? setter?.call(by: owner, withArguments: [value])
|
|
88
131
|
}
|
|
89
132
|
|
|
90
133
|
/**
|
|
91
134
|
Creates the JavaScript function that will be used as a getter of the property.
|
|
92
135
|
*/
|
|
93
|
-
internal func buildGetter(inRuntime runtime: JavaScriptRuntime
|
|
94
|
-
return runtime.createSyncFunction(name, argsCount: 0) { [weak self,
|
|
95
|
-
|
|
136
|
+
internal func buildGetter(inRuntime runtime: JavaScriptRuntime) -> JavaScriptObject {
|
|
137
|
+
return runtime.createSyncFunction(name, argsCount: 0) { [weak self, name] this, args in
|
|
138
|
+
guard let self = self else {
|
|
139
|
+
throw NativePropertyUnavailableException(name)
|
|
140
|
+
}
|
|
141
|
+
guard let getter = self.getter else {
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
return try getter.call(by: this, withArguments: args)
|
|
96
145
|
}
|
|
97
146
|
}
|
|
98
147
|
|
|
99
148
|
/**
|
|
100
149
|
Creates the JavaScript function that will be used as a setter of the property.
|
|
101
150
|
*/
|
|
102
|
-
internal func buildSetter(inRuntime runtime: JavaScriptRuntime
|
|
103
|
-
return runtime.createSyncFunction(name, argsCount: 1) { [weak self,
|
|
104
|
-
|
|
151
|
+
internal func buildSetter(inRuntime runtime: JavaScriptRuntime) -> JavaScriptObject {
|
|
152
|
+
return runtime.createSyncFunction(name, argsCount: 1) { [weak self, name] this, args in
|
|
153
|
+
guard let self = self else {
|
|
154
|
+
throw NativePropertyUnavailableException(name)
|
|
155
|
+
}
|
|
156
|
+
guard let setter = self.setter else {
|
|
157
|
+
return
|
|
158
|
+
}
|
|
159
|
+
return try setter.call(by: this, withArguments: args)
|
|
105
160
|
}
|
|
106
161
|
}
|
|
107
162
|
|
|
108
163
|
/**
|
|
109
164
|
Creates the JavaScript object representing the property descriptor.
|
|
110
165
|
*/
|
|
111
|
-
internal func buildDescriptor(inRuntime runtime: JavaScriptRuntime
|
|
166
|
+
internal func buildDescriptor(inRuntime runtime: JavaScriptRuntime) -> JavaScriptObject {
|
|
112
167
|
let descriptor = runtime.createObject()
|
|
113
168
|
|
|
114
169
|
descriptor.setProperty("enumerable", value: true)
|
|
115
170
|
|
|
116
171
|
if getter != nil {
|
|
117
|
-
descriptor.setProperty("get", value: buildGetter(inRuntime: runtime
|
|
172
|
+
descriptor.setProperty("get", value: buildGetter(inRuntime: runtime))
|
|
118
173
|
}
|
|
119
174
|
if setter != nil {
|
|
120
|
-
descriptor.setProperty("set", value: buildSetter(inRuntime: runtime
|
|
175
|
+
descriptor.setProperty("set", value: buildSetter(inRuntime: runtime))
|
|
121
176
|
}
|
|
122
177
|
return descriptor
|
|
123
178
|
}
|
|
124
179
|
}
|
|
125
180
|
|
|
181
|
+
// MARK: - Exceptions
|
|
182
|
+
|
|
183
|
+
internal final class NativePropertyUnavailableException: GenericException<String> {
|
|
184
|
+
override var reason: String {
|
|
185
|
+
return "Native property '\(param)' is no longer available in memory"
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
126
189
|
// MARK: - Factory functions
|
|
127
190
|
|
|
128
191
|
/**
|
|
129
192
|
Creates the property with given name. The component is basically no-op if you don't call `.get(_:)` or `.set(_:)` on it.
|
|
130
193
|
*/
|
|
131
|
-
public func Property(_ name: String) -> PropertyComponent {
|
|
194
|
+
public func Property(_ name: String) -> PropertyComponent<Void> {
|
|
132
195
|
return PropertyComponent(name: name)
|
|
133
196
|
}
|
|
134
197
|
|
|
135
198
|
/**
|
|
136
|
-
Creates the read-only property whose getter doesn't take the
|
|
199
|
+
Creates the read-only property whose getter doesn't take the owner as an argument.
|
|
137
200
|
*/
|
|
138
|
-
public func Property<Value: AnyArgument>(_ name: String, @_implicitSelfCapture get: @escaping () -> Value) -> PropertyComponent {
|
|
139
|
-
return PropertyComponent(name: name
|
|
201
|
+
public func Property<Value: AnyArgument>(_ name: String, @_implicitSelfCapture get: @escaping () -> Value) -> PropertyComponent<Void> {
|
|
202
|
+
return PropertyComponent(name: name, getter: get)
|
|
140
203
|
}
|
|
141
204
|
|
|
142
205
|
/**
|
|
143
|
-
Creates the read-only property whose getter takes the
|
|
206
|
+
Creates the read-only property whose getter takes the owner as an argument.
|
|
144
207
|
*/
|
|
145
|
-
public func Property<Value: AnyArgument,
|
|
208
|
+
public func Property<Value: AnyArgument, OwnerType>(
|
|
146
209
|
_ name: String,
|
|
147
|
-
@_implicitSelfCapture get: @escaping (
|
|
148
|
-
) -> PropertyComponent {
|
|
149
|
-
return PropertyComponent(name: name
|
|
210
|
+
@_implicitSelfCapture get: @escaping (_ this: OwnerType) -> Value
|
|
211
|
+
) -> PropertyComponent<OwnerType> {
|
|
212
|
+
return PropertyComponent<OwnerType>(name: name, getter: get)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
Creates the property that references to an immutable property of the owner object using the key path.
|
|
217
|
+
*/
|
|
218
|
+
public func Property<Value: AnyArgument, OwnerType>(
|
|
219
|
+
_ name: String,
|
|
220
|
+
_ keyPath: KeyPath<OwnerType, Value>
|
|
221
|
+
) -> PropertyComponent<OwnerType> {
|
|
222
|
+
return PropertyComponent<OwnerType>(name: name) { owner in
|
|
223
|
+
return owner[keyPath: keyPath]
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
Creates the property that references to a mutable property of the owner object using the key path.
|
|
229
|
+
*/
|
|
230
|
+
public func Property<Value: AnyArgument, OwnerType>(
|
|
231
|
+
_ name: String,
|
|
232
|
+
_ keyPath: ReferenceWritableKeyPath<OwnerType, Value>
|
|
233
|
+
) -> PropertyComponent<OwnerType> {
|
|
234
|
+
return PropertyComponent<OwnerType>(name: name) { owner in
|
|
235
|
+
return owner[keyPath: keyPath]
|
|
236
|
+
}
|
|
237
|
+
.set { owner, newValue in
|
|
238
|
+
owner[keyPath: keyPath] = newValue
|
|
239
|
+
}
|
|
150
240
|
}
|
|
@@ -11,6 +11,11 @@ open class SharedObject: AnySharedObject {
|
|
|
11
11
|
*/
|
|
12
12
|
public internal(set) var sharedObjectId: SharedObjectId = 0
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
The default public initializer of the shared object.
|
|
16
|
+
*/
|
|
17
|
+
public init() {}
|
|
18
|
+
|
|
14
19
|
/**
|
|
15
20
|
Returns the JavaScript shared object associated with the native shared object.
|
|
16
21
|
*/
|
|
@@ -169,6 +169,17 @@ class ClassComponentSpec: ExpoSpec {
|
|
|
169
169
|
expect(newValue.kind) == .number
|
|
170
170
|
expect(newValue.getInt()) == value + incrementBy
|
|
171
171
|
}
|
|
172
|
+
|
|
173
|
+
it("gets value from the dynamic property") {
|
|
174
|
+
let initialValue = Int.random(in: 1..<100)
|
|
175
|
+
let value = try runtime!.eval([
|
|
176
|
+
"object = new expo.modules.TestModule.Counter(\(initialValue))",
|
|
177
|
+
"object.currentValue"
|
|
178
|
+
])
|
|
179
|
+
|
|
180
|
+
expect(value.kind) == .number
|
|
181
|
+
expect(value.getInt()) == initialValue
|
|
182
|
+
}
|
|
172
183
|
}
|
|
173
184
|
}
|
|
174
185
|
}
|
|
@@ -190,6 +201,10 @@ fileprivate final class ModuleWithCounterClass: Module {
|
|
|
190
201
|
Function("getValue") { counter in
|
|
191
202
|
return counter.currentValue
|
|
192
203
|
}
|
|
204
|
+
|
|
205
|
+
Property("currentValue") { counter in
|
|
206
|
+
return counter.currentValue
|
|
207
|
+
}
|
|
193
208
|
}
|
|
194
209
|
}
|
|
195
210
|
}
|
|
@@ -40,6 +40,34 @@ final class EitherSpec: ExpoSpec {
|
|
|
40
40
|
it("throws when converting from neither type") {
|
|
41
41
|
expect({ try Either<String, Int>.convert(from: true) }).to(throwError(errorType: NeitherTypeException.self))
|
|
42
42
|
}
|
|
43
|
+
|
|
44
|
+
it("supports arrays") {
|
|
45
|
+
let either = try Either<String, [String]>.convert(from: ["foo"])
|
|
46
|
+
let value: [String]? = either.get()
|
|
47
|
+
|
|
48
|
+
expect(either.is([String].self)) == true
|
|
49
|
+
expect(value) == ["foo"]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
it("supports convertibles (UIColor)") {
|
|
53
|
+
let either = try Either<Int, UIColor>.convert(from: "blue")
|
|
54
|
+
let color: UIColor? = either.get()
|
|
55
|
+
|
|
56
|
+
expect(either.is(UIColor.self)) == true
|
|
57
|
+
expect(color?.cgColor.components) == CGColor(red: 0, green: 0, blue: 1, alpha: 1).components
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
it("supports records") {
|
|
61
|
+
struct TestRecord: Record {
|
|
62
|
+
@Field
|
|
63
|
+
var foo: String
|
|
64
|
+
}
|
|
65
|
+
let either = try Either<String, TestRecord>.convert(from: ["foo": "bar"])
|
|
66
|
+
let record: TestRecord? = either.get()
|
|
67
|
+
|
|
68
|
+
expect(either.is(TestRecord.self)) == true
|
|
69
|
+
expect(record?.foo) == "bar"
|
|
70
|
+
}
|
|
43
71
|
}
|
|
44
72
|
describe("EitherOfThree") {
|
|
45
73
|
it("is the third type") {
|