1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2 
3 #include "ExpoModulesHostObject.h"
4 #include "LazyObject.h"
5 
6 #include <folly/dynamic.h>
7 #include <jsi/JSIDynamic.h>
8 
9 namespace jsi = facebook::jsi;
10 
11 namespace expo {
12 
13 ExpoModulesHostObject::ExpoModulesHostObject(JSIInteropModuleRegistry *installer)
14   : installer(installer) {}
15 
16 /**
17  * Clears jsi references held by JSRegistry and JavaScriptRuntime.
18  */
19 ExpoModulesHostObject::~ExpoModulesHostObject() {
20   installer->jsRegistry.reset();
21   installer->runtimeHolder.reset();
22 }
23 
24 jsi::Value ExpoModulesHostObject::get(jsi::Runtime &runtime, const jsi::PropNameID &name) {
25   auto cName = name.utf8(runtime);
26 
27   if (!installer->hasModule(cName)) {
28     modulesCache.erase(cName);
29     return jsi::Value::undefined();
30   }
31   if (UniqueJSIObject &cachedObject = modulesCache[cName]) {
32     return jsi::Value(runtime, *cachedObject);
33   }
34 
35   // Create a lazy object for the specific module. It defers initialization of the final module object.
36   LazyObject::Shared moduleLazyObject = std::make_shared<LazyObject>(
37     [this, cName](jsi::Runtime &rt) {
38       auto module = installer->getModule(cName);
39       module->cthis()->jsiInteropModuleRegistry = installer;
40       return module->cthis()->getJSIObject(rt);
41     });
42 
43   // Save the module's lazy host object for later use.
44   modulesCache[cName] = std::make_unique<jsi::Object>(
45     jsi::Object::createFromHostObject(runtime, moduleLazyObject));
46 
47   return jsi::Value(runtime, *modulesCache[cName]);
48 }
49 
50 void ExpoModulesHostObject::set(jsi::Runtime &runtime, const jsi::PropNameID &name,
51                                 const jsi::Value &value) {
52   throw jsi::JSError(
53     runtime,
54     "RuntimeError: Cannot override the host object for expo module '" + name.utf8(runtime) + "'"
55   );
56 }
57 
58 std::vector<jsi::PropNameID> ExpoModulesHostObject::getPropertyNames(jsi::Runtime &rt) {
59   auto names = installer->getModulesName();
60   size_t size = names->size();
61   std::vector<jsi::PropNameID> result;
62   result.reserve(size);
63   for (int i = 0; i < size; i++) {
64     result.push_back(
65       jsi::PropNameID::forUtf8(rt, names->getElement(i)->toStdString())
66     );
67   }
68   return result;
69 }
70 } // namespace expo
71