@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 +3 -1
- package/lib/arborist/build-ideal-tree.js +8 -6
- package/lib/arborist/index.js +1 -1
- package/lib/arborist/load-actual.js +16 -4
- package/lib/arborist/reify.js +21 -37
- package/lib/audit-report.js +1 -1
- package/lib/calc-dep-flags.js +14 -2
- package/lib/diff.js +20 -4
- package/lib/inventory.js +17 -1
- package/lib/node.js +16 -2
- package/lib/shrinkwrap.js +8 -2
- package/lib/tracker.js +1 -1
- package/package.json +4 -2
- package/lib/proc-log.js +0 -21
- package/lib/update-root-package-json.js +0 -95
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
|
-
|
|
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 && !
|
|
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 =
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
const
|
|
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)
|
package/lib/arborist/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
package/lib/arborist/reify.js
CHANGED
|
@@ -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(
|
|
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
|
|
package/lib/audit-report.js
CHANGED
|
@@ -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('
|
|
15
|
+
const procLog = require('proc-log')
|
|
16
16
|
|
|
17
17
|
const fetch = require('npm-registry-fetch')
|
|
18
18
|
|
package/lib/calc-dep-flags.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
-
:
|
|
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
|
-
|
|
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
|
-
|
|
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('
|
|
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
|
-
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@npmcli/arborist",
|
|
3
|
-
"version": "2.6.
|
|
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": "^
|
|
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
|