@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 +129 -2
- package/dist/app.js +285 -0
- package/dist/codegen/constants.js +168 -0
- package/dist/codegen/index.js +38 -0
- package/dist/codegen/project.js +221 -0
- package/{bin → dist}/codegen/renderers.js +201 -84
- package/dist/codegen/spec.js +158 -0
- package/dist/codegen/types.js +16 -0
- package/dist/codegen.js +22 -0
- package/dist/dev/buildQueue.js +54 -0
- package/dist/dev/watcher.js +90 -0
- package/dist/metro.js +100 -0
- package/dist/react-native-rust-lib.js +470 -0
- package/dist/react-native-rust.js +130 -0
- package/dist/types.js +16 -0
- package/metro.js +2 -0
- package/package.json +30 -4
- package/bin/codegen/constants.js +0 -39
- package/bin/codegen/index.js +0 -9
- package/bin/codegen/project.js +0 -168
- package/bin/codegen/spec.js +0 -156
- package/bin/codegen.js +0 -1
- package/bin/react-native-rust-lib.js +0 -302
- package/bin/react-native-rust.js +0 -82
|
@@ -0,0 +1,158 @@
|
|
|
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 spec_exports = {};
|
|
20
|
+
__export(spec_exports, {
|
|
21
|
+
callbackInfo: () => callbackInfo,
|
|
22
|
+
parseSpec: () => parseSpec,
|
|
23
|
+
toSnakeCase: () => toSnakeCase,
|
|
24
|
+
typeInfo: () => typeInfo,
|
|
25
|
+
validateIdentifier: () => validateIdentifier
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(spec_exports);
|
|
28
|
+
var import_constants = require("./constants");
|
|
29
|
+
function typeInfo(typeNode, sourceFile, methodName, role) {
|
|
30
|
+
const info = import_constants.supportedTypes.get(typeNode.kind);
|
|
31
|
+
if (info && !(role === "parameter" && typeNode.kind === import_constants.ts.SyntaxKind.VoidKeyword)) return info;
|
|
32
|
+
if (role === "return" && import_constants.ts.isTypeReferenceNode(typeNode) && typeNode.typeName.getText(sourceFile) === "Promise") {
|
|
33
|
+
if (typeNode.typeArguments?.length !== 1) throw new Error(`Promise return in ${methodName}() must declare one result type.`);
|
|
34
|
+
const result = typeInfo(typeNode.typeArguments[0], sourceFile, methodName, "promise result");
|
|
35
|
+
if (result.promise) {
|
|
36
|
+
throw new Error(`Nested Promise or callback results are not supported in ${methodName}().`);
|
|
37
|
+
}
|
|
38
|
+
return { ...result, typescript: typeNode.getText(sourceFile), promise: true };
|
|
39
|
+
}
|
|
40
|
+
const typeName = import_constants.ts.isTypeReferenceNode(typeNode) ? typeNode.typeName.getText(sourceFile) : "";
|
|
41
|
+
const objectType = typeNode.kind === import_constants.ts.SyntaxKind.ObjectKeyword || ["CodegenTypes.UnsafeObject", "UnsafeObject"].includes(typeName);
|
|
42
|
+
if (objectType) {
|
|
43
|
+
return {
|
|
44
|
+
kind: "json",
|
|
45
|
+
typescript: typeNode.getText(sourceFile),
|
|
46
|
+
rust: "serde_json::Value",
|
|
47
|
+
cpp: "jsi::Object",
|
|
48
|
+
defaultValue: "serde_json::json!({})"
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const arrayElement = import_constants.ts.isArrayTypeNode(typeNode) ? typeNode.elementType : import_constants.ts.isTypeReferenceNode(typeNode) && ["Array", "ReadonlyArray"].includes(typeNode.typeName.getText(sourceFile)) && typeNode.typeArguments?.length === 1 ? typeNode.typeArguments[0] : null;
|
|
52
|
+
if (arrayElement) {
|
|
53
|
+
const elementType = typeInfo(arrayElement, sourceFile, methodName, "array element");
|
|
54
|
+
if (elementType.promise || elementType.kind === "void") {
|
|
55
|
+
throw new Error(`Unsupported array element type in ${methodName}().`);
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
kind: "json",
|
|
59
|
+
typescript: typeNode.getText(sourceFile),
|
|
60
|
+
rust: "serde_json::Value",
|
|
61
|
+
cpp: "jsi::Array",
|
|
62
|
+
defaultValue: "serde_json::json!([])"
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const text = typeNode.getText(sourceFile);
|
|
66
|
+
throw new Error(`Unsupported ${role} type "${text}" in ${methodName}(). Supported types are number, boolean, string, arrays, and CodegenTypes.UnsafeObject${role === "return" ? ", plus void and Promise<T>" : ""}.`);
|
|
67
|
+
}
|
|
68
|
+
function callbackInfo(typeNode, sourceFile, methodName) {
|
|
69
|
+
if (!import_constants.ts.isFunctionTypeNode(typeNode) || typeNode.typeParameters?.length) {
|
|
70
|
+
throw new Error(`Unsupported callback signature in ${methodName}().`);
|
|
71
|
+
}
|
|
72
|
+
if (typeNode.type.kind !== import_constants.ts.SyntaxKind.VoidKeyword || typeNode.parameters.length > 4) {
|
|
73
|
+
throw new Error(`Callbacks in ${methodName}() must return void and have at most four parameters.`);
|
|
74
|
+
}
|
|
75
|
+
const params = typeNode.parameters.map((parameter) => {
|
|
76
|
+
if (!import_constants.ts.isIdentifier(parameter.name) || parameter.questionToken || parameter.dotDotDotToken || !parameter.type) {
|
|
77
|
+
throw new Error(`Callback parameters in ${methodName}() must be named, required, and explicitly typed.`);
|
|
78
|
+
}
|
|
79
|
+
const info = typeInfo(parameter.type, sourceFile, methodName, "callback parameter");
|
|
80
|
+
if (info.promise || info.kind === "void") {
|
|
81
|
+
throw new Error(`Unsupported callback parameter type in ${methodName}().`);
|
|
82
|
+
}
|
|
83
|
+
return { name: parameter.name.text, ...info };
|
|
84
|
+
});
|
|
85
|
+
return { kind: "callback", typescript: typeNode.getText(sourceFile), cpp: "jsi::Function", params };
|
|
86
|
+
}
|
|
87
|
+
function toSnakeCase(name) {
|
|
88
|
+
return name.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
|
|
89
|
+
}
|
|
90
|
+
function validateIdentifier(name, location) {
|
|
91
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name) || import_constants.rustKeywords.has(name) || import_constants.cppKeywords.has(name)) {
|
|
92
|
+
throw new Error(`Unsupported identifier "${name}" in ${location}; use a non-keyword identifier.`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function parseSpec(sourceText, fileName = "NativeModule.ts") {
|
|
96
|
+
const sourceFile = import_constants.ts.createSourceFile(fileName, sourceText, import_constants.ts.ScriptTarget.Latest, true, import_constants.ts.ScriptKind.TS);
|
|
97
|
+
if (sourceFile.parseDiagnostics.length > 0) {
|
|
98
|
+
const diagnostic = sourceFile.parseDiagnostics[0];
|
|
99
|
+
throw new Error(`Could not parse ${fileName}: ${import_constants.ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")}`);
|
|
100
|
+
}
|
|
101
|
+
const spec = sourceFile.statements.find((statement) => import_constants.ts.isInterfaceDeclaration(statement) && statement.name.text === "Spec");
|
|
102
|
+
if (!spec) throw new Error(`No "Spec" interface was found in ${fileName}.`);
|
|
103
|
+
if (spec.typeParameters?.length) throw new Error("Generic TurboModule Spec interfaces are not supported.");
|
|
104
|
+
if (spec.members.length === 0) throw new Error("The Spec interface must declare at least one method.");
|
|
105
|
+
const names = /* @__PURE__ */ new Set();
|
|
106
|
+
const rustNames = /* @__PURE__ */ new Set();
|
|
107
|
+
const methods = spec.members.map((member) => {
|
|
108
|
+
if (!import_constants.ts.isMethodSignature(member)) {
|
|
109
|
+
throw new Error("Only method signatures are supported in the Spec interface.");
|
|
110
|
+
}
|
|
111
|
+
if (!member.name || !import_constants.ts.isIdentifier(member.name) || member.questionToken || member.typeParameters?.length) {
|
|
112
|
+
throw new Error("Optional, computed, and generic Spec methods are not supported.");
|
|
113
|
+
}
|
|
114
|
+
const name = member.name.text;
|
|
115
|
+
validateIdentifier(name, "Spec method");
|
|
116
|
+
if (names.has(name)) throw new Error(`Overloaded method "${name}" is not supported.`);
|
|
117
|
+
names.add(name);
|
|
118
|
+
const rustName = toSnakeCase(name);
|
|
119
|
+
validateIdentifier(rustName, `Rust mapping for ${name}()`);
|
|
120
|
+
if (rustNames.has(rustName)) throw new Error(`Multiple Spec methods map to the Rust name "${rustName}".`);
|
|
121
|
+
rustNames.add(rustName);
|
|
122
|
+
const params = member.parameters.map((parameter) => {
|
|
123
|
+
if (!import_constants.ts.isIdentifier(parameter.name) || parameter.dotDotDotToken || parameter.questionToken || parameter.initializer) {
|
|
124
|
+
throw new Error(`Rest, optional, and destructured parameters are not supported in ${name}().`);
|
|
125
|
+
}
|
|
126
|
+
const paramName = parameter.name.text;
|
|
127
|
+
validateIdentifier(paramName, `parameter in ${name}()`);
|
|
128
|
+
if (!parameter.type) throw new Error(`Parameter "${paramName}" in ${name}() needs an explicit type.`);
|
|
129
|
+
const info = import_constants.ts.isFunctionTypeNode(parameter.type) ? callbackInfo(parameter.type, sourceFile, name) : typeInfo(parameter.type, sourceFile, name, "parameter");
|
|
130
|
+
return { name: paramName, ...info };
|
|
131
|
+
});
|
|
132
|
+
if (new Set(params.map((param) => param.name)).size !== params.length) {
|
|
133
|
+
throw new Error(`Duplicate parameter names are not supported in ${name}().`);
|
|
134
|
+
}
|
|
135
|
+
if (!member.type) throw new Error(`Method "${name}()" needs an explicit return type.`);
|
|
136
|
+
return {
|
|
137
|
+
name,
|
|
138
|
+
rustName,
|
|
139
|
+
symbol: `rnrs_${rustName}`,
|
|
140
|
+
params,
|
|
141
|
+
returnType: typeInfo(member.type, sourceFile, name, "return")
|
|
142
|
+
};
|
|
143
|
+
});
|
|
144
|
+
for (const method of methods) {
|
|
145
|
+
if (method.returnType.promise && method.params.some((param) => param.kind === "callback")) {
|
|
146
|
+
throw new Error(`Callbacks in Promise method ${method.name}() are not supported. Use a Codegen event emitter for asynchronous callbacks.`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return methods;
|
|
150
|
+
}
|
|
151
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
152
|
+
0 && (module.exports = {
|
|
153
|
+
callbackInfo,
|
|
154
|
+
parseSpec,
|
|
155
|
+
toSnakeCase,
|
|
156
|
+
typeInfo,
|
|
157
|
+
validateIdentifier
|
|
158
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
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 __copyProps = (to, from, except, desc) => {
|
|
7
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
|
+
for (let key of __getOwnPropNames(from))
|
|
9
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
10
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
11
|
+
}
|
|
12
|
+
return to;
|
|
13
|
+
};
|
|
14
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
15
|
+
var types_exports = {};
|
|
16
|
+
module.exports = __toCommonJS(types_exports);
|
package/dist/codegen.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
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 __copyProps = (to, from, except, desc) => {
|
|
7
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
|
+
for (let key of __getOwnPropNames(from))
|
|
9
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
10
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
11
|
+
}
|
|
12
|
+
return to;
|
|
13
|
+
};
|
|
14
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
15
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
16
|
+
var codegen_exports = {};
|
|
17
|
+
module.exports = __toCommonJS(codegen_exports);
|
|
18
|
+
__reExport(codegen_exports, require("./codegen/index"), module.exports);
|
|
19
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
20
|
+
0 && (module.exports = {
|
|
21
|
+
...require("./codegen/index")
|
|
22
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
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 buildQueue_exports = {};
|
|
20
|
+
__export(buildQueue_exports, {
|
|
21
|
+
SingleFlightQueue: () => SingleFlightQueue
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(buildQueue_exports);
|
|
24
|
+
class SingleFlightQueue {
|
|
25
|
+
constructor(task) {
|
|
26
|
+
this.task = task;
|
|
27
|
+
}
|
|
28
|
+
task;
|
|
29
|
+
running = false;
|
|
30
|
+
pending = false;
|
|
31
|
+
/** Requests a run. Coalesced into the in-flight run's follow-up if one is already running. */
|
|
32
|
+
request() {
|
|
33
|
+
if (this.running) {
|
|
34
|
+
this.pending = true;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
void this.run();
|
|
38
|
+
}
|
|
39
|
+
async run() {
|
|
40
|
+
this.running = true;
|
|
41
|
+
do {
|
|
42
|
+
this.pending = false;
|
|
43
|
+
try {
|
|
44
|
+
await this.task();
|
|
45
|
+
} catch {
|
|
46
|
+
}
|
|
47
|
+
} while (this.pending);
|
|
48
|
+
this.running = false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
52
|
+
0 && (module.exports = {
|
|
53
|
+
SingleFlightQueue
|
|
54
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
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 watcher_exports = {};
|
|
30
|
+
__export(watcher_exports, {
|
|
31
|
+
classifyChange: () => classifyChange,
|
|
32
|
+
watchRustProject: () => watchRustProject
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(watcher_exports);
|
|
35
|
+
var import_node_path = __toESM(require("node:path"));
|
|
36
|
+
var import_chokidar = __toESM(require("chokidar"));
|
|
37
|
+
function classifyChange(filePath, target) {
|
|
38
|
+
const resolved = import_node_path.default.resolve(filePath);
|
|
39
|
+
if (resolved === import_node_path.default.resolve(target.specPath)) return "spec";
|
|
40
|
+
const rustSrc = import_node_path.default.resolve(target.rustRoot, "src");
|
|
41
|
+
const cargoToml = import_node_path.default.resolve(target.rustRoot, "Cargo.toml");
|
|
42
|
+
const cargoLock = import_node_path.default.resolve(target.rustRoot, "Cargo.lock");
|
|
43
|
+
if (resolved === cargoToml || resolved === cargoLock) return "rust";
|
|
44
|
+
if (resolved.startsWith(`${rustSrc}${import_node_path.default.sep}`) && resolved.endsWith(".rs")) return "rust";
|
|
45
|
+
return "other";
|
|
46
|
+
}
|
|
47
|
+
function watchRustProject(options) {
|
|
48
|
+
const { target, onChange, debounceMs = 200, log = console.log } = options;
|
|
49
|
+
const watcher = import_chokidar.default.watch(
|
|
50
|
+
[import_node_path.default.join(target.rustRoot, "**", "*.rs"), import_node_path.default.join(target.rustRoot, "Cargo.toml"), import_node_path.default.join(target.rustRoot, "Cargo.lock"), target.specPath],
|
|
51
|
+
{
|
|
52
|
+
ignored: [
|
|
53
|
+
import_node_path.default.join(target.rustRoot, "target", "**"),
|
|
54
|
+
import_node_path.default.join(target.rustRoot, "build", "**"),
|
|
55
|
+
import_node_path.default.join(target.rustRoot, "include", "**"),
|
|
56
|
+
"**/node_modules/**",
|
|
57
|
+
"**/.git/**"
|
|
58
|
+
],
|
|
59
|
+
ignoreInitial: true,
|
|
60
|
+
// Waits for a file's size to stop changing before firing, so editors that write in
|
|
61
|
+
// multiple chunks (atomic saves, rename-into-place) produce one event, not several.
|
|
62
|
+
awaitWriteFinish: { stabilityThreshold: 100, pollInterval: 20 }
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
let pendingKinds = /* @__PURE__ */ new Set();
|
|
66
|
+
let timer = null;
|
|
67
|
+
const schedule = (filePath, eventLabel) => {
|
|
68
|
+
const kind = classifyChange(filePath, target);
|
|
69
|
+
if (kind === "other") return;
|
|
70
|
+
pendingKinds.add(kind);
|
|
71
|
+
log(`[Rust] ${eventLabel} ${import_node_path.default.relative(import_node_path.default.dirname(target.rustRoot), filePath)}`);
|
|
72
|
+
if (timer) clearTimeout(timer);
|
|
73
|
+
timer = setTimeout(() => {
|
|
74
|
+
const kinds = pendingKinds;
|
|
75
|
+
pendingKinds = /* @__PURE__ */ new Set();
|
|
76
|
+
timer = null;
|
|
77
|
+
onChange(kinds);
|
|
78
|
+
}, debounceMs);
|
|
79
|
+
};
|
|
80
|
+
watcher.on("add", (filePath) => schedule(filePath, "Added"));
|
|
81
|
+
watcher.on("change", (filePath) => schedule(filePath, "Changed"));
|
|
82
|
+
watcher.on("unlink", (filePath) => schedule(filePath, "Deleted"));
|
|
83
|
+
watcher.on("error", (error) => log(`[Rust] Watcher error: ${error.message}`));
|
|
84
|
+
return watcher;
|
|
85
|
+
}
|
|
86
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
87
|
+
0 && (module.exports = {
|
|
88
|
+
classifyChange,
|
|
89
|
+
watchRustProject
|
|
90
|
+
});
|
package/dist/metro.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
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 metro_exports = {};
|
|
30
|
+
__export(metro_exports, {
|
|
31
|
+
findRustDir: () => findRustDir,
|
|
32
|
+
stopRustWatcher: () => stopRustWatcher,
|
|
33
|
+
withRust: () => withRust
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(metro_exports);
|
|
36
|
+
var import_node_fs = __toESM(require("node:fs"));
|
|
37
|
+
var import_node_path = __toESM(require("node:path"));
|
|
38
|
+
var import_node_child_process = require("node:child_process");
|
|
39
|
+
let watcherProcess = null;
|
|
40
|
+
function findRustDir(projectRoot, rustDir) {
|
|
41
|
+
const resolved = import_node_path.default.resolve(projectRoot, rustDir || "rust");
|
|
42
|
+
return import_node_fs.default.existsSync(import_node_path.default.join(resolved, "Cargo.toml")) ? resolved : null;
|
|
43
|
+
}
|
|
44
|
+
function ensureWatcherRunning(projectRoot, notify) {
|
|
45
|
+
if (watcherProcess) return;
|
|
46
|
+
const cliEntry = import_node_path.default.join(__dirname, "react-native-rust.js");
|
|
47
|
+
const child = (0, import_node_child_process.spawn)(process.execPath, [cliEntry, "watch"], { cwd: projectRoot });
|
|
48
|
+
watcherProcess = child;
|
|
49
|
+
child.stdout?.on("data", (chunk) => process.stdout.write(chunk));
|
|
50
|
+
child.stderr?.on("data", (chunk) => process.stderr.write(chunk));
|
|
51
|
+
child.on("exit", (code) => {
|
|
52
|
+
watcherProcess = null;
|
|
53
|
+
if (code !== 0 && code !== null) {
|
|
54
|
+
notify(`[RN Rust] The Rust watcher exited unexpectedly (code ${code}). Restart Metro to retry, or run \`npx react-native-rust watch\` manually.`);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
const stop = () => {
|
|
58
|
+
if (watcherProcess) watcherProcess.kill("SIGINT");
|
|
59
|
+
};
|
|
60
|
+
process.once("exit", stop);
|
|
61
|
+
process.once("SIGINT", stop);
|
|
62
|
+
process.once("SIGTERM", stop);
|
|
63
|
+
}
|
|
64
|
+
function stopRustWatcher() {
|
|
65
|
+
if (!watcherProcess) return Promise.resolve();
|
|
66
|
+
const child = watcherProcess;
|
|
67
|
+
return new Promise((resolve) => {
|
|
68
|
+
child.once("exit", () => resolve());
|
|
69
|
+
child.kill("SIGINT");
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
function withRust(config, options = {}) {
|
|
73
|
+
const projectRoot = config.projectRoot || process.cwd();
|
|
74
|
+
const rustDir = findRustDir(projectRoot, options.rustDir);
|
|
75
|
+
const existingWatchFolders = config.watchFolders || [];
|
|
76
|
+
const watchFolders = rustDir && !existingWatchFolders.includes(rustDir) ? [...existingWatchFolders, rustDir] : existingWatchFolders;
|
|
77
|
+
const previousEnhanceMiddleware = config.server?.enhanceMiddleware;
|
|
78
|
+
return {
|
|
79
|
+
...config,
|
|
80
|
+
watchFolders,
|
|
81
|
+
server: {
|
|
82
|
+
...config.server,
|
|
83
|
+
enhanceMiddleware: (middleware, server) => {
|
|
84
|
+
const next = previousEnhanceMiddleware ? previousEnhanceMiddleware(middleware, server) : middleware;
|
|
85
|
+
if (rustDir) {
|
|
86
|
+
ensureWatcherRunning(projectRoot, console.log);
|
|
87
|
+
} else {
|
|
88
|
+
console.log("[RN Rust] No rust/Cargo.toml found; skipping the automatic Rust watcher. Run `npx react-native-rust init` (or `init --app`) to add Rust support.");
|
|
89
|
+
}
|
|
90
|
+
return next;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
96
|
+
0 && (module.exports = {
|
|
97
|
+
findRustDir,
|
|
98
|
+
stopRustWatcher,
|
|
99
|
+
withRust
|
|
100
|
+
});
|