diff --git a/.changeset/polite-bikes-stay.md b/.changeset/polite-bikes-stay.md new file mode 100644 index 00000000..1a457c7f --- /dev/null +++ b/.changeset/polite-bikes-stay.md @@ -0,0 +1,5 @@ +--- +"react-native-node-api": patch +--- + +Fixed visualizing duplicate library names diff --git a/packages/host/src/node/cli/link-modules.ts b/packages/host/src/node/cli/link-modules.ts index 8b3bf2e0..a2d274f6 100644 --- a/packages/host/src/node/cli/link-modules.ts +++ b/packages/host/src/node/cli/link-modules.ts @@ -11,9 +11,10 @@ import { findNodeApiModulePathsByDependency, getAutolinkPath, getLibraryName, - logModulePaths, + visualizeLibraryMap, NamingStrategy, PlatformName, + getLibraryMap, } from "../path-utils"; export type ModuleLinker = ( @@ -78,9 +79,14 @@ export async function linkModules({ ), ); - if (hasDuplicateLibraryNames(absoluteModulePaths, naming)) { - logModulePaths(absoluteModulePaths, naming); - throw new Error("Found conflicting library names"); + const libraryMap = getLibraryMap(absoluteModulePaths, naming); + const duplicates = new Map( + Array.from(libraryMap.entries()).filter(([, paths]) => paths.length > 1), + ); + + if (duplicates.size > 0) { + const visualized = visualizeLibraryMap(duplicates); + throw new Error("Found conflicting library names:\n" + visualized); } return Promise.all( @@ -133,17 +139,6 @@ export async function pruneLinkedModules( ); } -export function hasDuplicateLibraryNames( - modulePaths: string[], - naming: NamingStrategy, -): boolean { - const libraryNames = modulePaths.map((modulePath) => { - return getLibraryName(modulePath, naming); - }); - const uniqueNames = new Set(libraryNames); - return uniqueNames.size !== libraryNames.length; -} - export function getLinkedModuleOutputPath( platform: PlatformName, modulePath: string, diff --git a/packages/host/src/node/cli/program.ts b/packages/host/src/node/cli/program.ts index 6fd037b3..169ca85b 100644 --- a/packages/host/src/node/cli/program.ts +++ b/packages/host/src/node/cli/program.ts @@ -16,10 +16,11 @@ import { findNodeApiModulePathsByDependency, getAutolinkPath, getLibraryName, - logModulePaths, + visualizeLibraryMap, normalizeModulePath, PlatformName, PLATFORMS, + getLibraryMap, } from "../path-utils"; import { command as vendorHermes } from "./hermes"; @@ -115,10 +116,10 @@ program successText: `Linked ${platformDisplayName} Node-API modules into ${prettyPath( platformOutputPath, )}`, - failText: (error) => + failText: () => `Failed to link ${platformDisplayName} Node-API modules into ${prettyPath( platformOutputPath, - )}: ${error.message}`, + )}`, }, ); @@ -209,14 +210,15 @@ program dependencies, )) { console.log( - chalk.blueBright(dependencyName), + "\n" + chalk.blueBright(dependencyName), "→", prettyPath(dependency.path), ); - logModulePaths( + const libraryMap = getLibraryMap( dependency.modulePaths.map((p) => path.join(dependency.path, p)), { packageName, pathSuffix }, ); + console.log(visualizeLibraryMap(libraryMap)); } } }), diff --git a/packages/host/src/node/duplicates.ts b/packages/host/src/node/duplicates.ts deleted file mode 100644 index 5e8be7f2..00000000 --- a/packages/host/src/node/duplicates.ts +++ /dev/null @@ -1,12 +0,0 @@ -export function findDuplicates(values: string[]) { - const seen = new Set(); - const duplicates = new Set(); - for (const value of values) { - if (seen.has(value)) { - duplicates.add(value); - } else { - seen.add(value); - } - } - return duplicates; -} diff --git a/packages/host/src/node/path-utils.ts b/packages/host/src/node/path-utils.ts index f898d566..60fd0ffa 100644 --- a/packages/host/src/node/path-utils.ts +++ b/packages/host/src/node/path-utils.ts @@ -7,8 +7,6 @@ import { createRequire } from "node:module"; import { chalk, prettyPath } from "@react-native-node-api/cli-utils"; -import { findDuplicates } from "./duplicates"; - // TODO: Change to .apple.node export const PLATFORMS = ["android", "apple"] as const; export type PlatformName = "android" | "apple"; @@ -267,32 +265,33 @@ export function resolvePackageRoot( } } -export function logModulePaths( - modulePaths: string[], - // TODO: Default to iterating and printing for all supported naming strategies - naming: NamingStrategy, -) { - const pathsPerName = new Map(); +/** + * Module paths per library name. + */ +export type LibraryMap = Map; + +export function getLibraryMap(modulePaths: string[], naming: NamingStrategy) { + const result = new Map(); for (const modulePath of modulePaths) { const libraryName = getLibraryName(modulePath, naming); - const existingPaths = pathsPerName.get(libraryName) ?? []; + const existingPaths = result.get(libraryName) ?? []; existingPaths.push(modulePath); - pathsPerName.set(libraryName, existingPaths); + result.set(libraryName, existingPaths); } + return result; +} - const allModulePaths = modulePaths.map((modulePath) => modulePath); - const duplicatePaths = findDuplicates(allModulePaths); - for (const [libraryName, modulePaths] of pathsPerName) { - console.log( +export function visualizeLibraryMap(libraryMap: LibraryMap) { + const result = []; + for (const [libraryName, modulePaths] of libraryMap) { + result.push( chalk.greenBright(`${libraryName}`), ...modulePaths.flatMap((modulePath) => { - const line = duplicatePaths.has(modulePath) - ? chalk.redBright(prettyPath(modulePath)) - : prettyPath(modulePath); - return `\n ↳ ${line}`; + return ` ↳ ${prettyPath(modulePath)}`; }), ); } + return result.join("\n"); } /**