snyk-nodejs-lockfile-parser
Version:
Generate a dep tree given a lockfile
175 lines • 7.91 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getChildNode = exports.getGraphDependencies = exports.getTopLevelDeps = exports.addPkgNodeToGraph = void 0;
exports.parsePkgJson = parsePkgJson;
const errors_1 = require("../errors");
const errors_2 = require("../errors");
const parsers_1 = require("../parsers");
const pkgJson_1 = require("../aliasesPreprocessors/pkgJson");
const addPkgNodeToGraph = (depGraphBuilder, node, options) => {
return depGraphBuilder.addPkgNode({ name: node.name, version: node.version }, node.id, {
labels: Object.assign(Object.assign(Object.assign(Object.assign({ scope: node.isDev ? 'dev' : 'prod' }, (options.isCyclic && { pruned: 'cyclic' })), (options.isWorkspacePkg && { pruned: 'true' })), (node.missingLockFileEntry && { missingLockFileEntry: 'true' })), (node.alias && {
alias: `${node.alias.aliasName}=>${node.alias.aliasTargetDepName}@${node.version}`,
})),
});
};
exports.addPkgNodeToGraph = addPkgNodeToGraph;
/**
* Get top level dependencies from the given package json object which is parsed from a package.json file.
* This includes both prod dependencies and dev dependencies supposing includeDevDeps is supported.
*/
const getTopLevelDeps = (pkgJson, options) => {
const prodDeps = (0, exports.getGraphDependencies)(pkgJson.dependencies || {}, {
isDev: false,
});
const devDeps = (0, exports.getGraphDependencies)(pkgJson.devDependencies || {}, {
isDev: true,
});
const optionalDeps = options.includeOptionalDeps
? (0, exports.getGraphDependencies)(pkgJson.optionalDependencies || {}, {
isDev: false,
isOptional: true,
})
: {};
const peerDeps = options.includePeerDeps
? (0, exports.getGraphDependencies)(pkgJson.peerDependencies || {}, { isDev: false })
: {};
const deps = Object.assign(Object.assign(Object.assign({}, prodDeps), optionalDeps), peerDeps);
if (pkgJson.aliases) {
for (const alias of Object.keys(pkgJson.aliases)) {
// Only add alias metadata to dependencies that are actually in deps
if (deps[alias]) {
deps[alias] = Object.assign(Object.assign({}, deps[alias]), { alias: Object.assign({}, pkgJson.aliases[alias]) });
}
}
}
if (options.includeDevDeps) {
// Ensure dev dependency 'isDev' flags are correctly set.
// Dev dependencies are applied last to override shared keys with regular dependencies.
return Object.assign(Object.assign({}, deps), devDeps);
}
// For includeDevDeps option set to false, simulate pnpm install --prod
// by excluding all devDependencies,
// ignoring potential duplicates in other dependency lists.
// https://pnpm.io/cli/install#--prod--p
return Object.keys(deps)
.filter((packageName) => !devDeps.hasOwnProperty(packageName))
.reduce((result, packageName) => {
result[packageName] = deps[packageName];
return result;
}, {});
};
exports.getTopLevelDeps = getTopLevelDeps;
/**
* Converts dependencies parsed from the a lock file to a dependencies object required by the graph.
* For example, { 'mime-db': '~1.12.0' } will be converted to { 'mime-db': { version: '~1.12.0', isDev: true/false } }.
*/
const getGraphDependencies = (dependencies, options) => {
return Object.entries(dependencies).reduce((pnpmDeps, [name, semver]) => {
pnpmDeps[name] = {
version: semver,
isDev: options.isDev,
isOptional: options.isOptional || false,
};
return pnpmDeps;
}, {});
};
exports.getGraphDependencies = getGraphDependencies;
function parsePkgJson(pkgJsonContent) {
try {
const parsedPkgJson = JSON.parse(pkgJsonContent);
if (!parsedPkgJson.name) {
parsedPkgJson.name = 'package.json';
}
return parsedPkgJson;
}
catch (e) {
throw new errors_1.InvalidUserInputError('package.json parsing failed with error ' + e.message);
}
}
const getChildNode = (name, depInfo, pkgs, strictOutOfSync, includeOptionalDeps) => {
var _a, _b, _c;
const childNodeKey = `${name}@${depInfo.version}`;
let childNode;
// Check if this lockfile entry is for an aliased package
// by looking for a corresponding npm: entry in the lockfile
let aliasInfo = depInfo.alias;
if (!aliasInfo && pkgs[childNodeKey]) {
// Look for any key in pkgs that matches the pattern: name@npm:*
// and has the same version as our current entry
for (const key in pkgs) {
if (key.startsWith(`${name}@npm:`)) {
const pkgEntry = pkgs[key];
if (pkgEntry.version === pkgs[childNodeKey].version) {
// Extract the npm: portion and parse it using the shared helper
const npmPortion = key.substring(name.length + 1); // Remove "name@" prefix
const parsed = (0, pkgJson_1.parseNpmAlias)(npmPortion);
if (parsed) {
const targetPkgName = parsed.packageName;
// Only add alias info if the alias name is different from the target name
if (targetPkgName !== name) {
aliasInfo = {
aliasName: name,
aliasTargetDepName: targetPkgName,
semver: parsed.version,
version: parsed.version,
};
}
break;
}
}
}
}
}
if (!pkgs[childNodeKey]) {
// Handle optional dependencies that don't have separate package entries
if (depInfo.isOptional) {
childNode = {
id: childNodeKey,
name: (_a = aliasInfo === null || aliasInfo === void 0 ? void 0 : aliasInfo.aliasTargetDepName) !== null && _a !== void 0 ? _a : name,
version: depInfo.version,
dependencies: {},
isDev: depInfo.isDev,
missingLockFileEntry: true,
alias: aliasInfo,
};
}
else if (strictOutOfSync && !/^file:/.test(depInfo.version)) {
throw new errors_2.OutOfSyncError(childNodeKey, parsers_1.LockfileType.yarn);
}
else {
childNode = {
id: childNodeKey,
name: (_b = aliasInfo === null || aliasInfo === void 0 ? void 0 : aliasInfo.aliasTargetDepName) !== null && _b !== void 0 ? _b : name,
version: depInfo.version,
dependencies: {},
isDev: depInfo.isDev,
missingLockFileEntry: true,
alias: aliasInfo,
};
}
}
else {
const depData = pkgs[childNodeKey];
const dependencies = (0, exports.getGraphDependencies)(depData.dependencies || {}, {
isDev: depInfo.isDev,
});
const optionalDependencies = includeOptionalDeps
? (0, exports.getGraphDependencies)(depData.optionalDependencies || {}, {
isDev: depInfo.isDev,
isOptional: true,
})
: {};
childNode = {
id: `${name}@${depData.version}`,
name: (_c = aliasInfo === null || aliasInfo === void 0 ? void 0 : aliasInfo.aliasTargetDepName) !== null && _c !== void 0 ? _c : name,
version: depData.version,
dependencies: Object.assign(Object.assign({}, dependencies), optionalDependencies),
isDev: depInfo.isDev,
alias: aliasInfo,
};
}
return childNode;
};
exports.getChildNode = getChildNode;
//# sourceMappingURL=util.js.map