@npmcli/arborist 7.5.1 → 7.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/arborist/build-ideal-tree.js +17 -43
- package/lib/arborist/index.js +2 -2
- package/lib/node.js +2 -0
- package/lib/packument-cache.js +77 -0
- package/lib/shrinkwrap.js +2 -1
- package/package.json +15 -14
|
@@ -53,48 +53,26 @@ const _addNodeToTrashList = Symbol.for('addNodeToTrashList')
|
|
|
53
53
|
// they'll affect things deeper in, then alphabetical for consistency between
|
|
54
54
|
// installs
|
|
55
55
|
class DepsQueue {
|
|
56
|
-
// [{ sorted, items }] indexed by depth
|
|
57
56
|
#deps = []
|
|
58
57
|
#sorted = true
|
|
59
|
-
#minDepth = 0
|
|
60
|
-
#length = 0
|
|
61
58
|
|
|
62
59
|
get length () {
|
|
63
|
-
return this.#length
|
|
60
|
+
return this.#deps.length
|
|
64
61
|
}
|
|
65
62
|
|
|
66
63
|
push (item) {
|
|
67
|
-
if (!this.#deps
|
|
68
|
-
this.#
|
|
69
|
-
this.#deps
|
|
70
|
-
// no minDepth check needed, this branch is only reached when we are in
|
|
71
|
-
// the middle of a shallower depth and creating a new one
|
|
72
|
-
return
|
|
73
|
-
}
|
|
74
|
-
if (!this.#deps[item.depth].items.includes(item)) {
|
|
75
|
-
this.#length++
|
|
76
|
-
this.#deps[item.depth].sorted = false
|
|
77
|
-
this.#deps[item.depth].items.push(item)
|
|
78
|
-
if (item.depth < this.#minDepth) {
|
|
79
|
-
this.#minDepth = item.depth
|
|
80
|
-
}
|
|
64
|
+
if (!this.#deps.includes(item)) {
|
|
65
|
+
this.#sorted = false
|
|
66
|
+
this.#deps.push(item)
|
|
81
67
|
}
|
|
82
68
|
}
|
|
83
69
|
|
|
84
70
|
pop () {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (!depth?.items.length) {
|
|
89
|
-
this.#minDepth++
|
|
90
|
-
}
|
|
71
|
+
if (!this.#sorted) {
|
|
72
|
+
this.#deps.sort((a, b) => (a.depth - b.depth) || localeCompare(a.path, b.path))
|
|
73
|
+
this.#sorted = true
|
|
91
74
|
}
|
|
92
|
-
|
|
93
|
-
depth.items.sort((a, b) => localeCompare(a.path, b.path))
|
|
94
|
-
depth.sorted = true
|
|
95
|
-
}
|
|
96
|
-
this.#length--
|
|
97
|
-
return depth.items.shift()
|
|
75
|
+
return this.#deps.shift()
|
|
98
76
|
}
|
|
99
77
|
}
|
|
100
78
|
|
|
@@ -1022,6 +1000,10 @@ This is a one-time fix-up, please be patient...
|
|
|
1022
1000
|
// may well be an optional dep that has gone missing. it'll
|
|
1023
1001
|
// fail later anyway.
|
|
1024
1002
|
for (const e of this.#problemEdges(placed)) {
|
|
1003
|
+
// XXX This is somehow load bearing. This makes tests that print
|
|
1004
|
+
// the ideal tree of a tree with tarball dependencies fail. This
|
|
1005
|
+
// can't be changed or removed till we figure out why
|
|
1006
|
+
// The test is named "tarball deps with transitive tarball deps"
|
|
1025
1007
|
promises.push(() =>
|
|
1026
1008
|
this.#fetchManifest(npa.resolve(e.name, e.spec, fromPath(placed, e)))
|
|
1027
1009
|
.catch(() => null)
|
|
@@ -1204,6 +1186,7 @@ This is a one-time fix-up, please be patient...
|
|
|
1204
1186
|
const options = {
|
|
1205
1187
|
...this.options,
|
|
1206
1188
|
avoid: this.#avoidRange(spec.name),
|
|
1189
|
+
fullMetadata: true,
|
|
1207
1190
|
}
|
|
1208
1191
|
// get the intended spec and stored metadata from yarn.lock file,
|
|
1209
1192
|
// if available and valid.
|
|
@@ -1212,19 +1195,10 @@ This is a one-time fix-up, please be patient...
|
|
|
1212
1195
|
if (this.#manifests.has(spec.raw)) {
|
|
1213
1196
|
return this.#manifests.get(spec.raw)
|
|
1214
1197
|
} else {
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
fullMetadata: true,
|
|
1220
|
-
}
|
|
1221
|
-
const p = pacote.manifest(spec, o)
|
|
1222
|
-
.then(({ license, ...mani }) => {
|
|
1223
|
-
this.#manifests.set(spec.raw, mani)
|
|
1224
|
-
return mani
|
|
1225
|
-
})
|
|
1226
|
-
this.#manifests.set(spec.raw, p)
|
|
1227
|
-
return p
|
|
1198
|
+
log.silly('fetch manifest', spec.raw.replace(spec.rawSpec, redact(spec.rawSpec)))
|
|
1199
|
+
const mani = await pacote.manifest(spec, options)
|
|
1200
|
+
this.#manifests.set(spec.raw, mani)
|
|
1201
|
+
return mani
|
|
1228
1202
|
}
|
|
1229
1203
|
}
|
|
1230
1204
|
|
package/lib/arborist/index.js
CHANGED
|
@@ -31,10 +31,10 @@ const { homedir } = require('os')
|
|
|
31
31
|
const { depth } = require('treeverse')
|
|
32
32
|
const mapWorkspaces = require('@npmcli/map-workspaces')
|
|
33
33
|
const { log, time } = require('proc-log')
|
|
34
|
-
|
|
35
34
|
const { saveTypeMap } = require('../add-rm-pkg-deps.js')
|
|
36
35
|
const AuditReport = require('../audit-report.js')
|
|
37
36
|
const relpath = require('../relpath.js')
|
|
37
|
+
const PackumentCache = require('../packument-cache.js')
|
|
38
38
|
|
|
39
39
|
const mixins = [
|
|
40
40
|
require('../tracker.js'),
|
|
@@ -82,7 +82,7 @@ class Arborist extends Base {
|
|
|
82
82
|
installStrategy: options.global ? 'shallow' : (options.installStrategy ? options.installStrategy : 'hoisted'),
|
|
83
83
|
lockfileVersion: lockfileVersion(options.lockfileVersion),
|
|
84
84
|
packageLockOnly: !!options.packageLockOnly,
|
|
85
|
-
packumentCache: options.packumentCache || new
|
|
85
|
+
packumentCache: options.packumentCache || new PackumentCache(),
|
|
86
86
|
path: options.path || '.',
|
|
87
87
|
rebuildBundle: 'rebuildBundle' in options ? !!options.rebuildBundle : true,
|
|
88
88
|
replaceRegistryHost: options.replaceRegistryHost,
|
package/lib/node.js
CHANGED
|
@@ -119,6 +119,8 @@ class Node {
|
|
|
119
119
|
// package's dependencies in a virtual root.
|
|
120
120
|
this.sourceReference = sourceReference
|
|
121
121
|
|
|
122
|
+
// TODO if this came from pacote.manifest we don't have to do this,
|
|
123
|
+
// we can be told to skip this step
|
|
122
124
|
const pkg = sourceReference ? sourceReference.package
|
|
123
125
|
: normalize(options.pkg || {})
|
|
124
126
|
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const { LRUCache } = require('lru-cache')
|
|
2
|
+
const { getHeapStatistics } = require('node:v8')
|
|
3
|
+
const { log } = require('proc-log')
|
|
4
|
+
|
|
5
|
+
// This is an in-memory cache that Pacote uses for packuments.
|
|
6
|
+
// Packuments are usually cached on disk. This allows for rapid re-requests
|
|
7
|
+
// of the same packument to bypass disk reads. The tradeoff here is memory
|
|
8
|
+
// usage for disk reads.
|
|
9
|
+
class PackumentCache extends LRUCache {
|
|
10
|
+
static #heapLimit = Math.floor(getHeapStatistics().heap_size_limit)
|
|
11
|
+
|
|
12
|
+
#sizeKey
|
|
13
|
+
#disposed = new Set()
|
|
14
|
+
|
|
15
|
+
#log (...args) {
|
|
16
|
+
log.silly('packumentCache', ...args)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
constructor ({
|
|
20
|
+
// How much of this.#heapLimit to take up
|
|
21
|
+
heapFactor = 0.25,
|
|
22
|
+
// How much of this.#maxSize we allow any one packument to take up
|
|
23
|
+
// Anything over this is not cached
|
|
24
|
+
maxEntryFactor = 0.5,
|
|
25
|
+
sizeKey = '_contentLength',
|
|
26
|
+
} = {}) {
|
|
27
|
+
const maxSize = Math.floor(PackumentCache.#heapLimit * heapFactor)
|
|
28
|
+
const maxEntrySize = Math.floor(maxSize * maxEntryFactor)
|
|
29
|
+
super({
|
|
30
|
+
maxSize,
|
|
31
|
+
maxEntrySize,
|
|
32
|
+
sizeCalculation: (p) => {
|
|
33
|
+
// Don't cache if we dont know the size
|
|
34
|
+
// Some versions of pacote set this to `0`, newer versions set it to `null`
|
|
35
|
+
if (!p[sizeKey]) {
|
|
36
|
+
return maxEntrySize + 1
|
|
37
|
+
}
|
|
38
|
+
if (p[sizeKey] < 10_000) {
|
|
39
|
+
return p[sizeKey] * 2
|
|
40
|
+
}
|
|
41
|
+
if (p[sizeKey] < 1_000_000) {
|
|
42
|
+
return Math.floor(p[sizeKey] * 1.5)
|
|
43
|
+
}
|
|
44
|
+
// It is less beneficial to store a small amount of super large things
|
|
45
|
+
// at the cost of all other packuments.
|
|
46
|
+
return maxEntrySize + 1
|
|
47
|
+
},
|
|
48
|
+
dispose: (v, k) => {
|
|
49
|
+
this.#disposed.add(k)
|
|
50
|
+
this.#log(k, 'dispose')
|
|
51
|
+
},
|
|
52
|
+
})
|
|
53
|
+
this.#sizeKey = sizeKey
|
|
54
|
+
this.#log(`heap:${PackumentCache.#heapLimit} maxSize:${maxSize} maxEntrySize:${maxEntrySize}`)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
set (k, v, ...args) {
|
|
58
|
+
// we use disposed only for a logging signal if we are setting packuments that
|
|
59
|
+
// have already been evicted from the cache previously. logging here could help
|
|
60
|
+
// us tune this in the future.
|
|
61
|
+
const disposed = this.#disposed.has(k)
|
|
62
|
+
/* istanbul ignore next - this doesnt happen consistently so hard to test without resorting to unit tests */
|
|
63
|
+
if (disposed) {
|
|
64
|
+
this.#disposed.delete(k)
|
|
65
|
+
}
|
|
66
|
+
this.#log(k, 'set', `size:${v[this.#sizeKey]} disposed:${disposed}`)
|
|
67
|
+
return super.set(k, v, ...args)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
has (k, ...args) {
|
|
71
|
+
const has = super.has(k, ...args)
|
|
72
|
+
this.#log(k, `cache-${has ? 'hit' : 'miss'}`)
|
|
73
|
+
return has
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
module.exports = PackumentCache
|
package/lib/shrinkwrap.js
CHANGED
|
@@ -1153,7 +1153,8 @@ class Shrinkwrap {
|
|
|
1153
1153
|
&& this.originalLockfileVersion !== this.lockfileVersion
|
|
1154
1154
|
) {
|
|
1155
1155
|
log.warn(
|
|
1156
|
-
|
|
1156
|
+
'shrinkwrap',
|
|
1157
|
+
`Converting lock file (${relative(process.cwd(), this.filename)}) from v${this.originalLockfileVersion} -> v${this.lockfileVersion}`
|
|
1157
1158
|
)
|
|
1158
1159
|
}
|
|
1159
1160
|
|
package/package.json
CHANGED
|
@@ -1,32 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@npmcli/arborist",
|
|
3
|
-
"version": "7.5.
|
|
3
|
+
"version": "7.5.2",
|
|
4
4
|
"description": "Manage node_modules trees",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@isaacs/string-locale-compare": "^1.1.0",
|
|
7
|
-
"@npmcli/fs": "^3.1.
|
|
7
|
+
"@npmcli/fs": "^3.1.1",
|
|
8
8
|
"@npmcli/installed-package-contents": "^2.1.0",
|
|
9
9
|
"@npmcli/map-workspaces": "^3.0.2",
|
|
10
|
-
"@npmcli/metavuln-calculator": "^7.1.
|
|
10
|
+
"@npmcli/metavuln-calculator": "^7.1.1",
|
|
11
11
|
"@npmcli/name-from-folder": "^2.0.0",
|
|
12
12
|
"@npmcli/node-gyp": "^3.0.0",
|
|
13
13
|
"@npmcli/package-json": "^5.1.0",
|
|
14
14
|
"@npmcli/query": "^3.1.0",
|
|
15
15
|
"@npmcli/redact": "^2.0.0",
|
|
16
16
|
"@npmcli/run-script": "^8.1.0",
|
|
17
|
-
"bin-links": "^4.0.
|
|
18
|
-
"cacache": "^18.0.
|
|
17
|
+
"bin-links": "^4.0.4",
|
|
18
|
+
"cacache": "^18.0.3",
|
|
19
19
|
"common-ancestor-path": "^1.0.1",
|
|
20
|
-
"hosted-git-info": "^7.0.
|
|
21
|
-
"json-parse-even-better-errors": "^3.0.
|
|
20
|
+
"hosted-git-info": "^7.0.2",
|
|
21
|
+
"json-parse-even-better-errors": "^3.0.2",
|
|
22
22
|
"json-stringify-nice": "^1.1.4",
|
|
23
|
+
"lru-cache": "^10.2.2",
|
|
23
24
|
"minimatch": "^9.0.4",
|
|
24
|
-
"nopt": "^7.
|
|
25
|
+
"nopt": "^7.2.1",
|
|
25
26
|
"npm-install-checks": "^6.2.0",
|
|
26
27
|
"npm-package-arg": "^11.0.2",
|
|
27
|
-
"npm-pick-manifest": "^9.0.
|
|
28
|
-
"npm-registry-fetch": "^17.0.
|
|
29
|
-
"pacote": "^18.0.
|
|
28
|
+
"npm-pick-manifest": "^9.0.1",
|
|
29
|
+
"npm-registry-fetch": "^17.0.1",
|
|
30
|
+
"pacote": "^18.0.6",
|
|
30
31
|
"parse-conflict-json": "^3.0.0",
|
|
31
32
|
"proc-log": "^4.2.0",
|
|
32
33
|
"proggy": "^2.0.0",
|
|
@@ -34,13 +35,13 @@
|
|
|
34
35
|
"promise-call-limit": "^3.0.1",
|
|
35
36
|
"read-package-json-fast": "^3.0.2",
|
|
36
37
|
"semver": "^7.3.7",
|
|
37
|
-
"ssri": "^10.0.
|
|
38
|
+
"ssri": "^10.0.6",
|
|
38
39
|
"treeverse": "^3.0.0",
|
|
39
40
|
"walk-up-path": "^3.0.1"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
43
|
"@npmcli/eslint-config": "^4.0.0",
|
|
43
|
-
"@npmcli/template-oss": "4.
|
|
44
|
+
"@npmcli/template-oss": "4.22.0",
|
|
44
45
|
"benchmark": "^2.1.4",
|
|
45
46
|
"minify-registry-metadata": "^3.0.0",
|
|
46
47
|
"nock": "^13.3.3",
|
|
@@ -91,7 +92,7 @@
|
|
|
91
92
|
},
|
|
92
93
|
"templateOSS": {
|
|
93
94
|
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
|
|
94
|
-
"version": "4.
|
|
95
|
+
"version": "4.22.0",
|
|
95
96
|
"content": "../../scripts/template-oss/index.js"
|
|
96
97
|
}
|
|
97
98
|
}
|