expo-modules-core 0.6.5 → 0.9.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 (219) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/README.md +1 -1
  3. package/android/ExpoModulesCorePlugin.gradle +15 -0
  4. package/android/build.gradle +31 -15
  5. package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +5 -5
  6. package/android/src/main/java/expo/modules/adapters/react/services/UIManagerModuleWrapper.java +13 -0
  7. package/android/src/main/java/expo/modules/core/ViewManager.java +9 -0
  8. package/android/src/main/java/expo/modules/core/interfaces/JavaScriptContextProvider.java +4 -0
  9. package/android/src/main/java/expo/modules/core/interfaces/ReactActivityHandler.java +37 -1
  10. package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.java +30 -0
  11. package/android/src/main/java/expo/modules/core/interfaces/services/UIManager.java +2 -0
  12. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +23 -5
  13. package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +5 -3
  14. package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +3 -8
  15. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +24 -9
  16. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +12 -7
  17. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +23 -1
  18. package/android/src/main/java/expo/modules/kotlin/Promise.kt +1 -1
  19. package/android/src/main/java/expo/modules/kotlin/callbacks/Callback.kt +5 -0
  20. package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallback.kt +39 -0
  21. package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallbackDelegate.kt +27 -0
  22. package/android/src/main/java/expo/modules/kotlin/defaultmodules/ErrorManagerModule.kt +25 -0
  23. package/android/src/main/java/expo/modules/kotlin/events/EventEmitter.kt +13 -0
  24. package/android/src/main/java/expo/modules/kotlin/events/KModuleEventEmitterWrapper.kt +102 -0
  25. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +93 -9
  26. package/android/src/main/java/expo/modules/kotlin/exception/ExceptionDecorator.kt +11 -0
  27. package/android/src/main/java/expo/modules/kotlin/{methods/AnyMethod.kt → functions/AnyFunction.kt} +18 -18
  28. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +15 -0
  29. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +170 -0
  30. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromise.kt +15 -0
  31. package/android/src/main/java/expo/modules/kotlin/functions/AsyncSuspendFunction.kt +36 -0
  32. package/android/src/main/java/expo/modules/kotlin/modules/DefinitionMarker.kt +4 -0
  33. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +17 -2
  34. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +416 -43
  35. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +2 -2
  36. package/android/src/main/java/expo/modules/kotlin/records/FieldValidator.kt +139 -0
  37. package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +71 -15
  38. package/android/src/main/java/expo/modules/kotlin/records/Required.kt +5 -0
  39. package/android/src/main/java/expo/modules/kotlin/records/ValidationBinder.kt +110 -0
  40. package/android/src/main/java/expo/modules/kotlin/records/Validators.kt +61 -0
  41. package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +11 -5
  42. package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverter.kt +35 -0
  43. package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverterHelper.kt +148 -0
  44. package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +10 -4
  45. package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +12 -6
  46. package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +29 -13
  47. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +2 -1
  48. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +9 -1
  49. package/android/src/main/java/expo/modules/kotlin/views/CallbacksDefinition.kt +3 -0
  50. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +71 -0
  51. package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +22 -0
  52. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinition.kt +18 -0
  53. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +114 -0
  54. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +30 -2
  55. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +81 -2
  56. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +62 -2
  57. package/build/EventEmitter.d.ts +1 -0
  58. package/build/EventEmitter.d.ts.map +1 -0
  59. package/build/NativeModulesProxy.d.ts +1 -0
  60. package/build/NativeModulesProxy.d.ts.map +1 -0
  61. package/build/NativeModulesProxy.native.d.ts +1 -4
  62. package/build/NativeModulesProxy.native.d.ts.map +1 -0
  63. package/build/NativeModulesProxy.native.js +1 -14
  64. package/build/NativeModulesProxy.native.js.map +1 -1
  65. package/build/NativeModulesProxy.types.d.ts +1 -3
  66. package/build/NativeModulesProxy.types.d.ts.map +1 -0
  67. package/build/NativeModulesProxy.types.js.map +1 -1
  68. package/build/NativeViewManagerAdapter.d.ts +1 -0
  69. package/build/NativeViewManagerAdapter.d.ts.map +1 -0
  70. package/build/NativeViewManagerAdapter.native.d.ts +1 -0
  71. package/build/NativeViewManagerAdapter.native.d.ts.map +1 -0
  72. package/build/NativeViewManagerAdapter.native.js +9 -33
  73. package/build/NativeViewManagerAdapter.native.js.map +1 -1
  74. package/build/PermissionsHook.d.ts +1 -0
  75. package/build/PermissionsHook.d.ts.map +1 -0
  76. package/build/PermissionsInterface.d.ts +1 -0
  77. package/build/PermissionsInterface.d.ts.map +1 -0
  78. package/build/Platform.d.ts +1 -0
  79. package/build/Platform.d.ts.map +1 -0
  80. package/build/SyntheticPlatformEmitter.d.ts +1 -0
  81. package/build/SyntheticPlatformEmitter.d.ts.map +1 -0
  82. package/build/SyntheticPlatformEmitter.web.d.ts +1 -0
  83. package/build/SyntheticPlatformEmitter.web.d.ts.map +1 -0
  84. package/build/deprecate.d.ts +1 -0
  85. package/build/deprecate.d.ts.map +1 -0
  86. package/build/environment/browser.d.ts +1 -0
  87. package/build/environment/browser.d.ts.map +1 -0
  88. package/build/environment/browser.web.d.ts +1 -0
  89. package/build/environment/browser.web.d.ts.map +1 -0
  90. package/build/errors/CodedError.d.ts +1 -0
  91. package/build/errors/CodedError.d.ts.map +1 -0
  92. package/build/errors/UnavailabilityError.d.ts +1 -0
  93. package/build/errors/UnavailabilityError.d.ts.map +1 -0
  94. package/build/index.d.ts +3 -0
  95. package/build/index.d.ts.map +1 -0
  96. package/build/index.js +2 -0
  97. package/build/index.js.map +1 -1
  98. package/build/requireNativeModule.d.ts +16 -0
  99. package/build/requireNativeModule.d.ts.map +1 -0
  100. package/build/requireNativeModule.js +18 -0
  101. package/build/requireNativeModule.js.map +1 -0
  102. package/build/sweet/NativeErrorManager.d.ts +3 -0
  103. package/build/sweet/NativeErrorManager.d.ts.map +1 -0
  104. package/build/sweet/NativeErrorManager.js +3 -0
  105. package/build/sweet/NativeErrorManager.js.map +1 -0
  106. package/build/sweet/setUpErrorManager.fx.d.ts +2 -0
  107. package/build/sweet/setUpErrorManager.fx.d.ts.map +1 -0
  108. package/build/sweet/setUpErrorManager.fx.js +11 -0
  109. package/build/sweet/setUpErrorManager.fx.js.map +1 -0
  110. package/ios/AppDelegates/EXAppDelegatesLoader.m +4 -8
  111. package/ios/AppDelegates/ExpoAppDelegate.swift +22 -20
  112. package/ios/EXAppDefines.h +1 -0
  113. package/ios/EXAppDefines.m +6 -0
  114. package/ios/EXUtilities.h +2 -0
  115. package/ios/EXUtilities.m +12 -0
  116. package/ios/ExpoModulesCore.h +4 -0
  117. package/ios/ExpoModulesCore.podspec +4 -2
  118. package/ios/Interfaces/FileSystem/EXFileSystemInterface.h +1 -1
  119. package/ios/Interfaces/TaskManager/EXTaskServiceInterface.h +1 -0
  120. package/ios/JSI/{JSIConversions.h → EXJSIConversions.h} +5 -0
  121. package/ios/JSI/{JSIConversions.mm → EXJSIConversions.mm} +21 -1
  122. package/ios/JSI/{JSIInstaller.h → EXJSIInstaller.h} +10 -0
  123. package/ios/JSI/EXJSIInstaller.mm +17 -0
  124. package/ios/JSI/EXJSIUtils.h +19 -0
  125. package/ios/JSI/EXJSIUtils.mm +89 -0
  126. package/ios/JSI/EXJavaScriptObject.h +97 -0
  127. package/ios/JSI/EXJavaScriptObject.mm +121 -0
  128. package/ios/JSI/EXJavaScriptRuntime.h +73 -0
  129. package/ios/JSI/EXJavaScriptRuntime.mm +153 -0
  130. package/ios/JSI/EXJavaScriptValue.h +57 -0
  131. package/ios/JSI/EXJavaScriptValue.mm +166 -0
  132. package/ios/JSI/ExpoModulesHostObject.h +33 -0
  133. package/ios/JSI/ExpoModulesHostObject.mm +41 -0
  134. package/ios/JSI/JavaScriptRuntime.swift +32 -0
  135. package/ios/JSI/JavaScriptValue.swift +94 -0
  136. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +3 -23
  137. package/ios/NativeModulesProxy/EXNativeModulesProxy.h +2 -2
  138. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +101 -75
  139. package/ios/RCTComponentData+Privates.h +12 -0
  140. package/ios/ReactDelegates/EXReactCompatibleHelpers.h +18 -0
  141. package/ios/ReactDelegates/EXReactCompatibleHelpers.m +19 -0
  142. package/ios/ReactDelegates/ExpoReactDelegate.swift +3 -3
  143. package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +4 -4
  144. package/ios/ReactDelegates/ModulePriorities.swift +1 -1
  145. package/ios/Swift/AppContext.swift +57 -4
  146. package/ios/Swift/Arguments/AnyArgumentType.swift +1 -1
  147. package/ios/Swift/Arguments/ArgumentType.swift +4 -0
  148. package/ios/Swift/Arguments/Convertibles.swift +13 -13
  149. package/ios/Swift/Arguments/Types/EnumArgumentType.swift +11 -17
  150. package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +1 -1
  151. package/ios/Swift/Arguments/Types/RawArgumentType.swift +2 -2
  152. package/ios/Swift/Conversions.swift +51 -56
  153. package/ios/Swift/EventListener.swift +8 -10
  154. package/ios/Swift/Events/Callback.swift +66 -0
  155. package/ios/Swift/Events/Event.swift +43 -0
  156. package/ios/Swift/Exceptions/ChainableException.swift +51 -0
  157. package/ios/Swift/{CodedError.swift → Exceptions/CodedError.swift} +1 -12
  158. package/ios/Swift/Exceptions/Exception.swift +62 -0
  159. package/ios/Swift/Exceptions/ExceptionOrigin.swift +28 -0
  160. package/ios/Swift/Exceptions/GenericException.swift +20 -0
  161. package/ios/Swift/Exceptions/UnexpectedException.swift +16 -0
  162. package/ios/Swift/Functions/AnyFunction.swift +16 -1
  163. package/ios/Swift/Functions/AsyncFunctionComponent.swift +182 -0
  164. package/ios/Swift/Functions/ConcreteFunction.swift +52 -59
  165. package/ios/Swift/Functions/SyncFunctionComponent.swift +181 -0
  166. package/ios/Swift/JavaScriptUtils.swift +99 -0
  167. package/ios/Swift/ModuleHolder.swift +69 -18
  168. package/ios/Swift/ModuleRegistry.swift +4 -1
  169. package/ios/Swift/Modules/AnyModule.swift +0 -1
  170. package/ios/Swift/Modules/ModuleDefinition.swift +4 -13
  171. package/ios/Swift/Modules/ModuleDefinitionBuilder.swift +0 -1
  172. package/ios/Swift/Modules/ModuleDefinitionComponents.swift +54 -220
  173. package/ios/Swift/ModulesProvider.swift +3 -11
  174. package/ios/Swift/Objects/ObjectDefinition.swift +30 -0
  175. package/ios/Swift/Objects/ObjectDefinitionComponents.swift +257 -0
  176. package/ios/Swift/Promise.swift +8 -3
  177. package/ios/Swift/Records/AnyField.swift +7 -0
  178. package/ios/Swift/Records/Field.swift +24 -19
  179. package/ios/Swift/Records/FieldOption.swift +1 -1
  180. package/ios/Swift/Records/Record.swift +12 -4
  181. package/ios/Swift/SwiftInteropBridge.swift +53 -15
  182. package/ios/Swift/Views/AnyViewProp.swift +1 -1
  183. package/ios/Swift/Views/ComponentData.swift +96 -0
  184. package/ios/Swift/Views/ConcreteViewProp.swift +6 -8
  185. package/ios/Swift/Views/ExpoView.swift +8 -0
  186. package/ios/Swift/Views/ViewFactory.swift +1 -1
  187. package/ios/Swift/Views/ViewManagerDefinition.swift +23 -2
  188. package/ios/Swift/Views/ViewManagerDefinitionBuilder.swift +0 -1
  189. package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +49 -0
  190. package/ios/Swift/Views/ViewModuleWrapper.swift +5 -2
  191. package/ios/Swift.h +5 -0
  192. package/ios/Tests/ArgumentTypeSpec.swift +5 -7
  193. package/ios/Tests/ConstantsSpec.swift +6 -7
  194. package/ios/Tests/ConvertiblesSpec.swift +35 -36
  195. package/ios/Tests/ExceptionsSpec.swift +111 -0
  196. package/ios/Tests/ExpoModulesSpec.swift +75 -0
  197. package/ios/Tests/FunctionSpec.swift +21 -25
  198. package/ios/Tests/FunctionWithConvertiblesSpec.swift +4 -5
  199. package/ios/Tests/JavaScriptObjectSpec.swift +97 -0
  200. package/ios/Tests/JavaScriptRuntimeSpec.swift +94 -0
  201. package/ios/Tests/Mocks/ModuleMocks.swift +1 -1
  202. package/ios/Tests/Mocks/ModulesProviderMock.swift +0 -1
  203. package/ios/Tests/ModuleEventListenersSpec.swift +16 -17
  204. package/ios/Tests/ModuleRegistrySpec.swift +2 -3
  205. package/ios/Tests/RecordSpec.swift +9 -20
  206. package/package.json +3 -3
  207. package/src/NativeModulesProxy.native.ts +2 -22
  208. package/src/NativeModulesProxy.types.ts +0 -8
  209. package/src/NativeViewManagerAdapter.native.tsx +12 -28
  210. package/src/index.ts +4 -0
  211. package/src/requireNativeModule.ts +29 -0
  212. package/src/sweet/NativeErrorManager.ts +2 -0
  213. package/src/sweet/setUpErrorManager.fx.ts +12 -0
  214. package/android/src/main/java/expo/modules/kotlin/events/KEventEmitterWrapper.kt +0 -26
  215. package/android/src/main/java/expo/modules/kotlin/methods/Method.kt +0 -14
  216. package/android/src/main/java/expo/modules/kotlin/methods/PromiseMethod.kt +0 -15
  217. package/ios/JSI/ExpoModulesProxySpec.h +0 -24
  218. package/ios/JSI/ExpoModulesProxySpec.mm +0 -135
  219. package/ios/JSI/JSIInstaller.mm +0 -22
