expo-modules-core 1.2.7 → 1.3.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 (180) hide show
  1. package/CHANGELOG.md +28 -5
  2. package/ExpoModulesCore.podspec +1 -0
  3. package/README.md +1 -1
  4. package/android/ExpoModulesCorePlugin.gradle +16 -0
  5. package/android/build.gradle +3 -2
  6. package/android/src/main/cpp/Exceptions.cpp +8 -0
  7. package/android/src/main/cpp/Exceptions.h +11 -0
  8. package/android/src/main/cpp/ExpoModulesHostObject.cpp +22 -5
  9. package/android/src/main/cpp/ExpoModulesHostObject.h +5 -0
  10. package/android/src/main/cpp/JNIInjector.cpp +2 -0
  11. package/android/src/main/cpp/JSIInteropModuleRegistry.cpp +25 -1
  12. package/android/src/main/cpp/JSIInteropModuleRegistry.h +14 -0
  13. package/android/src/main/cpp/JSIObjectWrapper.h +15 -4
  14. package/android/src/main/cpp/JSITypeConverter.h +3 -2
  15. package/android/src/main/cpp/JavaReferencesCache.cpp +2 -0
  16. package/android/src/main/cpp/JavaScriptFunction.cpp +56 -0
  17. package/android/src/main/cpp/JavaScriptFunction.h +54 -0
  18. package/android/src/main/cpp/JavaScriptModuleObject.cpp +225 -105
  19. package/android/src/main/cpp/JavaScriptModuleObject.h +67 -34
  20. package/android/src/main/cpp/JavaScriptObject.cpp +55 -1
  21. package/android/src/main/cpp/JavaScriptObject.h +17 -13
  22. package/android/src/main/cpp/JavaScriptRuntime.cpp +12 -3
  23. package/android/src/main/cpp/JavaScriptRuntime.h +9 -1
  24. package/android/src/main/cpp/JavaScriptValue.cpp +9 -0
  25. package/android/src/main/cpp/JavaScriptValue.h +4 -0
  26. package/android/src/main/cpp/MethodMetadata.cpp +66 -87
  27. package/android/src/main/cpp/MethodMetadata.h +18 -16
  28. package/android/src/main/cpp/ObjectDeallocator.h +25 -0
  29. package/android/src/main/cpp/WeakRuntimeHolder.cpp +7 -0
  30. package/android/src/main/cpp/WeakRuntimeHolder.h +4 -0
  31. package/android/src/main/cpp/types/CppType.h +4 -1
  32. package/android/src/main/cpp/types/FrontendConverter.cpp +58 -0
  33. package/android/src/main/cpp/types/FrontendConverter.h +45 -0
  34. package/android/src/main/cpp/types/FrontendConverterProvider.cpp +3 -0
  35. package/android/src/main/cpp/types/JNIToJSIConverter.cpp +88 -0
  36. package/android/src/main/cpp/types/JNIToJSIConverter.h +22 -0
  37. package/android/src/main/java/com/facebook/react/uimanager/ReactStylesDiffMapHelper.kt +10 -0
  38. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +8 -25
  39. package/android/src/main/java/expo/modules/kotlin/FilteredIterator.kt +37 -0
  40. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +1 -1
  41. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +30 -23
  42. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +0 -3
  43. package/android/src/main/java/expo/modules/kotlin/Utils.kt +21 -0
  44. package/android/src/main/java/expo/modules/kotlin/activityresult/AppContextActivityResultCaller.kt +21 -1
  45. package/android/src/main/java/expo/modules/kotlin/classcomponent/ClassComponentBuilder.kt +112 -0
  46. package/android/src/main/java/expo/modules/kotlin/classcomponent/ClassDefinitionData.kt +10 -0
  47. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +21 -0
  48. package/android/src/main/java/expo/modules/kotlin/exception/CommonExceptions.kt +15 -0
  49. package/android/src/main/java/expo/modules/kotlin/functions/AnyFunction.kt +17 -3
  50. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +38 -8
  51. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +3 -2
  52. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +3 -2
  53. package/android/src/main/java/expo/modules/kotlin/functions/SuspendFunctionComponent.kt +1 -0
  54. package/android/src/main/java/expo/modules/kotlin/functions/SyncFunctionComponent.kt +18 -11
  55. package/android/src/main/java/expo/modules/kotlin/jni/CppType.kt +4 -1
  56. package/android/src/main/java/expo/modules/kotlin/jni/JNIDeallocator.kt +73 -0
  57. package/android/src/main/java/expo/modules/kotlin/jni/JSIInteropModuleRegistry.kt +28 -2
  58. package/android/src/main/java/expo/modules/kotlin/jni/JavaCallback.kt +8 -1
  59. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptFunction.kt +48 -0
  60. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptModuleObject.kt +40 -3
  61. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptObject.kt +23 -3
  62. package/android/src/main/java/expo/modules/kotlin/jni/JavaScriptValue.kt +26 -1
  63. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +0 -11
  64. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +26 -16
  65. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +3 -1
  66. package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObject.kt +12 -0
  67. package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObjectRegistry.kt +62 -0
  68. package/android/src/main/java/expo/modules/kotlin/sharedobjects/SharedObjectTypeConverter.kt +27 -0
  69. package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +2 -1
  70. package/android/src/main/java/expo/modules/kotlin/types/EitherTypeConverter.kt +7 -6
  71. package/android/src/main/java/expo/modules/kotlin/types/JavaScriptFunctionTypeConverter.kt +22 -0
  72. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +30 -24
  73. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +45 -1
  74. package/android/src/main/java/expo/modules/kotlin/types/TypedArrayTypeConverter.kt +3 -2
  75. package/android/src/main/java/expo/modules/kotlin/views/AnyViewProp.kt +3 -1
  76. package/android/src/main/java/expo/modules/kotlin/views/ConcreteViewProp.kt +3 -3
  77. package/android/src/main/java/expo/modules/kotlin/views/FilteredReadableMap.kt +53 -0
  78. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +25 -5
  79. package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +25 -5
  80. package/android/src/main/java/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +161 -10
  81. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +0 -67
  82. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +6 -7
  83. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +40 -3
  84. package/android/src/main/java/expo/modules/kotlin/views/ViewTypeConverter.kt +44 -0
  85. package/android-annotation/build.gradle +45 -0
  86. package/android-annotation/src/main/java/expo/modules/annotation/Config.kt +7 -0
  87. package/android-annotation/src/main/java/expo/modules/annotation/ConverterBinder.kt +7 -0
  88. package/android-annotation-processor/build.gradle +51 -0
  89. package/android-annotation-processor/src/main/java/expo/modules/annotationprocessor/ExpoSymbolProcessor.kt +175 -0
  90. package/android-annotation-processor/src/main/java/expo/modules/annotationprocessor/ExpoSymbolProcessorProvider.kt +10 -0
  91. package/android-annotation-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider +1 -0
  92. package/build/NativeViewManagerAdapter.native.d.ts.map +1 -1
  93. package/build/NativeViewManagerAdapter.native.js +36 -23
  94. package/build/NativeViewManagerAdapter.native.js.map +1 -1
  95. package/build/requireNativeModule.js +2 -2
  96. package/build/requireNativeModule.js.map +1 -1
  97. package/common/cpp/fabric/ExpoViewProps.cpp +18 -3
  98. package/common/cpp/fabric/ExpoViewProps.h +4 -1
  99. package/ios/Fabric/ExpoFabricView.swift +10 -10
  100. package/ios/Fabric/ExpoFabricViewObjC.h +2 -0
  101. package/ios/Fabric/ExpoFabricViewObjC.mm +17 -2
  102. package/ios/JSI/EXJSIInstaller.mm +1 -1
  103. package/ios/JSI/EXJSIUtils.h +5 -0
  104. package/ios/JSI/EXJSIUtils.mm +17 -0
  105. package/ios/JSI/EXJavaScriptRuntime.h +5 -0
  106. package/ios/JSI/EXJavaScriptRuntime.mm +6 -0
  107. package/ios/JSI/EXJavaScriptValue.h +2 -0
  108. package/ios/JSI/EXJavaScriptValue.mm +8 -0
  109. package/ios/JSI/EXJavaScriptWeakObject.mm +29 -8
  110. package/ios/JSI/EXRawJavaScriptFunction.h +24 -0
  111. package/ios/JSI/EXRawJavaScriptFunction.mm +52 -0
  112. package/ios/JSI/ExpoModulesHostObject.mm +1 -1
  113. package/ios/JSI/JavaScriptValue.swift +28 -1
  114. package/ios/ModuleRegistry/EXModuleRegistry.h +0 -4
  115. package/ios/ModuleRegistry/EXModuleRegistry.m +0 -23
  116. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +0 -16
  117. package/ios/ModuleRegistryProvider/EXModuleRegistryProvider.m +0 -6
  118. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +1 -31
  119. package/ios/Swift/AppContext.swift +46 -6
  120. package/ios/Swift/Arguments/Convertible.swift +3 -3
  121. package/ios/Swift/Arguments/Convertibles.swift +5 -5
  122. package/ios/Swift/Classes/ClassComponent.swift +18 -12
  123. package/ios/Swift/Classes/ClassRegistry.swift +31 -0
  124. package/ios/Swift/Conversions.swift +19 -3
  125. package/ios/Swift/Convertibles/Convertibles+Color.swift +3 -3
  126. package/ios/Swift/Convertibles/Either.swift +6 -4
  127. package/ios/Swift/DynamicTypes/AnyDynamicType.swift +18 -2
  128. package/ios/Swift/DynamicTypes/DynamicArrayType.swift +3 -3
  129. package/ios/Swift/DynamicTypes/DynamicConvertibleType.swift +2 -2
  130. package/ios/Swift/DynamicTypes/DynamicEnumType.swift +1 -1
  131. package/ios/Swift/DynamicTypes/DynamicJavaScriptType.swift +27 -0
  132. package/ios/Swift/DynamicTypes/DynamicOptionalType.swift +9 -2
  133. package/ios/Swift/DynamicTypes/DynamicRawType.swift +1 -1
  134. package/ios/Swift/DynamicTypes/DynamicSharedObjectType.swift +16 -2
  135. package/ios/Swift/DynamicTypes/DynamicType.swift +6 -0
  136. package/ios/Swift/DynamicTypes/DynamicTypedArrayType.swift +15 -4
  137. package/ios/Swift/DynamicTypes/DynamicViewType.swift +68 -0
  138. package/ios/Swift/ExpoBridgeModule.swift +1 -1
  139. package/ios/Swift/Functions/AnyFunction.swift +5 -4
  140. package/ios/Swift/Functions/AsyncFunctionComponent.swift +22 -19
  141. package/ios/Swift/Functions/ConcurrentFunctionDefinition.swift +29 -13
  142. package/ios/Swift/Functions/SyncFunctionComponent.swift +26 -15
  143. package/ios/Swift/JavaScriptFunction.swift +68 -0
  144. package/ios/Swift/JavaScriptUtils.swift +57 -18
  145. package/ios/Swift/ModuleHolder.swift +22 -10
  146. package/ios/Swift/Modules/ModuleDefinition.swift +8 -2
  147. package/ios/Swift/Objects/JavaScriptObjectBuilder.swift +8 -8
  148. package/ios/Swift/Objects/ObjectDefinition.swift +17 -15
  149. package/ios/Swift/Objects/PropertyComponent.swift +23 -17
  150. package/ios/Swift/Records/AnyField.swift +1 -1
  151. package/ios/Swift/Records/Field.swift +2 -2
  152. package/ios/Swift/Records/Record.swift +5 -5
  153. package/ios/Swift/SharedObjects/SharedObjectRegistry.swift +4 -0
  154. package/ios/Swift/Views/AnyViewProp.swift +1 -1
  155. package/ios/Swift/Views/ComponentData.swift +37 -2
  156. package/ios/Swift/Views/ConcreteViewProp.swift +2 -2
  157. package/ios/Swift/Views/ViewDefinition.swift +39 -0
  158. package/ios/Swift/Views/ViewModuleWrapper.swift +0 -29
  159. package/ios/Tests/ClassComponentSpec.swift +39 -27
  160. package/ios/Tests/ConvertiblesSpec.swift +75 -49
  161. package/ios/Tests/DynamicTypeSpec.swift +29 -27
  162. package/ios/Tests/EitherSpec.swift +9 -7
  163. package/ios/Tests/ExpoModulesSpec.swift +13 -13
  164. package/ios/Tests/FunctionSpec.swift +38 -22
  165. package/ios/Tests/JavaScriptRuntimeSpec.swift +4 -0
  166. package/ios/Tests/PropertyComponentSpec.swift +33 -30
  167. package/ios/Tests/RecordSpec.swift +7 -5
  168. package/ios/Tests/SharedObjectRegistrySpec.swift +12 -12
  169. package/ios/Tests/TypedArraysSpec.swift +1 -1
  170. package/ios/Tests/ViewDefinitionSpec.swift +4 -2
  171. package/package.json +2 -2
  172. package/src/NativeViewManagerAdapter.native.tsx +33 -29
  173. package/src/requireNativeModule.ts +2 -2
  174. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +0 -132
  175. package/ios/EXViewManager.h +0 -21
  176. package/ios/EXViewManager.m +0 -128
  177. package/ios/ModuleRegistryAdapter/EXViewManagerAdapterClassesRegistry.h +0 -17
  178. package/ios/ModuleRegistryAdapter/EXViewManagerAdapterClassesRegistry.m +0 -67
  179. package/ios/ViewManagerAdapter/EXViewManagerAdapter.h +0 -17
  180. package/ios/ViewManagerAdapter/EXViewManagerAdapter.m +0 -45
