1// Copyright 2022-present 650 Industries. All rights reserved.
2
3#import <ExpoModulesCore/EXJSIConversions.h>
4#import <ExpoModulesCore/EXJavaScriptValue.h>
5#import <ExpoModulesCore/EXJavaScriptRuntime.h>
6#import <ExpoModulesCore/EXRawJavaScriptFunction.h>
7#import <ExpoModulesCore/EXJavaScriptTypedArray.h>
8#import <ExpoModulesCore/TypedArray.h>
9
10@implementation EXJavaScriptValue {
11  __weak EXJavaScriptRuntime *_runtime;
12  std::shared_ptr<jsi::Value> _value;
13}
14
15- (nonnull instancetype)initWithRuntime:(nonnull EXJavaScriptRuntime *)runtime
16                                  value:(std::shared_ptr<jsi::Value>)value
17{
18  if (self = [super init]) {
19    _runtime = runtime;
20    _value = value;
21  }
22  return self;
23}
24
25- (nonnull jsi::Value *)get
26{
27  return _value.get();
28}
29
30#pragma mark - Type checking
31
32- (BOOL)isUndefined
33{
34  return _value->isUndefined();
35}
36
37- (BOOL)isNull
38{
39  return _value->isNull();
40}
41
42- (BOOL)isBool
43{
44  return _value->isBool();
45}
46
47- (BOOL)isNumber
48{
49  return _value->isNumber();
50}
51
52- (BOOL)isString
53{
54  return _value->isString();
55}
56
57- (BOOL)isSymbol
58{
59  return _value->isSymbol();
60}
61
62- (BOOL)isObject
63{
64  return _value->isObject();
65}
66
67- (BOOL)isFunction
68{
69  if (_value->isObject()) {
70    jsi::Runtime *runtime = [_runtime get];
71    return _value->getObject(*runtime).isFunction(*runtime);
72  }
73  return false;
74}
75
76- (BOOL)isTypedArray
77{
78  if (_value->isObject()) {
79    jsi::Runtime *runtime = [_runtime get];
80    return expo::isTypedArray(*runtime, _value->getObject(*runtime));
81  }
82  return false;
83}
84
85#pragma mark - Type casting
86
87- (nullable id)getRaw
88{
89  return expo::convertJSIValueToObjCObject(*[_runtime get], *_value, [_runtime callInvoker]);
90}
91
92- (BOOL)getBool
93{
94  return _value->getBool();
95}
96
97- (NSInteger)getInt
98{
99  return _value->getNumber();
100}
101
102- (double)getDouble
103{
104  return _value->getNumber();
105}
106
107- (nonnull NSString *)getString
108{
109  jsi::Runtime *runtime = [_runtime get];
110  return expo::convertJSIStringToNSString(*runtime, _value->getString(*runtime));
111}
112
113- (nonnull NSArray<EXJavaScriptValue *> *)getArray
114{
115  jsi::Runtime *runtime = [_runtime get];
116  jsi::Array jsiArray = _value->getObject(*runtime).getArray(*runtime);
117  size_t arraySize = jsiArray.size(*runtime);
118  NSMutableArray *result = [NSMutableArray arrayWithCapacity:arraySize];
119
120  for (size_t i = 0; i < arraySize; i++) {
121    jsi::Value item = jsiArray.getValueAtIndex(*runtime, i);
122
123    if (item.isUndefined() || item.isNull()) {
124      [result addObject:(id)kCFNull];
125    } else {
126      std::shared_ptr<jsi::Value> valuePtr = std::make_shared<jsi::Value>(*runtime, item);
127      [result addObject:[[EXJavaScriptValue alloc] initWithRuntime:_runtime value:valuePtr]];
128    }
129  }
130  return result;
131}
132
133- (nonnull NSDictionary<NSString *, id> *)getDictionary
134{
135  jsi::Runtime *runtime = [_runtime get];
136  return expo::convertJSIObjectToNSDictionary(*runtime, _value->getObject(*runtime), [_runtime callInvoker]);
137}
138
139- (nonnull EXJavaScriptObject *)getObject
140{
141  jsi::Runtime *runtime = [_runtime get];
142  std::shared_ptr<jsi::Object> objectPtr = std::make_shared<jsi::Object>(_value->asObject(*runtime));
143  return [[EXJavaScriptObject alloc] initWith:objectPtr runtime:_runtime];
144}
145
146- (nonnull EXRawJavaScriptFunction *)getFunction
147{
148  jsi::Runtime *runtime = [_runtime get];
149  std::shared_ptr<jsi::Function> functionPtr = std::make_shared<jsi::Function>(_value->asObject(*runtime).asFunction(*runtime));
150  return [[EXRawJavaScriptFunction alloc] initWith:functionPtr runtime:_runtime];
151}
152
153- (nullable EXJavaScriptTypedArray *)getTypedArray
154{
155  if (![self isTypedArray]) {
156    return nil;
157  }
158  jsi::Runtime *runtime = [_runtime get];
159  std::shared_ptr<jsi::Object> objectPtr = std::make_shared<jsi::Object>(_value->asObject(*runtime));
160  return [[EXJavaScriptTypedArray alloc] initWith:objectPtr runtime:_runtime];
161}
162
163#pragma mark - Helpers
164
165- (nonnull NSString *)toString
166{
167  jsi::Runtime *runtime = [_runtime get];
168  return expo::convertJSIStringToNSString(*runtime, _value->toString(*runtime));
169}
170
171@end
172