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