mirror of
https://github.com/morluto/rea.git
synced 2026-10-12 02:19:24 +00:00
62 lines
2.2 KiB
JavaScript
62 lines
2.2 KiB
JavaScript
import { readFile } from "node:fs/promises";
|
|
import { resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const REMEDIATION = "Run `npm ci`, then retry.";
|
|
|
|
const readJson = async (path) => JSON.parse(await readFile(path, "utf8"));
|
|
|
|
const directDependencies = (rootPackage) => ({
|
|
...rootPackage.dependencies,
|
|
...rootPackage.devDependencies,
|
|
});
|
|
|
|
const installedPackageKey = (name) => `node_modules/${name}`;
|
|
|
|
/** Compare root direct dependencies with npm's hidden installed lockfile. */
|
|
export const dependencyInstallProblems = (rootLock, installedLock) => {
|
|
const rootPackage = rootLock.packages?.[""];
|
|
if (rootPackage === undefined)
|
|
return ["package-lock.json does not contain a root package entry"];
|
|
const installedPackages = installedLock.packages ?? {};
|
|
return Object.keys(directDependencies(rootPackage))
|
|
.sort()
|
|
.flatMap((name) => {
|
|
const key = installedPackageKey(name);
|
|
const expected = rootLock.packages?.[key]?.version;
|
|
const actual = installedPackages[key]?.version;
|
|
if (expected === undefined)
|
|
return [`${name}: missing resolved version in package-lock.json`];
|
|
if (actual === undefined)
|
|
return [`${name}: missing from the installed dependency lockfile`];
|
|
return actual === expected
|
|
? []
|
|
: [`${name}: installed ${actual}, expected ${expected}`];
|
|
});
|
|
};
|
|
|
|
const main = async () => {
|
|
const root = process.cwd();
|
|
try {
|
|
const [rootLock, installedLock] = await Promise.all([
|
|
readJson(resolve(root, "package-lock.json")),
|
|
readJson(resolve(root, "node_modules/.package-lock.json")),
|
|
]);
|
|
const problems = dependencyInstallProblems(rootLock, installedLock);
|
|
if (problems.length === 0) return;
|
|
process.stderr.write(
|
|
`Direct dependency installation is stale:\n${problems.map((problem) => `- ${problem}`).join("\n")}\n${REMEDIATION}\n`,
|
|
);
|
|
process.exitCode = 1;
|
|
} catch (error) {
|
|
const reason =
|
|
error instanceof Error ? error.message : "unreadable lockfile";
|
|
process.stderr.write(
|
|
`Could not verify the installed direct dependencies: ${reason}\n${REMEDIATION}\n`,
|
|
);
|
|
process.exitCode = 1;
|
|
}
|
|
};
|
|
|
|
if (process.argv[1] === fileURLToPath(import.meta.url)) await main();
|