Skip to content

Commit 33c92bb

Browse files
authored
Autofix to increased latest version range (#358)
1 parent 896f0a0 commit 33c92bb

File tree

9 files changed

+181
-4
lines changed

9 files changed

+181
-4
lines changed

lib/dependency-versions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
compareVersionRanges,
55
compareVersionRangesSafe,
66
versionRangeToRange,
7-
getLatestVersion,
7+
getIncreasedLatestVersion,
88
getHighestRangeType,
99
} from './semver.js';
1010
import semver from 'semver';
@@ -273,7 +273,7 @@ export function fixMismatchingVersions(
273273
);
274274
let fixedVersion;
275275
try {
276-
fixedVersion = getLatestVersion(versions);
276+
fixedVersion = getIncreasedLatestVersion(versions);
277277
} catch {
278278
// Skip this dependency.
279279
notFixed.push(mismatchingVersion);

lib/output.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import chalk from 'chalk';
22
import type { MismatchingDependencyVersions } from './dependency-versions.js';
3-
import { compareVersionRangesSafe, getLatestVersion } from './semver.js';
3+
import {
4+
compareVersionRangesSafe,
5+
getIncreasedLatestVersion,
6+
} from './semver.js';
47
import { table } from 'table';
58

69
export function mismatchingVersionsToOutput(
@@ -67,7 +70,7 @@ export function mismatchingVersionsFixedToOutput(
6770
.flatMap((mismatchingVersion) => {
6871
let version;
6972
try {
70-
version = getLatestVersion(
73+
version = getIncreasedLatestVersion(
7174
mismatchingVersion.versions.map((v) => v.version)
7275
);
7376
} catch {

lib/semver.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,32 @@ export function getHighestRangeType(ranges: string[]): string {
6262
const sorted = ranges.sort(compareRanges);
6363
return sorted[sorted.length - 1]; // Range with highest precedence will be sorted to end of list.
6464
}
65+
66+
// Example input: ['1.5.0', '^1.0.0'], output: '^1.5.0'
67+
export function getIncreasedLatestVersion(versions: string[]): string {
68+
const latestVersion = getLatestVersion(versions);
69+
const latestVersionBare = semver.coerce(latestVersion);
70+
71+
let result = latestVersion;
72+
let resultBare = latestVersionBare;
73+
for (const version of versions) {
74+
if (version === latestVersion) {
75+
continue;
76+
}
77+
78+
const versionBare = semver.coerce(version);
79+
80+
if (
81+
latestVersionBare &&
82+
semver.satisfies(latestVersionBare, version) &&
83+
versionBare &&
84+
semver.gt(latestVersionBare, versionBare) &&
85+
resultBare
86+
) {
87+
result = version.replace(String(versionBare), String(resultBare));
88+
resultBare = semver.coerce(result);
89+
}
90+
}
91+
92+
return result;
93+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"workspaces": [
3+
"*"
4+
],
5+
"devDependencies": {
6+
"foo": "^1.0.0"
7+
}
8+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"name": "package1",
3+
"dependencies": {
4+
"foo": "1.5.0"
5+
}
6+
}

test/fixtures/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,7 @@ export const FIXTURE_PATH_INCONSISTENT_LOCAL_PACKAGE_VERSION = join(
4444
FIXTURE_PATH,
4545
'inconsistent-local-package-version'
4646
);
47+
export const FIXTURE_PATH_INCREASABLE_RANGE = join(
48+
FIXTURE_PATH,
49+
'increasable-range'
50+
);

test/lib/dependency-versions-test.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,5 +684,64 @@ describe('Utils | dependency-versions', function () {
684684
]);
685685
});
686686
});
687+
688+
describe('increasable range', function () {
689+
beforeEach(function () {
690+
// Create a mock workspace filesystem for temporary usage in this test because changes will be written to some files.
691+
mockFs({
692+
'package.json': JSON.stringify({
693+
workspaces: ['*'],
694+
}),
695+
package1: {
696+
'package.json': JSON.stringify({
697+
name: 'package1',
698+
dependencies: {
699+
foo: '^1.0.0',
700+
},
701+
}),
702+
},
703+
package2: {
704+
'package.json': JSON.stringify({
705+
name: 'package2',
706+
dependencies: {
707+
foo: '1.5.0',
708+
},
709+
}),
710+
},
711+
});
712+
});
713+
714+
afterEach(function () {
715+
mockFs.restore();
716+
});
717+
718+
it('increases the range', function () {
719+
const packages = getPackagesHelper('.');
720+
const mismatchingVersions = calculateMismatchingVersions(
721+
calculateVersionsForEachDependency(packages)
722+
);
723+
fixMismatchingVersions(packages, mismatchingVersions);
724+
725+
// Read in package.json files.
726+
const packageJson1Contents = readFileSync(
727+
'package1/package.json',
728+
'utf-8'
729+
);
730+
const packageJson2Contents = readFileSync(
731+
'package2/package.json',
732+
'utf-8'
733+
);
734+
const packageJson1: PackageJson = JSON.parse(packageJson1Contents);
735+
const packageJson2: PackageJson = JSON.parse(packageJson2Contents);
736+
737+
expect(
738+
packageJson1.dependencies && packageJson1.dependencies['foo']
739+
).toStrictEqual('^1.5.0');
740+
741+
expect(
742+
packageJson2.dependencies && packageJson2.dependencies['foo']
743+
).toStrictEqual('^1.5.0');
744+
});
745+
});
687746
});
688747
});

