@npmcli/arborist 2.7.1 → 2.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/actual.js +4 -2
- package/bin/audit.js +12 -6
- package/bin/dedupe.js +49 -0
- package/bin/funding.js +4 -2
- package/bin/ideal.js +2 -1
- package/bin/lib/logging.js +4 -3
- package/bin/lib/options.js +14 -12
- package/bin/lib/timers.js +6 -3
- package/bin/license.js +9 -5
- package/bin/prune.js +6 -3
- package/bin/reify.js +6 -3
- package/bin/virtual.js +4 -2
- package/lib/add-rm-pkg-deps.js +25 -14
- package/lib/arborist/audit.js +2 -1
- package/lib/arborist/build-ideal-tree.js +246 -757
- package/lib/arborist/deduper.js +2 -1
- package/lib/arborist/index.js +8 -4
- package/lib/arborist/load-actual.js +32 -15
- package/lib/arborist/load-virtual.js +34 -18
- package/lib/arborist/load-workspaces.js +4 -2
- package/lib/arborist/rebuild.js +31 -16
- package/lib/arborist/reify.js +332 -119
- package/lib/audit-report.js +42 -22
- package/lib/calc-dep-flags.js +18 -9
- package/lib/can-place-dep.js +430 -0
- package/lib/case-insensitive-map.js +50 -0
- package/lib/consistent-resolve.js +2 -1
- package/lib/deepest-nesting-target.js +18 -0
- package/lib/dep-valid.js +8 -4
- package/lib/diff.js +74 -22
- package/lib/edge.js +29 -14
- package/lib/gather-dep-set.js +2 -1
- package/lib/inventory.js +12 -6
- package/lib/link.js +14 -9
- package/lib/node.js +269 -118
- package/lib/optional-set.js +4 -2
- package/lib/peer-entry-sets.js +77 -0
- package/lib/place-dep.js +578 -0
- package/lib/printable.js +48 -18
- package/lib/realpath.js +12 -6
- package/lib/shrinkwrap.js +168 -91
- package/lib/signal-handling.js +6 -3
- package/lib/spec-from-lock.js +7 -4
- package/lib/tracker.js +24 -18
- package/lib/tree-check.js +12 -6
- package/lib/version-from-tgz.js +4 -2
- package/lib/vuln.js +28 -16
- package/lib/yarn-lock.js +27 -15
- package/package.json +9 -13
- package/lib/peer-set.js +0 -25
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// package children are represented with a Map object, but many file systems
|
|
2
|
+
// are case-insensitive and unicode-normalizing, so we need to treat
|
|
3
|
+
// node.children.get('FOO') and node.children.get('foo') as the same thing.
|
|
4
|
+
|
|
5
|
+
const _keys = Symbol('keys')
|
|
6
|
+
const _normKey = Symbol('normKey')
|
|
7
|
+
const normalize = s => s.normalize('NFKD').toLowerCase()
|
|
8
|
+
const OGMap = Map
|
|
9
|
+
module.exports = class Map extends OGMap {
|
|
10
|
+
constructor (items = []) {
|
|
11
|
+
super()
|
|
12
|
+
this[_keys] = new OGMap()
|
|
13
|
+
for (const [key, val] of items) {
|
|
14
|
+
this.set(key, val)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
[_normKey] (key) {
|
|
19
|
+
return typeof key === 'string' ? normalize(key) : key
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get (key) {
|
|
23
|
+
const normKey = this[_normKey](key)
|
|
24
|
+
return this[_keys].has(normKey) ? super.get(this[_keys].get(normKey))
|
|
25
|
+
: undefined
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
set (key, val) {
|
|
29
|
+
const normKey = this[_normKey](key)
|
|
30
|
+
if (this[_keys].has(normKey)) {
|
|
31
|
+
super.delete(this[_keys].get(normKey))
|
|
32
|
+
}
|
|
33
|
+
this[_keys].set(normKey, key)
|
|
34
|
+
return super.set(key, val)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
delete (key) {
|
|
38
|
+
const normKey = this[_normKey](key)
|
|
39
|
+
if (this[_keys].has(normKey)) {
|
|
40
|
+
const prevKey = this[_keys].get(normKey)
|
|
41
|
+
this[_keys].delete(normKey)
|
|
42
|
+
return super.delete(prevKey)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
has (key) {
|
|
47
|
+
const normKey = this[_normKey](key)
|
|
48
|
+
return this[_keys].has(normKey) && super.has(this[_keys].get(normKey))
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
const npa = require('npm-package-arg')
|
|
6
6
|
const relpath = require('./relpath.js')
|
|
7
7
|
const consistentResolve = (resolved, fromPath, toPath, relPaths = false) => {
|
|
8
|
-
if (!resolved)
|
|
8
|
+
if (!resolved) {
|
|
9
9
|
return null
|
|
10
|
+
}
|
|
10
11
|
|
|
11
12
|
try {
|
|
12
13
|
const hostedOpt = { noCommittish: false }
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// given a starting node, what is the *deepest* target where name could go?
|
|
2
|
+
// This is not on the Node class for the simple reason that we sometimes
|
|
3
|
+
// need to check the deepest *potential* target for a Node that is not yet
|
|
4
|
+
// added to the tree where we are checking.
|
|
5
|
+
const deepestNestingTarget = (start, name) => {
|
|
6
|
+
for (const target of start.ancestry()) {
|
|
7
|
+
// note: this will skip past the first target if edge is peer
|
|
8
|
+
if (target.isProjectRoot || !target.resolveParent || target.globalTop) {
|
|
9
|
+
return target
|
|
10
|
+
}
|
|
11
|
+
const targetEdge = target.edgesOut.get(name)
|
|
12
|
+
if (!targetEdge || !targetEdge.peer) {
|
|
13
|
+
return target
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = deepestNestingTarget
|
package/lib/dep-valid.js
CHANGED
|
@@ -44,8 +44,9 @@ const depValid = (child, requested, requestor) => {
|
|
|
44
44
|
|
|
45
45
|
switch (requested.type) {
|
|
46
46
|
case 'range':
|
|
47
|
-
if (requested.fetchSpec === '*')
|
|
47
|
+
if (requested.fetchSpec === '*') {
|
|
48
48
|
return true
|
|
49
|
+
}
|
|
49
50
|
// fallthrough
|
|
50
51
|
case 'version':
|
|
51
52
|
// if it's a version or a range other than '*', semver it
|
|
@@ -108,17 +109,20 @@ const depValid = (child, requested, requestor) => {
|
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
const tarballValid = (child, requested, requestor) => {
|
|
111
|
-
if (child.isLink)
|
|
112
|
+
if (child.isLink) {
|
|
112
113
|
return false
|
|
114
|
+
}
|
|
113
115
|
|
|
114
|
-
if (child.resolved)
|
|
116
|
+
if (child.resolved) {
|
|
115
117
|
return child.resolved.replace(/\\/g, '/') === `file:${requested.fetchSpec.replace(/\\/g, '/')}`
|
|
118
|
+
}
|
|
116
119
|
|
|
117
120
|
// if we have a legacy mutated package.json file. we can't be 100%
|
|
118
121
|
// sure that it resolved to the same file, but if it was the same
|
|
119
122
|
// request, that's a pretty good indicator of sameness.
|
|
120
|
-
if (child.package._requested)
|
|
123
|
+
if (child.package._requested) {
|
|
121
124
|
return child.package._requested.saveSpec === requested.saveSpec
|
|
125
|
+
}
|
|
122
126
|
|
|
123
127
|
// ok, we're probably dealing with some legacy cruft here, not much
|
|
124
128
|
// we can do at this point unfortunately.
|
package/lib/diff.js
CHANGED
|
@@ -31,7 +31,12 @@ class Diff {
|
|
|
31
31
|
this.removed = []
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
static calculate ({
|
|
34
|
+
static calculate ({
|
|
35
|
+
actual,
|
|
36
|
+
ideal,
|
|
37
|
+
filterNodes = [],
|
|
38
|
+
shrinkwrapInflated = new Set(),
|
|
39
|
+
}) {
|
|
35
40
|
// if there's a filterNode, then:
|
|
36
41
|
// - get the path from the root to the filterNode. The root or
|
|
37
42
|
// root.target should have an edge either to the filterNode or
|
|
@@ -43,8 +48,9 @@ class Diff {
|
|
|
43
48
|
const extraneous = new Set()
|
|
44
49
|
for (const filterNode of filterNodes) {
|
|
45
50
|
const { root } = filterNode
|
|
46
|
-
if (root !== ideal && root !== actual)
|
|
51
|
+
if (root !== ideal && root !== actual) {
|
|
47
52
|
throw new Error('invalid filterNode: outside idealTree/actualTree')
|
|
53
|
+
}
|
|
48
54
|
const rootTarget = root.target
|
|
49
55
|
const edge = [...rootTarget.edgesOut.values()].filter(e => {
|
|
50
56
|
return e.to && (e.to === filterNode || e.to.target === filterNode)
|
|
@@ -73,8 +79,9 @@ class Diff {
|
|
|
73
79
|
: [...actualNode.edgesOut.values()].filter(e => e.to).map(e => e.to)
|
|
74
80
|
if (actualNode) {
|
|
75
81
|
for (const child of actualNode.children.values()) {
|
|
76
|
-
if (child.extraneous)
|
|
82
|
+
if (child.extraneous) {
|
|
77
83
|
extraneous.add(child)
|
|
84
|
+
}
|
|
78
85
|
}
|
|
79
86
|
}
|
|
80
87
|
|
|
@@ -82,8 +89,9 @@ class Diff {
|
|
|
82
89
|
},
|
|
83
90
|
})
|
|
84
91
|
}
|
|
85
|
-
for (const extra of extraneous)
|
|
92
|
+
for (const extra of extraneous) {
|
|
86
93
|
filterSet.add(extra)
|
|
94
|
+
}
|
|
87
95
|
|
|
88
96
|
return depth({
|
|
89
97
|
tree: new Diff({actual, ideal, filterSet, shrinkwrapInflated}),
|
|
@@ -94,23 +102,27 @@ class Diff {
|
|
|
94
102
|
}
|
|
95
103
|
|
|
96
104
|
const getAction = ({actual, ideal}) => {
|
|
97
|
-
if (!ideal)
|
|
105
|
+
if (!ideal) {
|
|
98
106
|
return 'REMOVE'
|
|
107
|
+
}
|
|
99
108
|
|
|
100
109
|
// bundled meta-deps are copied over to the ideal tree when we visit it,
|
|
101
110
|
// so they'll appear to be missing here. There's no need to handle them
|
|
102
111
|
// in the diff, though, because they'll be replaced at reify time anyway
|
|
103
112
|
// Otherwise, add the missing node.
|
|
104
|
-
if (!actual)
|
|
113
|
+
if (!actual) {
|
|
105
114
|
return ideal.inDepBundle ? null : 'ADD'
|
|
115
|
+
}
|
|
106
116
|
|
|
107
117
|
// always ignore the root node
|
|
108
|
-
if (ideal.isRoot && actual.isRoot)
|
|
118
|
+
if (ideal.isRoot && actual.isRoot) {
|
|
109
119
|
return null
|
|
120
|
+
}
|
|
110
121
|
|
|
111
122
|
// if the versions don't match, it's a change no matter what
|
|
112
|
-
if (ideal.version !== actual.version)
|
|
123
|
+
if (ideal.version !== actual.version) {
|
|
113
124
|
return 'CHANGE'
|
|
125
|
+
}
|
|
114
126
|
|
|
115
127
|
const binsExist = ideal.binPaths.every((path) => existsSync(path))
|
|
116
128
|
|
|
@@ -125,33 +137,38 @@ const getAction = ({actual, ideal}) => {
|
|
|
125
137
|
const noIntegrity = !ideal.integrity && !actual.integrity
|
|
126
138
|
const noResolved = !ideal.resolved && !actual.resolved
|
|
127
139
|
const resolvedMatch = ideal.resolved && ideal.resolved === actual.resolved
|
|
128
|
-
if (noIntegrity && binsExist && (resolvedMatch || noResolved))
|
|
140
|
+
if (noIntegrity && binsExist && (resolvedMatch || noResolved)) {
|
|
129
141
|
return null
|
|
142
|
+
}
|
|
130
143
|
|
|
131
144
|
// otherwise, verify that it's the same bits
|
|
132
145
|
// note that if ideal has integrity, and resolved doesn't, we treat
|
|
133
146
|
// that as a 'change', so that it gets re-fetched and locked down.
|
|
134
147
|
const integrityMismatch = !ideal.integrity || !actual.integrity ||
|
|
135
148
|
!ssri.parse(ideal.integrity).match(actual.integrity)
|
|
136
|
-
if (integrityMismatch || !binsExist)
|
|
149
|
+
if (integrityMismatch || !binsExist) {
|
|
137
150
|
return 'CHANGE'
|
|
151
|
+
}
|
|
138
152
|
|
|
139
153
|
return null
|
|
140
154
|
}
|
|
141
155
|
|
|
142
156
|
const allChildren = node => {
|
|
143
|
-
if (!node)
|
|
157
|
+
if (!node) {
|
|
144
158
|
return new Map()
|
|
159
|
+
}
|
|
145
160
|
|
|
146
161
|
// if the node is root, and also a link, then what we really
|
|
147
162
|
// want is to traverse the target's children
|
|
148
|
-
if (node.isRoot && node.isLink)
|
|
163
|
+
if (node.isRoot && node.isLink) {
|
|
149
164
|
return allChildren(node.target)
|
|
165
|
+
}
|
|
150
166
|
|
|
151
167
|
const kids = new Map()
|
|
152
168
|
for (const n of [node, ...node.fsChildren]) {
|
|
153
|
-
for (const kid of n.children.values())
|
|
169
|
+
for (const kid of n.children.values()) {
|
|
154
170
|
kids.set(kid.path, kid)
|
|
171
|
+
}
|
|
155
172
|
}
|
|
156
173
|
return kids
|
|
157
174
|
}
|
|
@@ -160,7 +177,14 @@ const allChildren = node => {
|
|
|
160
177
|
// to create the diff tree
|
|
161
178
|
const getChildren = diff => {
|
|
162
179
|
const children = []
|
|
163
|
-
const {
|
|
180
|
+
const {
|
|
181
|
+
actual,
|
|
182
|
+
ideal,
|
|
183
|
+
unchanged,
|
|
184
|
+
removed,
|
|
185
|
+
filterSet,
|
|
186
|
+
shrinkwrapInflated,
|
|
187
|
+
} = diff
|
|
164
188
|
|
|
165
189
|
// Note: we DON'T diff fsChildren themselves, because they are either
|
|
166
190
|
// included in the package contents, or part of some other project, and
|
|
@@ -182,26 +206,45 @@ const getChildren = diff => {
|
|
|
182
206
|
for (const path of paths) {
|
|
183
207
|
const actual = actualKids.get(path)
|
|
184
208
|
const ideal = idealKids.get(path)
|
|
185
|
-
diffNode(
|
|
209
|
+
diffNode({
|
|
210
|
+
actual,
|
|
211
|
+
ideal,
|
|
212
|
+
children,
|
|
213
|
+
unchanged,
|
|
214
|
+
removed,
|
|
215
|
+
filterSet,
|
|
216
|
+
shrinkwrapInflated,
|
|
217
|
+
})
|
|
186
218
|
}
|
|
187
219
|
|
|
188
|
-
if (diff.leaves && !children.length)
|
|
220
|
+
if (diff.leaves && !children.length) {
|
|
189
221
|
diff.leaves.push(diff)
|
|
222
|
+
}
|
|
190
223
|
|
|
191
224
|
return children
|
|
192
225
|
}
|
|
193
226
|
|
|
194
|
-
const diffNode = (
|
|
195
|
-
|
|
227
|
+
const diffNode = ({
|
|
228
|
+
actual,
|
|
229
|
+
ideal,
|
|
230
|
+
children,
|
|
231
|
+
unchanged,
|
|
232
|
+
removed,
|
|
233
|
+
filterSet,
|
|
234
|
+
shrinkwrapInflated,
|
|
235
|
+
}) => {
|
|
236
|
+
if (filterSet.size && !(filterSet.has(ideal) || filterSet.has(actual))) {
|
|
196
237
|
return
|
|
238
|
+
}
|
|
197
239
|
|
|
198
240
|
const action = getAction({actual, ideal})
|
|
199
241
|
|
|
200
242
|
// if it's a match, then get its children
|
|
201
243
|
// otherwise, this is the child diff node
|
|
202
244
|
if (action || (!shrinkwrapInflated.has(ideal) && ideal.hasShrinkwrap)) {
|
|
203
|
-
if (action === 'REMOVE')
|
|
245
|
+
if (action === 'REMOVE') {
|
|
204
246
|
removed.push(actual)
|
|
247
|
+
}
|
|
205
248
|
children.push(new Diff({actual, ideal, filterSet, shrinkwrapInflated}))
|
|
206
249
|
} else {
|
|
207
250
|
unchanged.push(ideal)
|
|
@@ -227,13 +270,22 @@ const diffNode = (actual, ideal, children, unchanged, removed, filterSet, shrink
|
|
|
227
270
|
if (actual && bd && bd.length) {
|
|
228
271
|
const bundledChildren = []
|
|
229
272
|
for (const node of actual.children.values()) {
|
|
230
|
-
if (node.inBundle)
|
|
273
|
+
if (node.inBundle) {
|
|
231
274
|
bundledChildren.push(node)
|
|
275
|
+
}
|
|
232
276
|
}
|
|
233
|
-
for (const node of bundledChildren)
|
|
277
|
+
for (const node of bundledChildren) {
|
|
234
278
|
node.parent = ideal
|
|
279
|
+
}
|
|
235
280
|
}
|
|
236
|
-
children.push(...getChildren({
|
|
281
|
+
children.push(...getChildren({
|
|
282
|
+
actual,
|
|
283
|
+
ideal,
|
|
284
|
+
unchanged,
|
|
285
|
+
removed,
|
|
286
|
+
filterSet,
|
|
287
|
+
shrinkwrapInflated,
|
|
288
|
+
}))
|
|
237
289
|
}
|
|
238
290
|
}
|
|
239
291
|
|
package/lib/edge.js
CHANGED
|
@@ -37,6 +37,7 @@ const printableEdge = (edge) => {
|
|
|
37
37
|
...(edgeFrom != null ? { from: edgeFrom } : {}),
|
|
38
38
|
...(edgeTo ? { to: edgeTo } : {}),
|
|
39
39
|
...(edge.error ? { error: edge.error } : {}),
|
|
40
|
+
...(edge.overridden ? { overridden: true } : {}),
|
|
40
41
|
})
|
|
41
42
|
}
|
|
42
43
|
|
|
@@ -44,22 +45,26 @@ class Edge {
|
|
|
44
45
|
constructor (options) {
|
|
45
46
|
const { type, name, spec, accept, from } = options
|
|
46
47
|
|
|
47
|
-
if (typeof spec !== 'string')
|
|
48
|
+
if (typeof spec !== 'string') {
|
|
48
49
|
throw new TypeError('must provide string spec')
|
|
50
|
+
}
|
|
49
51
|
|
|
50
|
-
if (type === 'workspace' && npa(spec).type !== 'directory')
|
|
52
|
+
if (type === 'workspace' && npa(spec).type !== 'directory') {
|
|
51
53
|
throw new TypeError('workspace edges must be a symlink')
|
|
54
|
+
}
|
|
52
55
|
|
|
53
56
|
this[_spec] = spec
|
|
54
57
|
|
|
55
58
|
if (accept !== undefined) {
|
|
56
|
-
if (typeof accept !== 'string')
|
|
59
|
+
if (typeof accept !== 'string') {
|
|
57
60
|
throw new TypeError('accept field must be a string if provided')
|
|
61
|
+
}
|
|
58
62
|
this[_accept] = accept || '*'
|
|
59
63
|
}
|
|
60
64
|
|
|
61
|
-
if (typeof name !== 'string')
|
|
65
|
+
if (typeof name !== 'string') {
|
|
62
66
|
throw new TypeError('must provide dependency name')
|
|
67
|
+
}
|
|
63
68
|
this[_name] = name
|
|
64
69
|
|
|
65
70
|
if (!types.has(type)) {
|
|
@@ -68,19 +73,23 @@ class Edge {
|
|
|
68
73
|
`(valid types are: ${Edge.types.join(', ')})`)
|
|
69
74
|
}
|
|
70
75
|
this[_type] = type
|
|
71
|
-
if (!from)
|
|
76
|
+
if (!from) {
|
|
72
77
|
throw new TypeError('must provide "from" node')
|
|
78
|
+
}
|
|
73
79
|
this[_setFrom](from)
|
|
74
80
|
this[_error] = this[_loadError]()
|
|
81
|
+
this.overridden = false
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
satisfiedBy (node) {
|
|
78
|
-
return
|
|
85
|
+
return node.name === this.name &&
|
|
86
|
+
depValid(node, this.spec, this.accept, this.from)
|
|
79
87
|
}
|
|
80
88
|
|
|
81
89
|
explain (seen = []) {
|
|
82
|
-
if (this[_explanation])
|
|
90
|
+
if (this[_explanation]) {
|
|
83
91
|
return this[_explanation]
|
|
92
|
+
}
|
|
84
93
|
|
|
85
94
|
return this[_explanation] = this[_explain](seen)
|
|
86
95
|
}
|
|
@@ -99,8 +108,9 @@ class Edge {
|
|
|
99
108
|
}
|
|
100
109
|
|
|
101
110
|
get bundled () {
|
|
102
|
-
if (!this.from)
|
|
111
|
+
if (!this.from) {
|
|
103
112
|
return false
|
|
113
|
+
}
|
|
104
114
|
const { package: { bundleDependencies = [] } } = this.from
|
|
105
115
|
return bundleDependencies.includes(this.name)
|
|
106
116
|
}
|
|
@@ -165,7 +175,7 @@ class Edge {
|
|
|
165
175
|
[_loadError] () {
|
|
166
176
|
return !this[_to] ? (this.optional ? null : 'MISSING')
|
|
167
177
|
: this.peer && this.from === this.to.parent && !this.from.isTop ? 'PEER LOCAL'
|
|
168
|
-
: !
|
|
178
|
+
: !this.satisfiedBy(this.to) ? 'INVALID'
|
|
169
179
|
: 'OK'
|
|
170
180
|
}
|
|
171
181
|
|
|
@@ -173,20 +183,24 @@ class Edge {
|
|
|
173
183
|
this[_explanation] = null
|
|
174
184
|
const newTo = this[_from].resolve(this.name)
|
|
175
185
|
if (newTo !== this[_to]) {
|
|
176
|
-
if (this[_to])
|
|
186
|
+
if (this[_to]) {
|
|
177
187
|
this[_to].edgesIn.delete(this)
|
|
188
|
+
}
|
|
178
189
|
this[_to] = newTo
|
|
179
190
|
this[_error] = this[_loadError]()
|
|
180
|
-
if (this[_to])
|
|
191
|
+
if (this[_to]) {
|
|
181
192
|
this[_to].addEdgeIn(this)
|
|
182
|
-
|
|
193
|
+
}
|
|
194
|
+
} else if (hard) {
|
|
183
195
|
this[_error] = this[_loadError]()
|
|
196
|
+
}
|
|
184
197
|
}
|
|
185
198
|
|
|
186
199
|
detach () {
|
|
187
200
|
this[_explanation] = null
|
|
188
|
-
if (this[_to])
|
|
201
|
+
if (this[_to]) {
|
|
189
202
|
this[_to].edgesIn.delete(this)
|
|
203
|
+
}
|
|
190
204
|
this[_from].edgesOut.delete(this.name)
|
|
191
205
|
this[_to] = null
|
|
192
206
|
this[_error] = 'DETACHED'
|
|
@@ -196,8 +210,9 @@ class Edge {
|
|
|
196
210
|
[_setFrom] (node) {
|
|
197
211
|
this[_explanation] = null
|
|
198
212
|
this[_from] = node
|
|
199
|
-
if (node.edgesOut.has(this.name))
|
|
213
|
+
if (node.edgesOut.has(this.name)) {
|
|
200
214
|
node.edgesOut.get(this.name).detach()
|
|
215
|
+
}
|
|
201
216
|
node.addEdgeOut(this)
|
|
202
217
|
this.reload()
|
|
203
218
|
}
|
package/lib/gather-dep-set.js
CHANGED
|
@@ -14,8 +14,9 @@ const gatherDepSet = (set, edgeFilter) => {
|
|
|
14
14
|
// as the deps set increases in size.
|
|
15
15
|
for (const node of deps) {
|
|
16
16
|
for (const edge of node.edgesOut.values()) {
|
|
17
|
-
if (edge.to && edgeFilter(edge))
|
|
17
|
+
if (edge.to && edgeFilter(edge)) {
|
|
18
18
|
deps.add(edge.to)
|
|
19
|
+
}
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
|
package/lib/inventory.js
CHANGED
|
@@ -13,11 +13,13 @@ const debug = require('./debug.js')
|
|
|
13
13
|
const getLicense = pkg => {
|
|
14
14
|
if (pkg) {
|
|
15
15
|
const lic = pkg.license || pkg.licence
|
|
16
|
-
if (lic)
|
|
16
|
+
if (lic) {
|
|
17
17
|
return lic
|
|
18
|
+
}
|
|
18
19
|
const lics = pkg.licenses || pkg.licences
|
|
19
|
-
if (Array.isArray(lics))
|
|
20
|
+
if (Array.isArray(lics)) {
|
|
20
21
|
return lics[0]
|
|
22
|
+
}
|
|
21
23
|
}
|
|
22
24
|
}
|
|
23
25
|
|
|
@@ -42,8 +44,9 @@ class Inventory extends Map {
|
|
|
42
44
|
|
|
43
45
|
* filter (fn) {
|
|
44
46
|
for (const node of this.values()) {
|
|
45
|
-
if (fn(node))
|
|
47
|
+
if (fn(node)) {
|
|
46
48
|
yield node
|
|
49
|
+
}
|
|
47
50
|
}
|
|
48
51
|
}
|
|
49
52
|
|
|
@@ -62,8 +65,9 @@ class Inventory extends Map {
|
|
|
62
65
|
|
|
63
66
|
const current = super.get(node[this.primaryKey])
|
|
64
67
|
if (current) {
|
|
65
|
-
if (current === node)
|
|
68
|
+
if (current === node) {
|
|
66
69
|
return
|
|
70
|
+
}
|
|
67
71
|
this.delete(current)
|
|
68
72
|
}
|
|
69
73
|
super.set(node[this.primaryKey], node)
|
|
@@ -85,8 +89,9 @@ class Inventory extends Map {
|
|
|
85
89
|
}
|
|
86
90
|
|
|
87
91
|
delete (node) {
|
|
88
|
-
if (!this.has(node))
|
|
92
|
+
if (!this.has(node)) {
|
|
89
93
|
return
|
|
94
|
+
}
|
|
90
95
|
|
|
91
96
|
super.delete(node[this.primaryKey])
|
|
92
97
|
for (const [key, map] of this[_index].entries()) {
|
|
@@ -95,8 +100,9 @@ class Inventory extends Map {
|
|
|
95
100
|
const set = map.get(val)
|
|
96
101
|
if (set) {
|
|
97
102
|
set.delete(node)
|
|
98
|
-
if (set.size === 0)
|
|
103
|
+
if (set.size === 0) {
|
|
99
104
|
map.delete(node[key])
|
|
105
|
+
}
|
|
100
106
|
}
|
|
101
107
|
}
|
|
102
108
|
}
|
package/lib/link.js
CHANGED
|
@@ -11,8 +11,9 @@ class Link extends Node {
|
|
|
11
11
|
constructor (options) {
|
|
12
12
|
const { root, realpath, target, parent, fsParent } = options
|
|
13
13
|
|
|
14
|
-
if (!realpath && !(target && target.path))
|
|
14
|
+
if (!realpath && !(target && target.path)) {
|
|
15
15
|
throw new TypeError('must provide realpath for Link node')
|
|
16
|
+
}
|
|
16
17
|
|
|
17
18
|
super({
|
|
18
19
|
...options,
|
|
@@ -23,11 +24,11 @@ class Link extends Node {
|
|
|
23
24
|
: null),
|
|
24
25
|
})
|
|
25
26
|
|
|
26
|
-
if (target)
|
|
27
|
+
if (target) {
|
|
27
28
|
this.target = target
|
|
28
|
-
else if (this.realpath === this.root.path)
|
|
29
|
+
} else if (this.realpath === this.root.path) {
|
|
29
30
|
this.target = this.root
|
|
30
|
-
else {
|
|
31
|
+
} else {
|
|
31
32
|
this.target = new Node({
|
|
32
33
|
...options,
|
|
33
34
|
path: realpath,
|
|
@@ -48,8 +49,9 @@ class Link extends Node {
|
|
|
48
49
|
|
|
49
50
|
set target (target) {
|
|
50
51
|
const current = this[_target]
|
|
51
|
-
if (target === current)
|
|
52
|
+
if (target === current) {
|
|
52
53
|
return
|
|
54
|
+
}
|
|
53
55
|
|
|
54
56
|
if (current && current.then) {
|
|
55
57
|
debug(() => {
|
|
@@ -72,25 +74,28 @@ class Link extends Node {
|
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
if (!target) {
|
|
75
|
-
if (current && current.linksIn)
|
|
77
|
+
if (current && current.linksIn) {
|
|
76
78
|
current.linksIn.delete(this)
|
|
79
|
+
}
|
|
77
80
|
if (this.path) {
|
|
78
81
|
this[_delistFromMeta]()
|
|
79
82
|
this[_target] = null
|
|
80
83
|
this.package = {}
|
|
81
84
|
this[_refreshLocation]()
|
|
82
|
-
} else
|
|
85
|
+
} else {
|
|
83
86
|
this[_target] = null
|
|
87
|
+
}
|
|
84
88
|
return
|
|
85
89
|
}
|
|
86
90
|
|
|
87
91
|
if (!this.path) {
|
|
88
92
|
// temp node pending assignment to a tree
|
|
89
93
|
// we know it's not in the inventory yet, because no path.
|
|
90
|
-
if (target.path)
|
|
94
|
+
if (target.path) {
|
|
91
95
|
this.realpath = target.path
|
|
92
|
-
else
|
|
96
|
+
} else {
|
|
93
97
|
target.path = target.realpath = this.realpath
|
|
98
|
+
}
|
|
94
99
|
target.root = this.root
|
|
95
100
|
this[_target] = target
|
|
96
101
|
target.linksIn.add(this)
|