Skip to content

Commit

Permalink
Trim react-native from the name in the same places create-rn-library …
Browse files Browse the repository at this point in the history
…and Codegen does (#123)

Fixes #109.

This PR adds testing around the turbo-modules.

The tests runs through a host of different names, then 

- runs `create-react-native-library` with that name. 
- runs the `ubrn generate turbo-module` command
- the checks that generated files from the ubrn command still uses the
identifiers in the `create-react-native-library` files
- finally builds for ios and android the library.

This has meant a series of changes (for the better) to the templates.
  • Loading branch information
jhugman authored Oct 15, 2024
1 parent 2c0c8c9 commit c3fd7ab
Show file tree
Hide file tree
Showing 17 changed files with 509 additions and 46 deletions.
22 changes: 11 additions & 11 deletions crates/ubrn_cli/src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ mod files {
pub(super) fn get_files(config: Rc<TemplateConfig>) -> Vec<Rc<dyn RenderedFile>> {
vec![
// typescript
IndexTs::rc_new(config.clone()),
IndexTsx::rc_new(config.clone()),
// C++
TMHeader::rc_new(config.clone()),
TMCpp::rc_new(config.clone()),
Expand All @@ -189,7 +189,7 @@ mod files {
templated_file!(JavaModule, "ModuleTemplate.java");
impl RenderedFile for JavaModule {
fn path(&self, project_root: &Utf8Path) -> Utf8PathBuf {
let name = self.config.project.name_upper_camel();
let name = self.config.project.module_cpp();
let filename = format!("{name}Module.java");
self.config
.project
Expand All @@ -202,7 +202,7 @@ mod files {
templated_file!(JavaPackage, "PackageTemplate.java");
impl RenderedFile for JavaPackage {
fn path(&self, project_root: &Utf8Path) -> Utf8PathBuf {
let name = self.config.project.name_upper_camel();
let name = self.config.project.module_cpp();
let filename = format!("{name}Package.java");
self.config
.project
Expand Down Expand Up @@ -261,10 +261,10 @@ mod files {
}
}

templated_file!(IndexTs, "index.ts");
impl RenderedFile for IndexTs {
templated_file!(IndexTsx, "index.tsx");
impl RenderedFile for IndexTsx {
fn path(&self, project_root: &Utf8Path) -> Utf8PathBuf {
let filename = "index.ts";
let filename = "index.tsx";
self.config.project.tm.ts_path(project_root).join(filename)
}
}
Expand Down Expand Up @@ -295,7 +295,7 @@ mod files {
templated_file!(ModuleTemplateH, "ModuleTemplate.h");
impl RenderedFile for ModuleTemplateH {
fn path(&self, project_root: &Utf8Path) -> Utf8PathBuf {
let name = self.config.project.name_upper_camel();
let name = self.config.project.module_cpp();
let filename = format!("{name}.h");
self.config
.project
Expand All @@ -311,7 +311,7 @@ mod files {
templated_file!(ModuleTemplateMm, "ModuleTemplate.mm");
impl RenderedFile for ModuleTemplateMm {
fn path(&self, project_root: &Utf8Path) -> Utf8PathBuf {
let name = self.config.project.name_upper_camel();
let name = self.config.project.module_cpp();
let filename = format!("{name}.mm");
self.config
.project
Expand Down Expand Up @@ -432,7 +432,7 @@ mod tests {
templated_file!(TemplateTester, "TemplateTester.txt");
impl RenderedFile for TemplateTester {
fn path(&self, project_root: &Utf8Path) -> Utf8PathBuf {
let name = self.config.project.name_upper_camel();
let name = self.config.project.module_cpp();
let filename = format!("{name}.txt");
self.config
.project
Expand All @@ -454,10 +454,10 @@ mod tests {
// This is hard coded into the file. If this isn't here, then the test file hasn't rendered.
assert!(s.contains("hardcoded into template."));
assert_eq!(
config.project.name_upper_camel(),
config.project.module_cpp(),
"MyTesterTemplateProject".to_string()
);
assert!(s.contains("name_upper_camel = MyTesterTemplateProject."));
assert!(s.contains("module_cpp = MyTesterTemplateProject."));
assert!(s.contains("list of modules = ['NativeAlice', 'NativeBob', 'NativeCharlie']"));
Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion crates/ubrn_cli/src/codegen/templates/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Generated by uniffi-bindgen-react-native
cmake_minimum_required(VERSION 3.9.0)
project({{ self.config.project.cpp_filename() }})
project({{ self.config.project.module_cpp() }})

{%- let root = self.project_root() %}
{%- let dir = self.config.project.bindings.cpp_path(root) %}
Expand Down
4 changes: 2 additions & 2 deletions crates/ubrn_cli/src/codegen/templates/ModuleTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
#ifdef RCT_NEW_ARCH_ENABLED
#import "{{ self.config.project.tm.name() }}.h"

@interface {{ self.config.project.name_upper_camel() }} : NSObject <{{ self.config.project.codegen_filename() }}Spec>
@interface {{ self.config.project.module_cpp() }} : NSObject <{{ self.config.project.codegen_filename() }}Spec>
#else
#import <React/RCTBridgeModule.h>

@interface {{ self.config.project.name_upper_camel() }} : NSObject <RCTBridgeModule>
@interface {{ self.config.project.module_cpp() }} : NSObject <RCTBridgeModule>
#endif

@end
2 changes: 1 addition & 1 deletion crates/ubrn_cli/src/codegen/templates/ModuleTemplate.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{%- let android = self.config.project.android.clone() %}
{%- let name = self.config.project.name_upper_camel() %}
{%- let name = self.config.project.module_cpp() %}
{%- let module_class_name = name|fmt("{}Module") -%}
// Generated by uniffi-bindgen-react-native
package {{ android.package_name() }};
Expand Down
11 changes: 10 additions & 1 deletion crates/ubrn_cli/src/codegen/templates/ModuleTemplate.mm
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{%- let module_name = self.config.project.name_upper_camel() %}
{%- let module_name = self.config.project.module_cpp() %}
{%- let spec_jsi = self.config.project.tm.spec_name()|fmt("{}JSI") %}
{%- let ns = self.config.project.cpp_namespace() %}
{%- let uniffi_ns = "uniffi_generated" %}
Expand Down Expand Up @@ -40,6 +40,15 @@ @implementation {{ module_name }}

// Don't compile this code when we build for the old architecture.
#ifdef RCT_NEW_ARCH_ENABLED

// Automated testing checks {{ ns }}
// by comparing the whole line here.
/*
- (NSNumber *)multiply:(double)a b:(double)b {
NSNumber *result = @({{ ns }}::multiply(a, b));
}
*/

- (NSNumber *)installRustCrate {
@throw [NSException exceptionWithName:@"UnreachableException"
reason:@"This method should never be called."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ export interface Spec extends TurboModule {
cleanupRustCrate(): boolean;
}

export default TurboModuleRegistry.getEnforcing<Spec>('{{ self.config.project.name_upper_camel() }}');
export default TurboModuleRegistry.getEnforcing<Spec>('{{ self.config.project.spec_name() }}');
2 changes: 1 addition & 1 deletion crates/ubrn_cli/src/codegen/templates/PackageTemplate.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{%- let name = self.config.project.name_upper_camel() %}
{%- let name = self.config.project.module_cpp() %}
{%- let package_class_name = name|fmt("{}Package") %}
{%- let module_class_name = name|fmt("{}Module") -%}
// Generated by uniffi-bindgen-react-native
Expand Down
2 changes: 1 addition & 1 deletion crates/ubrn_cli/src/codegen/templates/TemplateTester.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
hardcoded into template.
name_upper_camel = {{ self.config.project.name_upper_camel() }}.
module_cpp = {{ self.config.project.module_cpp() }}.

list of modules = [
{%- for m in self.config.modules %}'
Expand Down
2 changes: 1 addition & 1 deletion crates/ubrn_cli/src/codegen/templates/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Generated by uniffi-bindgen-react-native
{%- let name = self.config.project.name_upper_camel() %}
{%- let name = self.config.project.module_cpp() %}
{%- let package_name = self.config.project.android.package_name() %}

buildscript {
Expand Down
10 changes: 9 additions & 1 deletion crates/ubrn_cli/src/codegen/templates/cpp-adapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,22 @@
#include <ReactCommon/CallInvokerHolder.h>
#include "{{ self.config.project.cpp_filename() }}.h"
{%- let package_name = self.config.project.android.package_name().replace(".", "_") %}
{%- let name = self.config.project.name_upper_camel() %}
{%- let name = self.config.project.module_cpp() %}
{%- let module_class_name = name|fmt("{}Module") %}
{%- let prefix = "Java_{}_{}"|format(package_name, module_class_name) %}
{%- let ns = self.config.project.cpp_namespace() %}

namespace jsi = facebook::jsi;
namespace react = facebook::react;

// Automated testing checks {{ prefix }} and {{ ns }}
// by comparing the whole line here.
/*
{{ prefix }}_nativeMultiply(JNIEnv *env, jclass type, jdouble a, jdouble b) {
return {{ ns }}::multiply(a, b);
}
*/

// Installer coming from {{ module_class_name }}
extern "C"
JNIEXPORT jboolean JNICALL
Expand Down
44 changes: 26 additions & 18 deletions crates/ubrn_cli/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod npm;

use camino::{Utf8Path, Utf8PathBuf};
use globset::GlobSet;
use heck::ToUpperCamelCase;
pub(crate) use npm::PackageJson;

use serde::Deserialize;
Expand Down Expand Up @@ -55,15 +56,21 @@ impl ProjectConfig {
}
}

fn trim_react_native(name: &str) -> String {
fn trim(name: &str) -> String {
name.trim_matches('-').trim_matches('_').to_string()
}

fn trim_react_native_2(name: &str) -> String {
name.strip_prefix("RN")
.unwrap_or(name)
.replace("ReactNative", "")
.replace("react-native", "")
#[allow(dead_code)]
fn trim_rn(name: &str) -> String {
trim_react_native(strip_prefix(name, "RN"))
}

fn strip_prefix<'a>(name: &'a str, prefix: &str) -> &'a str {
name.strip_prefix(prefix).unwrap_or(name)
}

pub(crate) fn trim_react_native(name: &str) -> String {
strip_prefix(strip_prefix(name, "ReactNative"), "react-native")
.trim_matches('-')
.trim_matches('_')
.to_string()
Expand All @@ -73,13 +80,13 @@ impl ProjectConfig {
pub(crate) fn project_root(&self) -> &Utf8Path {
&self.crate_.project_root
}
}

impl ProjectConfig {
fn name(&self) -> String {
trim_react_native(&self.name)
pub(crate) fn module_cpp(&self) -> String {
trim_react_native(&self.name).to_upper_camel_case()
}
}

impl ProjectConfig {
pub(crate) fn raw_name(&self) -> &str {
&self.name
}
Expand All @@ -88,13 +95,10 @@ impl ProjectConfig {
&self.repository
}

pub(crate) fn name_upper_camel(&self) -> String {
use heck::ToUpperCamelCase;
self.name().to_upper_camel_case()
}

pub(crate) fn cpp_namespace(&self) -> String {
self.name_upper_camel().to_lowercase()
trim_react_native(&self.name)
.to_upper_camel_case()
.to_lowercase()
}

pub(crate) fn cpp_filename(&self) -> String {
Expand All @@ -103,7 +107,11 @@ impl ProjectConfig {
}

pub(crate) fn codegen_filename(&self) -> String {
format!("Native{}", self.name_upper_camel())
format!("Native{}", self.spec_name())
}

pub(crate) fn spec_name(&self) -> String {
trim_react_native(&self.name).to_upper_camel_case()
}

pub(crate) fn exclude_files(&self) -> &GlobSet {
Expand Down Expand Up @@ -185,7 +193,7 @@ impl TurboModulesConfig {
fn default_spec_name() -> String {
let package_json = workspace::package_json();
let codegen_name = &package_json.codegen().name;
trim_react_native(codegen_name)
trim(codegen_name)
}
}

Expand Down
6 changes: 3 additions & 3 deletions crates/ubrn_cli/src/config/npm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use heck::ToUpperCamelCase;
use serde::Deserialize;

use super::{trim_react_native, trim_react_native_2};
use super::{trim, trim_react_native};

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
Expand All @@ -26,7 +26,7 @@ impl PackageJson {
}

pub(crate) fn name(&self) -> String {
trim_react_native(&self.name)
trim(&self.name)
}

pub(crate) fn android_package_name(&self) -> String {
Expand All @@ -37,7 +37,7 @@ impl PackageJson {
.unwrap_or_else(|| {
format!(
"com.{}",
trim_react_native_2(&self.name)
trim_react_native(&self.name)
.to_upper_camel_case()
.to_lowercase()
)
Expand Down
5 changes: 2 additions & 3 deletions crates/ubrn_cli/src/ios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@ use std::{collections::HashMap, fmt::Display, process::Command, str::FromStr};
use anyhow::{Context, Error, Result};
use camino::{Utf8Path, Utf8PathBuf};
use clap::Args;
use heck::ToUpperCamelCase;
use serde::{Deserialize, Serialize};
use ubrn_common::{mk_dir, rm_dir, run_cmd, CrateMetadata};

use crate::{
building::{CommonBuildArgs, ExtraArgs},
config::ProjectConfig,
config::{trim_react_native, ProjectConfig},
rust::CrateConfig,
workspace,
};
Expand Down Expand Up @@ -47,7 +46,7 @@ impl IOsConfig {
fn default_framework_name() -> String {
format!(
"{}Framework",
workspace::package_json().name().to_upper_camel_case()
trim_react_native(&workspace::package_json().name())
)
}

Expand Down
4 changes: 3 additions & 1 deletion docs/src/reference/turbo-module-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ There is a host of smaller files that need to be configured with these namespace
These include:

- For Javascript:
- An `index.ts` file, to call into the installation process, initialize the bindings for each namespace, and re-export the generated bindings for client code.
- An `index.tsx` file, to call into the installation process, initialize the bindings for each namespace, and re-export the generated bindings for client code.
- A Codegen file, to generates install methods from Javascript to Java and Objective C.
- For Android:
- A `Package.java` and `Module.java` file, which receives the codegen'd install method calls, to get the Hermes `JavascriptRuntime` and `CallInvokerHolder` to pass it via JNI to
Expand All @@ -21,3 +21,5 @@ These include:
- To build for Android
- A `CMakeLists.txt` file to configure the Android specific tool chain for all the generated C++ files.
- The `build.gradle` file which tells keeps the codegen package name in-sync and configures `cmake`. (note to self, this could be done from within the `CMakeLists.txt` file).

An up-to-date list can be found in [`ubrn_cli/src/codegen/templates`](https://github.com/jhugman/uniffi-bindgen-react-native/tree/main/crates/ubrn_cli/src/codegen/templates).
4 changes: 4 additions & 0 deletions integration/fixtures/turbo-module-testing/ubrn.config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
rust:
repo: https://github.com/ianthetechie/uniffi-starter
branch: main
manifestPath: rust/foobar/Cargo.toml
Loading

0 comments on commit c3fd7ab

Please sign in to comment.