@nodesecure/scanner
Version:
A package API to run a static analysis of your module's dependencies.
148 lines • 6.93 kB
JavaScript
import * as Vulnera from "@nodesecure/vulnera";
export function comparePayloads(payload, comparedPayload) {
if (payload.id === comparedPayload.id) {
throw new Error(`You try to compare two payloads with the same id '${payload.id}'`);
}
if (payload.rootDependencyName !== comparedPayload.rootDependencyName) {
throw new Error(`You can't compare different package payloads '${payload.rootDependencyName}' and '${comparedPayload.rootDependencyName}'`);
}
const givenVersion = Object.keys(payload.dependencies[payload.rootDependencyName].versions)[0];
const comparedVersion = Object.keys(comparedPayload.dependencies[comparedPayload.rootDependencyName].versions)[0];
return {
title: `'${payload.rootDependencyName}@${givenVersion}' -> '${comparedPayload.rootDependencyName}@${comparedVersion}'`,
warnings: arrayDiff(payload.warnings, comparedPayload.warnings),
scannerVersion: compareValues(payload.scannerVersion, comparedPayload.scannerVersion),
vulnerabilityStrategy: compareValues(payload.vulnerabilityStrategy, comparedPayload.vulnerabilityStrategy),
dependencies: compareDependencies(payload.dependencies, comparedPayload.dependencies)
};
}
function compareDependencies(original, toCompare) {
const { comparable, ...dependencies } = dictionariesDiff(original, toCompare);
const comparedDependencies = new Map();
for (const [name, [dep, comparedDep]] of comparable) {
const diff = {
publishers: arrayOfObjectsDiffByKey("name", dep.metadata.publishers, comparedDep.metadata.publishers),
maintainers: arrayOfObjectsDiffByKey("name", dep.metadata.maintainers, comparedDep.metadata.maintainers),
versions: compareVersions(dep.versions, comparedDep.versions),
vulnerabilities: arrayOfObjectsDiffByKey("id", dep.vulnerabilities, comparedDep.vulnerabilities)
};
comparedDependencies.set(name, diff);
}
return { compared: comparedDependencies, ...dependencies };
}
function compareVersions(original, toCompare) {
const { comparable, ...versions } = dictionariesDiff(original, toCompare);
const comparedVersions = new Map();
for (const [name, [version, comparedVersion]] of comparable) {
const diff = {
id: compareValues(version.id, comparedVersion.id),
size: compareValues(version.size, comparedVersion.size),
usedBy: compareDictionnaries(version.usedBy, comparedVersion.usedBy),
isDevDependency: compareValues(version.isDevDependency, comparedVersion.isDevDependency),
existOnRemoteRegistry: compareValues(version.existOnRemoteRegistry, comparedVersion.existOnRemoteRegistry),
description: compareValues(version.description, comparedVersion.description),
author: version.author && comparedVersion.author ? compareObjects("name", version.author, comparedVersion.author) : void 0,
// @ts-ignore
engines: compareDictionnaries(version.engines, comparedVersion.engines),
// FIXME: repository can be a string: https://github.com/pillarjs/encodeurl/blob/master/package.json#L14
repository: compareObjects("type", version.repository, comparedVersion.repository)
?? compareObjects("url", version.repository, comparedVersion.repository),
scripts: compareDictionnaries(version.scripts, comparedVersion.scripts),
warnings: arrayDiff(version.warnings, comparedVersion.warnings),
composition: compareComposition(version.composition, comparedVersion.composition),
uniqueLicenseIds: arrayDiff(version.uniqueLicenseIds, comparedVersion.uniqueLicenseIds),
flags: arrayDiff(version.flags, comparedVersion.flags),
links: compareValues(version.links, comparedVersion.links)
};
comparedVersions.set(name, diff);
}
return {
compared: comparedVersions,
...versions
};
}
function compareComposition(original, toCompare) {
return {
minified: arrayDiff(original.minified, toCompare.minified),
required_thirdparty: arrayDiff(original.required_thirdparty, toCompare.required_thirdparty),
required_nodejs: arrayDiff(original.required_nodejs, toCompare.required_nodejs),
unused: arrayDiff(original.unused, toCompare.unused),
missing: arrayDiff(original.missing, toCompare.missing)
};
}
function compareDictionnaries(original, toCompare) {
const { comparable, ...diff } = dictionariesDiff(original, toCompare);
const compared = new Map();
for (const [name, [entity, comparedEntity]] of comparable) {
compared.set(name, compareValues(entity, comparedEntity));
}
return {
compared,
...diff
};
}
function compareObjects(key, original = Object.create(null), toCompare = Object.create(null)) {
if (original[key] === toCompare[key]) {
return undefined;
}
return {
prev: original,
now: toCompare
};
}
function compareValues(original, toCompare) {
if (typeof original === "object") {
if (JSON.stringify(original) === JSON.stringify(toCompare)) {
return undefined;
}
}
else if (original === toCompare) {
return undefined;
}
return {
prev: original,
now: toCompare
};
}
function dictionariesDiff(original = {}, toCompare = {}) {
const added = new Map();
const removed = new Map();
const comparable = new Map();
Object.keys(original).forEach((key) => {
if (key in toCompare) {
comparable.set(key, [original[key], toCompare[key]]);
}
else {
removed.set(key, original[key]);
}
});
Object.keys(toCompare).forEach((key) => {
if (!(key in original)) {
added.set(key, toCompare[key]);
}
});
return { added, removed, comparable };
}
function arrayDiff(original = [], toCompare = []) {
const added = toCompare.filter((v, i) => {
if (typeof v !== "object") {
return v !== original[i];
}
return JSON.stringify(v) !== JSON.stringify(original[i]);
});
const removed = original.filter((v, i) => {
if (typeof v !== "object") {
return v !== toCompare[i];
}
return JSON.stringify(v) !== JSON.stringify(toCompare[i]);
});
return { added, removed };
}
export function arrayOfObjectsDiffByKey(key, original = [], toCompare = []) {
const toCompareMap = new Map(toCompare.map((item) => [item[key], item]));
const originalMap = new Map(original.map((item) => [item[key], item]));
const added = toCompare.filter((item) => !originalMap.has(item[key]));
const removed = original.filter((item) => !toCompareMap.has(item[key]));
return { added, removed };
}
//# sourceMappingURL=comparePayloads.js.map