1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2 
3 #include "JavaScriptObject.h"
4 #include "JavaScriptValue.h"
5 #include "JavaScriptRuntime.h"
6 #include "JSITypeConverter.h"
7 
8 namespace expo {
9 void JavaScriptObject::registerNatives() {
10   registerHybrid({
11                    makeNativeMethod("hasProperty", JavaScriptObject::jniHasProperty),
12                    makeNativeMethod("getProperty", JavaScriptObject::jniGetProperty),
13                    makeNativeMethod("getPropertyNames", JavaScriptObject::jniGetPropertyNames),
14                    makeNativeMethod("setBoolProperty", JavaScriptObject::setProperty<bool>),
15                    makeNativeMethod("setDoubleProperty", JavaScriptObject::setProperty<double>),
16                    makeNativeMethod("setStringProperty",
17                                     JavaScriptObject::setProperty<jni::alias_ref<jstring>>),
18                    makeNativeMethod("setJSValueProperty",
19                                     JavaScriptObject::setProperty<jni::alias_ref<JavaScriptValue::javaobject>>),
20                    makeNativeMethod("setJSObjectProperty",
21                                     JavaScriptObject::setProperty<jni::alias_ref<JavaScriptObject::javaobject>>),
22                    makeNativeMethod("unsetProperty", JavaScriptObject::unsetProperty),
23                    makeNativeMethod("defineBoolProperty", JavaScriptObject::defineProperty<bool>),
24                    makeNativeMethod("defineDoubleProperty",
25                                     JavaScriptObject::defineProperty<double>),
26                    makeNativeMethod("defineStringProperty",
27                                     JavaScriptObject::defineProperty<jni::alias_ref<jstring>>),
28                    makeNativeMethod("defineJSValueProperty",
29                                     JavaScriptObject::defineProperty<jni::alias_ref<JavaScriptValue::javaobject>>),
30                    makeNativeMethod("defineJSObjectProperty",
31                                     JavaScriptObject::defineProperty<jni::alias_ref<JavaScriptObject::javaobject>>),
32                  });
33 }
34 
35 JavaScriptObject::JavaScriptObject(
36   std::weak_ptr<JavaScriptRuntime> runtime,
37   std::shared_ptr<jsi::Object> jsObject
38 ) : runtimeHolder(std::move(runtime)), jsObject(std::move(jsObject)) {
39   assert(runtimeHolder.lock() != nullptr);
40 }
41 
42 std::shared_ptr<jsi::Object> JavaScriptObject::get() {
43   return jsObject;
44 }
45 
46 bool JavaScriptObject::hasProperty(const std::string &name) {
47   auto runtime = runtimeHolder.lock();
48   assert(runtime != nullptr);
49   return jsObject->hasProperty(*runtime->get(), name.c_str());
50 }
51 
52 jsi::Value JavaScriptObject::getProperty(const std::string &name) {
53   auto runtime = runtimeHolder.lock();
54   assert(runtime != nullptr);
55   return jsObject->getProperty(*runtime->get(), name.c_str());
56 }
57 
58 bool JavaScriptObject::jniHasProperty(jni::alias_ref<jstring> name) {
59   return hasProperty(name->toStdString());
60 }
61 
62 jni::local_ref<JavaScriptValue::javaobject> JavaScriptObject::jniGetProperty(
63   jni::alias_ref<jstring> name
64 ) {
65   auto result = std::make_shared<jsi::Value>(getProperty(name->toStdString()));
66   return JavaScriptValue::newObjectCxxArgs(runtimeHolder, result);
67 }
68 
69 std::vector<std::string> JavaScriptObject::getPropertyNames() {
70   auto runtime = runtimeHolder.lock();
71   assert(runtime != nullptr);
72 
73   jsi::Array properties = jsObject->getPropertyNames(*runtime->get());
74   auto size = properties.size(*runtime->get());
75 
76   std::vector<std::string> names(size);
77   for (size_t i = 0; i < size; i++) {
78     auto propertyName = properties
79       .getValueAtIndex(*runtime->get(), i)
80       .asString(*runtime->get())
81       .utf8(*runtime->get());
82     names[i] = propertyName;
83   }
84 
85   return names;
86 }
87 
88 jni::local_ref<jni::JArrayClass<jstring>> JavaScriptObject::jniGetPropertyNames() {
89   std::vector<std::string> cResult = getPropertyNames();
90   auto paredResult = jni::JArrayClass<jstring>::newArray(cResult.size());
91   for (size_t i = 0; i < cResult.size(); i++) {
92     paredResult->setElement(i, jni::make_jstring(cResult[i]).get());
93   }
94 
95   return paredResult;
96 }
97 
98 void JavaScriptObject::setProperty(const std::string &name, jsi::Value value) {
99   auto runtime = runtimeHolder.lock();
100   assert(runtime != nullptr);
101   jsObject->setProperty(*runtime->get(), name.c_str(), value);
102 }
103 
104 void JavaScriptObject::unsetProperty(jni::alias_ref<jstring> name) {
105   auto runtime = runtimeHolder.lock();
106   assert(runtime != nullptr);
107   auto cName = name->toStdString();
108   jsObject->setProperty(
109     *runtime->get(),
110     cName.c_str(),
111     jsi::Value::undefined()
112   );
113 }
114 
115 jsi::Object JavaScriptObject::preparePropertyDescriptor(
116   jsi::Runtime &jsRuntime,
117   int options
118 ) {
119   jsi::Object descriptor(jsRuntime);
120   descriptor.setProperty(jsRuntime, "configurable", (bool) ((1 << 0) & options));
121   descriptor.setProperty(jsRuntime, "enumerable", (bool) ((1 << 1) & options));
122   descriptor.setProperty(jsRuntime, "writable", (bool) ((1 << 2) & options));
123   return descriptor;
124 }
125 } // namespace expo
126