@npmcli/arborist 4.0.3 → 4.1.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/LICENSE.md +20 -0
- package/README.md +3 -3
- package/bin/prune.js +1 -1
- package/bin/reify.js +1 -1
- package/lib/add-rm-pkg-deps.js +3 -3
- package/lib/arborist/build-ideal-tree.js +12 -6
- package/lib/arborist/index.js +34 -22
- package/lib/arborist/load-actual.js +25 -7
- package/lib/arborist/load-virtual.js +5 -4
- package/lib/arborist/rebuild.js +7 -7
- package/lib/arborist/reify.js +15 -11
- package/lib/audit-report.js +3 -3
- package/lib/calc-dep-flags.js +1 -1
- package/lib/can-place-dep.js +2 -2
- package/lib/dep-valid.js +1 -1
- package/lib/diff.js +7 -7
- package/lib/edge.js +38 -3
- package/lib/from-path.js +1 -1
- package/lib/link.js +1 -1
- package/lib/node.js +51 -6
- package/lib/override-set.js +123 -0
- package/lib/place-dep.js +5 -3
- package/lib/printable.js +13 -4
- package/lib/relpath.js +1 -1
- package/lib/retire-path.js +1 -1
- package/lib/shrinkwrap.js +4 -4
- package/lib/version-from-tgz.js +2 -2
- package/lib/vuln.js +1 -1
- package/lib/yarn-lock.js +2 -2
- package/package.json +20 -13
- package/LICENSE +0 -22
package/LICENSE.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<!-- This file is automatically added by @npmcli/template-oss. Do not edit. -->
|
|
2
|
+
|
|
3
|
+
ISC License
|
|
4
|
+
|
|
5
|
+
Copyright npm, Inc.
|
|
6
|
+
|
|
7
|
+
Permission to use, copy, modify, and/or distribute this
|
|
8
|
+
software for any purpose with or without fee is hereby
|
|
9
|
+
granted, provided that the above copyright notice and this
|
|
10
|
+
permission notice appear in all copies.
|
|
11
|
+
|
|
12
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND NPM DISCLAIMS ALL
|
|
13
|
+
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
|
14
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
|
|
15
|
+
EVENT SHALL NPM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
16
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
17
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|
18
|
+
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
19
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
|
|
20
|
+
USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
Inspect and manage `node_modules` trees.
|
|
4
4
|
|
|
5
|
-

|
|
5
|
+

