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.
Files changed (159) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +1 -1
  3. package/android/build.gradle +5 -5
  4. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +11 -1
  5. package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +5 -3
  6. package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +8 -2
  7. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +13 -4
  8. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +7 -6
  9. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +6 -1
  10. package/android/src/main/java/expo/modules/kotlin/Promise.kt +1 -1
  11. package/android/src/main/java/expo/modules/kotlin/callbacks/Callback.kt +5 -0
  12. package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallback.kt +28 -0
  13. package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallbackDelegate.kt +27 -0
  14. package/android/src/main/java/expo/modules/kotlin/defaultmodules/ErrorManagerModule.kt +25 -0
  15. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +68 -8
  16. package/android/src/main/java/expo/modules/kotlin/exception/ExceptionDecorator.kt +11 -0
  17. package/android/src/main/java/expo/modules/kotlin/methods/AnyMethod.kt +13 -14
  18. package/android/src/main/java/expo/modules/kotlin/modules/DefinitionMarker.kt +4 -0
  19. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +3 -2
  20. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +44 -4
  21. package/android/src/main/java/expo/modules/kotlin/records/Record.kt +39 -0
  22. package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +14 -7
  23. package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +11 -5
  24. package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +10 -4
  25. package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +12 -6
  26. package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +29 -13
  27. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +2 -1
  28. package/android/src/main/java/expo/modules/kotlin/views/CallbacksDefinition.kt +3 -0
  29. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +22 -0
  30. package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +22 -0
  31. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +27 -2
  32. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +29 -1
  33. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +59 -2
  34. package/build/EventEmitter.d.ts +1 -0
  35. package/build/EventEmitter.d.ts.map +1 -0
  36. package/build/NativeModulesProxy.d.ts +1 -0
  37. package/build/NativeModulesProxy.d.ts.map +1 -0
  38. package/build/NativeModulesProxy.native.d.ts +1 -0
  39. package/build/NativeModulesProxy.native.d.ts.map +1 -0
  40. package/build/NativeModulesProxy.types.d.ts +1 -0
  41. package/build/NativeModulesProxy.types.d.ts.map +1 -0
  42. package/build/NativeViewManagerAdapter.d.ts +1 -0
  43. package/build/NativeViewManagerAdapter.d.ts.map +1 -0
  44. package/build/NativeViewManagerAdapter.native.d.ts +1 -0
  45. package/build/NativeViewManagerAdapter.native.d.ts.map +1 -0
  46. package/build/PermissionsHook.d.ts +1 -0
  47. package/build/PermissionsHook.d.ts.map +1 -0
  48. package/build/PermissionsInterface.d.ts +1 -0
  49. package/build/PermissionsInterface.d.ts.map +1 -0
  50. package/build/Platform.d.ts +1 -0
  51. package/build/Platform.d.ts.map +1 -0
  52. package/build/SyntheticPlatformEmitter.d.ts +1 -0
  53. package/build/SyntheticPlatformEmitter.d.ts.map +1 -0
  54. package/build/SyntheticPlatformEmitter.web.d.ts +1 -0
  55. package/build/SyntheticPlatformEmitter.web.d.ts.map +1 -0
  56. package/build/deprecate.d.ts +1 -0
  57. package/build/deprecate.d.ts.map +1 -0
  58. package/build/environment/browser.d.ts +1 -0
  59. package/build/environment/browser.d.ts.map +1 -0
  60. package/build/environment/browser.web.d.ts +1 -0
  61. package/build/environment/browser.web.d.ts.map +1 -0
  62. package/build/errors/CodedError.d.ts +1 -0
  63. package/build/errors/CodedError.d.ts.map +1 -0
  64. package/build/errors/UnavailabilityError.d.ts +1 -0
  65. package/build/errors/UnavailabilityError.d.ts.map +1 -0
  66. package/build/index.d.ts +3 -0
  67. package/build/index.d.ts.map +1 -0
  68. package/build/index.js +2 -0
  69. package/build/index.js.map +1 -1
  70. package/build/requireNativeModule.d.ts +16 -0
  71. package/build/requireNativeModule.d.ts.map +1 -0
  72. package/build/requireNativeModule.js +18 -0
  73. package/build/requireNativeModule.js.map +1 -0
  74. package/build/sweet/NativeErrorManager.d.ts +3 -0
  75. package/build/sweet/NativeErrorManager.d.ts.map +1 -0
  76. package/build/sweet/NativeErrorManager.js +3 -0
  77. package/build/sweet/NativeErrorManager.js.map +1 -0
  78. package/build/sweet/setUpErrorManager.fx.d.ts +2 -0
  79. package/build/sweet/setUpErrorManager.fx.d.ts.map +1 -0
  80. package/build/sweet/setUpErrorManager.fx.js +11 -0
  81. package/build/sweet/setUpErrorManager.fx.js.map +1 -0
  82. package/ios/AppDelegates/ExpoAppDelegate.swift +18 -10
  83. package/ios/JSI/ExpoModulesHostObject.h +33 -0
  84. package/ios/JSI/ExpoModulesHostObject.mm +40 -0
  85. package/ios/JSI/ExpoModulesProxySpec.h +4 -0
  86. package/ios/JSI/ExpoModulesProxySpec.mm +1 -3
  87. package/ios/JSI/JSIConversions.h +2 -0
  88. package/ios/JSI/JSIConversions.mm +9 -0
  89. package/ios/JSI/JSIInstaller.h +10 -0
  90. package/ios/JSI/JSIInstaller.mm +14 -2
  91. package/ios/JSI/JavaScriptObject.h +60 -0
  92. package/ios/JSI/JavaScriptObject.mm +93 -0
  93. package/ios/JSI/JavaScriptRuntime.h +54 -0
  94. package/ios/JSI/JavaScriptRuntime.mm +102 -0
  95. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +2 -12
  96. package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.h +16 -0
  97. package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.m +28 -0
  98. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +90 -66
  99. package/ios/RCTComponentData+Privates.h +12 -0
  100. package/ios/ReactDelegates/ExpoReactDelegate.swift +2 -2
  101. package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +3 -3
  102. package/ios/ReactDelegates/ModulePriorities.swift +1 -1
  103. package/ios/Swift/AppContext.swift +38 -4
  104. package/ios/Swift/Arguments/ArgumentType.swift +4 -0
  105. package/ios/Swift/Arguments/Convertibles.swift +13 -13
  106. package/ios/Swift/Arguments/Types/EnumArgumentType.swift +11 -17
  107. package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +1 -1
  108. package/ios/Swift/Arguments/Types/RawArgumentType.swift +2 -2
  109. package/ios/Swift/Conversions.swift +51 -56
  110. package/ios/Swift/EventListener.swift +8 -10
  111. package/ios/Swift/Events/Callback.swift +66 -0
  112. package/ios/Swift/Events/Event.swift +43 -0
  113. package/ios/Swift/Exceptions/ChainableException.swift +51 -0
  114. package/ios/Swift/{CodedError.swift → Exceptions/CodedError.swift} +1 -12
  115. package/ios/Swift/Exceptions/Exception.swift +62 -0
  116. package/ios/Swift/Exceptions/ExceptionOrigin.swift +28 -0
  117. package/ios/Swift/Exceptions/GenericException.swift +20 -0
  118. package/ios/Swift/Exceptions/UnexpectedException.swift +16 -0
  119. package/ios/Swift/Functions/AnyFunction.swift +11 -1
  120. package/ios/Swift/Functions/ConcreteFunction.swift +37 -16
  121. package/ios/Swift/JavaScriptUtils.swift +43 -0
  122. package/ios/Swift/ModuleHolder.swift +53 -14
  123. package/ios/Swift/ModuleRegistry.swift +4 -1
  124. package/ios/Swift/Modules/AnyModule.swift +0 -1
  125. package/ios/Swift/Modules/ModuleDefinition.swift +4 -13
  126. package/ios/Swift/Modules/ModuleDefinitionBuilder.swift +0 -1
  127. package/ios/Swift/Modules/ModuleDefinitionComponents.swift +0 -188
  128. package/ios/Swift/ModulesProvider.swift +0 -1
  129. package/ios/Swift/Objects/ObjectDefinition.swift +30 -0
  130. package/ios/Swift/Objects/ObjectDefinitionComponents.swift +208 -0
  131. package/ios/Swift/Promise.swift +8 -3
  132. package/ios/Swift/Records/AnyField.swift +7 -0
  133. package/ios/Swift/Records/Field.swift +24 -19
  134. package/ios/Swift/Records/FieldOption.swift +1 -1
  135. package/ios/Swift/Records/Record.swift +12 -4
  136. package/ios/Swift/SwiftInteropBridge.swift +39 -10
  137. package/ios/Swift/Views/AnyViewProp.swift +1 -1
  138. package/ios/Swift/Views/ComponentData.swift +95 -0
  139. package/ios/Swift/Views/ConcreteViewProp.swift +6 -8
  140. package/ios/Swift/Views/ViewFactory.swift +1 -1
  141. package/ios/Swift/Views/ViewManagerDefinition.swift +23 -2
  142. package/ios/Swift/Views/ViewManagerDefinitionBuilder.swift +0 -1
  143. package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +26 -0
  144. package/ios/Swift/Views/ViewModuleWrapper.swift +5 -2
  145. package/ios/Tests/ArgumentTypeSpec.swift +3 -4
  146. package/ios/Tests/ConstantsSpec.swift +4 -4
  147. package/ios/Tests/ConvertiblesSpec.swift +33 -33
  148. package/ios/Tests/ExceptionsSpec.swift +112 -0
  149. package/ios/Tests/FunctionSpec.swift +20 -22
  150. package/ios/Tests/FunctionWithConvertiblesSpec.swift +2 -2
  151. package/ios/Tests/Mocks/ModuleMocks.swift +1 -1
  152. package/ios/Tests/Mocks/ModulesProviderMock.swift +0 -1
  153. package/ios/Tests/ModuleEventListenersSpec.swift +1 -1
  154. package/ios/Tests/RecordSpec.swift +7 -17
  155. package/package.json +3 -3
  156. package/src/index.ts +4 -0
  157. package/src/requireNativeModule.ts +29 -0
  158. package/src/sweet/NativeErrorManager.ts +2 -0
  159. package/src/sweet/setUpErrorManager.fx.ts +12 -0
