linkPackages

tcmts.cli.mirror.linkPackages · #vyb3iw2w · term · runs on the server

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));
      }
    }
  }
}

used by