|
|
6
6
|
|
|
7
|
-
There's more documentation [in the
|
|
8
|
-
folder](https://github.com/npm/arborist/tree/main/
|
|
7
|
+
There's more documentation [in the docs
|
|
8
|
+
folder](https://github.com/npm/arborist/tree/main/docs).
|
|
9
9
|
|
|
10
10
|
## USAGE
|
|
11
11
|
|
package/bin/prune.js
CHANGED
package/bin/reify.js
CHANGED
package/lib/add-rm-pkg-deps.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
const localeCompare = require('@isaacs/string-locale-compare')('en')
|
|
4
4
|
|
|
5
|
-
const add = ({pkg, add, saveBundle, saveType, log}) => {
|
|
5
|
+
const add = ({ pkg, add, saveBundle, saveType, log }) => {
|
|
6
6
|
for (const spec of add) {
|
|
7
|
-
addSingle({pkg, spec, saveBundle, saveType, log})
|
|
7
|
+
addSingle({ pkg, spec, saveBundle, saveType, log })
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
return pkg
|
|
@@ -20,7 +20,7 @@ const saveTypeMap = new Map([
|
|
|
20
20
|
['peer', 'peerDependencies'],
|
|
21
21
|
])
|
|
22
22
|
|
|
23
|
-
const addSingle = ({pkg, spec, saveBundle, saveType, log}) => {
|
|
23
|
+
const addSingle = ({ pkg, spec, saveBundle, saveType, log }) => {
|
|
24
24
|
const { name, rawSpec } = spec
|
|
25
25
|
|
|
26
26
|
// if the user does not give us a type, we infer which type(s)
|
|
@@ -31,7 +31,7 @@ const Node = require('../node.js')
|
|
|
31
31
|
const Link = require('../link.js')
|
|
32
32
|
const addRmPkgDeps = require('../add-rm-pkg-deps.js')
|
|
33
33
|
const optionalSet = require('../optional-set.js')
|
|
34
|
-
const {checkEngine, checkPlatform} = require('npm-install-checks')
|
|
34
|
+
const { checkEngine, checkPlatform } = require('npm-install-checks')
|
|
35
35
|
|
|
36
36
|
const relpath = require('../relpath.js')
|
|
37
37
|
|
|
@@ -311,7 +311,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
311
311
|
? Shrinkwrap.reset({
|
|
312
312
|
path: this.path,
|
|
313
313
|
lockfileVersion: this.options.lockfileVersion,
|
|
314
|
-
}).then(meta => Object.assign(root, {meta}))
|
|
314
|
+
}).then(meta => Object.assign(root, { meta }))
|
|
315
315
|
: this.loadVirtual({ root }))
|
|
316
316
|
|
|
317
317
|
// if we don't have a lockfile to go from, then start with the
|
|
@@ -379,6 +379,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
379
379
|
optional: false,
|
|
380
380
|
global: this[_global],
|
|
381
381
|
legacyPeerDeps: this.legacyPeerDeps,
|
|
382
|
+
loadOverrides: true,
|
|
382
383
|
})
|
|
383
384
|
if (root.isLink) {
|
|
384
385
|
root.target = new Node({
|
|
@@ -492,7 +493,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
492
493
|
|
|
493
494
|
// This returns a promise because we might not have the name yet,
|
|
494
495
|
// and need to call pacote.manifest to find the name.
|
|
495
|
-
[_add] (tree, {add, saveType = null, saveBundle = false}) {
|
|
496
|
+
[_add] (tree, { add, saveType = null, saveBundle = false }) {
|
|
496
497
|
// get the name for each of the specs in the list.
|
|
497
498
|
// ie, doing `foo@bar` we just return foo
|
|
498
499
|
// but if it's a url or git, we don't know the name until we
|
|
@@ -676,6 +677,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
676
677
|
// calls rather than walking over everything in the tree.
|
|
677
678
|
const set = this.idealTree.inventory
|
|
678
679
|
.filter(n => this[_shouldUpdateNode](n))
|
|
680
|
+
// XXX add any invalid edgesOut to the queue
|
|
679
681
|
for (const node of set) {
|
|
680
682
|
for (const edge of node.edgesIn) {
|
|
681
683
|
this.addTracker('idealTree', edge.from.name, edge.from.location)
|
|
@@ -772,7 +774,10 @@ This is a one-time fix-up, please be patient...
|
|
|
772
774
|
[_buildDeps] () {
|
|
773
775
|
process.emit('time', 'idealTree:buildDeps')
|
|
774
776
|
const tree = this.idealTree.target
|
|
777
|
+
tree.assertRootOverrides()
|
|
775
778
|
this[_depsQueue].push(tree)
|
|
779
|
+
// XXX also push anything that depends on a node with a name
|
|
780
|
+
// in the override list
|
|
776
781
|
this.log.silly('idealTree', 'buildDeps')
|
|
777
782
|
this.addTracker('idealTree', tree.name, '')
|
|
778
783
|
return this[_buildDepStep]()
|
|
@@ -936,7 +941,7 @@ This is a one-time fix-up, please be patient...
|
|
|
936
941
|
}
|
|
937
942
|
})
|
|
938
943
|
|
|
939
|
-
tasks.push({edge, dep})
|
|
944
|
+
tasks.push({ edge, dep })
|
|
940
945
|
}
|
|
941
946
|
|
|
942
947
|
const placeDeps = tasks
|
|
@@ -1112,6 +1117,7 @@ This is a one-time fix-up, please be patient...
|
|
|
1112
1117
|
path: node.realpath,
|
|
1113
1118
|
sourceReference: node,
|
|
1114
1119
|
legacyPeerDeps: this.legacyPeerDeps,
|
|
1120
|
+
overrides: node.overrides,
|
|
1115
1121
|
})
|
|
1116
1122
|
|
|
1117
1123
|
// also need to set up any targets from any link deps, so that
|
|
@@ -1271,7 +1277,7 @@ This is a one-time fix-up, please be patient...
|
|
|
1271
1277
|
// we typically only install non-optional peers, but we have to
|
|
1272
1278
|
// factor them into the peerSet so that we can avoid conflicts
|
|
1273
1279
|
.filter(e => e.peer && !(e.valid && e.to))
|
|
1274
|
-
.sort(({name: a}, {name: b}) => localeCompare(a, b))
|
|
1280
|
+
.sort(({ name: a }, { name: b }) => localeCompare(a, b))
|
|
1275
1281
|
|
|
1276
1282
|
for (const edge of peerEdges) {
|
|
1277
1283
|
// already placed this one, and we're happy with it.
|
|
@@ -1280,7 +1286,7 @@ This is a one-time fix-up, please be patient...
|
|
|
1280
1286
|
}
|
|
1281
1287
|
|
|
1282
1288
|
const parentEdge = node.parent.edgesOut.get(edge.name)
|
|
1283
|
-
const {isProjectRoot, isWorkspace} = node.parent.sourceReference
|
|
1289
|
+
const { isProjectRoot, isWorkspace } = node.parent.sourceReference
|
|
1284
1290
|
const isMine = isProjectRoot || isWorkspace
|
|
1285
1291
|
const conflictOK = this[_force] || !isMine && !this[_strictPeerDeps]
|
|
1286
1292
|
|
package/lib/arborist/index.js
CHANGED
|
@@ -26,9 +26,10 @@
|
|
|
26
26
|
// the base class, so that the overall voltron class is easier to test and
|
|
27
27
|
// cover, and separation of concerns can be maintained.
|
|
28
28
|
|
|
29
|
-
const {resolve} = require('path')
|
|
30
|
-
const {homedir} = require('os')
|
|
29
|
+
const { resolve } = require('path')
|
|
30
|
+
const { homedir } = require('os')
|
|
31
31
|
const procLog = require('proc-log')
|
|
32
|
+
const { depth } = require('treeverse')
|
|
32
33
|
const { saveTypeMap } = require('../add-rm-pkg-deps.js')
|
|
33
34
|
|
|
34
35
|
const mixins = [
|
|
@@ -88,6 +89,9 @@ class Arborist extends Base {
|
|
|
88
89
|
process.emit('timeEnd', 'arborist:ctor')
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
// TODO: We should change these to static functions instead
|
|
93
|
+
// of methods for the next major version
|
|
94
|
+
|
|
91
95
|
// returns an array of the actual nodes for all the workspaces
|
|
92
96
|
workspaceNodes (tree, workspaces) {
|
|
93
97
|
return getWorkspaceNodes(tree, workspaces, this.log)
|
|
@@ -103,15 +107,15 @@ class Arborist extends Base {
|
|
|
103
107
|
}
|
|
104
108
|
}
|
|
105
109
|
}
|
|
106
|
-
const
|
|
110
|
+
const wsDepSet = new Set(wsNodes)
|
|
107
111
|
const extraneous = new Set()
|
|
108
|
-
for (const node of
|
|
112
|
+
for (const node of wsDepSet) {
|
|
109
113
|
for (const edge of node.edgesOut.values()) {
|
|
110
114
|
const dep = edge.to
|
|
111
115
|
if (dep) {
|
|
112
|
-
|
|
116
|
+
wsDepSet.add(dep)
|
|
113
117
|
if (dep.isLink) {
|
|
114
|
-
|
|
118
|
+
wsDepSet.add(dep.target)
|
|
115
119
|
}
|
|
116
120
|
}
|
|
117
121
|
}
|
|
@@ -122,28 +126,36 @@ class Arborist extends Base {
|
|
|
122
126
|
}
|
|
123
127
|
}
|
|
124
128
|
for (const extra of extraneous) {
|
|
125
|
-
|
|
129
|
+
wsDepSet.add(extra)
|
|
126
130
|
}
|
|
127
131
|
|
|
128
|
-
return
|
|
132
|
+
return wsDepSet
|
|
129
133
|
}
|
|
130
134
|
|
|
135
|
+
// returns a set of root dependencies, excluding depdencies that are
|
|
136
|
+
// exclusively workspace dependencies
|
|
131
137
|
excludeWorkspacesDependencySet (tree) {
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
const rootDepSet = new Set()
|
|
139
|
+
depth({
|
|
140
|
+
tree,
|
|
141
|
+
visit: node => {
|
|
142
|
+
for (const { to } of node.edgesOut.values()) {
|
|
143
|
+
if (!to || to.isWorkspace) {
|
|
144
|
+
continue
|
|
145
|
+
}
|
|
146
|
+
for (const edgeIn of to.edgesIn.values()) {
|
|
147
|
+
if (edgeIn.from.isRoot || rootDepSet.has(edgeIn.from)) {
|
|
148
|
+
rootDepSet.add(to)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
142
151
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
152
|
+
return node
|
|
153
|
+
},
|
|
154
|
+
filter: node => node,
|
|
155
|
+
getChildren: (node, tree) =>
|
|
156
|
+
[...tree.edgesOut.values()].map(edge => edge.to),
|
|
157
|
+
})
|
|
158
|
+
return rootDepSet
|
|
147
159
|
}
|
|
148
160
|
}
|
|
149
161
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// mix-in implementing the loadActual method
|
|
2
2
|
|
|
3
|
-
const {relative, dirname, resolve, join, normalize} = require('path')
|
|
3
|
+
const { relative, dirname, resolve, join, normalize } = require('path')
|
|
4
4
|
|
|
5
5
|
const rpj = require('read-package-json-fast')
|
|
6
|
-
const {promisify} = require('util')
|
|
6
|
+
const { promisify } = require('util')
|
|
7
7
|
const readdir = promisify(require('readdir-scoped-modules'))
|
|
8
8
|
const walkUp = require('walk-up-path')
|
|
9
9
|
const ancestorPath = require('common-ancestor-path')
|
|
@@ -127,16 +127,20 @@ module.exports = cls => class ActualLoader extends cls {
|
|
|
127
127
|
realpath: real,
|
|
128
128
|
pkg: {},
|
|
129
129
|
global,
|
|
130
|
+
loadOverrides: true,
|
|
130
131
|
})
|
|
131
|
-
return this[_loadActualActually]({root, ignoreMissing, global})
|
|
132
|
+
return this[_loadActualActually]({ root, ignoreMissing, global })
|
|
132
133
|
}
|
|
133
134
|
|
|
134
135
|
// not in global mode, hidden lockfile is allowed, load root pkg too
|
|
135
136
|
this[_actualTree] = await this[_loadFSNode]({
|
|
136
137
|
path: this.path,
|
|
137
138
|
real: await realpath(this.path, this[_rpcache], this[_stcache]),
|
|
139
|
+
loadOverrides: true,
|
|
138
140
|
})
|
|
139
141
|
|
|
142
|
+
this[_actualTree].assertRootOverrides()
|
|
143
|
+
|
|
140
144
|
// Note: hidden lockfile will be rejected if it's not the latest thing
|
|
141
145
|
// in the folder, or if any of the entries in the hidden lockfile are
|
|
142
146
|
// missing.
|
|
@@ -163,7 +167,7 @@ module.exports = cls => class ActualLoader extends cls {
|
|
|
163
167
|
// we can't easily get a ref to Arborist in this module, without
|
|
164
168
|
// creating a circular reference, since this class is a mixin used
|
|
165
169
|
// to build up the Arborist class itself.
|
|
166
|
-
await new this.constructor({...this.options}).loadVirtual({
|
|
170
|
+
await new this.constructor({ ...this.options }).loadVirtual({
|
|
167
171
|
root: this[_actualTree],
|
|
168
172
|
})
|
|
169
173
|
await this[_loadWorkspaces](this[_actualTree])
|
|
@@ -236,13 +240,26 @@ module.exports = cls => class ActualLoader extends cls {
|
|
|
236
240
|
this[_actualTree] = root
|
|
237
241
|
}
|
|
238
242
|
|
|
239
|
-
[_loadFSNode] ({ path, parent, real, root }) {
|
|
243
|
+
[_loadFSNode] ({ path, parent, real, root, loadOverrides }) {
|
|
240
244
|
if (!real) {
|
|
241
245
|
return realpath(path, this[_rpcache], this[_stcache])
|
|
242
246
|
.then(
|
|
243
|
-
real => this[_loadFSNode]({
|
|
247
|
+
real => this[_loadFSNode]({
|
|
248
|
+
path,
|
|
249
|
+
parent,
|
|
250
|
+
real,
|
|
251
|
+
root,
|
|
252
|
+
loadOverrides,
|
|
253
|
+
}),
|
|
244
254
|
// if realpath fails, just provide a dummy error node
|
|
245
|
-
error => new Node({
|
|
255
|
+
error => new Node({
|
|
256
|
+
error,
|
|
257
|
+
path,
|
|
258
|
+
realpath: path,
|
|
259
|
+
parent,
|
|
260
|
+
root,
|
|
261
|
+
loadOverrides,
|
|
262
|
+
})
|
|
246
263
|
)
|
|
247
264
|
}
|
|
248
265
|
|
|
@@ -271,6 +288,7 @@ module.exports = cls => class ActualLoader extends cls {
|
|
|
271
288
|
error,
|
|
272
289
|
parent,
|
|
273
290
|
root,
|
|
291
|
+
loadOverrides,
|
|
274
292
|
})
|
|
275
293
|
})
|
|
276
294
|
.then(node => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// mixin providing the loadVirtual method
|
|
2
2
|
const localeCompare = require('@isaacs/string-locale-compare')('en')
|
|
3
3
|
|
|
4
|
-
const {resolve} = require('path')
|
|
4
|
+
const { resolve } = require('path')
|
|
5
5
|
|
|
6
6
|
const nameFromFolder = require('@npmcli/name-from-folder')
|
|
7
7
|
const consistentResolve = require('../consistent-resolve.js')
|
|
@@ -72,6 +72,7 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
72
72
|
this[rootOptionProvided] = options.root
|
|
73
73
|
|
|
74
74
|
await this[loadFromShrinkwrap](s, root)
|
|
75
|
+
root.assertRootOverrides()
|
|
75
76
|
return treeCheck(this.virtualTree)
|
|
76
77
|
}
|
|
77
78
|
|
|
@@ -97,7 +98,7 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
97
98
|
this[checkRootEdges](s, root)
|
|
98
99
|
root.meta = s
|
|
99
100
|
this.virtualTree = root
|
|
100
|
-
const {links, nodes} = this[resolveNodes](s, root)
|
|
101
|
+
const { links, nodes } = this[resolveNodes](s, root)
|
|
101
102
|
await this[resolveLinks](links, nodes)
|
|
102
103
|
if (!(s.originalLockfileVersion >= 2)) {
|
|
103
104
|
this[assignBundles](nodes)
|
|
@@ -208,7 +209,7 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
208
209
|
nodes.set(location, this[loadNode](location, meta))
|
|
209
210
|
}
|
|
210
211
|
}
|
|
211
|
-
return {links, nodes}
|
|
212
|
+
return { links, nodes }
|
|
212
213
|
}
|
|
213
214
|
|
|
214
215
|
// links is the set of metadata, and nodes is the map of non-Link nodes
|
|
@@ -240,7 +241,7 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
240
241
|
if (!location || node.isLink && !node.target.location) {
|
|
241
242
|
continue
|
|
242
243
|
}
|
|
243
|
-
const { name, parent, package: { inBundle }} = node
|
|
244
|
+
const { name, parent, package: { inBundle } } = node
|
|
244
245
|
|
|
245
246
|
if (!parent) {
|
|
246
247
|
continue
|
package/lib/arborist/rebuild.js
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
// bundle building needed. Called by reify, and by `npm rebuild`.
|
|
3
3
|
|
|
4
4
|
const localeCompare = require('@isaacs/string-locale-compare')('en')
|
|
5
|
-
const {depth: dfwalk} = require('treeverse')
|
|
5
|
+
const { depth: dfwalk } = require('treeverse')
|
|
6
6
|
const promiseAllRejectLate = require('promise-all-reject-late')
|
|
7
7
|
const rpj = require('read-package-json-fast')
|
|
8
8
|
const binLinks = require('bin-links')
|
|
9
9
|
const runScript = require('@npmcli/run-script')
|
|
10
10
|
const promiseCallLimit = require('promise-call-limit')
|
|
11
|
-
const {resolve} = require('path')
|
|
11
|
+
const { resolve } = require('path')
|
|
12
12
|
const {
|
|
13
13
|
isNodeGypPackage,
|
|
14
14
|
defaultGypInstallScript,
|
|
@@ -220,7 +220,7 @@ module.exports = cls => class Builder extends cls {
|
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
if (this[_oldMeta] === null) {
|
|
223
|
-
const {root: {meta}} = node
|
|
223
|
+
const { root: { meta } } = node
|
|
224
224
|
this[_oldMeta] = meta && meta.loadedFromDisk &&
|
|
225
225
|
!(meta.originalLockfileVersion >= 2)
|
|
226
226
|
}
|
|
@@ -242,7 +242,7 @@ module.exports = cls => class Builder extends cls {
|
|
|
242
242
|
const pkg = await rpj(node.path + '/package.json').catch(() => ({}))
|
|
243
243
|
set.delete(node)
|
|
244
244
|
|
|
245
|
-
const {scripts = {}} = pkg
|
|
245
|
+
const { scripts = {} } = pkg
|
|
246
246
|
node.package.scripts = scripts
|
|
247
247
|
return this[_addToBuildSet](node, set, true)
|
|
248
248
|
}
|
|
@@ -319,9 +319,9 @@ module.exports = cls => class Builder extends cls {
|
|
|
319
319
|
}
|
|
320
320
|
const p = runScript(runOpts).catch(er => {
|
|
321
321
|
const { code, signal } = er
|
|
322
|
-
this.log.info('run', pkg._id, event, {code, signal})
|
|
322
|
+
this.log.info('run', pkg._id, event, { code, signal })
|
|
323
323
|
throw er
|
|
324
|
-
}).then(({args, code, signal, stdout, stderr}) => {
|
|
324
|
+
}).then(({ args, code, signal, stdout, stderr }) => {
|
|
325
325
|
this.scriptsRun.add({
|
|
326
326
|
pkg,
|
|
327
327
|
path,
|
|
@@ -333,7 +333,7 @@ module.exports = cls => class Builder extends cls {
|
|
|
333
333
|
stdout,
|
|
334
334
|
stderr,
|
|
335
335
|
})
|
|
336
|
-
this.log.info('run', pkg._id, event, {code, signal})
|
|
336
|
+
this.log.info('run', pkg._id, event, { code, signal })
|
|
337
337
|
})
|
|
338
338
|
|
|
339
339
|
await (this[_doHandleOptionalFailure]
|
package/lib/arborist/reify.js
CHANGED
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
const onExit = require('../signal-handling.js')
|
|
4
4
|
const pacote = require('pacote')
|
|
5
5
|
const AuditReport = require('../audit-report.js')
|
|
6
|
-
const {subset, intersects} = require('semver')
|
|
6
|
+
const { subset, intersects } = require('semver')
|
|
7
7
|
const npa = require('npm-package-arg')
|
|
8
8
|
const debug = require('../debug.js')
|
|
9
9
|
const walkUp = require('walk-up-path')
|
|
10
10
|
|
|
11
|
-
const {dirname, resolve, relative} = require('path')
|
|
12
|
-
const {depth: dfwalk} = require('treeverse')
|
|
11
|
+
const { dirname, resolve, relative } = require('path')
|
|
12
|
+
const { depth: dfwalk } = require('treeverse')
|
|
13
13
|
const fs = require('fs')
|
|
14
|
-
const {promisify} = require('util')
|
|
14
|
+
const { promisify } = require('util')
|
|
15
15
|
const lstat = promisify(fs.lstat)
|
|
16
16
|
const symlink = promisify(fs.symlink)
|
|
17
17
|
const mkdirp = require('mkdirp-infer-owner')
|
|
@@ -188,7 +188,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
188
188
|
// ok, we're about to start touching the fs. need to roll back
|
|
189
189
|
// if we get an early termination.
|
|
190
190
|
let reifyTerminated = null
|
|
191
|
-
const removeHandler = onExit(({signal}) => {
|
|
191
|
+
const removeHandler = onExit(({ signal }) => {
|
|
192
192
|
// only call once. if signal hits twice, we just terminate
|
|
193
193
|
removeHandler()
|
|
194
194
|
reifyTerminated = Object.assign(new Error('process terminated'), {
|
|
@@ -352,7 +352,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
352
352
|
if (includeRootDeps) {
|
|
353
353
|
// add all non-workspace nodes to filterNodes
|
|
354
354
|
for (const tree of [this.idealTree, this.actualTree]) {
|
|
355
|
-
for (const {type, to} of tree.edgesOut.values()) {
|
|
355
|
+
for (const { type, to } of tree.edgesOut.values()) {
|
|
356
356
|
if (type !== 'workspace' && to) {
|
|
357
357
|
filterNodes.push(to)
|
|
358
358
|
}
|
|
@@ -686,7 +686,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
686
686
|
}
|
|
687
687
|
|
|
688
688
|
[_warnDeprecated] (node) {
|
|
689
|
-
const {_id, deprecated} = node.package
|
|
689
|
+
const { _id, deprecated } = node.package
|
|
690
690
|
if (deprecated) {
|
|
691
691
|
this.log.warn('deprecated', `${_id}: ${deprecated}`)
|
|
692
692
|
}
|
|
@@ -1159,7 +1159,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1159
1159
|
const edge = addTree.edgesOut.get(name)
|
|
1160
1160
|
const pkg = addTree.package
|
|
1161
1161
|
const req = npa.resolve(name, edge.spec, addTree.realpath)
|
|
1162
|
-
const {rawSpec, subSpec} = req
|
|
1162
|
+
const { rawSpec, subSpec } = req
|
|
1163
1163
|
|
|
1164
1164
|
const spec = subSpec ? subSpec.rawSpec : rawSpec
|
|
1165
1165
|
const child = edge.to
|
|
@@ -1173,6 +1173,10 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1173
1173
|
}
|
|
1174
1174
|
|
|
1175
1175
|
let newSpec
|
|
1176
|
+
// True if the dependency is getting installed from a local file path
|
|
1177
|
+
// In this case it is not possible to do the normal version comparisons
|
|
1178
|
+
// as the new version will be a file path
|
|
1179
|
+
const isLocalDep = req.type === 'directory' || req.type === 'file'
|
|
1176
1180
|
if (req.registry) {
|
|
1177
1181
|
const version = child.version
|
|
1178
1182
|
const prefixRange = version ? this[_savePrefix] + version : '*'
|
|
@@ -1204,7 +1208,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1204
1208
|
} else {
|
|
1205
1209
|
newSpec = h.shortcut(opt)
|
|
1206
1210
|
}
|
|
1207
|
-
} else if (
|
|
1211
|
+
} else if (isLocalDep) {
|
|
1208
1212
|
// save the relative path in package.json
|
|
1209
1213
|
// Normally saveSpec is updated with the proper relative
|
|
1210
1214
|
// path already, but it's possible to specify a full absolute
|
|
@@ -1233,11 +1237,11 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1233
1237
|
if (hasSubKey(pkg, 'devDependencies', name)) {
|
|
1234
1238
|
pkg.devDependencies[name] = newSpec
|
|
1235
1239
|
// don't update peer or optional if we don't have to
|
|
1236
|
-
if (hasSubKey(pkg, 'peerDependencies', name) && !intersects(newSpec, pkg.peerDependencies[name])) {
|
|
1240
|
+
if (hasSubKey(pkg, 'peerDependencies', name) && (isLocalDep || !intersects(newSpec, pkg.peerDependencies[name]))) {
|
|
1237
1241
|
pkg.peerDependencies[name] = newSpec
|
|
1238
1242
|
}
|
|
1239
1243
|
|
|
1240
|
-
if (hasSubKey(pkg, 'optionalDependencies', name) && !intersects(newSpec, pkg.optionalDependencies[name])) {
|
|
1244
|
+
if (hasSubKey(pkg, 'optionalDependencies', name) && (isLocalDep || !intersects(newSpec, pkg.optionalDependencies[name]))) {
|
|
1241
1245
|
pkg.optionalDependencies[name] = newSpec
|
|
1242
1246
|
}
|
|
1243
1247
|
} else {
|
package/lib/audit-report.js
CHANGED
|
@@ -265,7 +265,7 @@ class AuditReport extends Map {
|
|
|
265
265
|
avoid: vuln.range,
|
|
266
266
|
avoidStrict: true,
|
|
267
267
|
})
|
|
268
|
-
return {name, version, isSemVerMajor}
|
|
268
|
+
return { name, version, isSemVerMajor }
|
|
269
269
|
} catch (er) {
|
|
270
270
|
return false
|
|
271
271
|
}
|
|
@@ -285,7 +285,7 @@ class AuditReport extends Map {
|
|
|
285
285
|
}
|
|
286
286
|
|
|
287
287
|
const bulk = {}
|
|
288
|
-
const {advisories} = report
|
|
288
|
+
const { advisories } = report
|
|
289
289
|
for (const advisory of Object.values(advisories)) {
|
|
290
290
|
const {
|
|
291
291
|
id,
|
|
@@ -296,7 +296,7 @@ class AuditReport extends Map {
|
|
|
296
296
|
module_name: name,
|
|
297
297
|
} = advisory
|
|
298
298
|
bulk[name] = bulk[name] || []
|
|
299
|
-
bulk[name].push({id, url, title, severity, vulnerable_versions})
|
|
299
|
+
bulk[name].push({ id, url, title, severity, vulnerable_versions })
|
|
300
300
|
}
|
|
301
301
|
|
|
302
302
|
return bulk
|
package/lib/calc-dep-flags.js
CHANGED
|
@@ -38,7 +38,7 @@ const calcDepFlagsStep = (node) => {
|
|
|
38
38
|
return calcDepFlagsStep(node.target)
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
node.edgesOut.forEach(({peer, optional, dev, to}) => {
|
|
41
|
+
node.edgesOut.forEach(({ peer, optional, dev, to }) => {
|
|
42
42
|
// if the dep is missing, then its flags are already maximally unset
|
|
43
43
|
if (!to) {
|
|
44
44
|
return
|
package/lib/can-place-dep.js
CHANGED
|
@@ -78,7 +78,7 @@ class CanPlaceDep {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
this._treeSnapshot = JSON.stringify([...target.root.inventory.entries()]
|
|
81
|
-
.map(([loc, {packageName, version, resolved}]) => {
|
|
81
|
+
.map(([loc, { packageName, version, resolved }]) => {
|
|
82
82
|
return [loc, packageName, version, resolved]
|
|
83
83
|
}).sort(([a], [b]) => localeCompare(a, b)))
|
|
84
84
|
})
|
|
@@ -118,7 +118,7 @@ class CanPlaceDep {
|
|
|
118
118
|
|
|
119
119
|
debug(() => {
|
|
120
120
|
const treeSnapshot = JSON.stringify([...target.root.inventory.entries()]
|
|
121
|
-
.map(([loc, {packageName, version, resolved}]) => {
|
|
121
|
+
.map(([loc, { packageName, version, resolved }]) => {
|
|
122
122
|
return [loc, packageName, version, resolved]
|
|
123
123
|
}).sort(([a], [b]) => localeCompare(a, b)))
|
|
124
124
|
/* istanbul ignore if */
|
package/lib/dep-valid.js
CHANGED
package/lib/diff.js
CHANGED
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
// Thus, the root Diff node is the shallowest change required
|
|
6
6
|
// for a given branch of the tree being mutated.
|
|
7
7
|
|
|
8
|
-
const {depth} = require('treeverse')
|
|
9
|
-
const {existsSync} = require('fs')
|
|
8
|
+
const { depth } = require('treeverse')
|
|
9
|
+
const { existsSync } = require('fs')
|
|
10
10
|
|
|
11
11
|
const ssri = require('ssri')
|
|
12
12
|
|
|
13
13
|
class Diff {
|
|
14
|
-
constructor ({actual, ideal, filterSet, shrinkwrapInflated}) {
|
|
14
|
+
constructor ({ actual, ideal, filterSet, shrinkwrapInflated }) {
|
|
15
15
|
this.filterSet = filterSet
|
|
16
16
|
this.shrinkwrapInflated = shrinkwrapInflated
|
|
17
17
|
this.children = []
|
|
@@ -94,14 +94,14 @@ class Diff {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
return depth({
|
|
97
|
-
tree: new Diff({actual, ideal, filterSet, shrinkwrapInflated}),
|
|
97
|
+
tree: new Diff({ actual, ideal, filterSet, shrinkwrapInflated }),
|
|
98
98
|
getChildren,
|
|
99
99
|
leave,
|
|
100
100
|
})
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
const getAction = ({actual, ideal}) => {
|
|
104
|
+
const getAction = ({ actual, ideal }) => {
|
|
105
105
|
if (!ideal) {
|
|
106
106
|
return 'REMOVE'
|
|
107
107
|
}
|
|
@@ -237,7 +237,7 @@ const diffNode = ({
|
|
|
237
237
|
return
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
-
const action = getAction({actual, ideal})
|
|
240
|
+
const action = getAction({ actual, ideal })
|
|
241
241
|
|
|
242
242
|
// if it's a match, then get its children
|
|
243
243
|
// otherwise, this is the child diff node
|
|
@@ -245,7 +245,7 @@ const diffNode = ({
|
|
|
245
245
|
if (action === 'REMOVE') {
|
|
246
246
|
removed.push(actual)
|
|
247
247
|
}
|
|
248
|
-
children.push(new Diff({actual, ideal, filterSet, shrinkwrapInflated}))
|
|
248
|
+
children.push(new Diff({ actual, ideal, filterSet, shrinkwrapInflated }))
|
|
249
249
|
} else {
|
|
250
250
|
unchanged.push(ideal)
|
|
251
251
|
// !*! Weird dirty hack warning !*!
|
package/lib/edge.js
CHANGED
|
@@ -29,6 +29,7 @@ class ArboristEdge {}
|
|
|
29
29
|
const printableEdge = (edge) => {
|
|
30
30
|
const edgeFrom = edge.from && edge.from.location
|
|
31
31
|
const edgeTo = edge.to && edge.to.location
|
|
32
|
+
const override = edge.overrides && edge.overrides.value
|
|
32
33
|
|
|
33
34
|
return Object.assign(new ArboristEdge(), {
|
|
34
35
|
name: edge.name,
|
|
@@ -38,12 +39,13 @@ const printableEdge = (edge) => {
|
|
|
38
39
|
...(edgeTo ? { to: edgeTo } : {}),
|
|
39
40
|
...(edge.error ? { error: edge.error } : {}),
|
|
40
41
|
...(edge.peerConflicted ? { peerConflicted: true } : {}),
|
|
42
|
+
...(override ? { overridden: override } : {}),
|
|
41
43
|
})
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
class Edge {
|
|
45
47
|
constructor (options) {
|
|
46
|
-
const { type, name, spec, accept, from } = options
|
|
48
|
+
const { type, name, spec, accept, from, overrides } = options
|
|
47
49
|
|
|
48
50
|
if (typeof spec !== 'string') {
|
|
49
51
|
throw new TypeError('must provide string spec')
|
|
@@ -55,6 +57,10 @@ class Edge {
|
|
|
55
57
|
|
|
56
58
|
this[_spec] = spec
|
|
57
59
|
|
|
60
|
+
if (overrides !== undefined) {
|
|
61
|
+
this.overrides = overrides
|
|
62
|
+
}
|
|
63
|
+
|
|
58
64
|
if (accept !== undefined) {
|
|
59
65
|
if (typeof accept !== 'string') {
|
|
60
66
|
throw new TypeError('accept field must be a string if provided')
|
|
@@ -82,8 +88,11 @@ class Edge {
|
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
satisfiedBy (node) {
|
|
85
|
-
|
|
86
|
-
|
|
91
|
+
if (node.name !== this.name) {
|
|
92
|
+
return false
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return depValid(node, this.spec, this.accept, this.from)
|
|
87
96
|
}
|
|
88
97
|
|
|
89
98
|
explain (seen = []) {
|
|
@@ -101,6 +110,10 @@ class Edge {
|
|
|
101
110
|
type: this.type,
|
|
102
111
|
name: this.name,
|
|
103
112
|
spec: this.spec,
|
|
113
|
+
...(this.rawSpec !== this.spec ? {
|
|
114
|
+
rawSpec: this.rawSpec,
|
|
115
|
+
overridden: true,
|
|
116
|
+
} : {}),
|
|
104
117
|
...(bundled ? { bundled } : {}),
|
|
105
118
|
...(error ? { error } : {}),
|
|
106
119
|
...(from ? { from: from.explain(null, seen) } : {}),
|
|
@@ -143,7 +156,28 @@ class Edge {
|
|
|
143
156
|
return this[_name]
|
|
144
157
|
}
|
|
145
158
|
|
|
159
|
+
get rawSpec () {
|
|
160
|
+
return this[_spec]
|
|
161
|
+
}
|
|
162
|
+
|
|
146
163
|
get spec () {
|
|
164
|
+
if (this.overrides && this.overrides.value && this.overrides.name === this.name) {
|
|
165
|
+
if (this.overrides.value.startsWith('$')) {
|
|
166
|
+
const ref = this.overrides.value.slice(1)
|
|
167
|
+
const pkg = this.from.root.package
|
|
168
|
+
const overrideSpec = (pkg.devDependencies && pkg.devDependencies[ref]) ||
|
|
169
|
+
(pkg.optionalDependencies && pkg.optionalDependencies[ref]) ||
|
|
170
|
+
(pkg.dependencies && pkg.dependencies[ref]) ||
|
|
171
|
+
(pkg.peerDependencies && pkg.peerDependencies[ref])
|
|
172
|
+
|
|
173
|
+
if (overrideSpec) {
|
|
174
|
+
return overrideSpec
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
throw new Error(`Unable to resolve reference ${this.overrides.value}`)
|
|
178
|
+
}
|
|
179
|
+
return this.overrides.value
|
|
180
|
+
}
|
|
147
181
|
return this[_spec]
|
|
148
182
|
}
|
|
149
183
|
|
|
@@ -213,6 +247,7 @@ class Edge {
|
|
|
213
247
|
if (node.edgesOut.has(this.name)) {
|
|
214
248
|
node.edgesOut.get(this.name).detach()
|
|
215
249
|
}
|
|
250
|
+
|
|
216
251
|
node.addEdgeOut(this)
|
|
217
252
|
this.reload()
|
|
218
253
|
}
|
package/lib/from-path.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// end up getting installed. directory (ie, symlink) deps also need
|
|
4
4
|
// to be resolved based on their targets, but that's what realpath is
|
|
5
5
|
|
|
6
|
-
const {dirname} = require('path')
|
|
6
|
+
const { dirname } = require('path')
|
|
7
7
|
const npa = require('npm-package-arg')
|
|
8
8
|
|
|
9
9
|
const fromPath = (node, spec) =>
|
package/lib/link.js
CHANGED
|
@@ -3,7 +3,7 @@ const relpath = require('./relpath.js')
|
|
|
3
3
|
const Node = require('./node.js')
|
|
4
4
|
const _loadDeps = Symbol.for('Arborist.Node._loadDeps')
|
|
5
5
|
const _target = Symbol.for('_target')
|
|
6
|
-
const {dirname} = require('path')
|
|
6
|
+
const { dirname } = require('path')
|
|
7
7
|
// defined by Node class
|
|
8
8
|
const _delistFromMeta = Symbol.for('_delistFromMeta')
|
|
9
9
|
const _refreshLocation = Symbol.for('_refreshLocation')
|
package/lib/node.js
CHANGED
|
@@ -32,15 +32,16 @@ const semver = require('semver')
|
|
|
32
32
|
const nameFromFolder = require('@npmcli/name-from-folder')
|
|
33
33
|
const Edge = require('./edge.js')
|
|
34
34
|
const Inventory = require('./inventory.js')
|
|
35
|
-
const
|
|
36
|
-
const {
|
|
35
|
+
const OverrideSet = require('./override-set.js')
|
|
36
|
+
const { normalize } = require('read-package-json-fast')
|
|
37
|
+
const { getPaths: getBinPaths } = require('bin-links')
|
|
37
38
|
const npa = require('npm-package-arg')
|
|
38
39
|
const debug = require('./debug.js')
|
|
39
40
|
const gatherDepSet = require('./gather-dep-set.js')
|
|
40
41
|
const treeCheck = require('./tree-check.js')
|
|
41
42
|
const walkUp = require('walk-up-path')
|
|
42
43
|
|
|
43
|
-
const {resolve, relative, dirname, basename} = require('path')
|
|
44
|
+
const { resolve, relative, dirname, basename } = require('path')
|
|
44
45
|
const util = require('util')
|
|
45
46
|
const _package = Symbol('_package')
|
|
46
47
|
const _parent = Symbol('_parent')
|
|
@@ -88,6 +89,8 @@ class Node {
|
|
|
88
89
|
legacyPeerDeps = false,
|
|
89
90
|
linksIn,
|
|
90
91
|
hasShrinkwrap,
|
|
92
|
+
overrides,
|
|
93
|
+
loadOverrides = false,
|
|
91
94
|
extraneous = true,
|
|
92
95
|
dev = true,
|
|
93
96
|
optional = true,
|
|
@@ -190,6 +193,17 @@ class Node {
|
|
|
190
193
|
// because this.package is read when adding to inventory
|
|
191
194
|
this[_package] = pkg && typeof pkg === 'object' ? pkg : {}
|
|
192
195
|
|
|
196
|
+
if (overrides) {
|
|
197
|
+
this.overrides = overrides
|
|
198
|
+
} else if (loadOverrides) {
|
|
199
|
+
const overrides = this[_package].overrides || {}
|
|
200
|
+
if (Object.keys(overrides).length > 0) {
|
|
201
|
+
this.overrides = new OverrideSet({
|
|
202
|
+
overrides: this[_package].overrides,
|
|
203
|
+
})
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
193
207
|
// only relevant for the root and top nodes
|
|
194
208
|
this.meta = meta
|
|
195
209
|
|
|
@@ -291,8 +305,8 @@ class Node {
|
|
|
291
305
|
}
|
|
292
306
|
|
|
293
307
|
get hasInstallScript () {
|
|
294
|
-
const {hasInstallScript, scripts} = this.package
|
|
295
|
-
const {install, preinstall, postinstall} = scripts || {}
|
|
308
|
+
const { hasInstallScript, scripts } = this.package
|
|
309
|
+
const { install, preinstall, postinstall } = scripts || {}
|
|
296
310
|
return !!(hasInstallScript || install || preinstall || postinstall)
|
|
297
311
|
}
|
|
298
312
|
|
|
@@ -376,7 +390,7 @@ class Node {
|
|
|
376
390
|
}
|
|
377
391
|
|
|
378
392
|
if (this.root.sourceReference) {
|
|
379
|
-
const {name, version} = this.root.package
|
|
393
|
+
const { name, version } = this.root.package
|
|
380
394
|
why.whileInstalling = {
|
|
381
395
|
name,
|
|
382
396
|
version,
|
|
@@ -963,6 +977,11 @@ class Node {
|
|
|
963
977
|
return false
|
|
964
978
|
}
|
|
965
979
|
|
|
980
|
+
// XXX need to check for two root nodes?
|
|
981
|
+
if (node.overrides !== this.overrides) {
|
|
982
|
+
return false
|
|
983
|
+
}
|
|
984
|
+
|
|
966
985
|
ignorePeers = new Set(ignorePeers)
|
|
967
986
|
|
|
968
987
|
// gather up all the deps of this node and that are only depended
|
|
@@ -1208,6 +1227,10 @@ class Node {
|
|
|
1208
1227
|
this[_changePath](newPath)
|
|
1209
1228
|
}
|
|
1210
1229
|
|
|
1230
|
+
if (parent.overrides) {
|
|
1231
|
+
this.overrides = parent.overrides.getNodeRule(this)
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1211
1234
|
// clobbers anything at that path, resets all appropriate references
|
|
1212
1235
|
this.root = parent.root
|
|
1213
1236
|
}
|
|
@@ -1279,11 +1302,33 @@ class Node {
|
|
|
1279
1302
|
}
|
|
1280
1303
|
}
|
|
1281
1304
|
|
|
1305
|
+
assertRootOverrides () {
|
|
1306
|
+
if (!this.isProjectRoot || !this.overrides) {
|
|
1307
|
+
return
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
for (const edge of this.edgesOut.values()) {
|
|
1311
|
+
// if these differ an override has been applied, those are not allowed
|
|
1312
|
+
// for top level dependencies so throw an error
|
|
1313
|
+
if (edge.spec !== edge.rawSpec && !edge.spec.startsWith('$')) {
|
|
1314
|
+
throw Object.assign(new Error(`Override for ${edge.name}@${edge.rawSpec} conflicts with direct dependency`), { code: 'EOVERRIDE' })
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1282
1319
|
addEdgeOut (edge) {
|
|
1320
|
+
if (this.overrides) {
|
|
1321
|
+
edge.overrides = this.overrides.getEdgeRule(edge)
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1283
1324
|
this.edgesOut.set(edge.name, edge)
|
|
1284
1325
|
}
|
|
1285
1326
|
|
|
1286
1327
|
addEdgeIn (edge) {
|
|
1328
|
+
if (edge.overrides) {
|
|
1329
|
+
this.overrides = edge.overrides
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1287
1332
|
this.edgesIn.add(edge)
|
|
1288
1333
|
|
|
1289
1334
|
// try to get metadata from the yarn.lock file
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
const npa = require('npm-package-arg')
|
|
2
|
+
const semver = require('semver')
|
|
3
|
+
|
|
4
|
+
class OverrideSet {
|
|
5
|
+
constructor ({ overrides, key, parent }) {
|
|
6
|
+
this.parent = parent
|
|
7
|
+
this.children = new Map()
|
|
8
|
+
|
|
9
|
+
if (typeof overrides === 'string') {
|
|
10
|
+
overrides = { '.': overrides }
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// change a literal empty string to * so we can use truthiness checks on
|
|
14
|
+
// the value property later
|
|
15
|
+
if (overrides['.'] === '') {
|
|
16
|
+
overrides['.'] = '*'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (parent) {
|
|
20
|
+
const spec = npa(key)
|
|
21
|
+
if (!spec.name) {
|
|
22
|
+
throw new Error(`Override without name: ${key}`)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
this.name = spec.name
|
|
26
|
+
spec.name = ''
|
|
27
|
+
this.key = key
|
|
28
|
+
this.keySpec = spec.rawSpec === '' ? '' : spec.toString()
|
|
29
|
+
this.value = overrides['.'] || this.keySpec
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
for (const [key, childOverrides] of Object.entries(overrides)) {
|
|
33
|
+
if (key === '.') {
|
|
34
|
+
continue
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const child = new OverrideSet({
|
|
38
|
+
parent: this,
|
|
39
|
+
key,
|
|
40
|
+
overrides: childOverrides,
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
this.children.set(child.key, child)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
getEdgeRule (edge) {
|
|
48
|
+
for (const rule of this.ruleset.values()) {
|
|
49
|
+
if (rule.name !== edge.name) {
|
|
50
|
+
continue
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (rule.keySpec === '' ||
|
|
54
|
+
semver.intersects(edge.spec, rule.keySpec)) {
|
|
55
|
+
return rule
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return this
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
getNodeRule (node) {
|
|
63
|
+
for (const rule of this.ruleset.values()) {
|
|
64
|
+
if (rule.name !== node.name) {
|
|
65
|
+
continue
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (rule.keySpec === '' ||
|
|
69
|
+
semver.satisfies(node.version, rule.keySpec) ||
|
|
70
|
+
semver.satisfies(node.version, rule.value)) {
|
|
71
|
+
return rule
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return this
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
getMatchingRule (node) {
|
|
79
|
+
for (const rule of this.ruleset.values()) {
|
|
80
|
+
if (rule.name !== node.name) {
|
|
81
|
+
continue
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (rule.keySpec === '' ||
|
|
85
|
+
semver.satisfies(node.version, rule.keySpec) ||
|
|
86
|
+
semver.satisfies(node.version, rule.value)) {
|
|
87
|
+
return rule
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return null
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
* ancestry () {
|
|
95
|
+
for (let ancestor = this; ancestor; ancestor = ancestor.parent) {
|
|
96
|
+
yield ancestor
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
get isRoot () {
|
|
101
|
+
return !this.parent
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
get ruleset () {
|
|
105
|
+
const ruleset = new Map()
|
|
106
|
+
|
|
107
|
+
for (const override of this.ancestry()) {
|
|
108
|
+
for (const kid of override.children.values()) {
|
|
109
|
+
if (!ruleset.has(kid.key)) {
|
|
110
|
+
ruleset.set(kid.key, kid)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (!override.isRoot && !ruleset.has(override.key)) {
|
|
115
|
+
ruleset.set(override.key, override)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return ruleset
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
module.exports = OverrideSet
|
package/lib/place-dep.js
CHANGED
|
@@ -295,6 +295,7 @@ class PlaceDep {
|
|
|
295
295
|
integrity: dep.integrity,
|
|
296
296
|
legacyPeerDeps: this.legacyPeerDeps,
|
|
297
297
|
error: dep.errors[0],
|
|
298
|
+
...(dep.overrides ? { overrides: dep.overrides } : {}),
|
|
298
299
|
...(dep.isLink ? { target: dep.target, realpath: dep.realpath } : {}),
|
|
299
300
|
})
|
|
300
301
|
|
|
@@ -407,11 +408,12 @@ class PlaceDep {
|
|
|
407
408
|
for (const entryEdge of peerEntrySets(edge.from).keys()) {
|
|
408
409
|
// either this one needs to be pruned and re-evaluated, or marked
|
|
409
410
|
// as peerConflicted and warned about. If the entryEdge comes in from
|
|
410
|
-
// the root, then we have to leave it alone, and in that
|
|
411
|
-
// will have already warned or crashed by getting to this point
|
|
411
|
+
// the root or a workspace, then we have to leave it alone, and in that
|
|
412
|
+
// case, it will have already warned or crashed by getting to this point
|
|
412
413
|
const entryNode = entryEdge.to
|
|
413
414
|
const deepestTarget = deepestNestingTarget(entryNode)
|
|
414
|
-
if (deepestTarget !== target &&
|
|
415
|
+
if (deepestTarget !== target &&
|
|
416
|
+
!(entryEdge.from.isProjectRoot || entryEdge.from.isWorkspace)) {
|
|
415
417
|
prunePeerSets.push(...gatherDepSet([entryNode], e => {
|
|
416
418
|
return e.to !== entryNode && !e.peerConflicted
|
|
417
419
|
}))
|
package/lib/printable.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// helper function to output a clearer visualization
|
|
2
2
|
// of the current node and its descendents
|
|
3
|
-
|
|
4
3
|
const localeCompare = require('@isaacs/string-locale-compare')('en')
|
|
5
4
|
const util = require('util')
|
|
6
5
|
const relpath = require('./relpath.js')
|
|
@@ -65,6 +64,11 @@ class ArboristNode {
|
|
|
65
64
|
this.errors = tree.errors.map(treeError)
|
|
66
65
|
}
|
|
67
66
|
|
|
67
|
+
if (tree.overrides) {
|
|
68
|
+
this.overrides = new Map([...tree.overrides.ruleset.values()]
|
|
69
|
+
.map((override) => [override.key, override.value]))
|
|
70
|
+
}
|
|
71
|
+
|
|
68
72
|
// edgesOut sorted by name
|
|
69
73
|
if (tree.edgesOut.size) {
|
|
70
74
|
this.edgesOut = new Map([...tree.edgesOut.entries()]
|
|
@@ -87,7 +91,7 @@ class ArboristNode {
|
|
|
87
91
|
// fsChildren sorted by path
|
|
88
92
|
if (tree.fsChildren.size) {
|
|
89
93
|
this.fsChildren = new Set([...tree.fsChildren]
|
|
90
|
-
.sort(({path: a}, {path: b}) => localeCompare(a, b))
|
|
94
|
+
.sort(({ path: a }, { path: b }) => localeCompare(a, b))
|
|
91
95
|
.map(tree => printableTree(tree, path)))
|
|
92
96
|
}
|
|
93
97
|
|
|
@@ -114,7 +118,7 @@ class ArboristLink extends ArboristNode {
|
|
|
114
118
|
}
|
|
115
119
|
}
|
|
116
120
|
|
|
117
|
-
const treeError = ({code, path}) => ({
|
|
121
|
+
const treeError = ({ code, path }) => ({
|
|
118
122
|
code,
|
|
119
123
|
...(path ? { path } : {}),
|
|
120
124
|
})
|
|
@@ -126,7 +130,10 @@ class Edge {
|
|
|
126
130
|
constructor (edge) {
|
|
127
131
|
this.type = edge.type
|
|
128
132
|
this.name = edge.name
|
|
129
|
-
this.spec = edge.
|
|
133
|
+
this.spec = edge.rawSpec || '*'
|
|
134
|
+
if (edge.rawSpec !== edge.spec) {
|
|
135
|
+
this.override = edge.spec
|
|
136
|
+
}
|
|
130
137
|
if (edge.error) {
|
|
131
138
|
this.error = edge.error
|
|
132
139
|
}
|
|
@@ -145,6 +152,8 @@ class EdgeOut extends Edge {
|
|
|
145
152
|
|
|
146
153
|
[util.inspect.custom] () {
|
|
147
154
|
return `{ ${this.type} ${this.name}@${this.spec}${
|
|
155
|
+
this.override ? ` overridden:${this.override}` : ''
|
|
156
|
+
}${
|
|
148
157
|
this.to ? ' -> ' + this.to : ''
|
|
149
158
|
}${
|
|
150
159
|
this.error ? ' ' + this.error : ''
|
package/lib/relpath.js
CHANGED
package/lib/retire-path.js
CHANGED
package/lib/shrinkwrap.js
CHANGED
|
@@ -35,7 +35,7 @@ const mismatch = (a, b) => a && b && a !== b
|
|
|
35
35
|
|
|
36
36
|
const procLog = require('proc-log')
|
|
37
37
|
const YarnLock = require('./yarn-lock.js')
|
|
38
|
-
const {promisify} = require('util')
|
|
38
|
+
const { promisify } = require('util')
|
|
39
39
|
const rimraf = promisify(require('rimraf'))
|
|
40
40
|
const fs = require('fs')
|
|
41
41
|
const readFile = promisify(fs.readFile)
|
|
@@ -180,7 +180,7 @@ const assertNoNewer = async (path, data, lockTime, dir = path, seen = null) => {
|
|
|
180
180
|
|
|
181
181
|
const parent = isParent ? dir : resolve(dir, 'node_modules')
|
|
182
182
|
const children = dir === path
|
|
183
|
-
? Promise.resolve([{name: 'node_modules', isDirectory: () => true }])
|
|
183
|
+
? Promise.resolve([{ name: 'node_modules', isDirectory: () => true }])
|
|
184
184
|
: readdir(parent, { withFileTypes: true })
|
|
185
185
|
|
|
186
186
|
return children.catch(() => [])
|
|
@@ -366,7 +366,7 @@ class Shrinkwrap {
|
|
|
366
366
|
if (fromYarn && fromYarn.version) {
|
|
367
367
|
// if it's the yarn or npm default registry, use the version as
|
|
368
368
|
// our effective spec. if it's any other kind of thing, use that.
|
|
369
|
-
const {resolved, version, integrity} = fromYarn
|
|
369
|
+
const { resolved, version, integrity } = fromYarn
|
|
370
370
|
const isYarnReg = spec.registry && yarnRegRe.test(resolved)
|
|
371
371
|
const isnpmReg = spec.registry && !isYarnReg && npmRegRe.test(resolved)
|
|
372
372
|
const isReg = isnpmReg || isYarnReg
|
|
@@ -1062,7 +1062,7 @@ class Shrinkwrap {
|
|
|
1062
1062
|
}
|
|
1063
1063
|
|
|
1064
1064
|
// now we walk the children, putting them in the 'dependencies' object
|
|
1065
|
-
const {children} = node.target
|
|
1065
|
+
const { children } = node.target
|
|
1066
1066
|
if (!children.size) {
|
|
1067
1067
|
delete lock.dependencies
|
|
1068
1068
|
} else {
|
package/lib/version-from-tgz.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint node/no-deprecated-api: "off" */
|
|
2
2
|
const semver = require('semver')
|
|
3
|
-
const {basename} = require('path')
|
|
4
|
-
const {parse} = require('url')
|
|
3
|
+
const { basename } = require('path')
|
|
4
|
+
const { parse } = require('url')
|
|
5
5
|
module.exports = (name, tgz) => {
|
|
6
6
|
const base = basename(tgz)
|
|
7
7
|
if (!base.endsWith('.tgz')) {
|
package/lib/vuln.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// @npmcli/metavuln-calculator
|
|
12
12
|
// - via: dependency vulns which cause this one
|
|
13
13
|
|
|
14
|
-
const {satisfies, simplifyRange} = require('semver')
|
|
14
|
+
const { satisfies, simplifyRange } = require('semver')
|
|
15
15
|
const semverOpt = { loose: true, includePrerelease: true }
|
|
16
16
|
|
|
17
17
|
const localeCompare = require('@isaacs/string-locale-compare')('en')
|
package/lib/yarn-lock.js
CHANGED
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
|
|
31
31
|
const localeCompare = require('@isaacs/string-locale-compare')('en')
|
|
32
32
|
const consistentResolve = require('./consistent-resolve.js')
|
|
33
|
-
const {dirname} = require('path')
|
|
34
|
-
const {breadth} = require('treeverse')
|
|
33
|
+
const { dirname } = require('path')
|
|
34
|
+
const { breadth } = require('treeverse')
|
|
35
35
|
|
|
36
36
|
// sort a key/value object into a string of JSON stringified keys and vals
|
|
37
37
|
const sortKV = obj => Object.keys(obj)
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@npmcli/arborist",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.1",
|
|
4
4
|
"description": "Manage node_modules trees",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@isaacs/string-locale-compare": "^1.0
|
|
6
|
+
"@isaacs/string-locale-compare": "^1.1.0",
|
|
7
7
|
"@npmcli/installed-package-contents": "^1.0.7",
|
|
8
8
|
"@npmcli/map-workspaces": "^2.0.0",
|
|
9
9
|
"@npmcli/metavuln-calculator": "^2.0.0",
|
|
10
10
|
"@npmcli/move-file": "^1.1.0",
|
|
11
11
|
"@npmcli/name-from-folder": "^1.0.1",
|
|
12
|
-
"@npmcli/node-gyp": "^1.0.
|
|
12
|
+
"@npmcli/node-gyp": "^1.0.3",
|
|
13
13
|
"@npmcli/package-json": "^1.0.1",
|
|
14
14
|
"@npmcli/run-script": "^2.0.0",
|
|
15
15
|
"bin-links": "^2.3.0",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"npm-package-arg": "^8.1.5",
|
|
24
24
|
"npm-pick-manifest": "^6.1.0",
|
|
25
25
|
"npm-registry-fetch": "^11.0.0",
|
|
26
|
-
"pacote": "^12.0.
|
|
27
|
-
"parse-conflict-json": "^
|
|
26
|
+
"pacote": "^12.0.2",
|
|
27
|
+
"parse-conflict-json": "^2.0.1",
|
|
28
28
|
"proc-log": "^1.0.0",
|
|
29
29
|
"promise-all-reject-late": "^1.0.0",
|
|
30
30
|
"promise-call-limit": "^1.0.1",
|
|
@@ -37,11 +37,12 @@
|
|
|
37
37
|
"walk-up-path": "^1.0.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@npmcli/
|
|
40
|
+
"@npmcli/template-oss": "^2.3.1",
|
|
41
41
|
"benchmark": "^2.1.4",
|
|
42
42
|
"chalk": "^4.1.0",
|
|
43
43
|
"minify-registry-metadata": "^2.1.0",
|
|
44
|
-
"
|
|
44
|
+
"nock": "^13.2.0",
|
|
45
|
+
"tap": "^15.1.2",
|
|
45
46
|
"tcompare": "^5.0.6"
|
|
46
47
|
},
|
|
47
48
|
"scripts": {
|
|
@@ -54,21 +55,22 @@
|
|
|
54
55
|
"postversion": "npm publish",
|
|
55
56
|
"prepublishOnly": "git push origin --follow-tags",
|
|
56
57
|
"eslint": "eslint",
|
|
57
|
-
"lint": "
|
|
58
|
+
"lint": "eslint '**/*.js'",
|
|
58
59
|
"lintfix": "npm run lint -- --fix",
|
|
59
60
|
"benchmark": "node scripts/benchmark.js",
|
|
60
61
|
"benchclean": "rm -rf scripts/benchmark/*/",
|
|
61
|
-
"npmclilint": "npmcli-lint"
|
|
62
|
+
"npmclilint": "npmcli-lint",
|
|
63
|
+
"postlint": "npm-template-check"
|
|
62
64
|
},
|
|
63
65
|
"repository": {
|
|
64
66
|
"type": "git",
|
|
65
67
|
"url": "https://github.com/npm/arborist"
|
|
66
68
|
},
|
|
67
|
-
"author": "
|
|
69
|
+
"author": "GitHub Inc.",
|
|
68
70
|
"license": "ISC",
|
|
69
71
|
"files": [
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
+
"bin",
|
|
73
|
+
"lib"
|
|
72
74
|
],
|
|
73
75
|
"main": "lib/index.js",
|
|
74
76
|
"bin": {
|
|
@@ -91,5 +93,10 @@
|
|
|
91
93
|
},
|
|
92
94
|
"engines": {
|
|
93
95
|
"node": "^12.13.0 || ^14.15.0 || >=16"
|
|
94
|
-
}
|
|
96
|
+
},
|
|
97
|
+
"templateVersion": "2.3.1",
|
|
98
|
+
"eslintIgnore": [
|
|
99
|
+
"test/fixtures/",
|
|
100
|
+
"!test/fixtures/*.js"
|
|
101
|
+
]
|
|
95
102
|
}
|
package/LICENSE
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
The ISC License
|
|
2
|
-
|
|
3
|
-
Copyright npm, Inc.
|
|
4
|
-
|
|
5
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
-
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
-
copyright notice and this permission notice appear in all copies.
|
|
8
|
-
|
|
9
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND NPM DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
-
AND FITNESS. IN NO EVENT SHALL NPM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
|
14
|
-
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
Files and metadata contained in `test/fixtures/registry-mocks/content` are
|
|
20
|
-
downloaded from the public npm registry. These are the property of their
|
|
21
|
-
respective owners. The use and distribution of said artifacts are covered by
|
|
22
|
-
their associated licenses.
|