@npmcli/arborist 7.3.1 → 7.4.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/lib/arborist/build-ideal-tree.js +56 -46
- package/lib/arborist/index.js +102 -14
- package/lib/arborist/load-actual.js +2 -4
- package/lib/arborist/rebuild.js +53 -82
- package/lib/arborist/reify.js +32 -20
- package/lib/case-insensitive-map.js +20 -20
- package/lib/index.js +0 -2
- package/lib/query-selector-all.js +86 -3
- package/lib/tracker.js +28 -29
- package/lib/version-from-tgz.js +4 -5
- package/lib/vuln.js +28 -31
- package/package.json +4 -4
- package/lib/arborist/audit.js +0 -51
- package/lib/arborist/deduper.js +0 -19
- package/lib/arborist/pruner.js +0 -30
- package/lib/arborist/set-workspaces.js +0 -19
- package/lib/get-workspace-nodes.js +0 -36
package/lib/arborist/rebuild.js
CHANGED
|
@@ -19,67 +19,37 @@ const boolEnv = b => b ? '1' : ''
|
|
|
19
19
|
const sortNodes = (a, b) =>
|
|
20
20
|
(a.depth - b.depth) || localeCompare(a.path, b.path)
|
|
21
21
|
|
|
22
|
-
const _workspaces = Symbol.for('workspaces')
|
|
23
|
-
const _build = Symbol('build')
|
|
24
|
-
const _loadDefaultNodes = Symbol('loadDefaultNodes')
|
|
25
|
-
const _retrieveNodesByType = Symbol('retrieveNodesByType')
|
|
26
|
-
const _resetQueues = Symbol('resetQueues')
|
|
27
|
-
const _rebuildBundle = Symbol('rebuildBundle')
|
|
28
|
-
const _ignoreScripts = Symbol('ignoreScripts')
|
|
29
|
-
const _binLinks = Symbol('binLinks')
|
|
30
|
-
const _oldMeta = Symbol('oldMeta')
|
|
31
|
-
const _createBinLinks = Symbol('createBinLinks')
|
|
32
|
-
const _doHandleOptionalFailure = Symbol('doHandleOptionalFailure')
|
|
33
|
-
const _linkAllBins = Symbol('linkAllBins')
|
|
34
|
-
const _runScripts = Symbol('runScripts')
|
|
35
|
-
const _buildQueues = Symbol('buildQueues')
|
|
36
|
-
const _addToBuildSet = Symbol('addToBuildSet')
|
|
37
22
|
const _checkBins = Symbol.for('checkBins')
|
|
38
|
-
const _queues = Symbol('queues')
|
|
39
|
-
const _scriptShell = Symbol('scriptShell')
|
|
40
|
-
const _includeWorkspaceRoot = Symbol.for('includeWorkspaceRoot')
|
|
41
|
-
const _workspacesEnabled = Symbol.for('workspacesEnabled')
|
|
42
|
-
|
|
43
|
-
const _force = Symbol.for('force')
|
|
44
|
-
const _global = Symbol.for('global')
|
|
45
23
|
|
|
46
24
|
// defined by reify mixin
|
|
47
25
|
const _handleOptionalFailure = Symbol.for('handleOptionalFailure')
|
|
48
26
|
const _trashList = Symbol.for('trashList')
|
|
49
27
|
|
|
50
28
|
module.exports = cls => class Builder extends cls {
|
|
29
|
+
#doHandleOptionalFailure
|
|
30
|
+
#oldMeta = null
|
|
31
|
+
#queues
|
|
32
|
+
|
|
51
33
|
constructor (options) {
|
|
52
34
|
super(options)
|
|
53
35
|
|
|
54
|
-
const {
|
|
55
|
-
ignoreScripts = false,
|
|
56
|
-
scriptShell,
|
|
57
|
-
binLinks = true,
|
|
58
|
-
rebuildBundle = true,
|
|
59
|
-
} = options
|
|
60
|
-
|
|
61
36
|
this.scriptsRun = new Set()
|
|
62
|
-
this
|
|
63
|
-
this[_ignoreScripts] = !!ignoreScripts
|
|
64
|
-
this[_scriptShell] = scriptShell
|
|
65
|
-
this[_rebuildBundle] = !!rebuildBundle
|
|
66
|
-
this[_resetQueues]()
|
|
67
|
-
this[_oldMeta] = null
|
|
37
|
+
this.#resetQueues()
|
|
68
38
|
}
|
|
69
39
|
|
|
70
40
|
async rebuild ({ nodes, handleOptionalFailure = false } = {}) {
|
|
71
41
|
// nothing to do if we're not building anything!
|
|
72
|
-
if (this
|
|
42
|
+
if (this.options.ignoreScripts && !this.options.binLinks) {
|
|
73
43
|
return
|
|
74
44
|
}
|
|
75
45
|
|
|
76
46
|
// when building for the first time, as part of reify, we ignore
|
|
77
47
|
// failures in optional nodes, and just delete them. however, when
|
|
78
48
|
// running JUST a rebuild, we treat optional failures as real fails
|
|
79
|
-
this
|
|
49
|
+
this.#doHandleOptionalFailure = handleOptionalFailure
|
|
80
50
|
|
|
81
51
|
if (!nodes) {
|
|
82
|
-
nodes = await this
|
|
52
|
+
nodes = await this.#loadDefaultNodes()
|
|
83
53
|
}
|
|
84
54
|
|
|
85
55
|
// separates links nodes so that it can run
|
|
@@ -89,15 +59,15 @@ module.exports = cls => class Builder extends cls {
|
|
|
89
59
|
const {
|
|
90
60
|
depNodes,
|
|
91
61
|
linkNodes,
|
|
92
|
-
} = this
|
|
62
|
+
} = this.#retrieveNodesByType(nodes)
|
|
93
63
|
|
|
94
64
|
// build regular deps
|
|
95
|
-
await this
|
|
65
|
+
await this.#build(depNodes, {})
|
|
96
66
|
|
|
97
67
|
// build link deps
|
|
98
68
|
if (linkNodes.size) {
|
|
99
|
-
this
|
|
100
|
-
await this
|
|
69
|
+
this.#resetQueues()
|
|
70
|
+
await this.#build(linkNodes, { type: 'links' })
|
|
101
71
|
}
|
|
102
72
|
|
|
103
73
|
process.emit('timeEnd', 'build')
|
|
@@ -105,20 +75,20 @@ module.exports = cls => class Builder extends cls {
|
|
|
105
75
|
|
|
106
76
|
// if we don't have a set of nodes, then just rebuild
|
|
107
77
|
// the actual tree on disk.
|
|
108
|
-
async
|
|
78
|
+
async #loadDefaultNodes () {
|
|
109
79
|
let nodes
|
|
110
80
|
const tree = await this.loadActual()
|
|
111
81
|
let filterSet
|
|
112
|
-
if (!this
|
|
82
|
+
if (!this.options.workspacesEnabled) {
|
|
113
83
|
filterSet = this.excludeWorkspacesDependencySet(tree)
|
|
114
84
|
nodes = tree.inventory.filter(node =>
|
|
115
85
|
filterSet.has(node) || node.isProjectRoot
|
|
116
86
|
)
|
|
117
|
-
} else if (this
|
|
87
|
+
} else if (this.options.workspaces.length) {
|
|
118
88
|
filterSet = this.workspaceDependencySet(
|
|
119
89
|
tree,
|
|
120
|
-
this
|
|
121
|
-
this
|
|
90
|
+
this.options.workspaces,
|
|
91
|
+
this.options.includeWorkspaceRoot
|
|
122
92
|
)
|
|
123
93
|
nodes = tree.inventory.filter(node => filterSet.has(node))
|
|
124
94
|
} else {
|
|
@@ -127,7 +97,7 @@ module.exports = cls => class Builder extends cls {
|
|
|
127
97
|
return nodes
|
|
128
98
|
}
|
|
129
99
|
|
|
130
|
-
|
|
100
|
+
#retrieveNodesByType (nodes) {
|
|
131
101
|
const depNodes = new Set()
|
|
132
102
|
const linkNodes = new Set()
|
|
133
103
|
const storeNodes = new Set()
|
|
@@ -154,7 +124,7 @@ module.exports = cls => class Builder extends cls {
|
|
|
154
124
|
//
|
|
155
125
|
// we avoid doing so if global=true since `bin-links` relies
|
|
156
126
|
// on having the target nodes available in global mode.
|
|
157
|
-
if (!this
|
|
127
|
+
if (!this.options.global) {
|
|
158
128
|
for (const node of linkNodes) {
|
|
159
129
|
depNodes.delete(node.target)
|
|
160
130
|
}
|
|
@@ -166,8 +136,8 @@ module.exports = cls => class Builder extends cls {
|
|
|
166
136
|
}
|
|
167
137
|
}
|
|
168
138
|
|
|
169
|
-
|
|
170
|
-
this
|
|
139
|
+
#resetQueues () {
|
|
140
|
+
this.#queues = {
|
|
171
141
|
preinstall: [],
|
|
172
142
|
install: [],
|
|
173
143
|
postinstall: [],
|
|
@@ -176,46 +146,46 @@ module.exports = cls => class Builder extends cls {
|
|
|
176
146
|
}
|
|
177
147
|
}
|
|
178
148
|
|
|
179
|
-
async
|
|
149
|
+
async #build (nodes, { type = 'deps' }) {
|
|
180
150
|
process.emit('time', `build:${type}`)
|
|
181
151
|
|
|
182
|
-
await this
|
|
152
|
+
await this.#buildQueues(nodes)
|
|
183
153
|
|
|
184
|
-
if (!this
|
|
185
|
-
await this
|
|
154
|
+
if (!this.options.ignoreScripts) {
|
|
155
|
+
await this.#runScripts('preinstall')
|
|
186
156
|
}
|
|
187
157
|
|
|
188
158
|
// links should run prepare scripts and only link bins after that
|
|
189
159
|
if (type === 'links') {
|
|
190
|
-
await this
|
|
160
|
+
await this.#runScripts('prepare')
|
|
191
161
|
}
|
|
192
|
-
if (this
|
|
193
|
-
await this
|
|
162
|
+
if (this.options.binLinks) {
|
|
163
|
+
await this.#linkAllBins()
|
|
194
164
|
}
|
|
195
165
|
|
|
196
|
-
if (!this
|
|
197
|
-
await this
|
|
198
|
-
await this
|
|
166
|
+
if (!this.options.ignoreScripts) {
|
|
167
|
+
await this.#runScripts('install')
|
|
168
|
+
await this.#runScripts('postinstall')
|
|
199
169
|
}
|
|
200
170
|
|
|
201
171
|
process.emit('timeEnd', `build:${type}`)
|
|
202
172
|
}
|
|
203
173
|
|
|
204
|
-
async
|
|
174
|
+
async #buildQueues (nodes) {
|
|
205
175
|
process.emit('time', 'build:queue')
|
|
206
176
|
const set = new Set()
|
|
207
177
|
|
|
208
178
|
const promises = []
|
|
209
179
|
for (const node of nodes) {
|
|
210
|
-
promises.push(this
|
|
180
|
+
promises.push(this.#addToBuildSet(node, set))
|
|
211
181
|
|
|
212
182
|
// if it has bundle deps, add those too, if rebuildBundle
|
|
213
|
-
if (this
|
|
183
|
+
if (this.options.rebuildBundle !== false) {
|
|
214
184
|
const bd = node.package.bundleDependencies
|
|
215
185
|
if (bd && bd.length) {
|
|
216
186
|
dfwalk({
|
|
217
187
|
tree: node,
|
|
218
|
-
leave: node => promises.push(this
|
|
188
|
+
leave: node => promises.push(this.#addToBuildSet(node, set)),
|
|
219
189
|
getChildren: node => [...node.children.values()],
|
|
220
190
|
filter: node => node.inBundle,
|
|
221
191
|
})
|
|
@@ -236,7 +206,7 @@ module.exports = cls => class Builder extends cls {
|
|
|
236
206
|
const tests = { bin, preinstall, install, postinstall, prepare }
|
|
237
207
|
for (const [key, has] of Object.entries(tests)) {
|
|
238
208
|
if (has) {
|
|
239
|
-
this[
|
|
209
|
+
this.#queues[key].push(node)
|
|
240
210
|
}
|
|
241
211
|
}
|
|
242
212
|
}
|
|
@@ -249,21 +219,21 @@ module.exports = cls => class Builder extends cls {
|
|
|
249
219
|
// the node path. Otherwise a package can have a preinstall script
|
|
250
220
|
// that unlinks something, to allow them to silently overwrite system
|
|
251
221
|
// binaries, which is unsafe and insecure.
|
|
252
|
-
if (!node.globalTop || this
|
|
222
|
+
if (!node.globalTop || this.options.force) {
|
|
253
223
|
return
|
|
254
224
|
}
|
|
255
225
|
const { path, package: pkg } = node
|
|
256
226
|
await binLinks.checkBins({ pkg, path, top: true, global: true })
|
|
257
227
|
}
|
|
258
228
|
|
|
259
|
-
async
|
|
229
|
+
async #addToBuildSet (node, set, refreshed = false) {
|
|
260
230
|
if (set.has(node)) {
|
|
261
231
|
return
|
|
262
232
|
}
|
|
263
233
|
|
|
264
|
-
if (this
|
|
234
|
+
if (this.#oldMeta === null) {
|
|
265
235
|
const { root: { meta } } = node
|
|
266
|
-
this
|
|
236
|
+
this.#oldMeta = meta && meta.loadedFromDisk &&
|
|
267
237
|
!(meta.originalLockfileVersion >= 2)
|
|
268
238
|
}
|
|
269
239
|
|
|
@@ -272,7 +242,7 @@ module.exports = cls => class Builder extends cls {
|
|
|
272
242
|
|
|
273
243
|
const { preinstall, install, postinstall, prepare } = scripts
|
|
274
244
|
const anyScript = preinstall || install || postinstall || prepare
|
|
275
|
-
if (!refreshed && !anyScript && (hasInstallScript || this
|
|
245
|
+
if (!refreshed && !anyScript && (hasInstallScript || this.#oldMeta)) {
|
|
276
246
|
// we either have an old metadata (and thus might have scripts)
|
|
277
247
|
// or we have an indication that there's install scripts (but
|
|
278
248
|
// don't yet know what they are) so we have to load the package.json
|
|
@@ -286,7 +256,7 @@ module.exports = cls => class Builder extends cls {
|
|
|
286
256
|
|
|
287
257
|
const { scripts = {} } = pkg
|
|
288
258
|
node.package.scripts = scripts
|
|
289
|
-
return this
|
|
259
|
+
return this.#addToBuildSet(node, set, true)
|
|
290
260
|
}
|
|
291
261
|
|
|
292
262
|
// Rebuild node-gyp dependencies lacking an install or preinstall script
|
|
@@ -309,8 +279,8 @@ module.exports = cls => class Builder extends cls {
|
|
|
309
279
|
}
|
|
310
280
|
}
|
|
311
281
|
|
|
312
|
-
async
|
|
313
|
-
const queue = this[
|
|
282
|
+
async #runScripts (event) {
|
|
283
|
+
const queue = this.#queues[event]
|
|
314
284
|
|
|
315
285
|
if (!queue.length) {
|
|
316
286
|
return
|
|
@@ -358,7 +328,7 @@ module.exports = cls => class Builder extends cls {
|
|
|
358
328
|
pkg,
|
|
359
329
|
stdio,
|
|
360
330
|
env,
|
|
361
|
-
scriptShell: this
|
|
331
|
+
scriptShell: this.options.scriptShell,
|
|
362
332
|
}
|
|
363
333
|
const p = runScript(runOpts).catch(er => {
|
|
364
334
|
const { code, signal } = er
|
|
@@ -382,7 +352,7 @@ module.exports = cls => class Builder extends cls {
|
|
|
382
352
|
log.info('run', pkg._id, event, { code, signal })
|
|
383
353
|
})
|
|
384
354
|
|
|
385
|
-
await (this
|
|
355
|
+
await (this.#doHandleOptionalFailure
|
|
386
356
|
? this[_handleOptionalFailure](node, p)
|
|
387
357
|
: p)
|
|
388
358
|
|
|
@@ -391,8 +361,8 @@ module.exports = cls => class Builder extends cls {
|
|
|
391
361
|
process.emit('timeEnd', `build:run:${event}`)
|
|
392
362
|
}
|
|
393
363
|
|
|
394
|
-
async
|
|
395
|
-
const queue = this
|
|
364
|
+
async #linkAllBins () {
|
|
365
|
+
const queue = this.#queues.bin
|
|
396
366
|
if (!queue.length) {
|
|
397
367
|
return
|
|
398
368
|
}
|
|
@@ -402,14 +372,15 @@ module.exports = cls => class Builder extends cls {
|
|
|
402
372
|
// sort the queue by node path, so that the module-local collision
|
|
403
373
|
// detector in bin-links will always resolve the same way.
|
|
404
374
|
for (const node of queue.sort(sortNodes)) {
|
|
405
|
-
|
|
375
|
+
// TODO these run before they're awaited
|
|
376
|
+
promises.push(this.#createBinLinks(node))
|
|
406
377
|
}
|
|
407
378
|
|
|
408
379
|
await promiseAllRejectLate(promises)
|
|
409
380
|
process.emit('timeEnd', 'build:link')
|
|
410
381
|
}
|
|
411
382
|
|
|
412
|
-
async
|
|
383
|
+
async #createBinLinks (node) {
|
|
413
384
|
if (this[_trashList].has(node.path)) {
|
|
414
385
|
return
|
|
415
386
|
}
|
|
@@ -420,11 +391,11 @@ module.exports = cls => class Builder extends cls {
|
|
|
420
391
|
pkg: node.package,
|
|
421
392
|
path: node.path,
|
|
422
393
|
top: !!(node.isTop || node.globalTop),
|
|
423
|
-
force: this
|
|
394
|
+
force: this.options.force,
|
|
424
395
|
global: !!node.globalTop,
|
|
425
396
|
})
|
|
426
397
|
|
|
427
|
-
await (this
|
|
398
|
+
await (this.#doHandleOptionalFailure
|
|
428
399
|
? this[_handleOptionalFailure](node, p)
|
|
429
400
|
: p)
|
|
430
401
|
|
package/lib/arborist/reify.js
CHANGED
|
@@ -24,7 +24,6 @@ const PackageJson = require('@npmcli/package-json')
|
|
|
24
24
|
const packageContents = require('@npmcli/installed-package-contents')
|
|
25
25
|
const runScript = require('@npmcli/run-script')
|
|
26
26
|
const { checkEngine, checkPlatform } = require('npm-install-checks')
|
|
27
|
-
const _force = Symbol.for('force')
|
|
28
27
|
|
|
29
28
|
const treeCheck = require('../tree-check.js')
|
|
30
29
|
const relpath = require('../relpath.js')
|
|
@@ -48,8 +47,6 @@ const _retireShallowNodes = Symbol.for('retireShallowNodes')
|
|
|
48
47
|
const _getBundlesByDepth = Symbol('getBundlesByDepth')
|
|
49
48
|
const _registryResolved = Symbol('registryResolved')
|
|
50
49
|
const _addNodeToTrashList = Symbol.for('addNodeToTrashList')
|
|
51
|
-
const _workspaces = Symbol.for('workspaces')
|
|
52
|
-
const _workspacesEnabled = Symbol.for('workspacesEnabled')
|
|
53
50
|
|
|
54
51
|
// shared by rebuild mixin
|
|
55
52
|
const _trashList = Symbol.for('trashList')
|
|
@@ -91,14 +88,11 @@ const _validateNodeModules = Symbol('validateNodeModules')
|
|
|
91
88
|
const _nmValidated = Symbol('nmValidated')
|
|
92
89
|
const _validatePath = Symbol('validatePath')
|
|
93
90
|
const _reifyPackages = Symbol.for('reifyPackages')
|
|
94
|
-
const _includeWorkspaceRoot = Symbol.for('includeWorkspaceRoot')
|
|
95
91
|
|
|
96
92
|
const _omitDev = Symbol('omitDev')
|
|
97
93
|
const _omitOptional = Symbol('omitOptional')
|
|
98
94
|
const _omitPeer = Symbol('omitPeer')
|
|
99
95
|
|
|
100
|
-
const _global = Symbol.for('global')
|
|
101
|
-
|
|
102
96
|
const _pruneBundledMetadeps = Symbol('pruneBundledMetadeps')
|
|
103
97
|
|
|
104
98
|
// defined by Ideal mixin
|
|
@@ -142,7 +136,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
142
136
|
async reify (options = {}) {
|
|
143
137
|
const linked = (options.installStrategy || this.options.installStrategy) === 'linked'
|
|
144
138
|
|
|
145
|
-
if (this[_packageLockOnly] && this
|
|
139
|
+
if (this[_packageLockOnly] && this.options.global) {
|
|
146
140
|
const er = new Error('cannot generate lockfile for global packages')
|
|
147
141
|
er.code = 'ESHRINKWRAPGLOBAL'
|
|
148
142
|
throw er
|
|
@@ -287,7 +281,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
287
281
|
.then(() => process.emit('timeEnd', 'reify:loadTrees'))
|
|
288
282
|
}
|
|
289
283
|
|
|
290
|
-
const actualOpt = this
|
|
284
|
+
const actualOpt = this.options.global ? {
|
|
291
285
|
ignoreMissing: true,
|
|
292
286
|
global: true,
|
|
293
287
|
filter: (node, kid) => {
|
|
@@ -314,7 +308,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
314
308
|
},
|
|
315
309
|
} : { ignoreMissing: true }
|
|
316
310
|
|
|
317
|
-
if (!this
|
|
311
|
+
if (!this.options.global) {
|
|
318
312
|
return Promise.all([
|
|
319
313
|
this.loadActual(actualOpt),
|
|
320
314
|
this.buildIdealTree(bitOpt),
|
|
@@ -341,12 +335,12 @@ module.exports = cls => class Reifier extends cls {
|
|
|
341
335
|
// to just invalidate the parts that changed, but avoid walking the
|
|
342
336
|
// whole tree again.
|
|
343
337
|
|
|
344
|
-
const includeWorkspaces = this
|
|
345
|
-
const includeRootDeps = !
|
|
346
|
-
|| this
|
|
338
|
+
const includeWorkspaces = this.options.workspacesEnabled
|
|
339
|
+
const includeRootDeps = !includeWorkspaces
|
|
340
|
+
|| this.options.includeWorkspaceRoot && this.options.workspaces.length > 0
|
|
347
341
|
|
|
348
342
|
const filterNodes = []
|
|
349
|
-
if (this
|
|
343
|
+
if (this.options.global && this.explicitRequests.size) {
|
|
350
344
|
const idealTree = this.idealTree.target
|
|
351
345
|
const actualTree = this.actualTree.target
|
|
352
346
|
// we ONLY are allowed to make changes in the global top-level
|
|
@@ -364,7 +358,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
364
358
|
} else {
|
|
365
359
|
if (includeWorkspaces) {
|
|
366
360
|
// add all ws nodes to filterNodes
|
|
367
|
-
for (const ws of this
|
|
361
|
+
for (const ws of this.options.workspaces) {
|
|
368
362
|
const ideal = this.idealTree.children.get(ws)
|
|
369
363
|
if (ideal) {
|
|
370
364
|
filterNodes.push(ideal)
|
|
@@ -656,7 +650,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
656
650
|
|
|
657
651
|
// do not allow node_modules to be a symlink
|
|
658
652
|
async [_validateNodeModules] (nm) {
|
|
659
|
-
if (this
|
|
653
|
+
if (this.options.force || this[_nmValidated].has(nm)) {
|
|
660
654
|
return
|
|
661
655
|
}
|
|
662
656
|
const st = await lstat(nm).catch(() => null)
|
|
@@ -992,11 +986,11 @@ module.exports = cls => class Reifier extends cls {
|
|
|
992
986
|
const tree = this.idealTree
|
|
993
987
|
|
|
994
988
|
// if we're operating on a workspace, only audit the workspace deps
|
|
995
|
-
if (this
|
|
989
|
+
if (this.options.workspaces.length) {
|
|
996
990
|
options.filterSet = this.workspaceDependencySet(
|
|
997
991
|
tree,
|
|
998
|
-
this
|
|
999
|
-
this
|
|
992
|
+
this.options.workspaces,
|
|
993
|
+
this.options.includeWorkspaceRoot
|
|
1000
994
|
)
|
|
1001
995
|
}
|
|
1002
996
|
|
|
@@ -1220,7 +1214,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1220
1214
|
// saveIdealTree to be able to write the lockfile by default.
|
|
1221
1215
|
const saveIdealTree = !(
|
|
1222
1216
|
(!save && !hasUpdates)
|
|
1223
|
-
|| this
|
|
1217
|
+
|| this.options.global
|
|
1224
1218
|
|| this[_dryRun]
|
|
1225
1219
|
)
|
|
1226
1220
|
|
|
@@ -1566,7 +1560,7 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1566
1560
|
this.actualTree = this.idealTree
|
|
1567
1561
|
this.idealTree = null
|
|
1568
1562
|
|
|
1569
|
-
if (!this
|
|
1563
|
+
if (!this.options.global) {
|
|
1570
1564
|
await this.actualTree.meta.save()
|
|
1571
1565
|
const ignoreScripts = !!this.options.ignoreScripts
|
|
1572
1566
|
// if we aren't doing a dry run or ignoring scripts and we actually made changes to the dep
|
|
@@ -1593,4 +1587,22 @@ module.exports = cls => class Reifier extends cls {
|
|
|
1593
1587
|
}
|
|
1594
1588
|
}
|
|
1595
1589
|
}
|
|
1590
|
+
|
|
1591
|
+
async dedupe (options = {}) {
|
|
1592
|
+
// allow the user to set options on the ctor as well.
|
|
1593
|
+
// XXX: deprecate separate method options objects.
|
|
1594
|
+
options = { ...this.options, ...options }
|
|
1595
|
+
const tree = await this.loadVirtual().catch(() => this.loadActual())
|
|
1596
|
+
const names = []
|
|
1597
|
+
for (const name of tree.inventory.query('name')) {
|
|
1598
|
+
if (tree.inventory.query('name', name).size > 1) {
|
|
1599
|
+
names.push(name)
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
return this.reify({
|
|
1603
|
+
...options,
|
|
1604
|
+
preferDedupe: true,
|
|
1605
|
+
update: { names },
|
|
1606
|
+
})
|
|
1607
|
+
}
|
|
1596
1608
|
}
|
|
@@ -2,49 +2,49 @@
|
|
|
2
2
|
// are case-insensitive and unicode-normalizing, so we need to treat
|
|
3
3
|
// node.children.get('FOO') and node.children.get('foo') as the same thing.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const OGMap = Map
|
|
9
|
-
module.exports = class Map extends OGMap {
|
|
5
|
+
module.exports = class CIMap extends Map {
|
|
6
|
+
#keys = new Map()
|
|
7
|
+
|
|
10
8
|
constructor (items = []) {
|
|
11
9
|
super()
|
|
12
|
-
this[_keys] = new OGMap()
|
|
13
10
|
for (const [key, val] of items) {
|
|
14
11
|
this.set(key, val)
|
|
15
12
|
}
|
|
16
13
|
}
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
#normKey (key) {
|
|
16
|
+
if (typeof key !== 'string') {
|
|
17
|
+
return key
|
|
18
|
+
}
|
|
19
|
+
return key.normalize('NFKD').toLowerCase()
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
get (key) {
|
|
23
|
-
const normKey = this
|
|
24
|
-
return this
|
|
23
|
+
const normKey = this.#normKey(key)
|
|
24
|
+
return this.#keys.has(normKey) ? super.get(this.#keys.get(normKey))
|
|
25
25
|
: undefined
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
set (key, val) {
|
|
29
|
-
const normKey = this
|
|
30
|
-
if (this
|
|
31
|
-
super.delete(this
|
|
29
|
+
const normKey = this.#normKey(key)
|
|
30
|
+
if (this.#keys.has(normKey)) {
|
|
31
|
+
super.delete(this.#keys.get(normKey))
|
|
32
32
|
}
|
|
33
|
-
this
|
|
33
|
+
this.#keys.set(normKey, key)
|
|
34
34
|
return super.set(key, val)
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
delete (key) {
|
|
38
|
-
const normKey = this
|
|
39
|
-
if (this
|
|
40
|
-
const prevKey = this
|
|
41
|
-
this
|
|
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
42
|
return super.delete(prevKey)
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
has (key) {
|
|
47
|
-
const normKey = this
|
|
48
|
-
return this
|
|
47
|
+
const normKey = this.#normKey(key)
|
|
48
|
+
return this.#keys.has(normKey) && super.has(this.#keys.get(normKey))
|
|
49
49
|
}
|
|
50
50
|
}
|
package/lib/index.js
CHANGED