expo-modules-core 0.6.4 → 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 +20 -0
- package/README.md +1 -1
- package/android/build.gradle +5 -5
- 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 +18 -10
- 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
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
import UIKit
|
|
4
4
|
import CoreGraphics
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
// Here we extend some common iOS types to implement `ConvertibleArgument` protocol and
|
|
7
|
+
// describe how they can be converted from primitive types received from JavaScript runtime.
|
|
8
|
+
// This allows these types to be used as argument types of functions callable from JavaScript.
|
|
9
|
+
// As an example, when the `CGPoint` type is used as an argument type, its instance can be
|
|
10
|
+
// created from an array of two doubles or an object with `x` and `y` fields.
|
|
11
11
|
|
|
12
12
|
// MARK: - Foundation
|
|
13
13
|
|
|
@@ -19,7 +19,7 @@ extension URL: ConvertibleArgument {
|
|
|
19
19
|
// If it has no scheme, we assume it was the file path.
|
|
20
20
|
return url.scheme != nil ? url : URL(fileURLWithPath: uri)
|
|
21
21
|
}
|
|
22
|
-
throw Conversions.
|
|
22
|
+
throw Conversions.ConvertingException<URL>(value)
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -37,7 +37,7 @@ extension UIColor: ConvertibleArgument {
|
|
|
37
37
|
if let value = value as? Int {
|
|
38
38
|
return try Conversions.toColor(argb: UInt64(value)) as! Self
|
|
39
39
|
}
|
|
40
|
-
throw Conversions.
|
|
40
|
+
throw Conversions.ConvertingException<UIColor>(value)
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -52,7 +52,7 @@ extension CGPoint: ConvertibleArgument {
|
|
|
52
52
|
let args = try Conversions.pickValues(from: value, byKeys: ["x", "y"], as: Double.self)
|
|
53
53
|
return CGPoint(x: args[0], y: args[1])
|
|
54
54
|
}
|
|
55
|
-
throw Conversions.
|
|
55
|
+
throw Conversions.ConvertingException<CGPoint>(value)
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -65,7 +65,7 @@ extension CGSize: ConvertibleArgument {
|
|
|
65
65
|
let args = try Conversions.pickValues(from: value, byKeys: ["width", "height"], as: Double.self)
|
|
66
66
|
return CGSize(width: args[0], height: args[1])
|
|
67
67
|
}
|
|
68
|
-
throw Conversions.
|
|
68
|
+
throw Conversions.ConvertingException<CGSize>(value)
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -78,7 +78,7 @@ extension CGVector: ConvertibleArgument {
|
|
|
78
78
|
let args = try Conversions.pickValues(from: value, byKeys: ["dx", "dy"], as: Double.self)
|
|
79
79
|
return CGVector(dx: args[0], dy: args[1])
|
|
80
80
|
}
|
|
81
|
-
throw Conversions.
|
|
81
|
+
throw Conversions.ConvertingException<CGVector>(value)
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -91,7 +91,7 @@ extension CGRect: ConvertibleArgument {
|
|
|
91
91
|
let args = try Conversions.pickValues(from: value, byKeys: ["x", "y", "width", "height"], as: Double.self)
|
|
92
92
|
return CGRect(x: args[0], y: args[1], width: args[2], height: args[3])
|
|
93
93
|
}
|
|
94
|
-
throw Conversions.
|
|
94
|
+
throw Conversions.ConvertingException<CGRect>(value)
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
|
|
@@ -99,9 +99,9 @@ extension CGColor: ConvertibleArgument {
|
|
|
99
99
|
public static func convert(from value: Any?) throws -> Self {
|
|
100
100
|
do {
|
|
101
101
|
return try UIColor.convert(from: value).cgColor as! Self
|
|
102
|
-
} catch _ as Conversions.
|
|
102
|
+
} catch _ as Conversions.ConvertingException<UIColor> {
|
|
103
103
|
// Rethrow `ConvertingError` with proper type
|
|
104
|
-
throw Conversions.
|
|
104
|
+
throw Conversions.ConvertingException<CGColor>(value)
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
}
|
|
@@ -43,10 +43,10 @@ public protocol EnumArgument: AnyArgument {
|
|
|
43
43
|
public extension EnumArgument where Self: RawRepresentable, Self: Hashable {
|
|
44
44
|
static func create<ArgType>(fromRawValue rawValue: ArgType) throws -> Self {
|
|
45
45
|
guard let rawValue = rawValue as? RawValue else {
|
|
46
|
-
throw
|
|
46
|
+
throw EnumCastingException((type: RawValue.self, value: rawValue))
|
|
47
47
|
}
|
|
48
48
|
guard let enumCase = Self.init(rawValue: rawValue) else {
|
|
49
|
-
throw
|
|
49
|
+
throw EnumNoSuchValueException((type: Self.self, value: rawValue))
|
|
50
50
|
}
|
|
51
51
|
return enumCase
|
|
52
52
|
}
|
|
@@ -75,31 +75,25 @@ public extension EnumArgument where Self: RawRepresentable, Self: Hashable {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
/**
|
|
78
|
-
An error that is thrown when the value cannot be
|
|
78
|
+
An error that is thrown when the value cannot be cast to associated `RawValue`.
|
|
79
79
|
*/
|
|
80
|
-
internal
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
var description: String {
|
|
85
|
-
"Cannot cast value `\(value)` to expected type `\(type)`"
|
|
80
|
+
internal class EnumCastingException: GenericException<(type: Any.Type, value: Any)> {
|
|
81
|
+
override var reason: String {
|
|
82
|
+
"Unable to cast '\(param.value)' to expected type \(param.type)"
|
|
86
83
|
}
|
|
87
84
|
}
|
|
88
85
|
|
|
89
86
|
/**
|
|
90
87
|
An error that is thrown when the value doesn't match any available case.
|
|
91
88
|
*/
|
|
92
|
-
internal
|
|
93
|
-
let type: EnumArgument.Type
|
|
94
|
-
let value: Any
|
|
95
|
-
|
|
89
|
+
internal class EnumNoSuchValueException: GenericException<(type: EnumArgument.Type, value: Any)> {
|
|
96
90
|
var allRawValuesFormatted: String {
|
|
97
|
-
return type.allRawValues
|
|
98
|
-
.map { "
|
|
91
|
+
return param.type.allRawValues
|
|
92
|
+
.map { "'\($0)'" }
|
|
99
93
|
.joined(separator: ", ")
|
|
100
94
|
}
|
|
101
95
|
|
|
102
|
-
var
|
|
103
|
-
"
|
|
96
|
+
override var reason: String {
|
|
97
|
+
"'\(param.value)' is not present in \(param.type) enum, it must be one of: \(allRawValuesFormatted)"
|
|
104
98
|
}
|
|
105
99
|
}
|
|
@@ -8,7 +8,7 @@ internal struct PromiseArgumentType: AnyArgumentType {
|
|
|
8
8
|
if let value = value as? Promise {
|
|
9
9
|
return value
|
|
10
10
|
}
|
|
11
|
-
throw Conversions.
|
|
11
|
+
throw Conversions.CastingException<Promise>(value)
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
var description: String = "Promise"
|
|
@@ -14,9 +14,9 @@ internal struct RawArgumentType<InnerType>: AnyArgumentType {
|
|
|
14
14
|
// Raw arguments are always non-optional, but they may receive `nil` values.
|
|
15
15
|
// Let's throw more specific error in this case.
|
|
16
16
|
if Optional.isNil(value) {
|
|
17
|
-
throw Conversions.
|
|
17
|
+
throw Conversions.NullCastException<InnerType>()
|
|
18
18
|
}
|
|
19
|
-
throw Conversions.
|
|
19
|
+
throw Conversions.CastingException<InnerType>(value)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
var description: String {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
1
|
internal final class Conversions {
|
|
3
2
|
/**
|
|
4
3
|
Converts an array to tuple. Because of tuples nature, it's not possible to convert an array of any size, so we can support only up to some fixed size.
|
|
5
4
|
*/
|
|
6
5
|
static func toTuple(_ array: [Any?]) throws -> Any? {
|
|
7
|
-
switch
|
|
6
|
+
switch array.count {
|
|
8
7
|
case 0:
|
|
9
8
|
return ()
|
|
10
9
|
case 1:
|
|
@@ -28,7 +27,7 @@ internal final class Conversions {
|
|
|
28
27
|
case 10:
|
|
29
28
|
return (array[0], array[1], array[2], array[3], array[4], array[5], array[6], array[7], array[8], array[9])
|
|
30
29
|
default:
|
|
31
|
-
throw
|
|
30
|
+
throw TooManyArgumentsException((count: array.count, limit: 10))
|
|
32
31
|
}
|
|
33
32
|
}
|
|
34
33
|
|
|
@@ -47,9 +46,9 @@ internal final class Conversions {
|
|
|
47
46
|
}
|
|
48
47
|
|
|
49
48
|
/**
|
|
50
|
-
Picks values under given keys from the dictionary,
|
|
51
|
-
- The dictionary is missing some of the given keys (`
|
|
52
|
-
- Some of the values cannot be
|
|
49
|
+
Picks values under given keys from the dictionary, cast to a specific type. Can throw exceptions when
|
|
50
|
+
- The dictionary is missing some of the given keys (`MissingKeysException`)
|
|
51
|
+
- Some of the values cannot be cast to specified type (`CastingValuesException`)
|
|
53
52
|
*/
|
|
54
53
|
static func pickValues<ValueType>(from dict: [String: Any], byKeys keys: [String], as type: ValueType.Type) throws -> [ValueType] {
|
|
55
54
|
var result = (
|
|
@@ -68,17 +67,17 @@ internal final class Conversions {
|
|
|
68
67
|
result.invalidKeys.append(key)
|
|
69
68
|
}
|
|
70
69
|
}
|
|
71
|
-
if result.missingKeys.
|
|
72
|
-
throw
|
|
70
|
+
if !result.missingKeys.isEmpty {
|
|
71
|
+
throw MissingKeysException<ValueType>(result.missingKeys)
|
|
73
72
|
}
|
|
74
|
-
if result.invalidKeys.
|
|
75
|
-
throw
|
|
73
|
+
if !result.invalidKeys.isEmpty {
|
|
74
|
+
throw CastingValuesException<ValueType>(result.invalidKeys)
|
|
76
75
|
}
|
|
77
76
|
return result.values
|
|
78
77
|
}
|
|
79
78
|
|
|
80
79
|
/**
|
|
81
|
-
Converts hex string to `UIColor` or throws an
|
|
80
|
+
Converts hex string to `UIColor` or throws an exception if the string is corrupted.
|
|
82
81
|
*/
|
|
83
82
|
static func toColor(hexString hex: String) throws -> UIColor {
|
|
84
83
|
var hexStr = hex
|
|
@@ -104,7 +103,7 @@ internal final class Conversions {
|
|
|
104
103
|
|
|
105
104
|
guard hexStr.range(of: #"^[0-9a-fA-F]{8}$"#, options: .regularExpression) != nil,
|
|
106
105
|
Scanner(string: hexStr).scanHexInt64(&rgba) else {
|
|
107
|
-
throw
|
|
106
|
+
throw InvalidHexColorException(hex)
|
|
108
107
|
}
|
|
109
108
|
return try toColor(rgba: rgba)
|
|
110
109
|
}
|
|
@@ -115,7 +114,7 @@ internal final class Conversions {
|
|
|
115
114
|
*/
|
|
116
115
|
static func toColor(argb: UInt64) throws -> UIColor {
|
|
117
116
|
guard argb <= UInt32.max else {
|
|
118
|
-
throw
|
|
117
|
+
throw HexColorOverflowException(argb)
|
|
119
118
|
}
|
|
120
119
|
let alpha = CGFloat((argb >> 24) & 0xff) / 255.0
|
|
121
120
|
let red = CGFloat((argb >> 16) & 0xff) / 255.0
|
|
@@ -129,7 +128,7 @@ internal final class Conversions {
|
|
|
129
128
|
*/
|
|
130
129
|
static func toColor(rgba: UInt64) throws -> UIColor {
|
|
131
130
|
guard rgba <= UInt32.max else {
|
|
132
|
-
throw
|
|
131
|
+
throw HexColorOverflowException(rgba)
|
|
133
132
|
}
|
|
134
133
|
let red = CGFloat((rgba >> 24) & 0xff) / 255.0
|
|
135
134
|
let green = CGFloat((rgba >> 16) & 0xff) / 255.0
|
|
@@ -145,90 +144,86 @@ internal final class Conversions {
|
|
|
145
144
|
return keys.map { "`\($0)`" }.joined(separator: ", ")
|
|
146
145
|
}
|
|
147
146
|
|
|
148
|
-
|
|
147
|
+
static func formatPlural(_ number: Int, _ singular: String, _ plural: String? = nil) -> String {
|
|
148
|
+
return String(number) + (number == 1 ? singular : (plural ?? singular + "s"))
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// MARK: - Exceptions
|
|
149
152
|
|
|
150
153
|
/**
|
|
151
|
-
An
|
|
154
|
+
An exception meaning that the number of arguments exceeds the limit.
|
|
152
155
|
*/
|
|
153
|
-
internal
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
var description: String {
|
|
157
|
-
"A number of arguments `\(count)` exceeds the limit of `\(limit)`"
|
|
156
|
+
internal class TooManyArgumentsException: GenericException<(count: Int, limit: Int)> {
|
|
157
|
+
override var reason: String {
|
|
158
|
+
"Native function expects \(formatPlural(param.limit, "argument")), but received \(param.count)"
|
|
158
159
|
}
|
|
159
160
|
}
|
|
160
161
|
|
|
161
162
|
/**
|
|
162
|
-
An
|
|
163
|
+
An exception that can be thrown by convertible types, when given value cannot be converted.
|
|
163
164
|
*/
|
|
164
|
-
internal
|
|
165
|
-
let value: Any?
|
|
165
|
+
internal class ConvertingException<TargetType>: GenericException<Any?> {
|
|
166
166
|
var code: String = "ERR_CONVERTING_FAILED"
|
|
167
|
-
var
|
|
168
|
-
"Cannot convert
|
|
167
|
+
override var reason: String {
|
|
168
|
+
"Cannot convert '\(String(describing: param))' to \(TargetType.self)"
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
/**
|
|
173
|
-
An
|
|
173
|
+
An exception that is thrown when given value cannot be cast.
|
|
174
174
|
*/
|
|
175
|
-
internal
|
|
176
|
-
let value: Any
|
|
175
|
+
internal class CastingException<TargetType>: GenericException<Any> {
|
|
177
176
|
var code: String = "ERR_CASTING_FAILED"
|
|
178
|
-
var
|
|
179
|
-
"Cannot cast
|
|
177
|
+
override var reason: String {
|
|
178
|
+
"Cannot cast '\(String(describing: param))' to \(TargetType.self)"
|
|
180
179
|
}
|
|
181
180
|
}
|
|
182
181
|
|
|
183
182
|
/**
|
|
184
|
-
An
|
|
185
|
-
when the values in given dictionary cannot be
|
|
183
|
+
An exception that can be thrown by convertible types,
|
|
184
|
+
when the values in given dictionary cannot be cast to specific type.
|
|
186
185
|
*/
|
|
187
|
-
internal
|
|
188
|
-
let keys: [String]
|
|
186
|
+
internal class CastingValuesException<ValueType>: GenericException<[String]> {
|
|
189
187
|
var code: String = "ERR_CASTING_VALUES_FAILED"
|
|
190
|
-
var
|
|
191
|
-
"Cannot cast keys \(formatKeys(
|
|
188
|
+
override var reason: String {
|
|
189
|
+
"Cannot cast keys \(formatKeys(param)) to \(ValueType.self)"
|
|
192
190
|
}
|
|
193
191
|
}
|
|
194
192
|
|
|
195
193
|
/**
|
|
196
|
-
An
|
|
194
|
+
An exception that can be thrown by convertible types,
|
|
197
195
|
when given dictionary is missing some required keys.
|
|
198
196
|
*/
|
|
199
|
-
internal
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
"Missing keys \(formatKeys(keys)) of type `\(ValueType.self)`"
|
|
197
|
+
internal class MissingKeysException<ValueType>: GenericException<[String]> {
|
|
198
|
+
override var reason: String {
|
|
199
|
+
"Missing keys \(formatKeys(param)) to create \(ValueType.self) record"
|
|
203
200
|
}
|
|
204
201
|
}
|
|
205
202
|
|
|
206
203
|
/**
|
|
207
|
-
An
|
|
204
|
+
An exception that is thrown when null value is tried to be cast to non-optional type.
|
|
208
205
|
*/
|
|
209
|
-
internal
|
|
210
|
-
var
|
|
211
|
-
"Cannot cast null
|
|
206
|
+
internal class NullCastException<TargetType>: Exception {
|
|
207
|
+
override var reason: String {
|
|
208
|
+
"Cannot cast null to non-optional '\(TargetType.self)'"
|
|
212
209
|
}
|
|
213
210
|
}
|
|
214
211
|
|
|
215
212
|
/**
|
|
216
|
-
An
|
|
213
|
+
An exception used when the hex color string is invalid (e.g. contains non-hex characters).
|
|
217
214
|
*/
|
|
218
|
-
internal
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
"Provided hex color `\(hex)` is invalid"
|
|
215
|
+
internal class InvalidHexColorException: GenericException<String> {
|
|
216
|
+
override var reason: String {
|
|
217
|
+
"Provided hex color '\(param)' is invalid"
|
|
222
218
|
}
|
|
223
219
|
}
|
|
224
220
|
|
|
225
221
|
/**
|
|
226
|
-
An
|
|
222
|
+
An exception used when the integer value of the color would result in an overflow of `UInt32`.
|
|
227
223
|
*/
|
|
228
|
-
internal
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
"Provided hex color `\(hex)` would result in an overflow"
|
|
224
|
+
internal class HexColorOverflowException: GenericException<UInt64> {
|
|
225
|
+
override var reason: String {
|
|
226
|
+
"Provided hex color '\(param)' would result in an overflow"
|
|
232
227
|
}
|
|
233
228
|
}
|
|
234
229
|
}
|
|
@@ -10,7 +10,7 @@ internal struct EventListener: AnyDefinition {
|
|
|
10
10
|
*/
|
|
11
11
|
init(_ name: EventName, _ listener: @escaping () -> Void) {
|
|
12
12
|
self.name = name
|
|
13
|
-
self.call = {
|
|
13
|
+
self.call = { _, _ in listener() }
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -18,9 +18,9 @@ internal struct EventListener: AnyDefinition {
|
|
|
18
18
|
*/
|
|
19
19
|
init<Sender>(_ name: EventName, _ listener: @escaping (Sender) -> Void) {
|
|
20
20
|
self.name = name
|
|
21
|
-
self.call = {
|
|
21
|
+
self.call = { sender, _ in
|
|
22
22
|
guard let sender = sender as? Sender else {
|
|
23
|
-
throw
|
|
23
|
+
throw InvalidSenderTypeException((eventName: name, senderType: Sender.self))
|
|
24
24
|
}
|
|
25
25
|
listener(sender)
|
|
26
26
|
}
|
|
@@ -31,20 +31,18 @@ internal struct EventListener: AnyDefinition {
|
|
|
31
31
|
*/
|
|
32
32
|
init<Sender, PayloadType>(_ name: EventName, _ listener: @escaping (Sender, PayloadType?) -> Void) {
|
|
33
33
|
self.name = name
|
|
34
|
-
self.call = {
|
|
34
|
+
self.call = { sender, payload in
|
|
35
35
|
guard let sender = sender as? Sender else {
|
|
36
|
-
throw
|
|
36
|
+
throw InvalidSenderTypeException((eventName: name, senderType: Sender.self))
|
|
37
37
|
}
|
|
38
38
|
listener(sender, payload as? PayloadType)
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
var
|
|
45
|
-
|
|
46
|
-
var description: String {
|
|
47
|
-
"Sender for event `\(eventName)` must be of type `\(senderType)`."
|
|
43
|
+
class InvalidSenderTypeException: GenericException<(eventName: EventName, senderType: Any.Type)> {
|
|
44
|
+
override var reason: String {
|
|
45
|
+
"Sender for event '\(param.eventName)' must be of type \(param.senderType)"
|
|
48
46
|
}
|
|
49
47
|
}
|
|
50
48
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Copyright 2021-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
An alias for type-erased callback handler.
|
|
5
|
+
*/
|
|
6
|
+
typealias AnyCallbackHandlerType = (Any) -> Void
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
Public type-erased protocol that `Callback` object conforms to.
|
|
10
|
+
*/
|
|
11
|
+
public protocol AnyCallback {
|
|
12
|
+
/**
|
|
13
|
+
Initializes an empty callback (no-op).
|
|
14
|
+
*/
|
|
15
|
+
init()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
Internal type-erased protocol for `Callback` object.
|
|
20
|
+
*/
|
|
21
|
+
internal protocol AnyCallbackInternal: AnyCallback {
|
|
22
|
+
/**
|
|
23
|
+
Sets the callback handler. By default the callback
|
|
24
|
+
is not settled which means it has no handler, thus is no-op.
|
|
25
|
+
*/
|
|
26
|
+
func settle(_ handler: @escaping AnyCallbackHandlerType)
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
Invalidates the callback, making its handler no-op.
|
|
30
|
+
*/
|
|
31
|
+
func invalidate()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
Callable object that represents a JavaScript function.
|
|
36
|
+
*/
|
|
37
|
+
public class Callback<ArgType>: AnyCallback, AnyCallbackInternal {
|
|
38
|
+
/**
|
|
39
|
+
The underlying closure to invoke when the callback is called.
|
|
40
|
+
*/
|
|
41
|
+
private var handler: AnyCallbackHandlerType?
|
|
42
|
+
|
|
43
|
+
// MARK: AnyCallback
|
|
44
|
+
|
|
45
|
+
public required init() {}
|
|
46
|
+
|
|
47
|
+
// MARK: AnyCallbackInternal
|
|
48
|
+
|
|
49
|
+
internal func settle(_ handler: @escaping AnyCallbackHandlerType) {
|
|
50
|
+
self.handler = handler
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
internal func invalidate() {
|
|
54
|
+
self.handler = nil
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// MARK: Calling as function
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
Allows the callback instance to be called as a function.
|
|
61
|
+
*/
|
|
62
|
+
public func callAsFunction(_ arg: ArgType) {
|
|
63
|
+
// TODO: Convert records to dictionaries (@tsapeta)
|
|
64
|
+
handler?(arg as Any)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Copyright 2021-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
Internal type-erased protocol for the instances of the `Event` property wrapper.
|
|
5
|
+
*/
|
|
6
|
+
internal protocol AnyEventInternal {
|
|
7
|
+
/**
|
|
8
|
+
Sets the handler on the wrapped callback.
|
|
9
|
+
*/
|
|
10
|
+
func settle(_ handler: @escaping AnyCallbackHandlerType)
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
Invalidates the callback.
|
|
14
|
+
*/
|
|
15
|
+
func invalidate()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
The class used as a property wrapper on view's or object's callbacks.
|
|
20
|
+
*/
|
|
21
|
+
@propertyWrapper
|
|
22
|
+
public final class Event<CallbackType: AnyCallback>: AnyEventInternal {
|
|
23
|
+
public var wrappedValue: CallbackType
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
The property wrapper initializer. The wrapped value falls back to the empty callback.
|
|
27
|
+
*/
|
|
28
|
+
public init(wrappedValue: CallbackType = CallbackType()) {
|
|
29
|
+
self.wrappedValue = wrappedValue
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
internal func settle(_ handler: @escaping AnyCallbackHandlerType) {
|
|
33
|
+
if let callback = wrappedValue as? AnyCallbackInternal {
|
|
34
|
+
callback.settle(handler)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
internal func invalidate() {
|
|
39
|
+
if let callback = wrappedValue as? AnyCallbackInternal {
|
|
40
|
+
callback.invalidate()
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
An exception that may have been caused by another error.
|
|
5
|
+
*/
|
|
6
|
+
public protocol ChainableException: Error, AnyObject {
|
|
7
|
+
/**
|
|
8
|
+
The direct cause of the exception.
|
|
9
|
+
*/
|
|
10
|
+
var cause: Error? { get set }
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
The first error that started the chain of exceptions.
|
|
14
|
+
*/
|
|
15
|
+
var rootCause: Error? { get }
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
Sets the direct cause of the exception and returns itself.
|
|
19
|
+
*/
|
|
20
|
+
func causedBy(_ error: Error) -> Self
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
Tells whether any of the cause in chain is of given type.
|
|
24
|
+
*/
|
|
25
|
+
func isCausedBy<ErrorType: Error>(_ errorType: ErrorType.Type) -> Bool
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public extension ChainableException {
|
|
29
|
+
var rootCause: Error? {
|
|
30
|
+
if let cause = cause as? ChainableException {
|
|
31
|
+
return cause.rootCause ?? cause
|
|
32
|
+
}
|
|
33
|
+
return cause
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@discardableResult
|
|
37
|
+
func causedBy(_ error: Error) -> Self {
|
|
38
|
+
cause = error
|
|
39
|
+
return self
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
func isCausedBy<ErrorType: Error>(_ errorType: ErrorType.Type) -> Bool {
|
|
43
|
+
if cause is ErrorType {
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
46
|
+
if let cause = cause as? ChainableException {
|
|
47
|
+
return cause.isCausedBy(errorType)
|
|
48
|
+
}
|
|
49
|
+
return false
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -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
|
+
}
|