expo-modules-core 0.4.9 → 0.6.2

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 (145) hide show
  1. package/CHANGELOG.md +33 -2
  2. package/android/build.gradle +30 -2
  3. package/android/src/main/java/expo/modules/adapters/react/ModuleRegistryAdapter.java +42 -5
  4. package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +49 -5
  5. package/android/src/main/java/expo/modules/core/BasePackage.java +6 -0
  6. package/android/src/main/java/expo/modules/core/ModulePriorities.kt +25 -0
  7. package/android/src/main/java/expo/modules/core/interfaces/ActivityEventListener.java +3 -1
  8. package/android/src/main/java/expo/modules/core/interfaces/Package.java +4 -0
  9. package/android/src/main/java/expo/modules/core/interfaces/ReactActivityHandler.java +21 -0
  10. package/android/src/main/java/expo/modules/core/interfaces/ReactActivityLifecycleListener.java +23 -0
  11. package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.java +14 -0
  12. package/android/src/main/java/expo/modules/core/utilities/KotlinUtilities.kt +23 -0
  13. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +166 -0
  14. package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +9 -0
  15. package/android/src/main/java/expo/modules/kotlin/ExpoModulesHelper.kt +18 -0
  16. package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +24 -0
  17. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +98 -0
  18. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +41 -0
  19. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +56 -0
  20. package/android/src/main/java/expo/modules/kotlin/ModulesProvider.kt +7 -0
  21. package/android/src/main/java/expo/modules/kotlin/Promise.kt +13 -0
  22. package/android/src/main/java/expo/modules/kotlin/ReactLifecycleDelegate.kt +39 -0
  23. package/android/src/main/java/expo/modules/kotlin/ReadableArrayIterator.kt +14 -0
  24. package/android/src/main/java/expo/modules/kotlin/ReadableTypeExtensions.kt +18 -0
  25. package/android/src/main/java/expo/modules/kotlin/allocators/ObjectConstructor.kt +5 -0
  26. package/android/src/main/java/expo/modules/kotlin/allocators/ObjectConstructorFactory.kt +31 -0
  27. package/android/src/main/java/expo/modules/kotlin/allocators/UnsafeAllocator.kt +49 -0
  28. package/android/src/main/java/expo/modules/kotlin/events/EventListener.kt +39 -0
  29. package/android/src/main/java/expo/modules/kotlin/events/EventName.kt +31 -0
  30. package/android/src/main/java/expo/modules/kotlin/events/EventsDefinition.kt +3 -0
  31. package/android/src/main/java/expo/modules/kotlin/events/KEventEmitterWrapper.kt +26 -0
  32. package/android/src/main/java/expo/modules/kotlin/events/OnActivityResultPayload.kt +8 -0
  33. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +70 -0
  34. package/android/src/main/java/expo/modules/kotlin/methods/AnyMethod.kt +50 -0
  35. package/android/src/main/java/expo/modules/kotlin/methods/Method.kt +14 -0
  36. package/android/src/main/java/expo/modules/kotlin/methods/PromiseMethod.kt +15 -0
  37. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +24 -0
  38. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +227 -0
  39. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +16 -0
  40. package/android/src/main/java/expo/modules/kotlin/records/Field.kt +5 -0
  41. package/android/src/main/java/expo/modules/kotlin/records/Record.kt +3 -0
  42. package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +55 -0
  43. package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +14 -0
  44. package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +44 -0
  45. package/android/src/main/java/expo/modules/kotlin/types/BasicTypeConverters.kt +60 -0
  46. package/android/src/main/java/expo/modules/kotlin/types/EnumTypeConverter.kt +84 -0
  47. package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +25 -0
  48. package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +39 -0
  49. package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +28 -0
  50. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +19 -0
  51. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +107 -0
  52. package/android/src/main/java/expo/modules/kotlin/views/AnyViewProp.kt +10 -0
  53. package/android/src/main/java/expo/modules/kotlin/views/ConcreteViewProp.kt +17 -0
  54. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +22 -0
  55. package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +21 -0
  56. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +41 -0
  57. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +40 -0
  58. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +21 -0
  59. package/android/src/main/java/expo/modules/kotlin/views/ViewWrapperDelegateHolder.kt +5 -0
  60. package/build/NativeModulesProxy.native.d.ts +4 -0
  61. package/build/NativeModulesProxy.native.js +14 -1
  62. package/build/NativeModulesProxy.native.js.map +1 -1
  63. package/build/NativeModulesProxy.types.d.ts +3 -0
  64. package/build/NativeModulesProxy.types.js.map +1 -1
  65. package/build/NativeViewManagerAdapter.native.js +1 -1
  66. package/build/NativeViewManagerAdapter.native.js.map +1 -1
  67. package/ios/AppDelegates/EXAppDelegateWrapper.h +19 -0
  68. package/ios/AppDelegates/EXAppDelegateWrapper.m +45 -0
  69. package/ios/AppDelegates/EXAppDelegatesLoader.h +15 -0
  70. package/ios/AppDelegates/EXAppDelegatesLoader.m +30 -0
  71. package/ios/AppDelegates/EXLegacyAppDelegateWrapper.h +16 -0
  72. package/ios/{EXAppDelegateWrapper.m → AppDelegates/EXLegacyAppDelegateWrapper.m} +2 -2
  73. package/ios/AppDelegates/ExpoAppDelegate.swift +282 -0
  74. package/ios/AppDelegates/ExpoAppDelegateSubscriber.swift +24 -0
  75. package/ios/EXAppDefines.h +26 -0
  76. package/ios/EXAppDefines.m +61 -0
  77. package/ios/ExpoModulesCore.podspec +8 -3
  78. package/ios/JSI/ExpoModulesProxySpec.h +24 -0
  79. package/ios/JSI/ExpoModulesProxySpec.mm +135 -0
  80. package/ios/JSI/JSIConversions.h +42 -0
  81. package/ios/JSI/JSIConversions.mm +164 -0
  82. package/ios/JSI/JSIInstaller.h +19 -0
  83. package/ios/JSI/JSIInstaller.mm +22 -0
  84. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +1 -6
  85. package/ios/NativeModulesProxy/EXNativeModulesProxy.h +6 -0
  86. package/ios/NativeModulesProxy/{EXNativeModulesProxy.m → EXNativeModulesProxy.mm} +63 -17
  87. package/ios/ReactDelegates/EXRCTBridgeDelegateInterceptor.h +16 -0
  88. package/ios/ReactDelegates/EXRCTBridgeDelegateInterceptor.m +49 -0
  89. package/ios/ReactDelegates/EXReactDelegateWrapper+Private.h +18 -0
  90. package/ios/ReactDelegates/EXReactDelegateWrapper.h +25 -0
  91. package/ios/ReactDelegates/EXReactDelegateWrapper.m +40 -0
  92. package/ios/ReactDelegates/ExpoReactDelegate.swift +37 -0
  93. package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +52 -0
  94. package/ios/ReactDelegates/ModulePriorities.swift +20 -0
  95. package/ios/Services/EXReactNativeEventEmitter.h +6 -0
  96. package/ios/Services/EXReactNativeEventEmitter.m +15 -0
  97. package/ios/Swift/AppContext.swift +14 -1
  98. package/ios/Swift/Arguments/AnyArgument.swift +14 -0
  99. package/ios/Swift/Arguments/AnyArgumentType.swift +13 -0
  100. package/ios/Swift/Arguments/ArgumentType.swift +24 -0
  101. package/ios/Swift/Arguments/ConvertibleArgument.swift +15 -0
  102. package/ios/Swift/Arguments/Convertibles.swift +107 -0
  103. package/ios/Swift/Arguments/Types/ArrayArgumentType.swift +42 -0
  104. package/ios/Swift/Arguments/Types/ConvertibleArgumentType.swift +16 -0
  105. package/ios/Swift/Arguments/Types/EnumArgumentType.swift +105 -0
  106. package/ios/Swift/Arguments/Types/OptionalArgumentType.swift +49 -0
  107. package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +15 -0
  108. package/ios/Swift/Arguments/Types/RawArgumentType.swift +25 -0
  109. package/ios/Swift/Conversions.swift +199 -7
  110. package/ios/Swift/EventListener.swift +37 -5
  111. package/ios/Swift/Functions/AnyFunction.swift +42 -0
  112. package/ios/Swift/{Methods/ConcreteMethod.swift → Functions/ConcreteFunction.swift} +32 -34
  113. package/ios/Swift/ModuleHolder.swift +86 -20
  114. package/ios/Swift/ModuleRegistry.swift +19 -8
  115. package/ios/Swift/Modules/AnyModule.swift +8 -8
  116. package/ios/Swift/Modules/Module.swift +11 -0
  117. package/ios/Swift/Modules/ModuleDefinition.swift +55 -15
  118. package/ios/Swift/Modules/ModuleDefinitionBuilder.swift +1 -1
  119. package/ios/Swift/Modules/ModuleDefinitionComponents.swift +149 -54
  120. package/ios/Swift/ModulesProvider.swift +19 -0
  121. package/ios/Swift/Promise.swift +1 -1
  122. package/ios/Swift/Records/Field.swift +1 -1
  123. package/ios/Swift/Records/Record.swift +8 -1
  124. package/ios/Swift/SwiftInteropBridge.swift +46 -17
  125. package/ios/Swift/Views/AnyViewProp.swift +2 -2
  126. package/ios/Swift/Views/ConcreteViewProp.swift +37 -10
  127. package/ios/Swift/Views/ViewModuleWrapper.swift +9 -4
  128. package/ios/Swift.h +9 -0
  129. package/ios/Tests/ArgumentTypeSpec.swift +145 -0
  130. package/ios/Tests/ConstantsSpec.swift +36 -0
  131. package/ios/Tests/ConvertiblesSpec.swift +265 -0
  132. package/ios/Tests/EXAppDefinesTest.m +99 -0
  133. package/ios/Tests/{MethodSpec.swift → FunctionSpec.swift} +69 -54
  134. package/ios/Tests/FunctionWithConvertiblesSpec.swift +66 -0
  135. package/ios/Tests/Mocks/ModuleMocks.swift +21 -7
  136. package/ios/Tests/ModuleEventListenersSpec.swift +17 -16
  137. package/ios/Tests/ModuleRegistrySpec.swift +4 -7
  138. package/package.json +3 -3
  139. package/src/NativeModulesProxy.native.ts +22 -2
  140. package/src/NativeModulesProxy.types.ts +8 -0
  141. package/src/NativeViewManagerAdapter.native.tsx +1 -1
  142. package/ios/EXAppDelegateWrapper.h +0 -13
  143. package/ios/Swift/Methods/AnyArgumentType.swift +0 -48
  144. package/ios/Swift/Methods/AnyMethod.swift +0 -31
  145. package/ios/Swift/Methods/AnyMethodArgument.swift +0 -13
