diff options
| author | Albert O'Shea <[email protected]> | 2025-11-18 17:46:49 +1100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-18 00:46:49 -0600 |
| commit | 5e13527416e183c7ea6d1baa3528b5c30108372e (patch) | |
| tree | 6d839be0118b84974eacc670a93823974787faba /nix/scripts/canonicalize-node-modules.ts | |
| parent | aba94c658f5c0987443196a5e850fdf7293d5006 (diff) | |
| download | opencode-5e13527416e183c7ea6d1baa3528b5c30108372e.tar.gz opencode-5e13527416e183c7ea6d1baa3528b5c30108372e.zip | |
feat: nix support for the nix folks (#3924)
Co-authored-by: opencode <[email protected]>
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Diffstat (limited to 'nix/scripts/canonicalize-node-modules.ts')
| -rw-r--r-- | nix/scripts/canonicalize-node-modules.ts | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/nix/scripts/canonicalize-node-modules.ts b/nix/scripts/canonicalize-node-modules.ts new file mode 100644 index 000000000..791d96dfe --- /dev/null +++ b/nix/scripts/canonicalize-node-modules.ts @@ -0,0 +1,94 @@ +import { lstat, mkdir, readdir, rm, symlink } from "fs/promises" +import { join, relative } from "path" + +type SemverLike = { + valid: (value: string) => string | null + rcompare: (left: string, right: string) => number +} + +type Entry = { + dir: string + version: string + label: string +} + +const root = process.cwd() +const bunRoot = join(root, "node_modules/.bun") +const linkRoot = join(bunRoot, "node_modules") +const directories = (await readdir(bunRoot)).sort() +const versions = new Map<string, Entry[]>() + +for (const entry of directories) { + const full = join(bunRoot, entry) + const info = await lstat(full) + if (!info.isDirectory()) { + continue + } + const marker = entry.lastIndexOf("@") + if (marker <= 0) { + continue + } + const slug = entry.slice(0, marker).replace(/\+/g, "/") + const version = entry.slice(marker + 1) + const list = versions.get(slug) ?? [] + list.push({ dir: full, version, label: entry }) + versions.set(slug, list) +} + +const semverModule = (await import(join(bunRoot, "node_modules/semver"))) as SemverLike | { + default: SemverLike +} +const semver = "default" in semverModule ? semverModule.default : semverModule +const selections = new Map<string, Entry>() + +for (const [slug, list] of versions) { + list.sort((a, b) => { + const left = semver.valid(a.version) + const right = semver.valid(b.version) + if (left && right) { + const delta = semver.rcompare(left, right) + if (delta !== 0) { + return delta + } + } + if (left && !right) { + return -1 + } + if (!left && right) { + return 1 + } + return b.version.localeCompare(a.version) + }) + selections.set(slug, list[0]) +} + +await rm(linkRoot, { recursive: true, force: true }) +await mkdir(linkRoot, { recursive: true }) + +const rewrites: string[] = [] + +for (const [slug, entry] of Array.from(selections.entries()).sort((a, b) => a[0].localeCompare(b[0]))) { + const parts = slug.split("/") + const leaf = parts.pop() + if (!leaf) { + continue + } + const parent = join(linkRoot, ...parts) + await mkdir(parent, { recursive: true }) + const linkPath = join(parent, leaf) + const desired = join(entry.dir, "node_modules", slug) + const relativeTarget = relative(parent, desired) + const resolved = relativeTarget.length === 0 ? "." : relativeTarget + await rm(linkPath, { recursive: true, force: true }) + await symlink(resolved, linkPath) + rewrites.push(slug + " -> " + resolved) +} + +rewrites.sort() +console.log("[canonicalize-node-modules] rebuilt", rewrites.length, "links") +for (const line of rewrites.slice(0, 20)) { + console.log(" ", line) +} +if (rewrites.length > 20) { + console.log(" ...") +}
\ No newline at end of file |
