expo-modules-core 0.7.0 → 0.9.1

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 (129) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +1 -1
  3. package/android/ExpoModulesCorePlugin.gradle +15 -0
  4. package/android/build.gradle +46 -32
  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 +13 -5
  13. package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +2 -13
  14. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +11 -5
  15. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +5 -1
  16. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +17 -0
  17. package/android/src/main/java/expo/modules/kotlin/callbacks/ViewCallback.kt +14 -3
  18. package/android/src/main/java/expo/modules/kotlin/events/EventEmitter.kt +13 -0
  19. package/android/src/main/java/expo/modules/kotlin/events/KModuleEventEmitterWrapper.kt +102 -0
  20. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +25 -1
  21. package/android/src/main/java/expo/modules/kotlin/{methods/AnyMethod.kt → functions/AnyFunction.kt} +6 -5
  22. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +15 -0
  23. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +170 -0
  24. package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromise.kt +15 -0
  25. package/android/src/main/java/expo/modules/kotlin/functions/AsyncSuspendFunction.kt +36 -0
  26. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +14 -0
  27. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +374 -41
  28. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +2 -2
  29. package/android/src/main/java/expo/modules/kotlin/records/FieldValidator.kt +139 -0
  30. package/android/src/main/java/expo/modules/kotlin/records/Record.kt +0 -39
  31. package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +59 -10
  32. package/android/src/main/java/expo/modules/kotlin/records/Required.kt +5 -0
  33. package/android/src/main/java/expo/modules/kotlin/records/ValidationBinder.kt +110 -0
  34. package/android/src/main/java/expo/modules/kotlin/records/Validators.kt +61 -0
  35. package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverter.kt +35 -0
  36. package/android/src/main/java/expo/modules/kotlin/types/JSTypeConverterHelper.kt +148 -0
  37. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +9 -1
  38. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +49 -0
  39. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinition.kt +18 -0
  40. package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +114 -0
  41. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +4 -1
  42. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +56 -5
  43. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +3 -0
  44. package/build/NativeModulesProxy.native.d.ts +0 -4
  45. package/build/NativeModulesProxy.native.d.ts.map +1 -1
  46. package/build/NativeModulesProxy.native.js +1 -14
  47. package/build/NativeModulesProxy.native.js.map +1 -1
  48. package/build/NativeModulesProxy.types.d.ts +0 -3
  49. package/build/NativeModulesProxy.types.d.ts.map +1 -1
  50. package/build/NativeModulesProxy.types.js.map +1 -1
  51. package/build/NativeViewManagerAdapter.native.d.ts.map +1 -1
  52. package/build/NativeViewManagerAdapter.native.js +9 -33
  53. package/build/NativeViewManagerAdapter.native.js.map +1 -1
  54. package/build/sweet/NativeErrorManager.js +1 -1
  55. package/build/sweet/NativeErrorManager.js.map +1 -1
  56. package/ios/AppDelegates/EXAppDelegatesLoader.m +4 -8
  57. package/ios/AppDelegates/ExpoAppDelegate.swift +4 -10
  58. package/ios/EXAppDefines.h +1 -0
  59. package/ios/EXAppDefines.m +6 -0
  60. package/ios/EXUtilities.h +2 -0
  61. package/ios/EXUtilities.m +12 -0
  62. package/ios/ExpoModulesCore.h +4 -0
  63. package/ios/ExpoModulesCore.podspec +4 -2
  64. package/ios/Interfaces/FileSystem/EXFileSystemInterface.h +1 -1
  65. package/ios/Interfaces/TaskManager/EXTaskServiceInterface.h +1 -0
  66. package/ios/JSI/{JSIConversions.h → EXJSIConversions.h} +4 -1
  67. package/ios/JSI/{JSIConversions.mm → EXJSIConversions.mm} +16 -5
  68. package/ios/JSI/{JSIInstaller.h → EXJSIInstaller.h} +3 -3
  69. package/ios/JSI/EXJSIInstaller.mm +17 -0
  70. package/ios/JSI/{ExpoModulesProxySpec.h → EXJSIUtils.h} +0 -9
  71. package/ios/JSI/{ExpoModulesProxySpec.mm → EXJSIUtils.mm} +4 -48
  72. package/ios/JSI/EXJavaScriptObject.h +97 -0
  73. package/ios/JSI/EXJavaScriptObject.mm +121 -0
  74. package/ios/JSI/{JavaScriptRuntime.h → EXJavaScriptRuntime.h} +27 -8
  75. package/ios/JSI/EXJavaScriptRuntime.mm +153 -0
  76. package/ios/JSI/EXJavaScriptValue.h +57 -0
  77. package/ios/JSI/EXJavaScriptValue.mm +166 -0
  78. package/ios/JSI/ExpoModulesHostObject.mm +2 -1
  79. package/ios/JSI/JavaScriptRuntime.swift +32 -0
  80. package/ios/JSI/JavaScriptValue.swift +94 -0
  81. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +1 -11
  82. package/ios/NativeModulesProxy/EXNativeModulesProxy.h +2 -2
  83. package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +24 -22
  84. package/ios/ReactDelegates/EXReactCompatibleHelpers.h +18 -0
  85. package/ios/ReactDelegates/EXReactCompatibleHelpers.m +19 -0
  86. package/ios/ReactDelegates/ExpoReactDelegate.swift +2 -2
  87. package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +1 -1
  88. package/ios/Swift/AppContext.swift +21 -2
  89. package/ios/Swift/Arguments/AnyArgumentType.swift +1 -1
  90. package/ios/Swift/Functions/AnyFunction.swift +5 -0
  91. package/ios/Swift/Functions/AsyncFunctionComponent.swift +182 -0
  92. package/ios/Swift/Functions/ConcreteFunction.swift +40 -68
  93. package/ios/Swift/Functions/SyncFunctionComponent.swift +181 -0
  94. package/ios/Swift/JavaScriptUtils.swift +56 -0
  95. package/ios/Swift/ModuleHolder.swift +17 -5
  96. package/ios/Swift/Modules/ModuleDefinitionComponents.swift +66 -44
  97. package/ios/Swift/ModulesProvider.swift +3 -10
  98. package/ios/Swift/Objects/ObjectDefinitionComponents.swift +49 -0
  99. package/ios/Swift/SwiftInteropBridge.swift +14 -5
  100. package/ios/Swift/Views/ComponentData.swift +2 -1
  101. package/ios/Swift/Views/ExpoView.swift +8 -0
  102. package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +23 -0
  103. package/ios/Swift.h +5 -0
  104. package/ios/Tests/ArgumentTypeSpec.swift +2 -3
  105. package/ios/Tests/ConstantsSpec.swift +6 -7
  106. package/ios/Tests/ConvertiblesSpec.swift +2 -3
  107. package/ios/Tests/ExceptionsSpec.swift +2 -3
  108. package/ios/Tests/ExpoModulesSpec.swift +75 -0
  109. package/ios/Tests/FunctionSpec.swift +13 -15
  110. package/ios/Tests/FunctionWithConvertiblesSpec.swift +4 -5
  111. package/ios/Tests/JavaScriptObjectSpec.swift +97 -0
  112. package/ios/Tests/JavaScriptRuntimeSpec.swift +94 -0
  113. package/ios/Tests/ModuleEventListenersSpec.swift +15 -16
  114. package/ios/Tests/ModuleRegistrySpec.swift +2 -3
  115. package/ios/Tests/RecordSpec.swift +2 -3
  116. package/package.json +2 -2
  117. package/src/NativeModulesProxy.native.ts +2 -22
  118. package/src/NativeModulesProxy.types.ts +0 -8
  119. package/src/NativeViewManagerAdapter.native.tsx +12 -28
  120. package/src/sweet/NativeErrorManager.ts +1 -1
  121. package/android/src/main/java/expo/modules/kotlin/events/KEventEmitterWrapper.kt +0 -26
  122. package/android/src/main/java/expo/modules/kotlin/methods/Method.kt +0 -14
  123. package/android/src/main/java/expo/modules/kotlin/methods/PromiseMethod.kt +0 -15
  124. package/ios/JSI/JSIInstaller.mm +0 -34
  125. package/ios/JSI/JavaScriptObject.h +0 -60
  126. package/ios/JSI/JavaScriptObject.mm +0 -93
  127. package/ios/JSI/JavaScriptRuntime.mm +0 -102
  128. package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.h +0 -16
  129. package/ios/NativeModulesProxy/EXComponentDataCompatibleWrapper.m +0 -28
