@npmcli/arborist 4.2.1 → 4.3.0

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.
@@ -269,6 +269,22 @@ module.exports = cls => class IdealTreeBuilder extends cls {
269
269
  this[_complete] = !!options.complete
270
270
  this[_preferDedupe] = !!options.preferDedupe
271
271
  this[_legacyBundling] = !!options.legacyBundling
272
+
273
+ // validates list of update names, they must
274
+ // be dep names only, no semver ranges are supported
275
+ for (const name of update.names) {
276
+ const spec = npa(name)
277
+ const validationError =
278
+ new TypeError(`Update arguments must not contain package version specifiers
279
+
280
+ Try using the package name instead, e.g:
281
+ npm update ${spec.name}`)
282
+ validationError.code = 'EUPDATEARGS'
283
+
284
+ if (spec.fetchSpec !== 'latest') {
285
+ throw validationError
286
+ }
287
+ }
272
288
  this[_updateNames] = update.names
273
289
 
274
290
  this[_updateAll] = update.all
@@ -320,7 +336,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
320
336
  // Load on a new Arborist object, so the Nodes aren't the same,
321
337
  // or else it'll get super confusing when we change them!
322
338
  .then(async root => {
323
- if (!this[_updateAll] && !this[_global] && !root.meta.loadedFromDisk) {
339
+ if ((!this[_updateAll] && !this[_global] && !root.meta.loadedFromDisk) || (this[_global] && this[_updateNames].length)) {
324
340
  await new this.constructor(this.options).loadActual({ root })
325
341
  const tree = root.target
326
342
  // even though we didn't load it from a package-lock.json FILE,
@@ -212,7 +212,8 @@ module.exports = cls => class ActualLoader extends cls {
212
212
  const promises = []
213
213
  for (const path of tree.workspaces.values()) {
214
214
  if (!this[_cache].has(path)) {
215
- const p = this[_loadFSNode]({ path, root: this[_actualTree] })
215
+ // workspace overrides use the root overrides
216
+ const p = this[_loadFSNode]({ path, root: this[_actualTree], useRootOverrides: true })
216
217
  .then(node => this[_loadFSTree](node))
217
218
  promises.push(p)
218
219
  }
@@ -240,7 +241,7 @@ module.exports = cls => class ActualLoader extends cls {
240
241
  this[_actualTree] = root
241
242
  }
242
243
 
243
- [_loadFSNode] ({ path, parent, real, root, loadOverrides }) {
244
+ [_loadFSNode] ({ path, parent, real, root, loadOverrides, useRootOverrides }) {
244
245
  if (!real) {
245
246
  return realpath(path, this[_rpcache], this[_stcache])
246
247
  .then(
@@ -250,6 +251,7 @@ module.exports = cls => class ActualLoader extends cls {
250
251
  real,
251
252
  root,
252
253
  loadOverrides,
254
+ useRootOverrides,
253
255
  }),
254
256
  // if realpath fails, just provide a dummy error node
255
257
  error => new Node({
@@ -289,6 +291,9 @@ module.exports = cls => class ActualLoader extends cls {
289
291
  parent,
290
292
  root,
291
293
  loadOverrides,
294
+ ...(useRootOverrides && root.overrides
295
+ ? { overrides: root.overrides.getNodeRule({ name: pkg.name, version: pkg.version }) }
296
+ : {}),
292
297
  })
293
298
  })
294
299
  .then(node => {
@@ -5,6 +5,7 @@ const pacote = require('pacote')
5
5
  const AuditReport = require('../audit-report.js')
6
6
  const { subset, intersects } = require('semver')
7
7
  const npa = require('npm-package-arg')
8
+ const semver = require('semver')
8
9
  const debug = require('../debug.js')
9
10
  const walkUp = require('walk-up-path')
10
11
 
@@ -1273,6 +1274,21 @@ module.exports = cls => class Reifier extends cls {
1273
1274
  }
1274
1275
  }
1275
1276
 
1277
+ // Returns true if any of the edges from this node has a semver
1278
+ // range definition that is an exact match to the version installed
1279
+ // e.g: should return true if for a given an installed version 1.0.0,
1280
+ // range is either =1.0.0 or 1.0.0
1281
+ const exactVersion = node => {
1282
+ for (const edge of node.edgesIn) {
1283
+ try {
1284
+ if (semver.subset(edge.spec, node.version)) {
1285
+ return false
1286
+ }
1287
+ } catch {}
1288
+ }
1289
+ return true
1290
+ }
1291
+
1276
1292
  // helper that retrieves an array of nodes that were
1277
1293
  // potentially updated during the reify process, in order
1278
1294
  // to limit the number of nodes to check and update, only
@@ -1284,6 +1300,8 @@ module.exports = cls => class Reifier extends cls {
1284
1300
  const filterDirectDependencies = node =>
1285
1301
  !node.isRoot && node.resolveParent.isRoot
1286
1302
  && (!names || names.includes(node.name))
1303
+ && exactVersion(node) // skip update for exact ranges
1304
+
1287
1305
  const directDeps = this.idealTree.inventory
1288
1306
  .filter(filterDirectDependencies)
1289
1307
 
package/lib/shrinkwrap.js CHANGED
@@ -476,8 +476,13 @@ class Shrinkwrap {
476
476
  // all good! hidden lockfile is the newest thing in here.
477
477
  return data
478
478
  }).catch(er => {
479
- const rel = relpath(this.path, this.filename)
480
- this.log.verbose('shrinkwrap', `failed to load ${rel}`, er)
479
+ /* istanbul ignore else */
480
+ if (typeof this.filename === 'string') {
481
+ const rel = relpath(this.path, this.filename)
482
+ this.log.verbose('shrinkwrap', `failed to load ${rel}`, er)
483
+ } else {
484
+ this.log.verbose('shrinkwrap', `failed to load ${this.path}`, er)
485
+ }
481
486
  this.loadingError = er
482
487
  this.loadedFromDisk = false
483
488
  this.ancientLockfile = false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@npmcli/arborist",
3
- "version": "4.2.1",
3
+ "version": "4.3.0",
4
4
  "description": "Manage node_modules trees",
5
5
  "dependencies": {
6
6
  "@isaacs/string-locale-compare": "^1.1.0",
@@ -22,7 +22,7 @@
22
22
  "npm-install-checks": "^4.0.0",
23
23
  "npm-package-arg": "^8.1.5",
24
24
  "npm-pick-manifest": "^6.1.0",
25
- "npm-registry-fetch": "^11.0.0",
25
+ "npm-registry-fetch": "^12.0.1",
26
26
  "pacote": "^12.0.2",
27
27
  "parse-conflict-json": "^2.0.1",
28
28
  "proc-log": "^1.0.0",