Skip to content

Commit b51b29c

Browse files
committed
fix(arborist): update save exact
When updating dependencies we need an extra check when filtering nodes to be updated that ensures we do not override semver ranges that are pointing to an exact version. e.g: =1.0.0, 1.0.0 Fixes: #4329
1 parent 8558527 commit b51b29c

File tree

6 files changed

+145
-0
lines changed

6 files changed

+145
-0
lines changed

workspaces/arborist/lib/arborist/reify.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const pacote = require('pacote')
55
const AuditReport = require('../audit-report.js')
66
const { subset, intersects } = require('semver')
77
const npa = require('npm-package-arg')
8+
const semver = require('semver')
89
const debug = require('../debug.js')
910
const walkUp = require('walk-up-path')
1011

@@ -1273,6 +1274,21 @@ module.exports = cls => class Reifier extends cls {
12731274
}
12741275
}
12751276

1277+
// Returns true if any of the edges from this node has a semver
1278+
// range definition that is an exact match to the version installed
1279+
// e.g: should return true if for a given an installed version 1.0.0,
1280+
// range is either =1.0.0 or 1.0.0
1281+
const exactVersion = node => {
1282+
for (const edge of node.edgesIn) {
1283+
try {
1284+
if (semver.subset(edge.spec, node.version)) {
1285+
return false
1286+
}
1287+
} catch {}
1288+
}
1289+
return true
1290+
}
1291+
12761292
// helper that retrieves an array of nodes that were
12771293
// potentially updated during the reify process, in order
12781294
// to limit the number of nodes to check and update, only
@@ -1284,6 +1300,8 @@ module.exports = cls => class Reifier extends cls {
12841300
const filterDirectDependencies = node =>
12851301
!node.isRoot && node.resolveParent.isRoot
12861302
&& (!names || names.includes(node.name))
1303+
&& exactVersion(node) // skip update for exact ranges
1304+
12871305
const directDeps = this.idealTree.inventory
12881306
.filter(filterDirectDependencies)
12891307

workspaces/arborist/test/arborist/reify.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2572,5 +2572,34 @@ t.test('save package.json on update', t => {
25722572
)
25732573
})
25742574

2575+
t.test('should preserve exact ranges', async t => {
2576+
const path = fixture(t, 'update-exact-version')
2577+
2578+
await reify(path, { update: true, save: true })
2579+
2580+
t.equal(
2581+
require(resolve(path, 'package.json')).dependencies.abbrev,
2582+
'1.0.4',
2583+
'should save no top level dep update to root package.json'
2584+
)
2585+
})
2586+
2587+
t.test('should preserve exact ranges, missing actual tree', async t => {
2588+
const path = t.testdir({
2589+
'package.json': JSON.stringify({
2590+
dependencies: {
2591+
abbrev: '1.0.4',
2592+
},
2593+
}),
2594+
})
2595+
2596+
await reify(path, { update: true, save: true })
2597+
2598+
t.equal(
2599+
require(resolve(path, 'package.json')).dependencies.abbrev,
2600+
'1.0.4',
2601+
'should save no top level dep update to root package.json'
2602+
)
2603+
})
25752604
t.end()
25762605
})
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// generated from test/fixtures/update-exact-version
2+
module.exports = t => {
3+
const path = t.testdir({
4+
"node_modules": {
5+
"abbrev": {
6+
"package.json": JSON.stringify({
7+
"name": "abbrev",
8+
"version": "1.0.4",
9+
"description": "Like ruby's abbrev module, but in js",
10+
"author": "Isaac Z. Schlueter <[email protected]>",
11+
"main": "./lib/abbrev.js",
12+
"scripts": {
13+
"test": "node lib/abbrev.js"
14+
},
15+
"repository": "http://github.com/isaacs/abbrev-js",
16+
"license": {
17+
"type": "MIT",
18+
"url": "https://github.com/isaacs/abbrev-js/raw/master/LICENSE"
19+
}
20+
})
21+
}
22+
},
23+
"package-lock.json": JSON.stringify({
24+
"name": "update-exact-version",
25+
"lockfileVersion": 2,
26+
"requires": true,
27+
"packages": {
28+
"": {
29+
"dependencies": {
30+
"abbrev": "1.0.4"
31+
}
32+
},
33+
"node_modules/abbrev": {
34+
"version": "1.0.4",
35+
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz",
36+
"integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0="
37+
}
38+
},
39+
"dependencies": {
40+
"abbrev": {
41+
"version": "1.0.4",
42+
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz",
43+
"integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0="
44+
}
45+
}
46+
}),
47+
"package.json": JSON.stringify({
48+
"dependencies": {
49+
"abbrev": "1.0.4"
50+
}
51+
})
52+
})
53+
return path
54+
}

workspaces/arborist/test/fixtures/update-exact-version/node_modules/abbrev/package.json

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

workspaces/arborist/test/fixtures/update-exact-version/package-lock.json

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"dependencies": {
3+
"abbrev": "1.0.4"
4+
}
5+
}

0 commit comments

Comments
 (0)