@npmcli/arborist 2.6.0 → 2.6.4

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.
package/bin/lib/timers.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const timers = Object.create(null)
2
2
  const { format } = require('util')
3
+ const options = require('./options.js')
3
4
 
4
5
  process.on('time', name => {
5
6
  if (timers[name])
@@ -15,7 +16,8 @@ process.on('timeEnd', name => {
15
16
  const res = process.hrtime(timers[name])
16
17
  delete timers[name]
17
18
  const msg = format(`${process.pid} ${name}`, res[0] * 1e3 + res[1] / 1e6)
18
- console.error(dim(msg))
19
+ if (options.timers !== false)
20
+ console.error(dim(msg))
19
21
  })
20
22
 
21
23
  process.on('exit', () => {
@@ -7,7 +7,7 @@ const semver = require('semver')
7
7
  const promiseCallLimit = require('promise-call-limit')
8
8
  const getPeerSet = require('../peer-set.js')
9
9
  const realpath = require('../../lib/realpath.js')
10
- const { resolve } = require('path')
10
+ const { resolve, dirname } = require('path')
11
11
  const { promisify } = require('util')
12
12
  const treeCheck = require('../tree-check.js')
13
13
  const readdir = promisify(require('readdir-scoped-modules'))
@@ -661,7 +661,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
661
661
  const ancient = meta.ancientLockfile
662
662
  const old = meta.loadedFromDisk && !(meta.originalLockfileVersion >= 2)
663
663
 
664
- if (inventory.size === 0 || !ancient && !(old && this[_complete]))
664
+ if (inventory.size === 0 || !ancient && !old)
665
665
  return
666
666
 
667
667
  // if the lockfile is from node v5 or earlier, then we'll have to reload
@@ -688,10 +688,12 @@ This is a one-time fix-up, please be patient...
688
688
  this.log.silly('inflate', node.location)
689
689
  const { resolved, version, path, name, location, integrity } = node
690
690
  // don't try to hit the registry for linked deps
691
- const useResolved = !version ||
692
- resolved && resolved.startsWith('file:')
693
- const id = useResolved ? resolved : version
694
- const spec = npa.resolve(name, id, path)
691
+ const useResolved = resolved && (
692
+ !version || resolved.startsWith('file:')
693
+ )
694
+ const id = useResolved ? resolved
695
+ : version || `file:${node.path}`
696
+ const spec = npa.resolve(name, id, dirname(path))
695
697
  const sloc = location.substr('node_modules/'.length)
696
698
  const t = `idealTree:inflate:${sloc}`
697
699
  this.addTracker(t)
@@ -28,7 +28,7 @@
28
28
 
29
29
  const {resolve} = require('path')
30
30
  const {homedir} = require('os')
31
- const procLog = require('../proc-log.js')
31
+ const procLog = require('proc-log')
32
32
  const { saveTypeMap } = require('../add-rm-pkg-deps.js')
33
33
 
34
34
  const mixins = [
@@ -22,6 +22,7 @@ const _loadFSTree = Symbol('loadFSTree')
22
22
  const _loadFSChildren = Symbol('loadFSChildren')
23
23
  const _findMissingEdges = Symbol('findMissingEdges')
24
24
  const _findFSParents = Symbol('findFSParents')
25
+ const _resetDepFlags = Symbol('resetDepFlags')
25
26
 
26
27
  const _actualTreeLoaded = Symbol('actualTreeLoaded')
27
28
  const _rpcache = Symbol.for('realpathCache')
@@ -74,6 +75,19 @@ module.exports = cls => class ActualLoader extends cls {
74
75
  this[_topNodes] = new Set()
75
76
  }
76
77
 
78
+ [_resetDepFlags] (tree, root) {
79
+ // reset all deps to extraneous prior to recalc
80
+ if (!root) {
81
+ for (const node of tree.inventory.values())
82
+ node.extraneous = true
83
+ }
84
+
85
+ // only reset root flags if we're not re-rooting,
86
+ // otherwise leave as-is
87
+ calcDepFlags(tree, !root)
88
+ return tree
89
+ }
90
+
77
91
  // public method
78
92
  async loadActual (options = {}) {
79
93
  // allow the user to set options on the ctor as well.
@@ -88,6 +102,7 @@ module.exports = cls => class ActualLoader extends cls {
88
102
  return this.actualTree ? this.actualTree
89
103
  : this[_actualTreePromise] ? this[_actualTreePromise]
90
104
  : this[_actualTreePromise] = this[_loadActual](options)
105
+ .then(tree => this[_resetDepFlags](tree, options.root))
91
106
  .then(tree => this.actualTree = treeCheck(tree))
92
107
  }
93
108
 
@@ -152,8 +167,7 @@ module.exports = cls => class ActualLoader extends cls {
152
167
  root: this[_actualTree],
153
168
  })
154
169
  await this[_loadWorkspaces](this[_actualTree])
155
- if (this[_actualTree].workspaces && this[_actualTree].workspaces.size)
156
- calcDepFlags(this[_actualTree], !root)
170
+
157
171
  this[_transplant](root)
158
172
  return this[_actualTree]
159
173
  }
@@ -178,8 +192,6 @@ module.exports = cls => class ActualLoader extends cls {
178
192
  dependencies[name] = dependencies[name] || '*'
179
193
  actualRoot.package = { ...actualRoot.package, dependencies }
180
194
  }
181
- // only reset root flags if we're not re-rooting, otherwise leave as-is
182
- calcDepFlags(this[_actualTree], !root)
183
195
  return this[_actualTree]
184
196
  }
185
197
 
@@ -2,7 +2,6 @@
2
2
 
3
3
  const onExit = require('../signal-handling.js')
4
4
  const pacote = require('pacote')
5
- const rpj = require('read-package-json-fast')
6
5
  const AuditReport = require('../audit-report.js')
7
6
  const {subset, intersects} = require('semver')
8
7
  const npa = require('npm-package-arg')
@@ -16,6 +15,7 @@ const mkdirp = require('mkdirp-infer-owner')
16
15
  const justMkdirp = require('mkdirp')
17
16
  const moveFile = require('@npmcli/move-file')
18
17
  const rimraf = promisify(require('rimraf'))
18
+ const PackageJson = require('@npmcli/package-json')
19
19
  const packageContents = require('@npmcli/installed-package-contents')
20
20
  const { checkEngine, checkPlatform } = require('npm-install-checks')
21
21
 
@@ -25,7 +25,6 @@ const Diff = require('../diff.js')
25
25
  const retirePath = require('../retire-path.js')
26
26
  const promiseAllRejectLate = require('promise-all-reject-late')
27
27
  const optionalSet = require('../optional-set.js')
28
- const updateRootPackageJson = require('../update-root-package-json.js')
29
28
  const calcDepFlags = require('../calc-dep-flags.js')
30
29
  const { saveTypeMap, hasSubKey } = require('../add-rm-pkg-deps.js')
31
30
 
@@ -57,7 +56,6 @@ const _extractOrLink = Symbol('extractOrLink')
57
56
  const _checkBins = Symbol.for('checkBins')
58
57
  const _symlink = Symbol('symlink')
59
58
  const _warnDeprecated = Symbol('warnDeprecated')
60
- const _loadAncientPackageDetails = Symbol('loadAncientPackageDetails')
61
59
  const _loadBundlesAndUpdateTrees = Symbol.for('loadBundlesAndUpdateTrees')
62
60
  const _submitQuickAudit = Symbol('submitQuickAudit')
63
61
  const _awaitQuickAudit = Symbol('awaitQuickAudit')
@@ -522,7 +520,6 @@ module.exports = cls => class Reifier extends cls {
522
520
  await this[_checkBins](node)
523
521
  await this[_extractOrLink](node)
524
522
  await this[_warnDeprecated](node)
525
- await this[_loadAncientPackageDetails](node)
526
523
  })
527
524
 
528
525
  return this[_handleOptionalFailure](node, p)
@@ -583,32 +580,6 @@ module.exports = cls => class Reifier extends cls {
583
580
  this.log.warn('deprecated', `${_id}: ${deprecated}`)
584
581
  }
585
582
 
586
- async [_loadAncientPackageDetails] (node, forceReload = false) {
587
- // If we're loading from a v1 lockfile, load details from the package.json
588
- // that weren't recorded in the old format.
589
- const {meta} = this.idealTree
590
- const ancient = meta.ancientLockfile
591
- const old = meta.loadedFromDisk && !(meta.originalLockfileVersion >= 2)
592
-
593
- // already replaced with the manifest if it's truly ancient
594
- if (node.path && (forceReload || (old && !ancient))) {
595
- // XXX should have a shared location where package.json is read,
596
- // so we don't ever read the same pj more than necessary.
597
- let pkg
598
- try {
599
- pkg = await rpj(node.path + '/package.json')
600
- } catch (err) {}
601
-
602
- if (pkg) {
603
- node.package.bin = pkg.bin
604
- node.package.os = pkg.os
605
- node.package.cpu = pkg.cpu
606
- node.package.engines = pkg.engines
607
- meta.add(node)
608
- }
609
- }
610
- }
611
-
612
583
  // if the node is optional, then the failure of the promise is nonfatal
613
584
  // just add it and its optional set to the trash list.
614
585
  [_handleOptionalFailure] (node, p) {
@@ -1058,6 +1029,25 @@ module.exports = cls => class Reifier extends cls {
1058
1029
 
1059
1030
  const promises = [this[_saveLockFile](saveOpt)]
1060
1031
 
1032
+ const updatePackageJson = async (tree) => {
1033
+ const pkgJson = await PackageJson.load(tree.path)
1034
+ .catch(() => new PackageJson(tree.path))
1035
+ const {
1036
+ dependencies = {},
1037
+ devDependencies = {},
1038
+ optionalDependencies = {},
1039
+ peerDependencies = {},
1040
+ } = tree.package
1041
+
1042
+ pkgJson.update({
1043
+ dependencies,
1044
+ devDependencies,
1045
+ optionalDependencies,
1046
+ peerDependencies,
1047
+ })
1048
+ await pkgJson.save()
1049
+ }
1050
+
1061
1051
  // grab any from explicitRequests that had deps removed
1062
1052
  for (const { from: tree } of this.explicitRequests)
1063
1053
  updatedTrees.add(tree)
@@ -1065,7 +1055,7 @@ module.exports = cls => class Reifier extends cls {
1065
1055
  for (const tree of updatedTrees) {
1066
1056
  // refresh the edges so they have the correct specs
1067
1057
  tree.package = tree.package
1068
- promises.push(updateRootPackageJson(tree))
1058
+ promises.push(updatePackageJson(tree))
1069
1059
  }
1070
1060
 
1071
1061
  await Promise.all(promises)
@@ -1079,12 +1069,6 @@ module.exports = cls => class Reifier extends cls {
1079
1069
 
1080
1070
  const { meta } = this.idealTree
1081
1071
 
1082
- // might have to update metadata for bins and stuff that gets lost
1083
- if (meta.loadedFromDisk && !(meta.originalLockfileVersion >= 2)) {
1084
- for (const node of this.idealTree.inventory.values())
1085
- await this[_loadAncientPackageDetails](node, true)
1086
- }
1087
-
1088
1072
  return meta.save(saveOpt)
1089
1073
  }
1090
1074
 
@@ -12,7 +12,7 @@ const _fixAvailable = Symbol('fixAvailable')
12
12
  const _checkTopNode = Symbol('checkTopNode')
13
13
  const _init = Symbol('init')
14
14
  const _omit = Symbol('omit')
15
- const procLog = require('./proc-log.js')
15
+ const procLog = require('proc-log')
16
16
 
17
17
  const fetch = require('npm-registry-fetch')
18
18
 
@@ -22,6 +22,11 @@ const calcDepFlagsStep = (node) => {
22
22
  // Since we're only walking through deps that are not already flagged
23
23
  // as non-dev/non-optional, it's typically a very shallow traversal
24
24
  node.extraneous = false
25
+ resetParents(node, 'extraneous')
26
+ resetParents(node, 'dev')
27
+ resetParents(node, 'peer')
28
+ resetParents(node, 'devOptional')
29
+ resetParents(node, 'optional')
25
30
 
26
31
  // for links, map their hierarchy appropriately
27
32
  if (node.target) {
@@ -29,8 +34,7 @@ const calcDepFlagsStep = (node) => {
29
34
  node.target.optional = node.optional
30
35
  node.target.devOptional = node.devOptional
31
36
  node.target.peer = node.peer
32
- node.target.extraneous = false
33
- node = node.target
37
+ return calcDepFlagsStep(node.target)
34
38
  }
35
39
 
36
40
  node.edgesOut.forEach(({peer, optional, dev, to}) => {
@@ -71,6 +75,14 @@ const calcDepFlagsStep = (node) => {
71
75
  return node
72
76
  }
73
77
 
78
+ const resetParents = (node, flag) => {
79
+ if (node[flag])
80
+ return
81
+
82
+ for (let p = node; p && (p === node || p[flag]); p = p.resolveParent)
83
+ p[flag] = false
84
+ }
85
+
74
86
  // typically a short walk, since it only traverses deps that
75
87
  // have the flag set.
76
88
  const unsetFlag = (node, flag) => {
package/lib/diff.js CHANGED
@@ -110,16 +110,32 @@ const getAction = ({actual, ideal}) => {
110
110
  if (ideal.isRoot && actual.isRoot)
111
111
  return null
112
112
 
113
+ // if the versions don't match, it's a change no matter what
114
+ if (ideal.version !== actual.version)
115
+ return 'CHANGE'
116
+
113
117
  const binsExist = ideal.binPaths.every((path) => existsSync(path))
114
118
 
115
119
  // top nodes, links, and git deps won't have integrity, but do have resolved
116
- if (!ideal.integrity && !actual.integrity && ideal.resolved === actual.resolved && binsExist)
120
+ // if neither node has integrity, the bins exist, and either (a) neither
121
+ // node has a resolved value or (b) they both do and match, then we can
122
+ // leave this one alone since we already know the versions match due to
123
+ // the condition above. The "neither has resolved" case (a) cannot be
124
+ // treated as a 'mark CHANGE and refetch', because shrinkwraps, bundles,
125
+ // and link deps may lack this information, and we don't want to try to
126
+ // go to the registry for something that isn't there.
127
+ const noIntegrity = !ideal.integrity && !actual.integrity
128
+ const noResolved = !ideal.resolved && !actual.resolved
129
+ const resolvedMatch = ideal.resolved && ideal.resolved === actual.resolved
130
+ if (noIntegrity && binsExist && (resolvedMatch || noResolved))
117
131
  return null
118
132
 
119
133
  // otherwise, verify that it's the same bits
120
134
  // note that if ideal has integrity, and resolved doesn't, we treat
121
135
  // that as a 'change', so that it gets re-fetched and locked down.
122
- if (!ideal.integrity || !actual.integrity || !ssri.parse(ideal.integrity).match(actual.integrity) || !binsExist)
136
+ const integrityMismatch = !ideal.integrity || !actual.integrity ||
137
+ !ssri.parse(ideal.integrity).match(actual.integrity)
138
+ if (integrityMismatch || !binsExist)
123
139
  return 'CHANGE'
124
140
 
125
141
  return null
@@ -129,9 +145,9 @@ const allChildren = node => {
129
145
  if (!node)
130
146
  return new Map()
131
147
 
132
- // if the node is a global root, and also a link, then what we really
148
+ // if the node is root, and also a link, then what we really
133
149
  // want is to traverse the target's children
134
- if (node.global && node.isRoot && node.isLink)
150
+ if (node.isRoot && node.isLink)
135
151
  return allChildren(node.target)
136
152
 
137
153
  const kids = new Map()
package/lib/inventory.js CHANGED
@@ -7,6 +7,20 @@ const _index = Symbol('_index')
7
7
  const defaultKeys = ['name', 'license', 'funding', 'realpath', 'packageName']
8
8
  const { hasOwnProperty } = Object.prototype
9
9
  const debug = require('./debug.js')
10
+
11
+ // handling for the outdated "licenses" array, just pick the first one
12
+ // also support the alternative spelling "licence"
13
+ const getLicense = pkg => {
14
+ if (pkg) {
15
+ const lic = pkg.license || pkg.licence
16
+ if (lic)
17
+ return lic
18
+ const lics = pkg.licenses || pkg.licences
19
+ if (Array.isArray(lics))
20
+ return lics[0]
21
+ }
22
+ }
23
+
10
24
  class Inventory extends Map {
11
25
  constructor (opt = {}) {
12
26
  const { primary, keys } = opt
@@ -56,7 +70,9 @@ class Inventory extends Map {
56
70
  for (const [key, map] of this[_index].entries()) {
57
71
  // if the node has the value, but it's false, then use that
58
72
  const val_ = hasOwnProperty.call(node, key) ? node[key]
59
- : node[key] || (node.package && node.package[key])
73
+ : key === 'license' ? getLicense(node.package)
74
+ : node[key] ? node[key]
75
+ : node.package && node.package[key]
60
76
  const val = typeof val_ === 'string' ? val_
61
77
  : !val_ || typeof val_ !== 'object' ? val_
62
78
  : key === 'license' ? val_.type
package/lib/node.js CHANGED
@@ -547,6 +547,8 @@ class Node {
547
547
 
548
548
  // try to find our parent/fsParent in the new root inventory
549
549
  for (const p of walkUp(dirname(this.path))) {
550
+ if (p === this.path)
551
+ continue
550
552
  const ploc = relpath(root.realpath, p)
551
553
  const parent = root.inventory.get(ploc)
552
554
  if (parent) {
@@ -783,7 +785,13 @@ class Node {
783
785
  }
784
786
 
785
787
  get fsParent () {
786
- return this[_fsParent]
788
+ const parent = this[_fsParent]
789
+ /* istanbul ignore next - should be impossible */
790
+ debug(() => {
791
+ if (parent === this)
792
+ throw new Error('node set to its own fsParent')
793
+ })
794
+ return parent
787
795
  }
788
796
 
789
797
  set fsParent (fsParent) {
@@ -1009,7 +1017,13 @@ class Node {
1009
1017
  }
1010
1018
 
1011
1019
  get parent () {
1012
- return this[_parent]
1020
+ const parent = this[_parent]
1021
+ /* istanbul ignore next - should be impossible */
1022
+ debug(() => {
1023
+ if (parent === this)
1024
+ throw new Error('node set to its own parent')
1025
+ })
1026
+ return parent
1013
1027
  }
1014
1028
 
1015
1029
  // This setter keeps everything in order when we move a node from
package/lib/shrinkwrap.js CHANGED
@@ -32,7 +32,7 @@ const mismatch = (a, b) => a && b && a !== b
32
32
  // After calling this.commit(), any nodes not present in the tree will have
33
33
  // been removed from the shrinkwrap data as well.
34
34
 
35
- const procLog = require('./proc-log.js')
35
+ const procLog = require('proc-log')
36
36
  const YarnLock = require('./yarn-lock.js')
37
37
  const {promisify} = require('util')
38
38
  const rimraf = promisify(require('rimraf'))
@@ -349,6 +349,7 @@ class Shrinkwrap {
349
349
  reset () {
350
350
  this.tree = null
351
351
  this[_awaitingUpdate] = new Map()
352
+ this.originalLockfileVersion = lockfileVersion
352
353
  this.data = {
353
354
  lockfileVersion,
354
355
  requires: true,
@@ -714,6 +715,7 @@ class Shrinkwrap {
714
715
  resolved,
715
716
  integrity,
716
717
  hasShrinkwrap,
718
+ version,
717
719
  } = this.get(node.path)
718
720
 
719
721
  const pathFixed = !resolved ? null
@@ -727,8 +729,12 @@ class Shrinkwrap {
727
729
  node.resolved === pathFixed
728
730
  const integrityOk = !integrity || !node.integrity ||
729
731
  node.integrity === integrity
732
+ const versionOk = !version || !node.version || version === node.version
730
733
 
731
- if ((resolved || integrity) && resolvedOk && integrityOk) {
734
+ const allOk = (resolved || integrity || version) &&
735
+ resolvedOk && integrityOk && versionOk
736
+
737
+ if (allOk) {
732
738
  node.resolved = node.resolved || pathFixed || null
733
739
  node.integrity = node.integrity || integrity || null
734
740
  node.hasShrinkwrap = node.hasShrinkwrap || hasShrinkwrap || false
package/lib/tracker.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const _progress = Symbol('_progress')
2
2
  const _onError = Symbol('_onError')
3
- const procLog = require('./proc-log.js')
3
+ const procLog = require('proc-log')
4
4
 
5
5
  module.exports = cls => class Tracker extends cls {
6
6
  constructor (options = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@npmcli/arborist",
3
- "version": "2.6.0",
3
+ "version": "2.6.4",
4
4
  "description": "Manage node_modules trees",
5
5
  "dependencies": {
6
6
  "@npmcli/installed-package-contents": "^1.0.7",
@@ -9,6 +9,7 @@
9
9
  "@npmcli/move-file": "^1.1.0",
10
10
  "@npmcli/name-from-folder": "^1.0.1",
11
11
  "@npmcli/node-gyp": "^1.0.1",
12
+ "@npmcli/package-json": "^1.0.1",
12
13
  "@npmcli/run-script": "^1.8.2",
13
14
  "bin-links": "^2.2.1",
14
15
  "cacache": "^15.0.3",
@@ -19,9 +20,10 @@
19
20
  "npm-install-checks": "^4.0.0",
20
21
  "npm-package-arg": "^8.1.0",
21
22
  "npm-pick-manifest": "^6.1.0",
22
- "npm-registry-fetch": "^10.0.0",
23
+ "npm-registry-fetch": "^11.0.0",
23
24
  "pacote": "^11.2.6",
24
25
  "parse-conflict-json": "^1.1.1",
26
+ "proc-log": "^1.0.0",
25
27
  "promise-all-reject-late": "^1.0.0",
26
28
  "promise-call-limit": "^1.0.1",
27
29
  "read-package-json-fast": "^2.0.2",
package/lib/proc-log.js DELETED
@@ -1,21 +0,0 @@
1
- // default logger.
2
- // emits 'log' events on the process
3
- const LEVELS = [
4
- 'notice',
5
- 'error',
6
- 'warn',
7
- 'info',
8
- 'verbose',
9
- 'http',
10
- 'silly',
11
- 'pause',
12
- 'resume',
13
- ]
14
-
15
- const log = level => (...args) => process.emit('log', level, ...args)
16
-
17
- const logger = {}
18
- for (const level of LEVELS)
19
- logger[level] = log(level)
20
-
21
- module.exports = logger
@@ -1,95 +0,0 @@
1
- const fs = require('fs')
2
- const promisify = require('util').promisify
3
- const readFile = promisify(fs.readFile)
4
- const writeFile = promisify(fs.writeFile)
5
- const {resolve} = require('path')
6
-
7
- const parseJSON = require('json-parse-even-better-errors')
8
-
9
- const depTypes = new Set([
10
- 'dependencies',
11
- 'optionalDependencies',
12
- 'devDependencies',
13
- 'peerDependencies',
14
- ])
15
-
16
- // sort alphabetically all types of deps for a given package
17
- const orderDeps = (pkg) => {
18
- for (const type of depTypes) {
19
- if (pkg && pkg[type]) {
20
- pkg[type] = Object.keys(pkg[type])
21
- .sort((a, b) => a.localeCompare(b, 'en'))
22
- .reduce((res, key) => {
23
- res[key] = pkg[type][key]
24
- return res
25
- }, {})
26
- }
27
- }
28
- return pkg
29
- }
30
- const parseJsonSafe = json => {
31
- try {
32
- return parseJSON(json)
33
- } catch (er) {
34
- return null
35
- }
36
- }
37
-
38
- const updateRootPackageJson = async tree => {
39
- const filename = resolve(tree.path, 'package.json')
40
- const originalJson = await readFile(filename, 'utf8').catch(() => null)
41
- const originalContent = parseJsonSafe(originalJson)
42
-
43
- const depsData = orderDeps({
44
- ...tree.package,
45
- })
46
-
47
- // optionalDependencies don't need to be repeated in two places
48
- if (depsData.dependencies) {
49
- if (depsData.optionalDependencies) {
50
- for (const name of Object.keys(depsData.optionalDependencies))
51
- delete depsData.dependencies[name]
52
- }
53
- if (Object.keys(depsData.dependencies).length === 0)
54
- delete depsData.dependencies
55
- }
56
-
57
- // if there's no package.json, just use internal pkg info as source of truth
58
- // clone the object though, so we can still refer to what it originally was
59
- const packageJsonContent = !originalContent ? depsData
60
- : Object.assign({}, originalContent)
61
-
62
- // loop through all types of dependencies and update package json content
63
- for (const type of depTypes)
64
- packageJsonContent[type] = depsData[type]
65
-
66
- // if original package.json had dep in peerDeps AND deps, preserve that.
67
- const { dependencies: origProd, peerDependencies: origPeer } =
68
- originalContent || {}
69
- const { peerDependencies: newPeer } = packageJsonContent
70
- if (origProd && origPeer && newPeer) {
71
- // we have original prod/peer deps, and new peer deps
72
- // copy over any that were in both in the original
73
- for (const name of Object.keys(origPeer)) {
74
- if (origProd[name] !== undefined && newPeer[name] !== undefined) {
75
- packageJsonContent.dependencies = packageJsonContent.dependencies || {}
76
- packageJsonContent.dependencies[name] = newPeer[name]
77
- }
78
- }
79
- }
80
-
81
- // format content
82
- const {
83
- [Symbol.for('indent')]: indent,
84
- [Symbol.for('newline')]: newline,
85
- } = tree.package
86
- const format = indent === undefined ? ' ' : indent
87
- const eol = newline === undefined ? '\n' : newline
88
- const content = (JSON.stringify(packageJsonContent, null, format) + '\n')
89
- .replace(/\n/g, eol)
90
-
91
- if (content !== originalJson)
92
- return writeFile(filename, content)
93
- }
94
-
95
- module.exports = updateRootPackageJson