Skip to content

Commit

Permalink
feat: Add NitroModules.hasHybridObject(..) and `NitroModules.getAll…
Browse files Browse the repository at this point in the history
…HybridMethodNames()` (#30)

* feat: Add `NitroModules.hasHybridObject(..)` and `NitroModules.getAllHybridMethodNames()`

* Fix docs
  • Loading branch information
mrousavy authored Aug 13, 2024
1 parent 9eac80f commit 6d2338d
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 10 deletions.
10 changes: 7 additions & 3 deletions packages/react-native-nitro-image/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,19 @@ export * from './specs/ImageFactory.nitro'
/**
* Constructors for creating instances of `Image`.
*/
export const ImageConstructors = NitroModules.get<ImageFactory>('ImageFactory')
export const ImageConstructors =
NitroModules.createHybridObject<ImageFactory>('ImageFactory')

/**
* The Hybrid Test Object
*/
export const HybridTestObject = NitroModules.get<TestObject>('TestObject')
export const HybridTestObject =
NitroModules.createHybridObject<TestObject>('TestObject')

/**
* The Swift-Kotlin implemented Hybrid Test Object
*/
export const HybridSwiftKotlinTestObject =
NitroModules.get<SwiftKotlinTestObject>('SwiftKotlinTestObject')
NitroModules.createHybridObject<SwiftKotlinTestObject>(
'SwiftKotlinTestObject'
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@

/**
* A registry that holds initializers for HybridObjects.
* This will be used to initialize them from JS using `NitroModules.get<T>(name)`.
* This will be used to initialize them from JS using `NitroModules.createHybridObject<T>(name)`.
* @noinspection JavaJniMissingFunction
*/
public class HybridObjectRegistry {
/**
* Registers the given HybridObject in the `HybridObjectRegistry`.
* It will be uniquely identified via it's `hybridObjectName`, and can be initialized from
* JS using `NitroModules.get<T>(name)` - which will call the `constructorFn` here.
* JS using `NitroModules.createHybridObject<T>(name)` - which will call the `constructorFn` here.
*/
public static native void registerHybridObjectConstructor(String hybridObjectName, HybridObjectInitializer initializer);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@ std::unordered_map<std::string, HybridObjectRegistry::HybridObjectConstructorFn>
return _constructorsMap;
}

bool HybridObjectRegistry::hasHybridObject(const std::string& name) {
return getRegistry().contains(name);
}

std::vector<std::string> HybridObjectRegistry::getAllHybridObjectNames() {
std::vector<std::string> keys;
keys.reserve(getRegistry().size());
for (const auto& entry : getRegistry()) {
keys.push_back(entry.first);
}
return keys;
}

void HybridObjectRegistry::registerHybridObjectConstructor(const std::string& hybridObjectName, HybridObjectConstructorFn&& constructorFn) {
Logger::log(TAG, "Registering HybridObject \"%s\"...", hybridObjectName);
auto& map = HybridObjectRegistry::getRegistry();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace margelo::nitro {

/**
* A registry that holds initializers for HybridObjects.
* This will be used to initialize them from JS using `NitroModules.get<T>(name)`.
* This will be used to initialize them from JS using `NitroModules.createHybridObject<T>(name)`.
*/
class HybridObjectRegistry {
public:
Expand All @@ -28,11 +28,13 @@ class HybridObjectRegistry {
/**
* Registers the given HybridObject in the `HybridObjectRegistry`.
* It will be uniquely identified via it's `hybridObjectName`, and can be initialized from
* JS using `NitroModules.get<T>(name)` - which will call the `constructorFn` here.
* JS using `NitroModules.createHybridObject<T>(name)` - which will call the `constructorFn` here.
*/
static void registerHybridObjectConstructor(const std::string& hybridObjectName, HybridObjectConstructorFn&& constructorFn);

static std::shared_ptr<HybridObject> createHybridObject(const std::string& hybridObjectName);
static bool hasHybridObject(const std::string& hybridObjectName);
static std::vector<std::string> getAllHybridObjectNames();

private:
static std::unordered_map<std::string, HybridObjectConstructorFn>& getRegistry();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@ jsi::Value NativeNitroModules::get(jsi::Runtime& runtime, const jsi::PropNameID&
}
if (name == "createHybridObject") {
return jsi::Function::createFromHostFunction(
runtime, jsi::PropNameID::forUtf8(runtime, "install"), 2,
runtime, jsi::PropNameID::forUtf8(runtime, "createHybridObject"), 2,
[=](jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args, size_t count) -> jsi::Value {
if (count != 1 && count != 2) {
#if DEBUG
if (count != 1 && count != 2) [[unlikely]] {
throw jsi::JSError(runtime, "NitroModules.createHybridObject(..) expects 1 or 2 arguments, but " + std::to_string(count) +
" were supplied!");
}
#endif
jsi::String objectName = args[0].asString(runtime);
std::optional<jsi::Object> optionalArgs = std::nullopt;
if (count > 1) {
Expand All @@ -47,6 +49,25 @@ jsi::Value NativeNitroModules::get(jsi::Runtime& runtime, const jsi::PropNameID&
return createHybridObject(runtime, objectName, optionalArgs);
});
}
if (name == "hasHybridObject") {
return jsi::Function::createFromHostFunction(
runtime, jsi::PropNameID::forUtf8(runtime, "hasHybridObject"), 1,
[=](jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args, size_t count) -> jsi::Value {
#if DEBUG
if (count != 1) [[unlikely]] {
throw jsi::JSError(runtime,
"NitroModules.hasHybridObject(..) expects 1 argument (name), but received " + std::to_string(count) + "!");
}
#endif
jsi::String objectName = args[0].asString(runtime);
return hasHybridObject(runtime, objectName);
});
}
if (name == "getAllHybridObjectNames") {
return jsi::Function::createFromHostFunction(runtime, jsi::PropNameID::forUtf8(runtime, "getAllHybridObjectNames"), 0,
[=](jsi::Runtime& runtime, const jsi::Value& thisArg, const jsi::Value* args,
size_t count) -> jsi::Value { return getAllHybridObjectNames(runtime); });
}

return jsi::Value::undefined();
}
Expand All @@ -66,4 +87,19 @@ jsi::Value NativeNitroModules::createHybridObject(jsi::Runtime& runtime, const j
return hybridObject->toObject(runtime);
}

jsi::Value NativeNitroModules::hasHybridObject(jsi::Runtime& runtime, const jsi::String& hybridObjectName) {
std::string name = hybridObjectName.utf8(runtime);
bool exists = HybridObjectRegistry::hasHybridObject(name);
return exists;
}

jsi::Value NativeNitroModules::getAllHybridObjectNames(jsi::Runtime& runtime) {
std::vector<std::string> keys = HybridObjectRegistry::getAllHybridObjectNames();
jsi::Array array(runtime, keys.size());
for (size_t i = 0; i < keys.size(); i++) {
array.setValueAtIndex(runtime, i, jsi::String::createFromUtf8(runtime, keys[i]));
}
return array;
}

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class NativeNitroModules : public TurboModule {

void install(jsi::Runtime& runtime);
jsi::Value createHybridObject(jsi::Runtime& runtime, const jsi::String& hybridObjectName, const std::optional<jsi::Object>& args);
jsi::Value hasHybridObject(jsi::Runtime& runtime, const jsi::String& hybridObjectName);
jsi::Value getAllHybridObjectNames(jsi::Runtime& runtime);

public:
constexpr static auto kModuleName = "NitroModulesCxx";
Expand Down
2 changes: 2 additions & 0 deletions packages/react-native-nitro-modules/src/NativeNitroModules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { ModuleNotFoundError } from './ModuleNotFoundError'
export interface Spec extends TurboModule {
install(): void
createHybridObject(name: string, args?: UnsafeObject): UnsafeObject
hasHybridObject(name: string): boolean
getAllHybridObjectNames(): string[]
}

let turboModule: Spec | undefined
Expand Down
16 changes: 15 additions & 1 deletion packages/react-native-nitro-modules/src/NitroModules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,23 @@ export const NitroModules = {
* @returns An instance of {@linkcode T}
* @throws an Error if {@linkcode T} has not been registered under the name {@linkcode name}.
*/
get<T extends HybridObject<any>>(name: string): T {
createHybridObject<T extends HybridObject<any>>(name: string): T {
const nitro = getNativeNitroModules()
const instance = nitro.createHybridObject(name)
return instance as T
},
/**
* Get a list of all registered Hybrid Objects.
*/
getAllHybridObjectNames(): string[] {
const nitro = getNativeNitroModules()
return nitro.getAllHybridObjectNames()
},
/**
* Returns whether a HybridObject under the given {@linkcode name} is registered, or not.
*/
hasHybridObject(name: string): boolean {
const nitro = getNativeNitroModules()
return nitro.hasHybridObject(name)
},
}

0 comments on commit 6d2338d

Please sign in to comment.