Skip to content

Commit 87c0c44

Browse files
committed
Add cli to find node-api xcframework paths
1 parent 7005e3a commit 87c0c44

File tree

4 files changed

+109
-2
lines changed

4 files changed

+109
-2
lines changed

packages/react-native-node-api-modules/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"main": "dist/host/index.js",
77
"type": "commonjs",
88
"bin": {
9-
"react-native-node-api-modules": "./bin/react-native-node-api-modules.js"
9+
"react-native-node-api-modules": "./bin/react-native-node-api-modules.mjs"
1010
},
1111
"exports": {
1212
".": {
@@ -52,6 +52,10 @@
5252
}
5353
],
5454
"license": "MIT",
55+
"dependencies": {
56+
"@commander-js/extra-typings": "^13.1.0",
57+
"commander": "^13.1.0"
58+
},
5559
"devDependencies": {
5660
"metro-config": "0.81.1",
5761
"node-api-headers": "^1.5.0"

packages/react-native-node-api-modules/react-native-node-api-modules.podspec

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ require "json"
33
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
44

55
require_relative "./scripts/patch-hermes"
6+
require_relative "./scripts/find-node-api-xcframeworks"
7+
8+
# Crawl directories for node-api xcframeworks
9+
node_api_xcframework_paths = find_node_api_xcframeworks(Pod::Config.instance.installation_root, __dir__);
10+
Pod::UI.puts "Found node-api.xcframeworks:"
11+
node_api_xcframework_paths.each do |path|
12+
Pod::UI.puts "→ #{path}"
13+
end
614

715
Pod::Spec.new do |s|
816
s.name = package["name"]
@@ -18,6 +26,8 @@ Pod::Spec.new do |s|
1826
s.source_files = "ios/**/*.{h,m,mm}", "cpp/**/*.{hpp,cpp,c,h}", "include/*.h"
1927
s.public_header_files = "include/*.h"
2028

29+
s.vendored_frameworks = node_api_xcframework_paths
30+
2131
# Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
2232
# See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
2333
if respond_to?(:install_modules_dependencies, true)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
def find_node_api_xcframeworks(podfile_path, podspec_path)
2+
output = `npx react-native-node-api-modules print-xcframework-paths #{podfile_path}`
3+
paths = JSON.parse(output)
4+
5+
unless paths.is_a?(Array)
6+
raise "Expected a list of paths"
7+
end
8+
9+
paths.map { |path| Pathname.new(path).relative_path_from(Pathname.new(podspec_path)).to_s }
10+
end
Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,86 @@
1+
import assert from "node:assert/strict";
2+
import path from "node:path";
3+
import fs from "node:fs";
4+
import { createRequire } from "node:module";
5+
6+
import { Command } from "@commander-js/extra-typings";
7+
8+
const XCFRAMEWORK_NAME = "node-api.xcframework";
9+
10+
/**
11+
* Search upwards from a directory to find a package.json and
12+
* return a list of the resolved paths of all dependencies of that package.
13+
*/
14+
export function findPackageDependencyPaths(from: string): string[] {
15+
const candidatePath = path.join(from, "package.json");
16+
const parentDir = path.dirname(from);
17+
if (fs.existsSync(candidatePath)) {
18+
const require = createRequire(from);
19+
const contents = fs.readFileSync(candidatePath, "utf-8");
20+
const json = JSON.parse(contents) as unknown;
21+
// Assert the package.json has the expected structure
22+
assert(
23+
typeof json === "object" && json !== null,
24+
"Expected package.json to be an object"
25+
);
26+
if (
27+
"dependencies" in json &&
28+
typeof json.dependencies === "object" &&
29+
json.dependencies !== null
30+
) {
31+
return Object.keys(json.dependencies)
32+
.map((dependencyName) => {
33+
try {
34+
return path.dirname(
35+
require.resolve(`${dependencyName}/package.json`)
36+
);
37+
} catch {
38+
return undefined;
39+
}
40+
})
41+
.filter((p) => typeof p === "string");
42+
} else {
43+
return [];
44+
}
45+
} else if (parentDir === from) {
46+
throw new Error("package.json not found in any parent directory");
47+
} else {
48+
return findPackageDependencyPaths(parentDir);
49+
}
50+
}
51+
52+
export function findXCFrameworkPaths(dependencyPath: string): string[] {
53+
return fs
54+
.readdirSync(dependencyPath, { withFileTypes: true })
55+
.flatMap((file) => {
56+
if (file.isDirectory()) {
57+
if (file.name === XCFRAMEWORK_NAME) {
58+
return [path.join(dependencyPath, file.name)];
59+
} else {
60+
// Traverse into the child directory
61+
return findXCFrameworkPaths(path.join(dependencyPath, file.name));
62+
}
63+
} else {
64+
return [];
65+
}
66+
});
67+
}
68+
69+
export const program = new Command("react-native-node-api-modules");
70+
71+
program
72+
.command("print-xcframework-paths")
73+
.argument("<installation-root>", "Parent directory of the Podfile", (p) =>
74+
path.resolve(process.cwd(), p)
75+
)
76+
.action((installationRoot: string) => {
77+
// Find the package.json of the app
78+
const dependencyPaths = findPackageDependencyPaths(installationRoot);
79+
const xcframeworkPaths = dependencyPaths.flatMap(findXCFrameworkPaths);
80+
// Find all node-api.xcframeworks files in the dependencies
81+
console.log(JSON.stringify(xcframeworkPaths, null, 2));
82+
});
83+
184
export function run(argv: string[]) {
2-
console.log("Hello from react-native-node-api-modules");
85+
program.parse(argv);
386
}

0 commit comments

Comments
 (0)