@@ -4,6 +4,7 @@
4
4
  #import <ExpoModulesCore/EXEventEmitter.h>
5
5
  #import <ExpoModulesCore/EXExportedModule.h>
6
6
  #import <ExpoModulesCore/EXModuleRegistry.h>
7
+ #import <ExpoModulesCore/Swift.h>
7
8
 
8
9
  @interface EXReactNativeEventEmitter ()
9
10
 
@@ -42,6 +43,10 @@
42
43
  - (NSArray<NSString *> *)supportedEvents
43
44
  {
44
45
  NSMutableSet<NSString *> *eventsAccumulator = [NSMutableSet set];
46
+
47
+ if (_swiftInteropBridge) {
48
+ [eventsAccumulator addObjectsFromArray:[_swiftInteropBridge getSupportedEvents]];
49
+ }
45
50
  for (EXExportedModule *exportedModule in [_exModuleRegistry getAllExportedModules]) {
46
51
  if ([exportedModule conformsToProtocol:@protocol(EXEventEmitter)]) {
47
52
  id<EXEventEmitter> eventEmitter = (id<EXEventEmitter>)exportedModule;
@@ -54,6 +59,11 @@
54
59
  RCT_EXPORT_METHOD(addProxiedListener:(NSString *)moduleName eventName:(NSString *)eventName)
55
60
  {
56
61
  [self addListener:eventName];
62
+
63
+ if ([_swiftInteropBridge hasModule:moduleName]) {
64
+ [_swiftInteropBridge modifyEventListenersCount:moduleName count:1];
65
+ return;
66
+ }
57
67
  // Validate module
58
68
  EXExportedModule *module = [_exModuleRegistry getExportedModuleForName:moduleName];
59
69
 
@@ -90,6 +100,11 @@ RCT_EXPORT_METHOD(addProxiedListener:(NSString *)moduleName eventName:(NSString
90
100
  RCT_EXPORT_METHOD(removeProxiedListeners:(NSString *)moduleName count:(double)count)
91
101
  {
92
102
  [self removeListeners:count];
103
+
104
+ if ([_swiftInteropBridge hasModule:moduleName]) {
105
+ [_swiftInteropBridge modifyEventListenersCount:moduleName count:-count];
106
+ return;
107
+ }
93
108
  // Validate module
94
109
  EXExportedModule *module = [_exModuleRegistry getExportedModuleForName:moduleName];
95
110
 
@@ -2,7 +2,7 @@ import UIKit
2
2
  /**
3
3
  The app context is an interface to a single Expo app.
4
4
  */
5
- public class AppContext {
5
+ public final class AppContext {
6
6
  /**
7
7
  The module registry for the app context.
8
8
  */
@@ -71,6 +71,13 @@ public class AppContext {
71
71
  return legacyModule(implementing: EXUtilitiesInterface.self)
72
72
  }
73
73
 
74
+ /**
75
+ Provides access to the event emitter from legacy module registry.
76
+ */
77
+ public var eventEmitter: EXEventEmitterService? {
78
+ return legacyModule(implementing: EXEventEmitterService.self)
79
+ }
80
+
74
81
  /**
75
82
  Starts listening to `UIApplication` notifications.
76
83
  */
@@ -108,4 +115,10 @@ public class AppContext {
108
115
  NotificationCenter.default.removeObserver(self)
109
116
  moduleRegistry.post(event: .appContextDestroys)
110
117
  }
118
+
119
+ // MARK: Errors
120
+
121
+ struct DeallocatedAppContextError: CodedError {
122
+ var description: String = "The app context has been deallocated."
123
+ }
111
124
  }
@@ -0,0 +1,14 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ A protocol for classes/structs accepted as an argument of functions.
5
+ */
6
+ public protocol AnyArgument {}
7
+
8
+ // Extend the primitive types — these may come from React Native bridge.
9
+ extension Bool: AnyArgument {}
10
+ extension Int: AnyArgument {}
11
+ extension Double: AnyArgument {}
12
+ extension String: AnyArgument {}
13
+ extension Array: AnyArgument {}
14
+ extension Dictionary: AnyArgument {}
@@ -0,0 +1,13 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ A protocol whose intention is to wrap function's argument type
5
+ to keep its real signature and not type-erase it by the compiler.
6
+ */
7
+ internal protocol AnyArgumentType: CustomStringConvertible {
8
+ /**
9
+ Casts given any value to the wrapped type and returns as `Any`.
10
+ NOTE: It may not be just simple type-casting (e.g. when the wrapped type conforms to `ConvertibleArgument`).
11
+ */
12
+ func cast<ArgType>(_ value: ArgType) throws -> Any
13
+ }
@@ -0,0 +1,24 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ Factory creating an instance of the argument type wrapper conforming to `AnyArgumentType`.
5
+ Depending on the given type, it may return one of `ArrayArgumentType`, `OptionalArgumentType`, `ConvertibleArgumentType`, etc.
6
+ */
7
+ internal func ArgumentType<T>(_ type: T.Type) -> AnyArgumentType {
8
+ if let ArrayType = T.self as? AnyArrayArgument.Type {
9
+ return ArrayArgumentType(elementType: ArrayType.getElementArgumentType())
10
+ }
11
+ if let OptionalType = T.self as? AnyOptionalArgument.Type {
12
+ return OptionalArgumentType(wrappedType: OptionalType.getWrappedArgumentType())
13
+ }
14
+ if let ConvertibleType = T.self as? ConvertibleArgument.Type {
15
+ return ConvertibleArgumentType(innerType: ConvertibleType)
16
+ }
17
+ if let EnumType = T.self as? EnumArgument.Type {
18
+ return EnumArgumentType(innerType: EnumType)
19
+ }
20
+ if T.self is Promise.Type {
21
+ return PromiseArgumentType()
22
+ }
23
+ return RawArgumentType(innerType: T.self)
24
+ }
@@ -0,0 +1,15 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ A protocol that allows custom classes or structs to be used as function arguments.
5
+ It requires static `convert(from:)` function that knows how to convert incoming
6
+ value of `Any` type to the type implemented by this protocol. It should throw an error
7
+ when the value is not recognized, is invalid or doesn't meet type requirements.
8
+ */
9
+ public protocol ConvertibleArgument: AnyArgument {
10
+ /**
11
+ Converts any value to the instance of its class (or struct).
12
+ Throws an error when given value cannot be converted.
13
+ */
14
+ static func convert(from value: Any?) throws -> Self
15
+ }
@@ -0,0 +1,107 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ import UIKit
4
+ import CoreGraphics
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.
11
+
12
+ // MARK: - Foundation
13
+
14
+ extension URL: ConvertibleArgument {
15
+ public static func convert(from value: Any?) throws -> Self {
16
+ if let uri = value as? String, let url = URL(string: uri) {
17
+ // `URL(string:)` is an optional init but it doesn't imply it's a valid URL,
18
+ // so here we don't check for the correctness of the URL.
19
+ // If it has no scheme, we assume it was the file path.
20
+ return url.scheme != nil ? url : URL(fileURLWithPath: uri)
21
+ }
22
+ throw Conversions.ConvertingError<URL>(value: value)
23
+ }
24
+ }
25
+
26
+ // MARK: - UIKit
27
+
28
+ extension UIColor: ConvertibleArgument {
29
+ public static func convert(from value: Any?) throws -> Self {
30
+ if let value = value as? String {
31
+ return try Conversions.toColor(hexString: value) as! Self
32
+ }
33
+ if let components = value as? [Double] {
34
+ let alpha = components.count > 3 ? components[3] : 1.0
35
+ return Self.init(red: CGFloat(components[0]), green: CGFloat(components[1]), blue: CGFloat(components[2]), alpha: CGFloat(alpha))
36
+ }
37
+ if let value = value as? Int {
38
+ return try Conversions.toColor(argb: UInt64(value)) as! Self
39
+ }
40
+ throw Conversions.ConvertingError<UIColor>(value: value)
41
+ }
42
+ }
43
+
44
+ // MARK: - CoreGraphics
45
+
46
+ extension CGPoint: ConvertibleArgument {
47
+ public static func convert(from value: Any?) throws -> CGPoint {
48
+ if let value = value as? [Double], value.count == 2 {
49
+ return CGPoint(x: value[0], y: value[1])
50
+ }
51
+ if let value = value as? [String: Any] {
52
+ let args = try Conversions.pickValues(from: value, byKeys: ["x", "y"], as: Double.self)
53
+ return CGPoint(x: args[0], y: args[1])
54
+ }
55
+ throw Conversions.ConvertingError<CGPoint>(value: value)
56
+ }
57
+ }
58
+
59
+ extension CGSize: ConvertibleArgument {
60
+ public static func convert(from value: Any?) throws -> CGSize {
61
+ if let value = value as? [Double], value.count == 2 {
62
+ return CGSize(width: value[0], height: value[1])
63
+ }
64
+ if let value = value as? [String: Any] {
65
+ let args = try Conversions.pickValues(from: value, byKeys: ["width", "height"], as: Double.self)
66
+ return CGSize(width: args[0], height: args[1])
67
+ }
68
+ throw Conversions.ConvertingError<CGSize>(value: value)
69
+ }
70
+ }
71
+
72
+ extension CGVector: ConvertibleArgument {
73
+ public static func convert(from value: Any?) throws -> CGVector {
74
+ if let value = value as? [Double], value.count == 2 {
75
+ return CGVector(dx: value[0], dy: value[1])
76
+ }
77
+ if let value = value as? [String: Any] {
78
+ let args = try Conversions.pickValues(from: value, byKeys: ["dx", "dy"], as: Double.self)
79
+ return CGVector(dx: args[0], dy: args[1])
80
+ }
81
+ throw Conversions.ConvertingError<CGVector>(value: value)
82
+ }
83
+ }
84
+
85
+ extension CGRect: ConvertibleArgument {
86
+ public static func convert(from value: Any?) throws -> CGRect {
87
+ if let value = value as? [Double], value.count == 4 {
88
+ return CGRect(x: value[0], y: value[1], width: value[2], height: value[3])
89
+ }
90
+ if let value = value as? [String: Any] {
91
+ let args = try Conversions.pickValues(from: value, byKeys: ["x", "y", "width", "height"], as: Double.self)
92
+ return CGRect(x: args[0], y: args[1], width: args[2], height: args[3])
93
+ }
94
+ throw Conversions.ConvertingError<CGRect>(value: value)
95
+ }
96
+ }
97
+
98
+ extension CGColor: ConvertibleArgument {
99
+ public static func convert(from value: Any?) throws -> Self {
100
+ do {
101
+ return try UIColor.convert(from: value).cgColor as! Self
102
+ } catch _ as Conversions.ConvertingError<UIColor> {
103
+ // Rethrow `ConvertingError` with proper type
104
+ throw Conversions.ConvertingError<CGColor>(value: value)
105
+ }
106
+ }
107
+ }
@@ -0,0 +1,42 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ An argument type representing array types. Requires the argument type for
5
+ array's element type as it delegates casting to that type for each element in the array.
6
+ */
7
+ internal struct ArrayArgumentType: AnyArgumentType {
8
+ let elementType: AnyArgumentType
9
+
10
+ func cast<ArgType>(_ value: ArgType) throws -> Any {
11
+ if let value = value as? [Any] {
12
+ return try value.map { try elementType.cast($0) }
13
+ }
14
+ // We should probably throw an error if we get here. On the other side, the array type
15
+ // requirement can be more loosen so we can try to arrayize values that are not arrays.
16
+ return [try elementType.cast(value)]
17
+ }
18
+
19
+ var description: String {
20
+ "[\(elementType.description)]"
21
+ }
22
+ }
23
+
24
+ /**
25
+ A type-erased protocol used to recognize arrays with elements of argument-compatible type.
26
+ `Array` is a generic type, so it's impossible to check the inheritance directly.
27
+ */
28
+ internal protocol AnyArrayArgument: AnyArgument {
29
+ /**
30
+ Exposes the `Element` generic type wrapped by the argument type to preserve its metadata.
31
+ */
32
+ static func getElementArgumentType() -> AnyArgumentType
33
+ }
34
+
35
+ /**
36
+ Extends the `Array` type to expose its generic `Element` as an argument type.
37
+ */
38
+ extension Array: AnyArrayArgument where Element: AnyArgument {
39
+ static func getElementArgumentType() -> AnyArgumentType {
40
+ return ArgumentType(Element.self)
41
+ }
42
+ }
@@ -0,0 +1,16 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ An argument type that wraps any type conforming to `ConvertibleArgument` protocol.
5
+ */
6
+ internal struct ConvertibleArgumentType: AnyArgumentType {
7
+ let innerType: ConvertibleArgument.Type
8
+
9
+ func cast<ArgType>(_ value: ArgType) throws -> Any {
10
+ return try innerType.convert(from: value)
11
+ }
12
+
13
+ var description: String {
14
+ String(describing: innerType.self)
15
+ }
16
+ }
@@ -0,0 +1,105 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ An argument type representing an enum that conforms to `EnumArgument`.
5
+ */
6
+ internal struct EnumArgumentType: AnyArgumentType {
7
+ let innerType: EnumArgument.Type
8
+
9
+ func cast<ArgType>(_ value: ArgType) throws -> Any {
10
+ return try innerType.create(fromRawValue: value)
11
+ }
12
+
13
+ var description: String {
14
+ "Enum<\(innerType)>"
15
+ }
16
+ }
17
+
18
+ /**
19
+ A protocol that allows converting raw values to enum cases.
20
+ */
21
+ public protocol EnumArgument: AnyArgument {
22
+ /**
23
+ Tries to create an enum case using given raw value.
24
+ May throw errors, e.g. when the raw value doesn't match any case.
25
+ */
26
+ static func create<ArgType>(fromRawValue rawValue: ArgType) throws -> Self
27
+
28
+ /**
29
+ Returns an array of all raw values available in the enum.
30
+ */
31
+ static var allRawValues: [Any] { get }
32
+
33
+ /**
34
+ Type-erased enum's raw value.
35
+ */
36
+ var anyRawValue: Any { get }
37
+ }
38
+
39
+ /**
40
+ Extension for `EnumArgument` that also conforms to `RawRepresentable`.
41
+ This constraint allows us to reference the associated `RawValue` type.
42
+ */
43
+ public extension EnumArgument where Self: RawRepresentable, Self: Hashable {
44
+ static func create<ArgType>(fromRawValue rawValue: ArgType) throws -> Self {
45
+ guard let rawValue = rawValue as? RawValue else {
46
+ throw EnumCastingError(type: RawValue.self, value: rawValue)
47
+ }
48
+ guard let enumCase = Self.init(rawValue: rawValue) else {
49
+ throw EnumNoSuchValueError(type: Self.self, value: rawValue)
50
+ }
51
+ return enumCase
52
+ }
53
+
54
+ var anyRawValue: Any {
55
+ rawValue
56
+ }
57
+
58
+ static var allRawValues: [Any] {
59
+ // Be careful — it operates on unsafe pointers!
60
+ let sequence = AnySequence { () -> AnyIterator<RawValue> in
61
+ var raw = 0
62
+ return AnyIterator {
63
+ let current: Self? = withUnsafePointer(to: &raw) { ptr in
64
+ ptr.withMemoryRebound(to: Self.self, capacity: 1) { $0.pointee }
65
+ }
66
+ guard let value = current?.rawValue else {
67
+ return nil
68
+ }
69
+ raw += 1
70
+ return value
71
+ }
72
+ }
73
+ return Array(sequence)
74
+ }
75
+ }
76
+
77
+ /**
78
+ An error that is thrown when the value cannot be casted to associated `RawValue`.
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)`"
86
+ }
87
+ }
88
+
89
+ /**
90
+ An error that is thrown when the value doesn't match any available case.
91
+ */
92
+ internal struct EnumNoSuchValueError: CodedError {
93
+ let type: EnumArgument.Type
94
+ let value: Any
95
+
96
+ var allRawValuesFormatted: String {
97
+ return type.allRawValues
98
+ .map { "`\($0)`" }
99
+ .joined(separator: ", ")
100
+ }
101
+
102
+ var description: String {
103
+ "Cannot create `\(type)` enum from value `\(value)`. It must be one of: \(allRawValuesFormatted)"
104
+ }
105
+ }
@@ -0,0 +1,49 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ An argument type that represents an optional type, which allows `nil` to be passed when casting.
5
+ Requires the argument type for optional's unwrapped type as it delegates casting to that type for non-nil values.
6
+ */
7
+ internal struct OptionalArgumentType: AnyArgumentType {
8
+ let wrappedType: AnyArgumentType
9
+
10
+ func cast<ArgType>(_ value: ArgType) throws -> Any {
11
+ if Optional.isNil(value) {
12
+ return Optional<Any>.none as Any
13
+ }
14
+ return try wrappedType.cast(value)
15
+ }
16
+
17
+ var description: String {
18
+ "\(wrappedType)?"
19
+ }
20
+ }
21
+
22
+ /**
23
+ A type-erased protocol used to recognize if the generic type is an optional type.
24
+ `Optional` is a generic enum, so it's impossible to check the inheritance directly.
25
+ */
26
+ internal protocol AnyOptionalArgument: AnyArgument {
27
+ /**
28
+ Exposes the `Wrapped` generic type wrapped by the argument type to preserve its metadata.`
29
+ */
30
+ static func getWrappedArgumentType() -> AnyArgumentType
31
+ }
32
+
33
+ /**
34
+ Make generic `Optional` implement non-generic `AnyOptional` and add handy check against type-erased `nil`.
35
+ */
36
+ extension Optional: AnyOptionalArgument {
37
+ static func getWrappedArgumentType() -> AnyArgumentType {
38
+ return ArgumentType(Wrapped.self)
39
+ }
40
+
41
+ static func isNil(_ object: Wrapped) -> Bool {
42
+ switch object as Any {
43
+ case Optional<Any>.none:
44
+ return true
45
+ default:
46
+ return false
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,15 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ An argument type that represents the `Promise` argument.
5
+ */
6
+ internal struct PromiseArgumentType: AnyArgumentType {
7
+ func cast<ArgType>(_ value: ArgType) throws -> Any {
8
+ if let value = value as? Promise {
9
+ return value
10
+ }
11
+ throw Conversions.CastingError<Promise>(value: value)
12
+ }
13
+
14
+ var description: String = "Promise"
15
+ }
@@ -0,0 +1,25 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ An argument type that can wrap any type, but it casts only type-compatible values using `as?` keyword.
5
+ The innermost type of other argument types like `ArrayArgumentType` and `OptionalArgumentType`.
6
+ */
7
+ internal struct RawArgumentType<InnerType>: AnyArgumentType {
8
+ let innerType: InnerType.Type
9
+
10
+ func cast<ArgType>(_ value: ArgType) throws -> Any {
11
+ if let value = value as? InnerType {
12
+ return value
13
+ }
14
+ // Raw arguments are always non-optional, but they may receive `nil` values.
15
+ // Let's throw more specific error in this case.
16
+ if Optional.isNil(value) {
17
+ throw Conversions.NullCastError<InnerType>()
18
+ }
19
+ throw Conversions.CastingError<InnerType>(value: value)
20
+ }
21
+
22
+ var description: String {
23
+ String(describing: innerType.self)
24
+ }
25
+ }