pnpm-dedup 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +218 -0
- package/dist/applyClusterFixes.js +252 -0
- package/dist/applyClusterFixes.js.map +1 -0
- package/dist/applyClusterFixes.test.js +474 -0
- package/dist/applyClusterFixes.test.js.map +1 -0
- package/dist/bin/pnpm-dedupe.js +35 -0
- package/dist/bin/pnpm-dedupe.js.map +1 -0
- package/dist/bin/pnpm-why-duplicate.js +23 -0
- package/dist/bin/pnpm-why-duplicate.js.map +1 -0
- package/dist/bin/pnpm-why-duplicate.test.js +57 -0
- package/dist/bin/pnpm-why-duplicate.test.js.map +1 -0
- package/dist/dedupe.js +86 -0
- package/dist/dedupe.js.map +1 -0
- package/dist/dedupeCheckConsistency.test.js +149 -0
- package/dist/dedupeCheckConsistency.test.js.map +1 -0
- package/dist/dedupeEndToEnd.test.js +121 -0
- package/dist/dedupeEndToEnd.test.js.map +1 -0
- package/dist/dedupePeers.test.js +105 -0
- package/dist/dedupePeers.test.js.map +1 -0
- package/dist/definitions/applyClusterFixes.d.ts +24 -0
- package/dist/definitions/applyClusterFixes.d.ts.map +1 -0
- package/dist/definitions/applyClusterFixes.test.d.ts +2 -0
- package/dist/definitions/applyClusterFixes.test.d.ts.map +1 -0
- package/dist/definitions/bin/pnpm-dedupe.d.ts +3 -0
- package/dist/definitions/bin/pnpm-dedupe.d.ts.map +1 -0
- package/dist/definitions/bin/pnpm-why-duplicate.d.ts +3 -0
- package/dist/definitions/bin/pnpm-why-duplicate.d.ts.map +1 -0
- package/dist/definitions/bin/pnpm-why-duplicate.test.d.ts +2 -0
- package/dist/definitions/bin/pnpm-why-duplicate.test.d.ts.map +1 -0
- package/dist/definitions/dedupe.d.ts +15 -0
- package/dist/definitions/dedupe.d.ts.map +1 -0
- package/dist/definitions/dedupeCheckConsistency.test.d.ts +2 -0
- package/dist/definitions/dedupeCheckConsistency.test.d.ts.map +1 -0
- package/dist/definitions/dedupeEndToEnd.test.d.ts +2 -0
- package/dist/definitions/dedupeEndToEnd.test.d.ts.map +1 -0
- package/dist/definitions/dedupePeers.test.d.ts +2 -0
- package/dist/definitions/dedupePeers.test.d.ts.map +1 -0
- package/dist/definitions/displayMany.d.ts +16 -0
- package/dist/definitions/displayMany.d.ts.map +1 -0
- package/dist/definitions/displayMany.test.d.ts +2 -0
- package/dist/definitions/displayMany.test.d.ts.map +1 -0
- package/dist/definitions/helpers/buildIdentifiedFixesMap.test.d.ts +2 -0
- package/dist/definitions/helpers/buildIdentifiedFixesMap.test.d.ts.map +1 -0
- package/dist/definitions/helpers/buildPnpmPackagesMap.d.ts +13 -0
- package/dist/definitions/helpers/buildPnpmPackagesMap.d.ts.map +1 -0
- package/dist/definitions/helpers/buildPnpmPackagesMap.test.d.ts +2 -0
- package/dist/definitions/helpers/buildPnpmPackagesMap.test.d.ts.map +1 -0
- package/dist/definitions/helpers/collectDependentRanges.d.ts +22 -0
- package/dist/definitions/helpers/collectDependentRanges.d.ts.map +1 -0
- package/dist/definitions/helpers/collectDependentRanges.test.d.ts +2 -0
- package/dist/definitions/helpers/collectDependentRanges.test.d.ts.map +1 -0
- package/dist/definitions/helpers/collectPnpmDependents.d.ts +8 -0
- package/dist/definitions/helpers/collectPnpmDependents.d.ts.map +1 -0
- package/dist/definitions/helpers/collectPnpmDependents.test.d.ts +2 -0
- package/dist/definitions/helpers/collectPnpmDependents.test.d.ts.map +1 -0
- package/dist/definitions/helpers/duplicateSnapshot.d.ts +3 -0
- package/dist/definitions/helpers/duplicateSnapshot.d.ts.map +1 -0
- package/dist/definitions/helpers/parsePnpmLockPackages.d.ts +44 -0
- package/dist/definitions/helpers/parsePnpmLockPackages.d.ts.map +1 -0
- package/dist/definitions/helpers/parsePnpmLockPackages.test.d.ts +2 -0
- package/dist/definitions/helpers/parsePnpmLockPackages.test.d.ts.map +1 -0
- package/dist/definitions/helpers/pnpmProtocol.d.ts +2 -0
- package/dist/definitions/helpers/pnpmProtocol.d.ts.map +1 -0
- package/dist/definitions/helpers/pnpmVersion.d.ts +11 -0
- package/dist/definitions/helpers/pnpmVersion.d.ts.map +1 -0
- package/dist/definitions/helpers/pnpmWorkspaceYaml.d.ts +23 -0
- package/dist/definitions/helpers/pnpmWorkspaceYaml.d.ts.map +1 -0
- package/dist/definitions/helpers/pnpmWorkspaceYaml.test.d.ts +2 -0
- package/dist/definitions/helpers/pnpmWorkspaceYaml.test.d.ts.map +1 -0
- package/dist/definitions/helpers/projectDir.d.ts +3 -0
- package/dist/definitions/helpers/projectDir.d.ts.map +1 -0
- package/dist/definitions/helpers/readInstalledManifest.d.ts +32 -0
- package/dist/definitions/helpers/readInstalledManifest.d.ts.map +1 -0
- package/dist/definitions/helpers/readInstalledManifest.test.d.ts +2 -0
- package/dist/definitions/helpers/readInstalledManifest.test.d.ts.map +1 -0
- package/dist/definitions/helpers/runPnpm.d.ts +11 -0
- package/dist/definitions/helpers/runPnpm.d.ts.map +1 -0
- package/dist/definitions/helpers/tempProjects.d.ts +8 -0
- package/dist/definitions/helpers/tempProjects.d.ts.map +1 -0
- package/dist/definitions/helpers/toLockstepGraph.d.ts +12 -0
- package/dist/definitions/helpers/toLockstepGraph.d.ts.map +1 -0
- package/dist/definitions/helpers/toLockstepGraph.test.d.ts +2 -0
- package/dist/definitions/helpers/toLockstepGraph.test.d.ts.map +1 -0
- package/dist/definitions/helpers/versionsSnapshot.d.ts +3 -0
- package/dist/definitions/helpers/versionsSnapshot.d.ts.map +1 -0
- package/dist/definitions/identifyClusterFixes.d.ts +7 -0
- package/dist/definitions/identifyClusterFixes.d.ts.map +1 -0
- package/dist/definitions/identifyClusterFixes.test.d.ts +2 -0
- package/dist/definitions/identifyClusterFixes.test.d.ts.map +1 -0
- package/dist/definitions/identifyResolutionFixes.test.d.ts +2 -0
- package/dist/definitions/identifyResolutionFixes.test.d.ts.map +1 -0
- package/dist/definitions/index.d.ts +25 -0
- package/dist/definitions/index.d.ts.map +1 -0
- package/dist/definitions/pnpmLockTypes.d.ts +42 -0
- package/dist/definitions/pnpmLockTypes.d.ts.map +1 -0
- package/dist/definitions/readPnpmLock.d.ts +3 -0
- package/dist/definitions/readPnpmLock.d.ts.map +1 -0
- package/dist/displayMany.js +56 -0
- package/dist/displayMany.js.map +1 -0
- package/dist/displayMany.test.js +146 -0
- package/dist/displayMany.test.js.map +1 -0
- package/dist/helpers/buildIdentifiedFixesMap.test.js +27 -0
- package/dist/helpers/buildIdentifiedFixesMap.test.js.map +1 -0
- package/dist/helpers/buildPnpmPackagesMap.js +23 -0
- package/dist/helpers/buildPnpmPackagesMap.js.map +1 -0
- package/dist/helpers/buildPnpmPackagesMap.test.js +68 -0
- package/dist/helpers/buildPnpmPackagesMap.test.js.map +1 -0
- package/dist/helpers/collectDependentRanges.js +118 -0
- package/dist/helpers/collectDependentRanges.js.map +1 -0
- package/dist/helpers/collectDependentRanges.test.js +211 -0
- package/dist/helpers/collectDependentRanges.test.js.map +1 -0
- package/dist/helpers/collectPnpmDependents.js +55 -0
- package/dist/helpers/collectPnpmDependents.js.map +1 -0
- package/dist/helpers/collectPnpmDependents.test.js +78 -0
- package/dist/helpers/collectPnpmDependents.test.js.map +1 -0
- package/dist/helpers/duplicateSnapshot.js +5 -0
- package/dist/helpers/duplicateSnapshot.js.map +1 -0
- package/dist/helpers/parsePnpmLockPackages.js +62 -0
- package/dist/helpers/parsePnpmLockPackages.js.map +1 -0
- package/dist/helpers/parsePnpmLockPackages.test.js +62 -0
- package/dist/helpers/parsePnpmLockPackages.test.js.map +1 -0
- package/dist/helpers/pnpmProtocol.js +2 -0
- package/dist/helpers/pnpmProtocol.js.map +1 -0
- package/dist/helpers/pnpmVersion.js +23 -0
- package/dist/helpers/pnpmVersion.js.map +1 -0
- package/dist/helpers/pnpmWorkspaceYaml.js +48 -0
- package/dist/helpers/pnpmWorkspaceYaml.js.map +1 -0
- package/dist/helpers/pnpmWorkspaceYaml.test.js +91 -0
- package/dist/helpers/pnpmWorkspaceYaml.test.js.map +1 -0
- package/dist/helpers/projectDir.js +10 -0
- package/dist/helpers/projectDir.js.map +1 -0
- package/dist/helpers/readInstalledManifest.js +139 -0
- package/dist/helpers/readInstalledManifest.js.map +1 -0
- package/dist/helpers/readInstalledManifest.test.js +83 -0
- package/dist/helpers/readInstalledManifest.test.js.map +1 -0
- package/dist/helpers/runPnpm.js +16 -0
- package/dist/helpers/runPnpm.js.map +1 -0
- package/dist/helpers/tempProjects.js +85 -0
- package/dist/helpers/tempProjects.js.map +1 -0
- package/dist/helpers/toLockstepGraph.js +34 -0
- package/dist/helpers/toLockstepGraph.js.map +1 -0
- package/dist/helpers/toLockstepGraph.test.js +81 -0
- package/dist/helpers/toLockstepGraph.test.js.map +1 -0
- package/dist/helpers/versionsSnapshot.js +5 -0
- package/dist/helpers/versionsSnapshot.js.map +1 -0
- package/dist/identifyClusterFixes.js +53 -0
- package/dist/identifyClusterFixes.js.map +1 -0
- package/dist/identifyClusterFixes.test.js +307 -0
- package/dist/identifyClusterFixes.test.js.map +1 -0
- package/dist/identifyResolutionFixes.test.js +49 -0
- package/dist/identifyResolutionFixes.test.js.map +1 -0
- package/dist/index.js +86 -0
- package/dist/index.js.map +1 -0
- package/dist/pnpmLockTypes.js +7 -0
- package/dist/pnpmLockTypes.js.map +1 -0
- package/dist/readPnpmLock.js +6 -0
- package/dist/readPnpmLock.js.map +1 -0
- package/package.json +71 -0
- package/src/applyClusterFixes.test.ts +560 -0
- package/src/applyClusterFixes.ts +466 -0
- package/src/bin/pnpm-dedupe.ts +44 -0
- package/src/bin/pnpm-why-duplicate.test.ts +79 -0
- package/src/bin/pnpm-why-duplicate.ts +34 -0
- package/src/dedupe.ts +124 -0
- package/src/dedupeCheckConsistency.test.ts +218 -0
- package/src/dedupeEndToEnd.test.ts +168 -0
- package/src/dedupePeers.test.ts +175 -0
- package/src/displayMany.test.ts +208 -0
- package/src/displayMany.ts +104 -0
- package/src/helpers/buildIdentifiedFixesMap.test.ts +33 -0
- package/src/helpers/buildPnpmPackagesMap.test.ts +119 -0
- package/src/helpers/buildPnpmPackagesMap.ts +53 -0
- package/src/helpers/collectDependentRanges.test.ts +311 -0
- package/src/helpers/collectDependentRanges.ts +185 -0
- package/src/helpers/collectPnpmDependents.test.ts +112 -0
- package/src/helpers/collectPnpmDependents.ts +79 -0
- package/src/helpers/duplicateSnapshot.ts +18 -0
- package/src/helpers/parsePnpmLockPackages.test.ts +93 -0
- package/src/helpers/parsePnpmLockPackages.ts +99 -0
- package/src/helpers/pnpmProtocol.ts +12 -0
- package/src/helpers/pnpmVersion.ts +28 -0
- package/src/helpers/pnpmWorkspaceYaml.test.ts +140 -0
- package/src/helpers/pnpmWorkspaceYaml.ts +77 -0
- package/src/helpers/projectDir.ts +14 -0
- package/src/helpers/readInstalledManifest.test.ts +124 -0
- package/src/helpers/readInstalledManifest.ts +202 -0
- package/src/helpers/runPnpm.ts +34 -0
- package/src/helpers/tempProjects.ts +94 -0
- package/src/helpers/toLockstepGraph.test.ts +98 -0
- package/src/helpers/toLockstepGraph.ts +52 -0
- package/src/helpers/versionsSnapshot.ts +9 -0
- package/src/identifyClusterFixes.test.ts +430 -0
- package/src/identifyClusterFixes.ts +114 -0
- package/src/identifyResolutionFixes.test.ts +82 -0
- package/src/index.ts +159 -0
- package/src/pnpmLockTypes.ts +44 -0
- package/src/readPnpmLock.ts +7 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { describe, it } from "bun:test";
|
|
2
|
+
import { deepStrictEqual, ok, strictEqual } from "node:assert/strict";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { buildPnpmPackagesMap } from "./helpers/buildPnpmPackagesMap.js";
|
|
6
|
+
import { parsePnpmLockPackages } from "./helpers/parsePnpmLockPackages.js";
|
|
7
|
+
import { createManifestReader } from "./helpers/readInstalledManifest.js";
|
|
8
|
+
import { identifyClusterFixes } from "./identifyClusterFixes.js";
|
|
9
|
+
import { readPnpmLock } from "./readPnpmLock.js";
|
|
10
|
+
const fixturesBase = (rel) => fileURLToPath(new URL(rel, import.meta.url));
|
|
11
|
+
// The fixtures are committed without node_modules, so the declared ranges of
|
|
12
|
+
// the requesters that matter are stubbed; the others fall back to their
|
|
13
|
+
// resolved version, as an uninstalled project would.
|
|
14
|
+
const manifests = {
|
|
15
|
+
"@tamagui/metro-plugin@1.139.4": {
|
|
16
|
+
"metro-config": "*",
|
|
17
|
+
"metro-transform-worker": "*",
|
|
18
|
+
},
|
|
19
|
+
"@react-native/community-cli-plugin@0.87.0": { metro: "^0.87.0" },
|
|
20
|
+
"@react-native/metro-config@0.87.0": { "metro-config": "^0.87.0" },
|
|
21
|
+
"react-native-web@0.21.2": { "@react-native/normalize-colors": "^0.74.1" },
|
|
22
|
+
"react-native-reanimated@4.5.3": { "react-native": "0.83 - 0.86" },
|
|
23
|
+
"react-native-worklets@0.11.4": {
|
|
24
|
+
"react-native": "0.83 - 0.86",
|
|
25
|
+
"@react-native/metro-config": "*",
|
|
26
|
+
},
|
|
27
|
+
"@pob/eslint-config@65.5.0": {
|
|
28
|
+
"@typescript-eslint/eslint-plugin": "^8.59.1",
|
|
29
|
+
"@typescript-eslint/parser": "^8.59.1",
|
|
30
|
+
"typescript-eslint": "^8.59.1",
|
|
31
|
+
},
|
|
32
|
+
"@pob/eslint-plugin@65.5.0": { "@typescript-eslint/utils": "8.59.1" },
|
|
33
|
+
"eslint-plugin-import-x@4.16.2": {
|
|
34
|
+
"@typescript-eslint/types": "^8.56.0",
|
|
35
|
+
"@typescript-eslint/utils": "^8.56.0",
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
// The @tamagui/* and react-native-* packages peer-depend on react-native with
|
|
39
|
+
// an open range (`*`, or `0.83 - 0.86` for reanimated/worklets, both above):
|
|
40
|
+
// without them react-native's ranges read as exact resolved versions and the
|
|
41
|
+
// "nobody asks for this version" guard is never exercised.
|
|
42
|
+
const readStubbedManifest = (name, version) => {
|
|
43
|
+
const dependencies = manifests[`${name}@${version}`];
|
|
44
|
+
if (dependencies)
|
|
45
|
+
return { dependencies };
|
|
46
|
+
if (name.startsWith("@tamagui/") || name.startsWith("react-native-")) {
|
|
47
|
+
return { peerDependencies: { "react-native": "*" } };
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
};
|
|
51
|
+
const clusterFixesFor = (scenario, readManifest = readStubbedManifest) => {
|
|
52
|
+
const lock = readPnpmLock(fixturesBase(`../test/fixtures/${scenario}/pnpm-lock.yaml`));
|
|
53
|
+
return identifyClusterFixes(lock, buildPnpmPackagesMap(parsePnpmLockPackages(lock)), readManifest);
|
|
54
|
+
};
|
|
55
|
+
// Only the families: a duplicate with no lockstep sibling is reported as a
|
|
56
|
+
// cluster of one, which the tests below single out on its own.
|
|
57
|
+
const lockstepFixesFor = (scenario, readManifest = readStubbedManifest) => clusterFixesFor(scenario, readManifest).filter((fix) => fix.members.length > 1);
|
|
58
|
+
const metroCluster = () => {
|
|
59
|
+
const fix = clusterFixesFor("wildcard-not-reused").find((candidate) => candidate.members.includes("metro"));
|
|
60
|
+
ok(fix, "expected a cluster containing metro");
|
|
61
|
+
return fix;
|
|
62
|
+
};
|
|
63
|
+
describe("identifyClusterFixes", () => {
|
|
64
|
+
// Same expectations as bun-dedup's identifyClusterFixes on its own
|
|
65
|
+
// `duplicated-typescript-eslint` fixture: the pnpm adapter must reach the
|
|
66
|
+
// same conclusion from a lockfile shaped very differently.
|
|
67
|
+
it("identifies the @typescript-eslint cluster dedupable to 8.59.1", () => {
|
|
68
|
+
const fixes = lockstepFixesFor("duplicated-typescript-eslint");
|
|
69
|
+
strictEqual(fixes.length, 1);
|
|
70
|
+
const fix = fixes[0];
|
|
71
|
+
strictEqual(fix.applicable, true);
|
|
72
|
+
strictEqual(fix.target, "8.59.1");
|
|
73
|
+
strictEqual(fix.direction, "down");
|
|
74
|
+
strictEqual(fix.needsRoundTrip, true);
|
|
75
|
+
ok(fix.members.includes("typescript-eslint"));
|
|
76
|
+
deepStrictEqual(fix.duplicatedMembers, [
|
|
77
|
+
"@typescript-eslint/project-service",
|
|
78
|
+
"@typescript-eslint/scope-manager",
|
|
79
|
+
"@typescript-eslint/tsconfig-utils",
|
|
80
|
+
"@typescript-eslint/types",
|
|
81
|
+
"@typescript-eslint/typescript-estree",
|
|
82
|
+
"@typescript-eslint/utils",
|
|
83
|
+
"@typescript-eslint/visitor-keys",
|
|
84
|
+
]);
|
|
85
|
+
deepStrictEqual(fix.reResolutionSet, [
|
|
86
|
+
"@typescript-eslint/eslint-plugin",
|
|
87
|
+
"@typescript-eslint/parser",
|
|
88
|
+
"typescript-eslint",
|
|
89
|
+
]);
|
|
90
|
+
});
|
|
91
|
+
it("finds no target when the requesters' manifests are unavailable", () => {
|
|
92
|
+
// Without node_modules every transitive range degrades to the resolved
|
|
93
|
+
// version, so `@pob/eslint-config`'s `^8.59.1` reads as `8.61.0` and
|
|
94
|
+
// `@pob/eslint-plugin`'s pin keeps utils at 8.59.1: no version is left that
|
|
95
|
+
// any duplicate can collapse onto.
|
|
96
|
+
const fixes = lockstepFixesFor("duplicated-typescript-eslint", () => undefined);
|
|
97
|
+
strictEqual(fixes.length, 1);
|
|
98
|
+
const fix = fixes[0];
|
|
99
|
+
strictEqual(fix.applicable, false);
|
|
100
|
+
strictEqual(fix.target, null);
|
|
101
|
+
deepStrictEqual(fix.reuseFixes, []);
|
|
102
|
+
});
|
|
103
|
+
// `hoisted-node-linker` is the shape of a real repo that reported no fix at
|
|
104
|
+
// all: with `nodeLinker: hoisted` there is no `node_modules/.pnpm/<pkg>` to
|
|
105
|
+
// read, so every declared range degraded to the resolved version. It is the
|
|
106
|
+
// only fixture whose manifests are committed, so the real reader runs here.
|
|
107
|
+
const hoistedFixtureDir = fixturesBase("../test/fixtures/hoisted-node-linker");
|
|
108
|
+
const hoistedClusterFix = (readManifest) => {
|
|
109
|
+
const lock = readPnpmLock(join(hoistedFixtureDir, "pnpm-lock.yaml"));
|
|
110
|
+
const fixes = identifyClusterFixes(lock, buildPnpmPackagesMap(parsePnpmLockPackages(lock)), readManifest);
|
|
111
|
+
strictEqual(fixes.length, 1);
|
|
112
|
+
return fixes[0];
|
|
113
|
+
};
|
|
114
|
+
it("reads the ranges out of a hoisted node_modules", () => {
|
|
115
|
+
const fix = hoistedClusterFix(createManifestReader(hoistedFixtureDir));
|
|
116
|
+
// the pinned 0.84.5 wins: `mini-plugin` asks for `*`, so nothing external
|
|
117
|
+
// wants 0.87.0 and the pin needs no editing
|
|
118
|
+
strictEqual(fix.applicable, true);
|
|
119
|
+
strictEqual(fix.target, "0.84.5");
|
|
120
|
+
strictEqual(fix.direction, "down");
|
|
121
|
+
deepStrictEqual(fix.convergentMembers, ["mini-metro", "mini-metro-config"]);
|
|
122
|
+
deepStrictEqual(fix.driverMembers, ["mini-metro"]);
|
|
123
|
+
deepStrictEqual(fix.workspaceChanges, []);
|
|
124
|
+
strictEqual(fix.needsRoundTrip, false);
|
|
125
|
+
deepStrictEqual(fix.reuseFixes.map((reuse) => `${reuse.requesterName}>${reuse.packageName} ${reuse.from} -> ${reuse.to}`), [
|
|
126
|
+
// read from a nested manifest three levels deep, via `.modules.yaml`
|
|
127
|
+
"mini-deep>mini-metro-config 0.87.0 -> 0.84.5",
|
|
128
|
+
"mini-plugin>mini-metro-config 0.87.0 -> 0.84.5",
|
|
129
|
+
]);
|
|
130
|
+
});
|
|
131
|
+
it("inverts the advice when the layout hides the manifests", () => {
|
|
132
|
+
// What the same lockfile reports when the manifests cannot be read:
|
|
133
|
+
// `mini-plugin`'s `*` reads as an exact `0.87.0`, so keeping the pin
|
|
134
|
+
// collapses nothing and the fix becomes "upgrade the pin" — the opposite of
|
|
135
|
+
// the answer above. Hence the warning when nothing is readable.
|
|
136
|
+
const fix = hoistedClusterFix(() => undefined);
|
|
137
|
+
strictEqual(fix.target, "0.87.0");
|
|
138
|
+
strictEqual(fix.direction, "up");
|
|
139
|
+
deepStrictEqual(fix.workspaceChanges.map((change) => `${change.packageName} ${change.range} -> ${change.to}`), ["mini-metro 0.84.5 -> 0.87.0"]);
|
|
140
|
+
deepStrictEqual(fix.reuseFixes, []);
|
|
141
|
+
});
|
|
142
|
+
it("returns no cluster fix when there is no lockstep family", () => {
|
|
143
|
+
deepStrictEqual(lockstepFixesFor("duplicated-printable-shell-command"), []);
|
|
144
|
+
});
|
|
145
|
+
// `exact-pin-forces-downgrade` commits its virtual store, so the real reader
|
|
146
|
+
// runs: `@yudiel/react-qr-scanner` pins barcode-detector at exactly 3.0.3
|
|
147
|
+
// while `expo-camera` declares `^3.0.0` and resolved 3.2.2.
|
|
148
|
+
const downgradeFixtureDir = fixturesBase("../test/fixtures/exact-pin-forces-downgrade");
|
|
149
|
+
it("converges a lone duplicate on the version every range accepts", () => {
|
|
150
|
+
const fixes = clusterFixesFor("exact-pin-forces-downgrade", createManifestReader(downgradeFixtureDir));
|
|
151
|
+
const fix = fixes.find((candidate) => candidate.members.includes("barcode-detector"));
|
|
152
|
+
ok(fix, "expected a fix for barcode-detector");
|
|
153
|
+
deepStrictEqual(fix.members, ["barcode-detector"]);
|
|
154
|
+
strictEqual(fix.applicable, true);
|
|
155
|
+
// 3.2.2 is rejected by the exact pin, so converging means moving the caret
|
|
156
|
+
// dependent down — which only an override can do
|
|
157
|
+
strictEqual(fix.target, "3.0.3");
|
|
158
|
+
strictEqual(fix.direction, "down");
|
|
159
|
+
deepStrictEqual(fix.convergentMembers, ["barcode-detector"]);
|
|
160
|
+
deepStrictEqual(fix.driverMembers, ["barcode-detector"]);
|
|
161
|
+
deepStrictEqual(fix.workspaceChanges, []);
|
|
162
|
+
deepStrictEqual(fix.externalConstraints.map((constraint) => [
|
|
163
|
+
constraint.requesterName,
|
|
164
|
+
constraint.range,
|
|
165
|
+
]), [
|
|
166
|
+
["@yudiel/react-qr-scanner", "3.0.3"],
|
|
167
|
+
["expo-camera", "^3.0.0"],
|
|
168
|
+
]);
|
|
169
|
+
});
|
|
170
|
+
it("finds nothing for the duplicate a convergence drags along", () => {
|
|
171
|
+
const fixes = clusterFixesFor("exact-pin-forces-downgrade", createManifestReader(downgradeFixtureDir));
|
|
172
|
+
const fix = fixes.find((candidate) => candidate.members.includes("zxing-wasm"));
|
|
173
|
+
ok(fix, "expected a fix record for zxing-wasm");
|
|
174
|
+
// barcode-detector@3.0.3 asks `^2.1.2` and 3.2.2 asks exactly 3.1.3
|
|
175
|
+
strictEqual(fix.applicable, false);
|
|
176
|
+
strictEqual(fix.target, null);
|
|
177
|
+
});
|
|
178
|
+
it("leaves a lone duplicate alone when only a workspace pin could move", () => {
|
|
179
|
+
// `printable-shell-command` is pinned at 5.0.7 by the workspace and at
|
|
180
|
+
// 5.3.1 by `betterdisplaycli`: converging means bumping the user's own pin,
|
|
181
|
+
// which is an upgrade decision rather than a dedupe.
|
|
182
|
+
deepStrictEqual(clusterFixesFor("duplicated-printable-shell-command"), []);
|
|
183
|
+
});
|
|
184
|
+
it("skips clusters whose members are all single-version", () => {
|
|
185
|
+
for (const fix of lockstepFixesFor("wildcard-not-reused")) {
|
|
186
|
+
ok(fix.duplicatedMembers.length > 0);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
it("detects the metro family the non-reused wildcard duplicated", () => {
|
|
190
|
+
const fix = metroCluster();
|
|
191
|
+
for (const member of [
|
|
192
|
+
"metro",
|
|
193
|
+
"metro-config",
|
|
194
|
+
"metro-transform-worker",
|
|
195
|
+
"ob1",
|
|
196
|
+
]) {
|
|
197
|
+
ok(fix.duplicatedMembers.includes(member), `expected ${member}`);
|
|
198
|
+
}
|
|
199
|
+
strictEqual(fix.duplicatedMembers.length, 16);
|
|
200
|
+
});
|
|
201
|
+
it("keeps external constraints and drops the derived internal pins", () => {
|
|
202
|
+
const byRequester = metroCluster().externalConstraints.map((constraint) => `${constraint.requesterName ?? "workspace"} -> ${constraint.packageName} @ ${constraint.range}`);
|
|
203
|
+
for (const expected of [
|
|
204
|
+
"workspace -> metro @ 0.84.5",
|
|
205
|
+
"@tamagui/metro-plugin -> metro-config @ *",
|
|
206
|
+
"@tamagui/metro-plugin -> metro-transform-worker @ *",
|
|
207
|
+
"react-native-web -> @react-native/normalize-colors @ ^0.74.1",
|
|
208
|
+
]) {
|
|
209
|
+
ok(byRequester.includes(expected), `expected constraint ${expected}`);
|
|
210
|
+
}
|
|
211
|
+
// metro's own `metro-config: 0.84.5` / `0.87.0` pins are internal: they
|
|
212
|
+
// exist only because metro resolved where it did.
|
|
213
|
+
const requesterNames = new Set(metroCluster().externalConstraints.map((constraint) => constraint.requesterName));
|
|
214
|
+
strictEqual(requesterNames.has("metro"), false);
|
|
215
|
+
strictEqual(requesterNames.has("metro-config"), false);
|
|
216
|
+
});
|
|
217
|
+
it("converges the family on the pinned version, without touching the pin", () => {
|
|
218
|
+
const fix = metroCluster();
|
|
219
|
+
// The root pins metro at 0.84.5 on purpose, so the pin is a constraint to
|
|
220
|
+
// resolve around, not something to upgrade: the family collapses onto
|
|
221
|
+
// 0.84.5 and `workspaceChanges` stays empty.
|
|
222
|
+
strictEqual(fix.applicable, true);
|
|
223
|
+
strictEqual(fix.target, "0.84.5");
|
|
224
|
+
strictEqual(fix.direction, "down");
|
|
225
|
+
strictEqual(fix.convergentMembers.length, 15);
|
|
226
|
+
deepStrictEqual(fix.workspaceChanges, []);
|
|
227
|
+
// metro is the only member a real range applies to (the pin): the 14
|
|
228
|
+
// metro-* packages are requested through `*` or through metro's own exact
|
|
229
|
+
// pins, so they carry no decision and follow it.
|
|
230
|
+
deepStrictEqual(fix.driverMembers, ["metro"]);
|
|
231
|
+
});
|
|
232
|
+
it("leaves react-native's version to the resolver", () => {
|
|
233
|
+
const fix = metroCluster();
|
|
234
|
+
// react-native@0.87.0 and @react-native/metro-config@0.87.0 are what hold
|
|
235
|
+
// the 0.87.0 metro subtree, and nothing pins either of them there — both
|
|
236
|
+
// arrive through `*` / `0.83 - 0.86` peer ranges (0.87.0 does not even
|
|
237
|
+
// satisfy the latter). They have to move, but which version they land on is
|
|
238
|
+
// the resolver's call, so no version is asserted for them.
|
|
239
|
+
deepStrictEqual(fix.floatingMembers, [
|
|
240
|
+
"@react-native/metro-config",
|
|
241
|
+
"react-native",
|
|
242
|
+
]);
|
|
243
|
+
deepStrictEqual(fix.reResolutionSet, []);
|
|
244
|
+
strictEqual(fix.needsRoundTrip, true);
|
|
245
|
+
});
|
|
246
|
+
it("repoints the wildcards that ignored the pinned version", () => {
|
|
247
|
+
const fix = metroCluster();
|
|
248
|
+
// What the fixture is actually about: `@tamagui/metro-plugin` declares
|
|
249
|
+
// `metro-config: "*"` / `metro-transform-worker: "*"`, and pnpm resolved
|
|
250
|
+
// both to 0.87.0 although the pinned 0.84.5 was already in the tree and the
|
|
251
|
+
// range accepts it — so the plugin runs against a different metro than the
|
|
252
|
+
// app's.
|
|
253
|
+
strictEqual(fix.anchor, "0.84.5");
|
|
254
|
+
deepStrictEqual(fix.reuseFixes.map((reuse) => `${reuse.requesterName}>${reuse.packageName} "${reuse.range}" ${reuse.from} -> ${reuse.to}`), [
|
|
255
|
+
'@tamagui/metro-plugin>metro-config "*" 0.87.0 -> 0.84.5',
|
|
256
|
+
'@tamagui/metro-plugin>metro-transform-worker "*" 0.87.0 -> 0.84.5',
|
|
257
|
+
]);
|
|
258
|
+
});
|
|
259
|
+
it("leaves alone the ranges that cannot accept the pinned version", () => {
|
|
260
|
+
const repointed = new Set(metroCluster().reuseFixes.map((reuse) => reuse.packageName));
|
|
261
|
+
// `@react-native/metro-config` requires `metro-config: ^0.87.0`, and
|
|
262
|
+
// `react-native-web` requires `@react-native/normalize-colors: ^0.74.1`:
|
|
263
|
+
// neither accepts 0.84.5, so neither is repointed.
|
|
264
|
+
strictEqual(repointed.has("@react-native/normalize-colors"), false);
|
|
265
|
+
deepStrictEqual(metroCluster()
|
|
266
|
+
.reuseFixes.filter((reuse) => reuse.requesterName === "@react-native/metro-config")
|
|
267
|
+
.map((reuse) => reuse.packageName), []);
|
|
268
|
+
});
|
|
269
|
+
// `aliased-swapped-names`: the importer pins the real `typescript` at 7.0.2
|
|
270
|
+
// through the `@typescript/native` key while `tool` needs 5.9.3, and the
|
|
271
|
+
// `typescript` key holds an unrelated package. Nothing converges, and nothing
|
|
272
|
+
// may propose editing the declaration that names the other package.
|
|
273
|
+
it("leaves an exact pin declared under a swapped alias key alone", () => {
|
|
274
|
+
const fixes = clusterFixesFor("aliased-swapped-names", () => undefined);
|
|
275
|
+
deepStrictEqual(fixes.map((fix) => fix.members), [["typescript"]]);
|
|
276
|
+
strictEqual(fixes[0].applicable, false);
|
|
277
|
+
deepStrictEqual(fixes[0].workspaceChanges, []);
|
|
278
|
+
});
|
|
279
|
+
// The same swapped keys, with `typescript` sitting in a lockstep family (its
|
|
280
|
+
// platform binaries) as it does from 7.0.0 on: the family makes the cluster
|
|
281
|
+
// big enough to escape the singleton guard above, and the pin is then the only
|
|
282
|
+
// thing standing between the dedupe and a rewrite of `"@typescript/native":
|
|
283
|
+
// "npm:typescript@7.0.2"` into `npm:typescript@6.0.3` — the alias repointed at
|
|
284
|
+
// the very package it exists to sit beside.
|
|
285
|
+
it("never repoints an alias to converge its family", () => {
|
|
286
|
+
const fix = clusterFixesFor("aliased-swapped-names-cluster", (name, version) => name === "@typescript/typescript6" && version === "6.0.2"
|
|
287
|
+
? { dependencies: { typescript: "^6" } }
|
|
288
|
+
: undefined).find((candidate) => candidate.members.includes("typescript"));
|
|
289
|
+
ok(fix);
|
|
290
|
+
strictEqual(fix.members.length, 3);
|
|
291
|
+
deepStrictEqual(fix.duplicatedMembers, ["typescript"]);
|
|
292
|
+
strictEqual(fix.applicable, false);
|
|
293
|
+
strictEqual(fix.target, null);
|
|
294
|
+
deepStrictEqual(fix.workspaceChanges, []);
|
|
295
|
+
});
|
|
296
|
+
it("reports a cluster no member can leave as not dedupable", () => {
|
|
297
|
+
// metro pins hermes-parser exactly at 0.35.0 and @react-native/* at 0.36.1,
|
|
298
|
+
// and hermes-estree only exists twice because hermes-parser does: nothing
|
|
299
|
+
// can collapse.
|
|
300
|
+
const fix = clusterFixesFor("wildcard-not-reused").find((candidate) => candidate.members.includes("hermes-parser"));
|
|
301
|
+
ok(fix);
|
|
302
|
+
strictEqual(fix.applicable, false);
|
|
303
|
+
strictEqual(fix.target, null);
|
|
304
|
+
deepStrictEqual(fix.convergentMembers, []);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
//# sourceMappingURL=identifyClusterFixes.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identifyClusterFixes.test.js","sourceRoot":"","sources":["../src/identifyClusterFixes.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { identifyResolutionFixes } from "pm-dedup-core";
|
|
5
|
+
const loadResolutionsFixture = (fileName) => {
|
|
6
|
+
return JSON.parse(fs.readFileSync(fileURLToPath(new URL(`../test/fixtures/resolutions/${fileName}`, import.meta.url)),
|
|
7
|
+
// eslint-disable-next-line unicorn/prefer-json-parse-buffer
|
|
8
|
+
"utf8"));
|
|
9
|
+
};
|
|
10
|
+
const loadDependentsFixture = (fileName) => {
|
|
11
|
+
return JSON.parse(fs.readFileSync(fileURLToPath(new URL(`../test/fixtures/dependents/${fileName}`, import.meta.url)),
|
|
12
|
+
// eslint-disable-next-line unicorn/prefer-json-parse-buffer
|
|
13
|
+
"utf8"));
|
|
14
|
+
};
|
|
15
|
+
const objetToMap = (obj) => new Map(Object.entries(obj));
|
|
16
|
+
describe("identifyResolutionFixes", () => {
|
|
17
|
+
it("should return an empty array when there are no resolutions", () => {
|
|
18
|
+
const resolutions = [];
|
|
19
|
+
const fixes = identifyResolutionFixes(resolutions, objetToMap({}));
|
|
20
|
+
expect(fixes).toEqual([]);
|
|
21
|
+
});
|
|
22
|
+
it("should return an empty array when there is only one resolution", () => {
|
|
23
|
+
const resolutions = loadResolutionsFixture("semver-7.7.3.json");
|
|
24
|
+
const dependents = loadDependentsFixture("semver-7.7.3.json");
|
|
25
|
+
const fixes = identifyResolutionFixes(resolutions, objetToMap(dependents));
|
|
26
|
+
expect(fixes).toEqual([]);
|
|
27
|
+
});
|
|
28
|
+
it("should not identify fixes when dependencies are not compatible", () => {
|
|
29
|
+
const resolutions = loadResolutionsFixture("babel-code-frame-7.26.2-7.27.1.json");
|
|
30
|
+
const dependents = loadDependentsFixture("babel-code-frame-7.26.2-7.27.1.json");
|
|
31
|
+
const fixes = identifyResolutionFixes(resolutions, objetToMap(dependents));
|
|
32
|
+
expect(fixes).toEqual([]);
|
|
33
|
+
});
|
|
34
|
+
it("should identify resolution fixes when dependencies are compatible", () => {
|
|
35
|
+
const resolutions = loadResolutionsFixture("printable-shell-command-5.0.7-5.0.8.json");
|
|
36
|
+
const dependents = loadDependentsFixture("printable-shell-command-5.0.7-5.0.8.json");
|
|
37
|
+
const fixes = identifyResolutionFixes(resolutions, objetToMap(dependents));
|
|
38
|
+
expect(fixes).toEqual([
|
|
39
|
+
{
|
|
40
|
+
mergeableResolutions: [
|
|
41
|
+
"printable-shell-command@5.0.7",
|
|
42
|
+
"printable-shell-command@5.0.8",
|
|
43
|
+
],
|
|
44
|
+
to: "printable-shell-command@5.0.8",
|
|
45
|
+
},
|
|
46
|
+
]);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
//# sourceMappingURL=identifyResolutionFixes.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identifyResolutionFixes.test.js","sourceRoot":"","sources":["../src/identifyResolutionFixes.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAIxD,MAAM,sBAAsB,GAAG,CAAC,QAAgB,EAAuB,EAAE;IACvE,OAAO,IAAI,CAAC,KAAK,CACf,EAAE,CAAC,YAAY,CACb,aAAa,CACX,IAAI,GAAG,CAAC,gCAAgC,QAAQ,EAAE,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CACrE;IACD,4DAA4D;IAC5D,MAAM,CACP,CACF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAC5B,QAAgB,EACa,EAAE;IAC/B,OAAO,IAAI,CAAC,KAAK,CACf,EAAE,CAAC,YAAY,CACb,aAAa,CACX,IAAI,GAAG,CAAC,+BAA+B,QAAQ,EAAE,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CACpE;IACD,4DAA4D;IAC5D,MAAM,CACP,CACF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,CAAsB,GAAiB,EAAa,EAAE,CACvE,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAa,CAAC,CAAC;AAE3C,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,WAAW,GAAwB,EAAE,CAAC;QAE5C,MAAM,KAAK,GAAG,uBAAuB,CAAC,WAAW,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;QACnE,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,WAAW,GAAG,sBAAsB,CAAC,mBAAmB,CAAC,CAAC;QAChE,MAAM,UAAU,GAAG,qBAAqB,CAAC,mBAAmB,CAAC,CAAC;QAC9D,MAAM,KAAK,GAAG,uBAAuB,CAAC,WAAW,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;QAC3E,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,WAAW,GAAG,sBAAsB,CACxC,qCAAqC,CACtC,CAAC;QACF,MAAM,UAAU,GAAG,qBAAqB,CACtC,qCAAqC,CACtC,CAAC;QACF,MAAM,KAAK,GAAG,uBAAuB,CAAC,WAAW,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;QAC3E,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,WAAW,GAAG,sBAAsB,CACxC,0CAA0C,CAC3C,CAAC;QACF,MAAM,UAAU,GAAG,qBAAqB,CACtC,0CAA0C,CAC3C,CAAC;QAEF,MAAM,KAAK,GAAG,uBAAuB,CAAC,WAAW,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;QAC3E,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;YACpB;gBACE,oBAAoB,EAAE;oBACpB,+BAA+B;oBAC/B,+BAA+B;iBAChC;gBACD,EAAE,EAAE,+BAA+B;aACpC;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { createPackageFilter, selectExplainedPackages, selectPackages, } from "pm-dedup-core";
|
|
2
|
+
import { displayMany } from "./displayMany.js";
|
|
3
|
+
import { buildPnpmPackagesMap, filterDuplicatesPnpmPackagesMap, } from "./helpers/buildPnpmPackagesMap.js";
|
|
4
|
+
import { collectDependentRanges } from "./helpers/collectDependentRanges.js";
|
|
5
|
+
import { parsePnpmLockPackages } from "./helpers/parsePnpmLockPackages.js";
|
|
6
|
+
import { lockPathOf, resolvePnpmProjectDir } from "./helpers/projectDir.js";
|
|
7
|
+
import { createManifestReaderWithStats } from "./helpers/readInstalledManifest.js";
|
|
8
|
+
import { identifyClusterFixes } from "./identifyClusterFixes.js";
|
|
9
|
+
import { readPnpmLock } from "./readPnpmLock.js";
|
|
10
|
+
export { dedupe } from "./dedupe.js";
|
|
11
|
+
export { applyClusterFixes } from "./applyClusterFixes.js";
|
|
12
|
+
export { identifyClusterFixes } from "./identifyClusterFixes.js";
|
|
13
|
+
export { toLockstepGraph } from "./helpers/toLockstepGraph.js";
|
|
14
|
+
export { displayMany } from "./displayMany.js";
|
|
15
|
+
export { readPnpmLock } from "./readPnpmLock.js";
|
|
16
|
+
export { parsePnpmLockPackages } from "./helpers/parsePnpmLockPackages.js";
|
|
17
|
+
export { buildPnpmPackagesMap, filterDuplicatesPnpmPackagesMap, } from "./helpers/buildPnpmPackagesMap.js";
|
|
18
|
+
export { collectPnpmDependents } from "./helpers/collectPnpmDependents.js";
|
|
19
|
+
export { collectDependentRanges } from "./helpers/collectDependentRanges.js";
|
|
20
|
+
export { readVersionsSnapshot } from "./helpers/versionsSnapshot.js";
|
|
21
|
+
export { createManifestReader, createManifestReaderWithStats, } from "./helpers/readInstalledManifest.js";
|
|
22
|
+
/**
|
|
23
|
+
* Every declared range of a transitive dependent is read from its installed
|
|
24
|
+
* manifest; the lockfile only stores resolved versions. When nothing is
|
|
25
|
+
* readable, each range degrades to an exact version and the reported fixes are
|
|
26
|
+
* not merely fewer but wrong — so say so instead of printing a confident answer.
|
|
27
|
+
*/
|
|
28
|
+
function warnWhenNoManifests(stats) {
|
|
29
|
+
if (stats.found > 0 || stats.missed === 0)
|
|
30
|
+
return;
|
|
31
|
+
console.log();
|
|
32
|
+
console.log("Warning: no installed manifest could be read under node_modules, so every dependent's range fell back to its resolved version and the fixes above are unreliable. Run `pnpm install` first.");
|
|
33
|
+
}
|
|
34
|
+
// The report and the fixes must agree on what every requester asked for, so
|
|
35
|
+
// both read the declared ranges the lockfile does not store.
|
|
36
|
+
function collectRanges(lock, packagesMap, readManifest) {
|
|
37
|
+
return collectDependentRanges(lock, new Set(Object.keys(packagesMap)), readManifest);
|
|
38
|
+
}
|
|
39
|
+
export function whyDuplicate({ filter: filterOptions, all = false, details = false, }) {
|
|
40
|
+
const filter = createPackageFilter(filterOptions);
|
|
41
|
+
const projectDir = resolvePnpmProjectDir();
|
|
42
|
+
if (projectDir === null)
|
|
43
|
+
return;
|
|
44
|
+
const lock = readPnpmLock(lockPathOf(projectDir));
|
|
45
|
+
const parsed = parsePnpmLockPackages(lock);
|
|
46
|
+
const packagesMap = buildPnpmPackagesMap(parsed);
|
|
47
|
+
const { packages: filteredPackages, title, notice, } = selectExplainedPackages({ packagesMap, filter, all });
|
|
48
|
+
const { readManifest, stats } = createManifestReaderWithStats(projectDir);
|
|
49
|
+
// A duplicate is often only explainable by its family: show the cluster fixes
|
|
50
|
+
// covering the matched packages, not just their own dependents.
|
|
51
|
+
const matchedClusterFixes = identifyClusterFixes(lock, packagesMap, readManifest).filter((fix) => fix.members.some(filter.selects));
|
|
52
|
+
displayMany({
|
|
53
|
+
title,
|
|
54
|
+
notice,
|
|
55
|
+
duplicatesPackagesMap: filteredPackages,
|
|
56
|
+
dependents: collectRanges(lock, filteredPackages, readManifest),
|
|
57
|
+
// the whole lockfile, so the count means the same whatever the filter
|
|
58
|
+
totalDependencies: Object.keys(packagesMap).length,
|
|
59
|
+
clusterFixes: matchedClusterFixes,
|
|
60
|
+
details,
|
|
61
|
+
});
|
|
62
|
+
warnWhenNoManifests(stats());
|
|
63
|
+
}
|
|
64
|
+
export function listDuplicates({ filter: filterOptions, details = false, } = {}) {
|
|
65
|
+
const filter = createPackageFilter(filterOptions);
|
|
66
|
+
const projectDir = resolvePnpmProjectDir();
|
|
67
|
+
if (projectDir === null)
|
|
68
|
+
return;
|
|
69
|
+
const lock = readPnpmLock(lockPathOf(projectDir));
|
|
70
|
+
const parsed = parsePnpmLockPackages(lock);
|
|
71
|
+
const packagesMap = buildPnpmPackagesMap(parsed);
|
|
72
|
+
const duplicatesPackagesMap = selectPackages(filterDuplicatesPnpmPackagesMap(packagesMap), filter);
|
|
73
|
+
const { readManifest, stats } = createManifestReaderWithStats(projectDir);
|
|
74
|
+
displayMany({
|
|
75
|
+
title: "duplicates",
|
|
76
|
+
duplicatesPackagesMap,
|
|
77
|
+
dependents: collectRanges(lock, duplicatesPackagesMap, readManifest),
|
|
78
|
+
totalDependencies: Object.keys(packagesMap).length,
|
|
79
|
+
// as in `whyDuplicate`: a family is shown whole as soon as it holds a
|
|
80
|
+
// selected member, because that is what explains the duplicate
|
|
81
|
+
clusterFixes: identifyClusterFixes(lock, packagesMap, readManifest).filter((fix) => fix.members.some(filter.selects)),
|
|
82
|
+
details,
|
|
83
|
+
});
|
|
84
|
+
warnWhenNoManifests(stats());
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pnpmLockTypes.js","sourceRoot":"","sources":["../src/pnpmLockTypes.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readPnpmLock.js","sourceRoot":"","sources":["../src/readPnpmLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAG7B,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,QAAgB,EAAgB,EAAE;IAC7D,OAAO,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAiB,CAAC;AAC/D,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pnpm-dedup",
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "List duplicates and dedupe pnpm lock file",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dedupe",
|
|
7
|
+
"duplicate",
|
|
8
|
+
"pnpm"
|
|
9
|
+
],
|
|
10
|
+
"homepage": "https://github.com/christophehurpeau/pm-tools",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/christophehurpeau/pm-tools/issues"
|
|
13
|
+
},
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": "Christophe Hurpeau <christophe@hurpeau.com> (https://christophe.hurpeau.com)",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/christophehurpeau/pm-tools.git",
|
|
19
|
+
"directory": "packages/pnpm-dedup"
|
|
20
|
+
},
|
|
21
|
+
"bin": {
|
|
22
|
+
"pnpm-dedup": "./dist/bin/pnpm-dedupe.js",
|
|
23
|
+
"pnpm-dedupe": "./dist/bin/pnpm-dedupe.js",
|
|
24
|
+
"pnpm-why-duplicate": "./dist/bin/pnpm-why-duplicate.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"src",
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"type": "module",
|
|
31
|
+
"sideEffects": false,
|
|
32
|
+
"main": "./dist/index.js",
|
|
33
|
+
"types": "./dist/definitions/index.d.ts",
|
|
34
|
+
"exports": {
|
|
35
|
+
"./package.json": "./package.json",
|
|
36
|
+
".": {
|
|
37
|
+
"types": "./dist/definitions/index.d.ts",
|
|
38
|
+
"node": {
|
|
39
|
+
"import": "./dist/index.js"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsc",
|
|
45
|
+
"lint": "bun run lint:oxlint && bun run lint:eslint",
|
|
46
|
+
"lint:eslint": "bun run --cwd '../..' eslint --quiet 'packages/pnpm-dedup'",
|
|
47
|
+
"lint:oxlint": "bun run --cwd '../..' oxlint --quiet 'packages/pnpm-dedup'",
|
|
48
|
+
"test": "bun run --cwd '../..' test -- 'packages/pnpm-dedup'",
|
|
49
|
+
"tsc": "tsc"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"pm-dedup-core": "workspace:*",
|
|
53
|
+
"semver": "7.8.5",
|
|
54
|
+
"tslib": "^2.8.1",
|
|
55
|
+
"yaml": "2.9.1"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@types/bun": "1.4.2",
|
|
59
|
+
"@typescript/native": "npm:typescript@7.0.2",
|
|
60
|
+
"typescript": "npm:@typescript/typescript6@6.0.2"
|
|
61
|
+
},
|
|
62
|
+
"engines": {
|
|
63
|
+
"node": ">=22.18.0"
|
|
64
|
+
},
|
|
65
|
+
"pob": {
|
|
66
|
+
"bundler": "tsc",
|
|
67
|
+
"entries": [
|
|
68
|
+
"index"
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
}
|