@npmcli/arborist 9.1.4 → 9.1.5

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.
@@ -1,6 +1,6 @@
1
1
  // mixin implementing the buildIdealTree method
2
2
  const localeCompare = require('@isaacs/string-locale-compare')('en')
3
- const rpj = require('read-package-json-fast')
3
+ const PackageJson = require('@npmcli/package-json')
4
4
  const npa = require('npm-package-arg')
5
5
  const pacote = require('pacote')
6
6
  const cacache = require('cacache')
@@ -268,7 +268,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
268
268
  root = await this.#globalRootNode()
269
269
  } else {
270
270
  try {
271
- const pkg = await rpj(this.path + '/package.json')
271
+ const { content: pkg } = await PackageJson.normalize(this.path)
272
272
  root = await this.#rootNodeFromPackage(pkg)
273
273
  } catch (err) {
274
274
  if (err.code === 'EJSONPARSE') {
@@ -448,7 +448,6 @@ module.exports = cls => class IdealTreeBuilder extends cls {
448
448
  const paths = await readdirScoped(nm).catch(() => [])
449
449
  for (const p of paths) {
450
450
  const name = p.replace(/\\/g, '/')
451
- tree.package.dependencies = tree.package.dependencies || {}
452
451
  const updateName = this[_updateNames].includes(name)
453
452
  if (this[_updateAll] || updateName) {
454
453
  if (updateName) {
@@ -1288,14 +1287,15 @@ This is a one-time fix-up, please be patient...
1288
1287
  })
1289
1288
  }
1290
1289
 
1291
- #linkFromSpec (name, spec, parent) {
1290
+ async #linkFromSpec (name, spec, parent) {
1292
1291
  const realpath = spec.fetchSpec
1293
1292
  const { installLinks, legacyPeerDeps } = this
1294
- return rpj(realpath + '/package.json').catch(() => ({})).then(pkg => {
1295
- const link = new Link({ name, parent, realpath, pkg, installLinks, legacyPeerDeps })
1296
- this.#linkNodes.add(link)
1297
- return link
1293
+ const { content: pkg } = await PackageJson.normalize(realpath).catch(() => {
1294
+ return { content: {} }
1298
1295
  })
1296
+ const link = new Link({ name, parent, realpath, pkg, installLinks, legacyPeerDeps })
1297
+ this.#linkNodes.add(link)
1298
+ return link
1299
1299
  }
1300
1300
 
1301
1301
  // load all peer deps and meta-peer deps into the node's parent
@@ -1,8 +1,8 @@
1
1
  // mix-in implementing the loadActual method
2
2
 
3
- const { relative, dirname, resolve, join, normalize } = require('node:path')
3
+ const { dirname, join, normalize, relative, resolve } = require('node:path')
4
4
 
5
- const rpj = require('read-package-json-fast')
5
+ const PackageJson = require('@npmcli/package-json')
6
6
  const { readdirScoped } = require('@npmcli/fs')
7
7
  const { walkUp } = require('walk-up-path')
8
8
  const ancestorPath = require('common-ancestor-path')
@@ -279,12 +279,16 @@ module.exports = cls => class ActualLoader extends cls {
279
279
  }
280
280
 
281
281
  try {
282
- const pkg = await rpj(join(real, 'package.json'))
282
+ const { content: pkg } = await PackageJson.normalize(real)
283
283
  params.pkg = pkg
284
284
  if (useRootOverrides && root.overrides) {
285
285
  params.overrides = root.overrides.getNodeRule({ name: pkg.name, version: pkg.version })
286
286
  }
287
287
  } catch (err) {
288
+ if (err.code === 'EJSONPARSE') {
289
+ // TODO @npmcli/package-json should be doing this
290
+ err.path = join(real, 'package.json')
291
+ }
288
292
  params.error = err
289
293
  }
290
294
 
@@ -1,16 +1,15 @@
1
+ const { resolve } = require('node:path')
1
2
  // mixin providing the loadVirtual method
2
3
  const mapWorkspaces = require('@npmcli/map-workspaces')
3
-
4
- const { resolve } = require('node:path')
5
-
4
+ const PackageJson = require('@npmcli/package-json')
6
5
  const nameFromFolder = require('@npmcli/name-from-folder')
6
+
7
7
  const consistentResolve = require('../consistent-resolve.js')
8
8
  const Shrinkwrap = require('../shrinkwrap.js')
9
9
  const Node = require('../node.js')
10
10
  const Link = require('../link.js')
11
11
  const relpath = require('../relpath.js')
12
12
  const calcDepFlags = require('../calc-dep-flags.js')
13
- const rpj = require('read-package-json-fast')
14
13
  const treeCheck = require('../tree-check.js')
15
14
 
16
15
  const flagsSuspect = Symbol.for('flagsSuspect')
@@ -54,10 +53,11 @@ module.exports = cls => class VirtualLoader extends cls {
54
53
 
55
54
  // when building the ideal tree, we pass in a root node to this function
56
55
  // otherwise, load it from the root package json or the lockfile
56
+ const pkg = await PackageJson.normalize(this.path).then(p => p.content).catch(() => s.data.packages[''] || {})
57
+ // TODO clean this up
57
58
  const {
58
- root = await this.#loadRoot(s),
59
+ root = await this[setWorkspaces](this.#loadNode('', pkg, true)),
59
60
  } = options
60
-
61
61
  this.#rootOptionProvided = options.root
62
62
 
63
63
  await this.#loadFromShrinkwrap(s, root)
@@ -65,12 +65,6 @@ module.exports = cls => class VirtualLoader extends cls {
65
65
  return treeCheck(this.virtualTree)
66
66
  }
67
67
 
68
- async #loadRoot (s) {
69
- const pj = this.path + '/package.json'
70
- const pkg = await rpj(pj).catch(() => s.data.packages['']) || {}
71
- return this[setWorkspaces](this.#loadNode('', pkg, true))
72
- }
73
-
74
68
  async #loadFromShrinkwrap (s, root) {
75
69
  if (!this.#rootOptionProvided) {
76
70
  // root is never any of these things, but might be a brand new
@@ -219,11 +213,7 @@ To fix:
219
213
  // we always need to read the package.json for link targets
220
214
  // outside node_modules because they can be changed by the local user
221
215
  if (!link.target.parent) {
222
- const pj = link.realpath + '/package.json'
223
- const pkg = await rpj(pj).catch(() => null)
224
- if (pkg) {
225
- link.target.package = pkg
226
- }
216
+ await PackageJson.normalize(link.realpath).then(p => link.target.package = p.content).catch(() => null)
227
217
  }
228
218
  }
229
219
  }
@@ -1,20 +1,19 @@
1
1
  // Arborist.rebuild({path = this.path}) will do all the binlinks and
2
2
  // bundle building needed. Called by reify, and by `npm rebuild`.
3
3
 
4
+ const PackageJson = require('@npmcli/package-json')
5
+ const binLinks = require('bin-links')
4
6
  const localeCompare = require('@isaacs/string-locale-compare')('en')
5
- const { depth: dfwalk } = require('treeverse')
6
7
  const promiseAllRejectLate = require('promise-all-reject-late')
7
- const rpj = require('read-package-json-fast')
8
- const binLinks = require('bin-links')
9
8
  const runScript = require('@npmcli/run-script')
10
9
  const { callLimit: promiseCallLimit } = require('promise-call-limit')
11
- const { resolve } = require('node:path')
10
+ const { depth: dfwalk } = require('treeverse')
12
11
  const { isNodeGypPackage, defaultGypInstallScript } = require('@npmcli/node-gyp')
13
12
  const { log, time } = require('proc-log')
13
+ const { resolve } = require('node:path')
14
14
 
15
15
  const boolEnv = b => b ? '1' : ''
16
- const sortNodes = (a, b) =>
17
- (a.depth - b.depth) || localeCompare(a.path, b.path)
16
+ const sortNodes = (a, b) => (a.depth - b.depth) || localeCompare(a.path, b.path)
18
17
 
19
18
  const _checkBins = Symbol.for('checkBins')
20
19
 
@@ -250,7 +249,9 @@ module.exports = cls => class Builder extends cls {
250
249
  // add to the set then remove while we're reading the pj, so we
251
250
  // don't accidentally hit it multiple times.
252
251
  set.add(node)
253
- const pkg = await rpj(node.path + '/package.json').catch(() => ({}))
252
+ const { content: pkg } = await PackageJson.normalize(node.path).catch(() => {
253
+ return { content: {} }
254
+ })
254
255
  set.delete(node)
255
256
 
256
257
  const { scripts = {} } = pkg
@@ -1,48 +1,37 @@
1
1
  // mixin implementing the reify method
2
- const onExit = require('../signal-handling.js')
3
- const pacote = require('pacote')
4
- const AuditReport = require('../audit-report.js')
5
- const { subset, intersects } = require('semver')
6
- const npa = require('npm-package-arg')
7
- const semver = require('semver')
8
- const debug = require('../debug.js')
9
- const { walkUp } = require('walk-up-path')
10
- const { log, time } = require('proc-log')
11
- const rpj = require('read-package-json-fast')
12
- const hgi = require('hosted-git-info')
13
-
14
- const { dirname, resolve, relative, join } = require('node:path')
15
- const { depth: dfwalk } = require('treeverse')
16
- const {
17
- lstat,
18
- mkdir,
19
- rm,
20
- symlink,
21
- } = require('node:fs/promises')
22
- const { moveFile } = require('@npmcli/fs')
23
2
  const PackageJson = require('@npmcli/package-json')
3
+ const hgi = require('hosted-git-info')
4
+ const npa = require('npm-package-arg')
24
5
  const packageContents = require('@npmcli/installed-package-contents')
6
+ const pacote = require('pacote')
7
+ const promiseAllRejectLate = require('promise-all-reject-late')
25
8
  const runScript = require('@npmcli/run-script')
9
+ const { callLimit: promiseCallLimit } = require('promise-call-limit')
26
10
  const { checkEngine, checkPlatform } = require('npm-install-checks')
11
+ const { depth: dfwalk } = require('treeverse')
12
+ const { dirname, resolve, relative, join } = require('node:path')
13
+ const { log, time } = require('proc-log')
14
+ const { lstat, mkdir, rm, symlink } = require('node:fs/promises')
15
+ const { moveFile } = require('@npmcli/fs')
16
+ const { subset, intersects } = require('semver')
17
+ const { walkUp } = require('walk-up-path')
27
18
 
28
- const treeCheck = require('../tree-check.js')
29
- const relpath = require('../relpath.js')
19
+ const AuditReport = require('../audit-report.js')
30
20
  const Diff = require('../diff.js')
31
- const retirePath = require('../retire-path.js')
32
- const promiseAllRejectLate = require('promise-all-reject-late')
33
- const { callLimit: promiseCallLimit } = require('promise-call-limit')
34
- const optionalSet = require('../optional-set.js')
35
21
  const calcDepFlags = require('../calc-dep-flags.js')
22
+ const debug = require('../debug.js')
23
+ const onExit = require('../signal-handling.js')
24
+ const optionalSet = require('../optional-set.js')
25
+ const relpath = require('../relpath.js')
26
+ const retirePath = require('../retire-path.js')
27
+ const treeCheck = require('../tree-check.js')
28
+ const { defaultLockfileVersion } = require('../shrinkwrap.js')
36
29
  const { saveTypeMap, hasSubKey } = require('../add-rm-pkg-deps.js')
37
30
 
38
- const Shrinkwrap = require('../shrinkwrap.js')
39
- const { defaultLockfileVersion } = Shrinkwrap
40
-
41
31
  // Part of steps (steps need refactoring before we can do anything about these)
42
32
  const _retireShallowNodes = Symbol.for('retireShallowNodes')
43
33
  const _loadBundlesAndUpdateTrees = Symbol.for('loadBundlesAndUpdateTrees')
44
34
  const _submitQuickAudit = Symbol('submitQuickAudit')
45
- const _addOmitsToTrashList = Symbol('addOmitsToTrashList')
46
35
  const _unpackNewModules = Symbol.for('unpackNewModules')
47
36
  const _build = Symbol.for('build')
48
37
 
@@ -85,6 +74,7 @@ module.exports = cls => class Reifier extends cls {
85
74
  #dryRun
86
75
  #nmValidated = new Set()
87
76
  #omit
77
+ #omitted
88
78
  #retiredPaths = {}
89
79
  #retiredUnchanged = {}
90
80
  #savePrefix
@@ -109,6 +99,7 @@ module.exports = cls => class Reifier extends cls {
109
99
  }
110
100
 
111
101
  this.#omit = new Set(options.omit)
102
+ this.#omitted = new Set()
112
103
 
113
104
  // start tracker block
114
105
  this.addTracker('reify')
@@ -141,6 +132,10 @@ module.exports = cls => class Reifier extends cls {
141
132
  this.idealTree = oldTree
142
133
  }
143
134
  await this[_saveIdealTree](options)
135
+ // clean omitted
136
+ for (const node of this.#omitted) {
137
+ node.parent = null
138
+ }
144
139
  // clean up any trash that is still in the tree
145
140
  for (const path of this[_trashList]) {
146
141
  const loc = relpath(this.idealTree.realpath, path)
@@ -315,7 +310,6 @@ module.exports = cls => class Reifier extends cls {
315
310
  ]],
316
311
  [_rollbackCreateSparseTree, [
317
312
  _createSparseTree,
318
- _addOmitsToTrashList,
319
313
  _loadShrinkwrapsAndUpdateTrees,
320
314
  _loadBundlesAndUpdateTrees,
321
315
  _submitQuickAudit,
@@ -470,6 +464,8 @@ module.exports = cls => class Reifier extends cls {
470
464
  // find all the nodes that need to change between the actual
471
465
  // and ideal trees.
472
466
  this.diff = Diff.calculate({
467
+ omit: this.#omit,
468
+ omitted: this.#omitted,
473
469
  shrinkwrapInflated: this.#shrinkwrapInflated,
474
470
  filterNodes,
475
471
  actual: this.actualTree,
@@ -554,37 +550,6 @@ module.exports = cls => class Reifier extends cls {
554
550
  })
555
551
  }
556
552
 
557
- // adding to the trash list will skip reifying, and delete them
558
- // if they are currently in the tree and otherwise untouched.
559
- [_addOmitsToTrashList] () {
560
- if (!this.#omit.size) {
561
- return
562
- }
563
-
564
- const timeEnd = time.start('reify:trashOmits')
565
- for (const node of this.idealTree.inventory.values()) {
566
- const { top } = node
567
-
568
- // if the top is not the root or workspace then we do not want to omit it
569
- if (!top.isProjectRoot && !top.isWorkspace) {
570
- continue
571
- }
572
-
573
- // if a diff filter has been created, then we do not omit the node if the
574
- // top node is not in that set
575
- if (this.diff?.filterSet?.size && !this.diff.filterSet.has(top)) {
576
- continue
577
- }
578
-
579
- // omit node if the dep type matches any omit flags that were set
580
- if (node.shouldOmit(this.#omit)) {
581
- this[_addNodeToTrashList](node)
582
- }
583
- }
584
-
585
- timeEnd()
586
- }
587
-
588
553
  [_createSparseTree] () {
589
554
  const timeEnd = time.start('reify:createSparse')
590
555
  // if we call this fn again, we look for the previous list
@@ -683,7 +648,6 @@ module.exports = cls => class Reifier extends cls {
683
648
  // reload the diff and sparse tree because the ideal tree changed
684
649
  .then(() => this[_diffTrees]())
685
650
  .then(() => this[_createSparseTree]())
686
- .then(() => this[_addOmitsToTrashList]())
687
651
  .then(() => this[_loadShrinkwrapsAndUpdateTrees]())
688
652
  .then(timeEnd)
689
653
  }
@@ -691,15 +655,10 @@ module.exports = cls => class Reifier extends cls {
691
655
  // create a symlink for Links, extract for Nodes
692
656
  // return the node object, since we usually want that
693
657
  // handle optional dep failures here
694
- // If node is in trash list, skip it
695
658
  // If reifying fails, and the node is optional, add it and its optionalSet
696
659
  // to the trash list
697
660
  // Always return the node.
698
661
  [_reifyNode] (node) {
699
- if (this[_trashList].has(node.path)) {
700
- return node
701
- }
702
-
703
662
  const timeEnd = time.start(`reifyNode:${node.location}`)
704
663
  this.addTracker('reify', node.name, node.location)
705
664
 
@@ -803,7 +762,7 @@ module.exports = cls => class Reifier extends cls {
803
762
  })
804
763
  // store nodes don't use Node class so node.package doesn't get updated
805
764
  if (node.isInStore) {
806
- const pkg = await rpj(join(node.path, 'package.json'))
765
+ const { content: pkg } = await PackageJson.normalize(node.path)
807
766
  node.package.scripts = pkg.scripts
808
767
  }
809
768
  return
@@ -1432,8 +1391,7 @@ module.exports = cls => class Reifier extends cls {
1432
1391
  if (options.saveType) {
1433
1392
  const depType = saveTypeMap.get(options.saveType)
1434
1393
  pkg[depType][name] = newSpec
1435
- // rpj will have moved it here if it was in both
1436
- // if it is empty it will be deleted later
1394
+ // PackageJson.normalize will have moved it here if it was in both, if it is empty it will be deleted later
1437
1395
  if (options.saveType === 'prod' && pkg.optionalDependencies) {
1438
1396
  delete pkg.optionalDependencies[name]
1439
1397
  }
@@ -1474,7 +1432,7 @@ module.exports = cls => class Reifier extends cls {
1474
1432
  const exactVersion = node => {
1475
1433
  for (const edge of node.edgesIn) {
1476
1434
  try {
1477
- if (semver.subset(edge.spec, node.version)) {
1435
+ if (subset(edge.spec, node.version)) {
1478
1436
  return false
1479
1437
  }
1480
1438
  } catch {
@@ -22,6 +22,7 @@ const calcDepFlagsStep = (node) => {
22
22
  // or normal dependency graphs overlap deep in the dep graph.
23
23
  // Since we're only walking through deps that are not already flagged
24
24
  // as non-dev/non-optional, it's typically a very shallow traversal
25
+
25
26
  node.extraneous = false
26
27
  resetParents(node, 'extraneous')
27
28
  resetParents(node, 'dev')
@@ -47,10 +48,16 @@ const calcDepFlagsStep = (node) => {
47
48
  if (!to) {
48
49
  return
49
50
  }
50
-
51
51
  // everything with any kind of edge into it is not extraneous
52
52
  to.extraneous = false
53
53
 
54
+ // If this is a peer edge, mark the target as peer
55
+ if (peer) {
56
+ to.peer = true
57
+ } else if (to.peer && !hasIncomingPeerEdge(to)) {
58
+ unsetFlag(to, 'peer')
59
+ }
60
+
54
61
  // devOptional is the *overlap* of the dev and optional tree.
55
62
  // however, for convenience and to save an extra rewalk, we leave
56
63
  // it set when we are in *either* tree, and then omit it from the
@@ -61,11 +68,6 @@ const calcDepFlagsStep = (node) => {
61
68
  // either the dev or opt trees
62
69
  const unsetDev = unsetDevOpt || !node.dev && !dev
63
70
  const unsetOpt = unsetDevOpt || !node.optional && !optional
64
- const unsetPeer = !node.peer && !peer
65
-
66
- if (unsetPeer) {
67
- unsetFlag(to, 'peer')
68
- }
69
71
 
70
72
  if (unsetDevOpt) {
71
73
  unsetFlag(to, 'devOptional')
@@ -83,6 +85,16 @@ const calcDepFlagsStep = (node) => {
83
85
  return node
84
86
  }
85
87
 
88
+ const hasIncomingPeerEdge = (node) => {
89
+ const target = node.isLink && node.target ? node.target : node
90
+ for (const edge of target.edgesIn) {
91
+ if (edge.type === 'peer') {
92
+ return true
93
+ }
94
+ }
95
+ return false
96
+ }
97
+
86
98
  const resetParents = (node, flag) => {
87
99
  if (node[flag]) {
88
100
  return
@@ -109,12 +121,19 @@ const unsetFlag = (node, flag) => {
109
121
  const children = []
110
122
  const targetNode = node.isLink && node.target ? node.target : node
111
123
  for (const edge of targetNode.edgesOut.values()) {
112
- if (
113
- edge.to &&
114
- edge.to[flag] &&
115
- ((flag !== 'peer' && edge.type === 'peer') || edge.type === 'prod')
116
- ) {
117
- children.push(edge.to)
124
+ if (edge.to?.[flag]) {
125
+ // For the peer flag, only follow peer edges to unset the flag
126
+ // Don't propagate peer flag through prod/dev/optional edges
127
+ if (flag === 'peer') {
128
+ if (edge.type === 'peer') {
129
+ children.push(edge.to)
130
+ }
131
+ } else {
132
+ // For other flags, follow prod edges (and peer edges for non-peer flags)
133
+ if (edge.type === 'prod' || edge.type === 'peer') {
134
+ children.push(edge.to)
135
+ }
136
+ }
118
137
  }
119
138
  }
120
139
  return children
package/lib/diff.js CHANGED
@@ -11,7 +11,9 @@ const { existsSync } = require('node:fs')
11
11
  const ssri = require('ssri')
12
12
 
13
13
  class Diff {
14
- constructor ({ actual, ideal, filterSet, shrinkwrapInflated }) {
14
+ constructor ({ actual, ideal, filterSet, shrinkwrapInflated, omit, omitted }) {
15
+ this.omit = omit
16
+ this.omitted = omitted
15
17
  this.filterSet = filterSet
16
18
  this.shrinkwrapInflated = shrinkwrapInflated
17
19
  this.children = []
@@ -36,6 +38,8 @@ class Diff {
36
38
  ideal,
37
39
  filterNodes = [],
38
40
  shrinkwrapInflated = new Set(),
41
+ omit = new Set(),
42
+ omitted = new Set(),
39
43
  }) {
40
44
  // if there's a filterNode, then:
41
45
  // - get the path from the root to the filterNode. The root or
@@ -94,18 +98,28 @@ class Diff {
94
98
  }
95
99
 
96
100
  return depth({
97
- tree: new Diff({ actual, ideal, filterSet, shrinkwrapInflated }),
101
+ tree: new Diff({ actual, ideal, filterSet, shrinkwrapInflated, omit, omitted }),
98
102
  getChildren,
99
103
  leave,
100
104
  })
101
105
  }
102
106
  }
103
107
 
104
- const getAction = ({ actual, ideal }) => {
108
+ const getAction = ({ actual, ideal, omit, omitted }) => {
105
109
  if (!ideal) {
106
110
  return 'REMOVE'
107
111
  }
108
112
 
113
+ if (ideal.shouldOmit?.(omit)) {
114
+ omitted.add(ideal)
115
+
116
+ if (actual) {
117
+ return 'REMOVE'
118
+ }
119
+
120
+ return null
121
+ }
122
+
109
123
  // bundled meta-deps are copied over to the ideal tree when we visit it,
110
124
  // so they'll appear to be missing here. There's no need to handle them
111
125
  // in the diff, though, because they'll be replaced at reify time anyway
@@ -184,6 +198,8 @@ const getChildren = diff => {
184
198
  removed,
185
199
  filterSet,
186
200
  shrinkwrapInflated,
201
+ omit,
202
+ omitted,
187
203
  } = diff
188
204
 
189
205
  // Note: we DON'T diff fsChildren themselves, because they are either
@@ -214,6 +230,8 @@ const getChildren = diff => {
214
230
  removed,
215
231
  filterSet,
216
232
  shrinkwrapInflated,
233
+ omit,
234
+ omitted,
217
235
  })
218
236
  }
219
237
 
@@ -232,12 +250,14 @@ const diffNode = ({
232
250
  removed,
233
251
  filterSet,
234
252
  shrinkwrapInflated,
253
+ omit,
254
+ omitted,
235
255
  }) => {
236
256
  if (filterSet.size && !(filterSet.has(ideal) || filterSet.has(actual))) {
237
257
  return
238
258
  }
239
259
 
240
- const action = getAction({ actual, ideal })
260
+ const action = getAction({ actual, ideal, omit, omitted })
241
261
 
242
262
  // if it's a match, then get its children
243
263
  // otherwise, this is the child diff node
@@ -245,7 +265,7 @@ const diffNode = ({
245
265
  if (action === 'REMOVE') {
246
266
  removed.push(actual)
247
267
  }
248
- children.push(new Diff({ actual, ideal, filterSet, shrinkwrapInflated }))
268
+ children.push(new Diff({ actual, ideal, filterSet, shrinkwrapInflated, omit, omitted }))
249
269
  } else {
250
270
  unchanged.push(ideal)
251
271
  // !*! Weird dirty hack warning !*!
@@ -285,6 +305,8 @@ const diffNode = ({
285
305
  removed,
286
306
  filterSet,
287
307
  shrinkwrapInflated,
308
+ omit,
309
+ omitted,
288
310
  }))
289
311
  }
290
312
  }
package/lib/node.js CHANGED
@@ -28,22 +28,28 @@
28
28
  // where we need to quickly find all instances of a given package name within a
29
29
  // tree.
30
30
 
31
- const semver = require('semver')
31
+ const PackageJson = require('@npmcli/package-json')
32
32
  const nameFromFolder = require('@npmcli/name-from-folder')
33
+ const npa = require('npm-package-arg')
34
+ const semver = require('semver')
35
+ const util = require('node:util')
36
+ const { getPaths: getBinPaths } = require('bin-links')
37
+ const { log } = require('proc-log')
38
+ const { resolve, relative, dirname, basename } = require('node:path')
39
+ const { walkUp } = require('walk-up-path')
40
+
41
+ const CaseInsensitiveMap = require('./case-insensitive-map.js')
33
42
  const Edge = require('./edge.js')
34
43
  const Inventory = require('./inventory.js')
35
44
  const OverrideSet = require('./override-set.js')
36
- const { normalize } = require('read-package-json-fast')
37
- const { getPaths: getBinPaths } = require('bin-links')
38
- const npa = require('npm-package-arg')
45
+ const consistentResolve = require('./consistent-resolve.js')
39
46
  const debug = require('./debug.js')
40
47
  const gatherDepSet = require('./gather-dep-set.js')
48
+ const printableTree = require('./printable.js')
49
+ const querySelectorAll = require('./query-selector-all.js')
50
+ const relpath = require('./relpath.js')
41
51
  const treeCheck = require('./tree-check.js')
42
- const { walkUp } = require('walk-up-path')
43
- const { log } = require('proc-log')
44
52
 
45
- const { resolve, relative, dirname, basename } = require('node:path')
46
- const util = require('node:util')
47
53
  const _package = Symbol('_package')
48
54
  const _parent = Symbol('_parent')
49
55
  const _target = Symbol.for('_target')
@@ -58,14 +64,6 @@ const _delistFromMeta = Symbol.for('_delistFromMeta')
58
64
  const _explain = Symbol('_explain')
59
65
  const _explanation = Symbol('_explanation')
60
66
 
61
- const relpath = require('./relpath.js')
62
- const consistentResolve = require('./consistent-resolve.js')
63
-
64
- const printableTree = require('./printable.js')
65
- const CaseInsensitiveMap = require('./case-insensitive-map.js')
66
-
67
- const querySelectorAll = require('./query-selector-all.js')
68
-
69
67
  class Node {
70
68
  #global
71
69
  #meta
@@ -121,14 +119,25 @@ class Node {
121
119
  // package's dependencies in a virtual root.
122
120
  this.sourceReference = sourceReference
123
121
 
124
- // TODO if this came from pacote.manifest we don't have to do this,
125
- // we can be told to skip this step
126
- const pkg = sourceReference ? sourceReference.package
127
- : normalize(options.pkg || {})
122
+ // have to set the internal package ref before assigning the parent, because this.package is read when adding to inventory
123
+ if (sourceReference) {
124
+ this[_package] = sourceReference.package
125
+ } else {
126
+ // TODO if this came from pacote.manifest we don't have to do this, we can be told to skip this step
127
+ const pkg = new PackageJson()
128
+ let content = {}
129
+ // TODO this is overly guarded. If pkg is not an object we should not allow it at all.
130
+ if (options.pkg && typeof options.pkg === 'object') {
131
+ content = options.pkg
132
+ }
133
+ pkg.fromContent(content)
134
+ pkg.syncNormalize()
135
+ this[_package] = pkg.content
136
+ }
128
137
 
129
138
  this.name = name ||
130
- nameFromFolder(path || pkg.name || realpath) ||
131
- pkg.name ||
139
+ nameFromFolder(path || this.package.name || realpath) ||
140
+ this.package.name ||
132
141
  null
133
142
 
134
143
  // should be equal if not a link
@@ -156,13 +165,13 @@ class Node {
156
165
  // probably what we're getting from pacote, which IS trustworthy.
157
166
  //
158
167
  // Otherwise, hopefully a shrinkwrap will help us out.
159
- const resolved = consistentResolve(pkg._resolved)
160
- if (resolved && !(/^file:/.test(resolved) && pkg._where)) {
168
+ const resolved = consistentResolve(this.package._resolved)
169
+ if (resolved && !(/^file:/.test(resolved) && this.package._where)) {
161
170
  this.resolved = resolved
162
171
  }
163
172
  }
164
- this.integrity = integrity || pkg._integrity || null
165
- this.hasShrinkwrap = hasShrinkwrap || pkg._hasShrinkwrap || false
173
+ this.integrity = integrity || this.package._integrity || null
174
+ this.hasShrinkwrap = hasShrinkwrap || this.package._hasShrinkwrap || false
166
175
  this.installLinks = installLinks
167
176
  this.legacyPeerDeps = legacyPeerDeps
168
177
 
@@ -203,17 +212,13 @@ class Node {
203
212
  this.edgesIn = new Set()
204
213
  this.edgesOut = new CaseInsensitiveMap()
205
214
 
206
- // have to set the internal package ref before assigning the parent,
207
- // because this.package is read when adding to inventory
208
- this[_package] = pkg && typeof pkg === 'object' ? pkg : {}
209
-
210
215
  if (overrides) {
211
216
  this.overrides = overrides
212
217
  } else if (loadOverrides) {
213
- const overrides = this[_package].overrides || {}
218
+ const overrides = this.package.overrides || {}
214
219
  if (Object.keys(overrides).length > 0) {
215
220
  this.overrides = new OverrideSet({
216
- overrides: this[_package].overrides,
221
+ overrides: this.package.overrides,
217
222
  })
218
223
  }
219
224
  }
@@ -314,7 +319,7 @@ class Node {
314
319
  }
315
320
 
316
321
  return getBinPaths({
317
- pkg: this[_package],
322
+ pkg: this.package,
318
323
  path: this.path,
319
324
  global: this.global,
320
325
  top: this.globalTop,
@@ -328,11 +333,11 @@ class Node {
328
333
  }
329
334
 
330
335
  get version () {
331
- return this[_package].version || ''
336
+ return this.package.version || ''
332
337
  }
333
338
 
334
339
  get packageName () {
335
- return this[_package].name || null
340
+ return this.package.name || null
336
341
  }
337
342
 
338
343
  get pkgid () {
@@ -490,6 +495,18 @@ class Node {
490
495
  }
491
496
 
492
497
  shouldOmit (omitSet) {
498
+ if (!omitSet.size) {
499
+ return false
500
+ }
501
+
502
+ const { top } = this
503
+
504
+ // if the top is not the root or workspace then we do not want to omit it
505
+ if (!top.isProjectRoot && !top.isWorkspace) {
506
+ return false
507
+ }
508
+
509
+ // omit node if the dep type matches any omit flags that were set
493
510
  return (
494
511
  this.peer && omitSet.has('peer') ||
495
512
  this.dev && omitSet.has('dev') ||
package/package.json CHANGED
@@ -1,38 +1,37 @@
1
1
  {
2
2
  "name": "@npmcli/arborist",
3
- "version": "9.1.4",
3
+ "version": "9.1.5",
4
4
  "description": "Manage node_modules trees",
5
5
  "dependencies": {
6
6
  "@isaacs/string-locale-compare": "^1.1.0",
7
7
  "@npmcli/fs": "^4.0.0",
8
8
  "@npmcli/installed-package-contents": "^3.0.0",
9
- "@npmcli/map-workspaces": "^4.0.1",
10
- "@npmcli/metavuln-calculator": "^9.0.0",
9
+ "@npmcli/map-workspaces": "^5.0.0",
10
+ "@npmcli/metavuln-calculator": "^9.0.2",
11
11
  "@npmcli/name-from-folder": "^3.0.0",
12
12
  "@npmcli/node-gyp": "^4.0.0",
13
- "@npmcli/package-json": "^6.0.1",
13
+ "@npmcli/package-json": "^7.0.0",
14
14
  "@npmcli/query": "^4.0.0",
15
15
  "@npmcli/redact": "^3.0.0",
16
- "@npmcli/run-script": "^9.0.1",
16
+ "@npmcli/run-script": "^10.0.0",
17
17
  "bin-links": "^5.0.0",
18
- "cacache": "^19.0.1",
18
+ "cacache": "^20.0.1",
19
19
  "common-ancestor-path": "^1.0.1",
20
- "hosted-git-info": "^8.0.0",
20
+ "hosted-git-info": "^9.0.0",
21
21
  "json-stringify-nice": "^1.1.4",
22
- "lru-cache": "^10.2.2",
23
- "minimatch": "^9.0.4",
22
+ "lru-cache": "^11.2.1",
23
+ "minimatch": "^10.0.3",
24
24
  "nopt": "^8.0.0",
25
25
  "npm-install-checks": "^7.1.0",
26
- "npm-package-arg": "^12.0.0",
27
- "npm-pick-manifest": "^10.0.0",
28
- "npm-registry-fetch": "^18.0.1",
29
- "pacote": "^21.0.0",
26
+ "npm-package-arg": "^13.0.0",
27
+ "npm-pick-manifest": "^11.0.1",
28
+ "npm-registry-fetch": "^19.0.0",
29
+ "pacote": "^21.0.2",
30
30
  "parse-conflict-json": "^4.0.0",
31
31
  "proc-log": "^5.0.0",
32
32
  "proggy": "^3.0.0",
33
33
  "promise-all-reject-late": "^1.0.0",
34
34
  "promise-call-limit": "^3.0.1",
35
- "read-package-json-fast": "^4.0.0",
36
35
  "semver": "^7.3.7",
37
36
  "ssri": "^12.0.0",
38
37
  "treeverse": "^3.0.0",
@@ -41,7 +40,7 @@
41
40
  "devDependencies": {
42
41
  "@npmcli/eslint-config": "^5.0.1",
43
42
  "@npmcli/mock-registry": "^1.0.0",
44
- "@npmcli/template-oss": "4.24.4",
43
+ "@npmcli/template-oss": "4.25.1",
45
44
  "benchmark": "^2.1.4",
46
45
  "minify-registry-metadata": "^4.0.0",
47
46
  "nock": "^13.3.3",
@@ -93,7 +92,7 @@
93
92
  },
94
93
  "templateOSS": {
95
94
  "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
96
- "version": "4.24.4",
95
+ "version": "4.25.1",
97
96
  "content": "../../scripts/template-oss/index.js"
98
97
  }
99
98
  }