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