@npmcli/arborist 9.1.4 → 9.1.5
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/lib/arborist/build-ideal-tree.js +8 -8
- package/lib/arborist/load-actual.js +7 -3
- package/lib/arborist/load-virtual.js +7 -17
- package/lib/arborist/rebuild.js +8 -7
- package/lib/arborist/reify.js +31 -73
- package/lib/calc-dep-flags.js +31 -12
- package/lib/diff.js +27 -5
- package/lib/node.js +52 -35
- package/package.json +15 -16
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// mixin implementing the buildIdealTree method
|
|
2
2
|
const localeCompare = require('@isaacs/string-locale-compare')('en')
|
|
3
|
-
const
|
|
3
|
+
const PackageJson = require('@npmcli/package-json')
|
|
4
4
|
const npa = require('npm-package-arg')
|
|
5
5
|
const pacote = require('pacote')
|
|
6
6
|
const cacache = require('cacache')
|
|
@@ -268,7 +268,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
268
268
|
root = await this.#globalRootNode()
|
|
269
269
|
} else {
|
|
270
270
|
try {
|
|
271
|
-
const pkg = await
|
|
271
|
+
const { content: pkg } = await PackageJson.normalize(this.path)
|
|
272
272
|
root = await this.#rootNodeFromPackage(pkg)
|
|
273
273
|
} catch (err) {
|
|
274
274
|
if (err.code === 'EJSONPARSE') {
|
|
@@ -448,7 +448,6 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
448
448
|
const paths = await readdirScoped(nm).catch(() => [])
|
|
449
449
|
for (const p of paths) {
|
|
450
450
|
const name = p.replace(/\\/g, '/')
|
|
451
|
-
tree.package.dependencies = tree.package.dependencies || {}
|
|
452
451
|
const updateName = this[_updateNames].includes(name)
|
|
453
452
|
if (this[_updateAll] || updateName) {
|
|
454
453
|
if (updateName) {
|
|
@@ -1288,14 +1287,15 @@ This is a one-time fix-up, please be patient...
|
|
|
1288
1287
|
})
|
|
1289
1288
|
}
|
|
1290
1289
|
|
|
1291
|
-
#linkFromSpec (name, spec, parent) {
|
|
1290
|
+
async #linkFromSpec (name, spec, parent) {
|
|
1292
1291
|
const realpath = spec.fetchSpec
|
|
1293
1292
|
const { installLinks, legacyPeerDeps } = this
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
this.#linkNodes.add(link)
|
|
1297
|
-
return link
|
|
1293
|
+
const { content: pkg } = await PackageJson.normalize(realpath).catch(() => {
|
|
1294
|
+
return { content: {} }
|
|
1298
1295
|
})
|
|
1296
|
+
const link = new Link({ name, parent, realpath, pkg, installLinks, legacyPeerDeps })
|
|
1297
|
+
this.#linkNodes.add(link)
|
|
1298
|
+
return link
|
|
1299
1299
|
}
|
|
1300
1300
|
|
|
1301
1301
|
// load all peer deps and meta-peer deps into the node's parent
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// mix-in implementing the loadActual method
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { dirname, join, normalize, relative, resolve } = require('node:path')
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const PackageJson = require('@npmcli/package-json')
|
|
6
6
|
const { readdirScoped } = require('@npmcli/fs')
|
|
7
7
|
const { walkUp } = require('walk-up-path')
|
|
8
8
|
const ancestorPath = require('common-ancestor-path')
|
|
@@ -279,12 +279,16 @@ module.exports = cls => class ActualLoader extends cls {
|
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
try {
|
|
282
|
-
const pkg = await
|
|
282
|
+
const { content: pkg } = await PackageJson.normalize(real)
|
|
283
283
|
params.pkg = pkg
|
|
284
284
|
if (useRootOverrides && root.overrides) {
|
|
285
285
|
params.overrides = root.overrides.getNodeRule({ name: pkg.name, version: pkg.version })
|
|
286
286
|
}
|
|
287
287
|
} catch (err) {
|
|
288
|
+
if (err.code === 'EJSONPARSE') {
|
|
289
|
+
// TODO @npmcli/package-json should be doing this
|
|
290
|
+
err.path = join(real, 'package.json')
|
|
291
|
+
}
|
|
288
292
|
params.error = err
|
|
289
293
|
}
|
|
290
294
|
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
+
const { resolve } = require('node:path')
|
|
1
2
|
// mixin providing the loadVirtual method
|
|
2
3
|
const mapWorkspaces = require('@npmcli/map-workspaces')
|
|
3
|
-
|
|
4
|
-
const { resolve } = require('node:path')
|
|
5
|
-
|
|
4
|
+
const PackageJson = require('@npmcli/package-json')
|
|
6
5
|
const nameFromFolder = require('@npmcli/name-from-folder')
|
|
6
|
+
|
|
7
7
|
const consistentResolve = require('../consistent-resolve.js')
|
|
8
8
|
const Shrinkwrap = require('../shrinkwrap.js')
|
|
9
9
|
const Node = require('../node.js')
|
|
10
10
|
const Link = require('../link.js')
|
|
11
11
|
const relpath = require('../relpath.js')
|
|
12
12
|
const calcDepFlags = require('../calc-dep-flags.js')
|
|
13
|
-
const rpj = require('read-package-json-fast')
|
|
14
13
|
const treeCheck = require('../tree-check.js')
|
|
15
14
|
|
|
16
15
|
const flagsSuspect = Symbol.for('flagsSuspect')
|
|
@@ -54,10 +53,11 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
54
53
|
|
|
55
54
|
// when building the ideal tree, we pass in a root node to this function
|
|
56
55
|
// otherwise, load it from the root package json or the lockfile
|
|
56
|
+
const pkg = await PackageJson.normalize(this.path).then(p => p.content).catch(() => s.data.packages[''] || {})
|
|
57
|
+
// TODO clean this up
|
|
57
58
|
const {
|
|
58
|
-
root = await this.#
|
|
59
|
+
root = await this[setWorkspaces](this.#loadNode('', pkg, true)),
|
|
59
60
|
} = options
|
|
60
|
-
|
|
61
61
|
this.#rootOptionProvided = options.root
|
|
62
62
|
|
|
63
63
|
await this.#loadFromShrinkwrap(s, root)
|
|
@@ -65,12 +65,6 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
65
65
|
return treeCheck(this.virtualTree)
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
async #loadRoot (s) {
|
|
69
|
-
const pj = this.path + '/package.json'
|
|
70
|
-
const pkg = await rpj(pj).catch(() => s.data.packages['']) || {}
|
|
71
|
-
return this[setWorkspaces](this.#loadNode('', pkg, true))
|
|
72
|
-
}
|
|
73
|
-
|
|
74
68
|
async #loadFromShrinkwrap (s, root) {
|
|
75
69
|
if (!this.#rootOptionProvided) {
|
|
76
70
|
// root is never any of these things, but might be a brand new
|
|
@@ -219,11 +213,7 @@ To fix:
|
|
|
219
213
|
// we always need to read the package.json for link targets
|
|
220
214
|
// outside node_modules because they can be changed by the local user
|
|
221
215
|
if (!link.target.parent) {
|
|
222
|
-
|
|
223
|
-
const pkg = await rpj(pj).catch(() => null)
|
|
224
|
-
if (pkg) {
|
|
225
|
-
link.target.package = pkg
|
|
226
|
-
}
|
|
216
|
+
await PackageJson.normalize(link.realpath).then(p => link.target.package = p.content).catch(() => null)
|
|
227
217
|
}
|
|
228
218
|
}
|
|
229
219
|
}
|
package/lib/arborist/rebuild.js
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
// Arborist.rebuild({path = this.path}) will do all the binlinks and
|
|
2
2
|
// bundle building needed. Called by reify, and by `npm rebuild`.
|
|
3
3
|
|
|
4
|
+
const PackageJson = require('@npmcli/package-json')
|
|
5
|
+
const binLinks = require('bin-links')
|
|
4
6
|
const localeCompare = require('@isaacs/string-locale-compare')('en')
|
|
5
|
-
const { depth: dfwalk } = require('treeverse')
|
|
6
7
|
const promiseAllRejectLate = require('promise-all-reject-late')
|
|
7
|
-
const rpj = require('read-package-json-fast')
|
|
8
|
-
const binLinks = require('bin-links')
|
|
9
8
|
const runScript = require('@npmcli/run-script')
|
|
10
9
|
const { callLimit: promiseCallLimit } = require('promise-call-limit')
|
|
11
|
-
const {
|
|
10
|
+
const { depth: dfwalk } = require('treeverse')
|
|
12
11
|
const { isNodeGypPackage, defaultGypInstallScript } = require('@npmcli/node-gyp')
|
|
13
12
|
const { log, time } = require('proc-log')
|
|
13
|
+
const { resolve } = require('node:path')
|
|
14
14
|
|
|
15
15
|
const boolEnv = b => b ? '1' : ''
|
|
16
|
-
const sortNodes = (a, b) =>
|
|
17
|
-
(a.depth - b.depth) || localeCompare(a.path, b.path)
|
|
16
|
+
const sortNodes = (a, b) => (a.depth - b.depth) || localeCompare(a.path, b.path)
|
|
18
17
|
|
|
19
18
|
const _checkBins = Symbol.for('checkBins')
|
|
20
19
|
|
|
@@ -250,7 +249,9 @@ module.exports = cls => class Builder extends cls {
|
|
|
250
249
|
// add to the set then remove while we're reading the pj, so we
|
|
251
250
|
// don't accidentally hit it multiple times.
|
|
252
251
|
set.add(node)
|
|
253
|
-
const pkg = await
|
|
252
|
+
const { content: pkg } = await PackageJson.normalize(node.path).catch(() => {
|
|
253
|
+
return { content: {} }
|
|
254
|
+
})
|
|
254
255
|
set.delete(node)
|
|
255
256
|
|
|
256
257
|
const { scripts = {} } = pkg
|
package/lib/arborist/reify.js
CHANGED
|
@@ -1,48 +1,37 @@
|
|
|
1
1
|
// mixin implementing the reify method
|
|
2
|
-
const onExit = require('../signal-handling.js')
|
|
3
|
-
const pacote = require('pacote')
|
|
4
|
-
const AuditReport = require('../audit-report.js')
|
|
5
|
-
const { subset, intersects } = require('semver')
|
|
6
|
-
const npa = require('npm-package-arg')
|
|
7
|
-
const semver = require('semver')
|
|
8
|
-
const debug = require('../debug.js')
|
|
9
|
-
const { walkUp } = require('walk-up-path')
|
|
10
|
-
const { log, time } = require('proc-log')
|
|
11
|
-
const rpj = require('read-package-json-fast')
|
|
12
|
-
const hgi = require('hosted-git-info')
|
|
13
|
-
|
|
14
|
-
const { dirname, resolve, relative, join } = require('node:path')
|
|
15
|
-
const { depth: dfwalk } = require('treeverse')
|
|
16
|
-
const {
|
|
17
|
-
lstat,
|
|
18
|
-
mkdir,
|
|
19
|
-
rm,
|
|
20
|
-
symlink,
|
|
21
|
-
} = require('node:fs/promises')
|
|
22
|
-
const { moveFile } = require('@npmcli/fs')
|
|
23
2
|
const PackageJson = require('@npmcli/package-json')
|
|
3
|
+
const hgi = require('hosted-git-info')
|
|
4
|
+
const npa = require('npm-package-arg')
|
|
24
5
|
const packageContents = require('@npmcli/installed-package-contents')
|
|
6
|
+
const pacote = require('pacote')
|
|
7
|
+
const promiseAllRejectLate = require('promise-all-reject-late')
|
|
25
8
|
const runScript = require('@npmcli/run-script')
|
|
9
|
+
const { callLimit: promiseCallLimit } = require('promise-call-limit')
|
|
26
10
|
const { checkEngine, checkPlatform } = require('npm-install-checks')
|
|
11
|
+
const { depth: dfwalk } = require('treeverse')
|
|
12
|
+
const { dirname, resolve, relative, join } = require('node:path')
|
|
13
|
+
const { log, time } = require('proc-log')
|
|
14
|
+
const { lstat, mkdir, rm, symlink } = require('node:fs/promises')
|
|
15
|
+
const { moveFile } = require('@npmcli/fs')
|
|
16
|
+
const { subset, intersects } = require('semver')
|
|
17
|
+
const { walkUp } = require('walk-up-path')
|
|
27
18
|
|
|
28
|
-
const
|
|
29
|
-
const relpath = require('../relpath.js')
|
|
19
|
+
const AuditReport = require('../audit-report.js')
|
|
30
20
|
const Diff = require('../diff.js')
|
|
31
|
-
const retirePath = require('../retire-path.js')
|
|
32
|
-
const promiseAllRejectLate = require('promise-all-reject-late')
|
|
33
|
-
const { callLimit: promiseCallLimit } = require('promise-call-limit')
|
|
34
|
-
const optionalSet = require('../optional-set.js')
|
|
35
21
|
const calcDepFlags = require('../calc-dep-flags.js')
|
|
22
|
+
const debug = require('../debug.js')
|
|
23
|
+
const onExit = require('../signal-handling.js')
|
|
24
|
+
const optionalSet = require('../optional-set.js')
|
|
25
|
+
const relpath = require('../relpath.js')
|
|
26
|
+
const retirePath = require('../retire-path.js')
|
|
27
|
+
const treeCheck = require('../tree-check.js')
|
|
28
|
+
const { defaultLockfileVersion } = require('../shrinkwrap.js')
|
|
36
29
|
const { saveTypeMap, hasSubKey } = require('../add-rm-pkg-deps.js')
|
|
37
30
|
|
|
38
|
-
const Shrinkwrap = require('../shrinkwrap.js')
|
|
39
|
-
const { defaultLockfileVersion } = Shrinkwrap
|
|
40
|
-
|
|
41
31
|
// Part of steps (steps need refactoring before we can do anything about these)
|
|
42
32
|
const _retireShallowNodes = Symbol.for('retireShallowNodes')
|
|
43
33
|
const _loadBundlesAndUpdateTrees = Symbol.for('loadBundlesAndUpdateTrees')
|
|
44
34
|
const _submitQuickAudit = Symbol('submitQuickAudit')
|
|
45
|
-
const _addOmitsToTrashList = Symbol('addOmitsToTrashList')
|
|
46
35
|
const _unpackNewModules = Symbol.for('unpackNewModules')
|
|
47
36
|
const _build = Symbol.for('build')
|
|
48
37
|
|
|
@@ -85,6 +74,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
85
74
|
#dryRun
|
|
86
75
|
#nmValidated = new Set()
|
|
87
76
|
#omit
|
|
77
|
+
#omitted
|
|
88
78
|
#retiredPaths = {}
|
|
89
79
|
#retiredUnchanged = {}
|
|
90
80
|
#savePrefix
|
|
@@ -109,6 +99,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
109
99
|
}
|
|
110
100
|
|
|
111
101
|
this.#omit = new Set(options.omit)
|
|
102
|
+
this.#omitted = new Set()
|
|
112
103
|
|
|
113
104
|
// start tracker block
|
|
114
105
|
this.addTracker('reify')
|
|
@@ -141,6 +132,10 @@ module.exports = cls => class Reifier extends cls {
|
|
|
141
132
|
this.idealTree = oldTree
|
|
142
133
|
}
|
|
143
134
|
await this[_saveIdealTree](options)
|
|
135
|
+
// clean omitted
|
|
136
|
+
for (const node of this.#omitted) {
|
|
137
|
+
node.parent = null
|
|
138
|
+
}
|
|
144
139
|
// clean up any trash that is still in the tree
|
|
145
140
|
for (const path of this[_trashList]) {
|
|
146
141
|
const loc = relpath(this.idealTree.realpath, path)
|
|
@@ -315,7 +310,6 @@ module.exports = cls => class Reifier extends cls {
|
|
|
315
310
|
]],
|
|
316
311
|
[_rollbackCreateSparseTree, [
|
|
317
312
|
_createSparseTree,
|
|
318
|
-
_addOmitsToTrashList,
|
|
319
313
|
_loadShrinkwrapsAndUpdateTrees,
|
|
320
314
|
_loadBundlesAndUpdateTrees,
|
|
321
315
|
_submitQuickAudit,
|
|
@@ -470,6 +464,8 @@ module.exports = cls => class Reifier extends cls {
|
|
|
470
464
|
// find all the nodes that need to change between the actual
|
|
471
465
|
// and ideal trees.
|
|
472
466
|
this.diff = Diff.calculate({
|
|
467
|
+
omit: this.#omit,
|
|
468
|
+
omitted: this.#omitted,
|
|
473
469
|
shrinkwrapInflated: this.#shrinkwrapInflated,
|
|
474
470
|
filterNodes,
|
|
475
471
|
actual: this.actualTree,
|
|
@@ -554,37 +550,6 @@ module.exports = cls => class Reifier extends cls {
|
|
|
554
550
|
})
|
|
555
551
|
}
|
|
556
552
|
|
|
557
|
-
// adding to the trash list will skip reifying, and delete them
|
|
558
|
-
// if they are currently in the tree and otherwise untouched.
|
|
559
|
-
[_addOmitsToTrashList] () {
|
|
560
|
-
if (!this.#omit.size) {
|
|
561
|
-
return
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
const timeEnd = time.start('reify:trashOmits')
|
|
565
|
-
for (const node of this.idealTree.inventory.values()) {
|
|
566
|
-
const { top } = node
|
|
567
|
-
|
|
568
|
-
// if the top is not the root or workspace then we do not want to omit it
|
|
569
|
-
if (!top.isProjectRoot && !top.isWorkspace) {
|
|
570
|
-
continue
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
// if a diff filter has been created, then we do not omit the node if the
|
|
574
|
-
// top node is not in that set
|
|
575
|
-
if (this.diff?.filterSet?.size && !this.diff.filterSet.has(top)) {
|
|
576
|
-
continue
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
// omit node if the dep type matches any omit flags that were set
|
|
580
|
-
if (node.shouldOmit(this.#omit)) {
|
|
581
|
-
this[_addNodeToTrashList](node)
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
timeEnd()
|
|
586
|
-
}
|
|
587
|
-
|
|
588
553
|
[_createSparseTree] () {
|
|
589
554
|
const timeEnd = time.start('reify:createSparse')
|
|
590
555
|
// if we call this fn again, we look for the previous list
|
|
@@ -683,7 +648,6 @@ module.exports = cls => class Reifier extends cls {
|
|
|
683
648
|
// reload the diff and sparse tree because the ideal tree changed
|
|
684
649
|
.then(() => this[_diffTrees]())
|
|
685
650
|
.then(() => this[_createSparseTree]())
|
|
686
|
-
.then(() => this[_addOmitsToTrashList]())
|
|
687
651
|
.then(() => this[_loadShrinkwrapsAndUpdateTrees]())
|
|
688
652
|
.then(timeEnd)
|
|
689
653
|
}
|
|
@@ -691,15 +655,10 @@ module.exports = cls => class Reifier extends cls {
|
|
|
691
655
|
// create a symlink for Links, extract for Nodes
|
|
692
656
|
// return the node object, since we usually want that
|
|
693
657
|
// handle optional dep failures here
|
|
694
|
-
// If node is in trash list, skip it
|
|
695
658
|
// If reifying fails, and the node is optional, add it and its optionalSet
|
|
696
659
|
// to the trash list
|
|
697
660
|
// Always return the node.
|
|
698
661
|
[_reifyNode] (node) {
|
|
699
|
-
if (this[_trashList].has(node.path)) {
|
|
700
|
-
return node
|
|
701
|
-
}
|
|
702
|
-
|
|
703
662
|
const timeEnd = time.start(`reifyNode:${node.location}`)
|
|
704
663
|
this.addTracker('reify', node.name, node.location)
|
|
705
664
|
|
|
@@ -803,7 +762,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
803
762
|
})
|
|
804
763
|
// store nodes don't use Node class so node.package doesn't get updated
|
|
805
764
|
if (node.isInStore) {
|
|
806
|
-
const pkg = await
|
|
765
|
+
const { content: pkg } = await PackageJson.normalize(node.path)
|
|
807
766
|
node.package.scripts = pkg.scripts
|
|
808
767
|
}
|
|
809
768
|
return
|
|
@@ -1432,8 +1391,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1432
1391
|
if (options.saveType) {
|
|
1433
1392
|
const depType = saveTypeMap.get(options.saveType)
|
|
1434
1393
|
pkg[depType][name] = newSpec
|
|
1435
|
-
//
|
|
1436
|
-
// if it is empty it will be deleted later
|
|
1394
|
+
// PackageJson.normalize will have moved it here if it was in both, if it is empty it will be deleted later
|
|
1437
1395
|
if (options.saveType === 'prod' && pkg.optionalDependencies) {
|
|
1438
1396
|
delete pkg.optionalDependencies[name]
|
|
1439
1397
|
}
|
|
@@ -1474,7 +1432,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1474
1432
|
const exactVersion = node => {
|
|
1475
1433
|
for (const edge of node.edgesIn) {
|
|
1476
1434
|
try {
|
|
1477
|
-
if (
|
|
1435
|
+
if (subset(edge.spec, node.version)) {
|
|
1478
1436
|
return false
|
|
1479
1437
|
}
|
|
1480
1438
|
} catch {
|
package/lib/calc-dep-flags.js
CHANGED
|
@@ -22,6 +22,7 @@ const calcDepFlagsStep = (node) => {
|
|
|
22
22
|
// or normal dependency graphs overlap deep in the dep graph.
|
|
23
23
|
// Since we're only walking through deps that are not already flagged
|
|
24
24
|
// as non-dev/non-optional, it's typically a very shallow traversal
|
|
25
|
+
|
|
25
26
|
node.extraneous = false
|
|
26
27
|
resetParents(node, 'extraneous')
|
|
27
28
|
resetParents(node, 'dev')
|
|
@@ -47,10 +48,16 @@ const calcDepFlagsStep = (node) => {
|
|
|
47
48
|
if (!to) {
|
|
48
49
|
return
|
|
49
50
|
}
|
|
50
|
-
|
|
51
51
|
// everything with any kind of edge into it is not extraneous
|
|
52
52
|
to.extraneous = false
|
|
53
53
|
|
|
54
|
+
// If this is a peer edge, mark the target as peer
|
|
55
|
+
if (peer) {
|
|
56
|
+
to.peer = true
|
|
57
|
+
} else if (to.peer && !hasIncomingPeerEdge(to)) {
|
|
58
|
+
unsetFlag(to, 'peer')
|
|
59
|
+
}
|
|
60
|
+
|
|
54
61
|
// devOptional is the *overlap* of the dev and optional tree.
|
|
55
62
|
// however, for convenience and to save an extra rewalk, we leave
|
|
56
63
|
// it set when we are in *either* tree, and then omit it from the
|
|
@@ -61,11 +68,6 @@ const calcDepFlagsStep = (node) => {
|
|
|
61
68
|
// either the dev or opt trees
|
|
62
69
|
const unsetDev = unsetDevOpt || !node.dev && !dev
|
|
63
70
|
const unsetOpt = unsetDevOpt || !node.optional && !optional
|
|
64
|
-
const unsetPeer = !node.peer && !peer
|
|
65
|
-
|
|
66
|
-
if (unsetPeer) {
|
|
67
|
-
unsetFlag(to, 'peer')
|
|
68
|
-
}
|
|
69
71
|
|
|
70
72
|
if (unsetDevOpt) {
|
|
71
73
|
unsetFlag(to, 'devOptional')
|
|
@@ -83,6 +85,16 @@ const calcDepFlagsStep = (node) => {
|
|
|
83
85
|
return node
|
|
84
86
|
}
|
|
85
87
|
|
|
88
|
+
const hasIncomingPeerEdge = (node) => {
|
|
89
|
+
const target = node.isLink && node.target ? node.target : node
|
|
90
|
+
for (const edge of target.edgesIn) {
|
|
91
|
+
if (edge.type === 'peer') {
|
|
92
|
+
return true
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return false
|
|
96
|
+
}
|
|
97
|
+
|
|
86
98
|
const resetParents = (node, flag) => {
|
|
87
99
|
if (node[flag]) {
|
|
88
100
|
return
|
|
@@ -109,12 +121,19 @@ const unsetFlag = (node, flag) => {
|
|
|
109
121
|
const children = []
|
|
110
122
|
const targetNode = node.isLink && node.target ? node.target : node
|
|
111
123
|
for (const edge of targetNode.edgesOut.values()) {
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
(
|
|
116
|
-
|
|
117
|
-
|
|
124
|
+
if (edge.to?.[flag]) {
|
|
125
|
+
// For the peer flag, only follow peer edges to unset the flag
|
|
126
|
+
// Don't propagate peer flag through prod/dev/optional edges
|
|
127
|
+
if (flag === 'peer') {
|
|
128
|
+
if (edge.type === 'peer') {
|
|
129
|
+
children.push(edge.to)
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
// For other flags, follow prod edges (and peer edges for non-peer flags)
|
|
133
|
+
if (edge.type === 'prod' || edge.type === 'peer') {
|
|
134
|
+
children.push(edge.to)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
118
137
|
}
|
|
119
138
|
}
|
|
120
139
|
return children
|
package/lib/diff.js
CHANGED
|
@@ -11,7 +11,9 @@ const { existsSync } = require('node:fs')
|
|
|
11
11
|
const ssri = require('ssri')
|
|
12
12
|
|
|
13
13
|
class Diff {
|
|
14
|
-
constructor ({ actual, ideal, filterSet, shrinkwrapInflated }) {
|
|
14
|
+
constructor ({ actual, ideal, filterSet, shrinkwrapInflated, omit, omitted }) {
|
|
15
|
+
this.omit = omit
|
|
16
|
+
this.omitted = omitted
|
|
15
17
|
this.filterSet = filterSet
|
|
16
18
|
this.shrinkwrapInflated = shrinkwrapInflated
|
|
17
19
|
this.children = []
|
|
@@ -36,6 +38,8 @@ class Diff {
|
|
|
36
38
|
ideal,
|
|
37
39
|
filterNodes = [],
|
|
38
40
|
shrinkwrapInflated = new Set(),
|
|
41
|
+
omit = new Set(),
|
|
42
|
+
omitted = new Set(),
|
|
39
43
|
}) {
|
|
40
44
|
// if there's a filterNode, then:
|
|
41
45
|
// - get the path from the root to the filterNode. The root or
|
|
@@ -94,18 +98,28 @@ class Diff {
|
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
return depth({
|
|
97
|
-
tree: new Diff({ actual, ideal, filterSet, shrinkwrapInflated }),
|
|
101
|
+
tree: new Diff({ actual, ideal, filterSet, shrinkwrapInflated, omit, omitted }),
|
|
98
102
|
getChildren,
|
|
99
103
|
leave,
|
|
100
104
|
})
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
107
|
|
|
104
|
-
const getAction = ({ actual, ideal }) => {
|
|
108
|
+
const getAction = ({ actual, ideal, omit, omitted }) => {
|
|
105
109
|
if (!ideal) {
|
|
106
110
|
return 'REMOVE'
|
|
107
111
|
}
|
|
108
112
|
|
|
113
|
+
if (ideal.shouldOmit?.(omit)) {
|
|
114
|
+
omitted.add(ideal)
|
|
115
|
+
|
|
116
|
+
if (actual) {
|
|
117
|
+
return 'REMOVE'
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return null
|
|
121
|
+
}
|
|
122
|
+
|
|
109
123
|
// bundled meta-deps are copied over to the ideal tree when we visit it,
|
|
110
124
|
// so they'll appear to be missing here. There's no need to handle them
|
|
111
125
|
// in the diff, though, because they'll be replaced at reify time anyway
|
|
@@ -184,6 +198,8 @@ const getChildren = diff => {
|
|
|
184
198
|
removed,
|
|
185
199
|
filterSet,
|
|
186
200
|
shrinkwrapInflated,
|
|
201
|
+
omit,
|
|
202
|
+
omitted,
|
|
187
203
|
} = diff
|
|
188
204
|
|
|
189
205
|
// Note: we DON'T diff fsChildren themselves, because they are either
|
|
@@ -214,6 +230,8 @@ const getChildren = diff => {
|
|
|
214
230
|
removed,
|
|
215
231
|
filterSet,
|
|
216
232
|
shrinkwrapInflated,
|
|
233
|
+
omit,
|
|
234
|
+
omitted,
|
|
217
235
|
})
|
|
218
236
|
}
|
|
219
237
|
|
|
@@ -232,12 +250,14 @@ const diffNode = ({
|
|
|
232
250
|
removed,
|
|
233
251
|
filterSet,
|
|
234
252
|
shrinkwrapInflated,
|
|
253
|
+
omit,
|
|
254
|
+
omitted,
|
|
235
255
|
}) => {
|
|
236
256
|
if (filterSet.size && !(filterSet.has(ideal) || filterSet.has(actual))) {
|
|
237
257
|
return
|
|
238
258
|
}
|
|
239
259
|
|
|
240
|
-
const action = getAction({ actual, ideal })
|
|
260
|
+
const action = getAction({ actual, ideal, omit, omitted })
|
|
241
261
|
|
|
242
262
|
// if it's a match, then get its children
|
|
243
263
|
// otherwise, this is the child diff node
|
|
@@ -245,7 +265,7 @@ const diffNode = ({
|
|
|
245
265
|
if (action === 'REMOVE') {
|
|
246
266
|
removed.push(actual)
|
|
247
267
|
}
|
|
248
|
-
children.push(new Diff({ actual, ideal, filterSet, shrinkwrapInflated }))
|
|
268
|
+
children.push(new Diff({ actual, ideal, filterSet, shrinkwrapInflated, omit, omitted }))
|
|
249
269
|
} else {
|
|
250
270
|
unchanged.push(ideal)
|
|
251
271
|
// !*! Weird dirty hack warning !*!
|
|
@@ -285,6 +305,8 @@ const diffNode = ({
|
|
|
285
305
|
removed,
|
|
286
306
|
filterSet,
|
|
287
307
|
shrinkwrapInflated,
|
|
308
|
+
omit,
|
|
309
|
+
omitted,
|
|
288
310
|
}))
|
|
289
311
|
}
|
|
290
312
|
}
|
package/lib/node.js
CHANGED
|
@@ -28,22 +28,28 @@
|
|
|
28
28
|
// where we need to quickly find all instances of a given package name within a
|
|
29
29
|
// tree.
|
|
30
30
|
|
|
31
|
-
const
|
|
31
|
+
const PackageJson = require('@npmcli/package-json')
|
|
32
32
|
const nameFromFolder = require('@npmcli/name-from-folder')
|
|
33
|
+
const npa = require('npm-package-arg')
|
|
34
|
+
const semver = require('semver')
|
|
35
|
+
const util = require('node:util')
|
|
36
|
+
const { getPaths: getBinPaths } = require('bin-links')
|
|
37
|
+
const { log } = require('proc-log')
|
|
38
|
+
const { resolve, relative, dirname, basename } = require('node:path')
|
|
39
|
+
const { walkUp } = require('walk-up-path')
|
|
40
|
+
|
|
41
|
+
const CaseInsensitiveMap = require('./case-insensitive-map.js')
|
|
33
42
|
const Edge = require('./edge.js')
|
|
34
43
|
const Inventory = require('./inventory.js')
|
|
35
44
|
const OverrideSet = require('./override-set.js')
|
|
36
|
-
const
|
|
37
|
-
const { getPaths: getBinPaths } = require('bin-links')
|
|
38
|
-
const npa = require('npm-package-arg')
|
|
45
|
+
const consistentResolve = require('./consistent-resolve.js')
|
|
39
46
|
const debug = require('./debug.js')
|
|
40
47
|
const gatherDepSet = require('./gather-dep-set.js')
|
|
48
|
+
const printableTree = require('./printable.js')
|
|
49
|
+
const querySelectorAll = require('./query-selector-all.js')
|
|
50
|
+
const relpath = require('./relpath.js')
|
|
41
51
|
const treeCheck = require('./tree-check.js')
|
|
42
|
-
const { walkUp } = require('walk-up-path')
|
|
43
|
-
const { log } = require('proc-log')
|
|
44
52
|
|
|
45
|
-
const { resolve, relative, dirname, basename } = require('node:path')
|
|
46
|
-
const util = require('node:util')
|
|
47
53
|
const _package = Symbol('_package')
|
|
48
54
|
const _parent = Symbol('_parent')
|
|
49
55
|
const _target = Symbol.for('_target')
|
|
@@ -58,14 +64,6 @@ const _delistFromMeta = Symbol.for('_delistFromMeta')
|
|
|
58
64
|
const _explain = Symbol('_explain')
|
|
59
65
|
const _explanation = Symbol('_explanation')
|
|
60
66
|
|
|
61
|
-
const relpath = require('./relpath.js')
|
|
62
|
-
const consistentResolve = require('./consistent-resolve.js')
|
|
63
|
-
|
|
64
|
-
const printableTree = require('./printable.js')
|
|
65
|
-
const CaseInsensitiveMap = require('./case-insensitive-map.js')
|
|
66
|
-
|
|
67
|
-
const querySelectorAll = require('./query-selector-all.js')
|
|
68
|
-
|
|
69
67
|
class Node {
|
|
70
68
|
#global
|
|
71
69
|
#meta
|
|
@@ -121,14 +119,25 @@ class Node {
|
|
|
121
119
|
// package's dependencies in a virtual root.
|
|
122
120
|
this.sourceReference = sourceReference
|
|
123
121
|
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
122
|
+
// have to set the internal package ref before assigning the parent, because this.package is read when adding to inventory
|
|
123
|
+
if (sourceReference) {
|
|
124
|
+
this[_package] = sourceReference.package
|
|
125
|
+
} else {
|
|
126
|
+
// TODO if this came from pacote.manifest we don't have to do this, we can be told to skip this step
|
|
127
|
+
const pkg = new PackageJson()
|
|
128
|
+
let content = {}
|
|
129
|
+
// TODO this is overly guarded. If pkg is not an object we should not allow it at all.
|
|
130
|
+
if (options.pkg && typeof options.pkg === 'object') {
|
|
131
|
+
content = options.pkg
|
|
132
|
+
}
|
|
133
|
+
pkg.fromContent(content)
|
|
134
|
+
pkg.syncNormalize()
|
|
135
|
+
this[_package] = pkg.content
|
|
136
|
+
}
|
|
128
137
|
|
|
129
138
|
this.name = name ||
|
|
130
|
-
nameFromFolder(path ||
|
|
131
|
-
|
|
139
|
+
nameFromFolder(path || this.package.name || realpath) ||
|
|
140
|
+
this.package.name ||
|
|
132
141
|
null
|
|
133
142
|
|
|
134
143
|
// should be equal if not a link
|
|
@@ -156,13 +165,13 @@ class Node {
|
|
|
156
165
|
// probably what we're getting from pacote, which IS trustworthy.
|
|
157
166
|
//
|
|
158
167
|
// Otherwise, hopefully a shrinkwrap will help us out.
|
|
159
|
-
const resolved = consistentResolve(
|
|
160
|
-
if (resolved && !(/^file:/.test(resolved) &&
|
|
168
|
+
const resolved = consistentResolve(this.package._resolved)
|
|
169
|
+
if (resolved && !(/^file:/.test(resolved) && this.package._where)) {
|
|
161
170
|
this.resolved = resolved
|
|
162
171
|
}
|
|
163
172
|
}
|
|
164
|
-
this.integrity = integrity ||
|
|
165
|
-
this.hasShrinkwrap = hasShrinkwrap ||
|
|
173
|
+
this.integrity = integrity || this.package._integrity || null
|
|
174
|
+
this.hasShrinkwrap = hasShrinkwrap || this.package._hasShrinkwrap || false
|
|
166
175
|
this.installLinks = installLinks
|
|
167
176
|
this.legacyPeerDeps = legacyPeerDeps
|
|
168
177
|
|
|
@@ -203,17 +212,13 @@ class Node {
|
|
|
203
212
|
this.edgesIn = new Set()
|
|
204
213
|
this.edgesOut = new CaseInsensitiveMap()
|
|
205
214
|
|
|
206
|
-
// have to set the internal package ref before assigning the parent,
|
|
207
|
-
// because this.package is read when adding to inventory
|
|
208
|
-
this[_package] = pkg && typeof pkg === 'object' ? pkg : {}
|
|
209
|
-
|
|
210
215
|
if (overrides) {
|
|
211
216
|
this.overrides = overrides
|
|
212
217
|
} else if (loadOverrides) {
|
|
213
|
-
const overrides = this
|
|
218
|
+
const overrides = this.package.overrides || {}
|
|
214
219
|
if (Object.keys(overrides).length > 0) {
|
|
215
220
|
this.overrides = new OverrideSet({
|
|
216
|
-
overrides: this
|
|
221
|
+
overrides: this.package.overrides,
|
|
217
222
|
})
|
|
218
223
|
}
|
|
219
224
|
}
|
|
@@ -314,7 +319,7 @@ class Node {
|
|
|
314
319
|
}
|
|
315
320
|
|
|
316
321
|
return getBinPaths({
|
|
317
|
-
pkg: this
|
|
322
|
+
pkg: this.package,
|
|
318
323
|
path: this.path,
|
|
319
324
|
global: this.global,
|
|
320
325
|
top: this.globalTop,
|
|
@@ -328,11 +333,11 @@ class Node {
|
|
|
328
333
|
}
|
|
329
334
|
|
|
330
335
|
get version () {
|
|
331
|
-
return this
|
|
336
|
+
return this.package.version || ''
|
|
332
337
|
}
|
|
333
338
|
|
|
334
339
|
get packageName () {
|
|
335
|
-
return this
|
|
340
|
+
return this.package.name || null
|
|
336
341
|
}
|
|
337
342
|
|
|
338
343
|
get pkgid () {
|
|
@@ -490,6 +495,18 @@ class Node {
|
|
|
490
495
|
}
|
|
491
496
|
|
|
492
497
|
shouldOmit (omitSet) {
|
|
498
|
+
if (!omitSet.size) {
|
|
499
|
+
return false
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const { top } = this
|
|
503
|
+
|
|
504
|
+
// if the top is not the root or workspace then we do not want to omit it
|
|
505
|
+
if (!top.isProjectRoot && !top.isWorkspace) {
|
|
506
|
+
return false
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// omit node if the dep type matches any omit flags that were set
|
|
493
510
|
return (
|
|
494
511
|
this.peer && omitSet.has('peer') ||
|
|
495
512
|
this.dev && omitSet.has('dev') ||
|
package/package.json
CHANGED
|
@@ -1,38 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@npmcli/arborist",
|
|
3
|
-
"version": "9.1.
|
|
3
|
+
"version": "9.1.5",
|
|
4
4
|
"description": "Manage node_modules trees",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@isaacs/string-locale-compare": "^1.1.0",
|
|
7
7
|
"@npmcli/fs": "^4.0.0",
|
|
8
8
|
"@npmcli/installed-package-contents": "^3.0.0",
|
|
9
|
-
"@npmcli/map-workspaces": "^
|
|
10
|
-
"@npmcli/metavuln-calculator": "^9.0.
|
|
9
|
+
"@npmcli/map-workspaces": "^5.0.0",
|
|
10
|
+
"@npmcli/metavuln-calculator": "^9.0.2",
|
|
11
11
|
"@npmcli/name-from-folder": "^3.0.0",
|
|
12
12
|
"@npmcli/node-gyp": "^4.0.0",
|
|
13
|
-
"@npmcli/package-json": "^
|
|
13
|
+
"@npmcli/package-json": "^7.0.0",
|
|
14
14
|
"@npmcli/query": "^4.0.0",
|
|
15
15
|
"@npmcli/redact": "^3.0.0",
|
|
16
|
-
"@npmcli/run-script": "^
|
|
16
|
+
"@npmcli/run-script": "^10.0.0",
|
|
17
17
|
"bin-links": "^5.0.0",
|
|
18
|
-
"cacache": "^
|
|
18
|
+
"cacache": "^20.0.1",
|
|
19
19
|
"common-ancestor-path": "^1.0.1",
|
|
20
|
-
"hosted-git-info": "^
|
|
20
|
+
"hosted-git-info": "^9.0.0",
|
|
21
21
|
"json-stringify-nice": "^1.1.4",
|
|
22
|
-
"lru-cache": "^
|
|
23
|
-
"minimatch": "^
|
|
22
|
+
"lru-cache": "^11.2.1",
|
|
23
|
+
"minimatch": "^10.0.3",
|
|
24
24
|
"nopt": "^8.0.0",
|
|
25
25
|
"npm-install-checks": "^7.1.0",
|
|
26
|
-
"npm-package-arg": "^
|
|
27
|
-
"npm-pick-manifest": "^
|
|
28
|
-
"npm-registry-fetch": "^
|
|
29
|
-
"pacote": "^21.0.
|
|
26
|
+
"npm-package-arg": "^13.0.0",
|
|
27
|
+
"npm-pick-manifest": "^11.0.1",
|
|
28
|
+
"npm-registry-fetch": "^19.0.0",
|
|
29
|
+
"pacote": "^21.0.2",
|
|
30
30
|
"parse-conflict-json": "^4.0.0",
|
|
31
31
|
"proc-log": "^5.0.0",
|
|
32
32
|
"proggy": "^3.0.0",
|
|
33
33
|
"promise-all-reject-late": "^1.0.0",
|
|
34
34
|
"promise-call-limit": "^3.0.1",
|
|
35
|
-
"read-package-json-fast": "^4.0.0",
|
|
36
35
|
"semver": "^7.3.7",
|
|
37
36
|
"ssri": "^12.0.0",
|
|
38
37
|
"treeverse": "^3.0.0",
|
|
@@ -41,7 +40,7 @@
|
|
|
41
40
|
"devDependencies": {
|
|
42
41
|
"@npmcli/eslint-config": "^5.0.1",
|
|
43
42
|
"@npmcli/mock-registry": "^1.0.0",
|
|
44
|
-
"@npmcli/template-oss": "4.
|
|
43
|
+
"@npmcli/template-oss": "4.25.1",
|
|
45
44
|
"benchmark": "^2.1.4",
|
|
46
45
|
"minify-registry-metadata": "^4.0.0",
|
|
47
46
|
"nock": "^13.3.3",
|
|
@@ -93,7 +92,7 @@
|
|
|
93
92
|
},
|
|
94
93
|
"templateOSS": {
|
|
95
94
|
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
|
|
96
|
-
"version": "4.
|
|
95
|
+
"version": "4.25.1",
|
|
97
96
|
"content": "../../scripts/template-oss/index.js"
|
|
98
97
|
}
|
|
99
98
|
}
|