snyk-mvn-plugin
Version:
Snyk CLI Maven plugin
124 lines • 4.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildDepGraph = buildDepGraph;
exports.buildWithoutVerbose = buildWithoutVerbose;
exports.buildWithVerbose = buildWithVerbose;
const dep_graph_1 = require("@snyk/dep-graph");
const dependency_1 = require("./dependency");
const yocto_queue_1 = require("@common.js/yocto-queue");
function buildDepGraph(mavenGraph, includeTestScope = false, verboseEnabled = false) {
const { rootId, nodes } = mavenGraph;
return verboseEnabled
? buildWithVerbose(rootId, nodes, includeTestScope)
: buildWithoutVerbose(rootId, nodes, includeTestScope);
}
function buildWithoutVerbose(rootId, nodes, includeTestScope = false) {
const parsedRoot = parseId(rootId);
const builder = new dep_graph_1.DepGraphBuilder({ name: 'maven' }, parsedRoot.pkgInfo);
const visitedMap = {};
const queue = new yocto_queue_1.default();
getItems(rootId, nodes[rootId]).forEach((item) => queue.enqueue(item));
// breadth first search
while (queue.size > 0) {
const item = queue.dequeue();
if (!item)
continue;
const { id, parentId } = item;
const parsed = parseId(id);
const node = nodes[id];
if (!includeTestScope && parsed.scope === 'test' && !node.reachesProdDep) {
continue;
}
const visited = visitedMap[parsed.key];
if (visited) {
const prunedId = visited.id + ':pruned';
builder.addPkgNode(visited.pkgInfo, prunedId, {
labels: { pruned: 'true' },
});
builder.connectDep(parentId, prunedId);
continue; // don't queue any more children
}
const parentNodeId = parentId === rootId ? builder.rootNodeId : parentId;
builder.addPkgNode(parsed.pkgInfo, id);
builder.connectDep(parentNodeId, id);
visitedMap[parsed.key] = parsed;
getItems(id, node).forEach((item) => queue.enqueue(item));
}
return builder.build();
}
function buildWithVerbose(rootId, nodes, includeTestScope = false) {
const parsedRoot = parseId(rootId);
const builder = new dep_graph_1.DepGraphBuilder({ name: 'maven' }, parsedRoot.pkgInfo);
const visitedMap = {};
const stack = [];
stack.push(...getVerboseItems(rootId, [], nodes[rootId]));
// depth first search
while (stack.length > 0) {
const item = stack.pop();
if (!item)
continue;
const { id, ancestry, parentId } = item;
const parsed = parseId(id, true);
const node = nodes[id];
if (!includeTestScope && parsed.scope === 'test' && !node.reachesProdDep) {
continue;
}
const visited = visitedMap[parsed.key];
// If verbose is enabled and our ancestry includes ourselves
// we are cyclic and should be pruned :)
if (ancestry.includes(parsed.key)) {
const prunedId = visited.id + ':pruned-cycle';
builder.addPkgNode(visited.pkgInfo, prunedId, {
labels: { pruned: 'cyclic' },
});
builder.connectDep(parentId, prunedId);
continue; // don't queue any more children
}
const parentNodeId = parentId === rootId ? builder.rootNodeId : parentId;
if (visited) {
builder.addPkgNode(visited.pkgInfo, visited.id);
builder.connectDep(parentNodeId, visited.id);
// use visited node when omited dependencies found (verbose)
stack.push(...getVerboseItems(visited.id, [...ancestry, parsed.key], node));
}
else {
builder.addPkgNode(parsed.pkgInfo, id);
builder.connectDep(parentNodeId, id);
visitedMap[parsed.key] = parsed;
// Remember to push updated ancestry here
stack.push(...getVerboseItems(id, [...ancestry, parsed.key], node));
}
}
return builder.build();
}
function getItems(parentId, node) {
const items = [];
for (const id of node?.dependsOn || []) {
items.push({ id, parentId });
}
return items;
}
function getVerboseItems(parentId, ancestry, node) {
const items = [];
for (const id of node?.dependsOn || []) {
items.push({ id, ancestry, parentId });
}
return items;
}
function parseId(id, verboseEnabled = false) {
const dep = (0, dependency_1.parseDependency)(id);
const maybeClassifier = dep.classifier ? `:${dep.classifier}` : '';
const name = `${dep.groupId}:${dep.artifactId}`;
return {
id,
key: verboseEnabled
? `${name}:${dep.type}${maybeClassifier}:${dep.version}:${dep.scope}`
: `${name}:${dep.type}${maybeClassifier}`,
pkgInfo: {
name,
version: dep.version,
},
scope: dep.scope,
};
}
//# sourceMappingURL=dep-graph.js.map