diff --git a/.changeset/tired-news-sort.md b/.changeset/tired-news-sort.md new file mode 100644 index 00000000..fe10f0f7 --- /dev/null +++ b/.changeset/tired-news-sort.md @@ -0,0 +1,6 @@ +--- +"ferric-cli": patch +--- + +- Add path as arg to build project. +- Changed default build output to send to dist folder. diff --git a/eslint.config.js b/eslint.config.js index c0af837e..6e46dec4 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -13,8 +13,8 @@ export default tseslint.config( "apps/test-app/ios/**", "packages/host/hermes/**", "packages/node-addon-examples/examples/**", - "packages/ferric-example/ferric_example.js", - "packages/ferric-example/ferric_example.d.ts", + "packages/ferric-example/dist/ferric_example.d.ts", + "packages/ferric-example/dist/ferric_example.js", "packages/ferric-example/target/**", "packages/node-tests/node/**", "packages/node-tests/tests/**", diff --git a/package-lock.json b/package-lock.json index 12ad7aa0..fa0f4050 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4077,9 +4077,9 @@ } }, "node_modules/@napi-rs/cli": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-3.0.3.tgz", - "integrity": "sha512-5PxtOcax9PoOriYWYf8BFNgOzUnsogYUDRM8p2leT2VtG/NTMZCyoRQMzSMB0qEaw+Durkefc5jXCpEF6wrWbA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-3.0.4.tgz", + "integrity": "sha512-ilbCI69DVDQcIUSUB504LM1+Nhvo0jKycWAzzPJ22YwUoWrru/w0+V5sfjPINgkshQ4Ykv+oZOJXk9Kg1ZBUvg==", "license": "MIT", "dependencies": { "@inquirer/prompts": "^7.4.0", @@ -4094,8 +4094,7 @@ "js-yaml": "^4.1.0", "lodash-es": "^4.17.21", "semver": "^7.7.1", - "typanion": "^3.14.0", - "wasm-sjlj": "^1.0.6" + "typanion": "^3.14.0" }, "bin": { "napi": "dist/cli.js", @@ -6584,9 +6583,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, @@ -7613,9 +7612,9 @@ "license": "MIT" }, "node_modules/bufout": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/bufout/-/bufout-0.3.2.tgz", - "integrity": "sha512-8C3TSxBG6jbr0L/PvDo90z5lsc+mpebbV2ZeRlg7f/4Lda/88mb8A4sOngfBj5y1V3I7yRrCuMBPpg5T5tGkcg==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/bufout/-/bufout-0.3.4.tgz", + "integrity": "sha512-m8iGxYUvWLdQ9CQ9Sjnmr8hJHlpXfRQn2CV3eI5b107MWQqAe/K/pqsCGmczkSy3r7E1HW5u5z86z2aBYbwwxQ==", "license": "ISC" }, "node_modules/bytes": { @@ -14054,12 +14053,6 @@ "makeerror": "1.0.12" } }, - "node_modules/wasm-sjlj": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/wasm-sjlj/-/wasm-sjlj-1.0.6.tgz", - "integrity": "sha512-pjaKtLJejlWm6+okPV2X1A6nIsRDD4qeK97eCh8DP8KXi3Nzn/HY01vpHhZHlhDri12eZqipjm8HhdTVw+ATxw==", - "license": "MIT" - }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", @@ -14568,11 +14561,11 @@ "name": "ferric-cli", "version": "0.2.3", "dependencies": { - "@commander-js/extra-typings": "^13.1.0", - "@napi-rs/cli": "~3.0.3", - "bufout": "^0.3.2", + "@commander-js/extra-typings": "14.0.0", + "@napi-rs/cli": "~3.0.4", + "bufout": "0.3.4", "chalk": "^5.4.1", - "commander": "^13.1.0", + "commander": "14.0.0", "ora": "^8.2.0", "react-native-node-api": "0.3.2" }, @@ -14588,12 +14581,12 @@ } }, "packages/ferric/node_modules/@commander-js/extra-typings": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@commander-js/extra-typings/-/extra-typings-13.1.0.tgz", - "integrity": "sha512-q5P52BYb1hwVWE6dtID7VvuJWrlfbCv4klj7BjUUOqMz4jbSZD4C9fJ9lRjL2jnBGTg+gDDlaXN51rkWcLk4fg==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@commander-js/extra-typings/-/extra-typings-14.0.0.tgz", + "integrity": "sha512-hIn0ncNaJRLkZrxBIp5AsW/eXEHNKYQBh0aPdoUqNgD+Io3NIykQqpKFyKcuasZhicGaEZJX/JBSIkZ4e5x8Dg==", "license": "MIT", "peerDependencies": { - "commander": "~13.1.0" + "commander": "~14.0.0" } }, "packages/ferric/node_modules/ansi-regex": { @@ -14636,12 +14629,12 @@ } }, "packages/ferric/node_modules/commander": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", - "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.0.tgz", + "integrity": "sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20" } }, "packages/ferric/node_modules/emoji-regex": { diff --git a/packages/ferric-example/.gitignore b/packages/ferric-example/.gitignore index 31c8570c..c984ee9d 100644 --- a/packages/ferric-example/.gitignore +++ b/packages/ferric-example/.gitignore @@ -5,6 +5,4 @@ Cargo.lock /*.apple.node/ /*.android.node/ -# Generated files -/ferric_example.d.ts -/ferric_example.js +dist diff --git a/packages/ferric-example/package.json b/packages/ferric-example/package.json index 02219ebc..0480d329 100644 --- a/packages/ferric-example/package.json +++ b/packages/ferric-example/package.json @@ -9,8 +9,8 @@ "url": "git+https://github.com/callstackincubator/react-native-node-api.git", "directory": "packages/ferric-example" }, - "main": "ferric_example.js", - "types": "ferric_example.d.ts", + "main": "dist/ferric_example.js", + "types": "dist/ferric_example.d.ts", "scripts": { "build": "ferric build", "bootstrap": "npm run build" diff --git a/packages/ferric/README.md b/packages/ferric/README.md index 0568eb37..8d8b058c 100644 --- a/packages/ferric/README.md +++ b/packages/ferric/README.md @@ -1,3 +1,16 @@ -# `ferric` +# `ferric` (ESM Module) A wrapper around Cargo making it easier to produce prebuilt binaries targeting iOS and Android matching [the prebuilt binary specification](https://github.com/callstackincubator/react-native-node-api/blob/main/docs/PREBUILDS.md) as well as [napi.rs](https://napi.rs/) to generate bindings from annotated Rust code. + +## Install the project + +`npm install --save-dev ferric-cli` + +## Add scripts + +```json +"scripts": { + "build": "ferric build --cwd folder_path", + "build:release": "npm run build -- --configuration release", +}, +``` diff --git a/packages/ferric/package.json b/packages/ferric/package.json index cb1111f2..c1ac3ec8 100644 --- a/packages/ferric/package.json +++ b/packages/ferric/package.json @@ -16,12 +16,12 @@ "start": "tsx src/run.ts" }, "dependencies": { - "@napi-rs/cli": "~3.0.3", - "@commander-js/extra-typings": "^13.1.0", - "bufout": "^0.3.2", + "@commander-js/extra-typings": "14.0.0", + "@napi-rs/cli": "~3.0.4", + "bufout": "0.3.4", "chalk": "^5.4.1", - "commander": "^13.1.0", - "react-native-node-api": "0.3.3", - "ora": "^8.2.0" + "commander": "14.0.0", + "ora": "^8.2.0", + "react-native-node-api": "0.3.3" } } diff --git a/packages/ferric/src/build.ts b/packages/ferric/src/build.ts index aaf97d77..ef6176b5 100644 --- a/packages/ferric/src/build.ts +++ b/packages/ferric/src/build.ts @@ -1,36 +1,35 @@ -import path from "node:path"; import fs from "node:fs"; +import path from "node:path"; import { Command, Option } from "@commander-js/extra-typings"; -import chalk from "chalk"; import { SpawnFailure } from "bufout"; +import chalk from "chalk"; import { oraPromise } from "ora"; import { - determineAndroidLibsFilename, + type AndroidTriplet, createAndroidLibsDirectory, - AndroidTriplet, createAppleFramework, - determineXCFrameworkFilename, - createXCframework, createUniversalAppleLibrary, + createXCframework, + determineAndroidLibsFilename, determineLibraryBasename, + determineXCFrameworkFilename, prettyPath, } from "react-native-node-api"; - -import { UsageError, assertFixable } from "./errors.js"; -import { ensureCargo, build } from "./cargo.js"; +import { getBlockComment } from "./banner.js"; +import { build, ensureCargo } from "./cargo.js"; +import { assertFixable, UsageError } from "./errors.js"; +import { generateTypeScriptDeclarations } from "./napi-rs.js"; import { ALL_TARGETS, ANDROID_TARGETS, - AndroidTargetName, + type AndroidTargetName, APPLE_TARGETS, - AppleTargetName, + type AppleTargetName, ensureInstalledTargets, filterTargetsByPlatform, } from "./targets.js"; -import { generateTypeScriptDeclarations } from "./napi-rs.js"; -import { getBlockComment } from "./banner.js"; type EntrypointOptions = { outputPath: string; @@ -97,6 +96,7 @@ const outputPathOption = new Option( "--output ", "Writing outputs to this directory", ).default(process.cwd()); +const cwdPathOption = new Option("--cwd ", "Specify project path"); const configurationOption = new Option( "--configuration ", "Build configuration", @@ -111,6 +111,7 @@ export const buildCommand = new Command("build") .addOption(androidTarget) .addOption(ndkVersionOption) .addOption(outputPathOption) + .addOption(cwdPathOption) .addOption(configurationOption) .addOption(xcframeworkExtensionOption) .action( @@ -120,9 +121,15 @@ export const buildCommand = new Command("build") android, ndkVersion, output: outputPath, + cwd: cwdPath, configuration, xcframeworkExtension, }) => { + const sourcePath = + cwdPath && cwdPath.length > 0 + ? path.join(outputPath, cwdPath) + : outputPath; + outputPath = path.join(sourcePath, "dist"); try { const targets = new Set([...targetArg]); if (apple) { @@ -175,7 +182,10 @@ export const buildCommand = new Command("build") Promise.all( appleTargets.map( async (target) => - [target, await build({ configuration, target })] as const, + [ + target, + await build({ configuration, target, sourcePath }), + ] as const, ), ), Promise.all( @@ -186,6 +196,7 @@ export const buildCommand = new Command("build") await build({ configuration, target, + sourcePath, ndkVersion, androidApiLevel: ANDROID_API_LEVEL, }), @@ -256,7 +267,7 @@ export const buildCommand = new Command("build") { text: "Assembling XCFramework", successText: `XCFramework assembled into ${chalk.dim( - path.relative(process.cwd(), xcframeworkOutputPath), + path.relative(outputPath, xcframeworkOutputPath), )}`, failText: ({ message }) => `Failed to assemble XCFramework: ${message}`, @@ -274,7 +285,7 @@ export const buildCommand = new Command("build") await oraPromise( generateTypeScriptDeclarations({ outputFilename: declarationsFilename, - createPath: process.cwd(), + createPath: sourcePath, outputPath, }), { diff --git a/packages/ferric/src/cargo.ts b/packages/ferric/src/cargo.ts index da4e8be9..8134efa6 100644 --- a/packages/ferric/src/cargo.ts +++ b/packages/ferric/src/cargo.ts @@ -5,17 +5,15 @@ import path from "node:path"; import { spawn } from "bufout"; import chalk from "chalk"; - +import { weakNodeApiPath } from "react-native-node-api"; import { assertFixable, UsageError } from "./errors.js"; import { - AndroidTargetName, - AppleTargetName, + type AndroidTargetName, + type AppleTargetName, isAndroidTarget, isAppleTarget, } from "./targets.js"; -import { weakNodeApiPath } from "react-native-node-api"; - const APPLE_XCFRAMEWORK_CHILDS_PER_TARGET: Record = { "aarch64-apple-darwin": "macos-arm64_x86_64", // Universal "x86_64-apple-darwin": "macos-arm64_x86_64", // Universal @@ -61,6 +59,7 @@ export function ensureCargo() { type BuildOptions = { configuration: "debug" | "release"; + sourcePath: string; } & ( | { target: AndroidTargetName; @@ -75,8 +74,15 @@ type BuildOptions = { ); export async function build(options: BuildOptions) { - const { target, configuration } = options; - const args = ["build", "--target", target]; + const { target, configuration, sourcePath } = options; + const manifestBuildPath = `${sourcePath}/Cargo.toml`; + const args = [ + "build", + "--target", + target, + "--manifest-path", + manifestBuildPath, + ]; if (configuration.toLowerCase() === "release") { args.push("--release"); } @@ -88,7 +94,7 @@ export async function build(options: BuildOptions) { }, }); const targetOutputPath = joinPathAndAssertExistence( - process.cwd(), + sourcePath, "target", target, configuration,