Skip to content

Commit 4b0c29a

Browse files
nlfwraithgar
authored andcommitted
deps: @npmcli/[email protected]
PR-URL: #4116 Credit: @nlf Close: #4116 Reviewed-by: @wraithgar
1 parent 4dbeb00 commit 4b0c29a

File tree

11 files changed

+258
-19
lines changed

11 files changed

+258
-19
lines changed

node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
379379
optional: false,
380380
global: this[_global],
381381
legacyPeerDeps: this.legacyPeerDeps,
382+
loadOverrides: true,
382383
})
383384
if (root.isLink) {
384385
root.target = new Node({
@@ -676,6 +677,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
676677
// calls rather than walking over everything in the tree.
677678
const set = this.idealTree.inventory
678679
.filter(n => this[_shouldUpdateNode](n))
680+
// XXX add any invalid edgesOut to the queue
679681
for (const node of set) {
680682
for (const edge of node.edgesIn) {
681683
this.addTracker('idealTree', edge.from.name, edge.from.location)
@@ -772,7 +774,10 @@ This is a one-time fix-up, please be patient...
772774
[_buildDeps] () {
773775
process.emit('time', 'idealTree:buildDeps')
774776
const tree = this.idealTree.target
777+
tree.assertRootOverrides()
775778
this[_depsQueue].push(tree)
779+
// XXX also push anything that depends on a node with a name
780+
// in the override list
776781
this.log.silly('idealTree', 'buildDeps')
777782
this.addTracker('idealTree', tree.name, '')
778783
return this[_buildDepStep]()
@@ -1112,6 +1117,7 @@ This is a one-time fix-up, please be patient...
11121117
path: node.realpath,
11131118
sourceReference: node,
11141119
legacyPeerDeps: this.legacyPeerDeps,
1120+
overrides: node.overrides,
11151121
})
11161122

11171123
// also need to set up any targets from any link deps, so that

node_modules/@npmcli/arborist/lib/arborist/load-actual.js

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ module.exports = cls => class ActualLoader extends cls {
127127
realpath: real,
128128
pkg: {},
129129
global,
130+
loadOverrides: true,
130131
})
131132
return this[_loadActualActually]({ root, ignoreMissing, global })
132133
}
@@ -135,8 +136,11 @@ module.exports = cls => class ActualLoader extends cls {
135136
this[_actualTree] = await this[_loadFSNode]({
136137
path: this.path,
137138
real: await realpath(this.path, this[_rpcache], this[_stcache]),
139+
loadOverrides: true,
138140
})
139141

142+
this[_actualTree].assertRootOverrides()
143+
140144
// Note: hidden lockfile will be rejected if it's not the latest thing
141145
// in the folder, or if any of the entries in the hidden lockfile are
142146
// missing.
@@ -236,13 +240,26 @@ module.exports = cls => class ActualLoader extends cls {
236240
this[_actualTree] = root
237241
}
238242

239-
[_loadFSNode] ({ path, parent, real, root }) {
243+
[_loadFSNode] ({ path, parent, real, root, loadOverrides }) {
240244
if (!real) {
241245
return realpath(path, this[_rpcache], this[_stcache])
242246
.then(
243-
real => this[_loadFSNode]({ path, parent, real, root }),
247+
real => this[_loadFSNode]({
248+
path,
249+
parent,
250+
real,
251+
root,
252+
loadOverrides,
253+
}),
244254
// if realpath fails, just provide a dummy error node
245-
error => new Node({ error, path, realpath: path, parent, root })
255+
error => new Node({
256+
error,
257+
path,
258+
realpath: path,
259+
parent,
260+
root,
261+
loadOverrides,
262+
})
246263
)
247264
}
248265

@@ -271,6 +288,7 @@ module.exports = cls => class ActualLoader extends cls {
271288
error,
272289
parent,
273290
root,
291+
loadOverrides,
274292
})
275293
})
276294
.then(node => {

node_modules/@npmcli/arborist/lib/arborist/load-virtual.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ module.exports = cls => class VirtualLoader extends cls {
7272
this[rootOptionProvided] = options.root
7373

7474
await this[loadFromShrinkwrap](s, root)
75+
root.assertRootOverrides()
7576
return treeCheck(this.virtualTree)
7677
}
7778

node_modules/@npmcli/arborist/lib/edge.js

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class ArboristEdge {}
2929
const printableEdge = (edge) => {
3030
const edgeFrom = edge.from && edge.from.location
3131
const edgeTo = edge.to && edge.to.location
32+
const override = edge.overrides && edge.overrides.value
3233

3334
return Object.assign(new ArboristEdge(), {
3435
name: edge.name,
@@ -38,12 +39,13 @@ const printableEdge = (edge) => {
3839
...(edgeTo ? { to: edgeTo } : {}),
3940
...(edge.error ? { error: edge.error } : {}),
4041
...(edge.peerConflicted ? { peerConflicted: true } : {}),
42+
...(override ? { overridden: override } : {}),
4143
})
4244
}
4345

4446
class Edge {
4547
constructor (options) {
46-
const { type, name, spec, accept, from } = options
48+
const { type, name, spec, accept, from, overrides } = options
4749

4850
if (typeof spec !== 'string') {
4951
throw new TypeError('must provide string spec')
@@ -55,6 +57,10 @@ class Edge {
5557

5658
this[_spec] = spec
5759

60+
if (overrides !== undefined) {
61+
this.overrides = overrides
62+
}
63+
5864
if (accept !== undefined) {
5965
if (typeof accept !== 'string') {
6066
throw new TypeError('accept field must be a string if provided')
@@ -82,8 +88,11 @@ class Edge {
8288
}
8389

8490
satisfiedBy (node) {
85-
return node.name === this.name &&
86-
depValid(node, this.spec, this.accept, this.from)
91+
if (node.name !== this.name) {
92+
return false
93+
}
94+
95+
return depValid(node, this.spec, this.accept, this.from)
8796
}
8897

8998
explain (seen = []) {
@@ -101,6 +110,10 @@ class Edge {
101110
type: this.type,
102111
name: this.name,
103112
spec: this.spec,
113+
...(this.rawSpec !== this.spec ? {
114+
rawSpec: this.rawSpec,
115+
overridden: true,
116+
} : {}),
104117
...(bundled ? { bundled } : {}),
105118
...(error ? { error } : {}),
106119
...(from ? { from: from.explain(null, seen) } : {}),
@@ -143,7 +156,28 @@ class Edge {
143156
return this[_name]
144157
}
145158

159+
get rawSpec () {
160+
return this[_spec]
161+
}
162+
146163
get spec () {
164+
if (this.overrides && this.overrides.value && this.overrides.name === this.name) {
165+
if (this.overrides.value.startsWith('$')) {
166+
const ref = this.overrides.value.slice(1)
167+
const pkg = this.from.root.package
168+
const overrideSpec = (pkg.devDependencies && pkg.devDependencies[ref]) ||
169+
(pkg.optionalDependencies && pkg.optionalDependencies[ref]) ||
170+
(pkg.dependencies && pkg.dependencies[ref]) ||
171+
(pkg.peerDependencies && pkg.peerDependencies[ref])
172+
173+
if (overrideSpec) {
174+
return overrideSpec
175+
}
176+
177+
throw new Error(`Unable to resolve reference ${this.overrides.value}`)
178+
}
179+
return this.overrides.value
180+
}
147181
return this[_spec]
148182
}
149183

@@ -213,6 +247,7 @@ class Edge {
213247
if (node.edgesOut.has(this.name)) {
214248
node.edgesOut.get(this.name).detach()
215249
}
250+
216251
node.addEdgeOut(this)
217252
this.reload()
218253
}

node_modules/@npmcli/arborist/lib/node.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const semver = require('semver')
3232
const nameFromFolder = require('@npmcli/name-from-folder')
3333
const Edge = require('./edge.js')
3434
const Inventory = require('./inventory.js')
35+
const OverrideSet = require('./override-set.js')
3536
const { normalize } = require('read-package-json-fast')
3637
const { getPaths: getBinPaths } = require('bin-links')
3738
const npa = require('npm-package-arg')
@@ -88,6 +89,8 @@ class Node {
8889
legacyPeerDeps = false,
8990
linksIn,
9091
hasShrinkwrap,
92+
overrides,
93+
loadOverrides = false,
9194
extraneous = true,
9295
dev = true,
9396
optional = true,
@@ -190,6 +193,17 @@ class Node {
190193
// because this.package is read when adding to inventory
191194
this[_package] = pkg && typeof pkg === 'object' ? pkg : {}
192195

196+
if (overrides) {
197+
this.overrides = overrides
198+
} else if (loadOverrides) {
199+
const overrides = this[_package].overrides || {}
200+
if (Object.keys(overrides).length > 0) {
201+
this.overrides = new OverrideSet({
202+
overrides: this[_package].overrides,
203+
})
204+
}
205+
}
206+
193207
// only relevant for the root and top nodes
194208
this.meta = meta
195209

@@ -963,6 +977,11 @@ class Node {
963977
return false
964978
}
965979

980+
// XXX need to check for two root nodes?
981+
if (node.overrides !== this.overrides) {
982+
return false
983+
}
984+
966985
ignorePeers = new Set(ignorePeers)
967986

968987
// gather up all the deps of this node and that are only depended
@@ -1208,6 +1227,10 @@ class Node {
12081227
this[_changePath](newPath)
12091228
}
12101229

1230+
if (parent.overrides) {
1231+
this.overrides = parent.overrides.getNodeRule(this)
1232+
}
1233+
12111234
// clobbers anything at that path, resets all appropriate references
12121235
this.root = parent.root
12131236
}
@@ -1279,11 +1302,33 @@ class Node {
12791302
}
12801303
}
12811304

1305+
assertRootOverrides () {
1306+
if (!this.isProjectRoot || !this.overrides) {
1307+
return
1308+
}
1309+
1310+
for (const edge of this.edgesOut.values()) {
1311+
// if these differ an override has been applied, those are not allowed
1312+
// for top level dependencies so throw an error
1313+
if (edge.spec !== edge.rawSpec && !edge.spec.startsWith('$')) {
1314+
throw Object.assign(new Error(`Override for ${edge.name}@${edge.rawSpec} conflicts with direct dependency`), { code: 'EOVERRIDE' })
1315+
}
1316+
}
1317+
}
1318+
12821319
addEdgeOut (edge) {
1320+
if (this.overrides) {
1321+
edge.overrides = this.overrides.getEdgeRule(edge)
1322+
}
1323+
12831324
this.edgesOut.set(edge.name, edge)
12841325
}
12851326

12861327
addEdgeIn (edge) {
1328+
if (edge.overrides) {
1329+
this.overrides = edge.overrides
1330+
}
1331+
12871332
this.edgesIn.add(edge)
12881333

12891334
// try to get metadata from the yarn.lock file

0 commit comments

Comments
 (0)