import { lstat, mkdir, readdir, symlink } from "node:fs/promises"; import path from "node:path"; /** * Links the repository's installed dependencies into a throwaway fixture root. * * The obvious form — one directory symlink at `/node_modules` — is * destructive. A fixture runs `pnpm` inside itself, pnpm does not recognise the * modules directory it finds there, and its purge follows the symlink and * deletes the *repository's* real dependencies mid-run. With `CI=true` that * happens without a prompt, so a test suite silently uninstalls the workspace * it is running in. * * `node_modules` is therefore a real directory here, and every entry inside it * is an individual symlink. Package resolution is unchanged, but a recursive * delete unlinks the fixture's own symlinks instead of walking through one link * into the shared tree. */ export async function linkFixtureNodeModules( fixtureRoot: string, sourceRoot: string = process.cwd(), ): Promise { const source = path.join(sourceRoot, "node_modules"); const target = path.join(fixtureRoot, "node_modules"); await mkdir(target, { recursive: true }); for (const entry of await readdir(source)) { const from = path.join(source, entry); const stats = await lstat(from); await symlink(from, path.join(target, entry), stats.isDirectory() ? "dir" : "file"); } }