@@ -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,7 +34,7 @@ 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
 
34
- NSArray *convertJSIValuesToNSArray(jsi::Runtime &runtime, const jsi::Value *values, size_t count, std::shared_ptr<CallInvoker> jsInvoker);
37
+ NSArray<EXJavaScriptValue *> *convertJSIValuesToNSArray(EXJavaScriptRuntime *runtime, const jsi::Value *values, size_t count);
35
38
 
36
39
  NSDictionary *convertJSIObjectToNSDictionary(jsi::Runtime &runtime, const jsi::Object &value, std::shared_ptr<CallInvoker> jsInvoker);
37
40
 
@@ -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,13 +94,16 @@ NSArray *convertJSIArrayToNSArray(jsi::Runtime &runtime, const jsi::Array &value
86
94
  return [result copy];
87
95
  }
88
96
 
89
- NSArray *convertJSIValuesToNSArray(jsi::Runtime &runtime, const jsi::Value *values, size_t count, std::shared_ptr<CallInvoker> jsInvoker)
97
+ NSArray<EXJavaScriptValue *> *convertJSIValuesToNSArray(EXJavaScriptRuntime *runtime, const jsi::Value *values, size_t count)
90
98
  {
91
- NSMutableArray *result = [NSMutableArray arrayWithCapacity:count];
99
+ NSMutableArray<EXJavaScriptValue *> *array = [NSMutableArray arrayWithCapacity:count];
100
+ jsi::Runtime *jsiRuntime = [runtime get];
101
+
92
102
  for (int i = 0; i < count; i++) {
93
- result[i] = convertJSIValueToObjCObject(runtime, values[i], jsInvoker);
103
+ std::shared_ptr<jsi::Value> value = std::make_shared<jsi::Value>(*jsiRuntime, values[i]);
104
+ array[i] = [[EXJavaScriptValue alloc] initWithRuntime:runtime value:value];
94
105
  }
95
- return result;
106
+ return array;
96
107
  }