@@ -52,14 +52,53 @@ public final class ViewDefinition<ViewType: UIView>: ViewManagerDefinition {
52
52
  public static func buildExpression(_ element: ViewLifecycleMethod<ViewType>) -> AnyViewDefinitionElement {
53
53
  return element
54
54
  }
55
+
56
+ /**
57
+ Accepts functions as a view definition elements.
58
+ */
59
+ public static func buildExpression<ElementType: ViewDefinitionFunctionElement>(
60
+ _ element: ElementType
61
+ ) -> AnyViewDefinitionElement {
62
+ return element
63
+ }
64
+
65
+ /**
66
+ Accepts functions that take the owner as a view definition elements.
67
+ */
68
+ public static func buildExpression<ElementType: ViewDefinitionFunctionElement>(
69
+ _ element: ElementType
70
+ ) -> AnyViewDefinitionElement where ElementType.ViewType == ViewType {
71
+ // Enforce async functions to run on the main queue
72
+ if var function = element as? AnyAsyncFunctionComponent {
73
+ function.runOnQueue(.main)
74
+ function.takesOwner = true
75
+ }
76
+ return element
77
+ }
55
78
  }
56
79
  }
57
80
 
81
+ // MARK: - AnyViewDefinitionElement
82
+
58
83
  public protocol AnyViewDefinitionElement: AnyDefinition {}
