expo-modules-core 0.9.0 → 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 +25 -0
  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 +88 -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
@@ -34,7 +34,7 @@ Pod::Spec.new do |s|
34
34
  s.source_files = '**/*.h'
35
35
  s.vendored_frameworks = "#{s.name}.xcframework"
36
36
  else
37
- s.source_files = '**/*.{h,m,mm,swift}'
37
+ s.source_files = '**/*.{h,m,mm,swift,cpp}'
38
38
  end
39
39
 
40
40
  s.exclude_files = 'Tests/'
@@ -1,6 +1,9 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
3
  #import <ReactCommon/TurboModuleUtils.h>
4
+ #import <ExpoModulesCore/EXJavaScriptValue.h>
5
+ #import <ExpoModulesCore/EXJavaScriptObject.h>
6
+ #import <ExpoModulesCore/EXJavaScriptWeakObject.h>
4
7
  #import <ExpoModulesCore/EXJSIConversions.h>
5
8
  #import <ExpoModulesCore/EXJavaScriptValue.h>
6
9
  #import <ExpoModulesCore/EXJavaScriptRuntime.h>
@@ -60,6 +63,9 @@ jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value)
60
63
  if ([value isKindOfClass:[EXJavaScriptObject class]]) {
61
64
  return jsi::Value(runtime, *[(EXJavaScriptObject *)value get]);
62
65
  }
