Skip to content

Commit 27fb534

Browse files
David Sveningssonext
David Sveningsson
authored andcommitted
fix: handle dependencies where the new version is out-of-range
1 parent 3b2842b commit 27fb534

File tree

4 files changed

+84
-1
lines changed

4 files changed

+84
-1
lines changed

package-lock.json

+14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
"@jest/globals": "29.7.0",
9090
"@types/jest": "29.5.14",
9191
"@types/npmlog": "7.0.0",
92+
"@types/semver": "7.5.8",
9293
"babel-plugin-transform-import-meta": "2.3.2",
9394
"esbuild": "0.25.0",
9495
"jest": "29.7.0",

src/prepare.js

+18-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { existsSync } from "node:fs";
44
import { format } from "node:util";
55
import { execa } from "execa";
66
import npmVersion from "libnpmversion";
7-
import semverParse from "semver/functions/parse.js";
7+
import { parse as semverParse, satisfies as semverSatisfies, validRange } from "semver";
88
import { Package } from "./lerna/package";
99
import { Project } from "./lerna/project";
1010
import getChangedPackages from "./get-changed-packages.js";
@@ -113,6 +113,7 @@ async function updateLockfile(npmrc, pkg, context) {
113113
* @param {Record<string, string>} currentVersions
114114
* @returns {void}
115115
*/
116+
/* eslint-disable-next-line complexity, sonarjs/cognitive-complexity -- hard to refactor into something much more readable */
116117
function bumpDependency(dependencies, newVersion, currentVersions) {
117118
const newParsed = semverParse(newVersion);
118119
if (!newParsed) {
@@ -132,21 +133,37 @@ function bumpDependency(dependencies, newVersion, currentVersions) {
132133
/* Exact versions */
133134
if (range === version) {
134135
dependencies[dep] = newVersion;
136+
continue;
135137
}
136138

137139
/* Hat ^x.y.z */
138140
if (range === `^${version}`) {
139141
dependencies[dep] = `^${newVersion}`;
142+
continue;
140143
}
141144

142145
/* Hat ^x.y */
143146
if (range === `^${parsed.major}.${parsed.minor}`) {
144147
dependencies[dep] = `^${newParsed.major}.${newParsed.minor}`;
148+
continue;
145149
}
146150

147151
/* Hat ^x */
148152
if (range === `^${parsed.major}`) {
149153
dependencies[dep] = `^${newParsed.major}`;
154+
continue;
155+
}
156+
157+
/* If the range is a a valid semver range but is no longer satisfied by the
158+
* new version forcibly update the range */
159+
if (validRange(range)) {
160+
const isSatisfied = semverSatisfies(newVersion, range);
161+
if (!isSatisfied) {
162+
const hat = range.startsWith("^") ? "^" : "";
163+
const numComponents = Array.from(range).filter((it) => it === ".").length + 1;
164+
const components = [newParsed.major, newParsed.minor, newParsed.patch];
165+
dependencies[dep] = `${hat}${components.slice(0, numComponents).join(".")}`;
166+
}
150167
}
151168
}
152169
}

src/prepare.test.js

+51
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,57 @@ it("Update package.json dependency when using hat", () => {
479479
});
480480
});
481481

482+
it("Update package.json dependency when new version is out of range", () => {
483+
expect.assertions(1);
484+
return withTempDir(async (cwd) => {
485+
const npmrc = await temporaryFile({ name: ".npmrc" });
486+
await createProject(cwd, "1.2.3");
487+
const foo = await createPackage(
488+
cwd,
489+
"foo",
490+
"1.2.3",
491+
{
492+
changed: true,
493+
},
494+
{
495+
dependencies: {
496+
a: "^1.1.0",
497+
b: "^1.1",
498+
c: "^1",
499+
},
500+
},
501+
);
502+
503+
await createPackage(cwd, "a", "1.2.3", { changed: true });
504+
await createPackage(cwd, "b", "1.2.3", { changed: true });
505+
await createPackage(cwd, "c", "1.2.3", { changed: true });
506+
507+
await prepare(
508+
npmrc,
509+
{},
510+
{
511+
cwd,
512+
env: {},
513+
stdout: context.stdout,
514+
stderr: context.stderr,
515+
nextRelease: { version: "2.0.0" },
516+
logger: context.logger,
517+
},
518+
);
519+
520+
// Verify dependency has been updated
521+
expect(await readJson(foo.manifestLocation)).toEqual({
522+
name: "foo",
523+
version: "2.0.0",
524+
dependencies: {
525+
a: "^2.0.0",
526+
b: "^2.0",
527+
c: "^2",
528+
},
529+
});
530+
});
531+
});
532+
482533
it("Should not update other dependencies", () => {
483534
expect.assertions(1);
484535
return withTempDir(async (cwd) => {

0 commit comments

Comments
 (0)