59
84
  extension ConcreteViewProp: AnyViewDefinitionElement {}
60
85
  extension EventsDefinition: AnyViewDefinitionElement {}
61
86
  extension ViewLifecycleMethod: AnyViewDefinitionElement {}
62
87
 
88
+ // MARK: - ViewDefinitionFunctionElement
89
+
90
+ public protocol ViewDefinitionFunctionElement: AnyViewDefinitionElement {
91
+ associatedtype ViewType
92
+ }
93
+ extension AsyncFunctionComponent: ViewDefinitionFunctionElement {
94
+ public typealias ViewType = FirstArgType
95
+ }
96
+ extension ConcurrentFunctionDefinition: ViewDefinitionFunctionElement {
97
+ public typealias ViewType = FirstArgType
98
+ }
99
+
100
+ extension UIView: AnyArgument {}
101
+
63
102
  /**
64
103
  Creates a view definition describing the native view exported to React.
65
104
  */
@@ -91,35 +91,6 @@ public final class ViewModuleWrapper: RCTViewManager, DynamicModuleWrapperProtoc
91
91
  return view
92
92
  }
93
93
 
94
- /**
95
- The config for `proxiedProperties` prop. In Objective-C style, this function is generated by `RCT_CUSTOM_VIEW_PROPERTY` macro.
96
- */
97
- @objc
98
- public class func propConfig_proxiedProperties() -> [String] {
99
- return ["NSDictionary", "__custom__"]
100
- }
101
-
102
- /**
103
- The setter for `proxiedProperties` prop. In Objective-C style, this function is generated by `RCT_CUSTOM_VIEW_PROPERTY` macro.
104
- */
105
- @objc
106
- public func set_proxiedProperties(_ json: Any, forView view: UIView, withDefaultView defaultView: UIView) {
107
- guard let json = json as? [String: Any], let viewManager = wrappedModuleHolder.definition.viewManager else {
108
- return
109
- }
110
- let props = viewManager.propsDict()
111
-
112
- for (key, prop) in props {
113
- let newValue = json[key] as Any
114
-
115
- // TODO: @tsapeta: Figure out better way to rethrow errors from here.
116
- // Adding `throws` keyword to the function results in different
117
- // method signature in Objective-C. Maybe just call `RCTLogError`?
118
- try? prop.set(value: Conversions.fromNSObject(newValue), onView: view)
119
- }
120
- viewManager.callLifecycleMethods(withType: .didUpdateProps, forView: view)
121
- }
122
-
123
94
  public static let viewManagerAdapterPrefix = "ViewManagerAdapter_"
124
95
 
