@npmcli/arborist 6.2.7 → 6.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/arborist/build-ideal-tree.js +271 -269
- package/lib/arborist/index.js +2 -1
- package/lib/arborist/load-actual.js +105 -108
- package/lib/arborist/load-virtual.js +58 -78
- package/lib/arborist/reify.js +1 -2
- package/lib/arborist/{load-workspaces.js → set-workspaces.js} +2 -2
- package/lib/calc-dep-flags.js +14 -10
- package/lib/dep-valid.js +15 -9
- package/lib/edge.js +168 -161
- package/lib/from-path.js +21 -15
- package/lib/inventory.js +68 -55
- package/lib/node.js +73 -76
- package/lib/query-selector-all.js +1 -1
- package/package.json +5 -5
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// mixin providing the loadVirtual method
|
|
2
|
-
const localeCompare = require('@isaacs/string-locale-compare')('en')
|
|
3
2
|
const mapWorkspaces = require('@npmcli/map-workspaces')
|
|
4
3
|
|
|
5
4
|
const { resolve } = require('path')
|
|
@@ -14,23 +13,12 @@ const calcDepFlags = require('../calc-dep-flags.js')
|
|
|
14
13
|
const rpj = require('read-package-json-fast')
|
|
15
14
|
const treeCheck = require('../tree-check.js')
|
|
16
15
|
|
|
17
|
-
const loadFromShrinkwrap = Symbol('loadFromShrinkwrap')
|
|
18
|
-
const resolveNodes = Symbol('resolveNodes')
|
|
19
|
-
const resolveLinks = Symbol('resolveLinks')
|
|
20
|
-
const assignBundles = Symbol('assignBundles')
|
|
21
|
-
const loadRoot = Symbol('loadRoot')
|
|
22
|
-
const loadNode = Symbol('loadVirtualNode')
|
|
23
|
-
const loadLink = Symbol('loadVirtualLink')
|
|
24
|
-
const loadWorkspaces = Symbol.for('loadWorkspaces')
|
|
25
16
|
const flagsSuspect = Symbol.for('flagsSuspect')
|
|
26
|
-
const
|
|
27
|
-
const checkRootEdges = Symbol('checkRootEdges')
|
|
28
|
-
const rootOptionProvided = Symbol('rootOptionProvided')
|
|
29
|
-
|
|
30
|
-
const depsToEdges = (type, deps) =>
|
|
31
|
-
Object.entries(deps).map(d => [type, ...d])
|
|
17
|
+
const setWorkspaces = Symbol.for('setWorkspaces')
|
|
32
18
|
|
|
33
19
|
module.exports = cls => class VirtualLoader extends cls {
|
|
20
|
+
#rootOptionProvided
|
|
21
|
+
|
|
34
22
|
constructor (options) {
|
|
35
23
|
super(options)
|
|
36
24
|
|
|
@@ -50,7 +38,7 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
50
38
|
options = { ...this.options, ...options }
|
|
51
39
|
|
|
52
40
|
if (options.root && options.root.meta) {
|
|
53
|
-
await this
|
|
41
|
+
await this.#loadFromShrinkwrap(options.root.meta, options.root)
|
|
54
42
|
return treeCheck(this.virtualTree)
|
|
55
43
|
}
|
|
56
44
|
|
|
@@ -67,24 +55,24 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
67
55
|
// when building the ideal tree, we pass in a root node to this function
|
|
68
56
|
// otherwise, load it from the root package json or the lockfile
|
|
69
57
|
const {
|
|
70
|
-
root = await this
|
|
58
|
+
root = await this.#loadRoot(s),
|
|
71
59
|
} = options
|
|
72
60
|
|
|
73
|
-
this
|
|
61
|
+
this.#rootOptionProvided = options.root
|
|
74
62
|
|
|
75
|
-
await this
|
|
63
|
+
await this.#loadFromShrinkwrap(s, root)
|
|
76
64
|
root.assertRootOverrides()
|
|
77
65
|
return treeCheck(this.virtualTree)
|
|
78
66
|
}
|
|
79
67
|
|
|
80
|
-
async
|
|
68
|
+
async #loadRoot (s) {
|
|
81
69
|
const pj = this.path + '/package.json'
|
|
82
70
|
const pkg = await rpj(pj).catch(() => s.data.packages['']) || {}
|
|
83
|
-
return this[
|
|
71
|
+
return this[setWorkspaces](this.#loadNode('', pkg, true))
|
|
84
72
|
}
|
|
85
73
|
|
|
86
|
-
async
|
|
87
|
-
if (!this
|
|
74
|
+
async #loadFromShrinkwrap (s, root) {
|
|
75
|
+
if (!this.#rootOptionProvided) {
|
|
88
76
|
// root is never any of these things, but might be a brand new
|
|
89
77
|
// baby Node object that never had its dep flags calculated.
|
|
90
78
|
root.extraneous = false
|
|
@@ -96,41 +84,37 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
96
84
|
this[flagsSuspect] = true
|
|
97
85
|
}
|
|
98
86
|
|
|
99
|
-
this
|
|
87
|
+
this.#checkRootEdges(s, root)
|
|
100
88
|
root.meta = s
|
|
101
89
|
this.virtualTree = root
|
|
102
|
-
const { links, nodes } = this
|
|
103
|
-
await this
|
|
90
|
+
const { links, nodes } = this.#resolveNodes(s, root)
|
|
91
|
+
await this.#resolveLinks(links, nodes)
|
|
104
92
|
if (!(s.originalLockfileVersion >= 2)) {
|
|
105
|
-
this
|
|
93
|
+
this.#assignBundles(nodes)
|
|
106
94
|
}
|
|
107
95
|
if (this[flagsSuspect]) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
96
|
+
// reset all dep flags
|
|
97
|
+
// can't use inventory here, because virtualTree might not be root
|
|
98
|
+
for (const node of nodes.values()) {
|
|
99
|
+
if (node.isRoot || node === this.#rootOptionProvided) {
|
|
100
|
+
continue
|
|
101
|
+
}
|
|
102
|
+
node.extraneous = true
|
|
103
|
+
node.dev = true
|
|
104
|
+
node.optional = true
|
|
105
|
+
node.devOptional = true
|
|
106
|
+
node.peer = true
|
|
119
107
|
}
|
|
120
|
-
|
|
121
|
-
node.dev = true
|
|
122
|
-
node.optional = true
|
|
123
|
-
node.devOptional = true
|
|
124
|
-
node.peer = true
|
|
108
|
+
calcDepFlags(this.virtualTree, !this.#rootOptionProvided)
|
|
125
109
|
}
|
|
126
|
-
|
|
110
|
+
return root
|
|
127
111
|
}
|
|
128
112
|
|
|
129
113
|
// check the lockfile deps, and see if they match. if they do not
|
|
130
114
|
// then we have to reset dep flags at the end. for example, if the
|
|
131
115
|
// user manually edits their package.json file, then we need to know
|
|
132
116
|
// that the idealTree is no longer entirely trustworthy.
|
|
133
|
-
|
|
117
|
+
#checkRootEdges (s, root) {
|
|
134
118
|
// loaded virtually from tree, no chance of being out of sync
|
|
135
119
|
// ancient lockfiles are critically damaged by this process,
|
|
136
120
|
// so we need to just hope for the best in those cases.
|
|
@@ -144,6 +128,7 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
144
128
|
const optional = lock.optionalDependencies || {}
|
|
145
129
|
const peer = lock.peerDependencies || {}
|
|
146
130
|
const peerOptional = {}
|
|
131
|
+
|
|
147
132
|
if (lock.peerDependenciesMeta) {
|
|
148
133
|
for (const [name, meta] of Object.entries(lock.peerDependenciesMeta)) {
|
|
149
134
|
if (meta.optional && peer[name] !== undefined) {
|
|
@@ -152,50 +137,45 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
152
137
|
}
|
|
153
138
|
}
|
|
154
139
|
}
|
|
140
|
+
|
|
155
141
|
for (const name of Object.keys(optional)) {
|
|
156
142
|
delete prod[name]
|
|
157
143
|
}
|
|
158
144
|
|
|
159
|
-
const lockWS =
|
|
145
|
+
const lockWS = {}
|
|
160
146
|
const workspaces = mapWorkspaces.virtual({
|
|
161
147
|
cwd: this.path,
|
|
162
148
|
lockfile: s.data,
|
|
163
149
|
})
|
|
150
|
+
|
|
164
151
|
for (const [name, path] of workspaces.entries()) {
|
|
165
|
-
lockWS
|
|
152
|
+
lockWS[name] = `file:${path.replace(/#/g, '%23')}`
|
|
166
153
|
}
|
|
167
154
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
...depsToEdges('dev', dev),
|
|
171
|
-
...depsToEdges('optional', optional),
|
|
172
|
-
...depsToEdges('peer', peer),
|
|
173
|
-
...depsToEdges('peerOptional', peerOptional),
|
|
174
|
-
...lockWS,
|
|
175
|
-
].sort(([atype, aname], [btype, bname]) =>
|
|
176
|
-
localeCompare(atype, btype) || localeCompare(aname, bname))
|
|
177
|
-
|
|
178
|
-
const rootEdges = [...root.edgesOut.values()]
|
|
179
|
-
.map(e => [e.type, e.name, e.spec])
|
|
180
|
-
.sort(([atype, aname], [btype, bname]) =>
|
|
181
|
-
localeCompare(atype, btype) || localeCompare(aname, bname))
|
|
182
|
-
|
|
183
|
-
if (rootEdges.length !== lockEdges.length) {
|
|
184
|
-
// something added or removed
|
|
185
|
-
return this[flagsSuspect] = true
|
|
186
|
-
}
|
|
155
|
+
// Should rootNames exclude optional?
|
|
156
|
+
const rootNames = new Set(root.edgesOut.keys())
|
|
187
157
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
158
|
+
const lockByType = ({ dev, optional, peer, peerOptional, prod, workspace: lockWS })
|
|
159
|
+
|
|
160
|
+
// Find anything in shrinkwrap deps that doesn't match root's type or spec
|
|
161
|
+
for (const type in lockByType) {
|
|
162
|
+
const deps = lockByType[type]
|
|
163
|
+
for (const name in deps) {
|
|
164
|
+
const edge = root.edgesOut.get(name)
|
|
165
|
+
if (!edge || edge.type !== type || edge.spec !== deps[name]) {
|
|
166
|
+
return this[flagsSuspect] = true
|
|
167
|
+
}
|
|
168
|
+
rootNames.delete(name)
|
|
193
169
|
}
|
|
194
170
|
}
|
|
171
|
+
// Something was in root that's not accounted for in shrinkwrap
|
|
172
|
+
if (rootNames.size) {
|
|
173
|
+
return this[flagsSuspect] = true
|
|
174
|
+
}
|
|
195
175
|
}
|
|
196
176
|
|
|
197
177
|
// separate out link metadatas, and create Node objects for nodes
|
|
198
|
-
|
|
178
|
+
#resolveNodes (s, root) {
|
|
199
179
|
const links = new Map()
|
|
200
180
|
const nodes = new Map([['', root]])
|
|
201
181
|
for (const [location, meta] of Object.entries(s.data.packages)) {
|
|
@@ -207,7 +187,7 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
207
187
|
if (meta.link) {
|
|
208
188
|
links.set(location, meta)
|
|
209
189
|
} else {
|
|
210
|
-
nodes.set(location, this
|
|
190
|
+
nodes.set(location, this.#loadNode(location, meta))
|
|
211
191
|
}
|
|
212
192
|
}
|
|
213
193
|
return { links, nodes }
|
|
@@ -215,12 +195,12 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
215
195
|
|
|
216
196
|
// links is the set of metadata, and nodes is the map of non-Link nodes
|
|
217
197
|
// Set the targets to nodes in the set, if we have them (we might not)
|
|
218
|
-
async
|
|
198
|
+
async #resolveLinks (links, nodes) {
|
|
219
199
|
for (const [location, meta] of links.entries()) {
|
|
220
200
|
const targetPath = resolve(this.path, meta.resolved)
|
|
221
201
|
const targetLoc = relpath(this.path, targetPath)
|
|
222
202
|
const target = nodes.get(targetLoc)
|
|
223
|
-
const link = this
|
|
203
|
+
const link = this.#loadLink(location, targetLoc, target, meta)
|
|
224
204
|
nodes.set(location, link)
|
|
225
205
|
nodes.set(targetLoc, link.target)
|
|
226
206
|
|
|
@@ -236,7 +216,7 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
236
216
|
}
|
|
237
217
|
}
|
|
238
218
|
|
|
239
|
-
|
|
219
|
+
#assignBundles (nodes) {
|
|
240
220
|
for (const [location, node] of nodes) {
|
|
241
221
|
// Skip assignment of parentage for the root package
|
|
242
222
|
if (!location || node.isLink && !node.target.location) {
|
|
@@ -265,7 +245,7 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
265
245
|
}
|
|
266
246
|
}
|
|
267
247
|
|
|
268
|
-
|
|
248
|
+
#loadNode (location, sw, loadOverrides) {
|
|
269
249
|
const p = this.virtualTree ? this.virtualTree.realpath : this.path
|
|
270
250
|
const path = resolve(p, location)
|
|
271
251
|
// shrinkwrap doesn't include package name unless necessary
|
|
@@ -303,7 +283,7 @@ module.exports = cls => class VirtualLoader extends cls {
|
|
|
303
283
|
return node
|
|
304
284
|
}
|
|
305
285
|
|
|
306
|
-
|
|
286
|
+
#loadLink (location, targetLoc, target, meta) {
|
|
307
287
|
const path = resolve(this.path, location)
|
|
308
288
|
const link = new Link({
|
|
309
289
|
installLinks: this.installLinks,
|
package/lib/arborist/reify.js
CHANGED
|
@@ -6,7 +6,7 @@ const { subset, intersects } = require('semver')
|
|
|
6
6
|
const npa = require('npm-package-arg')
|
|
7
7
|
const semver = require('semver')
|
|
8
8
|
const debug = require('../debug.js')
|
|
9
|
-
const walkUp = require('walk-up-path')
|
|
9
|
+
const { walkUp } = require('walk-up-path')
|
|
10
10
|
const log = require('proc-log')
|
|
11
11
|
const hgi = require('hosted-git-info')
|
|
12
12
|
const rpj = require('read-package-json-fast')
|
|
@@ -702,7 +702,6 @@ module.exports = cls => class Reifier extends cls {
|
|
|
702
702
|
})
|
|
703
703
|
await pacote.extract(res, node.path, {
|
|
704
704
|
...this.options,
|
|
705
|
-
Arborist: this.constructor,
|
|
706
705
|
resolved: node.resolved,
|
|
707
706
|
integrity: node.integrity,
|
|
708
707
|
})
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
const mapWorkspaces = require('@npmcli/map-workspaces')
|
|
2
2
|
|
|
3
3
|
// shared ref used by other mixins/Arborist
|
|
4
|
-
const
|
|
4
|
+
const _setWorkspaces = Symbol.for('setWorkspaces')
|
|
5
5
|
|
|
6
6
|
module.exports = cls => class MapWorkspaces extends cls {
|
|
7
|
-
async [
|
|
7
|
+
async [_setWorkspaces] (node) {
|
|
8
8
|
const workspaces = await mapWorkspaces({
|
|
9
9
|
cwd: node.path,
|
|
10
10
|
pkg: node.package,
|
package/lib/calc-dep-flags.js
CHANGED
|
@@ -51,14 +51,12 @@ const calcDepFlagsStep = (node) => {
|
|
|
51
51
|
// however, for convenience and to save an extra rewalk, we leave
|
|
52
52
|
// it set when we are in *either* tree, and then omit it from the
|
|
53
53
|
// package-lock if either dev or optional are set.
|
|
54
|
-
const unsetDevOpt = !node.devOptional && !node.dev && !node.optional &&
|
|
55
|
-
!dev && !optional
|
|
54
|
+
const unsetDevOpt = !node.devOptional && !node.dev && !node.optional && !dev && !optional
|
|
56
55
|
|
|
57
56
|
// if we are not in the devOpt tree, then we're also not in
|
|
58
57
|
// either the dev or opt trees
|
|
59
58
|
const unsetDev = unsetDevOpt || !node.dev && !dev
|
|
60
|
-
const unsetOpt = unsetDevOpt ||
|
|
61
|
-
!node.optional && !optional
|
|
59
|
+
const unsetOpt = unsetDevOpt || !node.optional && !optional
|
|
62
60
|
const unsetPeer = !node.peer && !peer
|
|
63
61
|
|
|
64
62
|
if (unsetPeer) {
|
|
@@ -91,8 +89,7 @@ const resetParents = (node, flag) => {
|
|
|
91
89
|
}
|
|
92
90
|
}
|
|
93
91
|
|
|
94
|
-
// typically a short walk, since it only traverses deps that
|
|
95
|
-
// have the flag set.
|
|
92
|
+
// typically a short walk, since it only traverses deps that have the flag set.
|
|
96
93
|
const unsetFlag = (node, flag) => {
|
|
97
94
|
if (node[flag]) {
|
|
98
95
|
node[flag] = false
|
|
@@ -104,10 +101,17 @@ const unsetFlag = (node, flag) => {
|
|
|
104
101
|
node.target.extraneous = node.target[flag] = false
|
|
105
102
|
}
|
|
106
103
|
},
|
|
107
|
-
getChildren: node =>
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
104
|
+
getChildren: node => {
|
|
105
|
+
const children = []
|
|
106
|
+
for (const edge of node.target.edgesOut.values()) {
|
|
107
|
+
if (edge.to && edge.to[flag] &&
|
|
108
|
+
(flag !== 'peer' && edge.type === 'peer' || edge.type === 'prod')
|
|
109
|
+
) {
|
|
110
|
+
children.push(edge.to)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return children
|
|
114
|
+
},
|
|
111
115
|
})
|
|
112
116
|
}
|
|
113
117
|
}
|
package/lib/dep-valid.js
CHANGED
|
@@ -84,15 +84,21 @@ const depValid = (child, requested, requestor) => {
|
|
|
84
84
|
const reqHost = requested.hosted
|
|
85
85
|
const reqCommit = /^[a-fA-F0-9]{40}$/.test(requested.gitCommittish || '')
|
|
86
86
|
const nc = { noCommittish: !reqCommit }
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
87
|
+
if (!resHost) {
|
|
88
|
+
if (resRepo.fetchSpec !== requested.fetchSpec) {
|
|
89
|
+
return false
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
if (reqHost?.ssh(nc) !== resHost.ssh(nc)) {
|
|
93
|
+
return false
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (!requested.gitRange) {
|
|
97
|
+
return true
|
|
98
|
+
}
|
|
99
|
+
return semver.satisfies(child.package.version, requested.gitRange, {
|
|
100
|
+
loose: true,
|
|
101
|
+
})
|
|
96
102
|
}
|
|
97
103
|
|
|
98
104
|
default: // unpossible, just being cautious
|