cli: flip around lockfile diff

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2022-12-13 22:10:51 +01:00
parent d2ad8ca3af
commit 60196dc40f
2 changed files with 71 additions and 56 deletions
@@ -416,30 +416,30 @@ d@^1:
it('should diff two legacy lockfiles', async () => {
expect(lockfileLegacyA.diff(lockfileLegacyB)).toEqual({
added: [
{ name: 'b', range: '4' },
{ name: 'd', range: '^1' },
{ name: 'b', range: '3' },
{ name: 'c', range: '^1' },
],
changed: [
{ name: 'a', range: '^1' },
{ name: 'b', range: '2.0.x' },
],
removed: [
{ name: 'b', range: '3' },
{ name: 'c', range: '^1' },
{ name: 'b', range: '4' },
{ name: 'd', range: '^1' },
],
});
expect(lockfileLegacyB.diff(lockfileLegacyA)).toEqual({
added: [
{ name: 'b', range: '3' },
{ name: 'c', range: '^1' },
{ name: 'b', range: '4' },
{ name: 'd', range: '^1' },
],
changed: [
{ name: 'a', range: '^1' },
{ name: 'b', range: '2.0.x' },
],
removed: [
{ name: 'b', range: '4' },
{ name: 'd', range: '^1' },
{ name: 'b', range: '3' },
{ name: 'c', range: '^1' },
],
});
});
@@ -447,30 +447,30 @@ d@^1:
it('should diff two modern lockfiles', async () => {
expect(lockfileModernA.diff(lockfileModernB)).toEqual({
added: [
{ name: 'b', range: '4' },
{ name: 'd', range: '^1' },
{ name: 'b', range: '3' },
{ name: 'c', range: '^1' },
],
changed: [
{ name: 'a', range: '^1' },
{ name: 'b', range: '2.0.x' },
],
removed: [
{ name: 'b', range: '3' },
{ name: 'c', range: '^1' },
{ name: 'b', range: '4' },
{ name: 'd', range: '^1' },
],
});
expect(lockfileModernB.diff(lockfileModernA)).toEqual({
added: [
{ name: 'b', range: '3' },
{ name: 'c', range: '^1' },
{ name: 'b', range: '4' },
{ name: 'd', range: '^1' },
],
changed: [
{ name: 'a', range: '^1' },
{ name: 'b', range: '2.0.x' },
],
removed: [
{ name: 'b', range: '4' },
{ name: 'd', range: '^1' },
{ name: 'b', range: '3' },
{ name: 'c', range: '^1' },
],
});
});
@@ -478,30 +478,30 @@ d@^1:
it('should diff legacy and modern lockfiles', async () => {
expect(lockfileLegacyA.diff(lockfileModernB)).toEqual({
added: [
{ name: 'b', range: '4' },
{ name: 'd', range: '^1' },
{ name: 'b', range: '3' },
{ name: 'c', range: '^1' },
],
changed: [
{ name: 'a', range: '^1' },
{ name: 'b', range: '2.0.x' },
],
removed: [
{ name: 'b', range: '3' },
{ name: 'c', range: '^1' },
{ name: 'b', range: '4' },
{ name: 'd', range: '^1' },
],
});
expect(lockfileLegacyB.diff(lockfileModernA)).toEqual({
added: [
{ name: 'b', range: '3' },
{ name: 'c', range: '^1' },
{ name: 'b', range: '4' },
{ name: 'd', range: '^1' },
],
changed: [
{ name: 'a', range: '^1' },
{ name: 'b', range: '2.0.x' },
],
removed: [
{ name: 'b', range: '4' },
{ name: 'd', range: '^1' },
{ name: 'b', range: '3' },
{ name: 'c', range: '^1' },
],
});
});
@@ -509,30 +509,30 @@ d@^1:
it('should diff modern and legacy lockfiles', async () => {
expect(lockfileModernA.diff(lockfileLegacyB)).toEqual({
added: [
{ name: 'b', range: '4' },
{ name: 'd', range: '^1' },
{ name: 'b', range: '3' },
{ name: 'c', range: '^1' },
],
changed: [
{ name: 'a', range: '^1' },
{ name: 'b', range: '2.0.x' },
],
removed: [
{ name: 'b', range: '3' },
{ name: 'c', range: '^1' },
{ name: 'b', range: '4' },
{ name: 'd', range: '^1' },
],
});
expect(lockfileModernB.diff(lockfileLegacyA)).toEqual({
added: [
{ name: 'b', range: '3' },
{ name: 'c', range: '^1' },
{ name: 'b', range: '4' },
{ name: 'd', range: '^1' },
],
changed: [
{ name: 'a', range: '^1' },
{ name: 'b', range: '2.0.x' },
],
removed: [
{ name: 'b', range: '4' },
{ name: 'd', range: '^1' },
{ name: 'b', range: '3' },
{ name: 'c', range: '^1' },
],
});
});
+39 -24
View File
@@ -38,6 +38,17 @@ type LockfileQueryEntry = {
dataKey: string;
};
type LockfileDiffEntry = {
name: string;
range: string;
};
type LockfileDiff = {
added: LockfileDiffEntry[];
changed: LockfileDiffEntry[];
removed: LockfileDiffEntry[];
};
/** Entries that have an invalid version range, for example an npm tag */
type AnalyzeResultInvalidRange = {
name: string;
@@ -328,56 +339,60 @@ export class Lockfile {
}
}
diff(newLockfile: Lockfile) {
/**
* Diff with another lockfile, returning entries that have been
* added, changed, and removed compared to the other lockfile.
*/
diff(otherLockfile: Lockfile): LockfileDiff {
const diff = {
added: new Array<{ name: string; range: string }>(),
removed: new Array<{ name: string; range: string }>(),
changed: new Array<{ name: string; range: string }>(),
removed: new Array<{ name: string; range: string }>(),
};
// Keeps track of packages that only exist in the old lockfile
// Keeps track of packages that only exist in this lockfile
const remainingOldNames = new Set(this.packages.keys());
for (const [name, newQueries] of newLockfile.packages) {
for (const [name, otherQueries] of otherLockfile.packages) {
remainingOldNames.delete(name);
const oldQueries = this.packages.get(name);
// If the packages doesn't exist in the old lockfile, add all entries
if (!oldQueries) {
diff.added.push(...newQueries.map(q => ({ name, range: q.range })));
const thisQueries = this.packages.get(name);
// If the packages doesn't exist in this lockfile, add all entries
if (!thisQueries) {
diff.removed.push(...otherQueries.map(q => ({ name, range: q.range })));
continue;
}
const remainingOldRanges = new Set(oldQueries.map(q => q.range));
const remainingOldRanges = new Set(thisQueries.map(q => q.range));
for (const newQuery of newQueries) {
remainingOldRanges.delete(newQuery.range);
for (const otherQuery of otherQueries) {
remainingOldRanges.delete(otherQuery.range);
const oldQuery = oldQueries.find(q => q.range === newQuery.range);
if (!oldQuery) {
diff.added.push({ name, range: newQuery.range });
const thisQuery = thisQueries.find(q => q.range === otherQuery.range);
if (!thisQuery) {
diff.removed.push({ name, range: otherQuery.range });
continue;
}
const newPkg = newLockfile.data[newQuery.dataKey];
const oldPkg = this.data[oldQuery.dataKey];
if (newPkg && oldPkg) {
const oldCheck = oldPkg.integrity || oldPkg.checksum;
const newCheck = newPkg.integrity || newPkg.checksum;
if (!oldCheck || !newCheck || oldCheck !== newCheck) {
diff.changed.push({ name, range: newQuery.range });
const otherPkg = otherLockfile.data[otherQuery.dataKey];
const thisPkg = this.data[thisQuery.dataKey];
if (otherPkg && thisPkg) {
const thisCheck = thisPkg.integrity || thisPkg.checksum;
const otherCheck = otherPkg.integrity || otherPkg.checksum;
if (!thisCheck || !otherCheck || thisCheck !== otherCheck) {
diff.changed.push({ name, range: otherQuery.range });
}
}
}
for (const oldRange of remainingOldRanges) {
diff.removed.push({ name, range: oldRange });
for (const thisRange of remainingOldRanges) {
diff.added.push({ name, range: thisRange });
}
}
for (const name of remainingOldNames) {
const queries = this.packages.get(name) ?? [];
diff.removed.push(...queries.map(q => ({ name, range: q.range })));
diff.added.push(...queries.map(q => ({ name, range: q.range })));
}
return diff;