@@ -20,24 +20,24 @@ open class ExpoAppDelegate: UIResponder, UIApplicationDelegate {
20
20
 
21
21
  // MARK: - Initializing the App
22
22
 
23
- open func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
23
+ open func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
24
24
  let parsedSubscribers = subscribers.filter {
25
25
  $0.responds(to: #selector(application(_:willFinishLaunchingWithOptions:)))
26
26
  }
27
-
27
+
28
28
  // If we can't find a subscriber that implements `willFinishLaunchingWithOptions`, we will delegate the decision if we can handel the passed URL to
29
29
  // the `didFinishLaunchingWithOptions` method by returning `true` here.
30
30
  // You can read more about how iOS handles deep links here: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623112-application#discussion
31
- if (parsedSubscribers.isEmpty) {
32
- return true;
31
+ if parsedSubscribers.isEmpty {
32
+ return true
33
33
  }
34
-
34
+
35
35
  return parsedSubscribers.reduce(false) { result, subscriber in
36
36
  return subscriber.application!(application, willFinishLaunchingWithOptions: launchOptions) || result
37
37
  }
38
38
  }
39
39
 
40
- open func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
40
+ open func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
41
41
  return subscribers.reduce(false) { result, subscriber in
42
42
  return subscriber.application?(application, didFinishLaunchingWithOptions: launchOptions) ?? false || result
43
43
  }
@@ -107,7 +107,11 @@ open class ExpoAppDelegate: UIResponder, UIApplicationDelegate {
107
107
  subscribers.forEach { $0.application?(application, didFailToRegisterForRemoteNotificationsWithError: error) }
108
108
  }
109
109
 
110
- open func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
110
+ open func application(
111
+ _ application: UIApplication,
112
+ didReceiveRemoteNotification userInfo: [AnyHashable: Any],
113
+ fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
114
+ ) {
111
115
  let selector = #selector(application(_:didReceiveRemoteNotification:fetchCompletionHandler:))
112
116
  let subs = subscribers.filter { $0.responds(to: selector) }
113
117
  var subscribersLeft = subs.count
@@ -143,7 +147,11 @@ open class ExpoAppDelegate: UIResponder, UIApplicationDelegate {
143
147
  }
144
148
  }
145
149
 
146
- open func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
150
+ open func application(
151
+ _ application: UIApplication,
152
+ continue userActivity: NSUserActivity,
153
+ restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
154
+ ) -> Bool {
147
155
  let selector = #selector(application(_:continue:restorationHandler:))
148
156
  let subs = subscribers.filter { $0.responds(to: selector) }
149
157
  var subscribersLeft = subs.count
@@ -238,7 +246,7 @@ open class ExpoAppDelegate: UIResponder, UIApplicationDelegate {
238
246
 
239
247
  // MARK: - Opening a URL-Specified Resource
240
248
 
241
- open func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
249
+ open func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
242
250
  return subscribers.contains { subscriber in
243
251
  return subscriber.application?(app, open: url, options: options) ?? false
244
252
  }
@@ -255,11 +263,8 @@ open class ExpoAppDelegate: UIResponder, UIApplicationDelegate {
255
263
  // MARK: - Statics
256
264
 
257
265
  @objc
258
- public static func registerSubscribersFrom(modulesProvider: ModulesProviderObjCProtocol) {
259
- guard let provider = modulesProvider as? ModulesProviderProtocol else {
260
- fatalError("Expo modules provider must implement `ModulesProviderProtocol`.")
261
- }
262
- provider.getAppDelegateSubscribers().forEach { subscriberType in
266
+ public static func registerSubscribersFrom(modulesProvider: ModulesProvider) {
267
+ modulesProvider.getAppDelegateSubscribers().forEach { subscriberType in
263
268
  registerSubscriber(subscriberType.init())
264
269
  }
265
270
  }
@@ -278,12 +283,9 @@ open class ExpoAppDelegate: UIResponder, UIApplicationDelegate {
278
283
  }
279
284
 
280
285
  @objc
281
- public static func registerReactDelegateHandlersFrom(modulesProvider: ModulesProviderObjCProtocol) {
282
- guard let provider = modulesProvider as? ModulesProviderProtocol else {
283
- fatalError("Expo modules provider must implement `ModulesProviderProtocol`.")
284
- }
285
- provider.getReactDelegateHandlers()
286
- .sorted { (tuple1, tuple2) -> Bool in
286
+ public static func registerReactDelegateHandlersFrom(modulesProvider: ModulesProvider) {
287
+ modulesProvider.getReactDelegateHandlers()
288
+ .sorted { tuple1, tuple2 -> Bool in
287
289
  return ModulePriorities.get(tuple1.packageName) > ModulePriorities.get(tuple2.packageName)
288
290
  }
289
291
  .forEach { handlerTuple in
@@ -16,6 +16,7 @@ NS_ASSUME_NONNULL_BEGIN
16
16
  @property (class, nonatomic, assign, readonly) BOOL APP_DEBUG NS_SWIFT_NAME(APP_DEBUG);
17
17
  @property (class, nonatomic, assign, readonly) BOOL APP_RCT_DEBUG NS_SWIFT_NAME(APP_RCT_DEBUG);
18
18
  @property (class, nonatomic, assign, readonly) BOOL APP_RCT_DEV NS_SWIFT_NAME(APP_RCT_DEV);
19
+ @property (class, nonatomic, assign, readonly) BOOL APP_NEW_ARCH_ENABLED NS_SWIFT_NAME(APP_NEW_ARCH_ENABLED);
19
20
 
20
21
  + (NSDictionary *)getAllDefines;
21
22
 
@@ -26,6 +26,12 @@ static BOOL _loaded = NO;
26
26
  return [_storage[@"APP_RCT_DEV"] boolValue];
27
27
  }
28
28
 
29
+ + (BOOL)APP_NEW_ARCH_ENABLED
30
+ {
31
+ [self throwIfNotLoaded];
32
+ return [_storage[@"APP_NEW_ARCH_ENABLED"] boolValue];
33
+ }
34
+
29
35
  + (NSDictionary *)getAllDefines
30
36
  {
31
37
  return _storage;
package/ios/EXUtilities.h CHANGED
@@ -20,6 +20,8 @@ NS_ASSUME_NONNULL_BEGIN
20
20
  - (nullable UIViewController *)currentViewController;
21
21
  - (nullable NSDictionary *)launchOptions;
22
22
 
23
+ + (BOOL)catchException:(void(^)(void))tryBlock error:(__autoreleasing NSError **)error;
24
+
23
25
  @end
24
26
 
25
27
  NS_ASSUME_NONNULL_END
package/ios/EXUtilities.m CHANGED
@@ -206,6 +206,18 @@ EX_REGISTER_MODULE();
206
206
  }
207
207
  }
208
208
 
209
+ + (BOOL)catchException:(void(^)(void))tryBlock error:(__autoreleasing NSError **)error
210
+ {
211
+ @try {
212
+ tryBlock();
213
+ return YES;
214
+ }
215
+ @catch (NSException *exception) {
216
+ *error = [[NSError alloc] initWithDomain:exception.name code:0 userInfo:exception.userInfo];
217
+ return NO;
218
+ }
219
+ }
220
+
209
221
  @end
210
222
 
211
223
  UIApplication * EXSharedApplication(void)
@@ -1,5 +1,9 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
+ // Some headers needs to be imported from Objective-C code too.
4
+ // Otherwise they won't be visible in `ExpoModulesCore-Swift.h`.
5
+ #import <React/RCTView.h>
6
+
3
7
  #if __has_include("ExpoModulesCore-umbrella.h")
4
8
  #import "ExpoModulesCore-umbrella.h"
5
9
  #endif
@@ -23,6 +23,9 @@ Pod::Spec.new do |s|
23
23
  'CLANG_CXX_LANGUAGE_STANDARD' => 'c++14',
24
24
  'SWIFT_COMPILATION_MODE' => 'wholemodule',
25
25
  }
26
+ s.user_target_xcconfig = {
27
+ "HEADER_SEARCH_PATHS" => "\"${PODS_CONFIGURATION_BUILD_DIR}/ExpoModulesCore/Swift Compatibility Header\"",
28
+ }
26
29
 
27
30
  s.dependency 'React-Core'
28
31
  s.dependency 'ReactCommon/turbomodule/core'
@@ -38,8 +41,7 @@ Pod::Spec.new do |s|
38
41
  s.private_header_files = ['**/*+Private.h', '**/Swift.h']
39
42
 
40
43
  s.test_spec 'Tests' do |test_spec|
41
- test_spec.dependency 'Quick'
42
- test_spec.dependency 'Nimble'
44
+ test_spec.dependency 'ExpoModulesTestCore'
43
45
 
44
46
  test_spec.source_files = 'Tests/**/*.{m,swift}'
45
47
  end
@@ -17,7 +17,7 @@ typedef NS_OPTIONS(unsigned int, EXFileSystemPermissionFlags) {
17
17
 
18
18
  // TODO: Move permissionsForURI to EXFileSystemManagerInterface
19
19
  - (EXFileSystemPermissionFlags)permissionsForURI:(NSURL *)uri;
20
- - (NSString *)generatePathInDirectory:(NSString *)directory withExtension:(NSString *)extension;
20
+ - (nonnull NSString *)generatePathInDirectory:(NSString *)directory withExtension:(NSString *)extension;
21
21
  - (BOOL)ensureDirExistsWithPath:(NSString *)path;
22
22
 
23
23
  @end
@@ -1,6 +1,7 @@
1
1
  // Copyright 2015-present 650 Industries. All rights reserved.
2
2
 
3
3
  #import <ExpoModulesCore/EXTaskInterface.h>
4
+ #import <ExpoModulesCore/EXTaskManagerInterface.h>
4
5
 
5
6
  @protocol EXTaskServiceInterface
6
7
 
@@ -11,6 +11,9 @@
11
11
  using namespace facebook;
12
12
  using namespace react;
13
13
 
14
+ @class EXJavaScriptValue;
15
+ @class EXJavaScriptRuntime;
16
+
14
17
  namespace expo {
15
18
 
16
19
  jsi::Value convertNSNumberToJSIBoolean(jsi::Runtime &runtime, NSNumber *value);
@@ -31,6 +34,8 @@ NSString *convertJSIStringToNSString(jsi::Runtime &runtime, const jsi::String &v
31
34
 
32
35
  NSArray *convertJSIArrayToNSArray(jsi::Runtime &runtime, const jsi::Array &value, std::shared_ptr<CallInvoker> jsInvoker);
33
36
 
37
+ NSArray<EXJavaScriptValue *> *convertJSIValuesToNSArray(EXJavaScriptRuntime *runtime, const jsi::Value *values, size_t count);
38
+
34
39
  NSDictionary *convertJSIObjectToNSDictionary(jsi::Runtime &runtime, const jsi::Object &value, std::shared_ptr<CallInvoker> jsInvoker);
35
40
 
36
41
  id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value, std::shared_ptr<CallInvoker> jsInvoker);
@@ -1,7 +1,9 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
3
  #import <ReactCommon/TurboModuleUtils.h>
4
- #import <ExpoModulesCore/JSIConversions.h>
4
+ #import <ExpoModulesCore/EXJSIConversions.h>
5
+ #import <ExpoModulesCore/EXJavaScriptValue.h>
6
+ #import <ExpoModulesCore/EXJavaScriptRuntime.h>
5
7
 
6
8
  namespace expo {
7
9
 
@@ -52,6 +54,12 @@ std::vector<jsi::Value> convertNSArrayToStdVector(jsi::Runtime &runtime, NSArray
52
54
 
53
55
  jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value)
54
56
  {
57
+ if ([value isKindOfClass:[EXJavaScriptValue class]]) {
58
+ return jsi::Value(runtime, *[(EXJavaScriptValue *)value get]);
59
+ }
60
+ if ([value isKindOfClass:[EXJavaScriptObject class]]) {
61
+ return jsi::Value(runtime, *[(EXJavaScriptObject *)value get]);
62
+ }
55
63
  if ([value isKindOfClass:[NSString class]]) {
56
64
  return convertNSStringToJSIString(runtime, (NSString *)value);
57
65
  } else if ([value isKindOfClass:[NSNumber class]]) {
@@ -86,6 +94,18 @@ NSArray *convertJSIArrayToNSArray(jsi::Runtime &runtime, const jsi::Array &value
86
94
  return [result copy];
87
95
  }
88
96
 
97
+ NSArray<EXJavaScriptValue *> *convertJSIValuesToNSArray(EXJavaScriptRuntime *runtime, const jsi::Value *values, size_t count)
98
+ {
99
+ NSMutableArray<EXJavaScriptValue *> *array = [NSMutableArray arrayWithCapacity:count];
100
+ jsi::Runtime *jsiRuntime = [runtime get];
101
+
102
+ for (int i = 0; i < count; i++) {
103
+ std::shared_ptr<jsi::Value> value = std::make_shared<jsi::Value>(*jsiRuntime, values[i]);
104
+ array[i] = [[EXJavaScriptValue alloc] initWithRuntime:runtime value:value];
105
+ }
106
+ return array;
107
+ }
108
+
89
109
  NSDictionary *convertJSIObjectToNSDictionary(jsi::Runtime &runtime, const jsi::Object &value, std::shared_ptr<CallInvoker> jsInvoker)
90
110
  {
91
111
  jsi::Array propertyNames = value.getPropertyNames(runtime);
@@ -17,3 +17,13 @@ void installRuntimeObjects(jsi::Runtime &runtime, std::shared_ptr<CallInvoker> c
17
17
  } // namespace expo
18
18
 
19
19
  #endif
20
+
21
+ #import <ExpoModulesCore/EXJavaScriptRuntime.h>
22
+
23
+ @class SwiftInteropBridge;
24
+
25
+ @interface EXJavaScriptRuntimeManager : NSObject
26
+
27
+ + (void)installExpoModulesToRuntime:(nonnull EXJavaScriptRuntime *)runtime withSwiftInterop:(nonnull SwiftInteropBridge *)swiftInterop;
28
+
29
+ @end
@@ -0,0 +1,17 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoModulesCore/EXJSIInstaller.h>
4
+ #import <ExpoModulesCore/ExpoModulesHostObject.h>
5
+ #import <ExpoModulesCore/Swift.h>
6
+
7
+ @implementation EXJavaScriptRuntimeManager
8
+
9
+ + (void)installExpoModulesToRuntime:(nonnull EXJavaScriptRuntime *)runtime withSwiftInterop:(nonnull SwiftInteropBridge *)swiftInterop
10
+ {
11
+ std::shared_ptr<expo::ExpoModulesHostObject> hostObjectPtr = std::make_shared<expo::ExpoModulesHostObject>(swiftInterop);
12
+ EXJavaScriptObject *global = [runtime global];
13
+
14
+ [global setProperty:@"ExpoModules" value:[runtime createHostObject:hostObjectPtr]];
15
+ }
16
+
17
+ @end
@@ -0,0 +1,19 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #ifdef __cplusplus
4
+
5
+ #import <jsi/jsi.h>
6
+ #import <ReactCommon/RCTTurboModule.h>
7
+
8
+ using namespace facebook;
9
+ using namespace react;
10
+
11
+ namespace expo {
12
+
13
+ using PromiseInvocationBlock = void (^)(RCTPromiseResolveBlock resolveWrapper, RCTPromiseRejectBlock rejectWrapper);
14
+
15
+ void callPromiseSetupWithBlock(jsi::Runtime &runtime, std::shared_ptr<CallInvoker> jsInvoker, std::shared_ptr<Promise> promise, PromiseInvocationBlock setupBlock);
16
+
17
+ } // namespace expo
18
+
19
+ #endif
@@ -0,0 +1,89 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ #import <React/RCTUtils.h>
4
+ #import <ExpoModulesCore/EXJSIConversions.h>
5
+ #import <ExpoModulesCore/EXJSIUtils.h>
6
+
7
+ using namespace facebook;
8
+
9
+ namespace expo {
10
+
11
+ void callPromiseSetupWithBlock(jsi::Runtime &runtime, std::shared_ptr<CallInvoker> jsInvoker, std::shared_ptr<Promise> promise, PromiseInvocationBlock setupBlock)
12
+ {
13
+ auto weakResolveWrapper = CallbackWrapper::createWeak(promise->resolve_.getFunction(runtime), runtime, jsInvoker);
14
+ auto weakRejectWrapper = CallbackWrapper::createWeak(promise->reject_.getFunction(runtime), runtime, jsInvoker);
15
+
16
+ __block BOOL resolveWasCalled = NO;
17
+ __block BOOL rejectWasCalled = NO;
18
+
19
+ RCTPromiseResolveBlock resolveBlock = ^(id result) {
20
+ if (rejectWasCalled) {
21
+ throw std::runtime_error("Tried to resolve a promise after it's already been rejected.");
22
+ }
23
+
24
+ if (resolveWasCalled) {
25
+ throw std::runtime_error("Tried to resolve a promise more than once.");
26
+ }
27
+
28
+ auto strongResolveWrapper = weakResolveWrapper.lock();
29
+ auto strongRejectWrapper = weakRejectWrapper.lock();
30
+ if (!strongResolveWrapper || !strongRejectWrapper) {
31
+ return;
32
+ }
33
+
34
+ strongResolveWrapper->jsInvoker().invokeAsync([weakResolveWrapper, weakRejectWrapper, result]() {
35
+ auto strongResolveWrapper2 = weakResolveWrapper.lock();
36
+ auto strongRejectWrapper2 = weakRejectWrapper.lock();
37
+ if (!strongResolveWrapper2 || !strongRejectWrapper2) {
38
+ return;
39
+ }
40
+
41
+ jsi::Runtime &rt = strongResolveWrapper2->runtime();
42
+ jsi::Value arg = convertObjCObjectToJSIValue(rt, result);
43
+ strongResolveWrapper2->callback().call(rt, arg);
44
+
45
+ strongResolveWrapper2->destroy();
46
+ strongRejectWrapper2->destroy();
47
+ });
48
+
49
+ resolveWasCalled = YES;
50
+ };
51
+
52
+ RCTPromiseRejectBlock rejectBlock = ^(NSString *code, NSString *message, NSError *error) {
53
+ if (resolveWasCalled) {
54
+ throw std::runtime_error("Tried to reject a promise after it's already been resolved.");
55
+ }
56
+
57
+ if (rejectWasCalled) {
58
+ throw std::runtime_error("Tried to reject a promise more than once.");
59
+ }
60
+
61
+ auto strongResolveWrapper = weakResolveWrapper.lock();
62
+ auto strongRejectWrapper = weakRejectWrapper.lock();
63
+ if (!strongResolveWrapper || !strongRejectWrapper) {
64
+ return;
65
+ }
66
+
67
+ NSDictionary *jsError = RCTJSErrorFromCodeMessageAndNSError(code, message, error);
68
+ strongRejectWrapper->jsInvoker().invokeAsync([weakResolveWrapper, weakRejectWrapper, jsError]() {
69
+ auto strongResolveWrapper2 = weakResolveWrapper.lock();
70
+ auto strongRejectWrapper2 = weakRejectWrapper.lock();
71
+ if (!strongResolveWrapper2 || !strongRejectWrapper2) {
72
+ return;
73
+ }
74
+
75
+ jsi::Runtime &rt = strongRejectWrapper2->runtime();
76
+ jsi::Value arg = convertNSDictionaryToJSIObject(rt, jsError);
77
+ strongRejectWrapper2->callback().call(rt, arg);
78
+
79
+ strongResolveWrapper2->destroy();
80
+ strongRejectWrapper2->destroy();
81
+ });
82
+
83
+ rejectWasCalled = YES;
84
+ };
85
+
86
+ setupBlock(resolveBlock, rejectBlock);
87
+ }
88
+
89
+ } // namespace expo
@@ -0,0 +1,97 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ #import <Foundation/Foundation.h>
4
+ #import <React/RCTBridgeModule.h>
5
+
6
+ #ifdef __cplusplus
7
+ #import <jsi/jsi.h>
8
+ #import <ReactCommon/CallInvoker.h>
9
+
10
+ namespace jsi = facebook::jsi;
11
+ #endif // __cplusplus
12
+
13
+ typedef void (^JSAsyncFunctionBlock)(NSArray * _Nonnull, RCTPromiseResolveBlock _Nonnull, RCTPromiseRejectBlock _Nonnull);
14
+ typedef id _Nullable (^JSSyncFunctionBlock)(NSArray * _Nonnull);
15
+
16
+ @class EXJavaScriptRuntime;
17
+ @class EXJavaScriptValue;
18
+
19
+ /**
20
+ The property descriptor options for the property being defined or modified.
21
+ */
22
+ typedef NS_OPTIONS(NSInteger, EXJavaScriptObjectPropertyDescriptor) {
23
+ /**
24
+ If set, the type of this property descriptor may be changed and if the property may be deleted from the corresponding object.
25
+ */
26
+ EXJavaScriptObjectPropertyDescriptorConfigurable = 1 << 0,
27
+ /**
28
+ If set, the property shows up during enumeration of the properties on the corresponding object.
29
+ */
30
+ EXJavaScriptObjectPropertyDescriptorEnumerable = 1 << 1,
31
+ /**
32
+ If set, the value associated with the property may be changed with an assignment operator.
33
+ */
34
+ EXJavaScriptObjectPropertyDescriptorWritable = 1 << 2,
35
+ } NS_SWIFT_NAME(JavaScriptObjectPropertyDescriptor);
36
+
37
+ NS_SWIFT_NAME(JavaScriptObject)
38
+ @interface EXJavaScriptObject : NSObject
39
+
40
+ // Some parts of the interface must be hidden for Swift – it can't import any C++ code.
41
+ #ifdef __cplusplus
42
+ - (nonnull instancetype)initWith:(std::shared_ptr<jsi::Object>)jsObjectPtr
43
+ runtime:(nonnull EXJavaScriptRuntime *)runtime;
44
+
45
+ /**
46
+ Returns the pointer to the underlying object.
47
+ */
48
+ - (nonnull jsi::Object *)get;
49
+ #endif // __cplusplus
50
+
51
+ #pragma mark - Accessing object properties
52
+
53
+ /**
54
+ \return a bool whether the object has a property with the given name.
55
+ */
56
+ - (BOOL)hasProperty:(nonnull NSString *)name;
57
+
58
+ /**
59
+ \return the property of the object with the given name.
60
+ If the name isn't a property on the object, returns the `undefined` value.
61
+ */
62
+ - (nonnull EXJavaScriptValue *)getProperty:(nonnull NSString *)name;
63
+
64
+ /**
65
+ \return an array consisting of all enumerable property names in the object and its prototype chain.
66
+ */
67
+ - (nonnull NSArray<NSString *> *)getPropertyNames;
68
+
69
+ #pragma mark - Modifying object properties
70
+
71
+ /**
72
+ Sets the value for the property with the given name.
73
+ */
74
+ - (void)setProperty:(nonnull NSString *)name value:(nullable id)value;
75
+
76
+ /**
77
+ Defines a new property or modifies an existing property on the object. Calls `Object.defineProperty` under the hood.
78
+ */
79
+ - (void)defineProperty:(nonnull NSString *)name value:(nullable id)value options:(EXJavaScriptObjectPropertyDescriptor)options;
80
+
81
+ #pragma mark - Functions
82
+
83
+ /**
84
+ Sets given function block on the object as a host function returning a promise.
85
+ */
86
+ - (void)setAsyncFunction:(nonnull NSString *)key
87
+ argsCount:(NSInteger)argsCount
88
+ block:(nonnull JSAsyncFunctionBlock)block;
89
+
90
+ /**
91
+ Sets given synchronous function block as a host function on the object.
92
+ */
93
+ - (void)setSyncFunction:(nonnull NSString *)name
94
+ argsCount:(NSInteger)argsCount
95
+ block:(nonnull JSSyncFunctionBlock)block;
96
+
97
+ @end
@@ -0,0 +1,121 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ #import <ExpoModulesCore/EXJSIConversions.h>
4
+ #import <ExpoModulesCore/EXJavaScriptObject.h>
5
+ #import <ExpoModulesCore/EXJavaScriptRuntime.h>
6
+
7
+ @implementation EXJavaScriptObject {
8
+ /**
9
+ Pointer to the `EXJavaScriptRuntime` wrapper.
10
+
11
+ \note It must be weak because only then the original runtime can be safely deallocated
12
+ when the JS engine wants to without unsetting it on each created object.
13
+ */
14
+ __weak EXJavaScriptRuntime *_runtime;
15
+
16
+ /**
17
+ Shared pointer to the original JSI object that is being wrapped by `EXJavaScriptObject` class.
18
+ */
19
+ std::shared_ptr<jsi::Object> _jsObjectPtr;
20
+ }
21
+
22
+ - (nonnull instancetype)initWith:(std::shared_ptr<jsi::Object>)jsObjectPtr
23
+ runtime:(nonnull EXJavaScriptRuntime *)runtime
24
+ {
25
+ if (self = [super init]) {
26
+ _runtime = runtime;
27
+ _jsObjectPtr = jsObjectPtr;
28
+ }
29
+ return self;
30
+ }
31
+
32
+ - (nonnull jsi::Object *)get
33
+ {
34
+ return _jsObjectPtr.get();
35
+ }
36
+
37
+ #pragma mark - Accessing object properties
38
+
39
+ - (BOOL)hasProperty:(nonnull NSString *)name
40
+ {
41
+ return _jsObjectPtr->hasProperty(*[_runtime get], [name UTF8String]);
42
+ }
43
+
44
+ - (nonnull EXJavaScriptValue *)getProperty:(nonnull NSString *)name
45
+ {
46
+ std::shared_ptr<jsi::Value> value = std::make_shared<jsi::Value>(_jsObjectPtr->getProperty(*[_runtime get], [name UTF8String]));
47
+ return [[EXJavaScriptValue alloc] initWithRuntime:_runtime value:value];
48
+ }
49
+
50
+ - (nonnull NSArray<NSString *> *)getPropertyNames
51
+ {
52
+ jsi::Runtime *runtime = [_runtime get];
53
+ jsi::Array propertyNamesArray = _jsObjectPtr->getPropertyNames(*[_runtime get]);
54
+ return expo::convertJSIArrayToNSArray(*runtime, propertyNamesArray, nullptr);
55
+ }
56
+
57
+ #pragma mark - Modifying object properties
58
+
59
+ - (void)setProperty:(nonnull NSString *)name value:(nullable id)value
60
+ {
61
+ jsi::Value jsiValue = expo::convertObjCObjectToJSIValue(*[_runtime get], value);
62
+ _jsObjectPtr->setProperty(*[_runtime get], [name UTF8String], jsiValue);
63
+ }
64
+
65
+ - (void)defineProperty:(nonnull NSString *)name value:(nullable id)value options:(EXJavaScriptObjectPropertyDescriptor)options
66
+ {
67
+ jsi::Runtime *runtime = [_runtime get];
68
+ jsi::Object global = runtime->global();
69
+ jsi::Object objectClass = global.getPropertyAsObject(*runtime, "Object");
70
+ jsi::Function definePropertyFunction = objectClass.getPropertyAsFunction(*runtime, "defineProperty");
71
+ jsi::Object descriptor = [self preparePropertyDescriptorWithOptions:options];
72
+
73
+ descriptor.setProperty(*runtime, "value", expo::convertObjCObjectToJSIValue(*runtime, value));
74
+
75
+ // This call is basically the same as `Object.defineProperty(object, name, descriptor)` in JS
76
+ definePropertyFunction.callWithThis(*runtime, objectClass, {
77
+ jsi::Value(*runtime, *_jsObjectPtr.get()),
78
+ jsi::String::createFromUtf8(*runtime, [name UTF8String]),
79
+ std::move(descriptor),
80
+ });
81
+ }
82
+
83
+ #pragma mark - Functions
84
+
85
+ - (void)setAsyncFunction:(nonnull NSString *)name
86
+ argsCount:(NSInteger)argsCount
87
+ block:(nonnull JSAsyncFunctionBlock)block
88
+ {
89
+ if (!_runtime) {
90
+ NSLog(@"Cannot set '%@' async function when the EXJavaScript runtime is no longer available.", name);
91
+ return;
92
+ }
93
+ jsi::Function function = [_runtime createAsyncFunction:name argsCount:argsCount block:block];
94
+ _jsObjectPtr->setProperty(*[_runtime get], [name UTF8String], function);
95
+ }
96
+
97
+ - (void)setSyncFunction:(nonnull NSString *)name
98
+ argsCount:(NSInteger)argsCount
99
+ block:(nonnull JSSyncFunctionBlock)block
100
+ {
101
+ if (!_runtime) {
102
+ NSLog(@"Cannot set '%@' sync function when the EXJavaScript runtime is no longer available.", name);
103
+ return;
104
+ }
105
+ jsi::Function function = [_runtime createSyncFunction:name argsCount:argsCount block:block];
106
+ _jsObjectPtr->setProperty(*[_runtime get], [name UTF8String], function);
107
+ }
108
+
109
+ #pragma mark - Private helpers
110
+
111
+ - (jsi::Object)preparePropertyDescriptorWithOptions:(EXJavaScriptObjectPropertyDescriptor)options
112
+ {
113
+ jsi::Runtime *runtime = [_runtime get];
114
+ jsi::Object descriptor(*runtime);
115
+ descriptor.setProperty(*runtime, "configurable", (bool)(options & EXJavaScriptObjectPropertyDescriptorConfigurable));
116
+ descriptor.setProperty(*runtime, "enumerable", (bool)(options & EXJavaScriptObjectPropertyDescriptorEnumerable));
117
+ descriptor.setProperty(*runtime, "writable", (bool)(options & EXJavaScriptObjectPropertyDescriptorWritable));
118
+ return descriptor;
119
+ }
120
+
121
+ @end