mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
77 lines
2.4 KiB
JavaScript
77 lines
2.4 KiB
JavaScript
#!/usr/bin/env node
|
|
// Workaround for https://github.com/npm/cli/issues/4460
|
|
//
|
|
// npm silently omits `resolved` and `integrity` fields from some
|
|
// package-lock.json entries in workspace monorepos (especially for
|
|
// workspace-hoisted packages). npm acknowledged this as a bug in 2022
|
|
// but has never shipped a fix.
|
|
//
|
|
// This is harmless for regular `npm ci`, but breaks offline installers
|
|
// like Nix that need every entry to have a resolved URL + integrity hash
|
|
// so they can pre-fetch all tarballs in a sandbox with no network access.
|
|
//
|
|
// This script finds incomplete entries and fills them in using `npm view`.
|
|
// It's idempotent — running it on an already-complete lockfile is a no-op.
|
|
//
|
|
// See also: https://github.com/npm/cli/issues/4263
|
|
// https://github.com/npm/cli/issues/6301
|
|
//
|
|
// Usage:
|
|
// node scripts/fix-lockfile.mjs
|
|
// node scripts/fix-lockfile.mjs path/to/package-lock.json
|
|
|
|
import fs from "fs";
|
|
import { execSync } from "child_process";
|
|
|
|
const lockPath = process.argv[2] || "package-lock.json";
|
|
const lock = JSON.parse(fs.readFileSync(lockPath, "utf8"));
|
|
|
|
// Collect workspace package roots (local packages, not from npm)
|
|
const workspaceRoots = new Set();
|
|
for (const [key, val] of Object.entries(lock.packages || {})) {
|
|
if (val.link) {
|
|
workspaceRoots.add(val.resolved || key);
|
|
}
|
|
}
|
|
|
|
let fixed = 0;
|
|
|
|
for (const [key, val] of Object.entries(lock.packages || {})) {
|
|
if (
|
|
!key || // root package
|
|
key.startsWith("node_modules/") || // top-level (already has resolved)
|
|
val.link || // workspace link entry
|
|
(val.resolved && val.integrity) || // already complete
|
|
!val.version || // no version to look up
|
|
workspaceRoots.has(key) // workspace package root (local, not on npm)
|
|
)
|
|
continue;
|
|
|
|
const pkgName = key.replace(/.*node_modules\//, "");
|
|
const version = val.version;
|
|
|
|
try {
|
|
const info = JSON.parse(
|
|
execSync(`npm view ${pkgName}@${version} --json dist`, {
|
|
encoding: "utf8",
|
|
stdio: ["pipe", "pipe", "pipe"],
|
|
}),
|
|
);
|
|
if (info.tarball && info.integrity) {
|
|
val.resolved = info.tarball;
|
|
val.integrity = info.integrity;
|
|
fixed++;
|
|
}
|
|
} catch {
|
|
console.error(`Warning: could not fetch info for ${pkgName}@${version}`);
|
|
}
|
|
}
|
|
|
|
fs.writeFileSync(lockPath, JSON.stringify(lock, null, 2) + "\n");
|
|
|
|
if (fixed > 0) {
|
|
console.log(`Fixed ${fixed} lockfile entries with missing resolved/integrity`);
|
|
} else {
|
|
console.log("Lockfile is already complete");
|
|
}
|