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