@npmcli/arborist 7.5.0 → 7.5.2

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.
@@ -53,48 +53,26 @@ const _addNodeToTrashList = Symbol.for('addNodeToTrashList')
53
53
  // they'll affect things deeper in, then alphabetical for consistency between
54
54
  // installs
55
55
  class DepsQueue {
56
- // [{ sorted, items }] indexed by depth
57
56
  #deps = []
58
57
  #sorted = true
59
- #minDepth = 0
60
- #length = 0
61
58
 
62
59
  get length () {
63
- return this.#length
60
+ return this.#deps.length
64
61
  }
65
62
 
66
63
  push (item) {
67
- if (!this.#deps[item.depth]) {
68
- this.#length++
69
- this.#deps[item.depth] = { sorted: true, items: [item] }
70
- // no minDepth check needed, this branch is only reached when we are in
71
- // the middle of a shallower depth and creating a new one
72
- return
73
- }
74
- if (!this.#deps[item.depth].items.includes(item)) {
75
- this.#length++
76
- this.#deps[item.depth].sorted = false
77
- this.#deps[item.depth].items.push(item)
78
- if (item.depth < this.#minDepth) {
79
- this.#minDepth = item.depth
80
- }
64
+ if (!this.#deps.includes(item)) {
65
+ this.#sorted = false
66
+ this.#deps.push(item)
81
67
  }
82
68
  }
83
69
 
84
70
  pop () {
85
- let depth
86
- while (!depth?.items.length) {
87
- depth = this.#deps[this.#minDepth]
88
- if (!depth?.items.length) {
89
- this.#minDepth++
90
- }
71
+ if (!this.#sorted) {
72
+ this.#deps.sort((a, b) => (a.depth - b.depth) || localeCompare(a.path, b.path))
73
+ this.#sorted = true
91
74
  }
92
- if (!depth.sorted) {
93
- depth.items.sort((a, b) => localeCompare(a.path, b.path))
94
- depth.sorted = true
95
- }
96
- this.#length--
97
- return depth.items.shift()
75
+ return this.#deps.shift()
98
76
  }
99
77
  }
100
78
 
@@ -463,7 +441,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
463
441
  }
464
442
  const dir = resolve(nm, name)
465
443
  const st = await lstat(dir)
466
- .catch(/* istanbul ignore next */ er => null)
444
+ .catch(/* istanbul ignore next */ () => null)
467
445
  if (st && st.isSymbolicLink()) {
468
446
  const target = await readlink(dir)
469
447
  const real = resolve(dirname(dir), target).replace(/#/g, '%23')
@@ -1022,9 +1000,13 @@ This is a one-time fix-up, please be patient...
1022
1000
  // may well be an optional dep that has gone missing. it'll
1023
1001
  // fail later anyway.
1024
1002
  for (const e of this.#problemEdges(placed)) {
1003
+ // XXX This is somehow load bearing. This makes tests that print
1004
+ // the ideal tree of a tree with tarball dependencies fail. This
1005
+ // can't be changed or removed till we figure out why
1006
+ // The test is named "tarball deps with transitive tarball deps"
1025
1007
  promises.push(() =>
1026
1008
  this.#fetchManifest(npa.resolve(e.name, e.spec, fromPath(placed, e)))
1027
- .catch(er => null)
1009
+ .catch(() => null)
1028
1010
  )
1029
1011
  }
1030
1012
  },
@@ -1204,6 +1186,7 @@ This is a one-time fix-up, please be patient...
1204
1186
  const options = {
1205
1187
  ...this.options,
1206
1188
  avoid: this.#avoidRange(spec.name),
1189
+ fullMetadata: true,
1207
1190
  }
1208
1191
  // get the intended spec and stored metadata from yarn.lock file,
1209
1192
  // if available and valid.
@@ -1212,19 +1195,10 @@ This is a one-time fix-up, please be patient...
1212
1195
  if (this.#manifests.has(spec.raw)) {
1213
1196
  return this.#manifests.get(spec.raw)
1214
1197
  } else {
1215
- const cleanRawSpec = redact(spec.rawSpec)
1216
- log.silly('fetch manifest', spec.raw.replace(spec.rawSpec, cleanRawSpec))
1217
- const o = {
1218
- ...options,
1219
- fullMetadata: true,
1220
- }
1221
- const p = pacote.manifest(spec, o)
1222
- .then(({ license, ...mani }) => {
1223
- this.#manifests.set(spec.raw, mani)
1224
- return mani
1225
- })
1226
- this.#manifests.set(spec.raw, p)
1227
- return p
1198
+ log.silly('fetch manifest', spec.raw.replace(spec.rawSpec, redact(spec.rawSpec)))
1199
+ const mani = await pacote.manifest(spec, options)
1200
+ this.#manifests.set(spec.raw, mani)
1201
+ return mani
1228
1202
  }
1229
1203
  }
1230
1204
 
@@ -1273,7 +1247,7 @@ This is a one-time fix-up, please be patient...
1273
1247
  })
1274
1248
  }
1275
1249
 
1276
- #linkFromSpec (name, spec, parent, edge) {
1250
+ #linkFromSpec (name, spec, parent) {
1277
1251
  const realpath = spec.fetchSpec
1278
1252
  const { installLinks, legacyPeerDeps } = this
1279
1253
  return rpj(realpath + '/package.json').catch(() => ({})).then(pkg => {
@@ -31,10 +31,10 @@ const { homedir } = require('os')
31
31
  const { depth } = require('treeverse')
32
32
  const mapWorkspaces = require('@npmcli/map-workspaces')
33
33
  const { log, time } = require('proc-log')
34
-
35
34
  const { saveTypeMap } = require('../add-rm-pkg-deps.js')
36
35
  const AuditReport = require('../audit-report.js')
37
36
  const relpath = require('../relpath.js')
37
+ const PackumentCache = require('../packument-cache.js')
38
38
 
39
39
  const mixins = [
40
40
  require('../tracker.js'),
@@ -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),
82
- packumentCache: options.packumentCache || new Map(),
84
+ packageLockOnly: !!options.packageLockOnly,
85
+ packumentCache: options.packumentCache || new PackumentCache(),
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,