test/lib/output-test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { getPackages } from '../../lib/workspace.js';
1010
import {
1111
FIXTURE_PATH_TESTING_OUTPUT,
1212
FIXTURE_PATH_NAMES_NOT_MATCHING_LOCATIONS,
13+
FIXTURE_PATH_INCREASABLE_RANGE,
1314
} from '../fixtures/index.js';
1415

1516
describe('Utils | output', function () {
@@ -123,6 +124,18 @@ describe('Utils | output', function () {
123124
).toMatchInlineSnapshot('"Fixed versions for 1 dependency: [email protected]"');
124125
});
125126

127+
it('behaves correctly with an increasable range', function () {
128+
expect(
129+
mismatchingVersionsFixedToOutput(
130+
calculateMismatchingVersions(
131+
calculateVersionsForEachDependency(
132+
getPackages(FIXTURE_PATH_INCREASABLE_RANGE, [], [], [], [])
133+
)
134+
).slice(0, 1)
135+
)
136+
).toMatchInlineSnapshot('"Fixed versions for 1 dependency: foo@^1.5.0"');
137+
});
138+
126139
it('behaves correctly with empty input', function () {
127140
expect(() =>
128141
mismatchingVersionsFixedToOutput([])

test/lib/semver-test.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
versionRangeToRange,
66
getLatestVersion,
77
getHighestRangeType,
8+
getIncreasedLatestVersion,
89
} from '../../lib/semver.js';
910

1011
describe('Utils | semver', function () {
@@ -112,4 +113,58 @@ describe('Utils | semver', function () {
112113
expect(getHighestRangeType(['^', '~'])).toStrictEqual('^');
113114
});
114115
});
116+
117+
describe('#getIncreasedLatestVersion', function () {
118+
it('behaves correctly', function () {
119+
// ^
120+
expect(getIncreasedLatestVersion(['^1.0.0', '1.5.0'])).toStrictEqual(
121+
'^1.5.0'
122+
);
123+
expect(getIncreasedLatestVersion(['1.5.0', '^1.0.0'])).toStrictEqual(
124+
'^1.5.0'
125+
);
126+
expect(getIncreasedLatestVersion(['^0.4.0', '^0.4.5'])).toStrictEqual(
127+
'^0.4.5'
128+
);
129+
expect(getIncreasedLatestVersion(['^0.4.0', '0.5.0'])).toStrictEqual(
130+
'0.5.0'
131+
);
132+
expect(getIncreasedLatestVersion(['^1.0.0', '2.0.0'])).toStrictEqual(
133+
'2.0.0'
134+
);
135+
expect(getIncreasedLatestVersion(['^1.0.0', '^1.0.0'])).toStrictEqual(
136+
'^1.0.0'
137+
);
138+
139+
// ^ ~
140+
expect(getIncreasedLatestVersion(['~1.5.0', '^1.0.0'])).toStrictEqual(
141+
'^1.5.0'
142+
);
143+
expect(getIncreasedLatestVersion(['~1.5.0', '^2.0.0'])).toStrictEqual(
144+
'^2.0.0'
145+
);
146+
expect(getIncreasedLatestVersion(['~2.0.0', '^1.5.0'])).toStrictEqual(
147+
'~2.0.0'
148+
);
149+
150+
// ~
151+
expect(getIncreasedLatestVersion(['~1.4.0', '1.4.5'])).toStrictEqual(
152+
'~1.4.5'
153+
);
154+
expect(getIncreasedLatestVersion(['~1.4.0', '~1.5.0'])).toStrictEqual(
155+
'~1.5.0'
156+
);
157+
expect(getIncreasedLatestVersion(['~1.0.0', '~1.0.0'])).toStrictEqual(
158+
'~1.0.0'
159+
);
160+
161+
// no range
162+
expect(getIncreasedLatestVersion(['1.5.0', '1.0.0'])).toStrictEqual(
163+
'1.5.0'
164+
);
165+
expect(getIncreasedLatestVersion(['1.0.0', '1.0.0'])).toStrictEqual(
166+
'1.0.0'
167+
);
168+
});
169+
});
115170
});

0 commit comments

Comments
 (0)