expo-modules-core 0.9.2 → 0.10.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 (167) hide show
  1. package/CHANGELOG.md +18 -5
  2. package/android/CMakeLists.txt +154 -0
  3. package/android/build.gradle +293 -5
  4. package/android/src/main/cpp/Exceptions.cpp +22 -0
  5. package/android/src/main/cpp/Exceptions.h +38 -0
  6. package/android/src/main/cpp/ExpoModulesHostObject.cpp +47 -0
  7. package/android/src/main/cpp/ExpoModulesHostObject.h +32 -0
  8. package/android/src/main/cpp/JNIFunctionBody.cpp +29 -0
  9. package/android/src/main/cpp/JNIFunctionBody.h +50 -0
  10. package/android/src/main/cpp/JNIInjector.cpp +19 -0
  11. package/android/src/main/cpp/JSIInteropModuleRegistry.cpp +122 -0
  12. package/android/src/main/cpp/JSIInteropModuleRegistry.h +96 -0
  13. package/android/src/main/cpp/JSIObjectWrapper.h +33 -0
  14. package/android/src/main/cpp/JSITypeConverter.h +84 -0
  15. package/android/src/main/cpp/JavaScriptModuleObject.cpp +138 -0
  16. package/android/src/main/cpp/JavaScriptModuleObject.h +122 -0
  17. package/android/src/main/cpp/JavaScriptObject.cpp +125 -0
  18. package/android/src/main/cpp/JavaScriptObject.h +131 -0
  19. package/android/src/main/cpp/JavaScriptRuntime.cpp +127 -0
  20. package/android/src/main/cpp/JavaScriptRuntime.h +87 -0
  21. package/android/src/main/cpp/JavaScriptValue.cpp +172 -0
  22. package/android/src/main/cpp/JavaScriptValue.h +78 -0
  23. package/android/src/main/cpp/MethodMetadata.cpp +230 -0
  24. package/android/src/main/cpp/MethodMetadata.h +92 -0
  25. package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +2 -0
  26. package/android/src/main/java/expo/modules/core/errors/ContextDestroyedException.kt +7 -0
  27. package/android/src/main/java/expo/modules/interfaces/permissions/Permissions.java +30 -0
  28. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +49 -1
  29. package/android/src/main/java/expo/modules/kotlin/ConcatIterator.kt +18 -0
  30. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +15 -12
  31. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +39 -3
  32. package/android/src/main/java/expo/modules/kotlin/defaultmodules/ErrorManagerModule.kt +2 -2
  33. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +13 -0
  34. package/android/src/main/java/expo/modules/kotlin/exception/ExceptionDecorator.kt +2 -0
  35. package/android/src/main/java/expo/modules/kotlin/functions/AnyFunction.kt +19 -14
  36. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +29 -7
  37. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +13 -13
  38. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +18 -0
  39. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +18 -0
  40. package/android/src/main/java/expo/modules/kotlin/functions/SuspendFunctionComponent.kt +56 -0
  41. package/android/src/main/java/expo/modules/kotlin/functions/SyncFunctionComponent.kt +28 -0
  42. package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +18 -0
  43. package/android/src/main/java/expo/modules/kotlin/jni/JNIFunctionBody.kt +39 -0
  44. package/android/src/main/java/expo/modules/kotlin/jni/JSIInteropModuleRegistry.kt +89 -0
  45. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptModuleObject.kt +44 -0
  46. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptObject.kt +113 -0
  47. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +35 -0
  48. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +15 -5
  49. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +65 -111
  50. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +35 -2
  51. package/android/src/main/java/expo/modules/kotlin/providers/AppContextProvider.kt +14 -0
  52. package/android/src/main/java/expo/modules/kotlin/providers/CurrentActivityProvider.kt +22 -0
  53. package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +19 -2
  54. package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +3 -2
  55. package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +7 -2
  56. package/android/src/main/java/expo/modules/kotlin/types/BasicTypeConverters.kt +68 -20
  57. package/android/src/main/java/expo/modules/kotlin/types/EnumTypeConverter.kt +50 -22
  58. package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +18 -2
  59. package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +18 -2
  60. package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +17 -2
  61. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +43 -3
  62. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +5 -0
  63. package/build/NativeModulesProxy.native.d.ts.map +1 -1
  64. package/build/NativeModulesProxy.native.js +9 -3
  65. package/build/NativeModulesProxy.native.js.map +1 -1
  66. package/ios/AppDelegates/EXAppDelegatesLoader.m +1 -2
  67. package/ios/ExpoModulesCore.podspec +1 -1
  68. package/ios/JSI/EXJSIConversions.mm +6 -0
  69. package/ios/JSI/EXJSIInstaller.h +15 -21
  70. package/ios/JSI/EXJSIInstaller.mm +39 -3
  71. package/ios/JSI/EXJSIUtils.h +47 -3
  72. package/ios/JSI/EXJSIUtils.mm +88 -4
  73. package/ios/JSI/EXJavaScriptObject.h +11 -18
  74. package/ios/JSI/EXJavaScriptObject.mm +37 -18
  75. package/ios/JSI/EXJavaScriptRuntime.h +43 -9
  76. package/ios/JSI/EXJavaScriptRuntime.mm +70 -27
  77. package/ios/JSI/EXJavaScriptTypedArray.h +30 -0
  78. package/ios/JSI/EXJavaScriptTypedArray.mm +29 -0
  79. package/ios/JSI/EXJavaScriptValue.h +3 -2
  80. package/ios/JSI/EXJavaScriptValue.mm +17 -20
  81. package/ios/JSI/EXJavaScriptWeakObject.h +23 -0
  82. package/ios/JSI/EXJavaScriptWeakObject.mm +53 -0
  83. package/ios/JSI/EXObjectDeallocator.h +27 -0
  84. package/ios/JSI/ExpoModulesHostObject.h +3 -3
  85. package/ios/JSI/ExpoModulesHostObject.mm +4 -4
  86. package/ios/JSI/JavaScriptRuntime.swift +38 -1
  87. package/ios/JSI/JavaScriptValue.swift +7 -0
  88. package/ios/JSI/TypedArray.cpp +67 -0
  89. package/ios/JSI/TypedArray.h +46 -0
  90. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +0 -11
  91. package/ios/NativeModulesProxy/EXNativeModulesProxy.h +17 -10
  92. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +85 -77
  93. package/ios/NativeModulesProxy/NativeModulesProxyModule.swift +17 -0
  94. package/ios/Services/EXReactNativeEventEmitter.h +2 -2
  95. package/ios/Services/EXReactNativeEventEmitter.m +11 -6
  96. package/ios/Swift/AppContext.swift +208 -28
  97. package/ios/Swift/Arguments/AnyArgument.swift +18 -0
  98. package/ios/Swift/Arguments/{Types/EnumArgumentType.swift → EnumArgument.swift} +2 -17
  99. package/ios/Swift/Classes/ClassComponent.swift +95 -0
  100. package/ios/Swift/Classes/ClassComponentElement.swift +33 -0
  101. package/ios/Swift/Classes/ClassComponentElementsBuilder.swift +34 -0
  102. package/ios/Swift/Classes/ClassComponentFactories.swift +96 -0
  103. package/ios/Swift/DynamicTypes/AnyDynamicType.swift +44 -0
  104. package/ios/Swift/DynamicTypes/DynamicArrayType.swift +56 -0
  105. package/ios/Swift/DynamicTypes/DynamicConvertibleType.swift +27 -0
  106. package/ios/Swift/DynamicTypes/DynamicEnumType.swift +27 -0
  107. package/ios/Swift/DynamicTypes/DynamicOptionalType.swift +63 -0
  108. package/ios/Swift/DynamicTypes/DynamicRawType.swift +33 -0
  109. package/ios/Swift/DynamicTypes/DynamicSharedObjectType.swift +37 -0
  110. package/ios/Swift/DynamicTypes/DynamicType.swift +39 -0
  111. package/ios/Swift/DynamicTypes/DynamicTypedArrayType.swift +46 -0
  112. package/ios/Swift/Exceptions/CodedError.swift +1 -1
  113. package/ios/Swift/Exceptions/Exception.swift +8 -6
  114. package/ios/Swift/Exceptions/UnexpectedException.swift +2 -1
  115. package/ios/Swift/ExpoBridgeModule.m +5 -0
  116. package/ios/Swift/ExpoBridgeModule.swift +65 -0
  117. package/ios/Swift/Functions/AnyFunction.swift +33 -31
  118. package/ios/Swift/Functions/AsyncFunctionComponent.swift +196 -59
  119. package/ios/Swift/Functions/SyncFunctionComponent.swift +142 -58
  120. package/ios/Swift/JavaScriptUtils.swift +32 -57
  121. package/ios/Swift/Logging/LogHandlers.swift +39 -0
  122. package/ios/Swift/Logging/LogType.swift +62 -0
  123. package/ios/Swift/Logging/Logger.swift +198 -0
  124. package/ios/Swift/ModuleHolder.swift +19 -54
  125. package/ios/Swift/ModuleRegistry.swift +7 -1
  126. package/ios/Swift/Modules/AnyModule.swift +3 -3
  127. package/ios/Swift/ModulesProvider.swift +2 -0
  128. package/ios/Swift/Objects/JavaScriptObjectBuilder.swift +37 -0
  129. package/ios/Swift/Objects/ObjectDefinition.swift +74 -1
  130. package/ios/Swift/Objects/ObjectDefinitionComponents.swift +77 -68
  131. package/ios/Swift/Objects/PropertyComponent.swift +147 -0
  132. package/ios/Swift/Promise.swift +12 -3
  133. package/ios/Swift/Records/Field.swift +2 -2
  134. package/ios/Swift/SharedObjects/SharedObject.swift +20 -0
  135. package/ios/Swift/SharedObjects/SharedObjectRegistry.swift +129 -0
  136. package/ios/Swift/TypedArrays/AnyTypedArray.swift +11 -0
  137. package/ios/Swift/TypedArrays/ConcreteTypedArrays.swift +56 -0
  138. package/ios/Swift/TypedArrays/GenericTypedArray.swift +49 -0
  139. package/ios/Swift/TypedArrays/TypedArray.swift +80 -0
  140. package/ios/Swift/Utilities.swift +28 -0
  141. package/ios/Swift/Views/ConcreteViewProp.swift +3 -3
  142. package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +2 -2
  143. package/ios/Tests/ClassComponentSpec.swift +210 -0
  144. package/ios/Tests/DynamicTypeSpec.swift +336 -0
  145. package/ios/Tests/EnumArgumentSpec.swift +48 -0
  146. package/ios/Tests/ExpoModulesSpec.swift +17 -3
  147. package/ios/Tests/FunctionSpec.swift +167 -118
  148. package/ios/Tests/Mocks/ModuleMocks.swift +1 -1
  149. package/ios/Tests/PropertyComponentSpec.swift +95 -0
  150. package/ios/Tests/SharedObjectRegistrySpec.swift +109 -0
  151. package/ios/Tests/TypedArraysSpec.swift +136 -0
  152. package/package.json +2 -2
  153. package/src/NativeModulesProxy.native.ts +13 -3
  154. package/src/ts-declarations/ExpoModules.d.ts +7 -0
  155. package/tsconfig.json +1 -1
  156. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromise.kt +0 -15
  157. package/android/src/main/java/expo/modules/kotlin/functions/AsyncSuspendFunction.kt +0 -36
  158. package/ios/Swift/Arguments/AnyArgumentType.swift +0 -13
  159. package/ios/Swift/Arguments/ArgumentType.swift +0 -28
  160. package/ios/Swift/Arguments/Types/ArrayArgumentType.swift +0 -42
  161. package/ios/Swift/Arguments/Types/ConvertibleArgumentType.swift +0 -16
  162. package/ios/Swift/Arguments/Types/OptionalArgumentType.swift +0 -49
  163. package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +0 -15
  164. package/ios/Swift/Arguments/Types/RawArgumentType.swift +0 -25
  165. package/ios/Swift/Functions/ConcreteFunction.swift +0 -103
  166. package/ios/Swift/SwiftInteropBridge.swift +0 -155
  167. package/ios/Tests/ArgumentTypeSpec.swift +0 -143
