1// Copyright 2022-present 650 Industries. All rights reserved. 2 3#import <ExpoModulesCore/EXJSIConversions.h> 4#import <ExpoModulesCore/EXJavaScriptValue.h> 5#import <ExpoModulesCore/EXJavaScriptObject.h> 6#import <ExpoModulesCore/EXJavaScriptRuntime.h> 7#import <ExpoModulesCore/EXJavaScriptWeakObject.h> 8#import <ExpoModulesCore/EXJSIUtils.h> 9#import <ExpoModulesCore/JSIUtils.h> 10 11@implementation EXJavaScriptObject { 12 /** 13 Pointer to the `EXJavaScriptRuntime` wrapper. 14 15 \note It must be weak because only then the original runtime can be safely deallocated 16 when the JS engine wants to without unsetting it on each created object. 17 */ 18 __weak EXJavaScriptRuntime *_runtime; 19 20 /** 21 Shared pointer to the original JSI object that is being wrapped by `EXJavaScriptObject` class. 22 */ 23 std::shared_ptr<jsi::Object> _jsObjectPtr; 24} 25 26- (nonnull instancetype)initWith:(std::shared_ptr<jsi::Object>)jsObjectPtr 27 runtime:(nonnull EXJavaScriptRuntime *)runtime 28{ 29 if (self = [super init]) { 30 _runtime = runtime; 31 _jsObjectPtr = jsObjectPtr; 32 } 33 return self; 34} 35 36- (nonnull jsi::Object *)get 37{ 38 return _jsObjectPtr.get(); 39} 40 41- (std::shared_ptr<jsi::Object>)getShared 42{ 43 return _jsObjectPtr; 44} 45 46#pragma mark - Accessing object properties 47 48- (BOOL)hasProperty:(nonnull NSString *)name 49{ 50 return _jsObjectPtr->hasProperty(*[_runtime get], [name UTF8String]); 51} 52 53- (nonnull EXJavaScriptValue *)getProperty:(nonnull NSString *)name 54{ 55 std::shared_ptr<jsi::Value> value = std::make_shared<jsi::Value>(_jsObjectPtr->getProperty(*[_runtime get], [name UTF8String])); 56 return [[EXJavaScriptValue alloc] initWithRuntime:_runtime value:value]; 57} 58 59- (nonnull NSArray<NSString *> *)getPropertyNames 60{ 61 jsi::Runtime *runtime = [_runtime get]; 62 jsi::Array propertyNamesArray = _jsObjectPtr->getPropertyNames(*[_runtime get]); 63 return expo::convertJSIArrayToNSArray(*runtime, propertyNamesArray, nullptr); 64} 65 66#pragma mark - Modifying object properties 67 68- (void)setProperty:(nonnull NSString *)name value:(nullable id)value 69{ 70 jsi::Value jsiValue = expo::convertObjCObjectToJSIValue(*[_runtime get], value); 71 _jsObjectPtr->setProperty(*[_runtime get], [name UTF8String], jsiValue); 72} 73 74- (void)defineProperty:(nonnull NSString *)name descriptor:(nonnull EXJavaScriptObject *)descriptor 75{ 76 jsi::Runtime *runtime = [_runtime get]; 77 jsi::Object *jsThis = _jsObjectPtr.get(); 78 79 expo::common::definePropertyOnJSIObject(*runtime, jsThis, [name UTF8String], std::move(*[descriptor get])); 80} 81 82- (void)defineProperty:(nonnull NSString *)name value:(nullable id)value options:(EXJavaScriptObjectPropertyDescriptor)options 83{ 84 jsi::Runtime *runtime = [_runtime get]; 85 jsi::Object *jsThis = _jsObjectPtr.get(); 86 87 jsi::Object descriptor = [self preparePropertyDescriptorWithOptions:options]; 88 descriptor.setProperty(*runtime, "value", expo::convertObjCObjectToJSIValue(*runtime, value)); 89 90 expo::common::definePropertyOnJSIObject(*runtime, jsThis, [name UTF8String], std::move(descriptor)); 91} 92 93#pragma mark - WeakObject 94 95- (nonnull EXJavaScriptWeakObject *)createWeak 96{ 97 return [[EXJavaScriptWeakObject alloc] initWith:_jsObjectPtr runtime:_runtime]; 98} 99 100#pragma mark - Deallocator 101 102- (void)setObjectDeallocator:(void (^)(void))deallocatorBlock 103{ 104 expo::common::setDeallocator(*[_runtime get], _jsObjectPtr, deallocatorBlock); 105} 106 107#pragma mark - Equality 108 109- (BOOL)isEqual:(id)object 110{ 111 if ([object isKindOfClass:EXJavaScriptObject.class]) { 112 jsi::Runtime *runtime = [_runtime get]; 113 jsi::Object *a = _jsObjectPtr.get(); 114 jsi::Object *b = [object get]; 115 return jsi::Object::strictEquals(*runtime, *a, *b); 116 } 117 return false; 118} 119 120#pragma mark - Private helpers 121 122- (jsi::Object)preparePropertyDescriptorWithOptions:(EXJavaScriptObjectPropertyDescriptor)options 123{ 124 jsi::Runtime *runtime = [_runtime get]; 125 jsi::Object descriptor(*runtime); 126 descriptor.setProperty(*runtime, "configurable", (bool)(options & EXJavaScriptObjectPropertyDescriptorConfigurable)); 127 descriptor.setProperty(*runtime, "enumerable", (bool)(options & EXJavaScriptObjectPropertyDescriptorEnumerable)); 128 descriptor.setProperty(*runtime, "writable", (bool)(options & EXJavaScriptObjectPropertyDescriptorWritable)); 129 return descriptor; 130} 131 132@end 133