@npmcli/arborist 2.8.2 → 2.9.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.
Files changed (49) hide show
  1. package/bin/actual.js +4 -2
  2. package/bin/audit.js +12 -6
  3. package/bin/dedupe.js +6 -3
  4. package/bin/funding.js +4 -2
  5. package/bin/ideal.js +2 -1
  6. package/bin/lib/logging.js +4 -3
  7. package/bin/lib/options.js +14 -12
  8. package/bin/lib/timers.js +6 -3
  9. package/bin/license.js +9 -5
  10. package/bin/prune.js +6 -3
  11. package/bin/reify.js +6 -3
  12. package/bin/virtual.js +4 -2
  13. package/lib/add-rm-pkg-deps.js +28 -15
  14. package/lib/arborist/audit.js +2 -1
  15. package/lib/arborist/build-ideal-tree.js +139 -72
  16. package/lib/arborist/deduper.js +2 -1
  17. package/lib/arborist/index.js +8 -4
  18. package/lib/arborist/load-actual.js +28 -13
  19. package/lib/arborist/load-virtual.js +37 -20
  20. package/lib/arborist/load-workspaces.js +4 -2
  21. package/lib/arborist/rebuild.js +34 -17
  22. package/lib/arborist/reify.js +153 -76
  23. package/lib/audit-report.js +44 -23
  24. package/lib/calc-dep-flags.js +18 -9
  25. package/lib/can-place-dep.js +59 -30
  26. package/lib/case-insensitive-map.js +4 -2
  27. package/lib/consistent-resolve.js +2 -1
  28. package/lib/deepest-nesting-target.js +4 -2
  29. package/lib/dep-valid.js +8 -4
  30. package/lib/diff.js +74 -22
  31. package/lib/edge.js +26 -13
  32. package/lib/gather-dep-set.js +2 -1
  33. package/lib/inventory.js +12 -6
  34. package/lib/link.js +14 -9
  35. package/lib/node.js +216 -113
  36. package/lib/optional-set.js +4 -2
  37. package/lib/peer-entry-sets.js +10 -5
  38. package/lib/place-dep.js +111 -37
  39. package/lib/printable.js +46 -25
  40. package/lib/realpath.js +12 -6
  41. package/lib/shrinkwrap.js +164 -90
  42. package/lib/signal-handling.js +6 -3
  43. package/lib/spec-from-lock.js +7 -4
  44. package/lib/tracker.js +24 -18
  45. package/lib/tree-check.js +12 -6
  46. package/lib/version-from-tgz.js +4 -2
  47. package/lib/vuln.js +44 -22
  48. package/lib/yarn-lock.js +34 -21
  49. package/package.json +8 -10
@@ -1,4 +1,5 @@
1
1
  // mixin implementing the buildIdealTree method
2
+ const localeCompare = require('@isaacs/string-locale-compare')('en')
2
3
  const rpj = require('read-package-json-fast')
3
4
  const npa = require('npm-package-arg')
4
5
  const pacote = require('pacote')
