@npmcli/arborist 7.5.0 → 7.5.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.
@@ -463,7 +463,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
463
463
  }
464
464
  const dir = resolve(nm, name)
465
465
  const st = await lstat(dir)
466
- .catch(/* istanbul ignore next */ er => null)
466
+ .catch(/* istanbul ignore next */ () => null)
467
467
  if (st && st.isSymbolicLink()) {
468
468
  const target = await readlink(dir)
469
469
  const real = resolve(dirname(dir), target).replace(/#/g, '%23')
@@ -1024,7 +1024,7 @@ This is a one-time fix-up, please be patient...
1024
1024
  for (const e of this.#problemEdges(placed)) {
1025
1025
  promises.push(() =>
1026
1026
  this.#fetchManifest(npa.resolve(e.name, e.spec, fromPath(placed, e)))
1027
- .catch(er => null)
1027
+ .catch(() => null)
1028
1028
  )
1029
1029
  }
1030
1030
  },
@@ -1273,7 +1273,7 @@ This is a one-time fix-up, please be patient...
1273
1273
  })
1274
1274
  }
1275
1275
 
1276
- #linkFromSpec (name, spec, parent, edge) {
1276
+ #linkFromSpec (name, spec, parent) {
1277
1277
  const realpath = spec.fetchSpec
1278
1278
  const { installLinks, legacyPeerDeps } = this
1279
1279
  return rpj(realpath + '/package.json').catch(() => ({})).then(pkg => {
@@ -74,20 +74,26 @@ class Arborist extends Base {
74
74
  Arborist: this.constructor,
75
75
  binLinks: 'binLinks' in options ? !!options.binLinks : true,
76
76
  cache: options.cache || `${homedir()}/.npm/_cacache`,
77
+ dryRun: !!options.dryRun,
78
+ formatPackageLock: 'formatPackageLock' in options ? !!options.formatPackageLock : true,
77
79
  force: !!options.force,
78
80
  global: !!options.global,
79
81
  ignoreScripts: !!options.ignoreScripts,
80
82
  installStrategy: options.global ? 'shallow' : (options.installStrategy ? options.installStrategy : 'hoisted'),
81
83
  lockfileVersion: lockfileVersion(options.lockfileVersion),
84
+ packageLockOnly: !!options.packageLockOnly,
82
85
  packumentCache: options.packumentCache || new Map(),
83
86
  path: options.path || '.',
84
87
  rebuildBundle: 'rebuildBundle' in options ? !!options.rebuildBundle : true,
85
88
  replaceRegistryHost: options.replaceRegistryHost,
89
+ savePrefix: 'savePrefix' in options ? options.savePrefix : '^',
86
90
  scriptShell: options.scriptShell,
87
91
  workspaces: options.workspaces || [],
88
92
  workspacesEnabled: options.workspacesEnabled !== false,
89
93
  }
90
- // TODO is this even used? If not is that a bug?
94
+ // TODO we only ever look at this.options.replaceRegistryHost, not
95
+ // this.replaceRegistryHost. Defaulting needs to be written back to
96
+ // this.options to work properly
91
97
  this.replaceRegistryHost = this.options.replaceRegistryHost =
92
98
  (!this.options.replaceRegistryHost || this.options.replaceRegistryHost === 'npmjs') ?
93
99
  'registry.npmjs.org' : this.options.replaceRegistryHost
@@ -96,6 +102,7 @@ class Arborist extends Base {
96
102
  throw new Error(`Invalid saveType ${options.saveType}`)
97
103
  }
98
104
  this.cache = resolve(this.options.cache)
105
+ this.diff = null
99
106
  this.path = resolve(this.options.path)
100
107
  timeEnd()
101
108
  }
@@ -250,6 +257,24 @@ class Arborist extends Base {
250
257
  this.finishTracker('audit')
251
258
  return ret
252
259
  }
260
+
261
+ async dedupe (options = {}) {
262
+ // allow the user to set options on the ctor as well.
263
+ // XXX: deprecate separate method options objects.
264
+ options = { ...this.options, ...options }
265
+ const tree = await this.loadVirtual().catch(() => this.loadActual())
266
+ const names = []
267
+ for (const name of tree.inventory.query('name')) {
268
+ if (tree.inventory.query('name', name).size > 1) {
269
+ names.push(name)
270
+ }
271
+ }
272
+ return this.reify({
273
+ ...options,
274
+ preferDedupe: true,
275
+ update: { names },
276
+ })
277
+ }
253
278
  }
254
279
 
255
280
  module.exports = Arborist
@@ -212,7 +212,7 @@ module.exports = cls => class IsolatedReifier extends cls {
212
212
  return { edges, nodes }
213
213
  }
214
214
 
