@rejaul/react-native-rust 1.0.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,11 +4,22 @@ Generate Rust functions and native bindings from a React Native TurboModule Type
4
4
 
5
5
  The CLI currently targets the **C++ TurboModule** template created by [`create-react-native-library`](https://www.npmjs.com/package/create-react-native-library).
6
6
 
7
+ ## Screenshots
8
+
9
+ The generated [`react-native-awesome-library-example`](react-native-awesome-library-example) app calling every generated method and rendering its live Rust result, on all three platforms:
10
+
11
+ | Android | iOS | Web |
12
+ | --- | --- | --- |
13
+ | ![Android screenshot](doc/screenshots/android.png) | ![iOS screenshot](doc/screenshots/ios.png) | ![Web screenshot](doc/screenshots/web.png) |
14
+
7
15
  ## Contents
8
16
 
17
+ - [Screenshots](#screenshots)
9
18
  - [Requirements](#requirements)
10
19
  - [Create a library](#create-a-library)
11
20
  - [Add Rust functions](#add-rust-functions)
21
+ - [Use Rust in an app](#use-rust-in-an-app)
22
+ - [Automatic development mode](#automatic-development-mode)
12
23
  - [Build and run](#build-and-run)
13
24
  - [Supported types](#supported-types)
14
25
  - [Publish](#publish)
@@ -24,6 +35,7 @@ The CLI currently targets the **C++ TurboModule** template created by [`create-r
24
35
  - Rust stable (`rustup`, `cargo`).
25
36
  - Android builds: Android SDK/NDK and `cargo-ndk`.
26
37
  - iOS builds: macOS, Xcode command-line tools, and the Rust Apple targets.
38
+ - Web builds (`react-native-web`): [`wasm-pack`](https://rustwasm.github.io/wasm-pack/) and the `wasm32-unknown-unknown` Rust target (`rustup target add wasm32-unknown-unknown`).
27
39
 
28
40
  ## Create a library
29
41
 
@@ -42,10 +54,10 @@ cd react-native-awesome-library
42
54
  yarn install
43
55
  ```
44
56
 
45
- To run the CLI from its source checkout before publishing, use the checkout's path from the desired parent folder:
57
+ To run the CLI from its source checkout before publishing, build it once (`npm run build` from the checkout root), then invoke the compiled output by path from the desired parent folder:
46
58
 
47
59
  ```sh
48
- node /path/to/rust_to_cpp/bin/react-native-rust.js create react-native-awesome-library
60
+ node /path/to/rust_to_cpp/dist/react-native-rust.js create react-native-awesome-library
49
61
  ```
50
62
 
51
63
  To add Rust support to an existing C++ TurboModule library, install the CLI and initialize it from that library's root:
@@ -89,6 +101,89 @@ Run Rust tests with:
89
101
  yarn rust:test
90
102
  ```
91
103
 
104
+ ## Use Rust in an app
105
+
106
+ For app-specific Rust code, run the CLI from the root of an existing React Native Community CLI app that has both `android/` and `ios/` folders:
107
+
108
+ ```sh
109
+ npx react-native-rust init --app
110
+ npm install
111
+ ```
112
+
113
+ The command creates a private local TurboModule package in `.rust-native/` (hidden, generated C++/TurboModule glue only — never hand-edit it), and puts the Rust crate itself at the app's own root, `rust/`, alongside `android/` and `ios/`. It adds `.rust-native/` to the app as a local dependency and generates its C++ bridge. It does not publish a separate library. App-local mode currently supports C++ TurboModule apps with both Android and iOS projects.
114
+
115
+ ```
116
+ my-app/
117
+ ├── rust/ ← edit this: your Rust crate
118
+ │ ├── Cargo.toml
119
+ │ └── src/api/
120
+ ├── .rust-native/ ← generated TurboModule glue; do not edit
121
+ ├── android/
122
+ ├── ios/
123
+ └── package.json
124
+ ```
125
+
126
+ Edit `.rust-native/src/NativeRustApp.ts` to declare methods, then implement their generated handlers under `rust/src/api/`. From the app root, regenerate the bindings and React Native Codegen output with:
127
+
128
+ ```sh
129
+ npm run rust:generate
130
+ ```
131
+
132
+ Build the Rust archive for the target platform, then build and launch the React Native app:
133
+
134
+ ```sh
135
+ npm run rust:build:android
136
+ npx react-native run-android
137
+ ```
138
+
139
+ For iOS, build the XCFramework, install Pods, then launch the app:
140
+
141
+ ```sh
142
+ npm run rust:build:ios
143
+ cd ios && pod install && cd ..
144
+ npx react-native run-ios
145
+ ```
146
+
147
+ The generated module is app-local and can be used from the app's JavaScript imports. The root `example/` project in this repository exercises this workflow.
148
+
149
+ ## Automatic development mode
150
+
151
+ The commands above (`rust:generate`, `rust:build:*`) still work exactly as before and remain fully supported. For day-to-day development, `react-native-rust watch` runs instead, watching the `Spec` and `rust/` and reacting automatically:
152
+
153
+ ```
154
+ Legacy workflow: init → generate → build (repeated by hand after every change)
155
+ New workflow: init once → npx react-native-rust watch (or npx react-native start, with Metro integration below)
156
+ ```
157
+
158
+ On every save, the watcher classifies the change and reacts accordingly, matching what a manual run of `generate`/`build` would already produce:
159
+
160
+ - **A Rust file under `rust/src/`, or `Cargo.toml`/`Cargo.lock`, changes** (an implementation-only edit): it runs an incremental `cargo build` only. Native bindings are not regenerated.
161
+ - **The `Spec` file changes** (a new method, or a signature change): it runs `generate()` first — preserving hand-written Rust handler bodies, exactly like running `rust:generate` by hand — and then `cargo build`.
162
+ - Rapid successive saves are debounced and coalesced into one build; a build already in progress is never interrupted, and at most one more run is queued behind it.
163
+ - A failed build or a failed code generation prints the error and keeps watching; it does not crash the process or leave stale generated files.
164
+
165
+ Run it directly:
166
+
167
+ ```sh
168
+ npx react-native-rust watch
169
+ ```
170
+
171
+ Or wire it into Metro so `npx react-native start` runs it automatically:
172
+
173
+ ```js
174
+ // metro.config.js
175
+ const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
176
+ const { withRust } = require('@rejaul/react-native-rust/metro');
177
+
178
+ module.exports = withRust(mergeConfig(getDefaultConfig(__dirname), {}));
179
+ ```
180
+
181
+ `withRust()` detects your Rust project automatically at `rust/` (both library mode and app-local mode keep it at the project root) and adds it to `watchFolders`; pass `{ rustDir: './rust' }` only if your Rust project lives somewhere non-standard. It starts the watcher only while Metro's dev server is actually serving requests — never during a production/release bundle — and its `[Rust]`/`[RN Rust]` output streams into the same terminal as Metro's own. If Rust hasn't been initialized yet, it no-ops with a one-line notice instead of erroring, so it's safe to add before running `init`.
182
+
183
+ If Metro integration isn't wired up (or doesn't fit your setup), run `npx react-native-rust watch` in a separate terminal alongside `npx react-native start` — it does the same thing standalone.
184
+
185
+ **What this does not do:** Rust and C++ are native code. A running Android/iOS app cannot hot-swap a rebuilt native library the way Metro hot-swaps JavaScript. Each cycle rebuilds the Rust crate and prints a reminder that you still need to run `npm run rust:build:ios` / `rust:build:android` and reinstall the app to load the change on a simulator or device. A `Spec` change also regenerates `src/rust-generated.native.tsx`, which Metro's own JS watcher will pick up and Fast Refresh on its own, same as any other JS/TS change.
186
+
92
187
  ## Build and run
93
188
 
94
189
  Run these commands from the library root. Generate TurboModule Codegen output with `yarn prepare` before building the host app.
@@ -150,6 +245,30 @@ Rust outputs are written under `rust/build/` and included in the generated libra
150
245
 
151
246
  The example screen in `example/src/App.tsx` exercises the supported scalar, JSON, Promise, and callback signatures.
152
247
 
248
+ ### Web
249
+
250
+ Install `wasm-pack` and the `wasm32-unknown-unknown` target once:
251
+
252
+ ```sh
253
+ cargo install wasm-pack
254
+ rustup target add wasm32-unknown-unknown
255
+ ```
256
+
257
+ Build the WebAssembly package:
258
+
259
+ ```sh
260
+ yarn rust:build:web
261
+ ```
262
+
263
+ This compiles `rust/` to `rust/build/web/pkg/` with `wasm-pack build --target web`, reusing the same `rust/src/api/<method>.rs` handlers as native — no separate implementation is needed. It replaces the generated `src/rust-generated.tsx` module (used by web bundlers that don't understand Metro's `.native.` file convention, such as Vite or webpack) with a real, WASM-backed implementation instead of the "not supported on native platforms" stub used before this module exists. Call and await its exported `initRustWeb()` once before using any generated function on web, since loading a `.wasm` file is asynchronous:
264
+
265
+ ```ts
266
+ import { initRustWeb, multiply } from 'react-native-awesome-library';
267
+
268
+ await initRustWeb();
269
+ multiply(3, 7); // 21
270
+ ```
271
+
153
272
  ## Supported types
154
273
 
155
274
  The generator supports these TypeScript-to-Rust/C++ mappings:
@@ -169,6 +288,8 @@ Arrays and `UnsafeObject` values cross the native boundary as JSON, so their con
169
288
 
170
289
  Typed object structs, optional or rest parameters, destructured parameters, generic methods, and overloads are not supported. Unsupported signatures fail before generated files are changed.
171
290
 
291
+ The same mappings apply on `react-native-web`: values cross as JSON strings via `wasm-bindgen` instead of the JSI C++ bridge, and callback parameters are passed as a JS function. See [Web](#web) for the build step and the async `initRustWeb()` call it requires.
292
+
172
293
  ## Publish
173
294
 
174
295
  Before publishing a generated React Native library, generate its TypeScript/native outputs and build the Rust artifacts for the platforms you intend to ship:
@@ -177,6 +298,7 @@ Before publishing a generated React Native library, generate its TypeScript/nati
177
298
  yarn prepare
178
299
  yarn rust:build:ios
179
300
  yarn rust:build:android
301
+ yarn rust:build:web
180
302
  npm pack --dry-run
181
303
  ```
182
304
 
@@ -196,7 +318,12 @@ Pushing a version tag such as `v1.0.2` runs [`.github/workflows/publish.yml`](.g
196
318
  - Android CMake cannot find `android/generated/jni`: run `yarn prepare` from the library root.
197
319
  - Android CMake cannot find a Rust `.a` archive: run `yarn rust:build:android` before launching the example.
198
320
  - iOS reports a missing Rust XCFramework: run `yarn rust:build:ios`, then `pod install` in `example/ios`.
321
+ - `wasm-pack: command not found`: install it with `cargo install wasm-pack`, or run `react-native-rust doctor web` to check both prerequisites.
322
+ - The web app throws "Call and await initRustWeb()...": await `initRustWeb()` once before calling any other generated function; loading the `.wasm` file is asynchronous even though the generated calls are not.
199
323
  - A React Native type is reported as unsupported: check the mappings and signature restrictions in [Supported types](#supported-types).
324
+ - `react-native-rust watch` prints "Rust is not initialized": run `react-native-rust init` (or `init --app`) first; the watcher requires `rust/Cargo.toml` to exist.
325
+ - Changes made in a running app never appear, even after "`[Rust] Build completed`": native code cannot hot-swap into a running process. Run `npm run rust:build:ios` / `rust:build:android` and reinstall the app, as [Automatic development mode](#automatic-development-mode) describes.
326
+ - `npx react-native start` doesn't print any `[Rust]` lines: confirm `metro.config.js` calls `withRust(...)` and that `rust/Cargo.toml` exists at the project root; otherwise run `npx react-native-rust watch` in a separate terminal.
200
327
 
201
328
  ## Contributing
202
329
 
package/dist/app.js ADDED
@@ -0,0 +1,285 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var app_exports = {};
30
+ __export(app_exports, {
31
+ appModuleRoot: () => appModuleRoot,
32
+ inDirectory: () => inDirectory,
33
+ initApp: () => initApp,
34
+ runCodegen: () => runCodegen
35
+ });
36
+ module.exports = __toCommonJS(app_exports);
37
+ var import_node_fs = __toESM(require("node:fs"));
38
+ var import_node_path = __toESM(require("node:path"));
39
+ var import_node_child_process = require("node:child_process");
40
+ var import_react_native_rust_lib = require("./react-native-rust-lib");
41
+ const moduleDirectory = ".rust-native";
42
+ const moduleName = "RustApp";
43
+ const packageName = "rust-app-native-module";
44
+ function writeFiles(root, files) {
45
+ for (const [relativePath, contents] of Object.entries(files)) {
46
+ const outputPath = import_node_path.default.join(root, relativePath);
47
+ import_node_fs.default.mkdirSync(import_node_path.default.dirname(outputPath), { recursive: true });
48
+ import_node_fs.default.writeFileSync(outputPath, contents);
49
+ }
50
+ }
51
+ function scaffoldFiles(appName) {
52
+ const javaPackageName = appName.replace(/([a-z0-9])([A-Z])/g, "$1.$2").replace(/[^a-zA-Z0-9]+/g, ".").replace(/^\.+|\.+$/g, "").toLowerCase() || "com.rustapp";
53
+ return {
54
+ "package.json": `${JSON.stringify({
55
+ name: packageName,
56
+ version: "0.0.1",
57
+ description: "App-local Rust TurboModule",
58
+ main: "src/index.tsx",
59
+ "react-native": "src/index.tsx",
60
+ types: "src/index.tsx",
61
+ files: ["src/", "cpp/", "android/", "ios/", "*.podspec", "react-native.config.js"],
62
+ peerDependencies: { react: "*", "react-native": ">=0.76" },
63
+ codegenConfig: {
64
+ name: `${moduleName}Spec`,
65
+ type: "modules",
66
+ jsSrcsDir: "src",
67
+ outputDir: { ios: "ios/generated", android: "android/generated" },
68
+ android: { javaPackageName },
69
+ includesGeneratedCode: true
70
+ },
71
+ // The Rust crate lives at the app's own root, not inside this generated module package.
72
+ reactNativeRust: { rustDir: "../rust" }
73
+ }, null, 2)}
74
+ `,
75
+ "react-native.config.js": `module.exports = {
76
+ dependency: {
77
+ platforms: {
78
+ android: {
79
+ cmakeListsPath: 'generated/jni/CMakeLists.txt',
80
+ cxxModuleCMakeListsModuleName: '${packageName}',
81
+ cxxModuleCMakeListsPath: 'CMakeLists.txt',
82
+ cxxModuleHeaderName: '${moduleName}Impl',
83
+ },
84
+ },
85
+ },
86
+ };
87
+ `,
88
+ [`${moduleName}.podspec`]: `Pod::Spec.new do |s|
89
+ s.name = "${moduleName}"
90
+ s.version = "0.0.1"
91
+ s.summary = "App-local Rust TurboModule"
92
+ s.homepage = "https://example.invalid"
93
+ s.license = "MIT"
94
+ s.author = "Local app"
95
+ s.source = { :git => "https://example.invalid" }
96
+ s.platforms = { :ios => min_ios_version_supported }
97
+ s.source_files = "cpp/**/*.{hpp,cpp,c,h}", "ios/**/*.{h,m,mm}", "ios/generated/*.{h,cpp,mm}"
98
+ install_modules_dependencies(s)
99
+ end
100
+ `,
101
+ // rust-include, rust-build-android, rust-build-ios: generated by `init`/`build` to reach
102
+ // the Rust crate at the app's own root (see resolveOutsideReference) — a real symlink or, for
103
+ // iOS, a copied build artifact, never hand-authored.
104
+ ".gitignore": "node_modules/\nrust-include\nrust-build-android\nrust-build-ios\nrust-build-web-pkg\n",
105
+ "src/NativeRustApp.ts": `import { TurboModuleRegistry, type TurboModule } from 'react-native';
106
+
107
+ export interface Spec extends TurboModule {
108
+ multiply(a: number, b: number): number;
109
+ }
110
+
111
+ export default TurboModuleRegistry.getEnforcing<Spec>('${moduleName}');
112
+ `,
113
+ "src/index.tsx": "export * from './rust-generated';\n",
114
+ "cpp/RustAppImpl.h": `#pragma once
115
+
116
+ #include <${moduleName}SpecJSI.h>
117
+
118
+ #include <memory>
119
+
120
+ namespace facebook::react {
121
+
122
+ class ${moduleName}Impl : public Native${moduleName}CxxSpec<${moduleName}Impl> {
123
+ public:
124
+ ${moduleName}Impl(std::shared_ptr<CallInvoker> jsInvoker);
125
+ double multiply(jsi::Runtime& rt, double a, double b);
126
+ };
127
+
128
+ }
129
+ `,
130
+ "cpp/RustAppImpl.cpp": `#include "RustAppImpl.h"
131
+
132
+ namespace facebook::react {
133
+
134
+ ${moduleName}Impl::${moduleName}Impl(std::shared_ptr<CallInvoker> jsInvoker)
135
+ : Native${moduleName}CxxSpec(std::move(jsInvoker)) {}
136
+
137
+ double ${moduleName}Impl::multiply(jsi::Runtime&, double a, double b) {
138
+ return a * b;
139
+ }
140
+
141
+ }
142
+ `,
143
+ "android/CMakeLists.txt": `cmake_minimum_required(VERSION 3.13)
144
+ set(CMAKE_VERBOSE_MAKEFILE ON)
145
+
146
+ add_library(
147
+ ${packageName}
148
+ STATIC
149
+ ../cpp/${moduleName}Impl.cpp
150
+ )
151
+
152
+ set_target_properties(
153
+ ${packageName} PROPERTIES
154
+ CXX_STANDARD 20
155
+ CXX_STANDARD_REQUIRED ON
156
+ CXX_EXTENSIONS OFF
157
+ )
158
+
159
+ target_include_directories(${packageName} PUBLIC ../cpp)
160
+
161
+ target_link_libraries(
162
+ ${packageName}
163
+ jsi
164
+ reactnative
165
+ react_codegen_${moduleName}Spec
166
+ )
167
+ `,
168
+ "ios/OnLoad.mm": `#import <Foundation/Foundation.h>
169
+ #import "${moduleName}Impl.h"
170
+ #import <ReactCommon/CxxTurboModuleUtils.h>
171
+
172
+ @interface ${moduleName}OnLoad : NSObject
173
+ @end
174
+
175
+ @implementation ${moduleName}OnLoad
176
+
177
+ using namespace facebook::react;
178
+
179
+ + (void)load
180
+ {
181
+ registerCxxModuleToGlobalModuleMap(
182
+ std::string(${moduleName}Impl::kModuleName),
183
+ [](std::shared_ptr<CallInvoker> jsInvoker) {
184
+ return std::make_shared<${moduleName}Impl>(jsInvoker);
185
+ }
186
+ );
187
+ }
188
+
189
+ @end
190
+ `
191
+ };
192
+ }
193
+ function appModuleRoot(appRoot = process.cwd()) {
194
+ const moduleRoot = import_node_path.default.join(appRoot, moduleDirectory);
195
+ if (!import_node_fs.default.existsSync(import_node_path.default.join(moduleRoot, "package.json"))) return null;
196
+ return import_node_fs.default.existsSync(import_node_path.default.join(appRoot, "rust", "Cargo.toml")) ? moduleRoot : null;
197
+ }
198
+ function inDirectory(directory, callback) {
199
+ const previousDirectory = process.cwd();
200
+ process.chdir(directory);
201
+ try {
202
+ return callback();
203
+ } finally {
204
+ process.chdir(previousDirectory);
205
+ }
206
+ }
207
+ function runCodegen(appRoot, moduleRoot) {
208
+ const script = import_node_path.default.join(appRoot, "node_modules", "react-native", "scripts", "generate-codegen-artifacts.js");
209
+ if (!import_node_fs.default.existsSync(script)) {
210
+ throw new Error("React Native dependencies are missing. Install the app dependencies, then run `react-native-rust generate`.");
211
+ }
212
+ const result = (0, import_node_child_process.spawnSync)(process.execPath, [script, "-p", moduleRoot, "-t", "all", "-s", "library"], {
213
+ cwd: appRoot,
214
+ encoding: "utf8",
215
+ stdio: "pipe"
216
+ });
217
+ if (result.error || result.status !== 0) {
218
+ throw new Error(`React Native Codegen failed: ${(result.stderr || result.stdout || result.error?.message || "").trim()}`);
219
+ }
220
+ }
221
+ function initApp() {
222
+ const appRoot = process.cwd();
223
+ const appManifestPath = import_node_path.default.join(appRoot, "package.json");
224
+ if (!import_node_fs.default.existsSync(appManifestPath)) throw new Error("Run `react-native-rust init --app` from a React Native app root.");
225
+ const appManifest = (0, import_react_native_rust_lib.readJson)(appManifestPath);
226
+ if (!(appManifest.dependencies || {})["react-native"]) throw new Error("This project does not declare react-native as a dependency.");
227
+ if (!import_node_fs.default.existsSync(import_node_path.default.join(appRoot, "android")) || !import_node_fs.default.existsSync(import_node_path.default.join(appRoot, "ios"))) {
228
+ throw new Error("App-local Rust currently requires both Android and iOS native project folders.");
229
+ }
230
+ const moduleRoot = import_node_path.default.join(appRoot, moduleDirectory);
231
+ if (import_node_fs.default.existsSync(moduleRoot)) throw new Error(`${moduleDirectory} already exists; no files were changed.`);
232
+ import_node_fs.default.mkdirSync(moduleRoot, { recursive: true });
233
+ try {
234
+ writeFiles(moduleRoot, scaffoldFiles(appManifest.name || "rust-app"));
235
+ inDirectory(moduleRoot, import_react_native_rust_lib.init);
236
+ const cliManifest = (0, import_react_native_rust_lib.readJson)(import_node_path.default.join(__dirname, "..", "package.json"));
237
+ const cliRoot = import_node_path.default.resolve(__dirname, "..");
238
+ const cliIsInstalled = cliRoot.split(import_node_path.default.sep).includes("node_modules");
239
+ const cliDependency = cliIsInstalled ? `^${cliManifest.version}` : `file:${import_node_path.default.relative(appRoot, cliRoot).split(import_node_path.default.sep).join("/") || "."}`;
240
+ const moduleManifestPath = import_node_path.default.join(moduleRoot, "package.json");
241
+ const moduleManifest = (0, import_react_native_rust_lib.readJson)(moduleManifestPath);
242
+ delete moduleManifest.devDependencies?.[cliManifest.name];
243
+ import_node_fs.default.writeFileSync(moduleManifestPath, `${JSON.stringify(moduleManifest, null, 2)}
244
+ `);
245
+ appManifest.dependencies = {
246
+ ...appManifest.dependencies,
247
+ [packageName]: `file:./${moduleDirectory.split(import_node_path.default.sep).join("/")}`
248
+ };
249
+ appManifest.devDependencies = {
250
+ ...appManifest.devDependencies,
251
+ [cliManifest.name]: appManifest.devDependencies?.[cliManifest.name] || cliDependency
252
+ };
253
+ appManifest.scripts = {
254
+ ...appManifest.scripts,
255
+ "rust:generate": "react-native-rust generate",
256
+ "rust:build:ios": "react-native-rust build ios",
257
+ "rust:build:android": "react-native-rust build android",
258
+ "rust:test": "cargo test --manifest-path rust/Cargo.toml"
259
+ };
260
+ runCodegen(appRoot, moduleRoot);
261
+ import_node_fs.default.writeFileSync(appManifestPath, `${JSON.stringify(appManifest, null, 2)}
262
+ `);
263
+ const gitignorePath = import_node_path.default.join(appRoot, ".gitignore");
264
+ const gitignore = import_node_fs.default.existsSync(gitignorePath) ? import_node_fs.default.readFileSync(gitignorePath, "utf8") : "";
265
+ const ignoredRustOutputs = ["rust/target/", "rust/build/"].filter((entry) => !gitignore.split(/\r?\n/).includes(entry));
266
+ if (ignoredRustOutputs.length > 0) {
267
+ const separator = gitignore.length > 0 && !gitignore.endsWith("\n") ? "\n" : "";
268
+ import_node_fs.default.writeFileSync(gitignorePath, `${gitignore}${separator}${ignoredRustOutputs.join("\n")}
269
+ `);
270
+ }
271
+ } catch (error) {
272
+ import_node_fs.default.rmSync(moduleRoot, { recursive: true, force: true });
273
+ import_node_fs.default.rmSync(import_node_path.default.join(appRoot, "rust"), { recursive: true, force: true });
274
+ throw error;
275
+ }
276
+ console.log("Created app-local Rust TurboModule: edit rust/src/api/, glue lives in .rust-native/ (generated, do not edit).");
277
+ console.log("Install app dependencies, then run `npm run rust:build:android` or `npm run rust:build:ios`.");
278
+ }
279
+ // Annotate the CommonJS export names for ESM import in node:
280
+ 0 && (module.exports = {
281
+ appModuleRoot,
282
+ inDirectory,
283
+ initApp,
284
+ runCodegen
285
+ });
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var constants_exports = {};
30
+ __export(constants_exports, {
31
+ HEADER_END: () => HEADER_END,
32
+ HEADER_START: () => HEADER_START,
33
+ SOURCE_END: () => SOURCE_END,
34
+ SOURCE_START: () => SOURCE_START,
35
+ cppKeywords: () => cppKeywords,
36
+ rustKeywords: () => rustKeywords,
37
+ supportedTypes: () => supportedTypes,
38
+ ts: () => import_typescript.default
39
+ });
40
+ module.exports = __toCommonJS(constants_exports);
41
+ var import_typescript = __toESM(require("typescript"));
42
+ const HEADER_START = "// react-native-rust:generated-methods:start";
43
+ const HEADER_END = "// react-native-rust:generated-methods:end";
44
+ const SOURCE_START = "// react-native-rust:generated-methods:start";
45
+ const SOURCE_END = "// react-native-rust:generated-methods:end";
46
+ const rustKeywords = /* @__PURE__ */ new Set([
47
+ "as",
48
+ "async",
49
+ "await",
50
+ "break",
51
+ "const",
52
+ "continue",
53
+ "crate",
54
+ "dyn",
55
+ "else",
56
+ "enum",
57
+ "extern",
58
+ "false",
59
+ "fn",
60
+ "for",
61
+ "if",
62
+ "impl",
63
+ "in",
64
+ "let",
65
+ "loop",
66
+ "match",
67
+ "mod",
68
+ "move",
69
+ "mut",
70
+ "pub",
71
+ "ref",
72
+ "return",
73
+ "self",
74
+ "Self",
75
+ "static",
76
+ "struct",
77
+ "super",
78
+ "trait",
79
+ "true",
80
+ "type",
81
+ "unsafe",
82
+ "use",
83
+ "where",
84
+ "while"
85
+ ]);
86
+ const cppKeywords = /* @__PURE__ */ new Set([
87
+ "alignas",
88
+ "alignof",
89
+ "and",
90
+ "asm",
91
+ "auto",
92
+ "bool",
93
+ "break",
94
+ "case",
95
+ "catch",
96
+ "char",
97
+ "class",
98
+ "const",
99
+ "continue",
100
+ "default",
101
+ "delete",
102
+ "do",
103
+ "double",
104
+ "else",
105
+ "enum",
106
+ "explicit",
107
+ "export",
108
+ "extern",
109
+ "false",
110
+ "float",
111
+ "for",
112
+ "friend",
113
+ "goto",
114
+ "if",
115
+ "inline",
116
+ "int",
117
+ "long",
118
+ "namespace",
119
+ "new",
120
+ "noexcept",
121
+ "not",
122
+ "nullptr",
123
+ "operator",
124
+ "or",
125
+ "private",
126
+ "protected",
127
+ "public",
128
+ "register",
129
+ "return",
130
+ "short",
131
+ "signed",
132
+ "sizeof",
133
+ "static",
134
+ "struct",
135
+ "switch",
136
+ "template",
137
+ "this",
138
+ "throw",
139
+ "true",
140
+ "try",
141
+ "typedef",
142
+ "typename",
143
+ "union",
144
+ "unsigned",
145
+ "using",
146
+ "virtual",
147
+ "void",
148
+ "volatile",
149
+ "while",
150
+ "xor"
151
+ ]);
152
+ const supportedTypes = /* @__PURE__ */ new Map([
153
+ [import_typescript.default.SyntaxKind.NumberKeyword, { kind: "number", typescript: "number", rust: "f64", cpp: "double", defaultValue: "0.0" }],
154
+ [import_typescript.default.SyntaxKind.BooleanKeyword, { kind: "boolean", typescript: "boolean", rust: "bool", cpp: "bool", defaultValue: "false" }],
155
+ [import_typescript.default.SyntaxKind.StringKeyword, { kind: "json", typescript: "string", rust: "String", cpp: "jsi::String", defaultValue: "String::new()" }],
156
+ [import_typescript.default.SyntaxKind.VoidKeyword, { kind: "void", typescript: "void", rust: "()", cpp: "void", defaultValue: null }]
157
+ ]);
158
+ // Annotate the CommonJS export names for ESM import in node:
159
+ 0 && (module.exports = {
160
+ HEADER_END,
161
+ HEADER_START,
162
+ SOURCE_END,
163
+ SOURCE_START,
164
+ cppKeywords,
165
+ rustKeywords,
166
+ supportedTypes,
167
+ ts
168
+ });
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var codegen_exports = {};
20
+ __export(codegen_exports, {
21
+ parseSpec: () => import_spec.parseSpec,
22
+ renderProjectBindings: () => import_project.renderProjectBindings,
23
+ renderRustFfiModule: () => import_renderers.renderRustFfiModule,
24
+ resolveOutsideReference: () => import_project.resolveOutsideReference,
25
+ toPosixRelative: () => import_project.toPosixRelative
26
+ });
27
+ module.exports = __toCommonJS(codegen_exports);
28
+ var import_spec = require("./spec");
29
+ var import_renderers = require("./renderers");
30
+ var import_project = require("./project");
31
+ // Annotate the CommonJS export names for ESM import in node:
32
+ 0 && (module.exports = {
33
+ parseSpec,
34
+ renderProjectBindings,
35
+ renderRustFfiModule,
36
+ resolveOutsideReference,
37
+ toPosixRelative
38
+ });