@@ -137,8 +138,9 @@ module.exports = cls => class IdealTreeBuilder extends cls {
137
138
  this[_globalStyle] = this[_global] || globalStyle
138
139
  this[_follow] = !!follow
139
140
 
140
- if (this[_workspaces].length && this[_global])
141
+ if (this[_workspaces].length && this[_global]) {
141
142
  throw new Error('Cannot operate on workspaces in global mode')
143
+ }
142
144
 
143
145
  this[_explicitRequests] = new Set()
144
146
  this[_preferDedupe] = false
@@ -168,18 +170,21 @@ module.exports = cls => class IdealTreeBuilder extends cls {
168
170
 
169
171
  // public method
170
172
  async buildIdealTree (options = {}) {
171
- if (this.idealTree)
173
+ if (this.idealTree) {
172
174
  return Promise.resolve(this.idealTree)
175
+ }
173
176
 
174
177
  // allow the user to set reify options on the ctor as well.
175
178
  // XXX: deprecate separate reify() options object.
176
179
  options = { ...this.options, ...options }
177
180
 
178
181
  // an empty array or any falsey value is the same as null
179
- if (!options.add || options.add.length === 0)
182
+ if (!options.add || options.add.length === 0) {
180
183
  options.add = null
181
- if (!options.rm || options.rm.length === 0)
184
+ }
185
+ if (!options.rm || options.rm.length === 0) {
182
186
  options.rm = null
187
+ }
183
188
 
184
189
  process.emit('time', 'idealTree')
185
190
 
@@ -230,11 +235,12 @@ module.exports = cls => class IdealTreeBuilder extends cls {
230
235
 
231
236
  [_checkEngine] (node) {
232
237
  const { engineStrict, npmVersion, nodeVersion } = this.options
233
- const c = () => checkEngine(node.package, npmVersion, nodeVersion, this[_force])
238
+ const c = () =>
239
+ checkEngine(node.package, npmVersion, nodeVersion, this[_force])
234
240
 
235
- if (engineStrict)
241
+ if (engineStrict) {
236
242
  c()
237
- else {
243
+ } else {
238
244
  try {
239
245
  c()
240
246
  } catch (er) {
@@ -252,8 +258,9 @@ module.exports = cls => class IdealTreeBuilder extends cls {
252
258
  : Array.isArray(options.update) ? { names: options.update }
253
259
  : options.update || {}
254
260
 
255
- if (update.all || !Array.isArray(update.names))
261
+ if (update.all || !Array.isArray(update.names)) {
256
262
  update.names = []
263
+ }
257
264
 
258
265
  this[_complete] = !!options.complete
259
266
  this[_preferDedupe] = !!options.preferDedupe
@@ -283,8 +290,9 @@ module.exports = cls => class IdealTreeBuilder extends cls {
283
290
  : rpj(this.path + '/package.json').then(
284
291
  pkg => this[_rootNodeFromPackage](pkg),
285
292
  er => {
286
- if (er.code === 'EJSONPARSE')
293
+ if (er.code === 'EJSONPARSE') {
287
294
  throw er
295
+ }
288
296
  return this[_rootNodeFromPackage]({})
289
297
  }
290
298
  ))
@@ -312,8 +320,9 @@ module.exports = cls => class IdealTreeBuilder extends cls {
312
320
  // even though we didn't load it from a package-lock.json FILE,
313
321
  // we still loaded it "from disk", meaning we have to reset
314
322
  // dep flags before assuming that any mutations were reflected.
315
- if (tree.children.size)
323
+ if (tree.children.size) {
316
324
  root.meta.loadedFromDisk = true
325
+ }
317
326
  }
318
327
  return root
319
328
  })
@@ -382,9 +391,9 @@ module.exports = cls => class IdealTreeBuilder extends cls {
382
391
  process.emit('time', 'idealTree:userRequests')
383
392
  const tree = this.idealTree.target
384
393
 
385
- if (!this[_workspaces].length)
394
+ if (!this[_workspaces].length) {
386
395
  await this[_applyUserRequestsToNode](tree, options)
387
- else {
396
+ } else {
388
397
  await Promise.all(this.workspaceNodes(tree, this[_workspaces])
389
398
  .map(node => this[_applyUserRequestsToNode](node, options)))
390
399
  }
@@ -396,8 +405,9 @@ module.exports = cls => class IdealTreeBuilder extends cls {
396
405
  // If we have a list of package names to update, and we know it's
397
406
  // going to update them wherever they are, add any paths into those
398
407
  // named nodes to the buildIdealTree queue.
399
- if (!this[_global] && this[_updateNames].length)
408
+ if (!this[_global] && this[_updateNames].length) {
400
409
  this[_queueNamedUpdates]()
410
+ }
401
411
 
402
412
  // global updates only update the globalTop nodes, but we need to know
403
413
  // that they're there, and not reinstall the world unnecessarily.
@@ -408,46 +418,55 @@ module.exports = cls => class IdealTreeBuilder extends cls {
408
418
  tree.package.dependencies = tree.package.dependencies || {}
409
419
  const updateName = this[_updateNames].includes(name)
410
420
  if (this[_updateAll] || updateName) {
411
- if (updateName)
421
+ if (updateName) {
412
422
  globalExplicitUpdateNames.push(name)
423
+ }
413
424
  const dir = resolve(nm, name)
414
- const st = await lstat(dir).catch(/* istanbul ignore next */ er => null)
425
+ const st = await lstat(dir)
426
+ .catch(/* istanbul ignore next */ er => null)
415
427
  if (st && st.isSymbolicLink()) {
416
428
  const target = await readlink(dir)
417
429
  const real = resolve(dirname(dir), target)
418
430
  tree.package.dependencies[name] = `file:${real}`
419
- } else
431
+ } else {
420
432
  tree.package.dependencies[name] = '*'
433
+ }
421
434
  }
422
435
  }
423
436
  }
424
437
 
425
- if (this.auditReport && this.auditReport.size > 0)
438
+ if (this.auditReport && this.auditReport.size > 0) {
426
439
  await this[_queueVulnDependents](options)
440
+ }
427
441
 
428
442
  const { add, rm } = options
429
443
 
430
444
  if (rm && rm.length) {
431
445
  addRmPkgDeps.rm(tree.package, rm)
432
- for (const name of rm)
446
+ for (const name of rm) {
433
447
  this[_explicitRequests].add({ from: tree, name, action: 'DELETE' })
448
+ }
434
449
  }
435
450
 
436
- if (add && add.length)
451
+ if (add && add.length) {
437
452
  await this[_add](tree, options)
453
+ }
438
454
 
439
455
  // triggers a refresh of all edgesOut. this has to be done BEFORE
440
456
  // adding the edges to explicitRequests, because the package setter
441
457
  // resets all edgesOut.
442
- if (add && add.length || rm && rm.length || this[_global])
458
+ if (add && add.length || rm && rm.length || this[_global]) {
443
459
  tree.package = tree.package
460
+ }
444
461
 
445
462
  for (const spec of this[_resolvedAdd]) {
446
- if (spec.tree === tree)
463
+ if (spec.tree === tree) {
447
464
  this[_explicitRequests].add(tree.edgesOut.get(spec.name))
465
+ }
448
466
  }
449
- for (const name of globalExplicitUpdateNames)
467
+ for (const name of globalExplicitUpdateNames) {
450
468
  this[_explicitRequests].add(tree.edgesOut.get(name))
469
+ }
451
470
 
452
471
  this[_depsQueue].push(tree)
453
472
  }
@@ -487,21 +506,24 @@ module.exports = cls => class IdealTreeBuilder extends cls {
487
506
  // if it's an explicit tag, we need to install that specific tag version
488
507
  const isTag = spec.rawSpec && spec.type === 'tag'
489
508
 
490
- if (spec.name && !isTag)
509
+ if (spec.name && !isTag) {
491
510
  return spec
511
+ }
492
512
 
493
513
  const mani = await pacote.manifest(spec, { ...this.options })
494
514
  // if it's a tag type, then we need to run it down to an actual version
495
- if (isTag)
515
+ if (isTag) {
496
516
  return npa(`${mani.name}@${mani.version}`)
517
+ }
497
518
 
498
519
  spec.name = mani.name
499
520
  return spec
500
521
  }
501
522
 
502
523
  async [_updateFilePath] (spec) {
503
- if (spec.type === 'file')
524
+ if (spec.type === 'file') {
504
525
  return this[_getRelpathSpec](spec, spec.fetchSpec)
526
+ }
505
527
 
506
528
  return spec
507
529
  }
@@ -601,8 +623,9 @@ module.exports = cls => class IdealTreeBuilder extends cls {
601
623
  nodesTouched.add(node)
602
624
  }
603
625
  }
604
- for (const node of nodesTouched)
626
+ for (const node of nodesTouched) {
605
627
  node.package = node.package
628
+ }
606
629
  }
607
630
  }
608
631
 
@@ -611,11 +634,13 @@ module.exports = cls => class IdealTreeBuilder extends cls {
611
634
  }
612
635
 
613
636
  [_avoidRange] (name) {
614
- if (!this.auditReport)
637
+ if (!this.auditReport) {
615
638
  return null
639
+ }
616
640
  const vuln = this.auditReport.get(name)
617
- if (!vuln)
641
+ if (!vuln) {
618
642
  return null
643
+ }
619
644
  return vuln.range
620
645
  }
621
646
 
@@ -652,8 +677,9 @@ module.exports = cls => class IdealTreeBuilder extends cls {
652
677
  const ancient = meta.ancientLockfile
653
678
  const old = meta.loadedFromDisk && !(meta.originalLockfileVersion >= 2)
654
679
 
655
- if (inventory.size === 0 || !ancient && !old)
680
+ if (inventory.size === 0 || !ancient && !old) {
656
681
  return
682
+ }
657
683
 
658
684
  // if the lockfile is from node v5 or earlier, then we'll have to reload
659
685
  // all the manifests of everything we encounter. this is costly, but at
@@ -672,8 +698,9 @@ This is a one-time fix-up, please be patient...
672
698
  this.addTracker('idealTree:inflate')
673
699
  const queue = []
674
700
  for (const node of inventory.values()) {
675
- if (node.isProjectRoot)
701
+ if (node.isProjectRoot) {
676
702
  continue
703
+ }
677
704
 
678
705
  queue.push(async () => {
679
706
  this.log.silly('inflate', node.location)
@@ -738,13 +765,14 @@ This is a one-time fix-up, please be patient...
738
765
  this[_currentDep] = null
739
766
  }
740
767
 
741
- if (!this[_depsQueue].length)
768
+ if (!this[_depsQueue].length) {
742
769
  return this[_resolveLinks]()
770
+ }
743
771
 
744
772
  // sort physically shallower deps up to the front of the queue,
745
773
  // because they'll affect things deeper in, then alphabetical
746
774
  this[_depsQueue].sort((a, b) =>
747
- (a.depth - b.depth) || a.path.localeCompare(b.path, 'en'))
775
+ (a.depth - b.depth) || localeCompare(a.path, b.path))
748
776
 
749
777
  const node = this[_depsQueue].shift()
750
778
  const bd = node.package.bundleDependencies
@@ -757,8 +785,9 @@ This is a one-time fix-up, please be patient...
757
785
  // satisfied by whatever's in that file anyway.
758
786
  if (this[_depsSeen].has(node) ||
759
787
  node.root !== this.idealTree ||
760
- hasShrinkwrap && !this[_complete])
788
+ hasShrinkwrap && !this[_complete]) {
761
789
  return this[_buildDepStep]()
790
+ }
762
791
 
763
792
  this[_depsSeen].add(node)
764
793
  this[_currentDep] = node
@@ -841,8 +870,9 @@ This is a one-time fix-up, please be patient...
841
870
  const tasks = []
842
871
  const peerSource = this[_peerSetSource].get(node) || node
843
872
  for (const edge of this[_problemEdges](node)) {
844
- if (edge.overridden)
873
+ if (edge.overridden) {
845
874
  continue
875
+ }
846
876
 
847
877
  // peerSetSource is only relevant when we have a peerEntryEdge
848
878
  // otherwise we're setting regular non-peer deps as if they have
@@ -878,15 +908,16 @@ This is a one-time fix-up, please be patient...
878
908
 
879
909
  /* istanbul ignore next */
880
910
  debug(() => {
881
- if (!dep)
911
+ if (!dep) {
882
912
  throw new Error('no dep??')
913
+ }
883
914
  })
884
915
 
885
916
  tasks.push({edge, dep})
886
917
  }
887
918
 
888
919
  const placeDeps = tasks
889
- .sort((a, b) => a.edge.name.localeCompare(b.edge.name, 'en'))
920
+ .sort((a, b) => localeCompare(a.edge.name, b.edge.name))
890
921
  .map(({ edge, dep }) => new PlaceDep({
891
922
  edge,
892
923
  dep,
@@ -912,17 +943,20 @@ This is a one-time fix-up, please be patient...
912
943
  visit: pd => {
913
944
  const { placed, edge, canPlace: cpd } = pd
914
945
  // if we didn't place anything, nothing to do here
915
- if (!placed)
946
+ if (!placed) {
916
947
  return
948
+ }
917
949
 
918
950
  // we placed something, that means we changed the tree
919
- if (placed.errors.length)
951
+ if (placed.errors.length) {
920
952
  this[_loadFailures].add(placed)
953
+ }
921
954
  this[_mutateTree] = true
922
955
  if (cpd.canPlaceSelf === OK) {
923
956
  for (const edgeIn of placed.edgesIn) {
924
- if (edgeIn === edge)
957
+ if (edgeIn === edge) {
925
958
  continue
959
+ }
926
960
  const { from, valid, overridden } = edgeIn
927
961
  if (!overridden && !valid && !this[_depsSeen].has(from)) {
928
962
  this.addTracker('idealTree', from.name, from.location)
@@ -936,8 +970,9 @@ This is a one-time fix-up, please be patient...
936
970
  // intentionally causing something to get nested which was
937
971
  // previously placed in this location.
938
972
  for (const edgeIn of placed.edgesIn) {
939
- if (edgeIn === edge)
973
+ if (edgeIn === edge) {
940
974
  continue
975
+ }
941
976
 
942
977
  const { valid, overridden } = edgeIn
943
978
  if (!valid && !overridden) {
@@ -959,8 +994,13 @@ This is a one-time fix-up, please be patient...
959
994
  return
960
995
  }
961
996
 
962
- // lastly, also check for the missing deps of the node we placed
997
+ // lastly, also check for the missing deps of the node we placed,
998
+ // and any holes created by pruning out conflicted peer sets.
963
999
  this[_depsQueue].push(placed)
1000
+ for (const dep of pd.needEvaluation) {
1001
+ this[_depsSeen].delete(dep)
1002
+ this[_depsQueue].push(dep)
1003
+ }
964
1004
 
965
1005
  // pre-fetch any problem edges, since we'll need these soon
966
1006
  // if it fails at this point, though, dont' worry because it
@@ -975,8 +1015,9 @@ This is a one-time fix-up, please be patient...
975
1015
  }
976
1016
 
977
1017
  for (const { to } of node.edgesOut.values()) {
978
- if (to && to.isLink && to.target)
1018
+ if (to && to.isLink && to.target) {
979
1019
  this[_linkNodes].add(to)
1020
+ }
980
1021
  }
981
1022
 
982
1023
  await Promise.all(promises)
@@ -1019,8 +1060,9 @@ This is a one-time fix-up, please be patient...
1019
1060
 
1020
1061
  if (required.has(edge.from) && edge.type !== 'peerOptional' ||
1021
1062
  secondEdge && (
1022
- required.has(secondEdge.from) && secondEdge.type !== 'peerOptional'))
1063
+ required.has(secondEdge.from) && secondEdge.type !== 'peerOptional')) {
1023
1064
  required.add(node)
1065
+ }
1024
1066
 
1025
1067
  // keep track of the thing that caused this node to be included.
1026
1068
  const src = parent.sourceReference
@@ -1030,16 +1072,18 @@ This is a one-time fix-up, please be patient...
1030
1072
  // otherwise we'll be tempted to put peers as other top-level installed
1031
1073
  // things, potentially clobbering what's there already, which is not
1032
1074
  // what we want. the missing edges will be picked up on the next pass.
1033
- if (this[_global] && edge.from.isProjectRoot)
1075
+ if (this[_global] && edge.from.isProjectRoot) {
1034
1076
  return node
1077
+ }
1035
1078
 
1036
1079
  // otherwise, we have to make sure that our peers can go along with us.
1037
1080
  return this[_loadPeerSet](node, required)
1038
1081
  }
1039
1082
 
1040
1083
  [_virtualRoot] (node, reuse = false) {
1041
- if (reuse && this[_virtualRoots].has(node))
1084
+ if (reuse && this[_virtualRoots].has(node)) {
1042
1085
  return this[_virtualRoots].get(node)
1086
+ }
1043
1087
 
1044
1088
  const vr = new Node({
1045
1089
  path: node.realpath,
@@ -1081,16 +1125,19 @@ This is a one-time fix-up, please be patient...
1081
1125
  return [...node.edgesOut.values()]
1082
1126
  .filter(edge => {
1083
1127
  // If it's included in a bundle, we take whatever is specified.
1084
- if (bundled.has(edge.name))
1128
+ if (bundled.has(edge.name)) {
1085
1129
  return false
1130
+ }
1086
1131
 
1087
1132
  // If it's already been logged as a load failure, skip it.
1088
- if (edge.to && this[_loadFailures].has(edge.to))
1133
+ if (edge.to && this[_loadFailures].has(edge.to)) {
1089
1134
  return false
1135
+ }
1090
1136
 
1091
1137
  // If it's shrinkwrapped, we use what the shrinkwap wants.
1092
- if (edge.to && edge.to.inShrinkwrap)
1138
+ if (edge.to && edge.to.inShrinkwrap) {
1093
1139
  return false
1140
+ }
1094
1141
 
1095
1142
  // If the edge has no destination, that's a problem, unless
1096
1143
  // if it's peerOptional and not explicitly requested.
@@ -1100,20 +1147,24 @@ This is a one-time fix-up, please be patient...
1100
1147
  }
1101
1148
 
1102
1149
  // If the edge has an error, there's a problem.
1103
- if (!edge.valid)
1150
+ if (!edge.valid) {
1104
1151
  return true
1152
+ }
1105
1153
 
1106
- // If user has explicitly asked to update this package by name, it's a problem.
1107
- if (this[_updateNames].includes(edge.name))
1154
+ // user explicitly asked to update this package by name, problem
1155
+ if (this[_updateNames].includes(edge.name)) {
1108
1156
  return true
1157
+ }
1109
1158
 
1110
- // If we're fixing a security vulnerability with this package, it's a problem.
1111
- if (this[_isVulnerable](edge.to))
1159
+ // fixing a security vulnerability with this package, problem
1160
+ if (this[_isVulnerable](edge.to)) {
1112
1161
  return true
1162
+ }
1113
1163
 
1114
- // If the user has explicitly asked to install this package, it's a "problem".
1115
- if (this[_explicitRequests].has(edge))
1164
+ // user has explicitly asked to install this package, problem
1165
+ if (this[_explicitRequests].has(edge)) {
1116
1166
  return true
1167
+ }
1117
1168
 
1118
1169
  // No problems!
1119
1170
  return false
@@ -1129,9 +1180,9 @@ This is a one-time fix-up, please be patient...
1129
1180
  // if available and valid.
1130
1181
  spec = this.idealTree.meta.checkYarnLock(spec, options)
1131
1182
 
1132
- if (this[_manifests].has(spec.raw))
1183
+ if (this[_manifests].has(spec.raw)) {
1133
1184
  return this[_manifests].get(spec.raw)
1134
- else {
1185
+ } else {
1135
1186
  this.log.silly('fetch manifest', spec.raw)
1136
1187
  const p = pacote.manifest(spec, options)
1137
1188
  .then(mani => {
@@ -1197,12 +1248,13 @@ This is a one-time fix-up, please be patient...
1197
1248
  // we typically only install non-optional peers, but we have to
1198
1249
  // factor them into the peerSet so that we can avoid conflicts
1199
1250
  .filter(e => e.peer && !(e.valid && e.to))
1200
- .sort(({name: a}, {name: b}) => a.localeCompare(b, 'en'))
1251
+ .sort(({name: a}, {name: b}) => localeCompare(a, b))
1201
1252
 
1202
1253
  for (const edge of peerEdges) {
1203
1254
  // already placed this one, and we're happy with it.
1204
- if (edge.valid && edge.to)
1255
+ if (edge.valid && edge.to) {
1205
1256
  continue
1257
+ }
1206
1258
 
1207
1259
  const parentEdge = node.parent.edgesOut.get(edge.name)
1208
1260
  const {isProjectRoot, isWorkspace} = node.parent.sourceReference
@@ -1223,11 +1275,17 @@ This is a one-time fix-up, please be patient...
1223
1275
  // a conflict. this is always a problem in strict mode, never
1224
1276
  // in force mode, and a problem in non-strict mode if this isn't
1225
1277
  // on behalf of our project. in all such cases, we warn at least.
1226
- const dep = await this[_nodeFromEdge](parentEdge, node.parent, edge, required)
1278
+ const dep = await this[_nodeFromEdge](
1279
+ parentEdge,
1280
+ node.parent,
1281
+ edge,
1282
+ required
1283
+ )
1227
1284
 
1228
1285
  // hooray! that worked!
1229
- if (edge.valid)
1286
+ if (edge.valid) {
1230
1287
  continue
1288
+ }
1231
1289
 
1232
1290
  // allow it. either we're overriding, or it's not something
1233
1291
  // that will be installed by default anyway, and we'll fail when
@@ -1260,8 +1318,9 @@ This is a one-time fix-up, please be patient...
1260
1318
  // isn't also required, then there's a good chance we won't need it,
1261
1319
  // so allow it for now and let it conflict if it turns out to actually
1262
1320
  // be necessary for the installation.
1263
- if (conflictOK || !required.has(edge.from))
1321
+ if (conflictOK || !required.has(edge.from)) {
1264
1322
  continue
1323
+ }
1265
1324
 
1266
1325
  // ok, it's the root, or we're in unforced strict mode, so this is bad
1267
1326
  this[_failPeerConflict](edge, parentEdge)
@@ -1304,15 +1363,17 @@ This is a one-time fix-up, please be patient...
1304
1363
  this[_linkNodes].delete(link)
1305
1364
 
1306
1365
  // link we never ended up placing, skip it
1307
- if (link.root !== this.idealTree)
1366
+ if (link.root !== this.idealTree) {
1308
1367
  continue
1368
+ }
1309
1369
 
1310
1370
  const tree = this.idealTree.target
1311
1371
  const external = !link.target.isDescendantOf(tree)
1312
1372
 
1313
1373
  // outside the root, somebody else's problem, ignore it
1314
- if (external && !this[_follow])
1374
+ if (external && !this[_follow]) {
1315
1375
  continue
1376
+ }
1316
1377
 
1317
1378
  // didn't find a parent for it or it has not been seen yet
1318
1379
  // so go ahead and process it.
@@ -1328,8 +1389,9 @@ This is a one-time fix-up, please be patient...
1328
1389
  }
1329
1390
  }
1330
1391
 
1331
- if (this[_depsQueue].length)
1392
+ if (this[_depsQueue].length) {
1332
1393
  return this[_buildDepStep]()
1394
+ }
1333
1395
  }
1334
1396
 
1335
1397
  [_fixDepFlags] () {
@@ -1344,8 +1406,9 @@ This is a one-time fix-up, please be patient...
1344
1406
  // all set to true, and there can be nothing extraneous, so there's
1345
1407
  // nothing to prune, because we built it from scratch. if we didn't
1346
1408
  // add or remove anything, then also nothing to do.
1347
- if (metaFromDisk && mutateTree)
1409
+ if (metaFromDisk && mutateTree) {
1348
1410
  resetDepFlags(this.idealTree)
1411
+ }
1349
1412
 
1350
1413
  // update all the dev/optional/etc flags in the tree
1351
1414
  // either we started with a fresh tree, or we
@@ -1353,9 +1416,9 @@ This is a one-time fix-up, please be patient...
1353
1416
  //
1354
1417
  // if we started from a blank slate, or changed something, then
1355
1418
  // the dep flags will be all set to true.
1356
- if (!metaFromDisk || mutateTree)
1419
+ if (!metaFromDisk || mutateTree) {
1357
1420
  calcDepFlags(this.idealTree)
1358
- else {
1421
+ } else {
1359
1422
  // otherwise just unset all the flags on the root node
1360
1423
  // since they will sometimes have the default value
1361
1424
  this.idealTree.extraneous = false
@@ -1370,25 +1433,29 @@ This is a one-time fix-up, please be patient...
1370
1433
  // then the tree is suspect. Prune what is marked as extraneous.
1371
1434
  // otherwise, don't bother.
1372
1435
  const needPrune = metaFromDisk && (mutateTree || flagsSuspect)
1373
- if (this[_prune] && needPrune)
1436
+ if (this[_prune] && needPrune) {
1374
1437
  this[_idealTreePrune]()
1438
+ }
1375
1439
 
1376
1440
  process.emit('timeEnd', 'idealTree:fixDepFlags')
1377
1441
  }
1378
1442
 
1379
1443
  [_idealTreePrune] () {
1380
- for (const node of this.idealTree.inventory.filter(n => n.extraneous))
1444
+ for (const node of this.idealTree.inventory.filter(n => n.extraneous)) {
1381
1445
  node.parent = null
1446
+ }
1382
1447
  }
1383
1448
 
1384
1449
  [_pruneFailedOptional] () {
1385
1450
  for (const node of this[_loadFailures]) {
1386
- if (!node.optional)
1451
+ if (!node.optional) {
1387
1452
  throw node.errors[0]
1453
+ }
1388
1454
 
1389
1455
  const set = optionalSet(node)
1390
- for (const node of set)
1456
+ for (const node of set) {
1391
1457
  node.parent = null
1458
+ }
1392
1459
  }
1393
1460
  }
1394
1461
  }
@@ -6,8 +6,9 @@ module.exports = cls => class Deduper extends cls {
6
6
  const tree = await this.loadVirtual().catch(() => this.loadActual())
7
7
  const names = []
8
8
  for (const name of tree.inventory.query('name')) {
9
- if (tree.inventory.query('name', name).size > 1)
9
+ if (tree.inventory.query('name', name).size > 1) {
10
10
  names.push(name)
11
+ }
11
12
  }
12
13
  return this.reify({
13
14
  ...options,
@@ -59,8 +59,9 @@ class Arborist extends Base {
59
59
  packumentCache: options.packumentCache || new Map(),
60
60
  log: options.log || procLog,
61
61
  }
62
- if (options.saveType && !saveTypeMap.get(options.saveType))
62
+ if (options.saveType && !saveTypeMap.get(options.saveType)) {
63
63
  throw new Error(`Invalid saveType ${options.saveType}`)
64
+ }
64
65
  this.cache = resolve(this.options.cache)
65
66
  this.path = resolve(this.options.path)
66
67
  process.emit('timeEnd', 'arborist:ctor')
@@ -81,17 +82,20 @@ class Arborist extends Base {
81
82
  const dep = edge.to
82
83
  if (dep) {
83
84
  set.add(dep)
84
- if (dep.isLink)
85
+ if (dep.isLink) {
85
86
  set.add(dep.target)
87
+ }
86
88
  }
87
89
  }
88
90
  for (const child of node.children.values()) {
89
- if (child.extraneous)
91
+ if (child.extraneous) {
90
92
  extraneous.add(child)
93
+ }
91
94
  }
92
95
  }
93
- for (const extra of extraneous)
96
+ for (const extra of extraneous) {
94
97
  set.add(extra)
98
+ }
95
99
  return set
96
100
  }
97
101
  }