#!/usr/bin/env bun // Canonicalize Bun-managed install indirection without modifying package contents. import { lstat, readdir, readlink, symlink, unlink, } from "node:fs/promises"; import { dirname, join, relative, resolve } from "node:path"; const nodeModulesRoot = resolve(process.cwd(), process.argv[2] ?? "node_modules"); async function pathExists(path: string): Promise { try { await lstat(path); return true; } catch { return false; } } function lexicalSort(values: Iterable): string[] { return [...values].sort((left, right) => left.localeCompare(right, "en")); } function normalizeRelativeTarget(fromDir: string, targetPath: string): string { const target = relative(fromDir, targetPath) || "."; return target.replaceAll(/\/+/g, "/"); } async function rewriteSymlink(linkPath: string, targetPath: string): Promise { const nextTarget = normalizeRelativeTarget(dirname(linkPath), targetPath); const currentTarget = await readlink(linkPath).catch(() => null); if (currentTarget === nextTarget) { return; } await unlink(linkPath); await symlink(nextTarget, linkPath); } async function canonicalizeManagedSymlink(linkPath: string): Promise { const linkDir = dirname(linkPath); const currentTarget = await readlink(linkPath).catch(() => null); if (currentTarget === null || currentTarget.length === 0) { return; } const resolvedTarget = resolve(linkDir, currentTarget); if (await pathExists(resolvedTarget)) { await rewriteSymlink(linkPath, resolvedTarget); return; } const normalizedBrokenTarget = normalizeRelativeTarget(linkDir, resolvedTarget); if (currentTarget !== normalizedBrokenTarget) { await unlink(linkPath); await symlink(normalizedBrokenTarget, linkPath); } } async function readSortedDir(path: string): Promise { return lexicalSort(await readdir(path)); } function isNodeModulesPackageEntry(path: string): boolean { const parent = dirname(path); const grandparent = dirname(parent); return parent.endsWith("/node_modules") || grandparent.endsWith("/node_modules"); } async function walkNodeModules(path: string): Promise { const entries = await readSortedDir(path); for (const entry of entries) { const entryPath = join(path, entry); const stats = await lstat(entryPath); if (stats.isSymbolicLink()) { const relativePath = relative(nodeModulesRoot, entryPath); const inBunStore = relativePath === ".bun" || relativePath.startsWith(".bun/"); const isWorkspaceLink = isNodeModulesPackageEntry(entryPath); if (inBunStore || isWorkspaceLink) { await canonicalizeManagedSymlink(entryPath); } continue; } if (!stats.isDirectory()) { continue; } if (entry === ".bin") { continue; } await walkNodeModules(entryPath); } } if (await pathExists(nodeModulesRoot)) { await walkNodeModules(nodeModulesRoot); }