expo-modules-core 0.6.1 → 0.7.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 +38 -0
- package/README.md +1 -1
- package/android/build.gradle +5 -5
- package/android/src/main/java/expo/modules/adapters/react/apploader/RNHeadlessAppLoader.kt +7 -1
- package/android/src/main/java/expo/modules/core/interfaces/ReactActivityLifecycleListener.java +23 -0
- package/android/src/main/java/expo/modules/kotlin/AppContext.kt +11 -1
- package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +5 -3
- package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +8 -2
- package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +13 -4
- package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +7 -6
- package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +6 -1
- package/android/src/main/java/expo/modules/kotlin/Promise.kt +1 -1
- package/android/src/main/java/expo/modules/kotlin/callbacks/Callback.kt +5 -0
- package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallback.kt +28 -0
- package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallbackDelegate.kt +27 -0
- package/android/src/main/java/expo/modules/kotlin/defaultmodules/ErrorManagerModule.kt +25 -0
- package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +68 -8
- package/android/src/main/java/expo/modules/kotlin/exception/ExceptionDecorator.kt +11 -0
- package/android/src/main/java/expo/modules/kotlin/methods/AnyMethod.kt +13 -14
- package/android/src/main/java/expo/modules/kotlin/modules/DefinitionMarker.kt +4 -0
- package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +3 -2
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +44 -4
- package/android/src/main/java/expo/modules/kotlin/records/Record.kt +39 -0
- package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +14 -7
- package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +11 -5
- package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +10 -4
- package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +12 -6
- package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +29 -13
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +2 -1
- package/android/src/main/java/expo/modules/kotlin/views/CallbacksDefinition.kt +3 -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 +22 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +27 -2
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +29 -1
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +59 -2
- package/build/EventEmitter.d.ts +1 -0
- package/build/EventEmitter.d.ts.map +1 -0
- package/build/NativeModulesProxy.d.ts +1 -0
- package/build/NativeModulesProxy.d.ts.map +1 -0
- package/build/NativeModulesProxy.native.d.ts +1 -0
- package/build/NativeModulesProxy.native.d.ts.map +1 -0
- package/build/NativeModulesProxy.types.d.ts +1 -0
- package/build/NativeModulesProxy.types.d.ts.map +1 -0
- package/build/NativeViewManagerAdapter.d.ts +1 -0
- package/build/NativeViewManagerAdapter.d.ts.map +1 -0
- package/build/NativeViewManagerAdapter.native.d.ts +1 -0
- package/build/NativeViewManagerAdapter.native.d.ts.map +1 -0
- package/build/PermissionsHook.d.ts +1 -0
- package/build/PermissionsHook.d.ts.map +1 -0
- package/build/PermissionsInterface.d.ts +1 -0
- package/build/PermissionsInterface.d.ts.map +1 -0
- package/build/Platform.d.ts +1 -0
- package/build/Platform.d.ts.map +1 -0
- package/build/SyntheticPlatformEmitter.d.ts +1 -0
- package/build/SyntheticPlatformEmitter.d.ts.map +1 -0
- package/build/SyntheticPlatformEmitter.web.d.ts +1 -0
- package/build/SyntheticPlatformEmitter.web.d.ts.map +1 -0
- package/build/deprecate.d.ts +1 -0
- package/build/deprecate.d.ts.map +1 -0
- package/build/environment/browser.d.ts +1 -0
- package/build/environment/browser.d.ts.map +1 -0
- package/build/environment/browser.web.d.ts +1 -0
- package/build/environment/browser.web.d.ts.map +1 -0
- package/build/errors/CodedError.d.ts +1 -0
- package/build/errors/CodedError.d.ts.map +1 -0
- package/build/errors/UnavailabilityError.d.ts +1 -0
- package/build/errors/UnavailabilityError.d.ts.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +2 -0
- package/build/index.js.map +1 -1
- package/build/requireNativeModule.d.ts +16 -0
- package/build/requireNativeModule.d.ts.map +1 -0
- package/build/requireNativeModule.js +18 -0
- package/build/requireNativeModule.js.map +1 -0
- package/build/sweet/NativeErrorManager.d.ts +3 -0
- package/build/sweet/NativeErrorManager.d.ts.map +1 -0
- package/build/sweet/NativeErrorManager.js +3 -0
- package/build/sweet/NativeErrorManager.js.map +1 -0
- package/build/sweet/setUpErrorManager.fx.d.ts +2 -0
- package/build/sweet/setUpErrorManager.fx.d.ts.map +1 -0
- package/build/sweet/setUpErrorManager.fx.js +11 -0
- package/build/sweet/setUpErrorManager.fx.js.map +1 -0
- package/ios/AppDelegates/ExpoAppDelegate.swift +27 -8
- package/ios/JSI/ExpoModulesHostObject.h +33 -0
- package/ios/JSI/ExpoModulesHostObject.mm +40 -0
- package/ios/JSI/ExpoModulesProxySpec.h +4 -0
- package/ios/JSI/ExpoModulesProxySpec.mm +1 -3
- package/ios/JSI/JSIConversions.h +2 -0
- package/ios/JSI/JSIConversions.mm +9 -0
- package/ios/JSI/JSIInstaller.h +10 -0
- package/ios/JSI/JSIInstaller.mm +14 -2
- package/ios/JSI/JavaScriptObject.h +60 -0
- package/ios/JSI/JavaScriptObject.mm +93 -0
- package/ios/JSI/JavaScriptRuntime.h +54 -0
- package/ios/JSI/JavaScriptRuntime.mm +102 -0
- package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +2 -12
- package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.h +16 -0
- package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.m +28 -0
- package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +90 -66
- package/ios/RCTComponentData+Privates.h +12 -0
- package/ios/ReactDelegates/ExpoReactDelegate.swift +2 -2
- package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +3 -3
- package/ios/ReactDelegates/ModulePriorities.swift +1 -1
- package/ios/Swift/AppContext.swift +38 -4
- package/ios/Swift/Arguments/ArgumentType.swift +4 -0
- package/ios/Swift/Arguments/Convertibles.swift +13 -13
- package/ios/Swift/Arguments/Types/EnumArgumentType.swift +11 -17
- package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +1 -1
- package/ios/Swift/Arguments/Types/RawArgumentType.swift +2 -2
- package/ios/Swift/Conversions.swift +51 -56
- package/ios/Swift/EventListener.swift +8 -10
- package/ios/Swift/Events/Callback.swift +66 -0
- package/ios/Swift/Events/Event.swift +43 -0
- package/ios/Swift/Exceptions/ChainableException.swift +51 -0
- package/ios/Swift/{CodedError.swift → Exceptions/CodedError.swift} +1 -12
- package/ios/Swift/Exceptions/Exception.swift +62 -0
- package/ios/Swift/Exceptions/ExceptionOrigin.swift +28 -0
- package/ios/Swift/Exceptions/GenericException.swift +20 -0
- package/ios/Swift/Exceptions/UnexpectedException.swift +16 -0
- package/ios/Swift/Functions/AnyFunction.swift +11 -1
- package/ios/Swift/Functions/ConcreteFunction.swift +37 -16
- package/ios/Swift/JavaScriptUtils.swift +43 -0
- package/ios/Swift/ModuleHolder.swift +53 -14
- package/ios/Swift/ModuleRegistry.swift +4 -1
- package/ios/Swift/Modules/AnyModule.swift +0 -1
- package/ios/Swift/Modules/ModuleDefinition.swift +4 -13
- package/ios/Swift/Modules/ModuleDefinitionBuilder.swift +0 -1
- package/ios/Swift/Modules/ModuleDefinitionComponents.swift +0 -188
- package/ios/Swift/ModulesProvider.swift +0 -1
- package/ios/Swift/Objects/ObjectDefinition.swift +30 -0
- package/ios/Swift/Objects/ObjectDefinitionComponents.swift +208 -0
- package/ios/Swift/Promise.swift +8 -3
- package/ios/Swift/Records/AnyField.swift +7 -0
- package/ios/Swift/Records/Field.swift +24 -19
- package/ios/Swift/Records/FieldOption.swift +1 -1
- package/ios/Swift/Records/Record.swift +12 -4
- package/ios/Swift/SwiftInteropBridge.swift +39 -10
- package/ios/Swift/Views/AnyViewProp.swift +1 -1
- package/ios/Swift/Views/ComponentData.swift +95 -0
- package/ios/Swift/Views/ConcreteViewProp.swift +6 -8
- package/ios/Swift/Views/ViewFactory.swift +1 -1
- package/ios/Swift/Views/ViewManagerDefinition.swift +23 -2
- package/ios/Swift/Views/ViewManagerDefinitionBuilder.swift +0 -1
- package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +26 -0
- package/ios/Swift/Views/ViewModuleWrapper.swift +5 -2
- package/ios/Tests/ArgumentTypeSpec.swift +3 -4
- package/ios/Tests/ConstantsSpec.swift +4 -4
- package/ios/Tests/ConvertiblesSpec.swift +33 -33
- package/ios/Tests/ExceptionsSpec.swift +112 -0
- package/ios/Tests/FunctionSpec.swift +20 -22
- package/ios/Tests/FunctionWithConvertiblesSpec.swift +2 -2
- package/ios/Tests/Mocks/ModuleMocks.swift +1 -1
- package/ios/Tests/Mocks/ModulesProviderMock.swift +0 -1
- package/ios/Tests/ModuleEventListenersSpec.swift +1 -1
- package/ios/Tests/RecordSpec.swift +7 -17
- package/package.json +3 -3
- package/src/index.ts +4 -0
- package/src/requireNativeModule.ts +29 -0
- package/src/sweet/NativeErrorManager.ts +2 -0
- package/src/sweet/setUpErrorManager.fx.ts +12 -0
|
@@ -18,7 +18,7 @@ public extension CodedError {
|
|
|
18
18
|
*/
|
|
19
19
|
var code: String {
|
|
20
20
|
let className = String(describing: type(of: self))
|
|
21
|
-
.replacingOccurrences(of: #"(Error)?(<.*>)?$"#, with: "", options: .regularExpression)
|
|
21
|
+
.replacingOccurrences(of: #"(Error|Exception)?(<.*>)?$"#, with: "", options: .regularExpression)
|
|
22
22
|
let regex = try! NSRegularExpression(pattern: "(.)([A-Z])", options: [])
|
|
23
23
|
let range = NSRange(location: 0, length: className.count)
|
|
24
24
|
|
|
@@ -48,14 +48,3 @@ public struct SimpleCodedError: CodedError {
|
|
|
48
48
|
self.description = description
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
Coded wrapper for uncoded errors. Intended to be used to handle unexpected native errors.
|
|
54
|
-
*/
|
|
55
|
-
public struct UnexpectedError: CodedError {
|
|
56
|
-
public let description: String
|
|
57
|
-
|
|
58
|
-
init(_ error: Error) {
|
|
59
|
-
self.description = error.localizedDescription
|
|
60
|
-
}
|
|
61
|
-
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
open class Exception: CodedError, ChainableException, CustomStringConvertible, CustomDebugStringConvertible {
|
|
4
|
+
open var name: String {
|
|
5
|
+
return String(describing: Self.self)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
String describing the reason of the exception.
|
|
10
|
+
*/
|
|
11
|
+
open var reason: String {
|
|
12
|
+
"undefined reason"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
The origin in code where the exception was created.
|
|
17
|
+
*/
|
|
18
|
+
open var origin: ExceptionOrigin
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
The default initializer that captures the place in the code where the exception was created.
|
|
22
|
+
- Warning: Call it only without arguments!
|
|
23
|
+
*/
|
|
24
|
+
public init(file: String = #fileID, line: UInt = #line, function: String = #function) {
|
|
25
|
+
self.origin = ExceptionOrigin(file: file, line: line, function: function)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// MARK: ChainableException
|
|
29
|
+
|
|
30
|
+
open var cause: Error?
|
|
31
|
+
|
|
32
|
+
// MARK: CustomStringConvertible
|
|
33
|
+
|
|
34
|
+
open var description: String {
|
|
35
|
+
return concatDescription(reason, withCause: cause, debug: false)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// MARK: CustomDebugStringConvertible
|
|
39
|
+
|
|
40
|
+
open var debugDescription: String {
|
|
41
|
+
let debugDescription = "\(name): \(reason) (at \(origin.file):\(origin.line))"
|
|
42
|
+
return concatDescription(debugDescription, withCause: cause, debug: true)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
Concatenates the exception description with its cause description.
|
|
48
|
+
*/
|
|
49
|
+
private func concatDescription(_ description: String, withCause cause: Error?, debug: Bool = false) -> String {
|
|
50
|
+
let causeSeparator = "\n→ Caused by: "
|
|
51
|
+
switch cause {
|
|
52
|
+
case let cause as Exception:
|
|
53
|
+
return description + causeSeparator + (debug ? cause.debugDescription : cause.description)
|
|
54
|
+
case let cause as CodedError:
|
|
55
|
+
// `CodedError` is deprecated but we need to provide backwards compatibility as some modules already used it.
|
|
56
|
+
return description + causeSeparator + cause.description
|
|
57
|
+
case let cause?:
|
|
58
|
+
return description + causeSeparator + cause.localizedDescription
|
|
59
|
+
default:
|
|
60
|
+
return description
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
Represents the place in code where the exception was created.
|
|
5
|
+
*/
|
|
6
|
+
public struct ExceptionOrigin: CustomStringConvertible {
|
|
7
|
+
/**
|
|
8
|
+
The path to the file in which the exception was created.
|
|
9
|
+
*/
|
|
10
|
+
let file: String
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
The line number on which the exception was created.
|
|
14
|
+
*/
|
|
15
|
+
let line: UInt
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
The name (selector) of the declaration in which the exception was created.
|
|
19
|
+
*/
|
|
20
|
+
let function: String
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
Stringified representation of the exception origin.
|
|
24
|
+
*/
|
|
25
|
+
public var description: String {
|
|
26
|
+
"at \(file):\(line) in \(function)"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
The exception that needs some additional parameters to be best described.
|
|
5
|
+
*/
|
|
6
|
+
open class GenericException<ParamType>: Exception {
|
|
7
|
+
/**
|
|
8
|
+
The additional parameter passed to the initializer.
|
|
9
|
+
*/
|
|
10
|
+
public let param: ParamType
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
The default initializer that takes a param and captures the place in the code where the exception was created.
|
|
14
|
+
- Warning: Call it only with one argument! If you need to pass more parameters, use a tuple instead.
|
|
15
|
+
*/
|
|
16
|
+
public init(_ param: ParamType, file: String = #fileID, line: UInt = #line, function: String = #function) {
|
|
17
|
+
self.param = param
|
|
18
|
+
super.init(file: file, line: line, function: function)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
Exception wrapper used to handle unexpected internal native errors.
|
|
5
|
+
*/
|
|
6
|
+
public class UnexpectedException: Exception {
|
|
7
|
+
private let errorDescription: String
|
|
8
|
+
|
|
9
|
+
public init(_ error: Error) {
|
|
10
|
+
self.errorDescription = error.localizedDescription
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public override var reason: String {
|
|
14
|
+
return errorDescription
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -24,10 +24,15 @@ public protocol AnyFunction: AnyDefinition {
|
|
|
24
24
|
*/
|
|
25
25
|
var queue: DispatchQueue? { get }
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
Whether the function needs to be called asynchronously from JavaScript.
|
|
29
|
+
*/
|
|
30
|
+
var isAsync: Bool { get }
|
|
31
|
+
|
|
27
32
|
/**
|
|
28
33
|
Calls the function on given module with arguments and a promise.
|
|
29
34
|
*/
|
|
30
|
-
func call(args: [Any], promise: Promise)
|
|
35
|
+
func call(args: [Any], promise: Promise)
|
|
31
36
|
|
|
32
37
|
/**
|
|
33
38
|
Synchronously calls the function with given arguments. If the function takes a promise,
|
|
@@ -39,4 +44,9 @@ public protocol AnyFunction: AnyDefinition {
|
|
|
39
44
|
Specifies on which queue the function should run.
|
|
40
45
|
*/
|
|
41
46
|
func runOnQueue(_ queue: DispatchQueue?) -> Self
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
Makes the JavaScript function synchronous.
|
|
50
|
+
*/
|
|
51
|
+
func runSynchronously() -> Self
|
|
42
52
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Dispatch
|
|
2
2
|
|
|
3
3
|
public final class ConcreteFunction<Args, ReturnType>: AnyFunction {
|
|
4
|
-
public typealias ClosureType = (Args) -> ReturnType
|
|
4
|
+
public typealias ClosureType = (Args) throws -> ReturnType
|
|
5
5
|
|
|
6
6
|
public let name: String
|
|
7
7
|
|
|
@@ -15,6 +15,8 @@ public final class ConcreteFunction<Args, ReturnType>: AnyFunction {
|
|
|
15
15
|
|
|
16
16
|
public var queue: DispatchQueue?
|
|
17
17
|
|
|
18
|
+
public var isAsync: Bool = true
|
|
19
|
+
|
|
18
20
|
let closure: ClosureType
|
|
19
21
|
|
|
20
22
|
let argTypes: [AnyArgumentType]
|
|
@@ -41,12 +43,12 @@ public final class ConcreteFunction<Args, ReturnType>: AnyFunction {
|
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
let tuple = try Conversions.toTuple(finalArgs) as! Args
|
|
44
|
-
returnedValue = closure(tuple)
|
|
46
|
+
returnedValue = try closure(tuple)
|
|
45
47
|
} catch let error as CodedError {
|
|
46
|
-
promise.reject(error)
|
|
48
|
+
promise.reject(FunctionCallException(name).causedBy(error))
|
|
47
49
|
return
|
|
48
|
-
} catch
|
|
49
|
-
promise.reject(
|
|
50
|
+
} catch {
|
|
51
|
+
promise.reject(UnexpectedException(error))
|
|
50
52
|
return
|
|
51
53
|
}
|
|
52
54
|
if !takesPromise {
|
|
@@ -62,7 +64,7 @@ public final class ConcreteFunction<Args, ReturnType>: AnyFunction {
|
|
|
62
64
|
let promise = Promise {
|
|
63
65
|
result = $0
|
|
64
66
|
semaphore.signal()
|
|
65
|
-
} rejecter: {
|
|
67
|
+
} rejecter: { _ in
|
|
66
68
|
semaphore.signal()
|
|
67
69
|
}
|
|
68
70
|
call(args: args, promise: promise)
|
|
@@ -72,7 +74,7 @@ public final class ConcreteFunction<Args, ReturnType>: AnyFunction {
|
|
|
72
74
|
do {
|
|
73
75
|
let finalArgs = try castArguments(args)
|
|
74
76
|
let tuple = try Conversions.toTuple(finalArgs) as! Args
|
|
75
|
-
return closure(tuple)
|
|
77
|
+
return try closure(tuple)
|
|
76
78
|
} catch let error {
|
|
77
79
|
return error
|
|
78
80
|
}
|
|
@@ -84,27 +86,46 @@ public final class ConcreteFunction<Args, ReturnType>: AnyFunction {
|
|
|
84
86
|
return self
|
|
85
87
|
}
|
|
86
88
|
|
|
89
|
+
public func runSynchronously() -> Self {
|
|
90
|
+
self.isAsync = false
|
|
91
|
+
return self
|
|
92
|
+
}
|
|
93
|
+
|
|
87
94
|
private func argumentType(atIndex index: Int) -> AnyArgumentType? {
|
|
88
95
|
return (0..<argTypes.count).contains(index) ? argTypes[index] : nil
|
|
89
96
|
}
|
|
90
97
|
|
|
91
98
|
private func castArguments(_ args: [Any]) throws -> [Any] {
|
|
92
99
|
if args.count != argumentsCount {
|
|
93
|
-
throw
|
|
100
|
+
throw InvalidArgsNumberException((received: args.count, expected: argumentsCount))
|
|
94
101
|
}
|
|
95
|
-
return try args.enumerated().map {
|
|
102
|
+
return try args.enumerated().map { index, arg in
|
|
96
103
|
let expectedType = argumentType(atIndex: index)
|
|
97
104
|
|
|
98
|
-
|
|
99
|
-
|
|
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
|
+
}
|
|
100
111
|
}
|
|
101
112
|
}
|
|
102
113
|
}
|
|
103
114
|
|
|
104
|
-
internal
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
+
}
|
|
126
|
+
|
|
127
|
+
internal class FunctionCallException: GenericException<String> {
|
|
128
|
+
override var reason: String {
|
|
129
|
+
"Call to function '\(param)' has been rejected"
|
|
109
130
|
}
|
|
110
131
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
// FIXME: Calling module's functions needs solid refactoring to not reference the module holder.
|
|
4
|
+
// Instead, it should be possible to directly call the function instance from here. (added by @tsapeta)
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
Creates a block that is executed when the module's async function is called.
|
|
8
|
+
*/
|
|
9
|
+
internal func createAsyncFunctionBlock(holder: ModuleHolder, name functionName: String) -> JSAsyncFunctionBlock {
|
|
10
|
+
let moduleName = holder.name
|
|
11
|
+
return { [weak holder, moduleName] args, resolve, reject in
|
|
12
|
+
guard let holder = holder else {
|
|
13
|
+
let exception = ModuleUnavailableException(moduleName)
|
|
14
|
+
reject(exception.code, exception.description, exception)
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
holder.call(function: functionName, args: args) { result, error in
|
|
18
|
+
if let error = error {
|
|
19
|
+
reject(error.code, error.description, error)
|
|
20
|
+
} else {
|
|
21
|
+
resolve(result)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
Creates a block that is executed when the module's sync function is called.
|
|
29
|
+
*/
|
|
30
|
+
internal func createSyncFunctionBlock(holder: ModuleHolder, name functionName: String) -> JSSyncFunctionBlock {
|
|
31
|
+
return { [weak holder] args in
|
|
32
|
+
guard let holder = holder else {
|
|
33
|
+
return nil
|
|
34
|
+
}
|
|
35
|
+
return holder.callSync(function: functionName, args: args)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private class ModuleUnavailableException: GenericException<String> {
|
|
40
|
+
override var reason: String {
|
|
41
|
+
"Module '\(param)' is no longer available"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -14,6 +14,11 @@ public final class ModuleHolder {
|
|
|
14
14
|
*/
|
|
15
15
|
private(set) weak var appContext: AppContext?
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
JavaScript object that represents the module instance in the runtime.
|
|
19
|
+
*/
|
|
20
|
+
public internal(set) lazy var javaScriptObject: JavaScriptObject? = createJavaScriptModuleObject()
|
|
21
|
+
|
|
17
22
|
/**
|
|
18
23
|
Caches the definition of the module type.
|
|
19
24
|
*/
|
|
@@ -26,6 +31,13 @@ public final class ModuleHolder {
|
|
|
26
31
|
return definition.name.isEmpty ? String(describing: type(of: module)) : definition.name
|
|
27
32
|
}
|
|
28
33
|
|
|
34
|
+
/**
|
|
35
|
+
Shortcut to get the underlying view manager definition.
|
|
36
|
+
*/
|
|
37
|
+
var viewManager: ViewManagerDefinition? {
|
|
38
|
+
return definition.viewManager
|
|
39
|
+
}
|
|
40
|
+
|
|
29
41
|
/**
|
|
30
42
|
Number of JavaScript listeners attached to the module.
|
|
31
43
|
*/
|
|
@@ -54,7 +66,7 @@ public final class ModuleHolder {
|
|
|
54
66
|
func call(function functionName: String, args: [Any], promise: Promise) {
|
|
55
67
|
do {
|
|
56
68
|
guard let function = definition.functions[functionName] else {
|
|
57
|
-
throw
|
|
69
|
+
throw FunctionNotFoundException((functionName: functionName, moduleName: self.name))
|
|
58
70
|
}
|
|
59
71
|
let queue = function.queue ?? DispatchQueue.global(qos: .default)
|
|
60
72
|
|
|
@@ -64,7 +76,7 @@ public final class ModuleHolder {
|
|
|
64
76
|
} catch let error as CodedError {
|
|
65
77
|
promise.reject(error)
|
|
66
78
|
} catch {
|
|
67
|
-
promise.reject(
|
|
79
|
+
promise.reject(UnexpectedException(error))
|
|
68
80
|
}
|
|
69
81
|
}
|
|
70
82
|
|
|
@@ -85,6 +97,36 @@ public final class ModuleHolder {
|
|
|
85
97
|
return nil
|
|
86
98
|
}
|
|
87
99
|
|
|
100
|
+
// MARK: JavaScript Module Object
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
Creates the JavaScript object that will be used to communicate with the native module.
|
|
104
|
+
The object is prefilled with module's constants and functions.
|
|
105
|
+
JavaScript can access it through `global.ExpoModules[moduleName]`.
|
|
106
|
+
- Note: The object will be `nil` when the runtime is unavailable (e.g. remote debugger is enabled).
|
|
107
|
+
*/
|
|
108
|
+
private func createJavaScriptModuleObject() -> JavaScriptObject? {
|
|
109
|
+
// It might be impossible to create any object at the moment (e.g. remote debugging, app context destroyed)
|
|
110
|
+
guard let object = appContext?.runtime?.createObject() else {
|
|
111
|
+
return nil
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Fill in with constants
|
|
115
|
+
for (key, value) in getConstants() {
|
|
116
|
+
object[key] = value
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Fill in with functions
|
|
120
|
+
for (_, fn) in definition.functions {
|
|
121
|
+
if fn.isAsync {
|
|
122
|
+
object.setAsyncFunction(fn.name, argsCount: fn.argumentsCount, block: createAsyncFunctionBlock(holder: self, name: fn.name))
|
|
123
|
+
} else {
|
|
124
|
+
object.setSyncFunction(fn.name, argsCount: fn.argumentsCount, block: createSyncFunctionBlock(holder: self, name: fn.name))
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return object
|
|
128
|
+
}
|
|
129
|
+
|
|
88
130
|
// MARK: Listening to native events
|
|
89
131
|
|
|
90
132
|
func listeners(forEvent event: EventName) -> [EventListener] {
|
|
@@ -112,9 +154,9 @@ public final class ModuleHolder {
|
|
|
112
154
|
*/
|
|
113
155
|
func modifyListenersCount(_ count: Int) {
|
|
114
156
|
if count > 0 && listenersCount == 0 {
|
|
115
|
-
|
|
157
|
+
_ = definition.functions["startObserving"]?.callSync(args: [])
|
|
116
158
|
} else if count < 0 && listenersCount + count <= 0 {
|
|
117
|
-
|
|
159
|
+
_ = definition.functions["stopObserving"]?.callSync(args: [])
|
|
118
160
|
}
|
|
119
161
|
listenersCount = max(0, listenersCount + count)
|
|
120
162
|
}
|
|
@@ -125,20 +167,17 @@ public final class ModuleHolder {
|
|
|
125
167
|
post(event: .moduleDestroy)
|
|
126
168
|
}
|
|
127
169
|
|
|
128
|
-
// MARK:
|
|
170
|
+
// MARK: - Exceptions
|
|
129
171
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
"Cannot find module `\(moduleName)`"
|
|
172
|
+
internal class ModuleNotFoundException: GenericException<String> {
|
|
173
|
+
override var reason: String {
|
|
174
|
+
"Module '\(param)' not found"
|
|
134
175
|
}
|
|
135
176
|
}
|
|
136
177
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
var description: String {
|
|
141
|
-
"Cannot find function `\(functionName)` in module `\(moduleName)`"
|
|
178
|
+
internal class FunctionNotFoundException: GenericException<(functionName: String, moduleName: String)> {
|
|
179
|
+
override var reason: String {
|
|
180
|
+
"Function '\(param.functionName)' not found in module '\(param.moduleName)'"
|
|
142
181
|
}
|
|
143
182
|
}
|
|
144
183
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
public final class ModuleRegistry: Sequence {
|
|
3
2
|
public typealias Element = ModuleHolder
|
|
4
3
|
|
|
@@ -63,6 +62,10 @@ public final class ModuleRegistry: Sequence {
|
|
|
63
62
|
return registry[moduleName]?.module
|
|
64
63
|
}
|
|
65
64
|
|
|
65
|
+
public func getModuleNames() -> [String] {
|
|
66
|
+
return Array(registry.keys)
|
|
67
|
+
}
|
|
68
|
+
|
|
66
69
|
public func makeIterator() -> IndexingIterator<[ModuleHolder]> {
|
|
67
70
|
return registry.map({ $1 }).makeIterator()
|
|
68
71
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
/**
|
|
3
2
|
A protocol that must be implemented to be a part of module's definition and the module definition itself.
|
|
4
3
|
*/
|
|
@@ -9,7 +8,7 @@ public protocol AnyDefinition {}
|
|
|
9
8
|
of the module and what it exports to the JavaScript world.
|
|
10
9
|
See `ModuleDefinitionBuilder` for more details on how to create it.
|
|
11
10
|
*/
|
|
12
|
-
public final class ModuleDefinition:
|
|
11
|
+
public final class ModuleDefinition: ObjectDefinition {
|
|
13
12
|
/**
|
|
14
13
|
The module's type associated with the definition. It's used to create the module instance.
|
|
15
14
|
*/
|
|
@@ -20,8 +19,6 @@ public final class ModuleDefinition: AnyDefinition {
|
|
|
20
19
|
*/
|
|
21
20
|
var name: String
|
|
22
21
|
|
|
23
|
-
let functions: [String : AnyFunction]
|
|
24
|
-
let constants: [ConstantsDefinition]
|
|
25
22
|
let eventListeners: [EventListener]
|
|
26
23
|
let viewManager: ViewManagerDefinition?
|
|
27
24
|
|
|
@@ -33,20 +30,12 @@ public final class ModuleDefinition: AnyDefinition {
|
|
|
33
30
|
/**
|
|
34
31
|
Initializer that is called by the `ModuleDefinitionBuilder` results builder.
|
|
35
32
|
*/
|
|
36
|
-
init(definitions: [AnyDefinition]) {
|
|
33
|
+
override init(definitions: [AnyDefinition]) {
|
|
37
34
|
self.name = definitions
|
|
38
35
|
.compactMap { $0 as? ModuleNameDefinition }
|
|
39
36
|
.last?
|
|
40
37
|
.name ?? ""
|
|
41
38
|
|
|
42
|
-
self.functions = definitions
|
|
43
|
-
.compactMap { $0 as? AnyFunction }
|
|
44
|
-
.reduce(into: [String : AnyFunction]()) { dict, function in
|
|
45
|
-
dict[function.name] = function
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
self.constants = definitions.compactMap { $0 as? ConstantsDefinition }
|
|
49
|
-
|
|
50
39
|
self.eventListeners = definitions.compactMap { $0 as? EventListener }
|
|
51
40
|
|
|
52
41
|
self.viewManager = definitions
|
|
@@ -58,6 +47,8 @@ public final class ModuleDefinition: AnyDefinition {
|
|
|
58
47
|
.compactMap { ($0 as? EventsDefinition)?.names }
|
|
59
48
|
.joined()
|
|
60
49
|
)
|
|
50
|
+
|
|
51
|
+
super.init(definitions: definitions)
|
|
61
52
|
}
|
|
62
53
|
|
|
63
54
|
/**
|