125
96
  /**
@@ -32,9 +32,9 @@ class ClassComponentSpec: ExpoSpec {
32
32
  }
33
33
 
34
34
  it("builds a class") {
35
- let runtime = JavaScriptRuntime()
35
+ let appContext = AppContext.create()
36
36
  let klass = Class("") {}
37
- let object = klass.build(inRuntime: runtime)
37
+ let object = try klass.build(appContext: appContext)
38
38
 
39
39
  expect(object.hasProperty("prototype")) == true
40
40
  expect(object.getProperty("prototype").kind) == .object
@@ -43,7 +43,7 @@ class ClassComponentSpec: ExpoSpec {
43
43
 
44
44
  describe("module") {
45
45
  let appContext = AppContext.create()
46
- let runtime = appContext.runtime
46
+ let runtime = try! appContext.runtime
47
47
 
48
48
  beforeSuite {
49
49
  class ClassTestModule: Module {
@@ -67,72 +67,72 @@ class ClassComponentSpec: ExpoSpec {
67
67
  }
68
68
 
69
69
  it("is a function") {
70
- let klass = try runtime?.eval("expo.modules.ClassTest.MyClass")
71
- expect(klass?.isFunction()) == true
70
+ let klass = try runtime.eval("expo.modules.ClassTest.MyClass")
71
+ expect(klass.isFunction()) == true
72
72
  }
73
73
 
74
74
  it("has a name") {
75
- let klass = try runtime?.eval("expo.modules.ClassTest.MyClass.name")
76
- expect(klass?.getString()) == "MyClass"
75
+ let klass = try runtime.eval("expo.modules.ClassTest.MyClass.name")
76
+ expect(klass.getString()) == "MyClass"
77
77
  }
78
78
 
79
79
  it("has a prototype") {
80
- let prototype = try runtime?.eval("expo.modules.ClassTest.MyClass.prototype")
81
- expect(prototype?.isObject()) == true
80
+ let prototype = try runtime.eval("expo.modules.ClassTest.MyClass.prototype")
81
+ expect(prototype.isObject()) == true
82
82
  }
83
83
 
84
84
  it("has keys in prototype") {
85
- let prototypeKeys = try runtime?.eval("Object.keys(expo.modules.ClassTest.MyClass.prototype)")
85
+ let prototypeKeys = try runtime.eval("Object.keys(expo.modules.ClassTest.MyClass.prototype)")
86
86
  .getArray()
87
- .map { $0.getString() } ?? []
87
+ .map { $0.getString() }
88
88
 
89
89
  expect(prototypeKeys).to(contain("myFunction"))
90
90
  expect(prototypeKeys).notTo(contain("__native_constructor__"))
91
91
  }
92
92
 
93
93
  it("is an instance of") {
94
- let isInstanceOf = try runtime?.eval([
94
+ let isInstanceOf = try runtime.eval([
95
95
  "myObject = new expo.modules.ClassTest.MyClass()",
96
96
  "myObject instanceof expo.modules.ClassTest.MyClass",
97
97
  ])
98
98
 
99
- expect(isInstanceOf?.getBool()) == true
99
+ expect(isInstanceOf.getBool()) == true
100
100
  }
101
101
 
102
102
  it("defines properties on initialization") {
103
103
  // The properties are not specified in the prototype, but defined during initialization.
104
- let object = try runtime?.eval("new expo.modules.ClassTest.MyClass()").asObject()
105
- expect(object?.getPropertyNames()).to(contain("foo"))
106
- expect(object?.getProperty("foo").getString()) == "bar"
104
+ let object = try runtime.eval("new expo.modules.ClassTest.MyClass()").asObject()
105
+ expect(object.getPropertyNames()).to(contain("foo"))
106
+ expect(object.getProperty("foo").getString()) == "bar"
107
107
  }
108
108
  }
109
109
 
110
110
  describe("class with associated type") {
111
111
  let appContext = AppContext.create()
112
- let runtime = appContext.runtime
112
+ let runtime = try! appContext.runtime
113
113
 
114
114
  beforeSuite {
115
115
  appContext.moduleRegistry.register(moduleType: ModuleWithCounterClass.self)
116
116
  }
117
117
  it("is defined") {
118
- let isDefined = try! runtime!.eval("'Counter' in expo.modules.TestModule")
118
+ let isDefined = try runtime.eval("'Counter' in expo.modules.TestModule")
119
119
 
120
120
  expect(isDefined.getBool()) == true
121
121
  }
122
122
  it("creates shared object") {
123
- let jsObject = try! runtime!.eval("new expo.modules.TestModule.Counter(0)").getObject()
123
+ let jsObject = try runtime.eval("new expo.modules.TestModule.Counter(0)").getObject()
124
124
  let nativeObject = SharedObjectRegistry.toNativeObject(jsObject)
125
125
 
126
126
  expect(nativeObject).notTo(beNil())
127
127
  }
128
128
  it("registers shared object") {
129
129
  let oldSize = SharedObjectRegistry.size
130
- try! runtime?.eval("object = new expo.modules.TestModule.Counter(0)")
130
+ try runtime.eval("object = new expo.modules.TestModule.Counter(0)")
131
131
 
132
132
  expect(SharedObjectRegistry.size) == oldSize + 1
133
133
  }
134
134
  it("calls function with owner") {
135
- try runtime?.eval([
135
+ try runtime.eval([
136
136
  "object = new expo.modules.TestModule.Counter(0)",
137
137
  "object.increment(1)",
138
138
  ])
@@ -140,7 +140,7 @@ class ClassComponentSpec: ExpoSpec {
140
140
  }
141
141
  it("creates with initial value") {
142
142
  let initialValue = Int.random(in: 1..<100)
143
- let value = try runtime!.eval([
143
+ let value = try runtime.eval([
144
144
  "object = new expo.modules.TestModule.Counter(\(initialValue))",
145
145
  "object.getValue()",
146
146
  ])
@@ -149,7 +149,7 @@ class ClassComponentSpec: ExpoSpec {
149
149
  expect(value.getInt()) == initialValue
150
150
  }
151
151
  it("gets shared object value") {
152
- let value = try runtime!.eval([
152
+ let value = try runtime.eval([
153
153
  "object = new expo.modules.TestModule.Counter(0)",
154
154
  "object.getValue()",
155
155
  ])
@@ -158,10 +158,10 @@ class ClassComponentSpec: ExpoSpec {
158
158
  expect(value.isNumber()) == true
159
159
  }
160
160
  it("changes shared object") {
161
- try! runtime?.eval("object = new expo.modules.TestModule.Counter(0)")
161
+ try runtime.eval("object = new expo.modules.TestModule.Counter(0)")
162
162
  let incrementBy = Int.random(in: 1..<100)
163
- let value = try runtime!.eval("object.getValue()").asInt()
164
- let newValue = try runtime!.eval([
163
+ let value = try runtime.eval("object.getValue()").asInt()
164
+ let newValue = try runtime.eval([
165
165
  "object.increment(\(incrementBy))",
166
166
  "object.getValue()",
167
167
  ])
@@ -172,7 +172,7 @@ class ClassComponentSpec: ExpoSpec {
172
172
 
173
173
  it("gets value from the dynamic property") {
174
174
  let initialValue = Int.random(in: 1..<100)
175
- let value = try runtime!.eval([
175
+ let value = try runtime.eval([
176
176
  "object = new expo.modules.TestModule.Counter(\(initialValue))",
177
177
  "object.currentValue"
178
178
  ])
@@ -180,6 +180,14 @@ class ClassComponentSpec: ExpoSpec {
180
180
  expect(value.kind) == .number
181
181
  expect(value.getInt()) == initialValue
182
182
  }
183
+
184
+ it("initializes the shared object from native") {
185
+ let initialValue = Int.random(in: 1..<100)
186
+ let value = try runtime.eval("expo.modules.TestModule.newCounter(\(initialValue))")
187
+
188
+ expect(value.kind) == .object
189
+ expect(value.getObject().getProperty("currentValue").getInt()) == initialValue
190
+ }
183
191
  }
184
192
  }
185
193
  }
@@ -191,6 +199,10 @@ fileprivate final class ModuleWithCounterClass: Module {
191
199
  func definition() -> ModuleDefinition {
192
200
  Name("TestModule")
193
201
 
202
+ Function("newCounter") { (initialValue: Int) in
203
+ return Counter(initialValue: initialValue)
204
+ }
205
+
194
206
  Class(Counter.self) {
195
207
  Constructor { (initialValue: Int) in
196
208
  return Counter(initialValue: initialValue)
@@ -7,10 +7,12 @@ import ExpoModulesTestCore
7
7
 
8
8
  class ConvertiblesSpec: ExpoSpec {
9
9
  override func spec() {
10
+ let appContext = AppContext.create()
11
+
10
12
  describe("URL") {
11
13
  it("converts from remote url") {
12
14
  let remoteUrlString = "https://expo.dev"
13
- let url = try URL.convert(from: remoteUrlString)
15
+ let url = try URL.convert(from: remoteUrlString, appContext: appContext)
14
16
 
15
17
  expect(url.path) == ""
16
18
  expect(url.absoluteString) == remoteUrlString
@@ -19,7 +21,7 @@ class ConvertiblesSpec: ExpoSpec {
19
21
  it("converts from url with unencoded query") {
20
22
  let query = "param=🥓"
21
23
  let urlString = "https://expo.dev/?\(query)"
22
- let url = try URL.convert(from: urlString)
24
+ let url = try URL.convert(from: urlString, appContext: appContext)
23
25
 
24
26
  if #available(iOS 16.0, *) {
25
27
  expect(url.query(percentEncoded: true)) == "param=%F0%9F%A5%93"
@@ -33,7 +35,7 @@ class ConvertiblesSpec: ExpoSpec {
33
35
  it("converts from url with encoded query") {
34
36
  let query = "param=%F0%9F%A5%93"
35
37
  let urlString = "https://expo.dev/?\(query)"
36
- let url = try URL.convert(from: urlString)
38
+ let url = try URL.convert(from: urlString, appContext: appContext)
37
39
 
38
40
  if #available(iOS 16.0, *) {
39
41
  expect(url.query(percentEncoded: true)) == query
@@ -47,7 +49,7 @@ class ConvertiblesSpec: ExpoSpec {
47
49
  it("converts from url with encoded query containg the anchor") {
48
50
  let query = "color=%230000ff"
49
51
  let urlString = "https://expo.dev/?\(query)#anchor"
50
- let url = try URL.convert(from: urlString)
52
+ let url = try URL.convert(from: urlString, appContext: appContext)
51
53
 
52
54
  expect(url.query) == query
53
55
  expect(url.absoluteString) == urlString
@@ -58,7 +60,7 @@ class ConvertiblesSpec: ExpoSpec {
58
60
  it("converts from url with encoded path") {
59
61
  let path = "/expo/%2F%25%3F%5E%26/test" // -> /expo//%?^&/test
60
62
  let urlString = "https://expo.dev\(path)"
61
- let url = try URL.convert(from: urlString)
63
+ let url = try URL.convert(from: urlString, appContext: appContext)
62
64
 
63
65
  expect(url.absoluteString) == urlString
64
66
  expect(url.path) == path.removingPercentEncoding
@@ -73,7 +75,7 @@ class ConvertiblesSpec: ExpoSpec {
73
75
  // The percent character alone must be percent-encoded to `%25` beforehand, otherwise it should throw an exception.
74
76
  let urlString = "https://expo.dev/?param=%"
75
77
 
76
- expect({ try URL.convert(from: urlString) }).to(throwError(errorType: UrlContainsInvalidCharactersException.self))
78
+ expect({ try URL.convert(from: urlString, appContext: appContext) }).to(throwError(errorType: UrlContainsInvalidCharactersException.self))
77
79
  }
78
80
 
79
81
  it("converts from url containing the anchor") {
@@ -82,7 +84,7 @@ class ConvertiblesSpec: ExpoSpec {
82
84
  // thus it cannot be percent-encoded.
83
85
  let query = "param=#expo"
84
86
  let urlString = "https://expo.dev/?\(query)"
85
- let url = try URL.convert(from: urlString)
87
+ let url = try URL.convert(from: urlString, appContext: appContext)
86
88
 
87
89
  expect(url.query) == "param="
88
90
  expect(url.fragment) == "expo"
@@ -91,7 +93,7 @@ class ConvertiblesSpec: ExpoSpec {
91
93
 
92
94
  it("converts from file url") {
93
95
  let fileUrlString = "file:///expo/tmp"
94
- let url = try URL.convert(from: fileUrlString)
96
+ let url = try URL.convert(from: fileUrlString, appContext: appContext)
95
97
 
96
98
  expect(url.path) == "/expo/tmp"
97
99
  expect(url.absoluteString) == fileUrlString
@@ -100,7 +102,7 @@ class ConvertiblesSpec: ExpoSpec {
100
102
 
101
103
  it("converts from file path") {
102
104
  let filePath = "/expo/image.png"
103
- let url = try URL.convert(from: filePath)
105
+ let url = try URL.convert(from: filePath, appContext: appContext)
104
106
 
105
107
  expect(url.scheme) == "file"
106
108
  expect(url.path) == filePath
@@ -110,7 +112,7 @@ class ConvertiblesSpec: ExpoSpec {
110
112
 
111
113
  it("converts from file path with UTF8 characters") {
112
114
  let filePath = "/中文ÅÄÖąÓśĆñ.gif"
113
- let url = try URL.convert(from: filePath)
115
+ let url = try URL.convert(from: filePath, appContext: appContext)
114
116
 
115
117
  expect(url.scheme) == "file"
116
118
  expect(url.path) == filePath
@@ -119,7 +121,7 @@ class ConvertiblesSpec: ExpoSpec {
119
121
 
120
122
  it("converts from file path containing percent character") {
121
123
  let filePath = "/%.png"
122
- let url = try URL.convert(from: filePath)
124
+ let url = try URL.convert(from: filePath, appContext: appContext)
123
125
 
124
126
  expect(url.scheme) == "file"
125
127
  expect(url.path) == filePath
@@ -127,7 +129,7 @@ class ConvertiblesSpec: ExpoSpec {
127
129
  }
128
130
 
129
131
  it("throws when no string") {
130
- expect { try URL.convert(from: 29.5) }.to(
132
+ expect { try URL.convert(from: 29.5, appContext: appContext) }.to(
131
133
  throwError(errorType: Conversions.ConvertingException<URL>.self)
132
134
  )
133
135
  }
@@ -138,34 +140,40 @@ class ConvertiblesSpec: ExpoSpec {
138
140
  let y = 4.6
139
141
 
140
142
  it("converts from array of doubles") {
141
- let point = try CGPoint.convert(from: [x, y])
143
+ let point = try CGPoint.convert(from: [x, y], appContext: appContext)
142
144
 
143
145
  expect(point.x) == x
144
146
  expect(point.y) == y
145
147
  }
146
148
 
147
149
  it("converts from dict") {
148
- let point = try CGPoint.convert(from: ["x": x, "y": y])
150
+ let point = try CGPoint.convert(from: ["x": x, "y": y], appContext: appContext)
149
151
 
150
152
  expect(point.x) == x
151
153
  expect(point.y) == y
152
154
  }
153
155
 
154
156
  it("throws when array size is unexpected") { // different than two
155
- expect { try CGPoint.convert(from: []) }.to(throwError(errorType: Conversions.ConvertingException<CGPoint>.self))
156
- expect { try CGPoint.convert(from: [x]) }.to(throwError(errorType: Conversions.ConvertingException<CGPoint>.self))
157
- expect { try CGPoint.convert(from: [x, y, x]) }.to(throwError(errorType: Conversions.ConvertingException<CGPoint>.self))
157
+ expect { try CGPoint.convert(from: [], appContext: appContext) }.to(
158
+ throwError(errorType: Conversions.ConvertingException<CGPoint>.self)
159
+ )
160
+ expect { try CGPoint.convert(from: [x], appContext: appContext) }.to(
161
+ throwError(errorType: Conversions.ConvertingException<CGPoint>.self)
162
+ )
163
+ expect { try CGPoint.convert(from: [x, y, x], appContext: appContext) }.to(
164
+ throwError(errorType: Conversions.ConvertingException<CGPoint>.self)
165
+ )
158
166
  }
159
167
 
160
168
  it("throws when dict is missing some keys") {
161
- expect { try CGPoint.convert(from: ["test": x]) }.to(throwError {
169
+ expect { try CGPoint.convert(from: ["test": x], appContext: appContext) }.to(throwError {
162
170
  expect($0).to(beAKindOf(Conversions.MissingKeysException<Double>.self))
163
171
  expect(($0 as! CodedError).description) == Conversions.MissingKeysException<Double>(["x", "y"]).description
164
172
  })
165
173
  }
166
174
 
167
175
  it("throws when dict has uncastable keys") {
168
- expect { try CGPoint.convert(from: ["x": x, "y": "string"]) }.to(throwError {
176
+ expect { try CGPoint.convert(from: ["x": x, "y": "string"], appContext: appContext) }.to(throwError {
169
177
  expect($0).to(beAKindOf(Conversions.CastingValuesException<Double>.self))
170
178
  expect(($0 as! CodedError).description) == Conversions.CastingValuesException<Double>(["y"]).description
171
179
  })
@@ -177,34 +185,40 @@ class ConvertiblesSpec: ExpoSpec {
177
185
  let height = 81.7
178
186
 
179
187
  it("converts from array of doubles") {
180
- let size = try CGSize.convert(from: [width, height])
188
+ let size = try CGSize.convert(from: [width, height], appContext: appContext)
181
189
 
182
190
  expect(size.width) == width
183
191
  expect(size.height) == height
184
192
  }
185
193
 
186
194
  it("converts from dict") {
187
- let size = try CGSize.convert(from: ["width": width, "height": height])
195
+ let size = try CGSize.convert(from: ["width": width, "height": height], appContext: appContext)
188
196
 
189
197
  expect(size.width) == width
190
198
  expect(size.height) == height
191
199
  }
192
200
 
193
201
  it("throws when array size is unexpected") { // different than two
194
- expect { try CGSize.convert(from: []) }.to(throwError(errorType: Conversions.ConvertingException<CGSize>.self))
195
- expect { try CGSize.convert(from: [width]) }.to(throwError(errorType: Conversions.ConvertingException<CGSize>.self))
196
- expect { try CGSize.convert(from: [width, height, width]) }.to(throwError(errorType: Conversions.ConvertingException<CGSize>.self))
202
+ expect { try CGSize.convert(from: [], appContext: appContext) }.to(
203
+ throwError(errorType: Conversions.ConvertingException<CGSize>.self)
204
+ )
205
+ expect { try CGSize.convert(from: [width], appContext: appContext) }.to(
206
+ throwError(errorType: Conversions.ConvertingException<CGSize>.self)
207
+ )
208
+ expect { try CGSize.convert(from: [width, height, width], appContext: appContext) }.to(
209
+ throwError(errorType: Conversions.ConvertingException<CGSize>.self)
210
+ )
197
211
  }
198
212
 
199
213
  it("throws when dict is missing some keys") {
200
- expect { try CGSize.convert(from: ["width": width]) }.to(throwError {
214
+ expect { try CGSize.convert(from: ["width": width], appContext: appContext) }.to(throwError {
201
215
  expect($0).to(beAKindOf(Conversions.MissingKeysException<Double>.self))
202
216
  expect(($0 as! CodedError).description) == Conversions.MissingKeysException<Double>(["height"]).description
203
217
  })
204
218
  }
205
219
 
206
220
  it("throws when dict has uncastable keys") {
207
- expect { try CGSize.convert(from: ["width": "test", "height": height]) }.to(throwError {
221
+ expect { try CGSize.convert(from: ["width": "test", "height": height], appContext: appContext) }.to(throwError {
208
222
  expect($0).to(beAKindOf(Conversions.CastingValuesException<Double>.self))
209
223
  expect(($0 as! CodedError).description) == Conversions.CastingValuesException<Double>(["width"]).description
210
224
  })
@@ -216,34 +230,40 @@ class ConvertiblesSpec: ExpoSpec {
216
230
  let dy = -4.0
217
231
 
218
232
  it("converts from array of doubles") {
219
- let vector = try CGVector.convert(from: [dx, dy])
233
+ let vector = try CGVector.convert(from: [dx, dy], appContext: appContext)
220
234
 
221
235
  expect(vector.dx) == dx
222
236
  expect(vector.dy) == dy
223
237
  }
224
238
 
225
239
  it("converts from dict") {
226
- let vector = try CGVector.convert(from: ["dx": dx, "dy": dy])
240
+ let vector = try CGVector.convert(from: ["dx": dx, "dy": dy], appContext: appContext)
227
241
 
228
242
  expect(vector.dx) == dx
229
243
  expect(vector.dy) == dy
230
244
  }
231
245
 
232
246
  it("throws when array size is unexpected") { // different than two
233
- expect { try CGVector.convert(from: []) }.to(throwError(errorType: Conversions.ConvertingException<CGVector>.self))
234
- expect { try CGVector.convert(from: [dx]) }.to(throwError(errorType: Conversions.ConvertingException<CGVector>.self))
235
- expect { try CGVector.convert(from: [dx, dy, dx]) }.to(throwError(errorType: Conversions.ConvertingException<CGVector>.self))
247
+ expect { try CGVector.convert(from: [], appContext: appContext) }.to(
248
+ throwError(errorType: Conversions.ConvertingException<CGVector>.self)
249
+ )
250
+ expect { try CGVector.convert(from: [dx], appContext: appContext) }.to(
251
+ throwError(errorType: Conversions.ConvertingException<CGVector>.self)
252
+ )
253
+ expect { try CGVector.convert(from: [dx, dy, dx], appContext: appContext) }.to(
254
+ throwError(errorType: Conversions.ConvertingException<CGVector>.self)
255
+ )
236
256
  }
237
257
 
238
258
  it("throws when dict is missing some keys") {
239
- expect { try CGVector.convert(from: ["dx": dx]) }.to(throwError {
259
+ expect { try CGVector.convert(from: ["dx": dx], appContext: appContext) }.to(throwError {
240
260
  expect($0).to(beAKindOf(Conversions.MissingKeysException<Double>.self))
241
261
  expect(($0 as! CodedError).description) == Conversions.MissingKeysException<Double>(["dy"]).description
242
262
  })
243
263
  }
244
264
 
245
265
  it("throws when dict has uncastable keys") {
246
- expect { try CGVector.convert(from: ["dx": "dx", "dy": dy]) }.to(throwError {
266
+ expect { try CGVector.convert(from: ["dx": "dx", "dy": dy], appContext: appContext) }.to(throwError {
247
267
  expect($0).to(beAKindOf(Conversions.CastingValuesException<Double>.self))
248
268
  expect(($0 as! CodedError).description) == Conversions.CastingValuesException<Double>(["dx"]).description
249
269
  })
@@ -257,7 +277,7 @@ class ConvertiblesSpec: ExpoSpec {
257
277
  let height = 81.7
258
278
 
259
279
  it("converts from array of doubles") {
260
- let rect = try CGRect.convert(from: [x, y, width, height])
280
+ let rect = try CGRect.convert(from: [x, y, width, height], appContext: appContext)
261
281
 
262
282
  expect(rect.origin.x) == x
263
283
  expect(rect.origin.y) == y
@@ -266,7 +286,7 @@ class ConvertiblesSpec: ExpoSpec {
266
286
  }
267
287
 
268
288
  it("converts from dict") {
269
- let rect = try CGRect.convert(from: ["x": x, "y": y, "width": width, "height": height])
289
+ let rect = try CGRect.convert(from: ["x": x, "y": y, "width": width, "height": height], appContext: appContext)
270
290
 
271
291
  expect(rect.origin.x) == x
272
292
  expect(rect.origin.y) == y
@@ -275,20 +295,26 @@ class ConvertiblesSpec: ExpoSpec {
275
295
  }
276
296
 
277
297
  it("throws when array size is unexpected") { // different than four
278
- expect { try CGRect.convert(from: [x]) }.to(throwError(errorType: Conversions.ConvertingException<CGRect>.self))
279
- expect { try CGRect.convert(from: [x, y]) }.to(throwError(errorType: Conversions.ConvertingException<CGRect>.self))
280
- expect { try CGRect.convert(from: [x, y, width, height, y]) }.to(throwError(errorType: Conversions.ConvertingException<CGRect>.self))
298
+ expect { try CGRect.convert(from: [x], appContext: appContext) }.to(
299
+ throwError(errorType: Conversions.ConvertingException<CGRect>.self)
300
+ )
301
+ expect { try CGRect.convert(from: [x, y], appContext: appContext) }.to(
302
+ throwError(errorType: Conversions.ConvertingException<CGRect>.self)
303
+ )
304
+ expect { try CGRect.convert(from: [x, y, width, height, y], appContext: appContext) }.to(
305
+ throwError(errorType: Conversions.ConvertingException<CGRect>.self)
306
+ )
281
307
  }
282
308
 
283
309
  it("throws when dict is missing some keys") {
284
- expect { try CGRect.convert(from: ["x": x]) }.to(throwError {
310
+ expect { try CGRect.convert(from: ["x": x], appContext: appContext) }.to(throwError {
285
311
  expect($0).to(beAKindOf(Conversions.MissingKeysException<Double>.self))
286
312
  expect(($0 as! CodedError).description) == Conversions.MissingKeysException<Double>(["y", "width", "height"]).description
287
313
  })
288
314
  }
289
315
 
290
316
  it("throws when dict has uncastable keys") {
291
- expect { try CGRect.convert(from: ["x": x, "y": nil, "width": width, "height": "\(height)"]) }.to(throwError {
317
+ expect { try CGRect.convert(from: ["x": x, "y": nil, "width": width, "height": "\(height)"], appContext: appContext) }.to(throwError {
292
318
  expect($0).to(beAKindOf(Conversions.CastingValuesException<Double>.self))
293
319
  expect(($0 as! CodedError).description) == Conversions.CastingValuesException<Double>(["y", "height"]).description
294
320
  })
@@ -303,7 +329,7 @@ class ConvertiblesSpec: ExpoSpec {
303
329
  expect(color.components?[3]) == alpha / 255.0
304
330
  }
305
331
  func testInvalidHexColor(_ hex: String) {
306
- expect { try CGColor.convert(from: hex) }.to(throwError {
332
+ expect { try CGColor.convert(from: hex, appContext: appContext) }.to(throwError {
307
333
  expect($0).to(beAKindOf(Conversions.InvalidHexColorException.self))
308
334
  expect(($0 as! CodedError).description) == Conversions.InvalidHexColorException(hex).description
309
335
  })
@@ -311,37 +337,37 @@ class ConvertiblesSpec: ExpoSpec {
311
337
 
312
338
  it("converts from ARGB int") {
313
339
  // NOTE: int representation has alpha channel at the beginning
314
- let color = try CGColor.convert(from: 0x5147AC7F)
340
+ let color = try CGColor.convert(from: 0x5147AC7F, appContext: appContext)
315
341
  testColorComponents(color, 0x47, 0xAC, 0x7F, 0x51)
316
342
  }
317
343
 
318
344
  it("converts from RGBA hex string") {
319
- let color = try CGColor.convert(from: "47AC7F51")
345
+ let color = try CGColor.convert(from: "47AC7F51", appContext: appContext)
320
346
  testColorComponents(color, 0x47, 0xAC, 0x7F, 0x51)
321
347
  }
322
348
 
323
349
  it("converts from #RGBA hex string") {
324
- let color = try CGColor.convert(from: " #47AC7F51")
350
+ let color = try CGColor.convert(from: " #47AC7F51", appContext: appContext)
325
351
  testColorComponents(color, 0x47, 0xAC, 0x7F, 0x51)
326
352
  }
327
353
 
328
354
  it("converts from 3-character shorthand hex string") {
329
- let color = try CGColor.convert(from: "C2B ")
355
+ let color = try CGColor.convert(from: "C2B ", appContext: appContext)
330
356
  testColorComponents(color, 0xCC, 0x22, 0xBB, 0xFF)
331
357
  }
332
358
 
333
359
  it("converts from 4-character shorthand hex string") {
334
- let color = try CGColor.convert(from: " #9EA5 ")
360
+ let color = try CGColor.convert(from: " #9EA5 ", appContext: appContext)
335
361
  testColorComponents(color, 0x99, 0xEE, 0xAA, 0x55)
336
362
  }
337
363
 
338
364
  it("converts from CSS named color") {
339
- let papayawhip = try CGColor.convert(from: "papayawhip")
365
+ let papayawhip = try CGColor.convert(from: "papayawhip", appContext: appContext)
340
366
  testColorComponents(papayawhip, 0xFF, 0xEF, 0xD5, 0xFF)
341
367
  }
342
368
 
343
369
  it("converts from transparent") {
344
- let transparent = try CGColor.convert(from: "transparent")
370
+ let transparent = try CGColor.convert(from: "transparent", appContext: appContext)
345
371
  expect(transparent.alpha) == .zero
346
372
  }
347
373
 
@@ -356,7 +382,7 @@ class ConvertiblesSpec: ExpoSpec {
356
382
 
357
383
  it("throws when int overflows") {
358
384
  let hex = 0xBBAA88FF2
359
- expect { try CGColor.convert(from: hex) }.to(throwError {
385
+ expect { try CGColor.convert(from: hex, appContext: appContext) }.to(throwError {
360
386
  expect($0).to(beAKindOf(Conversions.HexColorOverflowException.self))
361
387
  expect(($0 as! CodedError).description) == Conversions.HexColorOverflowException(UInt64(hex)).description
362
388
  })