@npmcli/arborist 5.6.0 → 5.6.1
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/index.js +1 -0
- package/lib/add-rm-pkg-deps.js +62 -69
- package/lib/arborist/build-ideal-tree.js +75 -121
- package/lib/arborist/index.js +1 -1
- package/lib/arborist/load-actual.js +1 -0
- package/lib/arborist/rebuild.js +3 -0
- package/lib/arborist/reify.js +39 -43
- package/lib/audit-report.js +2 -0
- package/lib/link.js +1 -0
- package/lib/node.js +2 -1
- package/lib/shrinkwrap.js +33 -29
- package/lib/signal-handling.js +6 -2
- package/lib/spec-from-lock.js +4 -2
- package/package.json +8 -8
package/bin/index.js
CHANGED
package/lib/add-rm-pkg-deps.js
CHANGED
|
@@ -4,8 +4,67 @@ const log = require('proc-log')
|
|
|
4
4
|
const localeCompare = require('@isaacs/string-locale-compare')('en')
|
|
5
5
|
|
|
6
6
|
const add = ({ pkg, add, saveBundle, saveType }) => {
|
|
7
|
-
for (const
|
|
8
|
-
|
|
7
|
+
for (const { name, rawSpec } of add) {
|
|
8
|
+
// if the user does not give us a type, we infer which type(s)
|
|
9
|
+
// to keep based on the same order of priority we do when
|
|
10
|
+
// building the tree as defined in the _loadDeps method of
|
|
11
|
+
// the node class.
|
|
12
|
+
if (!saveType) {
|
|
13
|
+
saveType = inferSaveType(pkg, name)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (saveType === 'prod') {
|
|
17
|
+
// a production dependency can only exist as production (rpj ensures it
|
|
18
|
+
// doesn't coexist w/ optional)
|
|
19
|
+
deleteSubKey(pkg, 'devDependencies', name, 'dependencies')
|
|
20
|
+
deleteSubKey(pkg, 'peerDependencies', name, 'dependencies')
|
|
21
|
+
} else if (saveType === 'dev') {
|
|
22
|
+
// a dev dependency may co-exist as peer, or optional, but not production
|
|
23
|
+
deleteSubKey(pkg, 'dependencies', name, 'devDependencies')
|
|
24
|
+
} else if (saveType === 'optional') {
|
|
25
|
+
// an optional dependency may co-exist as dev (rpj ensures it doesn't
|
|
26
|
+
// coexist w/ prod)
|
|
27
|
+
deleteSubKey(pkg, 'peerDependencies', name, 'optionalDependencies')
|
|
28
|
+
} else { // peer or peerOptional is all that's left
|
|
29
|
+
// a peer dependency may coexist as dev
|
|
30
|
+
deleteSubKey(pkg, 'dependencies', name, 'peerDependencies')
|
|
31
|
+
deleteSubKey(pkg, 'optionalDependencies', name, 'peerDependencies')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const depType = saveTypeMap.get(saveType)
|
|
35
|
+
|
|
36
|
+
pkg[depType] = pkg[depType] || {}
|
|
37
|
+
if (rawSpec !== '' || pkg[depType][name] === undefined) {
|
|
38
|
+
pkg[depType][name] = rawSpec || '*'
|
|
39
|
+
}
|
|
40
|
+
if (saveType === 'optional') {
|
|
41
|
+
// Affordance for previous npm versions that require this behaviour
|
|
42
|
+
pkg.dependencies = pkg.dependencies || {}
|
|
43
|
+
pkg.dependencies[name] = pkg.optionalDependencies[name]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (saveType === 'peer' || saveType === 'peerOptional') {
|
|
47
|
+
const pdm = pkg.peerDependenciesMeta || {}
|
|
48
|
+
if (saveType === 'peer' && pdm[name] && pdm[name].optional) {
|
|
49
|
+
pdm[name].optional = false
|
|
50
|
+
} else if (saveType === 'peerOptional') {
|
|
51
|
+
pdm[name] = pdm[name] || {}
|
|
52
|
+
pdm[name].optional = true
|
|
53
|
+
pkg.peerDependenciesMeta = pdm
|
|
54
|
+
}
|
|
55
|
+
// peerDeps are often also a devDep, so that they can be tested when
|
|
56
|
+
// using package managers that don't auto-install peer deps
|
|
57
|
+
if (pkg.devDependencies && pkg.devDependencies[name] !== undefined) {
|
|
58
|
+
pkg.devDependencies[name] = pkg.peerDependencies[name]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (saveBundle && saveType !== 'peer' && saveType !== 'peerOptional') {
|
|
63
|
+
// keep it sorted, keep it unique
|
|
64
|
+
const bd = new Set(pkg.bundleDependencies || [])
|
|
65
|
+
bd.add(name)
|
|
66
|
+
pkg.bundleDependencies = [...bd].sort(localeCompare)
|
|
67
|
+
}
|
|
9
68
|
}
|
|
10
69
|
|
|
11
70
|
return pkg
|
|
@@ -21,71 +80,6 @@ const saveTypeMap = new Map([
|
|
|
21
80
|
['peer', 'peerDependencies'],
|
|
22
81
|
])
|
|
23
82
|
|
|
24
|
-
const addSingle = ({ pkg, spec, saveBundle, saveType }) => {
|
|
25
|
-
const { name, rawSpec } = spec
|
|
26
|
-
|
|
27
|
-
// if the user does not give us a type, we infer which type(s)
|
|
28
|
-
// to keep based on the same order of priority we do when
|
|
29
|
-
// building the tree as defined in the _loadDeps method of
|
|
30
|
-
// the node class.
|
|
31
|
-
if (!saveType) {
|
|
32
|
-
saveType = inferSaveType(pkg, spec.name)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (saveType === 'prod') {
|
|
36
|
-
// a production dependency can only exist as production (rpj ensures it
|
|
37
|
-
// doesn't coexist w/ optional)
|
|
38
|
-
deleteSubKey(pkg, 'devDependencies', name, 'dependencies')
|
|
39
|
-
deleteSubKey(pkg, 'peerDependencies', name, 'dependencies')
|
|
40
|
-
} else if (saveType === 'dev') {
|
|
41
|
-
// a dev dependency may co-exist as peer, or optional, but not production
|
|
42
|
-
deleteSubKey(pkg, 'dependencies', name, 'devDependencies')
|
|
43
|
-
} else if (saveType === 'optional') {
|
|
44
|
-
// an optional dependency may co-exist as dev (rpj ensures it doesn't
|
|
45
|
-
// coexist w/ prod)
|
|
46
|
-
deleteSubKey(pkg, 'peerDependencies', name, 'optionalDependencies')
|
|
47
|
-
} else { // peer or peerOptional is all that's left
|
|
48
|
-
// a peer dependency may coexist as dev
|
|
49
|
-
deleteSubKey(pkg, 'dependencies', name, 'peerDependencies')
|
|
50
|
-
deleteSubKey(pkg, 'optionalDependencies', name, 'peerDependencies')
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const depType = saveTypeMap.get(saveType)
|
|
54
|
-
|
|
55
|
-
pkg[depType] = pkg[depType] || {}
|
|
56
|
-
if (rawSpec !== '' || pkg[depType][name] === undefined) {
|
|
57
|
-
pkg[depType][name] = rawSpec || '*'
|
|
58
|
-
}
|
|
59
|
-
if (saveType === 'optional') {
|
|
60
|
-
// Affordance for previous npm versions that require this behaviour
|
|
61
|
-
pkg.dependencies = pkg.dependencies || {}
|
|
62
|
-
pkg.dependencies[name] = pkg.optionalDependencies[name]
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (saveType === 'peer' || saveType === 'peerOptional') {
|
|
66
|
-
const pdm = pkg.peerDependenciesMeta || {}
|
|
67
|
-
if (saveType === 'peer' && pdm[name] && pdm[name].optional) {
|
|
68
|
-
pdm[name].optional = false
|
|
69
|
-
} else if (saveType === 'peerOptional') {
|
|
70
|
-
pdm[name] = pdm[name] || {}
|
|
71
|
-
pdm[name].optional = true
|
|
72
|
-
pkg.peerDependenciesMeta = pdm
|
|
73
|
-
}
|
|
74
|
-
// peerDeps are often also a devDep, so that they can be tested when
|
|
75
|
-
// using package managers that don't auto-install peer deps
|
|
76
|
-
if (pkg.devDependencies && pkg.devDependencies[name] !== undefined) {
|
|
77
|
-
pkg.devDependencies[name] = pkg.peerDependencies[name]
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (saveBundle && saveType !== 'peer' && saveType !== 'peerOptional') {
|
|
82
|
-
// keep it sorted, keep it unique
|
|
83
|
-
const bd = new Set(pkg.bundleDependencies || [])
|
|
84
|
-
bd.add(spec.name)
|
|
85
|
-
pkg.bundleDependencies = [...bd].sort(localeCompare)
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
83
|
// Finds where the package is already in the spec and infers saveType from that
|
|
90
84
|
const inferSaveType = (pkg, name) => {
|
|
91
85
|
for (const saveType of saveTypeMap.keys()) {
|
|
@@ -103,9 +97,8 @@ const inferSaveType = (pkg, name) => {
|
|
|
103
97
|
return 'prod'
|
|
104
98
|
}
|
|
105
99
|
|
|
106
|
-
const { hasOwnProperty } = Object.prototype
|
|
107
100
|
const hasSubKey = (pkg, depType, name) => {
|
|
108
|
-
return pkg[depType] && hasOwnProperty.call(pkg[depType], name)
|
|
101
|
+
return pkg[depType] && Object.prototype.hasOwnProperty.call(pkg[depType], name)
|
|
109
102
|
}
|
|
110
103
|
|
|
111
104
|
// Removes a subkey and warns about it if it's being replaced
|
|
@@ -81,18 +81,11 @@ const _linkNodes = Symbol('linkNodes')
|
|
|
81
81
|
const _follow = Symbol('follow')
|
|
82
82
|
const _globalStyle = Symbol('globalStyle')
|
|
83
83
|
const _globalRootNode = Symbol('globalRootNode')
|
|
84
|
-
const _isVulnerable = Symbol.for('isVulnerable')
|
|
85
84
|
const _usePackageLock = Symbol.for('usePackageLock')
|
|
86
85
|
const _rpcache = Symbol.for('realpathCache')
|
|
87
86
|
const _stcache = Symbol.for('statCache')
|
|
88
|
-
const _updateFilePath = Symbol('updateFilePath')
|
|
89
|
-
const _followSymlinkPath = Symbol('followSymlinkPath')
|
|
90
|
-
const _getRelpathSpec = Symbol('getRelpathSpec')
|
|
91
|
-
const _retrieveSpecName = Symbol('retrieveSpecName')
|
|
92
87
|
const _strictPeerDeps = Symbol('strictPeerDeps')
|
|
93
88
|
const _checkEngineAndPlatform = Symbol('checkEngineAndPlatform')
|
|
94
|
-
const _checkEngine = Symbol('checkEngine')
|
|
95
|
-
const _checkPlatform = Symbol('checkPlatform')
|
|
96
89
|
const _virtualRoots = Symbol('virtualRoots')
|
|
97
90
|
const _virtualRoot = Symbol('virtualRoot')
|
|
98
91
|
const _includeWorkspaceRoot = Symbol.for('includeWorkspaceRoot')
|
|
@@ -228,34 +221,22 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
228
221
|
}
|
|
229
222
|
|
|
230
223
|
async [_checkEngineAndPlatform] () {
|
|
224
|
+
const { engineStrict, npmVersion, nodeVersion } = this.options
|
|
231
225
|
for (const node of this.idealTree.inventory.values()) {
|
|
232
226
|
if (!node.optional) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
checkEngine(node.package, npmVersion, nodeVersion, this[_force])
|
|
247
|
-
|
|
248
|
-
if (engineStrict) {
|
|
249
|
-
c()
|
|
250
|
-
} else {
|
|
251
|
-
try {
|
|
252
|
-
c()
|
|
253
|
-
} catch (er) {
|
|
254
|
-
log.warn(er.code, er.message, {
|
|
255
|
-
package: er.pkgid,
|
|
256
|
-
required: er.required,
|
|
257
|
-
current: er.current,
|
|
258
|
-
})
|
|
227
|
+
try {
|
|
228
|
+
checkEngine(node.package, npmVersion, nodeVersion, this[_force])
|
|
229
|
+
} catch (err) {
|
|
230
|
+
if (engineStrict) {
|
|
231
|
+
throw err
|
|
232
|
+
}
|
|
233
|
+
log.warn(err.code, err.message, {
|
|
234
|
+
package: err.pkgid,
|
|
235
|
+
required: err.required,
|
|
236
|
+
current: err.current,
|
|
237
|
+
})
|
|
238
|
+
}
|
|
239
|
+
checkPlatform(node.package, this[_force])
|
|
259
240
|
}
|
|
260
241
|
}
|
|
261
242
|
}
|
|
@@ -378,6 +359,7 @@ Try using the package name instead, e.g:
|
|
|
378
359
|
this.idealTree = tree
|
|
379
360
|
this.virtualTree = null
|
|
380
361
|
process.emit('timeEnd', 'idealTree:init')
|
|
362
|
+
return tree
|
|
381
363
|
})
|
|
382
364
|
}
|
|
383
365
|
|
|
@@ -529,84 +511,59 @@ Try using the package name instead, e.g:
|
|
|
529
511
|
this[_depsQueue].push(tree)
|
|
530
512
|
}
|
|
531
513
|
|
|
532
|
-
// This returns a promise because we might not have the name yet,
|
|
533
|
-
//
|
|
534
|
-
[_add] (tree, { add, saveType = null, saveBundle = false }) {
|
|
535
|
-
//
|
|
536
|
-
|
|
537
|
-
// but if it's a url or git, we don't know the name until we
|
|
538
|
-
// fetch it and look in its manifest.
|
|
539
|
-
return Promise.all(add.map(async rawSpec => {
|
|
540
|
-
// We do NOT provide the path to npa here, because user-additions
|
|
541
|
-
// need to be resolved relative to the CWD the user is in.
|
|
542
|
-
const spec = await this[_retrieveSpecName](npa(rawSpec))
|
|
543
|
-
.then(spec => this[_updateFilePath](spec))
|
|
544
|
-
.then(spec => this[_followSymlinkPath](spec))
|
|
545
|
-
spec.tree = tree
|
|
546
|
-
return spec
|
|
547
|
-
})).then(add => {
|
|
548
|
-
this[_resolvedAdd].push(...add)
|
|
549
|
-
// now add is a list of spec objects with names.
|
|
550
|
-
// find a home for each of them!
|
|
551
|
-
addRmPkgDeps.add({
|
|
552
|
-
pkg: tree.package,
|
|
553
|
-
add,
|
|
554
|
-
saveBundle,
|
|
555
|
-
saveType,
|
|
556
|
-
path: this.path,
|
|
557
|
-
})
|
|
558
|
-
})
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
async [_retrieveSpecName] (spec) {
|
|
562
|
-
// if it's just @'' then we reload whatever's there, or get latest
|
|
563
|
-
// if it's an explicit tag, we need to install that specific tag version
|
|
564
|
-
const isTag = spec.rawSpec && spec.type === 'tag'
|
|
565
|
-
|
|
566
|
-
if (spec.name && !isTag) {
|
|
567
|
-
return spec
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
const mani = await pacote.manifest(spec, { ...this.options })
|
|
571
|
-
// if it's a tag type, then we need to run it down to an actual version
|
|
572
|
-
if (isTag) {
|
|
573
|
-
return npa(`${mani.name}@${mani.version}`)
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
spec.name = mani.name
|
|
577
|
-
return spec
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
async [_updateFilePath] (spec) {
|
|
581
|
-
if (spec.type === 'file') {
|
|
582
|
-
return this[_getRelpathSpec](spec, spec.fetchSpec)
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
return spec
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
async [_followSymlinkPath] (spec) {
|
|
589
|
-
if (spec.type === 'directory') {
|
|
590
|
-
const real = await (
|
|
591
|
-
realpath(spec.fetchSpec, this[_rpcache], this[_stcache])
|
|
592
|
-
// TODO: create synthetic test case to simulate realpath failure
|
|
593
|
-
.catch(/* istanbul ignore next */() => null)
|
|
594
|
-
)
|
|
514
|
+
// This returns a promise because we might not have the name yet, and need to
|
|
515
|
+
// call pacote.manifest to find the name.
|
|
516
|
+
async [_add] (tree, { add, saveType = null, saveBundle = false }) {
|
|
517
|
+
// If we have a link it will need to be added relative to the target's path
|
|
518
|
+
const path = tree.target.path
|
|
595
519
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
520
|
+
// get the name for each of the specs in the list.
|
|
521
|
+
// ie, doing `foo@bar` we just return foo but if it's a url or git, we
|
|
522
|
+
// don't know the name until we fetch it and look in its manifest.
|
|
523
|
+
await Promise.all(add.map(async rawSpec => {
|
|
524
|
+
// We do NOT provide the path to npa here, because user-additions need to
|
|
525
|
+
// be resolved relative to the tree being added to.
|
|
526
|
+
let spec = npa(rawSpec)
|
|
527
|
+
|
|
528
|
+
// if it's just @'' then we reload whatever's there, or get latest
|
|
529
|
+
// if it's an explicit tag, we need to install that specific tag version
|
|
530
|
+
const isTag = spec.rawSpec && spec.type === 'tag'
|
|
531
|
+
|
|
532
|
+
// look up the names of file/directory/git specs
|
|
533
|
+
if (!spec.name || isTag) {
|
|
534
|
+
const mani = await pacote.manifest(spec, { ...this.options })
|
|
535
|
+
if (isTag) {
|
|
536
|
+
// translate tag to a version
|
|
537
|
+
spec = npa(`${mani.name}@${mani.version}`)
|
|
538
|
+
}
|
|
539
|
+
spec.name = mani.name
|
|
540
|
+
}
|
|
600
541
|
|
|
601
|
-
[_getRelpathSpec] (spec, filepath) {
|
|
602
|
-
/* istanbul ignore else - should also be covered by realpath failure */
|
|
603
|
-
if (filepath) {
|
|
604
542
|
const { name } = spec
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
543
|
+
if (spec.type === 'file') {
|
|
544
|
+
spec = npa(`file:${relpath(path, spec.fetchSpec).replace(/#/g, '%23')}`, path)
|
|
545
|
+
spec.name = name
|
|
546
|
+
} else if (spec.type === 'directory') {
|
|
547
|
+
try {
|
|
548
|
+
const real = await realpath(spec.fetchSpec, this[_rpcache], this[_stcache])
|
|
549
|
+
spec = npa(`file:${relpath(path, real).replace(/#/g, '%23')}`, path)
|
|
550
|
+
spec.name = name
|
|
551
|
+
} catch {
|
|
552
|
+
// TODO: create synthetic test case to simulate realpath failure
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
spec.tree = tree
|
|
556
|
+
this[_resolvedAdd].push(spec)
|
|
557
|
+
}))
|
|
558
|
+
|
|
559
|
+
// now this._resolvedAdd is a list of spec objects with names.
|
|
560
|
+
// find a home for each of them!
|
|
561
|
+
addRmPkgDeps.add({
|
|
562
|
+
pkg: tree.package,
|
|
563
|
+
add: this[_resolvedAdd],
|
|
564
|
+
saveBundle,
|
|
565
|
+
saveType,
|
|
566
|
+
})
|
|
610
567
|
}
|
|
611
568
|
|
|
612
569
|
// TODO: provide a way to fix bundled deps by exposing metadata about
|
|
@@ -686,10 +643,6 @@ Try using the package name instead, e.g:
|
|
|
686
643
|
}
|
|
687
644
|
}
|
|
688
645
|
|
|
689
|
-
[_isVulnerable] (node) {
|
|
690
|
-
return this.auditReport && this.auditReport.isVulnerable(node)
|
|
691
|
-
}
|
|
692
|
-
|
|
693
646
|
[_avoidRange] (name) {
|
|
694
647
|
if (!this.auditReport) {
|
|
695
648
|
return null
|
|
@@ -781,17 +734,18 @@ This is a one-time fix-up, please be patient...
|
|
|
781
734
|
const spec = npa.resolve(name, id, dirname(path))
|
|
782
735
|
const t = `idealTree:inflate:${location}`
|
|
783
736
|
this.addTracker(t)
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
737
|
+
try {
|
|
738
|
+
const mani = await pacote.manifest(spec, {
|
|
739
|
+
...this.options,
|
|
740
|
+
resolved: resolved,
|
|
741
|
+
integrity: integrity,
|
|
742
|
+
fullMetadata: false,
|
|
743
|
+
})
|
|
790
744
|
node.package = { ...mani, _id: `${mani.name}@${mani.version}` }
|
|
791
|
-
}
|
|
745
|
+
} catch (er) {
|
|
792
746
|
const warning = `Could not fetch metadata for ${name}@${id}`
|
|
793
747
|
log.warn(heading, warning, er)
|
|
794
|
-
}
|
|
748
|
+
}
|
|
795
749
|
this.finishTracker(t)
|
|
796
750
|
})
|
|
797
751
|
}
|
|
@@ -1233,7 +1187,7 @@ This is a one-time fix-up, please be patient...
|
|
|
1233
1187
|
}
|
|
1234
1188
|
|
|
1235
1189
|
// fixing a security vulnerability with this package, problem
|
|
1236
|
-
if (this
|
|
1190
|
+
if (this.auditReport && this.auditReport.isVulnerable(edge.to)) {
|
|
1237
1191
|
return true
|
|
1238
1192
|
}
|
|
1239
1193
|
|
package/lib/arborist/index.js
CHANGED
|
@@ -134,7 +134,7 @@ class Arborist extends Base {
|
|
|
134
134
|
return wsDepSet
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
// returns a set of root dependencies, excluding
|
|
137
|
+
// returns a set of root dependencies, excluding dependencies that are
|
|
138
138
|
// exclusively workspace dependencies
|
|
139
139
|
excludeWorkspacesDependencySet (tree) {
|
|
140
140
|
const rootDepSet = new Set()
|
|
@@ -347,6 +347,7 @@ module.exports = cls => class ActualLoader extends cls {
|
|
|
347
347
|
// node_modules hierarchy, then load that node as well.
|
|
348
348
|
return this[_loadFSTree](link.target).then(() => link)
|
|
349
349
|
} else if (target.then) {
|
|
350
|
+
// eslint-disable-next-line promise/catch-or-return
|
|
350
351
|
target.then(node => link.target = node)
|
|
351
352
|
}
|
|
352
353
|
|
package/lib/arborist/rebuild.js
CHANGED
|
@@ -359,6 +359,9 @@ module.exports = cls => class Builder extends cls {
|
|
|
359
359
|
pkg,
|
|
360
360
|
path,
|
|
361
361
|
event,
|
|
362
|
+
// I do not know why this needs to be on THIS line but refactoring
|
|
363
|
+
// this function would be quite a process
|
|
364
|
+
// eslint-disable-next-line promise/always-return
|
|
362
365
|
cmd: args && args[args.length - 1],
|
|
363
366
|
env,
|
|
364
367
|
code,
|
package/lib/arborist/reify.js
CHANGED
|
@@ -69,7 +69,6 @@ const _symlink = Symbol('symlink')
|
|
|
69
69
|
const _warnDeprecated = Symbol('warnDeprecated')
|
|
70
70
|
const _loadBundlesAndUpdateTrees = Symbol.for('loadBundlesAndUpdateTrees')
|
|
71
71
|
const _submitQuickAudit = Symbol('submitQuickAudit')
|
|
72
|
-
const _awaitQuickAudit = Symbol('awaitQuickAudit')
|
|
73
72
|
const _unpackNewModules = Symbol.for('unpackNewModules')
|
|
74
73
|
const _moveContents = Symbol.for('moveContents')
|
|
75
74
|
const _moveBackRetiredUnchanged = Symbol.for('moveBackRetiredUnchanged')
|
|
@@ -156,7 +155,8 @@ module.exports = cls => class Reifier extends cls {
|
|
|
156
155
|
await this[_reifyPackages]()
|
|
157
156
|
await this[_saveIdealTree](options)
|
|
158
157
|
await this[_copyIdealToActual]()
|
|
159
|
-
|
|
158
|
+
// This is a very bad pattern and I can't wait to stop doing it
|
|
159
|
+
this.auditReport = await this.auditReport
|
|
160
160
|
|
|
161
161
|
this.finishTracker('reify')
|
|
162
162
|
process.emit('timeEnd', 'reify')
|
|
@@ -531,12 +531,12 @@ module.exports = cls => class Reifier extends cls {
|
|
|
531
531
|
const targets = [...roots, ...Object.keys(this[_retiredPaths])]
|
|
532
532
|
const unlinks = targets
|
|
533
533
|
.map(path => rimraf(path).catch(er => failures.push([path, er])))
|
|
534
|
-
return promiseAllRejectLate(unlinks)
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
534
|
+
return promiseAllRejectLate(unlinks).then(() => {
|
|
535
|
+
// eslint-disable-next-line promise/always-return
|
|
536
|
+
if (failures.length) {
|
|
537
|
+
log.warn('cleanup', 'Failed to remove some directories', failures)
|
|
538
|
+
}
|
|
539
|
+
})
|
|
540
540
|
.then(() => process.emit('timeEnd', 'reify:rollback:createSparse'))
|
|
541
541
|
.then(() => this[_rollbackRetireShallowNodes](er))
|
|
542
542
|
}
|
|
@@ -592,21 +592,21 @@ module.exports = cls => class Reifier extends cls {
|
|
|
592
592
|
this.addTracker('reify', node.name, node.location)
|
|
593
593
|
|
|
594
594
|
const { npmVersion, nodeVersion } = this.options
|
|
595
|
-
const p = Promise.resolve()
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
595
|
+
const p = Promise.resolve().then(async () => {
|
|
596
|
+
// when we reify an optional node, check the engine and platform
|
|
597
|
+
// first. be sure to ignore the --force and --engine-strict flags,
|
|
598
|
+
// since we always want to skip any optional packages we can't install.
|
|
599
|
+
// these checks throwing will result in a rollback and removal
|
|
600
|
+
// of the mismatches
|
|
601
|
+
// eslint-disable-next-line promise/always-return
|
|
602
|
+
if (node.optional) {
|
|
603
|
+
checkEngine(node.package, npmVersion, nodeVersion, false)
|
|
604
|
+
checkPlatform(node.package, false)
|
|
605
|
+
}
|
|
606
|
+
await this[_checkBins](node)
|
|
607
|
+
await this[_extractOrLink](node)
|
|
608
|
+
await this[_warnDeprecated](node)
|
|
609
|
+
})
|
|
610
610
|
|
|
611
611
|
return this[_handleOptionalFailure](node, p)
|
|
612
612
|
.then(() => {
|
|
@@ -916,9 +916,10 @@ module.exports = cls => class Reifier extends cls {
|
|
|
916
916
|
}
|
|
917
917
|
}
|
|
918
918
|
|
|
919
|
-
[_submitQuickAudit] () {
|
|
919
|
+
async [_submitQuickAudit] () {
|
|
920
920
|
if (this.options.audit === false) {
|
|
921
|
-
|
|
921
|
+
this.auditReport = null
|
|
922
|
+
return
|
|
922
923
|
}
|
|
923
924
|
|
|
924
925
|
// we submit the quick audit at this point in the process, as soon as
|
|
@@ -940,16 +941,10 @@ module.exports = cls => class Reifier extends cls {
|
|
|
940
941
|
)
|
|
941
942
|
}
|
|
942
943
|
|
|
943
|
-
this.auditReport = AuditReport.load(tree, options)
|
|
944
|
-
.
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
})
|
|
948
|
-
}
|
|
949
|
-
|
|
950
|
-
// return the promise if we're waiting for it, or the replaced result
|
|
951
|
-
[_awaitQuickAudit] () {
|
|
952
|
-
return this.auditReport
|
|
944
|
+
this.auditReport = AuditReport.load(tree, options).then(res => {
|
|
945
|
+
process.emit('timeEnd', 'reify:audit')
|
|
946
|
+
return res
|
|
947
|
+
})
|
|
953
948
|
}
|
|
954
949
|
|
|
955
950
|
// ok! actually unpack stuff into their target locations!
|
|
@@ -1126,7 +1121,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1126
1121
|
// remove the retired folders, and any deleted nodes
|
|
1127
1122
|
// If this fails, there isn't much we can do but tell the user about it.
|
|
1128
1123
|
// Thankfully, it's pretty unlikely that it'll fail, since rimraf is a tank.
|
|
1129
|
-
[_removeTrash] () {
|
|
1124
|
+
async [_removeTrash] () {
|
|
1130
1125
|
process.emit('time', 'reify:trash')
|
|
1131
1126
|
const promises = []
|
|
1132
1127
|
const failures = []
|
|
@@ -1136,12 +1131,11 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1136
1131
|
promises.push(rm(path))
|
|
1137
1132
|
}
|
|
1138
1133
|
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
.then(() => process.emit('timeEnd', 'reify:trash'))
|
|
1134
|
+
await promiseAllRejectLate(promises)
|
|
1135
|
+
if (failures.length) {
|
|
1136
|
+
log.warn('cleanup', 'Failed to remove some directories', failures)
|
|
1137
|
+
}
|
|
1138
|
+
process.emit('timeEnd', 'reify:trash')
|
|
1145
1139
|
}
|
|
1146
1140
|
|
|
1147
1141
|
// last but not least, we save the ideal tree metadata to the package-lock
|
|
@@ -1302,7 +1296,9 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1302
1296
|
if (semver.subset(edge.spec, node.version)) {
|
|
1303
1297
|
return false
|
|
1304
1298
|
}
|
|
1305
|
-
} catch {
|
|
1299
|
+
} catch {
|
|
1300
|
+
// ignore errors
|
|
1301
|
+
}
|
|
1306
1302
|
}
|
|
1307
1303
|
return true
|
|
1308
1304
|
}
|
package/lib/audit-report.js
CHANGED
|
@@ -175,7 +175,9 @@ class AuditReport extends Map {
|
|
|
175
175
|
} else {
|
|
176
176
|
// calculate a metavuln, if necessary
|
|
177
177
|
const calc = this.calculator.calculate(dep.packageName, advisory)
|
|
178
|
+
// eslint-disable-next-line promise/always-return
|
|
178
179
|
p.push(calc.then(meta => {
|
|
180
|
+
// eslint-disable-next-line promise/always-return
|
|
179
181
|
if (meta.testVersion(dep.version, spec)) {
|
|
180
182
|
advisories.add(meta)
|
|
181
183
|
}
|
package/lib/link.js
CHANGED
|
@@ -66,6 +66,7 @@ class Link extends Node {
|
|
|
66
66
|
// can set to a promise during an async tree build operation
|
|
67
67
|
// wait until then to assign it.
|
|
68
68
|
this[_target] = target
|
|
69
|
+
// eslint-disable-next-line promise/always-return, promise/catch-or-return
|
|
69
70
|
target.then(node => {
|
|
70
71
|
this[_target] = null
|
|
71
72
|
this.target = node
|
package/lib/node.js
CHANGED
|
@@ -564,7 +564,8 @@ class Node {
|
|
|
564
564
|
// this allows us to do new Node({...}) and then set the root later.
|
|
565
565
|
// just make the assignment so we don't lose it, and move on.
|
|
566
566
|
if (!this.path || !root.realpath || !root.path) {
|
|
567
|
-
|
|
567
|
+
this[_root] = root
|
|
568
|
+
return
|
|
568
569
|
}
|
|
569
570
|
|
|
570
571
|
// temporarily become a root node
|
package/lib/shrinkwrap.js
CHANGED
|
@@ -184,34 +184,32 @@ const assertNoNewer = async (path, data, lockTime, dir = path, seen = null) => {
|
|
|
184
184
|
? Promise.resolve([{ name: 'node_modules', isDirectory: () => true }])
|
|
185
185
|
: readdir(parent, { withFileTypes: true })
|
|
186
186
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
})))
|
|
203
|
-
.then(() => {
|
|
204
|
-
if (dir !== path) {
|
|
205
|
-
return
|
|
187
|
+
const ents = await children.catch(() => [])
|
|
188
|
+
await Promise.all(ents.map(async ent => {
|
|
189
|
+
const child = resolve(parent, ent.name)
|
|
190
|
+
if (ent.isDirectory() && !/^\./.test(ent.name)) {
|
|
191
|
+
await assertNoNewer(path, data, lockTime, child, seen)
|
|
192
|
+
} else if (ent.isSymbolicLink()) {
|
|
193
|
+
const target = resolve(parent, await readlink(child))
|
|
194
|
+
const tstat = await stat(target).catch(
|
|
195
|
+
/* istanbul ignore next - windows */ () => null)
|
|
196
|
+
seen.add(relpath(path, child))
|
|
197
|
+
/* istanbul ignore next - windows cannot do this */
|
|
198
|
+
if (tstat && tstat.isDirectory() && !seen.has(relpath(path, target))) {
|
|
199
|
+
await assertNoNewer(path, data, lockTime, target, seen)
|
|
206
200
|
}
|
|
201
|
+
}
|
|
202
|
+
}))
|
|
203
|
+
if (dir !== path) {
|
|
204
|
+
return
|
|
205
|
+
}
|
|
207
206
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
})
|
|
207
|
+
// assert that all the entries in the lockfile were seen
|
|
208
|
+
for (const loc of new Set(Object.keys(data.packages))) {
|
|
209
|
+
if (!seen.has(loc)) {
|
|
210
|
+
throw 'missing from node_modules: ' + loc
|
|
211
|
+
}
|
|
212
|
+
}
|
|
215
213
|
}
|
|
216
214
|
|
|
217
215
|
const _awaitingUpdate = Symbol('_awaitingUpdate')
|
|
@@ -261,7 +259,9 @@ class Shrinkwrap {
|
|
|
261
259
|
s.lockfileVersion = json.lockfileVersion
|
|
262
260
|
}
|
|
263
261
|
}
|
|
264
|
-
} catch
|
|
262
|
+
} catch {
|
|
263
|
+
// ignore errors
|
|
264
|
+
}
|
|
265
265
|
|
|
266
266
|
return s
|
|
267
267
|
}
|
|
@@ -442,7 +442,7 @@ class Shrinkwrap {
|
|
|
442
442
|
this.newline = newline !== undefined ? newline : this.newline
|
|
443
443
|
}
|
|
444
444
|
|
|
445
|
-
load () {
|
|
445
|
+
async load () {
|
|
446
446
|
// we don't need to load package-lock.json except for top of tree nodes,
|
|
447
447
|
// only npm-shrinkwrap.json.
|
|
448
448
|
return this[_maybeRead]().then(([sw, lock, yarn]) => {
|
|
@@ -464,7 +464,9 @@ class Shrinkwrap {
|
|
|
464
464
|
// ignore invalid yarn data. we'll likely clobber it later anyway.
|
|
465
465
|
try {
|
|
466
466
|
this.yarnLock.parse(yarn)
|
|
467
|
-
} catch
|
|
467
|
+
} catch {
|
|
468
|
+
// ignore errors
|
|
469
|
+
}
|
|
468
470
|
}
|
|
469
471
|
|
|
470
472
|
return data ? parseJSON(data) : {}
|
|
@@ -515,8 +517,10 @@ class Shrinkwrap {
|
|
|
515
517
|
!(lock.lockfileVersion >= 2) && !lock.requires
|
|
516
518
|
|
|
517
519
|
// load old lockfile deps into the packages listing
|
|
520
|
+
// eslint-disable-next-line promise/always-return
|
|
518
521
|
if (lock.dependencies && !lock.packages) {
|
|
519
522
|
return rpj(this.path + '/package.json').then(pkg => pkg, er => ({}))
|
|
523
|
+
// eslint-disable-next-line promise/always-return
|
|
520
524
|
.then(pkg => {
|
|
521
525
|
this[_loadAll]('', null, this.data)
|
|
522
526
|
this[_fixDependencies](pkg)
|
package/lib/signal-handling.js
CHANGED
|
@@ -19,7 +19,9 @@ const setup = fn => {
|
|
|
19
19
|
for (const sig of signals) {
|
|
20
20
|
try {
|
|
21
21
|
process.removeListener(sig, sigListeners[sig])
|
|
22
|
-
} catch
|
|
22
|
+
} catch {
|
|
23
|
+
// ignore errors
|
|
24
|
+
}
|
|
23
25
|
}
|
|
24
26
|
process.removeListener('beforeExit', onBeforeExit)
|
|
25
27
|
sigListeners.loaded = false
|
|
@@ -62,7 +64,9 @@ const setup = fn => {
|
|
|
62
64
|
process.setMaxListeners(length + 1)
|
|
63
65
|
}
|
|
64
66
|
process.on(sig, sigListeners[sig])
|
|
65
|
-
} catch
|
|
67
|
+
} catch {
|
|
68
|
+
// ignore errors
|
|
69
|
+
}
|
|
66
70
|
}
|
|
67
71
|
sigListeners.loaded = true
|
|
68
72
|
|
package/lib/spec-from-lock.js
CHANGED
|
@@ -21,10 +21,12 @@ const specFromLock = (name, lock, where) => {
|
|
|
21
21
|
if (lock.resolved) {
|
|
22
22
|
return npa.resolve(name, lock.resolved, where)
|
|
23
23
|
}
|
|
24
|
-
} catch
|
|
24
|
+
} catch {
|
|
25
|
+
// ignore errors
|
|
26
|
+
}
|
|
25
27
|
try {
|
|
26
28
|
return npa.resolve(name, lock.version, where)
|
|
27
|
-
} catch
|
|
29
|
+
} catch {
|
|
28
30
|
return {}
|
|
29
31
|
}
|
|
30
32
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@npmcli/arborist",
|
|
3
|
-
"version": "5.6.
|
|
3
|
+
"version": "5.6.1",
|
|
4
4
|
"description": "Manage node_modules trees",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@isaacs/string-locale-compare": "^1.1.0",
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
"@npmcli/name-from-folder": "^1.0.1",
|
|
12
12
|
"@npmcli/node-gyp": "^2.0.0",
|
|
13
13
|
"@npmcli/package-json": "^2.0.0",
|
|
14
|
-
"@npmcli/query": "^1.
|
|
14
|
+
"@npmcli/query": "^1.2.0",
|
|
15
15
|
"@npmcli/run-script": "^4.1.3",
|
|
16
|
-
"bin-links": "^3.0.
|
|
17
|
-
"cacache": "^16.
|
|
16
|
+
"bin-links": "^3.0.3",
|
|
17
|
+
"cacache": "^16.1.3",
|
|
18
18
|
"common-ancestor-path": "^1.0.1",
|
|
19
19
|
"json-parse-even-better-errors": "^2.3.1",
|
|
20
20
|
"json-stringify-nice": "^1.1.4",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"nopt": "^6.0.0",
|
|
25
25
|
"npm-install-checks": "^5.0.0",
|
|
26
26
|
"npm-package-arg": "^9.0.0",
|
|
27
|
-
"npm-pick-manifest": "^7.0.
|
|
27
|
+
"npm-pick-manifest": "^7.0.2",
|
|
28
28
|
"npm-registry-fetch": "^13.0.0",
|
|
29
29
|
"npmlog": "^6.0.2",
|
|
30
30
|
"pacote": "^13.6.1",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"walk-up-path": "^1.0.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@npmcli/eslint-config": "^3.0
|
|
45
|
-
"@npmcli/template-oss": "3.
|
|
44
|
+
"@npmcli/eslint-config": "^3.1.0",
|
|
45
|
+
"@npmcli/template-oss": "3.8.0",
|
|
46
46
|
"benchmark": "^2.1.4",
|
|
47
47
|
"chalk": "^4.1.0",
|
|
48
48
|
"minify-registry-metadata": "^2.1.0",
|
|
@@ -103,6 +103,6 @@
|
|
|
103
103
|
},
|
|
104
104
|
"templateOSS": {
|
|
105
105
|
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
|
|
106
|
-
"version": "3.
|
|
106
|
+
"version": "3.8.0"
|
|
107
107
|
}
|
|
108
108
|
}
|