66
+ if ([value isKindOfClass:[EXJavaScriptWeakObject class]]) {
67
+ return jsi::Value(runtime, *[[(EXJavaScriptWeakObject *)value lock] get]);
68
+ }
63
69
  if ([value isKindOfClass:[NSString class]]) {
64
70
  return convertNSStringToJSIString(runtime, (NSString *)value);
65
71
  } else if ([value isKindOfClass:[NSNumber class]]) {
@@ -1,29 +1,23 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
- #ifdef __cplusplus
3
+ #import <React/RCTBridge.h>
4
4
 
5
- #import <jsi/jsi.h>
6
- #import <ReactCommon/RCTTurboModule.h>
7
-
8
- #import <ExpoModulesCore/EXNativeModulesProxy.h>
9
-
10
- using namespace facebook;
11
- using namespace react;
12
-
13
- namespace expo {
14
-
15
- void installRuntimeObjects(jsi::Runtime &runtime, std::shared_ptr<CallInvoker> callInvoker, EXNativeModulesProxy *nativeModulesProxy);
16
-
17
- } // namespace expo
18
-
19
- #endif
20
-
21
- #import <ExpoModulesCore/EXJavaScriptRuntime.h>
22
-
23
- @class SwiftInteropBridge;
5
+ // Swift classes need forward-declaration in the headers.
6
+ @class EXAppContext;
7
+ @class EXJavaScriptRuntime;
24
8
 
25
9
  @interface EXJavaScriptRuntimeManager : NSObject
26
10
 
27
- + (void)installExpoModulesToRuntime:(nonnull EXJavaScriptRuntime *)runtime withSwiftInterop:(nonnull SwiftInteropBridge *)swiftInterop;
11
+ /**
12
+ Gets the JS runtime from the given bridge. May return `nil` when
13
+ the runtime is not available yet or the remote debugging is enabled.
14
+ */
15
+ + (nullable EXJavaScriptRuntime *)runtimeFromBridge:(nonnull RCTBridge *)bridge NS_SWIFT_NAME(runtime(fromBridge:));
16
+
17
+ /**
18
+ Installs ExpoModules host object in the runtime of the given app context.
19
+ Returns a bool value whether the installation succeeded.
20
+ */
21
+ + (BOOL)installExpoModulesHostObject:(nonnull EXAppContext *)appContext;
28
22
 
29
23
  @end
@@ -4,14 +4,50 @@
4
4
  #import <ExpoModulesCore/ExpoModulesHostObject.h>
5
5
  #import <ExpoModulesCore/Swift.h>
6
6
 
7
+ namespace jsi = facebook::jsi;
8
+
9
+ /**
10
+ This name will be used as a property of the JS global object to which the host object is added.
11
+ */
12
+ static NSString *expoModulesHostObjectPropertyName = @"ExpoModules";
13
+
14
+ @interface RCTBridge (ExpoBridgeWithRuntime)
15
+
16
+ - (void *)runtime;
17
+
18
+ @end
19
+
7
20
  @implementation EXJavaScriptRuntimeManager
8
21
 
9
- + (void)installExpoModulesToRuntime:(nonnull EXJavaScriptRuntime *)runtime withSwiftInterop:(nonnull SwiftInteropBridge *)swiftInterop
22
+ + (nullable EXJavaScriptRuntime *)runtimeFromBridge:(nonnull RCTBridge *)bridge
10
23
  {
11
- std::shared_ptr<expo::ExpoModulesHostObject> hostObjectPtr = std::make_shared<expo::ExpoModulesHostObject>(swiftInterop);
24
+ jsi::Runtime *jsiRuntime = [bridge respondsToSelector:@selector(runtime)] ? reinterpret_cast<jsi::Runtime *>(bridge.runtime) : nullptr;
25
+ return jsiRuntime ? [[EXJavaScriptRuntime alloc] initWithRuntime:jsiRuntime callInvoker:bridge.jsCallInvoker] : nil;
26
+ }
27
+
28
+ + (BOOL)installExpoModulesHostObject:(nonnull EXAppContext *)appContext
29
+ {
30
+ EXJavaScriptRuntime *runtime = [appContext runtime];
31
+
32
+ // The runtime may be unavailable, e.g. remote debugger is enabled or it hasn't been set yet.
33
+ if (!runtime) {
34
+ return false;
35
+ }
36
+
12
37
  EXJavaScriptObject *global = [runtime global];
13
38
 
14
- [global setProperty:@"ExpoModules" value:[runtime createHostObject:hostObjectPtr]];
39
+ if ([global hasProperty:expoModulesHostObjectPropertyName]) {
40
+ return false;
41
+ }
42
+
43
+ std::shared_ptr<expo::ExpoModulesHostObject> hostObjectPtr = std::make_shared<expo::ExpoModulesHostObject>(appContext);
44
+ EXJavaScriptObject *hostObject = [runtime createHostObject:hostObjectPtr];
45
+
46
+ // Define the ExpoModules object as a non-configurable, read-only and enumerable property.
47
+ [global defineProperty:expoModulesHostObjectPropertyName
48
+ value:hostObject
49
+ options:EXJavaScriptObjectPropertyDescriptorEnumerable];
50
+ return true;
15
51
  }
16
52
 
17
53
  @end
@@ -2,17 +2,61 @@
2
2
 
3
3
  #ifdef __cplusplus
4
4
 
5
+ #import <functional>
6
+
5
7
  #import <jsi/jsi.h>
6
8
  #import <ReactCommon/RCTTurboModule.h>
9
+ #import <ExpoModulesCore/EXObjectDeallocator.h>
7
10
 
8
- using namespace facebook;
9
- using namespace react;
11
+ namespace jsi = facebook::jsi;
12
+ namespace react = facebook::react;
10
13
 
11
14
  namespace expo {
12
15
 
16
+ #pragma mark - Promises
17
+
13
18
  using PromiseInvocationBlock = void (^)(RCTPromiseResolveBlock resolveWrapper, RCTPromiseRejectBlock rejectWrapper);
14
19
 
15
- void callPromiseSetupWithBlock(jsi::Runtime &runtime, std::shared_ptr<CallInvoker> jsInvoker, std::shared_ptr<Promise> promise, PromiseInvocationBlock setupBlock);
20
+ void callPromiseSetupWithBlock(jsi::Runtime &runtime, std::shared_ptr<react::CallInvoker> jsInvoker, std::shared_ptr<react::Promise> promise, PromiseInvocationBlock setupBlock);
21
+
22
+ #pragma mark - Classes
23
+
24
+ using ClassConstructor = std::function<void(jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *args, size_t count)>;
25
+
26
+ std::shared_ptr<jsi::Function> createClass(jsi::Runtime &runtime, const char *name, ClassConstructor constructor);
27
+
28
+ #pragma mark - Weak objects
29
+
30
+ /**
31
+ Checks whether the `WeakRef` class is available in the given runtime.
32
+ According to the docs, it is unimplemented in JSC prior to iOS 14.5.
33
+ As of the time of writing this comment it's also unimplemented in Hermes
34
+ where you should use `jsi::WeakObject` instead.
35
+ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef
36
+ */
37
+ bool isWeakRefSupported(jsi::Runtime &runtime);
38
+
39
+ /**
40
+ Creates the `WeakRef` with given JSI object. You should first use `isWeakRefSupported`
41
+ to check whether this feature is supported by the runtime.
42
+ */
43
+ std::shared_ptr<jsi::Object> createWeakRef(jsi::Runtime &runtime, std::shared_ptr<jsi::Object> object);
44
+
45
+ /**
46
+ Returns the `WeakRef` object's target object, or an empty pointer if the target object has been reclaimed.
47
+ */
48
+ std::shared_ptr<jsi::Object> derefWeakRef(jsi::Runtime &runtime, std::shared_ptr<jsi::Object> object);
49
+
50
+ #pragma mark - Define property
51
+
52
+ void defineProperty(jsi::Runtime &runtime, const jsi::Object *object, const char *name, jsi::Value value);
53
+
54
+ #pragma mark - Deallocator
55
+
56
+ /**
57
+ Sets the deallocator block on a given object, which is called when the object is being deallocated.
58
+ */
59
+ void setDeallocator(jsi::Runtime &runtime, std::shared_ptr<jsi::Object> object, ObjectDeallocatorBlock deallocatorBlock);
16
60
 
17
61
  } // namespace expo
18
62
 
@@ -1,17 +1,17 @@
1
1
  // Copyright 2022-present 650 Industries. All rights reserved.
2
2
 
3
+ #import <sstream>
4
+
3
5
  #import <React/RCTUtils.h>
4
6
  #import <ExpoModulesCore/EXJSIConversions.h>
5
7
  #import <ExpoModulesCore/EXJSIUtils.h>
6
8
 
7
- using namespace facebook;
8
-
9
9
  namespace expo {
10
10
 
11
11
  void callPromiseSetupWithBlock(jsi::Runtime &runtime, std::shared_ptr<CallInvoker> jsInvoker, std::shared_ptr<Promise> promise, PromiseInvocationBlock setupBlock)
12
12
  {
13
- auto weakResolveWrapper = CallbackWrapper::createWeak(promise->resolve_.getFunction(runtime), runtime, jsInvoker);
14
- auto weakRejectWrapper = CallbackWrapper::createWeak(promise->reject_.getFunction(runtime), runtime, jsInvoker);
13
+ auto weakResolveWrapper = react::CallbackWrapper::createWeak(promise->resolve_.getFunction(runtime), runtime, jsInvoker);
14
+ auto weakRejectWrapper = react::CallbackWrapper::createWeak(promise->reject_.getFunction(runtime), runtime, jsInvoker);
15
15
 
16
16
  __block BOOL resolveWasCalled = NO;
17
17
  __block BOOL rejectWasCalled = NO;
@@ -86,4 +86,88 @@ void callPromiseSetupWithBlock(jsi::Runtime &runtime, std::shared_ptr<CallInvoke
86
86
  setupBlock(resolveBlock, rejectBlock);
87
87
  }
88
88
 
89
+ std::shared_ptr<jsi::Function> createClass(jsi::Runtime &runtime, const char *name, ClassConstructor constructor) {
90
+ std::string nativeConstructorKey("__native_constructor__");
91
+
92
+ // Create a string buffer of the source code to evaluate.
93
+ std::stringstream source;
94
+ source << "(function " << name << "(...args) { this." << nativeConstructorKey << "(...args); return this; })";
95
+ std::shared_ptr<jsi::StringBuffer> sourceBuffer = std::make_shared<jsi::StringBuffer>(source.str());
96
+
97
+ // Evaluate the code and obtain returned value (the constructor function).
98
+ jsi::Object klass = runtime.evaluateJavaScript(sourceBuffer, "").asObject(runtime);
99
+
100
+ // Set the native constructor in the prototype.
101
+ jsi::Object prototype = klass.getPropertyAsObject(runtime, "prototype");
102
+ jsi::PropNameID nativeConstructorPropId = jsi::PropNameID::forAscii(runtime, nativeConstructorKey);
103
+ jsi::Function nativeConstructor = jsi::Function::createFromHostFunction(
104
+ runtime,
105
+ nativeConstructorPropId,
106
+ // The paramCount is not obligatory to match, it only affects the `length` property of the function.
107
+ 0,
108
+ [constructor](jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value {
109
+ constructor(runtime, thisValue, args, count);
110
+ return jsi::Value::undefined();
111
+ });
112
+
113
+ defineProperty(runtime, &prototype, nativeConstructorKey.c_str(), jsi::Value(runtime, nativeConstructor));
114
+
115
+ return std::make_shared<jsi::Function>(klass.asFunction(runtime));
116
+ }
117
+
118
+ #pragma mark - Weak objects
119
+
120
+ bool isWeakRefSupported(jsi::Runtime &runtime) {
121
+ return runtime.global().hasProperty(runtime, "WeakRef");
122
+ }
123
+
124
+ std::shared_ptr<jsi::Object> createWeakRef(jsi::Runtime &runtime, std::shared_ptr<jsi::Object> object) {
125
+ jsi::Object weakRef = runtime
126
+ .global()
127
+ .getProperty(runtime, "WeakRef")
128
+ .asObject(runtime)
129
+ .asFunction(runtime)
130
+ .callAsConstructor(runtime, jsi::Value(runtime, *object))
131
+ .asObject(runtime);
132
+ return std::make_shared<jsi::Object>(std::move(weakRef));
133
+ }
134
+
135
+ std::shared_ptr<jsi::Object> derefWeakRef(jsi::Runtime &runtime, std::shared_ptr<jsi::Object> object) {
136
+ jsi::Value ref = object->getProperty(runtime, "deref")
137
+ .asObject(runtime)
138
+ .asFunction(runtime)
139
+ .callWithThis(runtime, *object);
140
+
141
+ if (ref.isUndefined()) {
142
+ return nullptr;
143
+ }
144
+ return std::make_shared<jsi::Object>(ref.asObject(runtime));
145
+ }
146
+
147
+ #pragma mark - Define property
148
+
149
+ void defineProperty(jsi::Runtime &runtime, const jsi::Object *object, const char *name, jsi::Value value) {
150
+ jsi::Object global = runtime.global();
151
+ jsi::Object objectClass = global.getPropertyAsObject(runtime, "Object");
152
+ jsi::Function definePropertyFunction = objectClass.getPropertyAsFunction(runtime, "defineProperty");
153
+
154
+ jsi::Object descriptor(runtime);
155
+ descriptor.setProperty(runtime, "value", value);
156
+
157
+ definePropertyFunction.callWithThis(runtime, objectClass, {
158
+ jsi::Value(runtime, *object),
159
+ jsi::String::createFromUtf8(runtime, name),
160
+ std::move(descriptor),
161
+ });
162
+ }
163
+
164
+ #pragma mark - Deallocator
165
+
166
+ void setDeallocator(jsi::Runtime &runtime, std::shared_ptr<jsi::Object> object, ObjectDeallocatorBlock deallocatorBlock) {
167
+ std::shared_ptr<expo::ObjectDeallocator> hostObjectPtr = std::make_shared<ObjectDeallocator>(deallocatorBlock);
168
+ jsi::Object jsObject = jsi::Object::createFromHostObject(runtime, hostObjectPtr);
169
+
170
+ object->setProperty(runtime, "__expo_object_deallocator__", jsi::Value(runtime, jsObject));
171
+ }
172
+
89
173
  } // namespace expo
@@ -1,20 +1,16 @@
1
1
  // Copyright 2022-present 650 Industries. All rights reserved.
2
2
 
3
3
  #import <Foundation/Foundation.h>
4
- #import <React/RCTBridgeModule.h>
5
4
 
6
5
  #ifdef __cplusplus
7
6
  #import <jsi/jsi.h>
8
- #import <ReactCommon/CallInvoker.h>
9
7
 
10
8
  namespace jsi = facebook::jsi;
11
9
  #endif // __cplusplus
12
10
 
13
- typedef void (^JSAsyncFunctionBlock)(NSArray * _Nonnull, RCTPromiseResolveBlock _Nonnull, RCTPromiseRejectBlock _Nonnull);
14
- typedef id _Nullable (^JSSyncFunctionBlock)(NSArray * _Nonnull);
15
-
16
11
  @class EXJavaScriptRuntime;
17
12
  @class EXJavaScriptValue;
13
+ @class EXJavaScriptWeakObject;
18
14
 
19
15
  /**
20
16
  The property descriptor options for the property being defined or modified.
@@ -73,25 +69,22 @@ NS_SWIFT_NAME(JavaScriptObject)
73
69
  */
74
70
  - (void)setProperty:(nonnull NSString *)name value:(nullable id)value;
75
71
 
72
+ /**
73
+ Defines a new property or modifies an existing property on the object using the property descriptor.
74
+ */
75
+ - (void)defineProperty:(nonnull NSString *)name descriptor:(nonnull EXJavaScriptObject *)descriptor;
76
+
76
77
  /**
77
78
  Defines a new property or modifies an existing property on the object. Calls `Object.defineProperty` under the hood.
78
79
  */
79
80
  - (void)defineProperty:(nonnull NSString *)name value:(nullable id)value options:(EXJavaScriptObjectPropertyDescriptor)options;
80
81
 
81
- #pragma mark - Functions
82
+ #pragma mark - WeakObject
82
83
 
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;
84
+ - (nonnull EXJavaScriptWeakObject *)createWeak;
89
85
 
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;
86
+ #pragma mark - Deallocator
87
+
88
+ - (void)setObjectDeallocator:(void (^ _Nonnull)(void))deallocatorBlock;
96
89
 
97
90
  @end
@@ -1,8 +1,11 @@
1
1
  // Copyright 2022-present 650 Industries. All rights reserved.
2
2
 
3
3
  #import <ExpoModulesCore/EXJSIConversions.h>
4
+ #import <ExpoModulesCore/EXJavaScriptValue.h>
4
5
  #import <ExpoModulesCore/EXJavaScriptObject.h>
5
6
  #import <ExpoModulesCore/EXJavaScriptRuntime.h>
7
+ #import <ExpoModulesCore/EXJavaScriptWeakObject.h>
8
+ #import <ExpoModulesCore/EXJSIUtils.h>
6
9
 
7
10
  @implementation EXJavaScriptObject {
8
11
  /**
@@ -62,6 +65,21 @@
62
65
  _jsObjectPtr->setProperty(*[_runtime get], [name UTF8String], jsiValue);
63
66
  }
64
67
 
68
+ - (void)defineProperty:(nonnull NSString *)name descriptor:(nonnull EXJavaScriptObject *)descriptor
69
+ {
70
+ jsi::Runtime *runtime = [_runtime get];
71
+ jsi::Object global = runtime->global();
72
+ jsi::Object objectClass = global.getPropertyAsObject(*runtime, "Object");
73
+ jsi::Function definePropertyFunction = objectClass.getPropertyAsFunction(*runtime, "defineProperty");
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 get]),
80
+ });
81
+ }
82
+
65
83
  - (void)defineProperty:(nonnull NSString *)name value:(nullable id)value options:(EXJavaScriptObjectPropertyDescriptor)options
66
84
  {
67
85
  jsi::Runtime *runtime = [_runtime get];
@@ -80,30 +98,31 @@
80
98
  });
81
99
  }
82
100
 
83
- #pragma mark - Functions
101
+ #pragma mark - WeakObject
84
102
 
85
- - (void)setAsyncFunction:(nonnull NSString *)name
86
- argsCount:(NSInteger)argsCount
87
- block:(nonnull JSAsyncFunctionBlock)block
103
+ - (nonnull EXJavaScriptWeakObject *)createWeak
88
104
  {
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);
105
+ return [[EXJavaScriptWeakObject alloc] initWith:_jsObjectPtr runtime:_runtime];
95
106
  }
96
107
 
97
- - (void)setSyncFunction:(nonnull NSString *)name
98
- argsCount:(NSInteger)argsCount
99
- block:(nonnull JSSyncFunctionBlock)block
108
+ #pragma mark - Deallocator
109
+
110
+ - (void)setObjectDeallocator:(void (^)(void))deallocatorBlock
111
+ {
112
+ expo::setDeallocator(*[_runtime get], _jsObjectPtr, deallocatorBlock);
113
+ }
114
+
115
+ #pragma mark - Equality
116
+
117
+ - (BOOL)isEqual:(id)object
100
118
  {
101
- if (!_runtime) {
102
- NSLog(@"Cannot set '%@' sync function when the EXJavaScript runtime is no longer available.", name);
103
- return;
119
+ if ([object isKindOfClass:EXJavaScriptObject.class]) {
120
+ jsi::Runtime *runtime = [_runtime get];
121
+ jsi::Object *a = _jsObjectPtr.get();
122
+ jsi::Object *b = [object get];
123
+ return jsi::Object::strictEquals(*runtime, *a, *b);
104
124
  }
105
- jsi::Function function = [_runtime createSyncFunction:name argsCount:argsCount block:block];
106
- _jsObjectPtr->setProperty(*[_runtime get], [name UTF8String], function);
125
+ return false;
107
126
  }
108
127
 
109
128
  #pragma mark - Private helpers
@@ -1,7 +1,9 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
+ #import <Foundation/Foundation.h>
3
4
  #import <ExpoModulesCore/EXJavaScriptValue.h>
4
5
  #import <ExpoModulesCore/EXJavaScriptObject.h>
6
+ #import <React/RCTBridgeModule.h>
5
7
 
6
8
  #ifdef __cplusplus
7
9
  #import <ReactCommon/CallInvoker.h>
@@ -13,8 +15,20 @@ namespace react = facebook::react;
13
15
  @class EXJavaScriptValue;
14
16
  @class EXJavaScriptObject;
15
17
 
18
+ typedef void (^JSAsyncFunctionBlock)(EXJavaScriptValue * _Nonnull thisValue,
19
+ NSArray<EXJavaScriptValue *> * _Nonnull arguments,
20
+ RCTPromiseResolveBlock _Nonnull resolve,
21
+ RCTPromiseRejectBlock _Nonnull reject);
22
+
23
+ typedef id _Nullable (^JSSyncFunctionBlock)(EXJavaScriptValue * _Nonnull thisValue,
24
+ NSArray<EXJavaScriptValue *> * _Nonnull arguments,
25
+ NSError * _Nullable __autoreleasing * _Nullable error);
26
+
16
27
  #ifdef __cplusplus
17
- typedef jsi::Value (^JSHostFunctionBlock)(jsi::Runtime &runtime, std::shared_ptr<react::CallInvoker> callInvoker, NSArray<EXJavaScriptValue *> * _Nonnull arguments);
28
+ typedef jsi::Value (^JSHostFunctionBlock)(jsi::Runtime &runtime,
29
+ std::shared_ptr<react::CallInvoker> callInvoker,
30
+ EXJavaScriptValue * _Nonnull thisValue,
31
+ NSArray<EXJavaScriptValue *> * _Nonnull arguments);
18
32
  #endif // __cplusplus
19
33
 
20
34
  NS_SWIFT_NAME(JavaScriptRuntime)
@@ -26,6 +40,7 @@ NS_SWIFT_NAME(JavaScriptRuntime)
26
40
  - (nonnull instancetype)init;
27
41
 
28
42
  #ifdef __cplusplus
43
+
29
44
  - (nonnull instancetype)initWithRuntime:(nonnull jsi::Runtime *)runtime
30
45
  callInvoker:(std::shared_ptr<react::CallInvoker>)callInvoker;
31
46
 
@@ -44,13 +59,6 @@ NS_SWIFT_NAME(JavaScriptRuntime)
44
59
  */
45
60
  - (nonnull EXJavaScriptObject *)createHostObject:(std::shared_ptr<jsi::HostObject>)jsiHostObjectPtr;
46
61
 
47
- - (jsi::Function)createSyncFunction:(nonnull NSString *)name
48
- argsCount:(NSInteger)argsCount
49
- block:(nonnull JSSyncFunctionBlock)block;
50
-
51
- - (jsi::Function)createAsyncFunction:(nonnull NSString *)name
52
- argsCount:(NSInteger)argsCount
53
- block:(nonnull JSAsyncFunctionBlock)block;
54
62
  #endif // __cplusplus
55
63
 
56
64
  /**
@@ -63,11 +71,37 @@ NS_SWIFT_NAME(JavaScriptRuntime)
63
71
  */
64
72
  - (nonnull EXJavaScriptObject *)createObject;
65
73
 
74
+ /**
75
+ Creates a synchronous host function that runs given block when it's called.
76
+ The value returned by the block is synchronously returned to JS.
77
+ \return A JavaScript function represented as a `JavaScriptObject`.
78
+ */
79
+ - (nonnull EXJavaScriptObject *)createSyncFunction:(nonnull NSString *)name
80
+ argsCount:(NSInteger)argsCount
81
+ block:(nonnull JSSyncFunctionBlock)block NS_REFINED_FOR_SWIFT;
82
+
83
+ /**
84
+ Creates an asynchronous host function that runs given block when it's called.
85
+ The block receives a resolver that you should call when the asynchronous operation
86
+ succeeds and a rejecter to call whenever it fails.
87
+ \return A JavaScript function represented as a `JavaScriptObject`.
88
+ */
89
+ - (nonnull EXJavaScriptObject *)createAsyncFunction:(nonnull NSString *)name
90
+ argsCount:(NSInteger)argsCount
91
+ block:(nonnull JSAsyncFunctionBlock)block;
92
+
93
+ #pragma mark - Classes
94
+
95
+ typedef void (^ClassConstructorBlock)(EXJavaScriptObject * _Nonnull thisValue, NSArray<EXJavaScriptValue *> * _Nonnull arguments);
96
+
97
+ - (nonnull EXJavaScriptObject *)createClass:(nonnull NSString *)name
98
+ constructor:(nonnull ClassConstructorBlock)constructor;
99
+
66
100
  #pragma mark - Script evaluation
67
101
 
68
102
  /**
69
103
  Evaluates given JavaScript source code.
70
104
  */
71
- - (nonnull EXJavaScriptValue *)evaluateScript:(nonnull NSString *)scriptSource;
105
+ - (nonnull EXJavaScriptValue *)evaluateScript:(nonnull NSString *)scriptSource NS_REFINED_FOR_SWIFT;
72
106
 
73
107
  @end
@@ -82,33 +82,66 @@ using namespace facebook;
82
82
  return [[EXJavaScriptObject alloc] initWith:jsGlobalPtr runtime:self];
83
83
  }
84
84
 
85
- - (jsi::Function)createSyncFunction:(nonnull NSString *)name
86
- argsCount:(NSInteger)argsCount
87
- block:(nonnull JSSyncFunctionBlock)block
85
+ - (nonnull EXJavaScriptObject *)createSyncFunction:(nonnull NSString *)name
86
+ argsCount:(NSInteger)argsCount
87
+ block:(nonnull JSSyncFunctionBlock)block
88
88
  {
89
- return [self createHostFunction:name argsCount:argsCount block:^jsi::Value(jsi::Runtime &runtime, std::shared_ptr<react::CallInvoker> callInvoker, NSArray * _Nonnull arguments) {
90
- return expo::convertObjCObjectToJSIValue(runtime, block(arguments));
91
- }];
89
+ JSHostFunctionBlock hostFunctionBlock = ^jsi::Value(
90
+ jsi::Runtime &runtime,
91
+ std::shared_ptr<react::CallInvoker> callInvoker,
92
+ EXJavaScriptValue * _Nonnull thisValue,
93
+ NSArray<EXJavaScriptValue *> * _Nonnull arguments) {
94
+ NSError *error;
95
+ id result = block(thisValue, arguments, &error);
96
+
97
+ if (error == nil) {
98
+ return expo::convertObjCObjectToJSIValue(runtime, result);
99
+ } else {
100
+ throw jsi::JSError(runtime, [error.userInfo[@"message"] UTF8String]);
101
+ }
102
+ };
103
+ return [self createHostFunction:name argsCount:argsCount block:hostFunctionBlock];
92
104
  }
93
105
 
94
- - (jsi::Function)createAsyncFunction:(nonnull NSString *)name
95
- argsCount:(NSInteger)argsCount
96
- block:(nonnull JSAsyncFunctionBlock)block
106
+ - (nonnull EXJavaScriptObject *)createAsyncFunction:(nonnull NSString *)name
107
+ argsCount:(NSInteger)argsCount
108
+ block:(nonnull JSAsyncFunctionBlock)block
97
109
  {
98
- return [self createHostFunction:name argsCount:argsCount block:^jsi::Value(jsi::Runtime &runtime, std::shared_ptr<react::CallInvoker> callInvoker, NSArray *arguments) {
99
- if (!callInvoker) {
100
- // In mocked environment the call invoker may be null so it's not supported to call async functions.
101
- // Testing async functions is a bit more complicated anyway. See `init` description for more.
102
- throw jsi::JSError(runtime, "Calling async functions is not supported when the call invoker is unavailable");
103
- }
104
- // The function that is invoked as a setup of the EXJavaScript `Promise`.
105
- auto promiseSetup = [callInvoker, block, arguments](jsi::Runtime &runtime, std::shared_ptr<Promise> promise) {
106
- expo::callPromiseSetupWithBlock(runtime, callInvoker, promise, ^(RCTPromiseResolveBlock resolver, RCTPromiseRejectBlock rejecter) {
107
- block(arguments, resolver, rejecter);
108
- });
110
+ JSHostFunctionBlock hostFunctionBlock = ^jsi::Value(
111
+ jsi::Runtime &runtime,
112
+ std::shared_ptr<react::CallInvoker> callInvoker,
113
+ EXJavaScriptValue * _Nonnull thisValue,
114
+ NSArray<EXJavaScriptValue *> * _Nonnull arguments) {
115
+ if (!callInvoker) {
116
+ // In mocked environment the call invoker may be null so it's not supported to call async functions.
117
+ // Testing async functions is a bit more complicated anyway. See `init` description for more.
118
+ throw jsi::JSError(runtime, "Calling async functions is not supported when the call invoker is unavailable");
119
+ }
120
+ // The function that is invoked as a setup of the EXJavaScript `Promise`.
121
+ auto promiseSetup = [callInvoker, block, thisValue, arguments](jsi::Runtime &runtime, std::shared_ptr<Promise> promise) {
122
+ expo::callPromiseSetupWithBlock(runtime, callInvoker, promise, ^(RCTPromiseResolveBlock resolver, RCTPromiseRejectBlock rejecter) {
123
+ block(thisValue, arguments, resolver, rejecter);
124
+ });
125
+ };
126
+ return createPromiseAsJSIValue(runtime, promiseSetup);
109
127
  };
110
- return createPromiseAsJSIValue(runtime, promiseSetup);
111
- }];
128
+ return [self createHostFunction:name argsCount:argsCount block:hostFunctionBlock];
129
+ }
130
+
131
+ #pragma mark - Classes
132
+
133
+ - (nonnull EXJavaScriptObject *)createClass:(nonnull NSString *)name
134
+ constructor:(nonnull ClassConstructorBlock)constructor
135
+ {
136
+ expo::ClassConstructor jsConstructor = [self, constructor](jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *args, size_t count) {
137
+ std::shared_ptr<jsi::Object> thisPtr = std::make_shared<jsi::Object>(thisValue.asObject(runtime));
138
+ EXJavaScriptObject *caller = [[EXJavaScriptObject alloc] initWith:thisPtr runtime:self];
139
+ NSArray<EXJavaScriptValue *> *arguments = expo::convertJSIValuesToNSArray(self, args, count);
140
+
141
+ constructor(caller, arguments);
142
+ };
143
+ std::shared_ptr<jsi::Function> klass = expo::createClass(*_runtime, [name UTF8String], jsConstructor);
144
+ return [[EXJavaScriptObject alloc] initWith:klass runtime:self];
112
145
  }
113
146
 
114
147
  #pragma mark - Script evaluation
@@ -128,15 +161,21 @@ using namespace facebook;
128
161
  @"message": reason,
129
162
  @"stack": stack,
130
163
  }];
164
+ } catch (jsi::JSIException &error) {
165
+ NSString *reason = [NSString stringWithUTF8String:error.what()];
166
+
167
+ @throw [NSException exceptionWithName:@"ScriptEvaluationException" reason:reason userInfo:@{
168
+ @"message": reason
169
+ }];
131
170
  }
132
171
  return [[EXJavaScriptValue alloc] initWithRuntime:self value:result];
133
172
  }
