import { access, readdir, readFile, realpath } from "node:fs/promises"; import path from "node:path"; /** * What the packager knows about a package whose files were bundled: where it is, what it is called, * and whether it is third-party software. A package installed under a `node_modules` directory is * third-party; one that is not (a workspace package, or the module itself) is the platform's or the * module's own code. */ export interface BundledPackage { readonly root: string; readonly name: string; readonly version: string; readonly thirdParty: boolean; readonly manifest: Readonly>; } function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); } async function readManifest(directory: string): Promise | undefined> { try { const parsed = JSON.parse( await readFile(path.join(directory, "package.json"), "utf8"), ) as unknown; return isRecord(parsed) ? parsed : undefined; } catch { return undefined; } } /** Finds the package a bundled file belongs to: the nearest enclosing directory whose package.json * names a package and its version. Nested `package.json` files that only set a module type, as * some libraries ship in subdirectories, are skipped. */ export class BundledPackageIndex { readonly #byDirectory = new Map(); async packageOf(file: string): Promise { let directory = path.dirname(await realpath(file).catch(() => file)); const visited: string[] = []; let found: BundledPackage | undefined; for (;;) { if (this.#byDirectory.has(directory)) { found = this.#byDirectory.get(directory); break; } visited.push(directory); const manifest = await readManifest(directory); if (manifest && typeof manifest.name === "string" && typeof manifest.version === "string") { found = Object.freeze({ manifest: Object.freeze(manifest), name: manifest.name, root: directory, thirdParty: directory.split(path.sep).includes("node_modules"), version: manifest.version, }); break; } const parent = path.dirname(directory); if (parent === directory) { break; } directory = parent; } for (const seen of visited) { this.#byDirectory.set(seen, found); } return found; } } async function exists(file: string): Promise { try { await access(file); return true; } catch { return false; } } function declaresPlatform(manifest: Readonly>): boolean { return ["os", "cpu", "libc"].some((field) => manifest[field] !== undefined); } async function containsCompiledAddon(directory: string): Promise { const entries = await readdir(directory, { withFileTypes: true }).catch(() => []); for (const entry of entries) { if (entry.isDirectory()) { if ( entry.name !== "node_modules" && (await containsCompiledAddon(path.join(directory, entry.name))) ) { return true; } } else if (entry.name.toLowerCase().endsWith(".node")) { return true; } } return false; } /** The installed package a dependency name resolves to from `root`, by Node's own directory walk. */ async function installedDependency( root: string, name: string, ): Promise | undefined> { let directory = root; for (;;) { if (path.basename(directory) !== "node_modules") { const manifest = await readManifest(path.join(directory, "node_modules", ...name.split("/"))); if (manifest) { return manifest; } } const parent = path.dirname(directory); if (parent === directory) { return undefined; } directory = parent; } } /** * Whether a bundled package is native or platform-specific, which an `any` package may never * contain (ADR 0049): it declares an operating system, CPU, or C library; it is built with node-gyp; * it ships a compiled `.node` addon; or one of its installed dependencies declares a platform, as * packages that load a per-platform binary do. */ export async function isNativeOrPlatformSpecific(bundled: BundledPackage): Promise { const manifest = bundled.manifest; if (declaresPlatform(manifest) || manifest.gypfile === true) { return true; } if (await exists(path.join(bundled.root, "binding.gyp"))) { return true; } if (await containsCompiledAddon(bundled.root)) { return true; } for (const field of ["dependencies", "optionalDependencies"]) { const dependencies = manifest[field]; if (!isRecord(dependencies)) { continue; } for (const name of Object.keys(dependencies)) { const dependency = await installedDependency(bundled.root, name); if (dependency && declaresPlatform(dependency)) { return true; } } } return false; }