UNPKG

snyk-go-parser

Version:

Generate a dep tree given a collection of manifests

98 lines 3.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseGoModGraph = parseGoModGraph; const semver = require("@snyk/go-semver"); const dep_graph_1 = require("@snyk/dep-graph"); const types_1 = require("../types"); // Modules can be of shape `modules/snyk/inner/v2` or `modules/snyk/v2/inner` const GO_SEMVER_PREFIXED_MODULES_REGEX = /(.*)\/v[0-9]+(.*)/; const GO_MODULES = 'gomodules'; function parseGoModGraph(goModGraphOutput, projectName, projectVersion = types_1.DEFAULT_INITIAL_VERSION, opts = { pruneRepeatedSubDependencies: true }) { var _a; const lines = extractLines(goModGraphOutput); const maxVersions = getMaxVersions(lines); const depMap = getChildrenByParent(lines); const rootPkgInfo = { name: projectName || ((_a = lines[0]) === null || _a === void 0 ? void 0 : _a.parent.name) || 'empty', version: projectVersion, }; const dgBuilder = new dep_graph_1.DepGraphBuilder({ name: GO_MODULES }, rootPkgInfo); dfsVisit(dgBuilder, depMap, maxVersions, opts.pruneRepeatedSubDependencies, rootPkgInfo); return dgBuilder.build(); } function dfsVisit(dgBuilder, depMap, maxVersions, prune, pkg, visited) { const isRoot = visited === undefined; const nodeId = `${pkg.name}@${pkg.version}`; const parentId = isRoot ? 'root-node' : nodeId; if (isRoot && !prune) { visited = new Set(); } const deps = depMap[nodeId] || []; for (const { name, version } of deps) { const localVisited = visited || new Set(); const effectiveDep = { name, version: maxVersions.get(name) || version }; const depId = `${effectiveDep.name}@${effectiveDep.version}`; if (localVisited.has(depId)) { if (prune) { const prunedId = `${depId}:pruned`; dgBuilder.addPkgNode(effectiveDep, prunedId, { labels: { pruned: 'true' }, }); dgBuilder.connectDep(parentId, prunedId); } else { dgBuilder.connectDep(parentId, depId); } continue; } dgBuilder.addPkgNode(effectiveDep, depId); dgBuilder.connectDep(parentId, depId); localVisited.add(depId); dfsVisit(dgBuilder, depMap, maxVersions, prune, effectiveDep, localVisited); } } function extractLines(goModGraphOutput) { return goModGraphOutput .trim() .split('\n') .filter(Boolean) .map((line) => { const [parent, child] = line .trim() .split(/\s/) .map((item) => item.split('@')) .map(([name, version]) => ({ // Handle cases for prefixed-semver // see https://golang.org/ref/mod#major-version-suffixes name: name.replace(GO_SEMVER_PREFIXED_MODULES_REGEX, '$1$2'), version: version, })); return { parent, child }; }); } function getMaxVersions(lines) { const maxVersions = new Map(); for (const line of lines) { const { child } = line; if (!maxVersions.has(child.name) || semver.gt(child.version, maxVersions.get(child.name))) { maxVersions.set(child.name, child.version); } } return maxVersions; } function getChildrenByParent(lines) { const childrenByParent = {}; for (const line of lines) { const { parent, child } = line; const parentId = `${parent.name}@${parent.version || types_1.DEFAULT_INITIAL_VERSION}`; if (parentId in childrenByParent) { childrenByParent[parentId].push(child); } else { childrenByParent[parentId] = [child]; } } return childrenByParent; } //# sourceMappingURL=gomod-graph-parser.js.map