97
108
 
98
109
  NSDictionary *convertJSIObjectToNSDictionary(jsi::Runtime &runtime, const jsi::Object &value, std::shared_ptr<CallInvoker> jsInvoker)
@@ -18,12 +18,12 @@ void installRuntimeObjects(jsi::Runtime &runtime, std::shared_ptr<CallInvoker> c
18
18
 
19
19
  #endif
20
20
 
21
- #import <ExpoModulesCore/JavaScriptRuntime.h>
21
+ #import <ExpoModulesCore/EXJavaScriptRuntime.h>
22
22
 
23
23
  @class SwiftInteropBridge;
24
24
 
25
- @interface JavaScriptRuntimeManager : NSObject
25
+ @interface EXJavaScriptRuntimeManager : NSObject
26
26
 
27
- + (void)installExpoModulesToRuntime:(nonnull JavaScriptRuntime *)runtime withSwiftInterop:(nonnull SwiftInteropBridge *)swiftInterop;
27
+ + (void)installExpoModulesToRuntime:(nonnull EXJavaScriptRuntime *)runtime withSwiftInterop:(nonnull SwiftInteropBridge *)swiftInterop;
28
28
 
29
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
@@ -5,8 +5,6 @@
5
5
  #import <jsi/jsi.h>
6
6
  #import <ReactCommon/RCTTurboModule.h>
7
7
 
8
- #import <ExpoModulesCore/EXNativeModulesProxy.h>
9
-
10
8
  using namespace facebook;
11
9
  using namespace react;
12
10
 
@@ -16,13 +14,6 @@ using PromiseInvocationBlock = void (^)(RCTPromiseResolveBlock resolveWrapper, R
16
14
 
17
15
  void callPromiseSetupWithBlock(jsi::Runtime &runtime, std::shared_ptr<CallInvoker> jsInvoker, std::shared_ptr<Promise> promise, PromiseInvocationBlock setupBlock);
18
16
 
19
- class JSI_EXPORT ExpoModulesProxySpec : public TurboModule {
20
- public:
21
- ExpoModulesProxySpec(std::shared_ptr<CallInvoker> callInvoker, EXNativeModulesProxy *nativeModulesProxy);
22
-
23
- EXNativeModulesProxy *nativeModulesProxy;
24
- };
25
-
26
17
  } // namespace expo
27
18
 
28
19
  #endif
@@ -1,9 +1,10 @@
1
- // Copyright 2018-present 650 Industries. All rights reserved.
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
2
 
3
3
  #import <React/RCTUtils.h>
4
+ #import <ExpoModulesCore/EXJSIConversions.h>
5
+ #import <ExpoModulesCore/EXJSIUtils.h>
4
6
 
5
- #import <ExpoModulesCore/JSIConversions.h>
6
- #import <ExpoModulesCore/ExpoModulesProxySpec.h>
7
+ using namespace facebook;
7
8
 
8
9
  namespace expo {
9
10
 
@@ -85,49 +86,4 @@ void callPromiseSetupWithBlock(jsi::Runtime &runtime, std::shared_ptr<CallInvoke
85
86
  setupBlock(resolveBlock, rejectBlock);
86
87
  }
87
88
 
88
- static jsi::Value __hostFunction_ExpoModulesProxySpec_callMethodAsync(jsi::Runtime &runtime, TurboModule &turboModule, const jsi::Value *args, size_t count)
89
- {
90
- auto expoModulesProxy = static_cast<ExpoModulesProxySpec *>(&turboModule);
91
-
92
- // The function that is invoked as a setup of the JS `Promise`.
93
- auto promiseSetupFunc = [expoModulesProxy, args](jsi::Runtime &runtime, std::shared_ptr<Promise> promise) {
94
- callPromiseSetupWithBlock(runtime, expoModulesProxy->jsInvoker_, promise, ^(RCTPromiseResolveBlock resolver, RCTPromiseRejectBlock rejecter) {
95
- NSString *moduleName = convertJSIStringToNSString(runtime, args[0].getString(runtime));
96
- NSString *methodName = convertJSIStringToNSString(runtime, args[1].getString(runtime));
97
- NSArray *arguments = convertJSIArrayToNSArray(runtime, args[2].getObject(runtime).asArray(runtime), expoModulesProxy->jsInvoker_);
98
-
99
- [expoModulesProxy->nativeModulesProxy callMethod:moduleName
100
- methodNameOrKey:methodName
101
- arguments:arguments
102
- resolver:resolver
103
- rejecter:rejecter];
104
- });
105
- };
106
-
107
- return createPromiseAsJSIValue(runtime, promiseSetupFunc);
108
- }
109
-
110
- static jsi::Value __hostFunction_ExpoModulesProxySpec_callMethodSync(jsi::Runtime &runtime, TurboModule &turboModule, const jsi::Value *args, size_t count)
111
- {
112
- auto expoModulesProxy = static_cast<ExpoModulesProxySpec *>(&turboModule);
113
- NSString *moduleName = convertJSIStringToNSString(runtime, args[0].getString(runtime));
114
- NSString *methodName = convertJSIStringToNSString(runtime, args[1].getString(runtime));
115
- NSArray *arguments = convertJSIArrayToNSArray(runtime, args[2].getObject(runtime).asArray(runtime), expoModulesProxy->jsInvoker_);
116
-
117
- id result = [expoModulesProxy->nativeModulesProxy callMethodSync:moduleName
118
- methodName:methodName
119
- arguments:arguments];
120
-
121
- return convertObjCObjectToJSIValue(runtime, result);
122
- }
123
-
124
- ExpoModulesProxySpec::ExpoModulesProxySpec(std::shared_ptr<CallInvoker> callInvoker, EXNativeModulesProxy *nativeModulesProxy) :
125
- TurboModule("ExpoModulesProxy", callInvoker),
126
- nativeModulesProxy(nativeModulesProxy)
127
- {
128
- methodMap_["callMethodAsync"] = MethodMetadata {3, __hostFunction_ExpoModulesProxySpec_callMethodAsync};
129
-
130
- methodMap_["callMethodSync"] = MethodMetadata {3, __hostFunction_ExpoModulesProxySpec_callMethodSync};
131
- }
132
-
133
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
@@ -1,6 +1,7 @@
1
1
  // Copyright 2018-present 650 Industries. All rights reserved.
2
2
 
3
- #import <ExpoModulesCore/JavaScriptObject.h>
3
+ #import <ExpoModulesCore/EXJavaScriptValue.h>
4
+ #import <ExpoModulesCore/EXJavaScriptObject.h>
4
5
 
5
6
  #ifdef __cplusplus
6
7
  #import <ReactCommon/CallInvoker.h>
@@ -9,12 +10,23 @@ namespace jsi = facebook::jsi;
9
10
  namespace react = facebook::react;
10
11
  #endif // __cplusplus
11
12
 
12
- @interface JavaScriptRuntime : NSObject
13
+ @class EXJavaScriptValue;
14
+ @class EXJavaScriptObject;
13
15
 
14
16
  #ifdef __cplusplus
15
- typedef jsi::Value (^JSHostFunctionBlock)(jsi::Runtime &runtime, std::shared_ptr<react::CallInvoker> callInvoker, NSArray * _Nonnull arguments);
17
+ typedef jsi::Value (^JSHostFunctionBlock)(jsi::Runtime &runtime, std::shared_ptr<react::CallInvoker> callInvoker, NSArray<EXJavaScriptValue *> * _Nonnull arguments);
18
+ #endif // __cplusplus
19
+
20
+ NS_SWIFT_NAME(JavaScriptRuntime)
21
+ @interface EXJavaScriptRuntime : NSObject
22
+
23
+ /**
24
+ Creates a new JavaScript runtime.
25
+ */
26
+ - (nonnull instancetype)init;
16
27
 
17
- - (nonnull instancetype)initWithRuntime:(jsi::Runtime &)runtime
28
+ #ifdef __cplusplus
29
+ - (nonnull instancetype)initWithRuntime:(nonnull jsi::Runtime *)runtime
18
30
  callInvoker:(std::shared_ptr<react::CallInvoker>)callInvoker;
19
31
 
20
32
  /**
@@ -28,9 +40,9 @@ typedef jsi::Value (^JSHostFunctionBlock)(jsi::Runtime &runtime, std::shared_ptr
28
40
  - (std::shared_ptr<react::CallInvoker>)callInvoker;
29
41
 
30
42
  /**
31
- Wraps given host object to `JavaScriptObject`.
43
+ Wraps given host object to `EXJavaScriptObject`.
32
44
  */
33
- - (nonnull JavaScriptObject *)createHostObject:(std::shared_ptr<jsi::HostObject>)jsiHostObjectPtr;
45
+ - (nonnull EXJavaScriptObject *)createHostObject:(std::shared_ptr<jsi::HostObject>)jsiHostObjectPtr;
34
46
 
35
47
  - (jsi::Function)createSyncFunction:(nonnull NSString *)name
36
48
  argsCount:(NSInteger)argsCount
@@ -44,11 +56,18 @@ typedef jsi::Value (^JSHostFunctionBlock)(jsi::Runtime &runtime, std::shared_ptr
44
56
  /**
45
57
  Returns the runtime global object for use in Swift.
46
58
  */
47
- - (nonnull JavaScriptObject *)global;
59
+ - (nonnull EXJavaScriptObject *)global;
48
60
 
49
61
  /**
50
62
  Creates a new object for use in Swift.
51
63
  */
52
- - (nonnull JavaScriptObject *)createObject;
64
+ - (nonnull EXJavaScriptObject *)createObject;
65
+
66
+ #pragma mark - Script evaluation
67
+
68
+ /**
69
+ Evaluates given JavaScript source code.
70
+ */
71
+ - (nonnull EXJavaScriptValue *)evaluateScript:(nonnull NSString *)scriptSource;
53
72
 
54
73
  @end
@@ -0,0 +1,153 @@
1
+ // Copyright 2018-present 650 Industries. All rights reserved.
2
+
3
+ #import <jsi/jsi.h>
4
+
5
+ #if __has_include(<reacthermes/HermesExecutorFactory.h>)
6
+ #import <reacthermes/HermesExecutorFactory.h>
7
+ #elif __has_include(<hermes/hermes.h>)
8
+ #import <hermes/hermes.h>
9
+ #else
10
+ #import <jsi/JSCRuntime.h>
11
+ #endif
12
+
13
+ #import <ExpoModulesCore/EXJavaScriptRuntime.h>
14
+ #import <ExpoModulesCore/ExpoModulesHostObject.h>
15
+ #import <ExpoModulesCore/EXJSIUtils.h>
16
+ #import <ExpoModulesCore/EXJSIConversions.h>
17
+ #import <ExpoModulesCore/Swift.h>
18
+
19
+ using namespace facebook;
20
+
21
+ @implementation EXJavaScriptRuntime {
22
+ std::shared_ptr<jsi::Runtime> _runtime;
23
+ std::shared_ptr<react::CallInvoker> _jsCallInvoker;
24
+ }
25
+
26
+ /**
27
+ Initializes a runtime that is independent from React Native and its runtime initialization.
28
+ This flow is mostly intended for tests. The JS call invoker is unavailable thus calling async functions is not supported.
29
+ TODO: Implement the call invoker when it becomes necessary.
30
+ */
31
+ - (nonnull instancetype)init
32
+ {
33
+ if (self = [super init]) {
34
+ #if __has_include(<reacthermes/HermesExecutorFactory.h>) || __has_include(<hermes/hermes.h>)
35
+ _runtime = hermes::makeHermesRuntime();
36
+ #else
37
+ _runtime = jsc::makeJSCRuntime();
38
+ #endif
39
+ _jsCallInvoker = nil;
40
+ }
41
+ return self;
42
+ }
43
+
44
+ - (nonnull instancetype)initWithRuntime:(nonnull jsi::Runtime *)runtime
45
+ callInvoker:(std::shared_ptr<react::CallInvoker>)callInvoker
46
+ {
47
+ if (self = [super init]) {
48
+ // Creating a shared pointer that points to the runtime but doesn't own it, thus doesn't release it.
49
+ // In this code flow, the runtime should be owned by something else like the RCTBridge.
50
+ // See explanation for constructor (8): https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr
51
+ _runtime = std::shared_ptr<jsi::Runtime>(std::shared_ptr<jsi::Runtime>(), runtime);
52
+ _jsCallInvoker = callInvoker;
53
+ }
54
+ return self;
55
+ }
56
+
57
+ - (nonnull jsi::Runtime *)get
58
+ {
59
+ return _runtime.get();
60
+ }
61
+
62
+ - (std::shared_ptr<react::CallInvoker>)callInvoker
63
+ {
64
+ return _jsCallInvoker;
65
+ }
66
+
67
+ - (nonnull EXJavaScriptObject *)createObject
68
+ {
69
+ auto jsObjectPtr = std::make_shared<jsi::Object>(*_runtime);
70
+ return [[EXJavaScriptObject alloc] initWith:jsObjectPtr runtime:self];
71
+ }
72
+
73
+ - (nonnull EXJavaScriptObject *)createHostObject:(std::shared_ptr<jsi::HostObject>)jsiHostObjectPtr
74
+ {
75
+ auto jsObjectPtr = std::make_shared<jsi::Object>(jsi::Object::createFromHostObject(*_runtime, jsiHostObjectPtr));
76
+ return [[EXJavaScriptObject alloc] initWith:jsObjectPtr runtime:self];
77
+ }
78
+
79
+ - (nonnull EXJavaScriptObject *)global
80
+ {
81
+ auto jsGlobalPtr = std::make_shared<jsi::Object>(_runtime->global());
82
+ return [[EXJavaScriptObject alloc] initWith:jsGlobalPtr runtime:self];
83
+ }
84
+
85
+ - (jsi::Function)createSyncFunction:(nonnull NSString *)name
86
+ argsCount:(NSInteger)argsCount
87
+ block:(nonnull JSSyncFunctionBlock)block
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
+ }];
92
+ }
93
+
94
+ - (jsi::Function)createAsyncFunction:(nonnull NSString *)name
95
+ argsCount:(NSInteger)argsCount
96
+ block:(nonnull JSAsyncFunctionBlock)block
97
+ {
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
+ });
109
+ };
110
+ return createPromiseAsJSIValue(runtime, promiseSetup);
111
+ }];
112
+ }
113
+
114
+ #pragma mark - Script evaluation
115
+
116
+ - (nonnull EXJavaScriptValue *)evaluateScript:(nonnull NSString *)scriptSource
117
+ {
118
+ std::shared_ptr<jsi::StringBuffer> scriptBuffer = std::make_shared<jsi::StringBuffer>([scriptSource UTF8String]);
119
+ std::shared_ptr<jsi::Value> result;
120
+
121
+ try {
122
+ result = std::make_shared<jsi::Value>(_runtime->evaluateJavaScript(scriptBuffer, "<<evaluated>>"));
123
+ } catch (jsi::JSError &error) {
124
+ NSString *reason = [NSString stringWithUTF8String:error.getMessage().c_str()];
125
+ NSString *stack = [NSString stringWithUTF8String:error.getStack().c_str()];
126
+
127
+ @throw [NSException exceptionWithName:@"ScriptEvaluationException" reason:reason userInfo:@{
128
+ @"message": reason,
129
+ @"stack": stack,
130
+ }];
131
+ }
132
+ return [[EXJavaScriptValue alloc] initWithRuntime:self value:result];
133
+ }
134
+
135
+ #pragma mark - Private
136
+
137
+ - (jsi::Function)createHostFunction:(nonnull NSString *)name
138
+ argsCount:(NSInteger)argsCount
139
+ block:(nonnull JSHostFunctionBlock)block
140
+ {
141
+ jsi::PropNameID propNameId = jsi::PropNameID::forAscii(*_runtime, [name UTF8String], [name length]);
142
+ std::weak_ptr<react::CallInvoker> weakCallInvoker = _jsCallInvoker;
143
+ jsi::HostFunctionType function = [weakCallInvoker, block, self](jsi::Runtime &runtime, const jsi::Value &thisVal, const jsi::Value *args, size_t count) -> jsi::Value {
144
+ // Theoretically should check here whether the call invoker isn't null, but in mocked environment
145
+ // there is no need to care about that for synchronous calls, so it's ensured in `createAsyncFunction` instead.
146
+ auto callInvoker = weakCallInvoker.lock();
147
+ NSArray<EXJavaScriptValue *> *arguments = expo::convertJSIValuesToNSArray(self, args, count);
148
+ return block(runtime, callInvoker, arguments);
149
+ };
150
+ return jsi::Function::createFromHostFunction(*_runtime, propNameId, (unsigned int)argsCount, function);
151
+ }
152
+
153
+ @end