@pnpm/hooks.read-package-hook 1100.1.3 → 1100.2.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/CHANGELOG.md +11 -0
- package/lib/createVersionsOverrider.d.ts +15 -0
- package/lib/createVersionsOverrider.js +71 -29
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @pnpm/hooks.read-package-hook
|
|
2
2
|
|
|
3
|
+
## 1100.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- `overrides` now also govern peers that pnpm auto-installs. Previously an override only rewrote dependencies declared in a manifest, so a peer nobody declares — installed because `autoInstallPeers` is on — resolved against its declared peer range and could bring in a second copy of the very package the override pinned. For example, with `overrides: { react: npm:react@19.2.0 }` and a lone `lucide-react` dependency, pnpm installed `react@18.3.1`; it now installs the pinned `react@19.2.0` [#13320](https://github.com/pnpm/pnpm/issues/13320).
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies:
|
|
12
|
+
- @pnpm/types@1101.7.0
|
|
13
|
+
|
|
3
14
|
## 1100.1.3
|
|
4
15
|
|
|
5
16
|
### Patch Changes
|
|
@@ -11,4 +11,19 @@ export interface CreateVersionsOverriderOptions {
|
|
|
11
11
|
*/
|
|
12
12
|
convergeDeclaredRanges?: Map<string, Set<string>>;
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Resolves the specifier an override imposes on a single dependency edge, or
|
|
16
|
+
* `undefined` when no override claims it. `'-'` means the edge is removed.
|
|
17
|
+
*
|
|
18
|
+
* Edges that have no declaring manifest — a peer pnpm auto-installs — reach
|
|
19
|
+
* the overrides through this function instead of through the read-package
|
|
20
|
+
* hook, so parent-scoped overrides (`parent>child`) never apply to them.
|
|
21
|
+
*/
|
|
22
|
+
export type DependencyOverrider = (name: string, bareSpecifier: string, dir?: string) => string | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* `undefined` when no override in the set could ever claim an undeclared
|
|
25
|
+
* dependency, so the resolver skips the per-peer call in the common case of a
|
|
26
|
+
* project with no overrides — or with parent-scoped ones only.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createDependencyOverrider(overrides: VersionOverrideWithoutRawSelector[], rootDir: string): DependencyOverrider | undefined;
|
|
14
29
|
export declare function createVersionsOverrider(overrides: VersionOverrideWithoutRawSelector[], rootDir: string, opts?: CreateVersionsOverriderOptions): ReadPackageHook;
|
|
@@ -4,13 +4,27 @@ import normalizePath from 'normalize-path';
|
|
|
4
4
|
import { partition } from 'ramda';
|
|
5
5
|
import semver from 'semver';
|
|
6
6
|
import { isIntersectingRange } from './isIntersectingRange.js';
|
|
7
|
+
/**
|
|
8
|
+
* `undefined` when no override in the set could ever claim an undeclared
|
|
9
|
+
* dependency, so the resolver skips the per-peer call in the common case of a
|
|
10
|
+
* project with no overrides — or with parent-scoped ones only.
|
|
11
|
+
*/
|
|
12
|
+
export function createDependencyOverrider(overrides, rootDir) {
|
|
13
|
+
const { genericVersionOverrides, convergeVersions } = splitOverrides(overrides, rootDir);
|
|
14
|
+
if (genericVersionOverrides.length === 0 && convergeVersions.size === 0)
|
|
15
|
+
return undefined;
|
|
16
|
+
return (name, bareSpecifier, dir) => {
|
|
17
|
+
const versionOverride = pickVersionOverride({ versionOverrides: [], genericVersionOverrides }, name, bareSpecifier);
|
|
18
|
+
if (versionOverride) {
|
|
19
|
+
return versionOverride.newBareSpecifier === '-'
|
|
20
|
+
? '-'
|
|
21
|
+
: resolveOverriddenBareSpecifier(versionOverride, dir);
|
|
22
|
+
}
|
|
23
|
+
return convergeBareSpecifier(convergeVersions, name, bareSpecifier);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
7
26
|
export function createVersionsOverrider(overrides, rootDir, opts) {
|
|
8
|
-
const
|
|
9
|
-
const [versionOverrides, genericVersionOverrides] = partition(({ parentPkg }) => parentPkg != null, explicitOverrides.map((override) => ({
|
|
10
|
-
...override,
|
|
11
|
-
localTarget: createLocalTarget(override, rootDir),
|
|
12
|
-
})));
|
|
13
|
-
const convergeVersions = new Map(convergeOverrides.map((override) => [override.targetPkg.name, override.newBareSpecifier]));
|
|
27
|
+
const { versionOverrides, genericVersionOverrides, convergeVersions } = splitOverrides(overrides, rootDir);
|
|
14
28
|
return ((manifest, dir) => {
|
|
15
29
|
const versionOverridesWithParent = versionOverrides.filter(({ parentPkg }) => {
|
|
16
30
|
return (parentPkg.name === manifest.name &&
|
|
@@ -23,6 +37,18 @@ export function createVersionsOverrider(overrides, rootDir, opts) {
|
|
|
23
37
|
return manifest;
|
|
24
38
|
});
|
|
25
39
|
}
|
|
40
|
+
function splitOverrides(overrides, rootDir) {
|
|
41
|
+
const [convergeOverrides, explicitOverrides] = partition(({ converge }) => converge === true, overrides);
|
|
42
|
+
const [versionOverrides, genericVersionOverrides] = partition(({ parentPkg }) => parentPkg != null, explicitOverrides.map((override) => ({
|
|
43
|
+
...override,
|
|
44
|
+
localTarget: createLocalTarget(override, rootDir),
|
|
45
|
+
})));
|
|
46
|
+
return {
|
|
47
|
+
versionOverrides,
|
|
48
|
+
genericVersionOverrides,
|
|
49
|
+
convergeVersions: new Map(convergeOverrides.map((override) => [override.targetPkg.name, override.newBareSpecifier])),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
26
52
|
function createLocalTarget(override, rootDir) {
|
|
27
53
|
let protocol;
|
|
28
54
|
if (override.newBareSpecifier.startsWith('file:')) {
|
|
@@ -55,8 +81,7 @@ function overrideDepsOfPkg({ manifest, dir }, versionOverrides, genericVersionOv
|
|
|
55
81
|
}
|
|
56
82
|
function overrideDeps({ versionOverrides, genericVersionOverrides, dir, convergeOpts }, deps, peerDeps) {
|
|
57
83
|
for (const [name, bareSpecifier] of Object.entries(peerDeps ?? deps)) {
|
|
58
|
-
const versionOverride =
|
|
59
|
-
pickMostSpecificVersionOverride(genericVersionOverrides.filter(({ targetPkg }) => targetPkg.name === name && isIntersectingRange(targetPkg.bareSpecifier, bareSpecifier)));
|
|
84
|
+
const versionOverride = pickVersionOverride({ versionOverrides, genericVersionOverrides }, name, bareSpecifier);
|
|
60
85
|
if (!versionOverride) {
|
|
61
86
|
convergeDep(convergeOpts, { deps, peerDeps }, name, bareSpecifier);
|
|
62
87
|
continue;
|
|
@@ -70,9 +95,7 @@ function overrideDeps({ versionOverrides, genericVersionOverrides, dir, converge
|
|
|
70
95
|
}
|
|
71
96
|
continue;
|
|
72
97
|
}
|
|
73
|
-
const newBareSpecifier = versionOverride
|
|
74
|
-
? `${versionOverride.localTarget.protocol}${resolveLocalOverride(versionOverride.localTarget, dir)}`
|
|
75
|
-
: versionOverride.newBareSpecifier;
|
|
98
|
+
const newBareSpecifier = resolveOverriddenBareSpecifier(versionOverride, dir);
|
|
76
99
|
if (peerDeps == null || !isValidPeerRange(newBareSpecifier)) {
|
|
77
100
|
deps[versionOverride.targetPkg.name] = newBareSpecifier;
|
|
78
101
|
}
|
|
@@ -81,6 +104,30 @@ function overrideDeps({ versionOverrides, genericVersionOverrides, dir, converge
|
|
|
81
104
|
}
|
|
82
105
|
}
|
|
83
106
|
}
|
|
107
|
+
function convergeDep(convergeOpts, { deps, peerDeps }, name, bareSpecifier) {
|
|
108
|
+
recordConvergeDeclaredRange(convergeOpts, name, bareSpecifier);
|
|
109
|
+
const convergeVersion = convergeBareSpecifier(convergeOpts.convergeVersions, name, bareSpecifier);
|
|
110
|
+
if (convergeVersion == null)
|
|
111
|
+
return;
|
|
112
|
+
if (peerDeps == null) {
|
|
113
|
+
deps[name] = convergeVersion;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
peerDeps[name] = convergeVersion;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function recordConvergeDeclaredRange({ convergeVersions, convergeDeclaredRanges }, name, bareSpecifier) {
|
|
120
|
+
if (convergeDeclaredRanges == null)
|
|
121
|
+
return;
|
|
122
|
+
if (!convergeVersions.has(name) || semver.validRange(bareSpecifier, true) == null)
|
|
123
|
+
return;
|
|
124
|
+
let ranges = convergeDeclaredRanges.get(name);
|
|
125
|
+
if (ranges == null) {
|
|
126
|
+
ranges = new Set();
|
|
127
|
+
convergeDeclaredRanges.set(name, ranges);
|
|
128
|
+
}
|
|
129
|
+
ranges.add(bareSpecifier);
|
|
130
|
+
}
|
|
84
131
|
/**
|
|
85
132
|
* A convergence override (`"pkg@": "<version>"`) rewrites a dependency edge
|
|
86
133
|
* only when its version satisfies the edge's declared range, so incompatible
|
|
@@ -88,26 +135,21 @@ function overrideDeps({ versionOverrides, genericVersionOverrides, dir, converge
|
|
|
88
135
|
* `workspace:`, `catalog:`, `npm:`, git/URL, and dist-tag specifiers have no
|
|
89
136
|
* defined "satisfies" relation and are left untouched.
|
|
90
137
|
*/
|
|
91
|
-
function
|
|
138
|
+
function convergeBareSpecifier(convergeVersions, name, bareSpecifier) {
|
|
92
139
|
const convergeVersion = convergeVersions.get(name);
|
|
93
140
|
if (convergeVersion == null || semver.validRange(bareSpecifier, true) == null)
|
|
94
|
-
return;
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
deps[name] = convergeVersion;
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
peerDeps[name] = convergeVersion;
|
|
110
|
-
}
|
|
141
|
+
return undefined;
|
|
142
|
+
return semver.satisfies(convergeVersion, bareSpecifier, true) ? convergeVersion : undefined;
|
|
143
|
+
}
|
|
144
|
+
function pickVersionOverride({ versionOverrides, genericVersionOverrides }, name, bareSpecifier) {
|
|
145
|
+
const matches = (override) => override.targetPkg.name === name && isIntersectingRange(override.targetPkg.bareSpecifier, bareSpecifier);
|
|
146
|
+
return pickMostSpecificVersionOverride(versionOverrides.filter(matches)) ??
|
|
147
|
+
pickMostSpecificVersionOverride(genericVersionOverrides.filter(matches));
|
|
148
|
+
}
|
|
149
|
+
function resolveOverriddenBareSpecifier(versionOverride, dir) {
|
|
150
|
+
return versionOverride.localTarget
|
|
151
|
+
? `${versionOverride.localTarget.protocol}${resolveLocalOverride(versionOverride.localTarget, dir)}`
|
|
152
|
+
: versionOverride.newBareSpecifier;
|
|
111
153
|
}
|
|
112
154
|
function resolveLocalOverride({ specifiedViaRelativePath, absolutePath }, pkgDir) {
|
|
113
155
|
return specifiedViaRelativePath && pkgDir
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/hooks.read-package-hook",
|
|
3
|
-
"version": "1100.
|
|
3
|
+
"version": "1100.2.0",
|
|
4
4
|
"description": "Creates the default package reader hook used by pnpm",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -32,19 +32,19 @@
|
|
|
32
32
|
"@pnpm/deps.peer-range": "1100.1.1",
|
|
33
33
|
"@pnpm/error": "1100.1.0",
|
|
34
34
|
"@pnpm/resolving.parse-wanted-dependency": "1100.0.2",
|
|
35
|
-
"@pnpm/types": "1101.
|
|
35
|
+
"@pnpm/types": "1101.7.0",
|
|
36
36
|
"@yarnpkg/extensions": "2.0.6",
|
|
37
37
|
"normalize-path": "^3.0.0",
|
|
38
38
|
"ramda": "npm:@pnpm/ramda@0.28.1",
|
|
39
|
-
"semver": "^7.8.
|
|
39
|
+
"semver": "^7.8.5"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@jest/globals": "30.4.1",
|
|
43
|
-
"@pnpm/hooks.read-package-hook": "1100.
|
|
43
|
+
"@pnpm/hooks.read-package-hook": "1100.2.0",
|
|
44
44
|
"@types/normalize-path": "^3.0.2",
|
|
45
|
-
"@types/ramda": "0.
|
|
45
|
+
"@types/ramda": "0.32.0",
|
|
46
46
|
"@types/semver": "7.7.1",
|
|
47
|
-
"@yarnpkg/core": "4.
|
|
47
|
+
"@yarnpkg/core": "4.9.0"
|
|
48
48
|
},
|
|
49
49
|
"engines": {
|
|
50
50
|
"node": ">=22.13"
|