rugby
Version:
A Node.js CLI to collect npm package tarballs and assets (including those fetched by pre/postinstall scripts) for offline Artifactory use.
72 lines (62 loc) • 2.37 kB
JavaScript
;
const semver = require("semver");
// Build an ordered list of packages from package-lock.json. The lock already contains full dependency graph.
// We keep a Map key -> info, where key is name@version to preserve multiple versions of the same package.
// info = { name, version, resolved, integrity }
// And a topological-ish order map for deterministic processing.
async function discoverDependencyGraph({ projectDir, pkgJson, lockJson, verbose }) {
const packages = new Map();
// npm v7+ lockfile v2 has a top-level "packages" map and "dependencies" tree
if (lockJson && lockJson.packages) {
for (const [nodePath, info] of Object.entries(lockJson.packages)) {
if (!info || !info.version) continue;
// nodePath "" is the root project
if (nodePath === "") continue;
const name = info.name || inferNameFromPath(nodePath);
const version = info.version;
const key = `${name}@${version}`;
packages.set(key, {
name,
version,
resolved: info.resolved,
integrity: info.integrity,
});
}
} else if (lockJson && lockJson.dependencies) {
// Legacy lockfile v1
function walk(deps) {
for (const [name, info] of Object.entries(deps)) {
if (info && info.version) {
const version = info.version;
const key = `${name}@${version}`;
packages.set(key, {
name,
version,
resolved: info.resolved,
integrity: info.integrity,
});
}
if (info && info.dependencies) walk(info.dependencies);
}
}
walk(lockJson.dependencies);
}
// Maintain deterministic order by sorting by name@version
const order = new Map();
Array.from(packages.entries())
.sort((a, b) => {
const [ak, ai] = a;
const [bk, bi] = b;
if (ai.name === bi.name) return semver.compare(ai.version, bi.version);
return ai.name.localeCompare(bi.name);
})
.forEach(([key, info]) => order.set(key, info));
return { packages, order };
}
function inferNameFromPath(nodePath) {
// lock.packages paths look like node_modules/foo or node_modules/@scope/foo
const parts = nodePath.split("node_modules/").filter(Boolean);
const last = parts[parts.length - 1];
return last || nodePath || "";
}
module.exports = { discoverDependencyGraph };