linkPackages
uses node:fs
Let code taken from git (into root, a copy of the mirror dir) resolve its packages as it did: a workspace
package (a directory with a package.json naming it) to its copy here, anything else to what's installed now.
Each package gets a node_modules like its counterpart's in dir (pnpm installs dependencies per package), with
the workspace's own packages pointing at the copies.
import fs from "node:fs"; import path from "node:path"; export function linkPackages(root: string, dir: string, top: string) { // a directory and its own, by the name of the package each is (`@tcm/core`) const named = (d: string) => { const out = new Map<string, string>(); for (const p of [d, ...fs.readdirSync(d, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path.join(d, e.name))]) { const pkgJson = path.join(p, "package.json"); const name = fs.existsSync(pkgJson) ? (JSON.parse(fs.readFileSync(pkgJson, "utf8")) as { name?: string }).name : undefined; if (name) out.set(name, p); } return out; }; const workspace = named(root); // where each is now, which may not be where it was const now = named(dir); const packages = [...workspace.values()].filter((p) => p !== root); const link = (target: string, at: string) => { fs.mkdirSync(path.dirname(at), { recursive: true }); if (!fs.existsSync(at)) fs.symlinkSync(target, at, "dir"); }; for (const [name, p] of workspace) link(p, path.join(top, "node_modules", name)); const nameOf = new Map([...workspace].map(([n, p]) => [p, n])); for (const p of [root, ...packages]) { const installed = path.join(now.get(nameOf.get(p) ?? "") ?? path.join(dir, path.relative(root, p)), "node_modules"); if (!fs.existsSync(installed)) continue; for (const e of fs.readdirSync(installed)) { if (e.startsWith(".")) continue; const names = e.startsWith("@") ? fs.readdirSync(path.join(installed, e)).map((n) => `${e}/${n}`) : [e]; for (const name of names) { const target = workspace.get(name) ?? fs.realpathSync(path.join(installed, name)); link(target, path.join(p, "node_modules", name)); } } } }