215
- async [_createIsolatedTree] (idealTree) {
215
+ async [_createIsolatedTree] () {
216
216
  await this[_makeIdealGraph](this.options)
217
217
 
218
218
  const proxiedIdealTree = this.idealGraph
@@ -336,8 +336,8 @@ module.exports = cls => class ActualLoader extends cls {
336
336
  await this.#loadFSChildren(node.target)
337
337
  return Promise.all(
338
338
  [...node.target.children.entries()]
339
- .filter(([name, kid]) => !did.has(kid.realpath))
340
- .map(([name, kid]) => this.#loadFSTree(kid))
339
+ .filter(([, kid]) => !did.has(kid.realpath))
340
+ .map(([, kid]) => this.#loadFSTree(kid))
341
341
  )
342
342
  }
343
343
  }
@@ -283,7 +283,7 @@ module.exports = cls => class VirtualLoader extends cls {
283
283
  return node
284
284
  }
285
285
 
286
- #loadLink (location, targetLoc, target, meta) {
286
+ #loadLink (location, targetLoc, target) {
287
287
  const path = resolve(this.path, location)
288
288
  const link = new Link({
289
289
  installLinks: this.installLinks,
@@ -38,119 +38,96 @@ const { saveTypeMap, hasSubKey } = require('../add-rm-pkg-deps.js')
38
38
  const Shrinkwrap = require('../shrinkwrap.js')
39
39
  const { defaultLockfileVersion } = Shrinkwrap
40
40
 
41
- const _retiredPaths = Symbol('retiredPaths')
42
- const _retiredUnchanged = Symbol('retiredUnchanged')
43
- const _sparseTreeDirs = Symbol('sparseTreeDirs')
44
- const _sparseTreeRoots = Symbol('sparseTreeRoots')
45
- const _savePrefix = Symbol('savePrefix')
41
+ // Part of steps (steps need refactoring before we can do anything about these)
46
42
  const _retireShallowNodes = Symbol.for('retireShallowNodes')
47
- const _getBundlesByDepth = Symbol('getBundlesByDepth')
48
- const _registryResolved = Symbol('registryResolved')
49
- const _addNodeToTrashList = Symbol.for('addNodeToTrashList')
43
+ const _loadBundlesAndUpdateTrees = Symbol.for('loadBundlesAndUpdateTrees')
44
+ const _submitQuickAudit = Symbol('submitQuickAudit')
45
+ const _addOmitsToTrashList = Symbol('addOmitsToTrashList')
46
+ const _unpackNewModules = Symbol.for('unpackNewModules')
47
+ const _build = Symbol.for('build')
50
48
 
51
49
  // shared by rebuild mixin
52
50
  const _trashList = Symbol.for('trashList')
53
51
  const _handleOptionalFailure = Symbol.for('handleOptionalFailure')
54
52
  const _loadTrees = Symbol.for('loadTrees')
53
+ // defined by rebuild mixin
54
+ const _checkBins = Symbol.for('checkBins')
55
55
 
56
56
  // shared symbols for swapping out when testing
57
+ // TODO tests should not be this deep into internals
57
58
  const _diffTrees = Symbol.for('diffTrees')
58
59
  const _createSparseTree = Symbol.for('createSparseTree')
59
60
  const _loadShrinkwrapsAndUpdateTrees = Symbol.for('loadShrinkwrapsAndUpdateTrees')
60
- const _shrinkwrapInflated = Symbol('shrinkwrapInflated')
61
- const _bundleUnpacked = Symbol('bundleUnpacked')
62
- const _bundleMissing = Symbol('bundleMissing')
63
61
  const _reifyNode = Symbol.for('reifyNode')
64
- const _extractOrLink = Symbol('extractOrLink')
65
62
  const _updateAll = Symbol.for('updateAll')
66
63
  const _updateNames = Symbol.for('updateNames')
67
- // defined by rebuild mixin
68
- const _checkBins = Symbol.for('checkBins')
69
- const _symlink = Symbol('symlink')
70
- const _warnDeprecated = Symbol('warnDeprecated')
71
- const _loadBundlesAndUpdateTrees = Symbol.for('loadBundlesAndUpdateTrees')
72
- const _submitQuickAudit = Symbol('submitQuickAudit')
73
- const _unpackNewModules = Symbol.for('unpackNewModules')
74
64
  const _moveContents = Symbol.for('moveContents')
75
65
  const _moveBackRetiredUnchanged = Symbol.for('moveBackRetiredUnchanged')
76
- const _build = Symbol.for('build')
77
66
  const _removeTrash = Symbol.for('removeTrash')
78
67
  const _renamePath = Symbol.for('renamePath')
79
68
  const _rollbackRetireShallowNodes = Symbol.for('rollbackRetireShallowNodes')
80
69
  const _rollbackCreateSparseTree = Symbol.for('rollbackCreateSparseTree')
81
70
  const _rollbackMoveBackRetiredUnchanged = Symbol.for('rollbackMoveBackRetiredUnchanged')
82
71
  const _saveIdealTree = Symbol.for('saveIdealTree')
83
- const _copyIdealToActual = Symbol('copyIdealToActual')
84
- const _addOmitsToTrashList = Symbol('addOmitsToTrashList')
85
- const _packageLockOnly = Symbol('packageLockOnly')
86
- const _dryRun = Symbol('dryRun')
87
- const _validateNodeModules = Symbol('validateNodeModules')
88
- const _nmValidated = Symbol('nmValidated')
89
- const _validatePath = Symbol('validatePath')
90
72
  const _reifyPackages = Symbol.for('reifyPackages')
91
73
 
92
- const _omitDev = Symbol('omitDev')
93
- const _omitOptional = Symbol('omitOptional')
94
- const _omitPeer = Symbol('omitPeer')
95
-
96
- const _pruneBundledMetadeps = Symbol('pruneBundledMetadeps')
97
-
98
- // defined by Ideal mixin
74
+ // defined by build-ideal-tree mixin
99
75
  const _resolvedAdd = Symbol.for('resolvedAdd')
100
76
  const _usePackageLock = Symbol.for('usePackageLock')
101
- const _formatPackageLock = Symbol.for('formatPackageLock')
77
+ // used by build-ideal-tree mixin
78
+ const _addNodeToTrashList = Symbol.for('addNodeToTrashList')
102
79
 
103
80
  const _createIsolatedTree = Symbol.for('createIsolatedTree')
104
81
 
105
82
  module.exports = cls => class Reifier extends cls {
83
+ #bundleMissing = new Set() // child nodes we'd EXPECT to be included in a bundle, but aren't
84
+ #bundleUnpacked = new Set() // the nodes we unpack to read their bundles
85
+ #dryRun
86
+ #nmValidated = new Set()
87
+ #omitDev
88
+ #omitPeer
89
+ #omitOptional
90
+ #retiredPaths = {}
91
+ #retiredUnchanged = {}
92
+ #savePrefix
93
+ #shrinkwrapInflated = new Set()
94
+ #sparseTreeDirs = new Set()
95
+ #sparseTreeRoots = new Set()
96
+
106
97
  constructor (options) {
107
98
  super(options)
108
99
 
109
- const {
110
- savePrefix = '^',
111
- packageLockOnly = false,
112
- dryRun = false,
113
- formatPackageLock = true,
114
- } = options
115
-
116
- this[_dryRun] = !!dryRun
117
- this[_packageLockOnly] = !!packageLockOnly
118
- this[_savePrefix] = savePrefix
119
- this[_formatPackageLock] = !!formatPackageLock
120
-
121
- this.diff = null
122
- this[_retiredPaths] = {}
123
- this[_shrinkwrapInflated] = new Set()
124
- this[_retiredUnchanged] = {}
125
- this[_sparseTreeDirs] = new Set()
126
- this[_sparseTreeRoots] = new Set()
127
100
  this[_trashList] = new Set()
128
- // the nodes we unpack to read their bundles
129
- this[_bundleUnpacked] = new Set()
130
- // child nodes we'd EXPECT to be included in a bundle, but aren't
131
- this[_bundleMissing] = new Set()
132
- this[_nmValidated] = new Set()
133
101
  }
134
102
 
135
103
  // public method
136
104
  async reify (options = {}) {
137
105
  const linked = (options.installStrategy || this.options.installStrategy) === 'linked'
138
106
 
139
- if (this[_packageLockOnly] && this.options.global) {
107
+ if (this.options.packageLockOnly && this.options.global) {
140
108
  const er = new Error('cannot generate lockfile for global packages')
141
109
  er.code = 'ESHRINKWRAPGLOBAL'
142
110
  throw er
143
111
  }
144
112
 
145
113
  const omit = new Set(options.omit || [])
146
- this[_omitDev] = omit.has('dev')
147
- this[_omitOptional] = omit.has('optional')
148
- this[_omitPeer] = omit.has('peer')
114
+ this.#omitDev = omit.has('dev')
115
+ this.#omitOptional = omit.has('optional')
116
+ this.#omitPeer = omit.has('peer')
149
117
 
150
118
  // start tracker block
151
119
  this.addTracker('reify')
152
120
  const timeEnd = time.start('reify')
153
- await this[_validatePath]()
121
+ // don't create missing dirs on dry runs
122
+ if (!this.options.packageLockOnly && !this.options.dryRun) {
123
+ // we do NOT want to set ownership on this folder, especially
124
+ // recursively, because it can have other side effects to do that
125
+ // in a project directory. We just want to make it if it's missing.
126
+ await mkdir(resolve(this.path), { recursive: true })
127
+
128
+ // do not allow the top-level node_modules to be a symlink
129
+ await this.#validateNodeModules(resolve(this.path, 'node_modules'))
130
+ }
154
131
  await this[_loadTrees](options)
155
132
 
156
133
  const oldTree = this.idealTree
@@ -159,7 +136,7 @@ module.exports = cls => class Reifier extends cls {
159
136
  // this is currently technical debt which will be resolved in a refactor
160
137
  // of Node/Link trees
161
138
  log.warn('reify', 'The "linked" install strategy is EXPERIMENTAL and may contain bugs.')
162
- this.idealTree = await this[_createIsolatedTree](this.idealTree)
139
+ this.idealTree = await this[_createIsolatedTree]()
163
140
  }
164
141
  await this[_diffTrees]()
165
142
  await this[_reifyPackages]()
@@ -169,7 +146,124 @@ module.exports = cls => class Reifier extends cls {
169
146
  this.idealTree = oldTree
170
147
  }
171
148
  await this[_saveIdealTree](options)
172
- await this[_copyIdealToActual]()
149
+ // clean up any trash that is still in the tree
150
+ for (const path of this[_trashList]) {
151
+ const loc = relpath(this.idealTree.realpath, path)
152
+ const node = this.idealTree.inventory.get(loc)
153
+ if (node && node.root === this.idealTree) {
154
+ node.parent = null
155
+ }
156
+ }
157
+
158
+ // if we filtered to only certain nodes, then anything ELSE needs
159
+ // to be untouched in the resulting actual tree, even if it differs
160
+ // in the idealTree. Copy over anything that was in the actual and
161
+ // was not changed, delete anything in the ideal and not actual.
162
+ // Then we move the entire idealTree over to this.actualTree, and
163
+ // save the hidden lockfile.
164
+ if (this.diff && this.diff.filterSet.size) {
165
+ const reroot = new Set()
166
+
167
+ const { filterSet } = this.diff
168
+ const seen = new Set()
169
+ for (const [loc, ideal] of this.idealTree.inventory.entries()) {
170
+ seen.add(loc)
171
+
172
+ // if it's an ideal node from the filter set, then skip it
173
+ // because we already made whatever changes were necessary
174
+ if (filterSet.has(ideal)) {
175
+ continue
176
+ }
177
+
178
+ // otherwise, if it's not in the actualTree, then it's not a thing
179
+ // that we actually added. And if it IS in the actualTree, then
180
+ // it's something that we left untouched, so we need to record
181
+ // that.
182
+ const actual = this.actualTree.inventory.get(loc)
183
+ if (!actual) {
184
+ ideal.root = null
185
+ } else {
186
+ if ([...actual.linksIn].some(link => filterSet.has(link))) {
187
+ seen.add(actual.location)
188
+ continue
189
+ }
190
+ const { realpath, isLink } = actual
191
+ if (isLink && ideal.isLink && ideal.realpath === realpath) {
192
+ continue
193
+ } else {
194
+ reroot.add(actual)
195
+ }
196
+ }
197
+ }
198
+
199
+ // now find any actual nodes that may not be present in the ideal
200
+ // tree, but were left behind by virtue of not being in the filter
201
+ for (const [loc, actual] of this.actualTree.inventory.entries()) {
202
+ if (seen.has(loc)) {
203
+ continue
204
+ }
205
+ seen.add(loc)
206
+
207
+ // we know that this is something that ISN'T in the idealTree,
208
+ // or else we will have addressed it in the previous loop.
209
+ // If it's in the filterSet, that means we intentionally removed
210
+ // it, so nothing to do here.
211
+ if (filterSet.has(actual)) {
212
+ continue
213
+ }
214
+
215
+ reroot.add(actual)
216
+ }
217
+
218
+ // go through the rerooted actual nodes, and move them over.
219
+ for (const actual of reroot) {
220
+ actual.root = this.idealTree
221
+ }
222
+
223
+ // prune out any tops that lack a linkIn, they are no longer relevant.
224
+ for (const top of this.idealTree.tops) {
225
+ if (top.linksIn.size === 0) {
226
+ top.root = null
227
+ }
228
+ }
229
+
230
+ // need to calculate dep flags, since nodes may have been marked
231
+ // as extraneous or otherwise incorrect during transit.
232
+ calcDepFlags(this.idealTree)
233
+ }
234
+
235
+ // save the ideal's meta as a hidden lockfile after we actualize it
236
+ this.idealTree.meta.filename =
237
+ this.idealTree.realpath + '/node_modules/.package-lock.json'
238
+ this.idealTree.meta.hiddenLockfile = true
239
+ this.idealTree.meta.lockfileVersion = defaultLockfileVersion
240
+
241
+ this.actualTree = this.idealTree
242
+ this.idealTree = null
243
+
244
+ if (!this.options.global) {
245
+ await this.actualTree.meta.save()
246
+ const ignoreScripts = !!this.options.ignoreScripts
247
+ // if we aren't doing a dry run or ignoring scripts and we actually made changes to the dep
248
+ // tree, then run the dependencies scripts
249
+ if (!this.options.dryRun && !ignoreScripts && this.diff && this.diff.children.length) {
250
+ const { path, package: pkg } = this.actualTree.target
251
+ const stdio = this.options.foregroundScripts ? 'inherit' : 'pipe'
252
+ const { scripts = {} } = pkg
253
+ for (const event of ['predependencies', 'dependencies', 'postdependencies']) {
254
+ if (Object.prototype.hasOwnProperty.call(scripts, event)) {
255
+ log.info('run', pkg._id, event, scripts[event])
256
+ await time.start(`reify:run:${event}`, () => runScript({
257
+ event,
258
+ path,
259
+ pkg,
260
+ stdio,
261
+ scriptShell: this.options.scriptShell,
262
+ }))
263
+ }
264
+ }
265
+ }
266
+ }
173
267
  // This is a very bad pattern and I can't wait to stop doing it
174
268
  this.auditReport = await this.auditReport
175
269
 
@@ -178,28 +272,13 @@ module.exports = cls => class Reifier extends cls {
178
272
  return treeCheck(this.actualTree)
179
273
  }
180
274
 
181
- async [_validatePath] () {
182
- // don't create missing dirs on dry runs
183
- if (this[_packageLockOnly] || this[_dryRun]) {
184
- return
185
- }
186
-
187
- // we do NOT want to set ownership on this folder, especially
188
- // recursively, because it can have other side effects to do that
189
- // in a project directory. We just want to make it if it's missing.
190
- await mkdir(resolve(this.path), { recursive: true })
191
-
192
- // do not allow the top-level node_modules to be a symlink
193
- await this[_validateNodeModules](resolve(this.path, 'node_modules'))
194
- }
195
-
196
275
  async [_reifyPackages] () {
197
276
  // we don't submit the audit report or write to disk on dry runs
198
- if (this[_dryRun]) {
277
+ if (this.options.dryRun) {
199
278
  return
200
279
  }
201
280
 
202
- if (this[_packageLockOnly]) {
281
+ if (this.options.packageLockOnly) {
203
282
  // we already have the complete tree, so just audit it now,
204
283
  // and that's all we have to do here.
205
284
  return this[_submitQuickAudit]()
@@ -248,6 +327,7 @@ module.exports = cls => class Reifier extends cls {
248
327
  throw reifyTerminated
249
328
  }
250
329
  } catch (er) {
330
+ // TODO rollbacks shouldn't be relied on to throw err
251
331
  await this[rollback](er)
252
332
  /* istanbul ignore next - rollback throws, should never hit this */
253
333
  throw er
@@ -272,11 +352,11 @@ module.exports = cls => class Reifier extends cls {
272
352
  const timeEnd = time.start('reify:loadTrees')
273
353
  const bitOpt = {
274
354
  ...options,
275
- complete: this[_packageLockOnly] || this[_dryRun],
355
+ complete: this.options.packageLockOnly || this.options.dryRun,
276
356
  }
277
357
 
278
358
  // if we're only writing a package lock, then it doesn't matter what's here
279
- if (this[_packageLockOnly]) {
359
+ if (this.options.packageLockOnly) {
280
360
  return this.buildIdealTree(bitOpt).then(timeEnd)
281
361
  }
282
362
 
@@ -325,7 +405,7 @@ module.exports = cls => class Reifier extends cls {
325
405
  }
326
406
 
327
407
  [_diffTrees] () {
328
- if (this[_packageLockOnly]) {
408
+ if (this.options.packageLockOnly) {
329
409
  return
330
410
  }
331
411
 
@@ -383,7 +463,7 @@ module.exports = cls => class Reifier extends cls {
383
463
  // find all the nodes that need to change between the actual
384
464
  // and ideal trees.
385
465
  this.diff = Diff.calculate({
386
- shrinkwrapInflated: this[_shrinkwrapInflated],
466
+ shrinkwrapInflated: this.#shrinkwrapInflated,
387
467
  filterNodes,
388
468
  actual: this.actualTree,
389
469
  ideal: this.idealTree,
@@ -405,7 +485,7 @@ module.exports = cls => class Reifier extends cls {
405
485
  // replace them when rolling back on failure.
406
486
  [_addNodeToTrashList] (node, retire = false) {
407
487
  const paths = [node.path, ...node.binPaths]
408
- const moves = this[_retiredPaths]
488
+ const moves = this.#retiredPaths
409
489
  log.silly('reify', 'mark', retire ? 'retired' : 'deleted', paths)
410
490
  for (const path of paths) {
411
491
  if (retire) {
@@ -422,7 +502,7 @@ module.exports = cls => class Reifier extends cls {
422
502
  // changed or removed, so that we can rollback if necessary.
423
503
  [_retireShallowNodes] () {
424
504
  const timeEnd = time.start('reify:retireShallow')
425
- const moves = this[_retiredPaths] = {}
505
+ const moves = this.#retiredPaths = {}
426
506
  for (const diff of this.diff.children) {
427
507
  if (diff.action === 'CHANGE' || diff.action === 'REMOVE') {
428
508
  // we'll have to clean these up at the end, so add them to the list
@@ -455,12 +535,12 @@ module.exports = cls => class Reifier extends cls {
455
535
 
456
536
  [_rollbackRetireShallowNodes] (er) {
457
537
  const timeEnd = time.start('reify:rollback:retireShallow')
458
- const moves = this[_retiredPaths]
538
+ const moves = this.#retiredPaths
459
539
  const movePromises = Object.entries(moves)
460
540
  .map(([from, to]) => this[_renamePath](to, from))
461
541
  return promiseAllRejectLate(movePromises)
462
542
  // ignore subsequent rollback errors
463
- .catch(er => {})
543
+ .catch(() => {})
464
544
  .then(timeEnd)
465
545
  .then(() => {
466
546
  throw er
@@ -470,7 +550,7 @@ module.exports = cls => class Reifier extends cls {
470
550
  // adding to the trash list will skip reifying, and delete them
471
551
  // if they are currently in the tree and otherwise untouched.
472
552
  [_addOmitsToTrashList] () {
473
- if (!this[_omitDev] && !this[_omitOptional] && !this[_omitPeer]) {
553
+ if (!this.#omitDev && !this.#omitOptional && !this.#omitPeer) {
474
554
  return
475
555
  }
476
556
 
@@ -492,10 +572,10 @@ module.exports = cls => class Reifier extends cls {
492
572
 
493
573
  // omit node if the dep type matches any omit flags that were set
494
574
  if (
495
- node.peer && this[_omitPeer] ||
496
- node.dev && this[_omitDev] ||
497
- node.optional && this[_omitOptional] ||
498
- node.devOptional && this[_omitOptional] && this[_omitDev]
575
+ node.peer && this.#omitPeer ||
576
+ node.dev && this.#omitDev ||
577
+ node.optional && this.#omitOptional ||
578
+ node.devOptional && this.#omitOptional && this.#omitDev
499
579
  ) {
500
580
  this[_addNodeToTrashList](node)
501
581
  }
@@ -511,7 +591,7 @@ module.exports = cls => class Reifier extends cls {
511
591
  const leaves = this.diff.leaves
512
592
  .filter(diff => {
513
593
  return (diff.action === 'ADD' || diff.action === 'CHANGE') &&
514
- !this[_sparseTreeDirs].has(diff.ideal.path) &&
594
+ !this.#sparseTreeDirs.has(diff.ideal.path) &&
515
595
  !diff.ideal.isLink
516
596
  })
517
597
  .map(diff => diff.ideal)
@@ -528,25 +608,25 @@ module.exports = cls => class Reifier extends cls {
528
608
  continue
529
609
  }
530
610
  dirsChecked.add(d)
531
- const st = await lstat(d).catch(er => null)
611
+ const st = await lstat(d).catch(() => null)
532
612
  // this can happen if we have a link to a package with a name
533
613
  // that the filesystem treats as if it is the same thing.
534
614
  // would be nice to have conditional istanbul ignores here...
535
615
  /* istanbul ignore next - defense in depth */
536
616
  if (st && !st.isDirectory()) {
537
617
  const retired = retirePath(d)
538
- this[_retiredPaths][d] = retired
618
+ this.#retiredPaths[d] = retired
539
619
  this[_trashList].add(retired)
540
620
  await this[_renamePath](d, retired)
541
621
  }
542
622
  }
543
- this[_sparseTreeDirs].add(node.path)
623
+ this.#sparseTreeDirs.add(node.path)
544
624
  const made = await mkdir(node.path, { recursive: true })
545
625
  // if the directory already exists, made will be undefined. if that's the case
546
626
  // we don't want to remove it because we aren't the ones who created it so we
547
- // omit it from the _sparseTreeRoots
627
+ // omit it from the #sparseTreeRoots
548
628
  if (made) {
549
- this[_sparseTreeRoots].add(made)
629
+ this.#sparseTreeRoots.add(made)
550
630
  }
551
631
  })).then(timeEnd)
552
632
  }
@@ -554,10 +634,10 @@ module.exports = cls => class Reifier extends cls {
554
634
  [_rollbackCreateSparseTree] (er) {
555
635
  const timeEnd = time.start('reify:rollback:createSparse')
556
636
  // cut the roots of the sparse tree that were created, not the leaves
557
- const roots = this[_sparseTreeRoots]
637
+ const roots = this.#sparseTreeRoots
558
638
  // also delete the moves that we retired, so that we can move them back
559
639
  const failures = []
560
- const targets = [...roots, ...Object.keys(this[_retiredPaths])]
640
+ const targets = [...roots, ...Object.keys(this.#retiredPaths)]
561
641
  const unlinks = targets
562
642
  .map(path => rm(path, { recursive: true, force: true }).catch(er => failures.push([path, er])))
563
643
  return promiseAllRejectLate(unlinks).then(() => {
@@ -574,7 +654,7 @@ module.exports = cls => class Reifier extends cls {
574
654
  // we need to unpack them, read that shrinkwrap file, and then update
575
655
  // the tree by calling loadVirtual with the node as the root.
576
656
  [_loadShrinkwrapsAndUpdateTrees] () {
577
- const seen = this[_shrinkwrapInflated]
657
+ const seen = this.#shrinkwrapInflated
578
658
  const shrinkwraps = this.diff.leaves
579
659
  .filter(d => (d.action === 'CHANGE' || d.action === 'ADD' || !d.action) &&
580
660
  d.ideal.hasShrinkwrap && !seen.has(d.ideal) &&
@@ -632,8 +712,13 @@ module.exports = cls => class Reifier extends cls {
632
712
  checkPlatform(node.package, false, { cpu, os, libc })
633
713
  }
634
714
  await this[_checkBins](node)
635
- await this[_extractOrLink](node)
636
- await this[_warnDeprecated](node)
715
+ await this.#extractOrLink(node)
716
+ const { _id, deprecated } = node.package
717
+ // The .catch is in _handleOptionalFailure. Not ideal, this should be cleaned up.
718
+ // eslint-disable-next-line promise/always-return
719
+ if (deprecated) {
720
+ log.warn('deprecated', `${_id}: ${deprecated}`)
721
+ }
637
722
  })
638
723
 
639
724
  return this[_handleOptionalFailure](node, p)
@@ -645,22 +730,22 @@ module.exports = cls => class Reifier extends cls {
645
730
  }
646
731
 
647
732
  // do not allow node_modules to be a symlink
648
- async [_validateNodeModules] (nm) {
649
- if (this.options.force || this[_nmValidated].has(nm)) {
733
+ async #validateNodeModules (nm) {
734
+ if (this.options.force || this.#nmValidated.has(nm)) {
650
735
  return
651
736
  }
652
737
  const st = await lstat(nm).catch(() => null)
653
738
  if (!st || st.isDirectory()) {
654
- this[_nmValidated].add(nm)
739
+ this.#nmValidated.add(nm)
655
740
  return
656
741
  }
657
742
  log.warn('reify', 'Removing non-directory', nm)
658
743
  await rm(nm, { recursive: true, force: true })
659
744
  }
660
745
 
661
- async [_extractOrLink] (node) {
746
+ async #extractOrLink (node) {
662
747
  const nm = resolve(node.parent.path, 'node_modules')
663
- await this[_validateNodeModules](nm)
748
+ await this.#validateNodeModules(nm)
664
749
 
665
750
  if (!node.isLink) {
666
751
  // in normal cases, node.resolved should *always* be set by now.
@@ -672,7 +757,7 @@ module.exports = cls => class Reifier extends cls {
672
757
  // entirely, since we can't possibly reify it.
673
758
  let res = null
674
759
  if (node.resolved) {
675
- const registryResolved = this[_registryResolved](node.resolved)
760
+ const registryResolved = this.#registryResolved(node.resolved)
676
761
  if (registryResolved) {
677
762
  res = `${node.name}@${registryResolved}`
678
763
  }
@@ -694,7 +779,7 @@ module.exports = cls => class Reifier extends cls {
694
779
  return
695
780
  }
696
781
  await debug(async () => {
697
- const st = await lstat(node.path).catch(e => null)
782
+ const st = await lstat(node.path).catch(() => null)
698
783
  if (st && !st.isDirectory()) {
699
784
  debug.log('unpacking into a non-directory', node)
700
785
  throw Object.assign(new Error('ENOTDIR: not a directory'), {
@@ -718,10 +803,8 @@ module.exports = cls => class Reifier extends cls {
718
803
 
719
804
  // node.isLink
720
805
  await rm(node.path, { recursive: true, force: true })
721
- await this[_symlink](node)
722
- }
723
806
 
724
- async [_symlink] (node) {
807
+ // symlink
725
808
  const dir = dirname(node.path)
726
809
  const target = node.realpath
727
810
  const rel = relative(dir, target)
@@ -729,17 +812,10 @@ module.exports = cls => class Reifier extends cls {
729
812
  return symlink(rel, node.path, 'junction')
730
813
  }
731
814
 
732
- [_warnDeprecated] (node) {
733
- const { _id, deprecated } = node.package
734
- if (deprecated) {
735
- log.warn('deprecated', `${_id}: ${deprecated}`)
736
- }
737
- }
738
-
739
815
  // if the node is optional, then the failure of the promise is nonfatal
740
816
  // just add it and its optional set to the trash list.
741
817
  [_handleOptionalFailure] (node, p) {
742
- return (node.optional ? p.catch(er => {
818
+ return (node.optional ? p.catch(() => {
743
819
  const set = optionalSet(node)
744
820
  for (node of set) {
745
821
  log.verbose('reify', 'failed optional dependency', node.path)
@@ -748,7 +824,7 @@ module.exports = cls => class Reifier extends cls {
748
824
  }) : p).then(() => node)
749
825
  }
750
826
 
751
- [_registryResolved] (resolved) {
827
+ #registryResolved (resolved) {
752
828
  // the default registry url is a magic value meaning "the currently
753
829
  // configured registry".
754
830
  // `resolved` must never be falsey.
@@ -778,18 +854,48 @@ module.exports = cls => class Reifier extends cls {
778
854
  // by the contents of the package. however, in their case, rather than
779
855
  // shipping a virtual tree that must be reified, they ship an entire
780
856
  // reified actual tree that must be unpacked and not modified.
781
- [_loadBundlesAndUpdateTrees] (
782
- depth = 0, bundlesByDepth = this[_getBundlesByDepth]()
783
- ) {
857
+ [_loadBundlesAndUpdateTrees] (depth = 0, bundlesByDepth) {
858
+ let maxBundleDepth
859
+ if (!bundlesByDepth) {
860
+ bundlesByDepth = new Map()
861
+ maxBundleDepth = -1
862
+ dfwalk({
863
+ tree: this.diff,
864
+ visit: diff => {
865
+ const node = diff.ideal
866
+ if (!node) {
867
+ return
868
+ }
869
+ if (node.isProjectRoot) {
870
+ return
871
+ }
872
+
873
+ const { bundleDependencies } = node.package
874
+ if (bundleDependencies && bundleDependencies.length) {
875
+ maxBundleDepth = Math.max(maxBundleDepth, node.depth)
876
+ if (!bundlesByDepth.has(node.depth)) {
877
+ bundlesByDepth.set(node.depth, [node])
878
+ } else {
879
+ bundlesByDepth.get(node.depth).push(node)
880
+ }
881
+ }
882
+ },
883
+ getChildren: diff => diff.children,
884
+ })
885
+
886
+ bundlesByDepth.set('maxBundleDepth', maxBundleDepth)
887
+ } else {
888
+ maxBundleDepth = bundlesByDepth.get('maxBundleDepth')
889
+ }
890
+
784
891
  if (depth === 0) {
785
892
  time.start('reify:loadBundles')
786
893
  }
787
894
 
788
- const maxBundleDepth = bundlesByDepth.get('maxBundleDepth')
789
895
  if (depth > maxBundleDepth) {
790
896
  // if we did something, then prune the tree and update the diffs
791
897
  if (maxBundleDepth !== -1) {
792
- this[_pruneBundledMetadeps](bundlesByDepth)
898
+ this.#pruneBundledMetadeps(bundlesByDepth)
793
899
  this[_diffTrees]()
794
900
  }
795
901
  time.end('reify:loadBundles')
@@ -810,7 +916,7 @@ module.exports = cls => class Reifier extends cls {
810
916
  // extract all the nodes with bundles
811
917
  return promiseCallLimit(set.map(node => {
812
918
  return () => {
813
- this[_bundleUnpacked].add(node)
919
+ this.#bundleUnpacked.add(node)
814
920
  return this[_reifyNode](node)
815
921
  }
816
922
  }), { rejectLate: true })
@@ -839,46 +945,15 @@ module.exports = cls => class Reifier extends cls {
839
945
  },
840
946
  })
841
947
  for (const name of notTransplanted) {
842
- this[_bundleMissing].add(node.children.get(name))
948
+ this.#bundleMissing.add(node.children.get(name))
843
949
  }
844
950
  })))
845
951
  // move onto the next level of bundled items
846
952
  .then(() => this[_loadBundlesAndUpdateTrees](depth + 1, bundlesByDepth))
847
953
  }
848
954
 
849
- [_getBundlesByDepth] () {
850
- const bundlesByDepth = new Map()
851
- let maxBundleDepth = -1
852
- dfwalk({
853
- tree: this.diff,
854
- visit: diff => {
855
- const node = diff.ideal
856
- if (!node) {
857
- return
858
- }
859
- if (node.isProjectRoot) {
860
- return
861
- }
862
-
863
- const { bundleDependencies } = node.package
864
- if (bundleDependencies && bundleDependencies.length) {
865
- maxBundleDepth = Math.max(maxBundleDepth, node.depth)
866
- if (!bundlesByDepth.has(node.depth)) {
867
- bundlesByDepth.set(node.depth, [node])
868
- } else {
869
- bundlesByDepth.get(node.depth).push(node)
870
- }
871
- }
872
- },
873
- getChildren: diff => diff.children,
874
- })
875
-
876
- bundlesByDepth.set('maxBundleDepth', maxBundleDepth)
877
- return bundlesByDepth
878
- }
879
-
880
955
  // https://github.com/npm/cli/issues/1597#issuecomment-667639545
881
- [_pruneBundledMetadeps] (bundlesByDepth) {
956
+ #pruneBundledMetadeps (bundlesByDepth) {
882
957
  const bundleShadowed = new Set()
883
958
 
884
959
  // Example dep graph:
@@ -1012,9 +1087,9 @@ module.exports = cls => class Reifier extends cls {
1012
1087
  }
1013
1088
 
1014
1089
  const node = diff.ideal
1015
- const bd = this[_bundleUnpacked].has(node)
1016
- const sw = this[_shrinkwrapInflated].has(node)
1017
- const bundleMissing = this[_bundleMissing].has(node)
1090
+ const bd = this.#bundleUnpacked.has(node)
1091
+ const sw = this.#shrinkwrapInflated.has(node)
1092
+ const bundleMissing = this.#bundleMissing.has(node)
1018
1093
 
1019
1094
  // check whether we still need to unpack this one.
1020
1095
  // test the inDepBundle last, since that's potentially a tree walk.
@@ -1050,8 +1125,8 @@ module.exports = cls => class Reifier extends cls {
1050
1125
  // the actualTree and idealTree _don't_ differ, starting from the
1051
1126
  // shallowest nodes that we moved aside in the first place.
1052
1127
  const timeEnd = time.start('reify:unretire')
1053
- const moves = this[_retiredPaths]
1054
- this[_retiredUnchanged] = {}
1128
+ const moves = this.#retiredPaths
1129
+ this.#retiredUnchanged = {}
1055
1130
  return promiseAllRejectLate(this.diff.children.map(diff => {
1056
1131
  // skip if nothing was retired
1057
1132
  if (diff.action !== 'CHANGE' && diff.action !== 'REMOVE') {
@@ -1074,7 +1149,7 @@ module.exports = cls => class Reifier extends cls {
1074
1149
  }
1075
1150
  })
1076
1151
 
1077
- this[_retiredUnchanged][retireFolder] = []
1152
+ this.#retiredUnchanged[retireFolder] = []
1078
1153
  return promiseAllRejectLate(diff.unchanged.map(node => {
1079
1154
  // no need to roll back links, since we'll just delete them anyway
1080
1155
  if (node.isLink) {
@@ -1083,11 +1158,11 @@ module.exports = cls => class Reifier extends cls {
1083
1158
  }
1084
1159
 
1085
1160
  // will have been moved/unpacked along with bundler
1086
- if (node.inDepBundle && !this[_bundleMissing].has(node)) {
1161
+ if (node.inDepBundle && !this.#bundleMissing.has(node)) {
1087
1162
  return
1088
1163
  }
1089
1164
 
1090
- this[_retiredUnchanged][retireFolder].push(node)
1165
+ this.#retiredUnchanged[retireFolder].push(node)
1091
1166
 
1092
1167
  const rel = relative(realFolder, node.path)
1093
1168
  const fromPath = resolve(retireFolder, rel)
@@ -1114,10 +1189,10 @@ module.exports = cls => class Reifier extends cls {
1114
1189
  }
1115
1190
 
1116
1191
  [_rollbackMoveBackRetiredUnchanged] (er) {
1117
- const moves = this[_retiredPaths]
1192
+ const moves = this.#retiredPaths
1118
1193
  // flip the mapping around to go back
1119
1194
  const realFolders = new Map(Object.entries(moves).map(([k, v]) => [v, k]))
1120
- const promises = Object.entries(this[_retiredUnchanged])
1195
+ const promises = Object.entries(this.#retiredUnchanged)
1121
1196
  .map(([retireFolder, nodes]) => promiseAllRejectLate(nodes.map(node => {
1122
1197
  const realFolder = realFolders.get(retireFolder)
1123
1198
  const rel = relative(realFolder, node.path)
@@ -1209,7 +1284,7 @@ module.exports = cls => class Reifier extends cls {
1209
1284
  const saveIdealTree = !(
1210
1285
  (!save && !hasUpdates)
1211
1286
  || this.options.global
1212
- || this[_dryRun]
1287
+ || this.options.dryRun
1213
1288
  )
1214
1289
 
1215
1290
  if (!saveIdealTree) {
@@ -1245,7 +1320,7 @@ module.exports = cls => class Reifier extends cls {
1245
1320
  const isLocalDep = req.type === 'directory' || req.type === 'file'
1246
1321
  if (req.registry) {
1247
1322
  const version = child.version
1248
- const prefixRange = version ? this[_savePrefix] + version : '*'
1323
+ const prefixRange = version ? this.options.savePrefix + version : '*'
1249
1324
  // if we installed a range, then we save the range specified
1250
1325
  // if it is not a subset of the ^x.y.z. eg, installing a range
1251
1326
  // of `1.x <1.2.3` will not be saved as `^1.2.0`, because that
@@ -1280,7 +1355,7 @@ module.exports = cls => class Reifier extends cls {
1280
1355
  // using their relative path
1281
1356
  if (edge.type === 'workspace') {
1282
1357
  const { version } = edge.to.target
1283
- const prefixRange = version ? this[_savePrefix] + version : '*'
1358
+ const prefixRange = version ? this.options.savePrefix + version : '*'
1284
1359
  newSpec = prefixRange
1285
1360
  } else {
1286
1361
  // save the relative path in package.json
@@ -1449,151 +1524,12 @@ module.exports = cls => class Reifier extends cls {
1449
1524
 
1450
1525
  // TODO this ignores options.save
1451
1526
  await this.idealTree.meta.save({
1452
- format: (this[_formatPackageLock] && format) ? format
1453
- : this[_formatPackageLock],
1527
+ format: (this.options.formatPackageLock && format) ? format
1528
+ : this.options.formatPackageLock,
1454
1529
  })
1455
1530
  }
1456
1531
 
1457
1532
  timeEnd()
1458
1533
  return true
1459
1534
  }
1460
-
1461
- async [_copyIdealToActual] () {
1462
- // clean up any trash that is still in the tree
1463
- for (const path of this[_trashList]) {
1464
- const loc = relpath(this.idealTree.realpath, path)
1465
- const node = this.idealTree.inventory.get(loc)
1466
- if (node && node.root === this.idealTree) {
1467
- node.parent = null
1468
- }
1469
- }
1470
-
1471
- // if we filtered to only certain nodes, then anything ELSE needs
1472
- // to be untouched in the resulting actual tree, even if it differs
1473
- // in the idealTree. Copy over anything that was in the actual and
1474
- // was not changed, delete anything in the ideal and not actual.
1475
- // Then we move the entire idealTree over to this.actualTree, and
1476
- // save the hidden lockfile.
1477
- if (this.diff && this.diff.filterSet.size) {
1478
- const reroot = new Set()
1479
-
1480
- const { filterSet } = this.diff
1481
- const seen = new Set()
1482
- for (const [loc, ideal] of this.idealTree.inventory.entries()) {
1483
- seen.add(loc)
1484
-
1485
- // if it's an ideal node from the filter set, then skip it
1486
- // because we already made whatever changes were necessary
1487
- if (filterSet.has(ideal)) {
1488
- continue
1489
- }
1490
-
1491
- // otherwise, if it's not in the actualTree, then it's not a thing
1492
- // that we actually added. And if it IS in the actualTree, then
1493
- // it's something that we left untouched, so we need to record
1494
- // that.
1495
- const actual = this.actualTree.inventory.get(loc)
1496
- if (!actual) {
1497
- ideal.root = null
1498
- } else {
1499
- if ([...actual.linksIn].some(link => filterSet.has(link))) {
1500
- seen.add(actual.location)
1501
- continue
1502
- }
1503
- const { realpath, isLink } = actual
1504
- if (isLink && ideal.isLink && ideal.realpath === realpath) {
1505
- continue
1506
- } else {
1507
- reroot.add(actual)
1508
- }
1509
- }
1510
- }
1511
-
1512
- // now find any actual nodes that may not be present in the ideal
1513
- // tree, but were left behind by virtue of not being in the filter
1514
- for (const [loc, actual] of this.actualTree.inventory.entries()) {
1515
- if (seen.has(loc)) {
1516
- continue
1517
- }
1518
- seen.add(loc)
1519
-
1520
- // we know that this is something that ISN'T in the idealTree,
1521
- // or else we will have addressed it in the previous loop.
1522
- // If it's in the filterSet, that means we intentionally removed
1523
- // it, so nothing to do here.
1524
- if (filterSet.has(actual)) {
1525
- continue
1526
- }
1527
-
1528
- reroot.add(actual)
1529
- }
1530
-
1531
- // go through the rerooted actual nodes, and move them over.
1532
- for (const actual of reroot) {
1533
- actual.root = this.idealTree
1534
- }
1535
-
1536
- // prune out any tops that lack a linkIn, they are no longer relevant.
1537
- for (const top of this.idealTree.tops) {
1538
- if (top.linksIn.size === 0) {
1539
- top.root = null
1540
- }
1541
- }
1542
-
1543
- // need to calculate dep flags, since nodes may have been marked
1544
- // as extraneous or otherwise incorrect during transit.
1545
- calcDepFlags(this.idealTree)
1546
- }
1547
-
1548
- // save the ideal's meta as a hidden lockfile after we actualize it
1549
- this.idealTree.meta.filename =
1550
- this.idealTree.realpath + '/node_modules/.package-lock.json'
1551
- this.idealTree.meta.hiddenLockfile = true
1552
- this.idealTree.meta.lockfileVersion = defaultLockfileVersion
1553
-
1554
- this.actualTree = this.idealTree
1555
- this.idealTree = null
1556
-
1557
- if (!this.options.global) {
1558
- await this.actualTree.meta.save()
1559
- const ignoreScripts = !!this.options.ignoreScripts
1560
- // if we aren't doing a dry run or ignoring scripts and we actually made changes to the dep
1561
- // tree, then run the dependencies scripts
1562
- if (!this[_dryRun] && !ignoreScripts && this.diff && this.diff.children.length) {
1563
- const { path, package: pkg } = this.actualTree.target
1564
- const stdio = this.options.foregroundScripts ? 'inherit' : 'pipe'
1565
- const { scripts = {} } = pkg
1566
- for (const event of ['predependencies', 'dependencies', 'postdependencies']) {
1567
- if (Object.prototype.hasOwnProperty.call(scripts, event)) {
1568
- log.info('run', pkg._id, event, scripts[event])
1569
- await time.start(`reify:run:${event}`, () => runScript({
1570
- event,
1571
- path,
1572
- pkg,
1573
- stdio,
1574
- scriptShell: this.options.scriptShell,
1575
- }))
1576
- }
1577
- }
1578
- }
1579
- }
1580
- }
1581
-
1582
- async dedupe (options = {}) {
1583
- // allow the user to set options on the ctor as well.
1584
- // XXX: deprecate separate method options objects.
1585
- options = { ...this.options, ...options }
1586
- const tree = await this.loadVirtual().catch(() => this.loadActual())
1587
- const names = []
1588
- for (const name of tree.inventory.query('name')) {
1589
- if (tree.inventory.query('name', name).size > 1) {
1590
- names.push(name)
1591
- }
1592
- }
1593
- return this.reify({
1594
- ...options,
1595
- preferDedupe: true,
1596
- update: { names },
1597
- })
1598
- }
1599
1535
  }
package/lib/dep-valid.js CHANGED
@@ -124,7 +124,7 @@ const linkValid = (child, requested, requestor) => {
124
124
  return isLink && relative(child.realpath, requested.fetchSpec) === ''
125
125
  }
126
126
 
127
- const tarballValid = (child, requested, requestor) => {
127
+ const tarballValid = (child, requested) => {
128
128
  if (child.isLink) {
129
129
  return false
130
130
  }
package/lib/inventory.js CHANGED
@@ -130,7 +130,7 @@ class Inventory extends Map {
130
130
  return super.get(node.location) === node
131
131
  }
132
132
 
133
- set (k, v) {
133
+ set () {
134
134
  throw new Error('direct set() not supported, use inventory.add(node)')
135
135
  }
136
136
  }
@@ -650,27 +650,27 @@ class Results {
650
650
  // operators for attribute selectors
651
651
  const attributeOperators = {
652
652
  // attribute value is equivalent
653
- '=' ({ attr, value, insensitive }) {
653
+ '=' ({ attr, value }) {
654
654
  return attr === value
655
655
  },
656
656
  // attribute value contains word
657
- '~=' ({ attr, value, insensitive }) {
657
+ '~=' ({ attr, value }) {
658
658
  return (attr.match(/\w+/g) || []).includes(value)
659
659
  },
660
660
  // attribute value contains string
661
- '*=' ({ attr, value, insensitive }) {
661
+ '*=' ({ attr, value }) {
662
662
  return attr.includes(value)
663
663
  },
664
664
  // attribute value is equal or starts with
665
- '|=' ({ attr, value, insensitive }) {
665
+ '|=' ({ attr, value }) {
666
666
  return attr.startsWith(`${value}-`)
667
667
  },
668
668
  // attribute value starts with
669
- '^=' ({ attr, value, insensitive }) {
669
+ '^=' ({ attr, value }) {
670
670
  return attr.startsWith(value)
671
671
  },
672
672
  // attribute value ends with
673
- '$=' ({ attr, value, insensitive }) {
673
+ '$=' ({ attr, value }) {
674
674
  return attr.endsWith(value)
675
675
  },
676
676
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@npmcli/arborist",
3
- "version": "7.5.0",
3
+ "version": "7.5.1",
4
4
  "description": "Manage node_modules trees",
5
5
  "dependencies": {
6
6
  "@isaacs/string-locale-compare": "^1.1.0",
@@ -12,8 +12,8 @@
12
12
  "@npmcli/node-gyp": "^3.0.0",
13
13
  "@npmcli/package-json": "^5.1.0",
14
14
  "@npmcli/query": "^3.1.0",
15
- "@npmcli/redact": "^1.1.0",
16
- "@npmcli/run-script": "^8.0.0",
15
+ "@npmcli/redact": "^2.0.0",
16
+ "@npmcli/run-script": "^8.1.0",
17
17
  "bin-links": "^4.0.1",
18
18
  "cacache": "^18.0.0",
19
19
  "common-ancestor-path": "^1.0.1",
@@ -25,7 +25,7 @@
25
25
  "npm-install-checks": "^6.2.0",
26
26
  "npm-package-arg": "^11.0.2",
27
27
  "npm-pick-manifest": "^9.0.0",
28
- "npm-registry-fetch": "^16.2.1",
28
+ "npm-registry-fetch": "^17.0.0",
29
29
  "pacote": "^18.0.1",
30
30
  "parse-conflict-json": "^3.0.0",
31
31
  "proc-log": "^4.2.0",
@@ -62,7 +62,7 @@
62
62
  },
63
63
  "repository": {
64
64
  "type": "git",
65
- "url": "https://github.com/npm/cli.git",
65
+ "url": "git+https://github.com/npm/cli.git",
66
66
  "directory": "workspaces/arborist"
67
67
  },
68
68
  "author": "GitHub Inc.",