134
173
 
135
174
  #pragma mark - Private
136
175
 
137
- - (jsi::Function)createHostFunction:(nonnull NSString *)name
138
- argsCount:(NSInteger)argsCount
139
- block:(nonnull JSHostFunctionBlock)block
176
+ - (nonnull EXJavaScriptObject *)createHostFunction:(nonnull NSString *)name
177
+ argsCount:(NSInteger)argsCount
178
+ block:(nonnull JSHostFunctionBlock)block
140
179
  {
141
180
  jsi::PropNameID propNameId = jsi::PropNameID::forAscii(*_runtime, [name UTF8String], [name length]);
142
181
  std::weak_ptr<react::CallInvoker> weakCallInvoker = _jsCallInvoker;
@@ -145,9 +184,13 @@ using namespace facebook;
145
184
  // there is no need to care about that for synchronous calls, so it's ensured in `createAsyncFunction` instead.
146
185
  auto callInvoker = weakCallInvoker.lock();
147
186
  NSArray<EXJavaScriptValue *> *arguments = expo::convertJSIValuesToNSArray(self, args, count);
148
- return block(runtime, callInvoker, arguments);
187
+ std::shared_ptr<jsi::Value> thisValPtr = std::make_shared<jsi::Value>(runtime, std::move(thisVal));
188
+ EXJavaScriptValue *thisValue = [[EXJavaScriptValue alloc] initWithRuntime:self value:thisValPtr];
189
+
190
+ return block(runtime, callInvoker, thisValue, arguments);
149
191
  };
150
- return jsi::Function::createFromHostFunction(*_runtime, propNameId, (unsigned int)argsCount, function);
192
+ std::shared_ptr<jsi::Object> fnPtr = std::make_shared<jsi::Object>(jsi::Function::createFromHostFunction(*_runtime, propNameId, (unsigned int)argsCount, function));
193
+ return [[EXJavaScriptObject alloc] initWith:fnPtr runtime:self];
151
194
  }
152
195
 
153
196
  @end