expo-modules-core 0.6.4 → 0.8.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 (217) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +1 -1
  3. package/android/ExpoModulesCorePlugin.gradle +15 -0
  4. package/android/build.gradle +46 -32
  5. package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +5 -5
  6. package/android/src/main/java/expo/modules/adapters/react/services/UIManagerModuleWrapper.java +13 -0
  7. package/android/src/main/java/expo/modules/core/ViewManager.java +9 -0
  8. package/android/src/main/java/expo/modules/core/interfaces/JavaScriptContextProvider.java +4 -0
  9. package/android/src/main/java/expo/modules/core/interfaces/ReactActivityHandler.java +37 -1
  10. package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.java +19 -0
  11. package/android/src/main/java/expo/modules/core/interfaces/services/UIManager.java +2 -0
  12. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +23 -5
  13. package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +5 -3
  14. package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +3 -8
  15. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +24 -9
  16. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +12 -7
  17. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +23 -1
  18. package/android/src/main/java/expo/modules/kotlin/Promise.kt +1 -1
  19. package/android/src/main/java/expo/modules/kotlin/callbacks/Callback.kt +5 -0
  20. package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallback.kt +39 -0
  21. package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallbackDelegate.kt +27 -0
  22. package/android/src/main/java/expo/modules/kotlin/defaultmodules/ErrorManagerModule.kt +25 -0
  23. package/android/src/main/java/expo/modules/kotlin/events/EventEmitter.kt +13 -0
  24. package/android/src/main/java/expo/modules/kotlin/events/KModuleEventEmitterWrapper.kt +102 -0
  25. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +93 -9
  26. package/android/src/main/java/expo/modules/kotlin/exception/ExceptionDecorator.kt +11 -0
  27. package/android/src/main/java/expo/modules/kotlin/{methods/AnyMethod.kt → functions/AnyFunction.kt} +18 -18
  28. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +15 -0
  29. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +61 -0
  30. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromise.kt +15 -0
  31. package/android/src/main/java/expo/modules/kotlin/functions/AsyncSuspendFunction.kt +36 -0
  32. package/android/src/main/java/expo/modules/kotlin/modules/DefinitionMarker.kt +4 -0
  33. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +17 -2
  34. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +219 -30
  35. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +2 -2
  36. package/android/src/main/java/expo/modules/kotlin/records/FieldValidator.kt +139 -0
  37. package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +71 -15
  38. package/android/src/main/java/expo/modules/kotlin/records/Required.kt +5 -0
  39. package/android/src/main/java/expo/modules/kotlin/records/ValidationBinder.kt +110 -0
  40. package/android/src/main/java/expo/modules/kotlin/records/Validators.kt +61 -0
  41. package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +11 -5
  42. package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverter.kt +35 -0
  43. package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverterHelper.kt +148 -0
  44. package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +10 -4
  45. package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +12 -6
  46. package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +29 -13
  47. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +2 -1
  48. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +9 -1
  49. package/android/src/main/java/expo/modules/kotlin/views/CallbacksDefinition.kt +3 -0
  50. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +71 -0
  51. package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +22 -0
  52. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinition.kt +18 -0
  53. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +64 -0
  54. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +30 -2
  55. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +42 -1
  56. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +62 -2
  57. package/build/EventEmitter.d.ts +1 -0
  58. package/build/EventEmitter.d.ts.map +1 -0
  59. package/build/NativeModulesProxy.d.ts +1 -0
  60. package/build/NativeModulesProxy.d.ts.map +1 -0
  61. package/build/NativeModulesProxy.native.d.ts +1 -4
  62. package/build/NativeModulesProxy.native.d.ts.map +1 -0
  63. package/build/NativeModulesProxy.native.js +1 -14
  64. package/build/NativeModulesProxy.native.js.map +1 -1
  65. package/build/NativeModulesProxy.types.d.ts +1 -3
  66. package/build/NativeModulesProxy.types.d.ts.map +1 -0
  67. package/build/NativeModulesProxy.types.js.map +1 -1
  68. package/build/NativeViewManagerAdapter.d.ts +1 -0
  69. package/build/NativeViewManagerAdapter.d.ts.map +1 -0
  70. package/build/NativeViewManagerAdapter.native.d.ts +1 -0
  71. package/build/NativeViewManagerAdapter.native.d.ts.map +1 -0
  72. package/build/NativeViewManagerAdapter.native.js +9 -33
  73. package/build/NativeViewManagerAdapter.native.js.map +1 -1
  74. package/build/PermissionsHook.d.ts +1 -0
  75. package/build/PermissionsHook.d.ts.map +1 -0
  76. package/build/PermissionsInterface.d.ts +1 -0
  77. package/build/PermissionsInterface.d.ts.map +1 -0
  78. package/build/Platform.d.ts +1 -0
  79. package/build/Platform.d.ts.map +1 -0
  80. package/build/SyntheticPlatformEmitter.d.ts +1 -0
  81. package/build/SyntheticPlatformEmitter.d.ts.map +1 -0
  82. package/build/SyntheticPlatformEmitter.web.d.ts +1 -0
  83. package/build/SyntheticPlatformEmitter.web.d.ts.map +1 -0
  84. package/build/deprecate.d.ts +1 -0
  85. package/build/deprecate.d.ts.map +1 -0
  86. package/build/environment/browser.d.ts +1 -0
  87. package/build/environment/browser.d.ts.map +1 -0
  88. package/build/environment/browser.web.d.ts +1 -0
  89. package/build/environment/browser.web.d.ts.map +1 -0
  90. package/build/errors/CodedError.d.ts +1 -0
  91. package/build/errors/CodedError.d.ts.map +1 -0
  92. package/build/errors/UnavailabilityError.d.ts +1 -0
  93. package/build/errors/UnavailabilityError.d.ts.map +1 -0
  94. package/build/index.d.ts +3 -0
  95. package/build/index.d.ts.map +1 -0
  96. package/build/index.js +2 -0
  97. package/build/index.js.map +1 -1
  98. package/build/requireNativeModule.d.ts +16 -0
  99. package/build/requireNativeModule.d.ts.map +1 -0
  100. package/build/requireNativeModule.js +18 -0
  101. package/build/requireNativeModule.js.map +1 -0
  102. package/build/sweet/NativeErrorManager.d.ts +3 -0
  103. package/build/sweet/NativeErrorManager.d.ts.map +1 -0
  104. package/build/sweet/NativeErrorManager.js +3 -0
  105. package/build/sweet/NativeErrorManager.js.map +1 -0
  106. package/build/sweet/setUpErrorManager.fx.d.ts +2 -0
  107. package/build/sweet/setUpErrorManager.fx.d.ts.map +1 -0
  108. package/build/sweet/setUpErrorManager.fx.js +11 -0
  109. package/build/sweet/setUpErrorManager.fx.js.map +1 -0
  110. package/ios/AppDelegates/EXAppDelegatesLoader.m +4 -8
  111. package/ios/AppDelegates/ExpoAppDelegate.swift +22 -20
  112. package/ios/EXAppDefines.h +1 -0
  113. package/ios/EXAppDefines.m +6 -0
  114. package/ios/EXUtilities.h +2 -0
  115. package/ios/EXUtilities.m +12 -0
  116. package/ios/ExpoModulesCore.h +4 -0
  117. package/ios/ExpoModulesCore.podspec +4 -2
  118. package/ios/Interfaces/FileSystem/EXFileSystemInterface.h +1 -1
  119. package/ios/Interfaces/TaskManager/EXTaskServiceInterface.h +1 -0
  120. package/ios/JSI/{JSIConversions.h → EXJSIConversions.h} +5 -0
  121. package/ios/JSI/{JSIConversions.mm → EXJSIConversions.mm} +21 -1
  122. package/ios/JSI/{JSIInstaller.h → EXJSIInstaller.h} +10 -0
  123. package/ios/JSI/EXJSIInstaller.mm +17 -0
  124. package/ios/JSI/EXJSIUtils.h +19 -0
  125. package/ios/JSI/EXJSIUtils.mm +89 -0
  126. package/ios/JSI/EXJavaScriptObject.h +97 -0
  127. package/ios/JSI/EXJavaScriptObject.mm +121 -0
  128. package/ios/JSI/EXJavaScriptRuntime.h +73 -0
  129. package/ios/JSI/EXJavaScriptRuntime.mm +153 -0
  130. package/ios/JSI/EXJavaScriptValue.h +57 -0
  131. package/ios/JSI/EXJavaScriptValue.mm +166 -0
  132. package/ios/JSI/ExpoModulesHostObject.h +33 -0
  133. package/ios/JSI/ExpoModulesHostObject.mm +41 -0
  134. package/ios/JSI/JavaScriptRuntime.swift +32 -0
  135. package/ios/JSI/JavaScriptValue.swift +94 -0
  136. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +3 -23
  137. package/ios/NativeModulesProxy/EXNativeModulesProxy.h +2 -2
  138. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +101 -75
  139. package/ios/RCTComponentData+Privates.h +12 -0
  140. package/ios/ReactDelegates/EXReactCompatibleHelpers.h +18 -0
  141. package/ios/ReactDelegates/EXReactCompatibleHelpers.m +19 -0
  142. package/ios/ReactDelegates/ExpoReactDelegate.swift +3 -3
  143. package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +4 -4
  144. package/ios/ReactDelegates/ModulePriorities.swift +1 -1
  145. package/ios/Swift/AppContext.swift +64 -4
  146. package/ios/Swift/Arguments/ArgumentType.swift +4 -0
  147. package/ios/Swift/Arguments/Convertibles.swift +13 -13
  148. package/ios/Swift/Arguments/Types/EnumArgumentType.swift +11 -17
  149. package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +1 -1
  150. package/ios/Swift/Arguments/Types/RawArgumentType.swift +2 -2
  151. package/ios/Swift/Conversions.swift +51 -56
  152. package/ios/Swift/EventListener.swift +8 -10
  153. package/ios/Swift/Events/Callback.swift +66 -0
  154. package/ios/Swift/Events/Event.swift +43 -0
  155. package/ios/Swift/Exceptions/ChainableException.swift +51 -0
  156. package/ios/Swift/{CodedError.swift → Exceptions/CodedError.swift} +1 -12
  157. package/ios/Swift/Exceptions/Exception.swift +62 -0
  158. package/ios/Swift/Exceptions/ExceptionOrigin.swift +28 -0
  159. package/ios/Swift/Exceptions/GenericException.swift +20 -0
  160. package/ios/Swift/Exceptions/UnexpectedException.swift +16 -0
  161. package/ios/Swift/Functions/AnyFunction.swift +11 -1
  162. package/ios/Swift/Functions/AsyncFunction.swift +17 -0
  163. package/ios/Swift/Functions/ConcreteFunction.swift +43 -17
  164. package/ios/Swift/JavaScriptUtils.swift +54 -0
  165. package/ios/Swift/ModuleHolder.swift +66 -16
  166. package/ios/Swift/ModuleRegistry.swift +4 -1
  167. package/ios/Swift/Modules/AnyModule.swift +0 -1
  168. package/ios/Swift/Modules/ModuleDefinition.swift +4 -13
  169. package/ios/Swift/Modules/ModuleDefinitionBuilder.swift +0 -1
  170. package/ios/Swift/Modules/ModuleDefinitionComponents.swift +0 -188
  171. package/ios/Swift/ModulesProvider.swift +3 -11
  172. package/ios/Swift/Objects/ObjectDefinition.swift +30 -0
  173. package/ios/Swift/Objects/ObjectDefinitionComponents.swift +384 -0
  174. package/ios/Swift/Promise.swift +8 -3
  175. package/ios/Swift/Records/AnyField.swift +7 -0
  176. package/ios/Swift/Records/Field.swift +24 -19
  177. package/ios/Swift/Records/FieldOption.swift +1 -1
  178. package/ios/Swift/Records/Record.swift +12 -4
  179. package/ios/Swift/SwiftInteropBridge.swift +53 -15
  180. package/ios/Swift/Views/AnyViewProp.swift +1 -1
  181. package/ios/Swift/Views/ComponentData.swift +96 -0
  182. package/ios/Swift/Views/ConcreteViewProp.swift +6 -8
  183. package/ios/Swift/Views/ExpoView.swift +8 -0
  184. package/ios/Swift/Views/ViewFactory.swift +1 -1
  185. package/ios/Swift/Views/ViewManagerDefinition.swift +23 -2
  186. package/ios/Swift/Views/ViewManagerDefinitionBuilder.swift +0 -1
  187. package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +26 -0
  188. package/ios/Swift/Views/ViewModuleWrapper.swift +5 -2
  189. package/ios/Swift.h +5 -0
  190. package/ios/Tests/ArgumentTypeSpec.swift +5 -7
  191. package/ios/Tests/ConstantsSpec.swift +6 -7
  192. package/ios/Tests/ConvertiblesSpec.swift +35 -36
  193. package/ios/Tests/ExceptionsSpec.swift +111 -0
  194. package/ios/Tests/ExpoModulesSpec.swift +76 -0
  195. package/ios/Tests/FunctionSpec.swift +22 -25
  196. package/ios/Tests/FunctionWithConvertiblesSpec.swift +4 -5
  197. package/ios/Tests/JavaScriptObjectSpec.swift +97 -0
  198. package/ios/Tests/JavaScriptRuntimeSpec.swift +94 -0
  199. package/ios/Tests/Mocks/ModuleMocks.swift +1 -1
  200. package/ios/Tests/Mocks/ModulesProviderMock.swift +0 -1
  201. package/ios/Tests/ModuleEventListenersSpec.swift +3 -4
  202. package/ios/Tests/ModuleRegistrySpec.swift +2 -3
  203. package/ios/Tests/RecordSpec.swift +9 -20
  204. package/package.json +3 -3
  205. package/src/NativeModulesProxy.native.ts +2 -22
  206. package/src/NativeModulesProxy.types.ts +0 -8
  207. package/src/NativeViewManagerAdapter.native.tsx +12 -28
  208. package/src/index.ts +4 -0
  209. package/src/requireNativeModule.ts +29 -0
  210. package/src/sweet/NativeErrorManager.ts +2 -0
  211. package/src/sweet/setUpErrorManager.fx.ts +12 -0
  212. package/android/src/main/java/expo/modules/kotlin/events/KEventEmitterWrapper.kt +0 -26
  213. package/android/src/main/java/expo/modules/kotlin/methods/Method.kt +0 -14
  214. package/android/src/main/java/expo/modules/kotlin/methods/PromiseMethod.kt +0 -15
  215. package/ios/JSI/ExpoModulesProxySpec.h +0 -24
  216. package/ios/JSI/ExpoModulesProxySpec.mm +0 -135
  217. package/ios/JSI/JSIInstaller.mm +0 -22
@@ -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
+ }
@@ -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) -> Void
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
  }
@@ -0,0 +1,17 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ Represents a function that can only be called asynchronously, thus its JavaScript equivalent returns a Promise.
5
+
6
+ - ToDo: Move some asynchronous logic from `ConcreteFunction` (like `call(args:promise:)`) to this class and drop the `isAsync` property.
7
+ */
8
+ public final class AsyncFunction<Args, ReturnType>: ConcreteFunction<Args, ReturnType> {
9
+ override init(
10
+ _ name: String,
11
+ argTypes: [AnyArgumentType],
12
+ _ closure: @escaping ConcreteFunction<Args, ReturnType>.ClosureType
13
+ ) {
14
+ super.init(name, argTypes: argTypes, closure)
15
+ self.isAsync = true
16
+ }
17
+ }