Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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