// Copyright © 2021-present 650 Industries, Inc. (aka Expo) #include "JavaScriptModuleObject.h" #include "JSIInteropModuleRegistry.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace jni = facebook::jni; namespace jsi = facebook::jsi; namespace react = facebook::react; namespace expo { jni::local_ref::jhybriddata> JavaScriptModuleObject::initHybrid(jni::alias_ref jThis) { return makeCxxInstance(jThis); } void JavaScriptModuleObject::registerNatives() { registerHybrid({ makeNativeMethod("initHybrid", JavaScriptModuleObject::initHybrid), makeNativeMethod("exportConstants", JavaScriptModuleObject::exportConstants), makeNativeMethod("registerSyncFunction", JavaScriptModuleObject::registerSyncFunction), makeNativeMethod("registerAsyncFunction", JavaScriptModuleObject::registerAsyncFunction), }); } std::shared_ptr JavaScriptModuleObject::getJSIObject(jsi::Runtime &runtime) { if (jsiObject == nullptr) { auto hostObject = std::make_shared(this); jsiObject = std::make_shared( jsi::Object::createFromHostObject(runtime, hostObject)); } return jsiObject; } void JavaScriptModuleObject::exportConstants( jni::alias_ref constants ) { auto dynamic = constants->cthis()->consume(); assert(dynamic.isObject()); for (const auto &[key, value]: dynamic.items()) { this->constants[key.asString()] = value; } } void JavaScriptModuleObject::registerSyncFunction( jni::alias_ref name, jint args, jni::alias_ref desiredTypes, jni::alias_ref body ) { std::string cName = name->toStdString(); std::unique_ptr types = desiredTypes->getRegion(0, args); methodsMetadata.try_emplace( cName, cName, args, false, std::move(types), jni::make_global(body) ); } void JavaScriptModuleObject::registerAsyncFunction( jni::alias_ref name, jint args, jni::alias_ref desiredTypes, jni::alias_ref body ) { auto cName = name->toStdString(); std::unique_ptr types = desiredTypes->getRegion(0, args); methodsMetadata.try_emplace( cName, cName, args, true, std::move(types), jni::make_global(body) ); } JavaScriptModuleObject::HostObject::HostObject( JavaScriptModuleObject *jsModule) : jsModule(jsModule) {} jsi::Value JavaScriptModuleObject::HostObject::get(jsi::Runtime &runtime, const jsi::PropNameID &name) { auto cName = name.utf8(runtime); auto constantsRecord = jsModule->constants.find(cName); if (constantsRecord != jsModule->constants.end()) { auto dynamic = constantsRecord->second; return jsi::valueFromDynamic(runtime, dynamic); } auto metadataRecord = jsModule->methodsMetadata.find(cName); if (metadataRecord == jsModule->methodsMetadata.end()) { return jsi::Value::undefined(); } auto &metadata = metadataRecord->second; return jsi::Value(runtime, *metadata.toJSFunction(runtime, jsModule->jsiInteropModuleRegistry)); } void JavaScriptModuleObject::HostObject::set( jsi::Runtime &runtime, const jsi::PropNameID &name, const jsi::Value &value ) { throw jsi::JSError( runtime, "RuntimeError: Cannot override the host object for expo module '" + name.utf8(runtime) + "'" ); } std::vector JavaScriptModuleObject::HostObject::getPropertyNames( jsi::Runtime &rt ) { auto &metadata = jsModule->methodsMetadata; std::vector result; std::transform( metadata.begin(), metadata.end(), std::back_inserter(result), [&rt](const auto &kv) { return jsi::PropNameID::forUtf8(rt, kv.first); } ); auto &constants = jsModule->constants; std::transform( constants.begin(), constants.end(), std::back_inserter(result), [&rt](const auto &kv) { return jsi::PropNameID::forUtf8(rt, kv.first); } ); return result; } } // namespace expo