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   assert(runtimeHolder.lock() != nullptr);
34 }
35 
36 std::shared_ptr<jsi::Value> JavaScriptValue::get() {
37   return jsValue;
38 }
39 
40 std::string JavaScriptValue::kind() {
41   if (isNull()) {
42     return "null";
43   }
44   if (isUndefined()) {
45     return "undefined";
46   }
47   if (isBool()) {
48     return "boolean";
49   }
50   if (isNumber()) {
51     return "number";
52   }
53   if (isString()) {
54     return "string";
55   }
56   if (isSymbol()) {
57     return "symbol";
58   }
59   if (isFunction()) {
60     return "function";
61   }
62   if (isArray()) {
63     return "array";
64   }
65   if (isObject()) {
66     return "object";
67   }
68 
69   // TODO(@lukmccall): maybe throw exception?
70   return "unknown";
71 }
72 
73 bool JavaScriptValue::isNull() {
74   return jsValue->isNull();
75 }
76 
77 bool JavaScriptValue::isUndefined() {
78   return jsValue->isUndefined();
79 }
80 
81 bool JavaScriptValue::isBool() {
82   return jsValue->isBool();
83 }
84 
85 bool JavaScriptValue::isNumber() {
86   return jsValue->isNumber();
87 }
88 
89 bool JavaScriptValue::isString() {
90   return jsValue->isString();
91 }
92 
93 bool JavaScriptValue::isSymbol() {
94   return jsValue->isSymbol();
95 }
96 
97 bool JavaScriptValue::isFunction() {
98   if (jsValue->isObject()) {
99     auto runtime = runtimeHolder.lock();
100     assert(runtime != nullptr);
101     return jsValue->asObject(*runtime->get()).isFunction(*runtime->get());
102   }
103 
104   return false;
105 }
106 
107 bool JavaScriptValue::isArray() {
108   if (jsValue->isObject()) {
109     auto runtime = runtimeHolder.lock();
110     assert(runtime != nullptr);
111     return jsValue->asObject(*runtime->get()).isArray(*runtime->get());
112   }
113 
114   return false;
115 }
116 
117 bool JavaScriptValue::isObject() {
118   return jsValue->isObject();
119 }
120 
121 bool JavaScriptValue::getBool() {
122   return jsValue->getBool();
123 }
124 
125 double JavaScriptValue::getDouble() {
126   return jsValue->getNumber();
127 }
128 
129 std::string JavaScriptValue::getString() {
130   auto runtime = runtimeHolder.lock();
131   assert(runtime != nullptr);
132   return jsValue->getString(*runtime->get()).utf8(*runtime->get());
133 }
134 
135 jni::local_ref<JavaScriptObject::javaobject> JavaScriptValue::getObject() {
136   auto runtime = runtimeHolder.lock();
137   assert(runtime != nullptr);
138   auto jsObject = std::make_shared<jsi::Object>(jsValue->getObject(*runtime->get()));
139   return JavaScriptObject::newObjectCxxArgs(runtimeHolder, jsObject);
140 }
141 
142 jni::local_ref<jni::JArrayClass<JavaScriptValue::javaobject>> JavaScriptValue::getArray() {
143   auto runtime = runtimeHolder.lock();
144   assert(runtime != nullptr);
145 
146   auto jsArray = jsValue
147     ->getObject(*runtime->get())
148     .asArray(*runtime->get());
149   size_t size = jsArray.size(*runtime->get());
150 
151   auto result = jni::JArrayClass<JavaScriptValue::javaobject>::newArray(size);
152   for (size_t i = 0; i < size; i++) {
153     auto element = JavaScriptValue::newObjectCxxArgs(
154       runtimeHolder,
155       std::make_shared<jsi::Value>(jsArray.getValueAtIndex(*runtime->get(), i))
156     );
157 
158     result->setElement(i, element.release());
159   }
160   return result;
161 }
162 
163 jni::local_ref<jstring> JavaScriptValue::jniKind() {
164   auto result = kind();
165   return jni::make_jstring(result);
166 }
167 
168 jni::local_ref<jstring> JavaScriptValue::jniGetString() {
169   auto result = getString();
170   return jni::make_jstring(result);
171 }
172 } // namespace expo
173