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
7@implementation EXJavaScriptValue {
8  __weak EXJavaScriptRuntime *_runtime;
9  std::shared_ptr<jsi::Value> _value;
10}
11
12- (nonnull instancetype)initWithRuntime:(nonnull EXJavaScriptRuntime *)runtime
13                                  value:(std::shared_ptr<jsi::Value>)value
14{
15  if (self = [super init]) {
16    _runtime = runtime;
17    _value = value;
18  }
19  return self;
20}
21
22- (nonnull jsi::Value *)get
23{
24  return _value.get();
25}
26
27#pragma mark - Type checking
28
29- (BOOL)isUndefined
30{
31  return _value->isUndefined();
32}
33
34- (BOOL)isNull
35{
36  return _value->isNull();
37}
38
39- (BOOL)isBool
40{
41  return _value->isBool();
42}
43
44- (BOOL)isNumber
45{
46  return _value->isNumber();
47}
48
49- (BOOL)isString
50{
51  return _value->isString();
52}
53
54- (BOOL)isSymbol
55{
56  return _value->isSymbol();
57}
58
59- (BOOL)isObject
60{
61  return _value->isObject();
62}
63
64- (BOOL)isFunction
65{
66  if (_value->isObject()) {
67    jsi::Runtime *runtime = [_runtime get];
68    return _value->getObject(*runtime).isFunction(*runtime);
69  }
70  return false;
71}
72
73#pragma mark - Type casting
74
75- (nullable id)getRaw
76{
77  return expo::convertJSIValueToObjCObject(*[_runtime get], *_value, [_runtime callInvoker]);
78}
79
80- (BOOL)getBool
81{
82  return _value->getBool();
83}
84
85- (NSInteger)getInt
86{
87  return _value->getNumber();
88}
89
90- (double)getDouble
91{
92  return _value->getNumber();
93}
94
95- (nonnull NSString *)getString
96{
97  jsi::Runtime *runtime = [_runtime get];
98  return expo::convertJSIStringToNSString(*runtime, _value->getString(*runtime));
99}
100
101- (nonnull NSArray<EXJavaScriptValue *> *)getArray
102{
103  jsi::Runtime *runtime = [_runtime get];
104  jsi::Array jsiArray = _value->getObject(*runtime).getArray(*runtime);
105  size_t arraySize = jsiArray.size(*runtime);
106  NSMutableArray *result = [NSMutableArray arrayWithCapacity:arraySize];
107
108  for (size_t i = 0; i < arraySize; i++) {
109    jsi::Value item = jsiArray.getValueAtIndex(*runtime, i);
110
111    if (item.isUndefined() || item.isNull()) {
112      [result addObject:(id)kCFNull];
113    } else {
114      std::shared_ptr<jsi::Value> valuePtr = std::make_shared<jsi::Value>(*runtime, item);
115      [result addObject:[[EXJavaScriptValue alloc] initWithRuntime:_runtime value:valuePtr]];
116    }
117  }
118  return result;
119}
120
121- (nonnull NSDictionary<NSString *, id> *)getDictionary
122{
123  jsi::Runtime *runtime = [_runtime get];
124  return expo::convertJSIObjectToNSDictionary(*runtime, _value->getObject(*runtime), [_runtime callInvoker]);
125}
126
127- (nonnull EXJavaScriptObject *)getObject
128{
129  jsi::Runtime *runtime = [_runtime get];
130  std::shared_ptr<jsi::Object> objectPtr = std::make_shared<jsi::Object>(_value->asObject(*runtime));
131  return [[EXJavaScriptObject alloc] initWith:objectPtr runtime:_runtime];
132}
133
134#pragma mark - Helpers
135
136- (nonnull NSString *)toString
137{
138  jsi::Runtime *runtime = [_runtime get];
139  return expo::convertJSIStringToNSString(*runtime, _value->toString(*runtime));
140}
141
142@end
143