@npmcli/arborist 9.1.5 → 9.1.6
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/README.md +1 -1
- package/bin/index.js +1 -1
- package/lib/arborist/build-ideal-tree.js +23 -10
- package/lib/arborist/isolated-reifier.js +4 -4
- package/lib/arborist/load-actual.js +1 -1
- package/lib/arborist/load-virtual.js +1 -2
- package/lib/arborist/reify.js +11 -46
- package/lib/diff.js +17 -21
- package/lib/gather-dep-set.js +1 -1
- package/lib/node.js +6 -6
- package/lib/optional-set.js +2 -4
- package/lib/packument-cache.js +1 -1
- package/lib/place-dep.js +3 -3
- package/lib/query-selector-all.js +1 -1
- package/lib/shrinkwrap.js +3 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
Inspect and manage `node_modules` trees.
|
|
8
8
|
|
|
9
|
-

|
|
10
10
|
|
|
11
11
|
There's more documentation [in the docs
|
|
12
12
|
folder](https://github.com/npm/cli/tree/latest/workspaces/arborist/docs).
|
package/bin/index.js
CHANGED
|
@@ -37,7 +37,7 @@ ${message && '\n' + message + '\n'}
|
|
|
37
37
|
|
|
38
38
|
Additionally:
|
|
39
39
|
|
|
40
|
-
* --loglevel=warn|--quiet will
|
|
40
|
+
* --loglevel=warn|--quiet will suppress the printing of package trees
|
|
41
41
|
* --logfile <file|bool> will output logs to a file
|
|
42
42
|
* --timing will show timing information
|
|
43
43
|
* Instead of 'npm install <pkg>', use 'arborist reify --add=<pkg>'.
|
|
@@ -192,7 +192,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
async #checkEngineAndPlatform () {
|
|
195
|
-
const { engineStrict, npmVersion, nodeVersion, omit = [] } = this.options
|
|
195
|
+
const { engineStrict, npmVersion, nodeVersion, omit = [], cpu, os, libc } = this.options
|
|
196
196
|
const omitSet = new Set(omit)
|
|
197
197
|
|
|
198
198
|
for (const node of this.idealTree.inventory.values()) {
|
|
@@ -214,6 +214,19 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
214
214
|
}
|
|
215
215
|
checkPlatform(node.package, this.options.force)
|
|
216
216
|
}
|
|
217
|
+
if (node.optional && !node.inert) {
|
|
218
|
+
// Mark any optional packages we can't install as inert.
|
|
219
|
+
// We ignore the --force and --engine-strict flags.
|
|
220
|
+
try {
|
|
221
|
+
checkEngine(node.package, npmVersion, nodeVersion, false)
|
|
222
|
+
checkPlatform(node.package, false, { cpu, os, libc })
|
|
223
|
+
} catch (error) {
|
|
224
|
+
const set = optionalSet(node)
|
|
225
|
+
for (const node of set) {
|
|
226
|
+
node.inert = true
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
217
230
|
}
|
|
218
231
|
}
|
|
219
232
|
|
|
@@ -324,7 +337,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
324
337
|
})
|
|
325
338
|
|
|
326
339
|
.then(tree => {
|
|
327
|
-
// search the virtual tree for invalid edges, if any are found add their source to
|
|
340
|
+
// search the virtual tree for missing/invalid edges, if any are found add their source to
|
|
328
341
|
// the depsQueue so that we'll fix it later
|
|
329
342
|
depth({
|
|
330
343
|
tree,
|
|
@@ -338,7 +351,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
338
351
|
filter: node => node,
|
|
339
352
|
visit: node => {
|
|
340
353
|
for (const edge of node.edgesOut.values()) {
|
|
341
|
-
if (!edge.valid) {
|
|
354
|
+
if (!edge.to || !edge.valid) {
|
|
342
355
|
this.#depsQueue.push(node)
|
|
343
356
|
break // no need to continue the loop after the first hit
|
|
344
357
|
}
|
|
@@ -811,7 +824,7 @@ This is a one-time fix-up, please be patient...
|
|
|
811
824
|
node !== this.idealTree &&
|
|
812
825
|
node.resolved &&
|
|
813
826
|
(hasBundle || hasShrinkwrap) &&
|
|
814
|
-
!node.
|
|
827
|
+
!node.inert
|
|
815
828
|
if (crackOpen) {
|
|
816
829
|
const Arborist = this.constructor
|
|
817
830
|
const opt = { ...this.options }
|
|
@@ -1011,7 +1024,7 @@ This is a one-time fix-up, please be patient...
|
|
|
1011
1024
|
}
|
|
1012
1025
|
|
|
1013
1026
|
// pre-fetch any problem edges, since we'll need these soon
|
|
1014
|
-
// if it fails at this point, though,
|
|
1027
|
+
// if it fails at this point, though, don't worry because it
|
|
1015
1028
|
// may well be an optional dep that has gone missing. it'll
|
|
1016
1029
|
// fail later anyway.
|
|
1017
1030
|
for (const e of this.#problemEdges(placed)) {
|
|
@@ -1067,7 +1080,7 @@ This is a one-time fix-up, please be patient...
|
|
|
1067
1080
|
? await this.#nodeFromSpec(edge.name, spec2, parent, secondEdge)
|
|
1068
1081
|
: null
|
|
1069
1082
|
|
|
1070
|
-
// pick the second one if they're both happy with that
|
|
1083
|
+
// pick the second one if they're both happy with that; otherwise, first
|
|
1071
1084
|
const node = second && edge.valid ? second : first
|
|
1072
1085
|
// ensure the one we want is the one that's placed
|
|
1073
1086
|
node.parent = parent
|
|
@@ -1274,7 +1287,7 @@ This is a one-time fix-up, please be patient...
|
|
|
1274
1287
|
|
|
1275
1288
|
// failed to load the spec, either because of enotarget or
|
|
1276
1289
|
// fetch failure of some other sort. save it so we can verify
|
|
1277
|
-
// later that it's optional
|
|
1290
|
+
// later that it's optional; otherwise, the error is fatal.
|
|
1278
1291
|
const n = new Node({
|
|
1279
1292
|
name,
|
|
1280
1293
|
parent,
|
|
@@ -1431,7 +1444,7 @@ This is a one-time fix-up, please be patient...
|
|
|
1431
1444
|
// - if a path under an existing node, then assign that as the fsParent,
|
|
1432
1445
|
// and add it to the _depsQueue
|
|
1433
1446
|
//
|
|
1434
|
-
// call buildDepStep if anything was added to the queue
|
|
1447
|
+
// call buildDepStep if anything was added to the queue; otherwise, we're done
|
|
1435
1448
|
#resolveLinks () {
|
|
1436
1449
|
for (const link of this.#linkNodes) {
|
|
1437
1450
|
this.#linkNodes.delete(link)
|
|
@@ -1561,7 +1574,7 @@ This is a one-time fix-up, please be patient...
|
|
|
1561
1574
|
|
|
1562
1575
|
const set = optionalSet(node)
|
|
1563
1576
|
for (const node of set) {
|
|
1564
|
-
node.
|
|
1577
|
+
node.inert = true
|
|
1565
1578
|
}
|
|
1566
1579
|
}
|
|
1567
1580
|
}
|
|
@@ -1582,7 +1595,7 @@ This is a one-time fix-up, please be patient...
|
|
|
1582
1595
|
node.parent !== null
|
|
1583
1596
|
&& !node.isProjectRoot
|
|
1584
1597
|
&& !excludeNodes.has(node)
|
|
1585
|
-
&& !node.
|
|
1598
|
+
&& !node.inert
|
|
1586
1599
|
) {
|
|
1587
1600
|
this[_addNodeToTrashList](node)
|
|
1588
1601
|
}
|
|
@@ -81,7 +81,7 @@ module.exports = cls => class IsolatedReifier extends cls {
|
|
|
81
81
|
}
|
|
82
82
|
queue.push(e.to)
|
|
83
83
|
})
|
|
84
|
-
if (!next.isProjectRoot && !next.isWorkspace && !next.
|
|
84
|
+
if (!next.isProjectRoot && !next.isWorkspace && !next.inert) {
|
|
85
85
|
root.external.push(await this.externalProxyMemo(next))
|
|
86
86
|
}
|
|
87
87
|
}
|
|
@@ -140,15 +140,15 @@ module.exports = cls => class IsolatedReifier extends cls {
|
|
|
140
140
|
|
|
141
141
|
async assignCommonProperties (node, result) {
|
|
142
142
|
function validEdgesOut (node) {
|
|
143
|
-
return [...node.edgesOut.values()].filter(e => e.to && e.to.target && !(node.package.
|
|
143
|
+
return [...node.edgesOut.values()].filter(e => e.to && e.to.target && !(node.package.bundledDependencies || node.package.bundleDependencies || []).includes(e.to.name))
|
|
144
144
|
}
|
|
145
145
|
const edges = validEdgesOut(node)
|
|
146
146
|
const optionalDeps = edges.filter(e => e.optional).map(e => e.to.target)
|
|
147
147
|
const nonOptionalDeps = edges.filter(e => !e.optional).map(e => e.to.target)
|
|
148
148
|
|
|
149
149
|
result.localDependencies = await Promise.all(nonOptionalDeps.filter(n => n.isWorkspace).map(this.workspaceProxyMemo))
|
|
150
|
-
result.externalDependencies = await Promise.all(nonOptionalDeps.filter(n => !n.isWorkspace && !n.
|
|
151
|
-
result.externalOptionalDependencies = await Promise.all(optionalDeps.filter(n => !n.
|
|
150
|
+
result.externalDependencies = await Promise.all(nonOptionalDeps.filter(n => !n.isWorkspace && !n.inert).map(this.externalProxyMemo))
|
|
151
|
+
result.externalOptionalDependencies = await Promise.all(optionalDeps.filter(n => !n.inert).map(this.externalProxyMemo))
|
|
152
152
|
result.dependencies = [
|
|
153
153
|
...result.externalDependencies,
|
|
154
154
|
...result.localDependencies,
|
|
@@ -36,7 +36,7 @@ module.exports = cls => class ActualLoader extends cls {
|
|
|
36
36
|
// We don't do fsParent as a magic getter/setter, because it'd be too costly
|
|
37
37
|
// to keep up to date along the walk.
|
|
38
38
|
// And, we know that it can ONLY be relevant when the node is a target of a
|
|
39
|
-
// link
|
|
39
|
+
// link; otherwise, it'd be in a node_modules folder, so take advantage of
|
|
40
40
|
// that to limit the scans later.
|
|
41
41
|
#topNodes = new Set()
|
|
42
42
|
#transplantFilter
|
|
@@ -168,7 +168,7 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
// separate out link
|
|
171
|
+
// separate out link metadata, and create Node objects for nodes
|
|
172
172
|
#resolveNodes (s, root) {
|
|
173
173
|
const links = new Map()
|
|
174
174
|
const nodes = new Map([['', root]])
|
|
@@ -269,7 +269,6 @@ To fix:
|
|
|
269
269
|
integrity: sw.integrity,
|
|
270
270
|
resolved: consistentResolve(sw.resolved, this.path, path),
|
|
271
271
|
pkg: sw,
|
|
272
|
-
ideallyInert: sw.ideallyInert,
|
|
273
272
|
hasShrinkwrap: sw.hasShrinkwrap,
|
|
274
273
|
dev,
|
|
275
274
|
optional,
|
package/lib/arborist/reify.js
CHANGED
|
@@ -7,7 +7,6 @@ const pacote = require('pacote')
|
|
|
7
7
|
const promiseAllRejectLate = require('promise-all-reject-late')
|
|
8
8
|
const runScript = require('@npmcli/run-script')
|
|
9
9
|
const { callLimit: promiseCallLimit } = require('promise-call-limit')
|
|
10
|
-
const { checkEngine, checkPlatform } = require('npm-install-checks')
|
|
11
10
|
const { depth: dfwalk } = require('treeverse')
|
|
12
11
|
const { dirname, resolve, relative, join } = require('node:path')
|
|
13
12
|
const { log, time } = require('proc-log')
|
|
@@ -74,7 +73,6 @@ module.exports = cls => class Reifier extends cls {
|
|
|
74
73
|
#dryRun
|
|
75
74
|
#nmValidated = new Set()
|
|
76
75
|
#omit
|
|
77
|
-
#omitted
|
|
78
76
|
#retiredPaths = {}
|
|
79
77
|
#retiredUnchanged = {}
|
|
80
78
|
#savePrefix
|
|
@@ -99,7 +97,6 @@ module.exports = cls => class Reifier extends cls {
|
|
|
99
97
|
}
|
|
100
98
|
|
|
101
99
|
this.#omit = new Set(options.omit)
|
|
102
|
-
this.#omitted = new Set()
|
|
103
100
|
|
|
104
101
|
// start tracker block
|
|
105
102
|
this.addTracker('reify')
|
|
@@ -132,15 +129,17 @@ module.exports = cls => class Reifier extends cls {
|
|
|
132
129
|
this.idealTree = oldTree
|
|
133
130
|
}
|
|
134
131
|
await this[_saveIdealTree](options)
|
|
135
|
-
// clean
|
|
136
|
-
for (const node of this
|
|
137
|
-
node.
|
|
132
|
+
// clean inert
|
|
133
|
+
for (const node of this.idealTree.inventory.values()) {
|
|
134
|
+
if (node.inert) {
|
|
135
|
+
node.parent = null
|
|
136
|
+
}
|
|
138
137
|
}
|
|
139
138
|
// clean up any trash that is still in the tree
|
|
140
139
|
for (const path of this[_trashList]) {
|
|
141
140
|
const loc = relpath(this.idealTree.realpath, path)
|
|
142
141
|
const node = this.idealTree.inventory.get(loc)
|
|
143
|
-
if (node && node.root === this.idealTree
|
|
142
|
+
if (node && node.root === this.idealTree) {
|
|
144
143
|
node.parent = null
|
|
145
144
|
}
|
|
146
145
|
}
|
|
@@ -228,18 +227,6 @@ module.exports = cls => class Reifier extends cls {
|
|
|
228
227
|
this.idealTree.meta.hiddenLockfile = true
|
|
229
228
|
this.idealTree.meta.lockfileVersion = defaultLockfileVersion
|
|
230
229
|
|
|
231
|
-
// Preserve inertness for failed stuff.
|
|
232
|
-
if (this.actualTree) {
|
|
233
|
-
for (const [loc, actual] of this.actualTree.inventory.entries()) {
|
|
234
|
-
if (actual.ideallyInert) {
|
|
235
|
-
const ideal = this.idealTree.inventory.get(loc)
|
|
236
|
-
if (ideal) {
|
|
237
|
-
ideal.ideallyInert = true
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
230
|
this.actualTree = this.idealTree
|
|
244
231
|
this.idealTree = null
|
|
245
232
|
|
|
@@ -465,7 +452,6 @@ module.exports = cls => class Reifier extends cls {
|
|
|
465
452
|
// and ideal trees.
|
|
466
453
|
this.diff = Diff.calculate({
|
|
467
454
|
omit: this.#omit,
|
|
468
|
-
omitted: this.#omitted,
|
|
469
455
|
shrinkwrapInflated: this.#shrinkwrapInflated,
|
|
470
456
|
filterNodes,
|
|
471
457
|
actual: this.actualTree,
|
|
@@ -566,9 +552,6 @@ module.exports = cls => class Reifier extends cls {
|
|
|
566
552
|
// retire the same path at the same time.
|
|
567
553
|
const dirsChecked = new Set()
|
|
568
554
|
return promiseAllRejectLate(leaves.map(async node => {
|
|
569
|
-
if (node.ideallyInert) {
|
|
570
|
-
return
|
|
571
|
-
}
|
|
572
555
|
for (const d of walkUp(node.path)) {
|
|
573
556
|
if (d === node.top.path) {
|
|
574
557
|
break
|
|
@@ -662,18 +645,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
662
645
|
const timeEnd = time.start(`reifyNode:${node.location}`)
|
|
663
646
|
this.addTracker('reify', node.name, node.location)
|
|
664
647
|
|
|
665
|
-
const { npmVersion, nodeVersion, cpu, os, libc } = this.options
|
|
666
648
|
const p = Promise.resolve().then(async () => {
|
|
667
|
-
// when we reify an optional node, check the engine and platform
|
|
668
|
-
// first. be sure to ignore the --force and --engine-strict flags,
|
|
669
|
-
// since we always want to skip any optional packages we can't install.
|
|
670
|
-
// these checks throwing will result in a rollback and removal
|
|
671
|
-
// of the mismatches
|
|
672
|
-
// eslint-disable-next-line promise/always-return
|
|
673
|
-
if (node.optional) {
|
|
674
|
-
checkEngine(node.package, npmVersion, nodeVersion, false)
|
|
675
|
-
checkPlatform(node.package, false, { cpu, os, libc })
|
|
676
|
-
}
|
|
677
649
|
await this[_checkBins](node)
|
|
678
650
|
await this.#extractOrLink(node)
|
|
679
651
|
const { _id, deprecated } = node.package
|
|
@@ -707,10 +679,6 @@ module.exports = cls => class Reifier extends cls {
|
|
|
707
679
|
}
|
|
708
680
|
|
|
709
681
|
async #extractOrLink (node) {
|
|
710
|
-
if (node.ideallyInert) {
|
|
711
|
-
return
|
|
712
|
-
}
|
|
713
|
-
|
|
714
682
|
const nm = resolve(node.parent.path, 'node_modules')
|
|
715
683
|
await this.#validateNodeModules(nm)
|
|
716
684
|
|
|
@@ -791,9 +759,9 @@ module.exports = cls => class Reifier extends cls {
|
|
|
791
759
|
[_handleOptionalFailure] (node, p) {
|
|
792
760
|
return (node.optional ? p.catch(() => {
|
|
793
761
|
const set = optionalSet(node)
|
|
794
|
-
for (node of set) {
|
|
762
|
+
for (const node of set) {
|
|
795
763
|
log.verbose('reify', 'failed optional dependency', node.path)
|
|
796
|
-
node.
|
|
764
|
+
node.inert = true
|
|
797
765
|
this[_addNodeToTrashList](node)
|
|
798
766
|
}
|
|
799
767
|
}) : p).then(() => node)
|
|
@@ -1165,9 +1133,6 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1165
1133
|
|
|
1166
1134
|
this.#retiredUnchanged[retireFolder] = []
|
|
1167
1135
|
return promiseAllRejectLate(diff.unchanged.map(node => {
|
|
1168
|
-
if (node.ideallyInert) {
|
|
1169
|
-
return
|
|
1170
|
-
}
|
|
1171
1136
|
// no need to roll back links, since we'll just delete them anyway
|
|
1172
1137
|
if (node.isLink) {
|
|
1173
1138
|
return mkdir(dirname(node.path), { recursive: true, force: true })
|
|
@@ -1247,7 +1212,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1247
1212
|
// skip links that only live within node_modules as they are most
|
|
1248
1213
|
// likely managed by packages we installed, we only want to rebuild
|
|
1249
1214
|
// unchanged links we directly manage
|
|
1250
|
-
const linkedFromRoot = (node.parent === tree && !node.
|
|
1215
|
+
const linkedFromRoot = (node.parent === tree && !node.inert) || node.target.fsTop === tree
|
|
1251
1216
|
if (node.isLink && linkedFromRoot) {
|
|
1252
1217
|
nodes.push(node)
|
|
1253
1218
|
}
|
|
@@ -1358,7 +1323,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1358
1323
|
const alias = name !== pname
|
|
1359
1324
|
newSpec = alias ? `npm:${pname}@${range}` : range
|
|
1360
1325
|
} else if (req.hosted) {
|
|
1361
|
-
// save the git+https url if it has auth
|
|
1326
|
+
// save the git+https url if it has auth; otherwise, shortcut
|
|
1362
1327
|
const h = req.hosted
|
|
1363
1328
|
const opt = { noCommittish: false }
|
|
1364
1329
|
if (h.https && h.auth) {
|
|
@@ -1427,7 +1392,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1427
1392
|
|
|
1428
1393
|
// Returns true if any of the edges from this node has a semver
|
|
1429
1394
|
// range definition that is an exact match to the version installed
|
|
1430
|
-
// e.g: should return true if for a given
|
|
1395
|
+
// e.g: should return true if for a given and installed version 1.0.0,
|
|
1431
1396
|
// range is either =1.0.0 or 1.0.0
|
|
1432
1397
|
const exactVersion = node => {
|
|
1433
1398
|
for (const edge of node.edgesIn) {
|
package/lib/diff.js
CHANGED
|
@@ -11,9 +11,8 @@ const { existsSync } = require('node:fs')
|
|
|
11
11
|
const ssri = require('ssri')
|
|
12
12
|
|
|
13
13
|
class Diff {
|
|
14
|
-
constructor ({ actual, ideal, filterSet, shrinkwrapInflated, omit
|
|
14
|
+
constructor ({ actual, ideal, filterSet, shrinkwrapInflated, omit }) {
|
|
15
15
|
this.omit = omit
|
|
16
|
-
this.omitted = omitted
|
|
17
16
|
this.filterSet = filterSet
|
|
18
17
|
this.shrinkwrapInflated = shrinkwrapInflated
|
|
19
18
|
this.children = []
|
|
@@ -39,7 +38,6 @@ class Diff {
|
|
|
39
38
|
filterNodes = [],
|
|
40
39
|
shrinkwrapInflated = new Set(),
|
|
41
40
|
omit = new Set(),
|
|
42
|
-
omitted = new Set(),
|
|
43
41
|
}) {
|
|
44
42
|
// if there's a filterNode, then:
|
|
45
43
|
// - get the path from the root to the filterNode. The root or
|
|
@@ -98,28 +96,18 @@ class Diff {
|
|
|
98
96
|
}
|
|
99
97
|
|
|
100
98
|
return depth({
|
|
101
|
-
tree: new Diff({ actual, ideal, filterSet, shrinkwrapInflated, omit
|
|
99
|
+
tree: new Diff({ actual, ideal, filterSet, shrinkwrapInflated, omit }),
|
|
102
100
|
getChildren,
|
|
103
101
|
leave,
|
|
104
102
|
})
|
|
105
103
|
}
|
|
106
104
|
}
|
|
107
105
|
|
|
108
|
-
const getAction = ({ actual, ideal
|
|
106
|
+
const getAction = ({ actual, ideal }) => {
|
|
109
107
|
if (!ideal) {
|
|
110
108
|
return 'REMOVE'
|
|
111
109
|
}
|
|
112
110
|
|
|
113
|
-
if (ideal.shouldOmit?.(omit)) {
|
|
114
|
-
omitted.add(ideal)
|
|
115
|
-
|
|
116
|
-
if (actual) {
|
|
117
|
-
return 'REMOVE'
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return null
|
|
121
|
-
}
|
|
122
|
-
|
|
123
111
|
// bundled meta-deps are copied over to the ideal tree when we visit it,
|
|
124
112
|
// so they'll appear to be missing here. There's no need to handle them
|
|
125
113
|
// in the diff, though, because they'll be replaced at reify time anyway
|
|
@@ -199,7 +187,6 @@ const getChildren = diff => {
|
|
|
199
187
|
filterSet,
|
|
200
188
|
shrinkwrapInflated,
|
|
201
189
|
omit,
|
|
202
|
-
omitted,
|
|
203
190
|
} = diff
|
|
204
191
|
|
|
205
192
|
// Note: we DON'T diff fsChildren themselves, because they are either
|
|
@@ -231,7 +218,6 @@ const getChildren = diff => {
|
|
|
231
218
|
filterSet,
|
|
232
219
|
shrinkwrapInflated,
|
|
233
220
|
omit,
|
|
234
|
-
omitted,
|
|
235
221
|
})
|
|
236
222
|
}
|
|
237
223
|
|
|
@@ -251,13 +237,24 @@ const diffNode = ({
|
|
|
251
237
|
filterSet,
|
|
252
238
|
shrinkwrapInflated,
|
|
253
239
|
omit,
|
|
254
|
-
omitted,
|
|
255
240
|
}) => {
|
|
256
241
|
if (filterSet.size && !(filterSet.has(ideal) || filterSet.has(actual))) {
|
|
257
242
|
return
|
|
258
243
|
}
|
|
259
244
|
|
|
260
|
-
|
|
245
|
+
if (ideal?.shouldOmit?.(omit)) {
|
|
246
|
+
ideal.inert = true
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Treat inert nodes as undefined for the purposes of diffing.
|
|
250
|
+
if (ideal?.inert) {
|
|
251
|
+
ideal = undefined
|
|
252
|
+
}
|
|
253
|
+
if (!actual && !ideal) {
|
|
254
|
+
return
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const action = getAction({ actual, ideal })
|
|
261
258
|
|
|
262
259
|
// if it's a match, then get its children
|
|
263
260
|
// otherwise, this is the child diff node
|
|
@@ -265,7 +262,7 @@ const diffNode = ({
|
|
|
265
262
|
if (action === 'REMOVE') {
|
|
266
263
|
removed.push(actual)
|
|
267
264
|
}
|
|
268
|
-
children.push(new Diff({ actual, ideal, filterSet, shrinkwrapInflated, omit
|
|
265
|
+
children.push(new Diff({ actual, ideal, filterSet, shrinkwrapInflated, omit }))
|
|
269
266
|
} else {
|
|
270
267
|
unchanged.push(ideal)
|
|
271
268
|
// !*! Weird dirty hack warning !*!
|
|
@@ -306,7 +303,6 @@ const diffNode = ({
|
|
|
306
303
|
filterSet,
|
|
307
304
|
shrinkwrapInflated,
|
|
308
305
|
omit,
|
|
309
|
-
omitted,
|
|
310
306
|
}))
|
|
311
307
|
}
|
|
312
308
|
}
|
package/lib/gather-dep-set.js
CHANGED
|
@@ -20,7 +20,7 @@ const gatherDepSet = (set, edgeFilter) => {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
// now remove all nodes in the set that have a
|
|
23
|
+
// now remove all nodes in the set that have a dependent outside the set
|
|
24
24
|
// if any change is made, then re-check
|
|
25
25
|
// continue until no changes made, or deps set evaporates fully.
|
|
26
26
|
let changed = true
|
package/lib/node.js
CHANGED
|
@@ -101,7 +101,7 @@ class Node {
|
|
|
101
101
|
global = false,
|
|
102
102
|
dummy = false,
|
|
103
103
|
sourceReference = null,
|
|
104
|
-
|
|
104
|
+
inert = false,
|
|
105
105
|
} = options
|
|
106
106
|
// this object gives querySelectorAll somewhere to stash context about a node
|
|
107
107
|
// while processing a query
|
|
@@ -207,7 +207,7 @@ class Node {
|
|
|
207
207
|
this.extraneous = false
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
this.
|
|
210
|
+
this.inert = inert
|
|
211
211
|
|
|
212
212
|
this.edgesIn = new Set()
|
|
213
213
|
this.edgesOut = new CaseInsensitiveMap()
|
|
@@ -248,7 +248,7 @@ class Node {
|
|
|
248
248
|
this.fsParent = fsParent || null
|
|
249
249
|
|
|
250
250
|
// see parent/root setters below.
|
|
251
|
-
// root is set to parent's root if we have a parent
|
|
251
|
+
// root is set to parent's root if we have a parent; otherwise, if it's
|
|
252
252
|
// null, then it's set to the node itself.
|
|
253
253
|
if (!parent && !fsParent) {
|
|
254
254
|
this.root = root || null
|
|
@@ -832,7 +832,7 @@ class Node {
|
|
|
832
832
|
edge.reload()
|
|
833
833
|
}
|
|
834
834
|
}
|
|
835
|
-
// reload all edgesOut where root
|
|
835
|
+
// reload all edgesOut where root doesn't match, or is missing, since
|
|
836
836
|
// it might not be missing in the new tree
|
|
837
837
|
for (const edge of this.edgesOut.values()) {
|
|
838
838
|
if (!edge.to || edge.to.root !== root) {
|
|
@@ -1268,7 +1268,7 @@ class Node {
|
|
|
1268
1268
|
// with another by the same name (eg, to update or dedupe).
|
|
1269
1269
|
// This does a couple of walks out on the node_modules tree, recursing
|
|
1270
1270
|
// into child nodes. However, as setting the parent is typically done
|
|
1271
|
-
// with nodes that don't have
|
|
1271
|
+
// with nodes that don't have many children, and (deduped) package
|
|
1272
1272
|
// trees tend to be broad rather than deep, it's not that bad.
|
|
1273
1273
|
// The only walk that starts from the parent rather than this node is
|
|
1274
1274
|
// limited by edge name.
|
|
@@ -1412,7 +1412,7 @@ class Node {
|
|
|
1412
1412
|
}
|
|
1413
1413
|
|
|
1414
1414
|
recalculateOutEdgesOverrides () {
|
|
1415
|
-
// For each edge out
|
|
1415
|
+
// For each edge out propagate the new overrides through.
|
|
1416
1416
|
for (const edge of this.edgesOut.values()) {
|
|
1417
1417
|
edge.reload(true)
|
|
1418
1418
|
if (edge.to) {
|
package/lib/optional-set.js
CHANGED
|
@@ -29,10 +29,8 @@ const optionalSet = node => {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
// now that we've hit the boundary, gather the rest of the nodes in
|
|
32
|
-
// the optional section
|
|
33
|
-
|
|
34
|
-
// from outside the set.
|
|
35
|
-
return gatherDepSet(set, edge => !edge.optional)
|
|
32
|
+
// the optional section that don't have dependents outside the set.
|
|
33
|
+
return gatherDepSet(set, edge => !set.has(edge.to))
|
|
36
34
|
}
|
|
37
35
|
|
|
38
36
|
module.exports = optionalSet
|
package/lib/packument-cache.js
CHANGED
|
@@ -30,7 +30,7 @@ class PackumentCache extends LRUCache {
|
|
|
30
30
|
maxSize,
|
|
31
31
|
maxEntrySize,
|
|
32
32
|
sizeCalculation: (p) => {
|
|
33
|
-
// Don't cache if we
|
|
33
|
+
// Don't cache if we don't know the size
|
|
34
34
|
// Some versions of pacote set this to `0`, newer versions set it to `null`
|
|
35
35
|
if (!p[sizeKey]) {
|
|
36
36
|
return maxEntrySize + 1
|
package/lib/place-dep.js
CHANGED
|
@@ -203,7 +203,7 @@ class PlaceDep {
|
|
|
203
203
|
this.warnPeerConflict()
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
// if we get a KEEP in
|
|
206
|
+
// if we get a KEEP in an update scenario, then we MAY have something
|
|
207
207
|
// already duplicating this unnecessarily! For example:
|
|
208
208
|
// ```
|
|
209
209
|
// root (dep: y@1)
|
|
@@ -317,7 +317,7 @@ class PlaceDep {
|
|
|
317
317
|
force: this.force,
|
|
318
318
|
installLinks: this.installLinks,
|
|
319
319
|
installStrategy: this.installStrategy,
|
|
320
|
-
legacyPeerDeps: this.
|
|
320
|
+
legacyPeerDeps: this.legacyPeerDeps,
|
|
321
321
|
preferDedupe: this.preferDedupe,
|
|
322
322
|
strictPeerDeps: this.strictPeerDeps,
|
|
323
323
|
updateNames: this.updateName,
|
|
@@ -421,7 +421,7 @@ class PlaceDep {
|
|
|
421
421
|
// prune all the nodes in a branch of the tree that can be safely removed
|
|
422
422
|
// This is only the most basic duplication detection; it finds if there
|
|
423
423
|
// is another satisfying node further up the tree, and if so, dedupes.
|
|
424
|
-
// Even
|
|
424
|
+
// Even if installStrategy is nested, we do this amount of deduplication.
|
|
425
425
|
pruneDedupable (node, descend = true) {
|
|
426
426
|
if (node.canDedupe(this.preferDedupe, this.explicitRequest)) {
|
|
427
427
|
// gather up all deps that have no valid edges in from outside
|
|
@@ -785,7 +785,7 @@ const hasParent = (node, compareNodes) => {
|
|
|
785
785
|
compareNode = compareNode.target
|
|
786
786
|
}
|
|
787
787
|
|
|
788
|
-
// follows logical parent for link
|
|
788
|
+
// follows logical parent for link ancestors
|
|
789
789
|
if (node.isTop && (node.resolveParent === compareNode)) {
|
|
790
790
|
return true
|
|
791
791
|
}
|
package/lib/shrinkwrap.js
CHANGED
|
@@ -109,7 +109,6 @@ const nodeMetaKeys = [
|
|
|
109
109
|
'inBundle',
|
|
110
110
|
'hasShrinkwrap',
|
|
111
111
|
'hasInstallScript',
|
|
112
|
-
'ideallyInert',
|
|
113
112
|
]
|
|
114
113
|
|
|
115
114
|
const metaFieldFromPkg = (pkg, key) => {
|
|
@@ -136,10 +135,6 @@ const assertNoNewer = async (path, data, lockTime, dir, seen) => {
|
|
|
136
135
|
|
|
137
136
|
const parent = isParent ? dir : resolve(dir, 'node_modules')
|
|
138
137
|
const rel = relpath(path, dir)
|
|
139
|
-
const inert = data.packages[rel]?.ideallyInert
|
|
140
|
-
if (inert) {
|
|
141
|
-
return
|
|
142
|
-
}
|
|
143
138
|
seen.add(rel)
|
|
144
139
|
let entries
|
|
145
140
|
if (dir === path) {
|
|
@@ -178,7 +173,7 @@ const assertNoNewer = async (path, data, lockTime, dir, seen) => {
|
|
|
178
173
|
|
|
179
174
|
// assert that all the entries in the lockfile were seen
|
|
180
175
|
for (const loc in data.packages) {
|
|
181
|
-
if (!seen.has(loc)
|
|
176
|
+
if (!seen.has(loc)) {
|
|
182
177
|
throw new Error(`missing from node_modules: ${loc}`)
|
|
183
178
|
}
|
|
184
179
|
}
|
|
@@ -436,7 +431,7 @@ class Shrinkwrap {
|
|
|
436
431
|
const [sw, lock, yarn] = await this.loadFiles
|
|
437
432
|
data = sw || lock || '{}'
|
|
438
433
|
|
|
439
|
-
// use shrinkwrap only for deps
|
|
434
|
+
// use shrinkwrap only for deps; otherwise, prefer package-lock
|
|
440
435
|
// and ignore npm-shrinkwrap if both are present.
|
|
441
436
|
// TODO: emit a warning here or something if both are present.
|
|
442
437
|
if (this.hiddenLockfile) {
|
|
@@ -788,10 +783,6 @@ class Shrinkwrap {
|
|
|
788
783
|
// ok, I did my best! good luck!
|
|
789
784
|
}
|
|
790
785
|
|
|
791
|
-
if (lock.ideallyInert) {
|
|
792
|
-
meta.ideallyInert = true
|
|
793
|
-
}
|
|
794
|
-
|
|
795
786
|
if (lock.bundled) {
|
|
796
787
|
meta.inBundle = true
|
|
797
788
|
}
|
|
@@ -962,12 +953,6 @@ class Shrinkwrap {
|
|
|
962
953
|
this.#buildLegacyLockfile(this.tree, this.data)
|
|
963
954
|
}
|
|
964
955
|
|
|
965
|
-
if (!this.hiddenLockfile) {
|
|
966
|
-
for (const node of Object.values(this.data.packages)) {
|
|
967
|
-
delete node.ideallyInert
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
|
|
971
956
|
// lf version 1 = dependencies only
|
|
972
957
|
// lf version 2 = dependencies and packages
|
|
973
958
|
// lf version 3 = packages only
|
|
@@ -993,7 +978,7 @@ class Shrinkwrap {
|
|
|
993
978
|
|
|
994
979
|
// npm v6 and before tracked 'from', meaning "the request that led
|
|
995
980
|
// to this package being installed". However, that's inherently
|
|
996
|
-
//
|
|
981
|
+
// racy and non-deterministic in a world where deps are deduped
|
|
997
982
|
// ahead of fetch time. In order to maintain backwards compatibility
|
|
998
983
|
// with v6 in the lockfile, we do this trick where we pick a valid
|
|
999
984
|
// dep link out of the edgesIn set. Choose the edge with the fewest
|