Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/orange-bananas-obey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"react-native-node-api": minor
---

Scope is now stripped from package names when renaming libraries while linking
2 changes: 1 addition & 1 deletion apps/test-app/babel.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = {
presets: ["module:@react-native/babel-preset"],
// plugins: [['module:react-native-node-api/babel-plugin', { stripPathSuffix: true }]],
// plugins: [['module:react-native-node-api/babel-plugin', { packageName: "strip", pathSuffix: "strip" }]],
plugins: ["module:react-native-node-api/babel-plugin"],
};
30 changes: 24 additions & 6 deletions packages/host/src/node/babel-plugin/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,22 @@ import {
isNodeApiModule,
findNodeAddonForBindings,
NamingStrategy,
PathSuffixChoice,
assertPathSuffix,
LibraryNamingChoice,
assertLibraryNamingChoice,
} from "../path-utils";

export type PluginOptions = {
/**
* Controls how the package name is transformed into a library name.
* The transformation is needed to disambiguate and avoid conflicts between addons with the same name (but in different sub-paths or packages).
*
* As an example, if the package name is `@my-org/my-pkg` and the path of the addon within the package is `build/Release/my-addon.node` (and `pathSuffix` is set to `"strip"`):
* - `"omit"`: Only the path within the package is used and the library name will be `my-addon`.
* - `"strip"`: Scope / org gets stripped and the library name will be `my-pkg--my-addon`.
* - `"keep"`: The org and name is kept and the library name will be `my-org--my-pkg--my-addon`.
*/
packageName?: LibraryNamingChoice;

/**
* Controls how the path of the addon inside a package is transformed into a library name.
* The transformation is needed to disambiguate and avoid conflicts between addons with the same name (but in different sub-paths or packages).
Expand All @@ -23,13 +34,16 @@ export type PluginOptions = {
* - `"strip"` (default): Path gets stripped to its basename and the library name will be `my-pkg--my-addon`.
* - `"keep"`: The full path is kept and the library name will be `my-pkg--build-Release-my-addon`.
*/
pathSuffix?: PathSuffixChoice;
pathSuffix?: LibraryNamingChoice;
};

function assertOptions(opts: unknown): asserts opts is PluginOptions {
assert(typeof opts === "object" && opts !== null, "Expected an object");
if ("pathSuffix" in opts) {
assertPathSuffix(opts.pathSuffix);
assertLibraryNamingChoice(opts.pathSuffix);
}
if ("packageName" in opts) {
assertLibraryNamingChoice(opts.packageName);
}
}