@@ -3,11 +3,11 @@
3
3
  import UIKit
4
4
  import CoreGraphics
5
5
 
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.
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.ConvertingError<URL>(value: value)
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.ConvertingError<UIColor>(value: value)
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.ConvertingError<CGPoint>(value: value)
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.ConvertingError<CGSize>(value: value)
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.ConvertingError<CGVector>(value: value)
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.ConvertingError<CGRect>(value: value)
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.ConvertingError<UIColor> {
102
+ } catch _ as Conversions.ConvertingException<UIColor> {
103
103
  // Rethrow `ConvertingError` with proper type
104
- throw Conversions.ConvertingError<CGColor>(value: value)
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 EnumCastingError(type: RawValue.self, value: rawValue)
46
+ throw EnumCastingException((type: RawValue.self, value: rawValue))
47
47
  }
48
48
  guard let enumCase = Self.init(rawValue: rawValue) else {
49
- throw EnumNoSuchValueError(type: Self.self, value: rawValue)
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 casted to associated `RawValue`.
78
+ An error that is thrown when the value cannot be cast to associated `RawValue`.
79
79
  */
80
- internal struct EnumCastingError: CodedError {
81
- let type: Any.Type
82
- let value: Any
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 struct EnumNoSuchValueError: CodedError {
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 { "`\($0)`" }
91
+ return param.type.allRawValues
92
+ .map { "'\($0)'" }
99
93
  .joined(separator: ", ")
100
94
  }
101
95
 
102
- var description: String {
103
- "Cannot create `\(type)` enum from value `\(value)`. It must be one of: \(allRawValuesFormatted)"
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.CastingError<Promise>(value: value)
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.NullCastError<InnerType>()
17
+ throw Conversions.NullCastException<InnerType>()
18
18
  }
19
- throw Conversions.CastingError<InnerType>(value: value)
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 (array.count) {
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 TooManyArgumentsError(count: array.count, limit: 10)
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, casted to a specific type. Can throw errors when
51
- - The dictionary is missing some of the given keys (`MissingKeysError`)
52
- - Some of the values cannot be casted to specified type (`CastingValuesError`)
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.count > 0 {
72
- throw MissingKeysError<ValueType>(keys: result.missingKeys)
70
+ if !result.missingKeys.isEmpty {
71
+ throw MissingKeysException<ValueType>(result.missingKeys)
73
72
  }
74
- if result.invalidKeys.count > 0 {
75
- throw CastingValuesError<ValueType>(keys: result.invalidKeys)
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 error if the string is corrupted.
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 InvalidHexColorError(hex: hex)
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 HexColorOverflowError(hex: argb)
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 HexColorOverflowError(hex: rgba)
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
- // MARK: - Errors
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 error meaning that the number of arguments exceeds the limit.
154
+ An exception meaning that the number of arguments exceeds the limit.
152
155
  */
153
- internal struct TooManyArgumentsError: CodedError {
154
- let count: Int
155
- let limit: Int
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 error that can be thrown by convertible types, when given value cannot be converted.
163
+ An exception that can be thrown by convertible types, when given value cannot be converted.
163
164
  */
164
- internal struct ConvertingError<TargetType>: CodedError {
165
- let value: Any?
165
+ internal class ConvertingException<TargetType>: GenericException<Any?> {
166
166
  var code: String = "ERR_CONVERTING_FAILED"
167
- var description: String {
168
- "Cannot convert `\(String(describing: value))` to `\(TargetType.self)`"
167
+ override var reason: String {
168
+ "Cannot convert '\(String(describing: param))' to \(TargetType.self)"
169
169
  }
170
170
  }
171
171
 
172
172
  /**
173
- An error that is thrown when given value cannot be casted.
173
+ An exception that is thrown when given value cannot be cast.
174
174
  */
175
- internal struct CastingError<TargetType>: CodedError {
176
- let value: Any
175
+ internal class CastingException<TargetType>: GenericException<Any> {
177
176
  var code: String = "ERR_CASTING_FAILED"
178
- var description: String {
179
- "Cannot cast `\(String(describing: value))` to `\(TargetType.self)`"
177
+ override var reason: String {
178
+ "Cannot cast '\(String(describing: param))' to \(TargetType.self)"
180
179
  }
181
180
  }
182
181
 
183
182
  /**
184
- An error that can be thrown by convertible types,
185
- when the values in given dictionary cannot be casted to specific type.
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 struct CastingValuesError<ValueType>: CodedError {
188
- let keys: [String]
186
+ internal class CastingValuesException<ValueType>: GenericException<[String]> {
189
187
  var code: String = "ERR_CASTING_VALUES_FAILED"
190
- var description: String {
191
- "Cannot cast keys \(formatKeys(keys)) to `\(ValueType.self)`"
188
+ override var reason: String {
189
+ "Cannot cast keys \(formatKeys(param)) to \(ValueType.self)"
192
190
  }
193
191
  }
194
192
 
195
193
  /**
196
- An error that can be throw by convertible types,
194
+ An exception that can be thrown by convertible types,
197
195
  when given dictionary is missing some required keys.
198
196
  */
199
- internal struct MissingKeysError<ValueType>: CodedError {
200
- let keys: [String]
201
- var description: String {
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 error that is thrown when null value is tried to be casted to non-optional type.
204
+ An exception that is thrown when null value is tried to be cast to non-optional type.
208
205
  */
209
- internal struct NullCastError<TargetType>: CodedError {
210
- var description: String {
211
- "Cannot cast null value to non-optional `\(TargetType.self)`"
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 error used when the hex color string is invalid (e.g. contains non-hex characters).
213
+ An exception used when the hex color string is invalid (e.g. contains non-hex characters).
217
214
  */
218
- internal struct InvalidHexColorError: CodedError {
219
- let hex: String
220
- var description: String {
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 error used when the integer value of the color would result in an overflow of `UInt32`.
222
+ An exception used when the integer value of the color would result in an overflow of `UInt32`.
227
223
  */
228
- internal struct HexColorOverflowError: CodedError {
229
- let hex: UInt64
230
- var description: String {
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 = { (sender, payload) in listener() }
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 = { (sender, payload) in
21
+ self.call = { sender, _ in
22
22
  guard let sender = sender as? Sender else {
23
- throw InvalidSenderTypeError(eventName: name, senderType: Sender.self)
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 = { (sender, payload) in
34
+ self.call = { sender, payload in
35
35
  guard let sender = sender as? Sender else {
36
- throw InvalidSenderTypeError(eventName: name, senderType: Sender.self)
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
- struct InvalidSenderTypeError: CodedError {
44
- var eventName: EventName
45
- var senderType: Any.Type
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
+ }