1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2 
3 #include "JavaScriptValue.h"
4 
5 #include "JavaScriptRuntime.h"
6 #include "JavaScriptObject.h"
7 #include "JavaScriptTypedArray.h"
8 #include "TypedArray.h"
9 #include "Exceptions.h"
10 
11 namespace expo {
12 void JavaScriptValue::registerNatives() {
13   registerHybrid({
14                    makeNativeMethod("kind", JavaScriptValue::jniKind),
15                    makeNativeMethod("isNull", JavaScriptValue::isNull),
16                    makeNativeMethod("isUndefined", JavaScriptValue::isUndefined),
17                    makeNativeMethod("isBool", JavaScriptValue::isBool),
18                    makeNativeMethod("isNumber", JavaScriptValue::isNumber),
19                    makeNativeMethod("isString", JavaScriptValue::isString),
20                    makeNativeMethod("isSymbol", JavaScriptValue::isSymbol),
21                    makeNativeMethod("isFunction", JavaScriptValue::isFunction),
22                    makeNativeMethod("isArray", JavaScriptValue::isArray),
23                    makeNativeMethod("isTypedArray", JavaScriptValue::isTypedArray),
24                    makeNativeMethod("isObject", JavaScriptValue::isObject),
25                    makeNativeMethod("getBool", JavaScriptValue::getBool),
26                    makeNativeMethod("getDouble", JavaScriptValue::getDouble),
27                    makeNativeMethod("getString", JavaScriptValue::jniGetString),
28                    makeNativeMethod("getObject", JavaScriptValue::getObject),
29                    makeNativeMethod("getArray", JavaScriptValue::getArray),
30                    makeNativeMethod("getTypedArray", JavaScriptValue::getTypedArray),
31                  });
32 }
33 
34 JavaScriptValue::JavaScriptValue(
35   std::weak_ptr<JavaScriptRuntime> runtime,
36   std::shared_ptr<jsi::Value> jsValue
37 ) : runtimeHolder(std::move(runtime)), jsValue(std::move(jsValue)) {
38   runtimeHolder.ensureRuntimeIsValid();
39 }
40 
41 JavaScriptValue::JavaScriptValue(
42   WeakRuntimeHolder runtime,
43   std::shared_ptr<jsi::Value> jsValue
44 ) : runtimeHolder(std::move(runtime)), jsValue(std::move(jsValue)) {
45   runtimeHolder.ensureRuntimeIsValid();
46 }
47 
48 std::shared_ptr<jsi::Value> JavaScriptValue::get() {
49   return jsValue;
50 }
51 
52 std::string JavaScriptValue::kind() {
53   if (isNull()) {
54     return "null";
55   }
56   if (isUndefined()) {
57     return "undefined";
58   }
59   if (isBool()) {
60     return "boolean";
61   }
62   if (isNumber()) {
63     return "number";
64   }
65   if (isString()) {
66     return "string";
67   }
68   if (isSymbol()) {
69     return "symbol";
70   }
71   if (isFunction()) {
72     return "function";
73   }
74   if (isArray()) {
75     return "array";
76   }
77   if (isObject()) {
78     return "object";
79   }
80 
81   jni::throwNewJavaException(
82     UnexpectedException::create("Unknown type").get()
83   );
84 }
85 
86 bool JavaScriptValue::isNull() {
87   return jsValue->isNull();
88 }
89 
90 bool JavaScriptValue::isUndefined() {
91   return jsValue->isUndefined();
92 }
93 
94 bool JavaScriptValue::isBool() {
95   return jsValue->isBool();
96 }
97 
98 bool JavaScriptValue::isNumber() {
99   return jsValue->isNumber();
100 }
101 
102 bool JavaScriptValue::isString() {
103   return jsValue->isString();
104 }
105 
106 bool JavaScriptValue::isSymbol() {
107   return jsValue->isSymbol();
108 }
109 
110 bool JavaScriptValue::isFunction() {
111   if (jsValue->isObject()) {
112     auto &jsRuntime = runtimeHolder.getJSRuntime();
113     return jsValue->asObject(jsRuntime).isFunction(jsRuntime);
114   }
115 
116   return false;
117 }
118 
119 bool JavaScriptValue::isArray() {
120   if (jsValue->isObject()) {
121     auto &jsRuntime = runtimeHolder.getJSRuntime();
122     return jsValue->asObject(jsRuntime).isArray(jsRuntime);
123   }
124 
125   return false;
126 }
127 
128 bool JavaScriptValue::isObject() {
129   return jsValue->isObject();
130 }
131 
132 bool JavaScriptValue::isTypedArray() {
133   if (jsValue->isObject()) {
134     jsi::Runtime &jsRuntime = runtimeHolder.getJSRuntime();
135     return expo::isTypedArray(jsRuntime, jsValue->getObject(jsRuntime));
136   }
137   return false;
138 }
139 
140 bool JavaScriptValue::getBool() {
141   return jsValue->getBool();
142 }
143 
144 double JavaScriptValue::getDouble() {
145   return jsValue->getNumber();
146 }
147 
148 std::string JavaScriptValue::getString() {
149   auto &jsRuntime = runtimeHolder.getJSRuntime();
150   return jsValue->getString(jsRuntime).utf8(jsRuntime);
151 }
152 
153 jni::local_ref<JavaScriptObject::javaobject> JavaScriptValue::getObject() {
154   auto &jsRuntime = runtimeHolder.getJSRuntime();
155   auto jsObject = std::make_shared<jsi::Object>(jsValue->getObject(jsRuntime));
156   return JavaScriptObject::newObjectCxxArgs(runtimeHolder, jsObject);
157 }
158 
159 jni::local_ref<jni::JArrayClass<JavaScriptValue::javaobject>> JavaScriptValue::getArray() {
160   auto &jsRuntime = runtimeHolder.getJSRuntime();
161 
162   auto jsArray = jsValue
163     ->getObject(jsRuntime)
164     .asArray(jsRuntime);
165   size_t size = jsArray.size(jsRuntime);
166 
167   auto result = jni::JArrayClass<JavaScriptValue::javaobject>::newArray(size);
168   for (size_t i = 0; i < size; i++) {
169     auto element = JavaScriptValue::newObjectCxxArgs(
170       runtimeHolder,
171       std::make_shared<jsi::Value>(jsArray.getValueAtIndex(jsRuntime, i))
172     );
173 
174     result->setElement(i, element.release());
175   }
176   return result;
177 }
178 
179 jni::local_ref<jstring> JavaScriptValue::jniKind() {
180   auto result = kind();
181   return jni::make_jstring(result);
182 }
183 
184 jni::local_ref<jstring> JavaScriptValue::jniGetString() {
185   auto result = getString();
186   return jni::make_jstring(result);
187 }
188 
189 jni::local_ref<JavaScriptTypedArray::javaobject> JavaScriptValue::getTypedArray() {
190   auto &jsRuntime = runtimeHolder.getJSRuntime();
191   auto jsObject = std::make_shared<jsi::Object>(jsValue->getObject(jsRuntime));
192   return JavaScriptTypedArray::newObjectCxxArgs(runtimeHolder, jsObject);
193 }
194 } // namespace expo
195