Expand Down Expand Up @@ -57,7 +71,7 @@ export function plugin(): PluginObj {
visitor: {
CallExpression(p) {
assertOptions(this.opts);
const { pathSuffix = "strip" } = this.opts;
const { pathSuffix = "strip", packageName = "strip" } = this.opts;
if (typeof this.filename !== "string") {
// This transformation only works when the filename is known
return;
Expand All @@ -80,6 +94,7 @@ export function plugin(): PluginObj {
const resolvedPath = findNodeAddonForBindings(id, from);
if (typeof resolvedPath === "string") {
replaceWithRequireNodeAddon(p.parentPath, resolvedPath, {
packageName,
pathSuffix,
});
}
Expand All @@ -89,7 +104,10 @@ export function plugin(): PluginObj {
isNodeApiModule(path.join(from, id))
) {
const relativePath = path.join(from, id);
replaceWithRequireNodeAddon(p, relativePath, { pathSuffix });
replaceWithRequireNodeAddon(p, relativePath, {
packageName,
pathSuffix,
});
}
}
},
Expand Down
21 changes: 17 additions & 4 deletions packages/host/src/node/cli/options.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
import { Option } from "@react-native-node-api/cli-utils";

import { assertPathSuffix, PATH_SUFFIX_CHOICES } from "../path-utils";
import {
assertLibraryNamingChoice,
LIBRARY_NAMING_CHOICES,
} from "../path-utils";

const { NODE_API_PATH_SUFFIX } = process.env;
const { NODE_API_PACKAGE_NAME, NODE_API_PATH_SUFFIX } = process.env;
if (typeof NODE_API_PACKAGE_NAME === "string") {
assertLibraryNamingChoice(NODE_API_PACKAGE_NAME);
}
if (typeof NODE_API_PATH_SUFFIX === "string") {
assertPathSuffix(NODE_API_PATH_SUFFIX);
assertLibraryNamingChoice(NODE_API_PATH_SUFFIX);
}

export const packageNameOption = new Option(
"--package-name <strategy>",
"Controls how the package name is transformed into a library name",
)
.choices(LIBRARY_NAMING_CHOICES)
.default(NODE_API_PACKAGE_NAME || "strip");

export const pathSuffixOption = new Option(
"--path-suffix <strategy>",
"Controls how the path of the addon inside a package is transformed into a library name",
)
.choices(PATH_SUFFIX_CHOICES)
.choices(LIBRARY_NAMING_CHOICES)
.default(NODE_API_PATH_SUFFIX || "strip");
26 changes: 16 additions & 10 deletions packages/host/src/node/cli/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
} from "../path-utils";

import { command as vendorHermes } from "./hermes";
import { pathSuffixOption } from "./options";
import { packageNameOption, pathSuffixOption } from "./options";
import { linkModules, pruneLinkedModules, ModuleLinker } from "./link-modules";
import { linkXcframework } from "./apple";
import { linkAndroidDir } from "./android";
Expand Down Expand Up @@ -70,10 +70,14 @@ program
)
.option("--android", "Link Android modules")
.option("--apple", "Link Apple modules")
.addOption(packageNameOption)
.addOption(pathSuffixOption)
.action(
wrapAction(
async (pathArg, { force, prune, pathSuffix, android, apple }) => {
async (
pathArg,
{ force, prune, pathSuffix, android, apple, packageName },
) => {
console.log("Auto-linking Node-API modules from", chalk.dim(pathArg));
const platforms: PlatformName[] = [];
if (android) {
Expand Down Expand Up @@ -101,7 +105,7 @@ program
platform,
fromPath: path.resolve(pathArg),
incremental: !force,
naming: { pathSuffix },
naming: { packageName, pathSuffix },
linker: getLinker(platform),
}),
{
Expand Down Expand Up @@ -173,9 +177,10 @@ program
.description("Lists Node-API modules")
.argument("[from-path]", "Some path inside the app package", process.cwd())
.option("--json", "Output as JSON", false)
.addOption(packageNameOption)
.addOption(pathSuffixOption)
.action(
wrapAction(async (fromArg, { json, pathSuffix }) => {
wrapAction(async (fromArg, { json, pathSuffix, packageName }) => {
const rootPath = path.resolve(fromArg);
const dependencies = await findNodeApiModulePathsByDependency({
fromPath: rootPath,
Expand Down Expand Up @@ -210,7 +215,7 @@ program
);
logModulePaths(
dependency.modulePaths.map((p) => path.join(dependency.path, p)),
{ pathSuffix },
{ packageName, pathSuffix },
);
}
}
Expand All @@ -222,21 +227,22 @@ program
.description(
"Utility to print, module path, the hash of a single Android library",
)
.addOption(packageNameOption)
.addOption(pathSuffixOption)
.action(
wrapAction((pathInput, { pathSuffix }) => {
wrapAction((pathInput, { pathSuffix, packageName }) => {
const resolvedModulePath = path.resolve(pathInput);
const normalizedModulePath = normalizeModulePath(resolvedModulePath);
const { packageName, relativePath } =
determineModuleContext(resolvedModulePath);
const context = determineModuleContext(resolvedModulePath);
const libraryName = getLibraryName(resolvedModulePath, {
packageName,
pathSuffix,
});
console.log({
resolvedModulePath,
normalizedModulePath,
packageName,
relativePath,
packageName: context.packageName,
relativePath: context.relativePath,
libraryName,
});
}),
Expand Down
48 changes: 48 additions & 0 deletions packages/host/src/node/path-utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,13 +208,15 @@ describe("getLibraryName", () => {
});
assert.equal(
getLibraryName(path.join(tempDirectoryPath, "addon"), {
packageName: "keep",
pathSuffix: "keep",
}),
"my-package--addon",
);

assert.equal(
getLibraryName(path.join(tempDirectoryPath, "sub-directory/addon"), {
packageName: "keep",
pathSuffix: "keep",
}),
"my-package--sub-directory-addon",
Expand All @@ -230,13 +232,15 @@ describe("getLibraryName", () => {
});
assert.equal(
getLibraryName(path.join(tempDirectoryPath, "addon"), {
packageName: "keep",
pathSuffix: "strip",
}),
"my-package--addon",
);

assert.equal(
getLibraryName(path.join(tempDirectoryPath, "sub-directory", "addon"), {
packageName: "keep",
pathSuffix: "strip",
}),
"my-package--addon",
Expand All @@ -252,18 +256,62 @@ describe("getLibraryName", () => {
});
assert.equal(
getLibraryName(path.join(tempDirectoryPath, "addon"), {
packageName: "keep",
pathSuffix: "omit",
}),
"my-package",
);

assert.equal(
getLibraryName(path.join(tempDirectoryPath, "sub-directory", "addon"), {
packageName: "keep",
pathSuffix: "omit",
}),
"my-package",
);
});

it("keeps and escapes scope from package name", (context) => {
const tempDirectoryPath = setupTempDirectory(context, {
"package.json": `{ "name": "@my-org/my-package" }`,
"addon.apple.node/addon.node": "// This is supposed to be a binary file",
});
assert.equal(
getLibraryName(path.join(tempDirectoryPath, "addon"), {
packageName: "keep",
pathSuffix: "strip",
}),
"my-org__my-package--addon",
);
});

it("strips scope from package name", (context) => {
const tempDirectoryPath = setupTempDirectory(context, {
"package.json": `{ "name": "@my-org/my-package" }`,
"addon.apple.node/addon.node": "// This is supposed to be a binary file",
});
assert.equal(
getLibraryName(path.join(tempDirectoryPath, "addon"), {
packageName: "strip",
pathSuffix: "strip",
}),
"my-package--addon",
);
});

it("omits scope from package name", (context) => {
const tempDirectoryPath = setupTempDirectory(context, {
"package.json": `{ "name": "@my-org/my-package" }`,
"addon.apple.node/addon.node": "// This is supposed to be a binary file",
});
assert.equal(
getLibraryName(path.join(tempDirectoryPath, "addon"), {
packageName: "omit",
pathSuffix: "strip",
}),
"addon",
);
});
});

describe("findPackageDependencyPaths", () => {
Expand Down
Loading
Loading