@@ -1,19 +1,4 @@
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
- }
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
17
2
 
18
3
  /**
19
4
  A protocol that allows converting raw values to enum cases.
@@ -23,7 +8,7 @@ public protocol EnumArgument: AnyArgument {
23
8
  Tries to create an enum case using given raw value.
24
9
  May throw errors, e.g. when the raw value doesn't match any case.
25
10
  */
26
- static func create<ArgType>(fromRawValue rawValue: ArgType) throws -> Self
11
+ static func create<RawValueType>(fromRawValue rawValue: RawValueType) throws -> Self
27
12
 
28
13
  /**
29
14
  Returns an array of all raw values available in the enum.
@@ -0,0 +1,95 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ Represents a JavaScript class.
5
+ */
6
+ public final class ClassComponent: ObjectDefinition {
7
+ /**
8
+ Name of the class.
9
+ */
10
+ let name: String
11
+
12
+ /**
13
+ A synchronous function that gets called when the object of this class is initializing.
14
+ */
15
+ let constructor: AnySyncFunctionComponent?
16
+
17
+ /**
18
+ A dynamic type for the associated object class.
19
+ */
20
+ let associatedType: AnyDynamicType?
21
+
22
+ init<AssociatedObject: ClassAssociatedObject>(
23
+ name: String,
24
+ associatedType: AssociatedObject.Type,
25
+ elements: [AnyClassComponentElement] = []
26
+ ) {
27
+ self.name = name
28
+ self.constructor = elements.first(where: isConstructor) as? AnySyncFunctionComponent
29
+ self.associatedType = ~AssociatedObject.self
30
+
31
+ // Constructors can't be passed down to the object component
32
+ // as we shouldn't override the default `<Class>.prototype.constructor`.
33
+ let elementsWithoutConstructors = elements.filter({ !isConstructor($0) })
34
+
35
+ super.init(definitions: elementsWithoutConstructors)
36
+ }
37
+
38
+ // MARK: - JavaScriptObjectBuilder
39
+
40
+ public override func build(inRuntime runtime: JavaScriptRuntime) -> JavaScriptObject {
41
+ let klass = runtime.createClass(name) { [weak self, weak runtime] this, arguments in
42
+ guard let self = self, let runtime = runtime else {
43
+ // TODO: Throw an exception? (@tsapeta)
44
+ return
45
+ }
46
+ // The properties can't go into the prototype as they would be shared across all instances.
47
+ // Instead, we decorate the instance object on initialization.
48
+ self.decorateWithProperties(runtime: runtime, object: this)
49
+
50
+ // Call the native constructor when defined.
51
+ let result = try? self.constructor?.call(by: this, withArguments: arguments)
52
+
53
+ // Register the shared object if returned by the constructor.
54
+ if let result = result as? SharedObject {
55
+ SharedObjectRegistry.add(native: result, javaScript: this)
56
+ }
57
+ }
58
+ decorate(object: klass, inRuntime: runtime)
59
+ return klass
60
+ }
61
+
62
+ public override func decorate(object: JavaScriptObject, inRuntime runtime: JavaScriptRuntime) {
63
+ // Here we actually don't decorate the input object (constructor) but its prototype.
64
+ // Properties are intentionally skipped here — they have to decorate an instance instead of the prototype.
65
+ let prototype = object.getProperty("prototype").getObject()
66
+ decorateWithConstants(runtime: runtime, object: prototype)
67
+ decorateWithFunctions(runtime: runtime, object: prototype)
68
+ decorateWithClasses(runtime: runtime, object: prototype)
69
+ }
70
+ }
71
+
72
+ // MARK: - ClassAssociatedObject
73
+
74
+ /**
75
+ A protocol for types that can be used an associated type of the `ClassComponent`.
76
+ */
77
+ internal protocol ClassAssociatedObject {}
78
+
79
+ // Basically we only need these two
80
+ extension JavaScriptObject: ClassAssociatedObject {}
81
+ extension SharedObject: ClassAssociatedObject {}
82
+
83
+ // MARK: - Privates
84
+
85
+ /**
86
+ Checks whether the definition item is a constructor — a synchronous function whose name is "constructor".
87
+
88
+ We do it that way for the following two reasons:
89
+ - It's easier to reuse existing `SyncFunctionComponent`.
90
+ - Redefining prototype's `constructor` is a bad idea so a function with this name
91
+ needs to be filtered out when decorating the prototype.
92
+ */
93
+ fileprivate func isConstructor(_ item: AnyDefinition) -> Bool {
94
+ return (item as? AnySyncFunctionComponent)?.name == "constructor"
95
+ }
@@ -0,0 +1,33 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ A type-erased protocol that must be implemented by the components passed as ``ClassComponent`` elements.
5
+ */
6
+ public protocol AnyClassComponentElement: AnyDefinition {}
7
+
8
+ /**
9
+ Class component element with an associated owner type. The `OwnerType` should refer to
10
+ the type that the parent `Class` component is associated with (e.g. the shared object type).
11
+ */
12
+ public protocol ClassComponentElement: AnyClassComponentElement {
13
+ associatedtype OwnerType
14
+ }
15
+
16
+ // MARK: - Conformance
17
+ // Allow some other components to be used as the class component elements.
18
+
19
+ extension SyncFunctionComponent: ClassComponentElement {
20
+ public typealias OwnerType = FirstArgType
21
+ }
22
+
23
+ extension AsyncFunctionComponent: ClassComponentElement {
24
+ public typealias OwnerType = FirstArgType
25
+ }
26
+
27
+ extension PropertyComponent: ClassComponentElement {
28
+ public typealias OwnerType = Void
29
+ }
30
+
31
+ extension ConstantsDefinition: ClassComponentElement {
32
+ public typealias OwnerType = Void
33
+ }
@@ -0,0 +1,34 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ A result builder that captures the ``ClassComponent`` elements such as functions, constants and properties.
5
+ */
6
+ @resultBuilder
7
+ public struct ClassComponentElementsBuilder<OwnerType> {
8
+ public static func buildBlock(_ elements: AnyClassComponentElement...) -> [AnyClassComponentElement] {
9
+ return elements
10
+ }
11
+
12
+ /**
13
+ Default implementation without any constraints that just returns type-erased element.
14
+ */
15
+ static func buildExpression<ElementType: ClassComponentElement>(
16
+ _ element: ElementType
17
+ ) -> AnyClassComponentElement {
18
+ return element
19
+ }
20
+
21
+ /**
22
+ In case the element's owner type matches builder's generic type,
23
+ we need to instruct the function to pass `this` to the closure
24
+ as the first argument and deduct it from `argumentsCount`.
25
+ */
26
+ static func buildExpression<ElementType: ClassComponentElement>(
27
+ _ element: ElementType
28
+ ) -> AnyClassComponentElement where ElementType.OwnerType == OwnerType {
29
+ if var function = element as? AnyFunction {
30
+ function.takesOwner = true
31
+ }
32
+ return element
33
+ }
34
+ }
@@ -0,0 +1,96 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ Class constructor without arguments.
5
+ */
6
+ public func Constructor<R>(
7
+ _ body: @escaping () throws -> R
8
+ ) -> SyncFunctionComponent<(), Void, R> {
9
+ return Function("constructor", body)
10
+ }
11
+
12
+ /**
13
+ Class constructor with one argument.
14
+ */
15
+ public func Constructor<R, A0: AnyArgument>(
16
+ _ body: @escaping (A0) throws -> R
17
+ ) -> SyncFunctionComponent<(A0), A0, R> {
18
+ return Function("constructor", body)
19
+ }
20
+
21
+ /**
22
+ Class constructor with two arguments.
23
+ */
24
+ public func Constructor<R, A0: AnyArgument, A1: AnyArgument>(
25
+ _ body: @escaping (A0, A1) throws -> R
26
+ ) -> SyncFunctionComponent<(A0, A1), A0, R> {
27
+ return Function("constructor", body)
28
+ }
29
+
30
+ /**
31
+ Class constructor with three arguments.
32
+ */
33
+ public func Constructor<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument>(
34
+ _ body: @escaping (A0, A1, A2) throws -> R
35
+ ) -> SyncFunctionComponent<(A0, A1, A2), A0, R> {
36
+ return Function("constructor", body)
37
+ }
38
+
39
+ /**
40
+ Class constructor with four arguments.
41
+ */
42
+ public func Constructor<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument>(
43
+ _ body: @escaping (A0, A1, A2, A3) throws -> R
44
+ ) -> SyncFunctionComponent<(A0, A1, A2, A3), A0, R> {
45
+ return Function("constructor", body)
46
+ }
47
+
48
+ /**
49
+ Class constructor with five arguments.
50
+ */
51
+ public func Constructor<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument>(
52
+ _ body: @escaping (A0, A1, A2, A3, A4) throws -> R
53
+ ) -> SyncFunctionComponent<(A0, A1, A2, A3, A4), A0, R> {
54
+ return Function("constructor", body)
55
+ }
56
+
57
+ /**
58
+ Class constructor with six arguments.
59
+ */
60
+ public func Constructor<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument>(
61
+ _ body: @escaping (A0, A1, A2, A3, A4, A5) throws -> R
62
+ ) -> SyncFunctionComponent<(A0, A1, A2, A3, A4, A5), A0, R> {
63
+ return Function("constructor", body)
64
+ }
65
+
66
+ /**
67
+ Creates the component describing a JavaScript class.
68
+ */
69
+ public func Class(
70
+ _ name: String,
71
+ @ClassComponentElementsBuilder<JavaScriptObject> _ elements: () -> [AnyClassComponentElement]
72
+ ) -> ClassComponent {
73
+ return ClassComponent(name: name, associatedType: JavaScriptObject.self, elements: elements())
74
+ }
75
+
76
+ /**
77
+ Creates the component describing a JavaScript class with an associated native shared object class.
78
+ */
79
+ public func Class<SharedObjectType: SharedObject>(
80
+ _ name: String = String(describing: SharedObjectType.self),
81
+ _ sharedObjectType: SharedObjectType.Type,
82
+ @ClassComponentElementsBuilder<SharedObjectType> _ elements: () -> [AnyClassComponentElement]
83
+ ) -> ClassComponent {
84
+ return ClassComponent(name: name, associatedType: SharedObjectType.self, elements: elements())
85
+ }
86
+
87
+ /**
88
+ Creates the component describing a JavaScript class with an associated native shared object class
89
+ and with the name that is inferred from the shared object type.
90
+ */
91
+ public func Class<SharedObjectType: SharedObject>(
92
+ _ sharedObjectType: SharedObjectType.Type,
93
+ @ClassComponentElementsBuilder<SharedObjectType> _ elements: () -> [AnyClassComponentElement]
94
+ ) -> ClassComponent {
95
+ return ClassComponent(name: String(describing: SharedObjectType.self), associatedType: SharedObjectType.self, elements: elements())
96
+ }
@@ -0,0 +1,44 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ A protocol whose intention is to wrap any type
5
+ to keep its real signature and not type-erase it by the compiler.
6
+ */
7
+ public protocol AnyDynamicType: CustomStringConvertible {
8
+ /**
9
+ Checks whether the inner type is the same as the given type.
10
+ */
11
+ func wraps<InnerType>(_ type: InnerType.Type) -> Bool
12
+
13
+ /**
14
+ Checks whether the dynamic type is equal to another,
15
+ that is when the type of the dynamic types are equal and their inner types are equal.
16
+ */
17
+ func equals(_ type: AnyDynamicType) -> Bool
18
+
19
+ /**
20
+ Casts given any value to the wrapped type and returns as `Any`.
21
+ NOTE: It may not be just simple type-casting (e.g. when the wrapped type conforms to `ConvertibleArgument`).
22
+ */
23
+ func cast<ValueType>(_ value: ValueType) throws -> Any
24
+ }
25
+
26
+ // MARK: - Operators
27
+
28
+ infix operator ~>
29
+ public func ~> <T>(lhs: AnyDynamicType, rhs: T.Type) -> Bool {
30
+ return lhs.wraps(rhs)
31
+ }
32
+
33
+ infix operator !~>
34
+ public func !~> <T>(lhs: AnyDynamicType, rhs: T.Type) -> Bool {
35
+ return !lhs.wraps(rhs)
36
+ }
37
+
38
+ public func == (lhs: AnyDynamicType, rhs: AnyDynamicType) -> Bool {
39
+ return lhs.equals(rhs)
40
+ }
41
+
42
+ public func != (lhs: AnyDynamicType, rhs: AnyDynamicType) -> Bool {
43
+ return !lhs.equals(rhs)
44
+ }
@@ -0,0 +1,56 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ A dynamic type representing array types. Requires the array's element type
5
+ for the initialization as it delegates casting to that type for each element in the array.
6
+ */
7
+ internal struct DynamicArrayType: AnyDynamicType {
8
+ let elementType: AnyDynamicType
9
+
10
+ func wraps<InnerType>(_ type: InnerType.Type) -> Bool {
11
+ if let ArrayType = InnerType.self as? AnyArray.Type {
12
+ return elementType.equals(ArrayType.getElementDynamicType())
13
+ }
14
+ return false
15
+ }
16
+
17
+ func equals(_ type: AnyDynamicType) -> Bool {
18
+ if let arrayType = type as? Self {
19
+ return arrayType.elementType.equals(elementType)
20
+ }
21
+ return false
22
+ }
23
+
24
+ func cast<ValueType>(_ value: ValueType) throws -> Any {
25
+ if let value = value as? [Any] {
26
+ return try value.map { try elementType.cast($0) }
27
+ }
28
+ // We should probably throw an error if we get here. On the other side, the array type
29
+ // requirement can be more loosen so we can try to arrayize values that are not arrays.
30
+ return [try elementType.cast(value)]
31
+ }
32
+
33
+ var description: String {
34
+ "[\(elementType.description)]"
35
+ }
36
+ }
37
+
38
+ /**
39
+ A type-erased protocol used to recognize if the generic type is an array type.
40
+ `Array` is a generic type, so it's impossible to check the inheritance directly.
41
+ */
42
+ internal protocol AnyArray {
43
+ /**
44
+ Exposes the `Element` generic type wrapped by the dynamic type to preserve its metadata.
45
+ */
46
+ static func getElementDynamicType() -> AnyDynamicType
47
+ }
48
+
49
+ /**
50
+ Extends the `Array` type to expose its generic `Element` as a dynamic type.
51
+ */
52
+ extension Array: AnyArray {
53
+ static func getElementDynamicType() -> AnyDynamicType {
54
+ return DynamicType(Element.self)
55
+ }
56
+ }
@@ -0,0 +1,27 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ A dynamic type that wraps any type conforming to `ConvertibleArgument` protocol.
5
+ */
6
+ internal struct DynamicConvertibleType: AnyDynamicType {
7
+ let innerType: ConvertibleArgument.Type
8
+
9
+ func wraps<InnerType>(_ type: InnerType.Type) -> Bool {
10
+ return innerType == InnerType.self
11
+ }
12
+
13
+ func equals(_ type: AnyDynamicType) -> Bool {
14
+ if let convertibleType = type as? Self {
15
+ return convertibleType.innerType == innerType
16
+ }
17
+ return false
18
+ }
19
+
20
+ func cast<ValueType>(_ value: ValueType) throws -> Any {
21
+ return try innerType.convert(from: value)
22
+ }
23
+
24
+ var description: String {
25
+ String(describing: innerType.self)
26
+ }
27
+ }
@@ -0,0 +1,27 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ A dynamic type representing an enum that conforms to `EnumArgument`.
5
+ */
6
+ internal struct DynamicEnumType: AnyDynamicType {
7
+ let innerType: EnumArgument.Type
8
+
9
+ func wraps<InnerType>(_ type: InnerType.Type) -> Bool {
10
+ return innerType == InnerType.self
11
+ }
12
+
13
+ func equals(_ type: AnyDynamicType) -> Bool {
14
+ if let enumType = type as? Self {
15
+ return enumType.innerType == innerType
16
+ }
17
+ return false
18
+ }
19
+
20
+ func cast<ValueType>(_ value: ValueType) throws -> Any {
21
+ return try innerType.create(fromRawValue: value)
22
+ }
23
+
24
+ var description: String {
25
+ "Enum<\(innerType)>"
26
+ }
27
+ }
@@ -0,0 +1,63 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ A dynamic type that represents an optional type, which allows `nil` to be passed when casting.
5
+ Requires the optional's wrapped type as it delegates casting to that type for non-nil values.
6
+ */
7
+ internal struct DynamicOptionalType: AnyDynamicType {
8
+ let wrappedType: AnyDynamicType
9
+
10
+ func wraps<InnerType>(_ type: InnerType.Type) -> Bool {
11
+ if let OptionalType = InnerType.self as? AnyOptional.Type {
12
+ return wrappedType.equals(OptionalType.getWrappedDynamicType())
13
+ }
14
+ return false
15
+ }
16
+
17
+ func equals(_ type: AnyDynamicType) -> Bool {
18
+ if let optionalType = type as? Self {
19
+ return optionalType.wrappedType.equals(wrappedType)
20
+ }
21
+ return false
22
+ }
23
+
24
+ func cast<ValueType>(_ value: ValueType) throws -> Any {
25
+ if Optional.isNil(value) || value is NSNull {
26
+ return Optional<Any>.none as Any
27
+ }
28
+ return try wrappedType.cast(value)
29
+ }
30
+
31
+ var description: String {
32
+ "\(wrappedType)?"
33
+ }
34
+ }
35
+
36
+ /**
37
+ A type-erased protocol used to recognize if the generic type is an optional type.
38
+ `Optional` is a generic enum, so it's impossible to check the inheritance directly.
39
+ */
40
+ internal protocol AnyOptional {
41
+ /**
42
+ Exposes the `Wrapped` generic type wrapped by the dynamic type to preserve its metadata.`
43
+ */
44
+ static func getWrappedDynamicType() -> AnyDynamicType
45
+ }
46
+
47
+ /**
48
+ Make generic `Optional` implement non-generic `AnyOptional` and add handy check against type-erased `nil`.
49
+ */
50
+ extension Optional: AnyOptional {
51
+ static func getWrappedDynamicType() -> AnyDynamicType {
52
+ return DynamicType(Wrapped.self)
53
+ }
54
+
55
+ static func isNil(_ object: Wrapped) -> Bool {
56
+ switch object as Any {
57
+ case Optional<Any>.none:
58
+ return true
59
+ default:
60
+ return false
61
+ }
62
+ }
63
+ }
@@ -0,0 +1,33 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ A dynamic type that can wrap any type, but it casts only type-compatible values using `as?` keyword.
5
+ The innermost type of the other dynamic types like `ArrayArgumentType` and `OptionalArgumentType`.
6
+ */
7
+ internal struct DynamicRawType<InnerType>: AnyDynamicType {
8
+ let innerType: InnerType.Type
9
+
10
+ func wraps<InnerType>(_ type: InnerType.Type) -> Bool {
11
+ return type == innerType
12
+ }
13
+
14
+ func equals(_ type: AnyDynamicType) -> Bool {
15
+ return type is Self
16
+ }
17
+
18
+ func cast<ValueType>(_ value: ValueType) throws -> Any {
19
+ if let value = value as? InnerType {
20
+ return value
21
+ }
22
+ // Raw types are always non-optional, but they may receive `nil` values.
23
+ // Let's throw more specific error in this case.
24
+ if Optional.isNil(value) {
25
+ throw Conversions.NullCastException<InnerType>()
26
+ }
27
+ throw Conversions.CastingException<InnerType>(value)
28
+ }
29
+
30
+ var description: String {
31
+ String(describing: innerType.self)
32
+ }
33
+ }
@@ -0,0 +1,37 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ /**
4
+ A dynamic type representing the `SharedObject` type and its subclasses.
5
+ */
6
+ internal struct DynamicSharedObjectType: AnyDynamicType {
7
+ let innerType: SharedObject.Type
8
+
9
+ func wraps<InnerType>(_ type: InnerType.Type) -> Bool {
10
+ return innerType == InnerType.self
11
+ }
12
+
13
+ func equals(_ type: AnyDynamicType) -> Bool {
14
+ if let sharedObjectType = type as? Self {
15
+ return sharedObjectType.innerType == innerType
16
+ }
17
+ return false
18
+ }
19
+
20
+ func cast<ValueType>(_ value: ValueType) throws -> Any {
21
+ if let jsObject = try (value as? JavaScriptValue)?.asObject(),
22
+ let nativeSharedObject = SharedObjectRegistry.toNativeObject(jsObject) {
23
+ return nativeSharedObject
24
+ }
25
+ throw NativeSharedObjectNotFoundException()
26
+ }
27
+
28
+ var description: String {
29
+ return "SharedObject<\(innerType)>"
30
+ }
31
+ }
32
+
33
+ internal final class NativeSharedObjectNotFoundException: Exception {
34
+ override var reason: String {
35
+ "Unable to find the native shared object associated with given JavaScript object"
36
+ }
37
+ }
@@ -0,0 +1,39 @@
1
+ // Copyright 2021-present 650 Industries. All rights reserved.
2
+
3
+ // Function names should start with a lowercase character, but in this one case
4
+ // we want it to be uppercase as we treat it more like a generic class.
5
+ // swiftlint:disable identifier_name
6
+
7
+ /**
8
+ Factory creating an instance of the dynamic type wrapper conforming to `AnyDynamicType`.
9
+ Depending on the given type, it may return one of `DynamicArrayType`, `DynamicOptionalType`, `DynamicConvertibleType`, etc.
10
+ */
11
+ internal func DynamicType<T>(_ type: T.Type) -> AnyDynamicType {
12
+ if let ArrayType = T.self as? AnyArray.Type {
13
+ return DynamicArrayType(elementType: ArrayType.getElementDynamicType())
14
+ }
15
+ if let OptionalType = T.self as? AnyOptional.Type {
16
+ return DynamicOptionalType(wrappedType: OptionalType.getWrappedDynamicType())
17
+ }
18
+ if let ConvertibleType = T.self as? ConvertibleArgument.Type {
19
+ return DynamicConvertibleType(innerType: ConvertibleType)
20
+ }
21
+ if let EnumType = T.self as? EnumArgument.Type {
22
+ return DynamicEnumType(innerType: EnumType)
23
+ }
24
+ if let SharedObjectType = T.self as? SharedObject.Type {
25
+ return DynamicSharedObjectType(innerType: SharedObjectType)
26
+ }
27
+ if let TypedArrayType = T.self as? AnyTypedArray.Type {
28
+ return DynamicTypedArrayType(innerType: TypedArrayType)
29
+ }
30
+ return DynamicRawType(innerType: T.self)
31
+ }
32
+
33
+ /**
34
+ Handy prefix operator that makes the dynamic type from the static type.
35
+ */
36
+ prefix operator ~
37
+ public prefix func ~ <T>(type: T.Type) -> AnyDynamicType {
38
+ return DynamicType(type)
39
+ }
@@ -0,0 +1,46 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ internal struct DynamicTypedArrayType: AnyDynamicType {
4
+ let innerType: AnyTypedArray.Type
5
+
6
+ func wraps<InnerType>(_ type: InnerType.Type) -> Bool {
7
+ return innerType == InnerType.self
8
+ }
9
+
10
+ func equals(_ type: AnyDynamicType) -> Bool {
11
+ if let typedArrayType = type as? Self {
12
+ return typedArrayType.innerType == innerType
13
+ }
14
+ return false
15
+ }
16
+
17
+ func cast<ValueType>(_ value: ValueType) throws -> Any {
18
+ // It must be a JavaScript typed array.
19
+ guard let value = value as? JavaScriptValue, let jsTypedArray = value.getTypedArray() else {
20
+ throw NotTypedArrayException(innerType)
21
+ }
22
+ let typedArray = TypedArray.create(from: jsTypedArray)
23
+
24
+ // Concrete typed arrays must be the same as the inner type.
25
+ guard innerType == TypedArray.self || type(of: typedArray) == innerType else {
26
+ throw ArrayTypeMismatchException((received: type(of: typedArray), expected: innerType))
27
+ }
28
+ return typedArray
29
+ }
30
+
31
+ var description: String {
32
+ return String(describing: innerType)
33
+ }
34
+ }
35
+
36
+ internal final class ArrayTypeMismatchException: GenericException<(received: Any.Type, expected: Any.Type)> {
37
+ override var reason: String {
38
+ "Received a typed array of type \(param.received), expected \(param.expected)"
39
+ }
40
+ }
41
+
42
+ internal final class NotTypedArrayException: GenericException<AnyTypedArray.Type> {
43
+ override var reason: String {
44
+ "Given argument is not an instance of \(param)"
45
+ }
46
+ }
@@ -3,7 +3,7 @@ import Foundation
3
3
  /**
4
4
  A protocol for errors specyfing its `code` and providing the `description`.
5
5
  */
6
- public protocol CodedError: Error {
6
+ public protocol CodedError: Error, CustomStringConvertible {
7
7
  var code: String { get }
8
8
  var description: String { get }
9
9
  }