@npmcli/arborist 2.8.2 → 2.8.3
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/bin/actual.js +4 -2
- package/bin/audit.js +12 -6
- package/bin/dedupe.js +6 -3
- package/bin/funding.js +4 -2
- package/bin/ideal.js +2 -1
- package/bin/lib/logging.js +4 -3
- package/bin/lib/options.js +14 -12
- package/bin/lib/timers.js +6 -3
- package/bin/license.js +9 -5
- package/bin/prune.js +6 -3
- package/bin/reify.js +6 -3
- package/bin/virtual.js +4 -2
- package/lib/add-rm-pkg-deps.js +25 -14
- package/lib/arborist/audit.js +2 -1
- package/lib/arborist/build-ideal-tree.js +129 -68
- package/lib/arborist/deduper.js +2 -1
- package/lib/arborist/index.js +8 -4
- package/lib/arborist/load-actual.js +28 -13
- package/lib/arborist/load-virtual.js +34 -18
- package/lib/arborist/load-workspaces.js +4 -2
- package/lib/arborist/rebuild.js +31 -16
- package/lib/arborist/reify.js +153 -76
- package/lib/audit-report.js +42 -22
- package/lib/calc-dep-flags.js +18 -9
- package/lib/can-place-dep.js +56 -28
- package/lib/case-insensitive-map.js +4 -2
- package/lib/consistent-resolve.js +2 -1
- package/lib/deepest-nesting-target.js +4 -2
- package/lib/dep-valid.js +8 -4
- package/lib/diff.js +74 -22
- package/lib/edge.js +26 -13
- package/lib/gather-dep-set.js +2 -1
- package/lib/inventory.js +12 -6
- package/lib/link.js +14 -9
- package/lib/node.js +216 -113
- package/lib/optional-set.js +4 -2
- package/lib/peer-entry-sets.js +10 -5
- package/lib/place-dep.js +56 -29
- package/lib/printable.js +41 -21
- package/lib/realpath.js +12 -6
- package/lib/shrinkwrap.js +162 -89
- package/lib/signal-handling.js +6 -3
- package/lib/spec-from-lock.js +7 -4
- package/lib/tracker.js +24 -18
- package/lib/tree-check.js +12 -6
- package/lib/version-from-tgz.js +4 -2
- package/lib/vuln.js +28 -16
- package/lib/yarn-lock.js +27 -15
- package/package.json +7 -10
package/lib/audit-report.js
CHANGED
|
@@ -63,8 +63,9 @@ class AuditReport extends Map {
|
|
|
63
63
|
prod = false
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
if (prod)
|
|
66
|
+
if (prod) {
|
|
67
67
|
dependencies.prod++
|
|
68
|
+
}
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
// if it doesn't have any topVulns, then it's fixable with audit fix
|
|
@@ -104,8 +105,9 @@ class AuditReport extends Map {
|
|
|
104
105
|
async run () {
|
|
105
106
|
this.report = await this[_getReport]()
|
|
106
107
|
this.log.silly('audit report', this.report)
|
|
107
|
-
if (this.report)
|
|
108
|
+
if (this.report) {
|
|
108
109
|
await this[_init]()
|
|
110
|
+
}
|
|
109
111
|
return this
|
|
110
112
|
}
|
|
111
113
|
|
|
@@ -119,8 +121,9 @@ class AuditReport extends Map {
|
|
|
119
121
|
|
|
120
122
|
const promises = []
|
|
121
123
|
for (const [name, advisories] of Object.entries(this.report)) {
|
|
122
|
-
for (const advisory of advisories)
|
|
124
|
+
for (const advisory of advisories) {
|
|
123
125
|
promises.push(this.calculator.calculate(name, advisory))
|
|
126
|
+
}
|
|
124
127
|
}
|
|
125
128
|
|
|
126
129
|
// now the advisories are calculated with a set of versions
|
|
@@ -136,43 +139,51 @@ class AuditReport extends Map {
|
|
|
136
139
|
// adding multiple advisories with the same range is fine, but no
|
|
137
140
|
// need to search for nodes we already would have added.
|
|
138
141
|
const k = `${name}@${range}`
|
|
139
|
-
if (seen.has(k))
|
|
142
|
+
if (seen.has(k)) {
|
|
140
143
|
continue
|
|
144
|
+
}
|
|
141
145
|
|
|
142
146
|
seen.add(k)
|
|
143
147
|
|
|
144
148
|
const vuln = this.get(name) || new Vuln({ name, advisory })
|
|
145
|
-
if (this.has(name))
|
|
149
|
+
if (this.has(name)) {
|
|
146
150
|
vuln.addAdvisory(advisory)
|
|
151
|
+
}
|
|
147
152
|
super.set(name, vuln)
|
|
148
153
|
|
|
149
154
|
const p = []
|
|
150
155
|
for (const node of this.tree.inventory.query('packageName', name)) {
|
|
151
|
-
if (!shouldAudit(node, this[_omit], this.filterSet))
|
|
156
|
+
if (!shouldAudit(node, this[_omit], this.filterSet)) {
|
|
152
157
|
continue
|
|
158
|
+
}
|
|
153
159
|
|
|
154
160
|
// if not vulnerable by this advisory, keep searching
|
|
155
|
-
if (!advisory.testVersion(node.version))
|
|
161
|
+
if (!advisory.testVersion(node.version)) {
|
|
156
162
|
continue
|
|
163
|
+
}
|
|
157
164
|
|
|
158
165
|
// we will have loaded the source already if this is a metavuln
|
|
159
|
-
if (advisory.type === 'metavuln')
|
|
166
|
+
if (advisory.type === 'metavuln') {
|
|
160
167
|
vuln.addVia(this.get(advisory.dependency))
|
|
168
|
+
}
|
|
161
169
|
|
|
162
170
|
// already marked this one, no need to do it again
|
|
163
|
-
if (vuln.nodes.has(node))
|
|
171
|
+
if (vuln.nodes.has(node)) {
|
|
164
172
|
continue
|
|
173
|
+
}
|
|
165
174
|
|
|
166
175
|
// haven't marked this one yet. get its dependents.
|
|
167
176
|
vuln.nodes.add(node)
|
|
168
177
|
for (const { from: dep, spec } of node.edgesIn) {
|
|
169
|
-
if (dep.isTop && !vuln.topNodes.has(dep))
|
|
178
|
+
if (dep.isTop && !vuln.topNodes.has(dep)) {
|
|
170
179
|
this[_checkTopNode](dep, vuln, spec)
|
|
171
|
-
else {
|
|
180
|
+
} else {
|
|
172
181
|
// calculate a metavuln, if necessary
|
|
173
|
-
|
|
174
|
-
|
|
182
|
+
const calc = this.calculator.calculate(dep.packageName, advisory)
|
|
183
|
+
p.push(calc.then(meta => {
|
|
184
|
+
if (meta.testVersion(dep.version, spec)) {
|
|
175
185
|
advisories.add(meta)
|
|
186
|
+
}
|
|
176
187
|
}))
|
|
177
188
|
}
|
|
178
189
|
}
|
|
@@ -193,9 +204,11 @@ class AuditReport extends Map {
|
|
|
193
204
|
// the nodes it references, then remove it from the advisory list.
|
|
194
205
|
// happens when using omit with old audit endpoint.
|
|
195
206
|
for (const advisory of vuln.advisories) {
|
|
196
|
-
const relevant = [...vuln.nodes]
|
|
197
|
-
|
|
207
|
+
const relevant = [...vuln.nodes]
|
|
208
|
+
.some(n => advisory.testVersion(n.version))
|
|
209
|
+
if (!relevant) {
|
|
198
210
|
vuln.deleteAdvisory(advisory)
|
|
211
|
+
}
|
|
199
212
|
}
|
|
200
213
|
}
|
|
201
214
|
process.emit('timeEnd', 'auditReport:init')
|
|
@@ -221,18 +234,21 @@ class AuditReport extends Map {
|
|
|
221
234
|
// this will always be set to at least {name, versions:{}}
|
|
222
235
|
const paku = vuln.packument
|
|
223
236
|
|
|
224
|
-
if (!vuln.testSpec(spec))
|
|
237
|
+
if (!vuln.testSpec(spec)) {
|
|
225
238
|
return true
|
|
239
|
+
}
|
|
226
240
|
|
|
227
241
|
// similarly, even if we HAVE a packument, but we're looking for it
|
|
228
242
|
// somewhere other than the registry, and we got something vulnerable,
|
|
229
243
|
// then we're stuck with it.
|
|
230
244
|
const specObj = npa(spec)
|
|
231
|
-
if (!specObj.registry)
|
|
245
|
+
if (!specObj.registry) {
|
|
232
246
|
return false
|
|
247
|
+
}
|
|
233
248
|
|
|
234
|
-
if (specObj.subSpec)
|
|
249
|
+
if (specObj.subSpec) {
|
|
235
250
|
spec = specObj.subSpec.rawSpec
|
|
251
|
+
}
|
|
236
252
|
|
|
237
253
|
// We don't provide fixes for top nodes other than root, but we
|
|
238
254
|
// still check to see if the node is fixable with a different version,
|
|
@@ -287,8 +303,9 @@ class AuditReport extends Map {
|
|
|
287
303
|
|
|
288
304
|
async [_getReport] () {
|
|
289
305
|
// if we're not auditing, just return false
|
|
290
|
-
if (this.options.audit === false || this.tree.inventory.size === 1)
|
|
306
|
+
if (this.options.audit === false || this.tree.inventory.size === 1) {
|
|
291
307
|
return null
|
|
308
|
+
}
|
|
292
309
|
|
|
293
310
|
process.emit('time', 'auditReport:getReport')
|
|
294
311
|
try {
|
|
@@ -299,8 +316,9 @@ class AuditReport extends Map {
|
|
|
299
316
|
|
|
300
317
|
// no sense asking if we don't have anything to audit,
|
|
301
318
|
// we know it'll be empty
|
|
302
|
-
if (!Object.keys(body).length)
|
|
319
|
+
if (!Object.keys(body).length) {
|
|
303
320
|
return null
|
|
321
|
+
}
|
|
304
322
|
|
|
305
323
|
const res = await fetch('/-/npm/v1/security/advisories/bulk', {
|
|
306
324
|
...this.options,
|
|
@@ -353,13 +371,15 @@ const prepareBulkData = (tree, omit, filterSet) => {
|
|
|
353
371
|
for (const name of tree.inventory.query('packageName')) {
|
|
354
372
|
const set = new Set()
|
|
355
373
|
for (const node of tree.inventory.query('packageName', name)) {
|
|
356
|
-
if (!shouldAudit(node, omit, filterSet))
|
|
374
|
+
if (!shouldAudit(node, omit, filterSet)) {
|
|
357
375
|
continue
|
|
376
|
+
}
|
|
358
377
|
|
|
359
378
|
set.add(node.version)
|
|
360
379
|
}
|
|
361
|
-
if (set.size)
|
|
380
|
+
if (set.size) {
|
|
362
381
|
payload[name] = [...set]
|
|
382
|
+
}
|
|
363
383
|
}
|
|
364
384
|
return payload
|
|
365
385
|
}
|
package/lib/calc-dep-flags.js
CHANGED
|
@@ -11,7 +11,8 @@ const calcDepFlags = (tree, resetRoot = true) => {
|
|
|
11
11
|
tree,
|
|
12
12
|
visit: node => calcDepFlagsStep(node),
|
|
13
13
|
filter: node => node,
|
|
14
|
-
getChildren: (node, tree) =>
|
|
14
|
+
getChildren: (node, tree) =>
|
|
15
|
+
[...tree.edgesOut.values()].map(edge => edge.to),
|
|
15
16
|
})
|
|
16
17
|
return ret
|
|
17
18
|
}
|
|
@@ -39,8 +40,9 @@ const calcDepFlagsStep = (node) => {
|
|
|
39
40
|
|
|
40
41
|
node.edgesOut.forEach(({peer, optional, dev, to}) => {
|
|
41
42
|
// if the dep is missing, then its flags are already maximally unset
|
|
42
|
-
if (!to)
|
|
43
|
+
if (!to) {
|
|
43
44
|
return
|
|
45
|
+
}
|
|
44
46
|
|
|
45
47
|
// everything with any kind of edge into it is not extraneous
|
|
46
48
|
to.extraneous = false
|
|
@@ -59,28 +61,34 @@ const calcDepFlagsStep = (node) => {
|
|
|
59
61
|
!node.optional && !optional
|
|
60
62
|
const unsetPeer = !node.peer && !peer
|
|
61
63
|
|
|
62
|
-
if (unsetPeer)
|
|
64
|
+
if (unsetPeer) {
|
|
63
65
|
unsetFlag(to, 'peer')
|
|
66
|
+
}
|
|
64
67
|
|
|
65
|
-
if (unsetDevOpt)
|
|
68
|
+
if (unsetDevOpt) {
|
|
66
69
|
unsetFlag(to, 'devOptional')
|
|
70
|
+
}
|
|
67
71
|
|
|
68
|
-
if (unsetDev)
|
|
72
|
+
if (unsetDev) {
|
|
69
73
|
unsetFlag(to, 'dev')
|
|
74
|
+
}
|
|
70
75
|
|
|
71
|
-
if (unsetOpt)
|
|
76
|
+
if (unsetOpt) {
|
|
72
77
|
unsetFlag(to, 'optional')
|
|
78
|
+
}
|
|
73
79
|
})
|
|
74
80
|
|
|
75
81
|
return node
|
|
76
82
|
}
|
|
77
83
|
|
|
78
84
|
const resetParents = (node, flag) => {
|
|
79
|
-
if (node[flag])
|
|
85
|
+
if (node[flag]) {
|
|
80
86
|
return
|
|
87
|
+
}
|
|
81
88
|
|
|
82
|
-
for (let p = node; p && (p === node || p[flag]); p = p.resolveParent)
|
|
89
|
+
for (let p = node; p && (p === node || p[flag]); p = p.resolveParent) {
|
|
83
90
|
p[flag] = false
|
|
91
|
+
}
|
|
84
92
|
}
|
|
85
93
|
|
|
86
94
|
// typically a short walk, since it only traverses deps that
|
|
@@ -92,8 +100,9 @@ const unsetFlag = (node, flag) => {
|
|
|
92
100
|
tree: node,
|
|
93
101
|
visit: node => {
|
|
94
102
|
node.extraneous = node[flag] = false
|
|
95
|
-
if (node.isLink)
|
|
103
|
+
if (node.isLink) {
|
|
96
104
|
node.target.extraneous = node.target[flag] = false
|
|
105
|
+
}
|
|
97
106
|
},
|
|
98
107
|
getChildren: node => [...node.target.edgesOut.values()]
|
|
99
108
|
.filter(edge => edge.to && edge.to[flag] &&
|
package/lib/can-place-dep.js
CHANGED
|
@@ -64,14 +64,17 @@ class CanPlaceDep {
|
|
|
64
64
|
} = options
|
|
65
65
|
|
|
66
66
|
debug(() => {
|
|
67
|
-
if (!dep)
|
|
67
|
+
if (!dep) {
|
|
68
68
|
throw new Error('no dep provided to CanPlaceDep')
|
|
69
|
+
}
|
|
69
70
|
|
|
70
|
-
if (!target)
|
|
71
|
+
if (!target) {
|
|
71
72
|
throw new Error('no target provided to CanPlaceDep')
|
|
73
|
+
}
|
|
72
74
|
|
|
73
|
-
if (!edge)
|
|
75
|
+
if (!edge) {
|
|
74
76
|
throw new Error('no edge provided to CanPlaceDep')
|
|
77
|
+
}
|
|
75
78
|
|
|
76
79
|
this._treeSnapshot = JSON.stringify([...target.root.inventory.entries()]
|
|
77
80
|
.map(([loc, {packageName, version, resolved}]) => {
|
|
@@ -108,8 +111,9 @@ class CanPlaceDep {
|
|
|
108
111
|
this.edgeOverride = !dep.satisfies(edge)
|
|
109
112
|
|
|
110
113
|
this.canPlace = this.checkCanPlace()
|
|
111
|
-
if (!this.canPlaceSelf)
|
|
114
|
+
if (!this.canPlaceSelf) {
|
|
112
115
|
this.canPlaceSelf = this.canPlace
|
|
116
|
+
}
|
|
113
117
|
|
|
114
118
|
debug(() => {
|
|
115
119
|
const treeSnapshot = JSON.stringify([...target.root.inventory.entries()]
|
|
@@ -131,15 +135,18 @@ class CanPlaceDep {
|
|
|
131
135
|
|
|
132
136
|
// if the dep failed to load, we're going to fail the build or
|
|
133
137
|
// prune it out anyway, so just move forward placing/replacing it.
|
|
134
|
-
if (dep.errors.length)
|
|
138
|
+
if (dep.errors.length) {
|
|
135
139
|
return current ? REPLACE : OK
|
|
140
|
+
}
|
|
136
141
|
|
|
137
142
|
// cannot place peers inside their dependents, except for tops
|
|
138
|
-
if (targetEdge && targetEdge.peer && !target.isTop)
|
|
143
|
+
if (targetEdge && targetEdge.peer && !target.isTop) {
|
|
139
144
|
return CONFLICT
|
|
145
|
+
}
|
|
140
146
|
|
|
141
|
-
if (targetEdge && !dep.satisfies(targetEdge) && targetEdge !== this.edge)
|
|
147
|
+
if (targetEdge && !dep.satisfies(targetEdge) && targetEdge !== this.edge) {
|
|
142
148
|
return CONFLICT
|
|
149
|
+
}
|
|
143
150
|
|
|
144
151
|
return current ? this.checkCanPlaceCurrent() : this.checkCanPlaceNoCurrent()
|
|
145
152
|
}
|
|
@@ -150,8 +157,9 @@ class CanPlaceDep {
|
|
|
150
157
|
const { preferDedupe, explicitRequest, current, target, edge, dep } = this
|
|
151
158
|
|
|
152
159
|
if (dep.matches(current)) {
|
|
153
|
-
if (current.satisfies(edge) || this.edgeOverride)
|
|
160
|
+
if (current.satisfies(edge) || this.edgeOverride) {
|
|
154
161
|
return explicitRequest ? REPLACE : KEEP
|
|
162
|
+
}
|
|
155
163
|
}
|
|
156
164
|
|
|
157
165
|
const { version: curVer } = current
|
|
@@ -163,19 +171,22 @@ class CanPlaceDep {
|
|
|
163
171
|
* but it is theoretically possible if peer deps are pinned. In
|
|
164
172
|
* that case we treat it like any other conflict, and keep trying */
|
|
165
173
|
const cpp = this.canPlacePeers(REPLACE)
|
|
166
|
-
if (cpp !== CONFLICT)
|
|
174
|
+
if (cpp !== CONFLICT) {
|
|
167
175
|
return cpp
|
|
176
|
+
}
|
|
168
177
|
}
|
|
169
178
|
|
|
170
179
|
// ok, can't replace the current with new one, but maybe current is ok?
|
|
171
|
-
if (current.satisfies(edge) && (!explicitRequest || preferDedupe))
|
|
180
|
+
if (current.satisfies(edge) && (!explicitRequest || preferDedupe)) {
|
|
172
181
|
return KEEP
|
|
182
|
+
}
|
|
173
183
|
|
|
174
184
|
// if we prefer deduping, then try replacing newer with older
|
|
175
185
|
if (preferDedupe && !tryReplace && dep.canReplace(current)) {
|
|
176
186
|
const cpp = this.canPlacePeers(REPLACE)
|
|
177
|
-
if (cpp !== CONFLICT)
|
|
187
|
+
if (cpp !== CONFLICT) {
|
|
178
188
|
return cpp
|
|
189
|
+
}
|
|
179
190
|
}
|
|
180
191
|
|
|
181
192
|
// Check for interesting cases!
|
|
@@ -185,29 +196,33 @@ class CanPlaceDep {
|
|
|
185
196
|
const myDeepest = this.deepestNestingTarget
|
|
186
197
|
|
|
187
198
|
// ok, i COULD be placed deeper, so leave the current one alone.
|
|
188
|
-
if (target !== myDeepest)
|
|
199
|
+
if (target !== myDeepest) {
|
|
189
200
|
return CONFLICT
|
|
201
|
+
}
|
|
190
202
|
|
|
191
203
|
// if we are not checking a peerDep, then we MUST place it here, in the
|
|
192
204
|
// target that has a non-peer dep on it.
|
|
193
|
-
if (!edge.peer && target === edge.from)
|
|
205
|
+
if (!edge.peer && target === edge.from) {
|
|
194
206
|
return this.canPlacePeers(REPLACE)
|
|
207
|
+
}
|
|
195
208
|
|
|
196
209
|
// if we aren't placing a peer in a set, then we're done here.
|
|
197
210
|
// This is ignored because it SHOULD be redundant, as far as I can tell,
|
|
198
211
|
// with the deepest target and target===edge.from tests. But until we
|
|
199
212
|
// can prove that isn't possible, this condition is here for safety.
|
|
200
213
|
/* istanbul ignore if - allegedly impossible */
|
|
201
|
-
if (!this.parent && !edge.peer)
|
|
214
|
+
if (!this.parent && !edge.peer) {
|
|
202
215
|
return CONFLICT
|
|
216
|
+
}
|
|
203
217
|
|
|
204
218
|
// check the deps in the peer group for each edge into that peer group
|
|
205
219
|
// if ALL of them can be pushed deeper, or if it's ok to replace its
|
|
206
220
|
// members with the contents of the new peer group, then we're good.
|
|
207
221
|
let canReplace = true
|
|
208
222
|
for (const [entryEdge, currentPeers] of peerEntrySets(current)) {
|
|
209
|
-
if (entryEdge === this.edge || entryEdge === this.peerEntryEdge)
|
|
223
|
+
if (entryEdge === this.edge || entryEdge === this.peerEntryEdge) {
|
|
210
224
|
continue
|
|
225
|
+
}
|
|
211
226
|
|
|
212
227
|
// First, see if it's ok to just replace the peerSet entirely.
|
|
213
228
|
// we do this by walking out from the entryEdge, because in a case like
|
|
@@ -231,8 +246,9 @@ class CanPlaceDep {
|
|
|
231
246
|
const entryNode = entryEdge.to
|
|
232
247
|
const entryRep = dep.parent.children.get(entryNode.name)
|
|
233
248
|
if (entryRep) {
|
|
234
|
-
if (entryRep.canReplace(entryNode, dep.parent.children.keys()))
|
|
249
|
+
if (entryRep.canReplace(entryNode, dep.parent.children.keys())) {
|
|
235
250
|
continue
|
|
251
|
+
}
|
|
236
252
|
}
|
|
237
253
|
|
|
238
254
|
let canClobber = !entryRep
|
|
@@ -240,12 +256,14 @@ class CanPlaceDep {
|
|
|
240
256
|
const peerReplacementWalk = new Set([entryNode])
|
|
241
257
|
OUTER: for (const currentPeer of peerReplacementWalk) {
|
|
242
258
|
for (const edge of currentPeer.edgesOut.values()) {
|
|
243
|
-
if (!edge.peer || !edge.valid)
|
|
259
|
+
if (!edge.peer || !edge.valid) {
|
|
244
260
|
continue
|
|
261
|
+
}
|
|
245
262
|
const rep = dep.parent.children.get(edge.name)
|
|
246
263
|
if (!rep) {
|
|
247
|
-
if (edge.to)
|
|
264
|
+
if (edge.to) {
|
|
248
265
|
peerReplacementWalk.add(edge.to)
|
|
266
|
+
}
|
|
249
267
|
continue
|
|
250
268
|
}
|
|
251
269
|
if (!rep.satisfies(edge)) {
|
|
@@ -255,14 +273,16 @@ class CanPlaceDep {
|
|
|
255
273
|
}
|
|
256
274
|
}
|
|
257
275
|
}
|
|
258
|
-
if (canClobber)
|
|
276
|
+
if (canClobber) {
|
|
259
277
|
continue
|
|
278
|
+
}
|
|
260
279
|
|
|
261
280
|
// ok, we can't replace, but maybe we can nest the current set deeper?
|
|
262
281
|
let canNestCurrent = true
|
|
263
282
|
for (const currentPeer of currentPeers) {
|
|
264
|
-
if (!canNestCurrent)
|
|
283
|
+
if (!canNestCurrent) {
|
|
265
284
|
break
|
|
285
|
+
}
|
|
266
286
|
|
|
267
287
|
// still possible to nest this peerSet
|
|
268
288
|
const curDeep = deepestNestingTarget(entryEdge.from, currentPeer.name)
|
|
@@ -270,14 +290,16 @@ class CanPlaceDep {
|
|
|
270
290
|
canNestCurrent = false
|
|
271
291
|
canReplace = false
|
|
272
292
|
}
|
|
273
|
-
if (canNestCurrent)
|
|
293
|
+
if (canNestCurrent) {
|
|
274
294
|
continue
|
|
295
|
+
}
|
|
275
296
|
}
|
|
276
297
|
}
|
|
277
298
|
|
|
278
299
|
// if we can nest or replace all the current peer groups, we can replace.
|
|
279
|
-
if (canReplace)
|
|
300
|
+
if (canReplace) {
|
|
280
301
|
return this.canPlacePeers(REPLACE)
|
|
302
|
+
}
|
|
281
303
|
|
|
282
304
|
return CONFLICT
|
|
283
305
|
}
|
|
@@ -293,8 +315,9 @@ class CanPlaceDep {
|
|
|
293
315
|
if (current) {
|
|
294
316
|
for (const edge of current.edgesIn.values()) {
|
|
295
317
|
if (edge.from.isDescendantOf(target) && edge.valid) {
|
|
296
|
-
if (!dep.satisfies(edge))
|
|
318
|
+
if (!dep.satisfies(edge)) {
|
|
297
319
|
return CONFLICT
|
|
320
|
+
}
|
|
298
321
|
}
|
|
299
322
|
}
|
|
300
323
|
}
|
|
@@ -316,8 +339,9 @@ class CanPlaceDep {
|
|
|
316
339
|
get allChildren () {
|
|
317
340
|
const set = new Set(this.children)
|
|
318
341
|
for (const child of set) {
|
|
319
|
-
for (const grandchild of child.children)
|
|
342
|
+
for (const grandchild of child.children) {
|
|
320
343
|
set.add(grandchild)
|
|
344
|
+
}
|
|
321
345
|
}
|
|
322
346
|
return [...set]
|
|
323
347
|
}
|
|
@@ -329,15 +353,17 @@ class CanPlaceDep {
|
|
|
329
353
|
// check if peers can go here. returns state or CONFLICT
|
|
330
354
|
canPlacePeers (state) {
|
|
331
355
|
this.canPlaceSelf = state
|
|
332
|
-
if (this._canPlacePeers)
|
|
356
|
+
if (this._canPlacePeers) {
|
|
333
357
|
return this._canPlacePeers
|
|
358
|
+
}
|
|
334
359
|
|
|
335
360
|
// TODO: represent peerPath in ERESOLVE error somehow?
|
|
336
361
|
const peerPath = [...this.peerPath, this.dep]
|
|
337
362
|
let sawConflict = false
|
|
338
363
|
for (const peerEdge of this.dep.edgesOut.values()) {
|
|
339
|
-
if (!peerEdge.peer || !peerEdge.to || peerPath.includes(peerEdge.to))
|
|
364
|
+
if (!peerEdge.peer || !peerEdge.to || peerPath.includes(peerEdge.to)) {
|
|
340
365
|
continue
|
|
366
|
+
}
|
|
341
367
|
const peer = peerEdge.to
|
|
342
368
|
// it may be the case that the *initial* dep can be nested, but a peer
|
|
343
369
|
// of that dep needs to be placed shallower, because the target has
|
|
@@ -354,13 +380,15 @@ class CanPlaceDep {
|
|
|
354
380
|
})
|
|
355
381
|
/* istanbul ignore next */
|
|
356
382
|
debug(() => {
|
|
357
|
-
if (this.children.some(c => c.dep === cpp.dep))
|
|
383
|
+
if (this.children.some(c => c.dep === cpp.dep)) {
|
|
358
384
|
throw new Error('checking same dep repeatedly')
|
|
385
|
+
}
|
|
359
386
|
})
|
|
360
387
|
this.children.push(cpp)
|
|
361
388
|
|
|
362
|
-
if (cpp.canPlace === CONFLICT)
|
|
389
|
+
if (cpp.canPlace === CONFLICT) {
|
|
363
390
|
sawConflict = true
|
|
391
|
+
}
|
|
364
392
|
}
|
|
365
393
|
|
|
366
394
|
this._canPlacePeers = sawConflict ? CONFLICT : state
|
|
@@ -10,8 +10,9 @@ module.exports = class Map extends OGMap {
|
|
|
10
10
|
constructor (items = []) {
|
|
11
11
|
super()
|
|
12
12
|
this[_keys] = new OGMap()
|
|
13
|
-
for (const [key, val] of items)
|
|
13
|
+
for (const [key, val] of items) {
|
|
14
14
|
this.set(key, val)
|
|
15
|
+
}
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
[_normKey] (key) {
|
|
@@ -26,8 +27,9 @@ module.exports = class Map extends OGMap {
|
|
|
26
27
|
|
|
27
28
|
set (key, val) {
|
|
28
29
|
const normKey = this[_normKey](key)
|
|
29
|
-
if (this[_keys].has(normKey))
|
|
30
|
+
if (this[_keys].has(normKey)) {
|
|
30
31
|
super.delete(this[_keys].get(normKey))
|
|
32
|
+
}
|
|
31
33
|
this[_keys].set(normKey, key)
|
|
32
34
|
return super.set(key, val)
|
|
33
35
|
}
|
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
const npa = require('npm-package-arg')
|
|
6
6
|
const relpath = require('./relpath.js')
|
|
7
7
|
const consistentResolve = (resolved, fromPath, toPath, relPaths = false) => {
|
|
8
|
-
if (!resolved)
|
|
8
|
+
if (!resolved) {
|
|
9
9
|
return null
|
|
10
|
+
}
|
|
10
11
|
|
|
11
12
|
try {
|
|
12
13
|
const hostedOpt = { noCommittish: false }
|
|
@@ -5,11 +5,13 @@
|
|
|
5
5
|
const deepestNestingTarget = (start, name) => {
|
|
6
6
|
for (const target of start.ancestry()) {
|
|
7
7
|
// note: this will skip past the first target if edge is peer
|
|
8
|
-
if (target.isProjectRoot || !target.resolveParent || target.globalTop)
|
|
8
|
+
if (target.isProjectRoot || !target.resolveParent || target.globalTop) {
|
|
9
9
|
return target
|
|
10
|
+
}
|
|
10
11
|
const targetEdge = target.edgesOut.get(name)
|
|
11
|
-
if (!targetEdge || !targetEdge.peer)
|
|
12
|
+
if (!targetEdge || !targetEdge.peer) {
|
|
12
13
|
return target
|
|
14
|
+
}
|
|
13
15
|
}
|
|
14
16
|
}
|
|
15
17
|
|
package/lib/dep-valid.js
CHANGED
|
@@ -44,8 +44,9 @@ const depValid = (child, requested, requestor) => {
|
|
|
44
44
|
|
|
45
45
|
switch (requested.type) {
|
|
46
46
|
case 'range':
|
|
47
|
-
if (requested.fetchSpec === '*')
|
|
47
|
+
if (requested.fetchSpec === '*') {
|
|
48
48
|
return true
|
|
49
|
+
}
|
|
49
50
|
// fallthrough
|
|
50
51
|
case 'version':
|
|
51
52
|
// if it's a version or a range other than '*', semver it
|
|
@@ -108,17 +109,20 @@ const depValid = (child, requested, requestor) => {
|
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
const tarballValid = (child, requested, requestor) => {
|
|
111
|
-
if (child.isLink)
|
|
112
|
+
if (child.isLink) {
|
|
112
113
|
return false
|
|
114
|
+
}
|
|
113
115
|
|
|
114
|
-
if (child.resolved)
|
|
116
|
+
if (child.resolved) {
|
|
115
117
|
return child.resolved.replace(/\\/g, '/') === `file:${requested.fetchSpec.replace(/\\/g, '/')}`
|
|
118
|
+
}
|
|
116
119
|
|
|
117
120
|
// if we have a legacy mutated package.json file. we can't be 100%
|
|
118
121
|
// sure that it resolved to the same file, but if it was the same
|
|
119
122
|
// request, that's a pretty good indicator of sameness.
|
|
120
|
-
if (child.package._requested)
|
|
123
|
+
if (child.package._requested) {
|
|
121
124
|
return child.package._requested.saveSpec === requested.saveSpec
|
|
125
|
+
}
|
|
122
126
|
|
|
123
127
|
// ok, we're probably dealing with some legacy cruft here, not much
|
|
124
128
|
// we can do at this point unfortunately.
|