Skip to content

Commit ef2aa44

Browse files
authored
feat: check resolutions for inconsistencies (#348)
1 parent 07e78f3 commit ef2aa44

File tree

5 files changed

+191
-9
lines changed

5 files changed

+191
-9
lines changed

lib/dependency-versions.ts

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,19 @@ function recordDependencyVersionsForPackageJson(
9393
);
9494
}
9595
}
96+
97+
if (package_.packageJson.resolutions) {
98+
for (const [dependency, dependencyVersion] of Object.entries(
99+
package_.packageJson.resolutions
100+
)) {
101+
recordDependencyVersion(
102+
dependenciesToVersionsSeen,
103+
dependency,
104+
dependencyVersion,
105+
package_
106+
);
107+
}
108+
}
96109
}
97110

98111
function recordDependencyVersion(
@@ -235,7 +248,7 @@ export function filterOutIgnoredDependencies(
235248
function writeDependencyVersion(
236249
packageJsonPath: string,
237250
packageJsonEndsInNewline: boolean,
238-
isDependency: boolean, // true for dependency, false for dev-dependency.
251+
type: 'dependencies' | 'devDependencies' | 'resolutions',
239252
dependencyName: string,
240253
newVersion: string
241254
) {
@@ -245,9 +258,7 @@ function writeDependencyVersion(
245258
});
246259

247260
packageJsonEditor.set(
248-
`${
249-
isDependency ? 'dependencies' : 'devDependencies'
250-
}.${dependencyName.replace(
261+
`${type}.${dependencyName.replace(
251262
/\./g, // Escape dots to avoid creating unwanted nested properties.
252263
'\\.'
253264
)}`,
@@ -314,7 +325,7 @@ export function fixMismatchingVersions(
314325
writeDependencyVersion(
315326
package_.pathPackageJson,
316327
package_.packageJsonEndsInNewline,
317-
false,
328+
'devDependencies',
318329
mismatchingVersion.dependency,
319330
fixedVersion
320331
);
@@ -330,7 +341,23 @@ export function fixMismatchingVersions(
330341
writeDependencyVersion(
331342
package_.pathPackageJson,
332343
package_.packageJsonEndsInNewline,
333-
true,
344+
'dependencies',
345+
mismatchingVersion.dependency,
346+
fixedVersion
347+
);
348+
isFixed = true;
349+
}
350+
351+
if (
352+
package_.packageJson.resolutions &&
353+
package_.packageJson.resolutions[mismatchingVersion.dependency] &&
354+
package_.packageJson.resolutions[mismatchingVersion.dependency] !==
355+
fixedVersion
356+
) {
357+
writeDependencyVersion(
358+
package_.pathPackageJson,
359+
package_.packageJsonEndsInNewline,
360+
'resolutions',
334361
mismatchingVersion.dependency,
335362
fixedVersion
336363
);

test/fixtures/index.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,16 @@ export const FIXTURE_PATH_INCREASABLE_RANGE = join(
4848
FIXTURE_PATH,
4949
'increasable-range'
5050
);
51-
5251
export const FIXTURE_PATH_VALID_WITH_PACKAGES = join(
5352
FIXTURE_PATH,
5453
'valid-with-packages'
5554
);
56-
5755
export const FIXTURE_PATH_WORKSPACE_PACKAGE_NOT_AN_ARRAY = join(
5856
FIXTURE_PATH,
5957
'workspace-packages-not-an-array'
6058
);
61-
6259
export const FIXTURE_PATH_NESTED_WORKSPACES = join(
6360
FIXTURE_PATH,
6461
'nested-workspaces'
6562
);
63+
export const FIXTURE_PATH_RESOLUTIONS = join(FIXTURE_PATH, 'resolutions');
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"workspaces": [
3+
"*"
4+
],
5+
"devDependencies": {
6+
"foo": "^1.2.0"
7+
},
8+
"resolutions": {
9+
"foo": "^2.0.0",
10+
"bar": "^1.0.0"
11+
}
12+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "package1",
3+
"dependencies": {
4+
"foo": "1.3.0",
5+
"bar": "^1.0.0"
6+
}
7+
}

test/lib/dependency-versions-test.ts

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
FIXTURE_PATH_NO_DEPENDENCIES,
1313
FIXTURE_PATH_PACKAGE_MISSING_PACKAGE_JSON,
1414
FIXTURE_PATH_INCONSISTENT_LOCAL_PACKAGE_VERSION,
15+
FIXTURE_PATH_RESOLUTIONS,
1516
} from '../fixtures/index.js';
1617
import mockFs from 'mock-fs';
1718
import { readFileSync } from 'node:fs';
@@ -170,6 +171,43 @@ describe('Utils | dependency-versions', function () {
170171
},
171172
]);
172173
});
174+
175+
it('has mismatches with resolutions', function () {
176+
const dependencyVersions = calculateVersionsForEachDependency(
177+
getPackagesHelper(FIXTURE_PATH_RESOLUTIONS)
178+
);
179+
expect(calculateMismatchingVersions(dependencyVersions)).toStrictEqual([
180+
{
181+
dependency: 'foo',
182+
versions: [
183+
{
184+
version: '^1.2.0',
185+
packages: [
186+
expect.objectContaining({
187+
path: FIXTURE_PATH_RESOLUTIONS,
188+
}),
189+
],
190+
},
191+
{
192+
version: '1.3.0',
193+
packages: [
194+
expect.objectContaining({
195+
path: join(FIXTURE_PATH_RESOLUTIONS, 'package1'),
196+
}),
197+
],
198+
},
199+
{
200+
version: '^2.0.0',
201+
packages: [
202+
expect.objectContaining({
203+
path: FIXTURE_PATH_RESOLUTIONS,
204+
}),
205+
],
206+
},
207+
],
208+
},
209+
]);
210+
});
173211
});
174212

175213
describe('#filterOutIgnoredDependencies', function () {
@@ -685,6 +723,106 @@ describe('Utils | dependency-versions', function () {
685723
});
686724
});
687725

726+
describe('resolutions', function () {
727+
beforeEach(function () {
728+
// Create a mock workspace filesystem for temporary usage in this test because changes will be written to some files.
729+
mockFs({
730+
'package.json': JSON.stringify({
731+
workspaces: ['*'],
732+
devDependencies: {
733+
foo: '^1.2.0',
734+
},
735+
resolutions: {
736+
foo: '^1.0.0',
737+
bar: '^1.0.0',
738+
},
739+
}),
740+
package1: {
741+
'package.json': JSON.stringify({
742+
name: 'package1',
743+
dependencies: {
744+
foo: '^2.0.0',
745+
bar: '^1.0.0',
746+
},
747+
}),
748+
},
749+
});
750+
});
751+
752+
afterEach(function () {
753+
mockFs.restore();
754+
});
755+
756+
it('fixes the fixable inconsistencies', function () {
757+
const packages = getPackagesHelper('.');
758+
const mismatchingVersions = calculateMismatchingVersions(
759+
calculateVersionsForEachDependency(packages)
760+
);
761+
const { fixed, notFixed } = fixMismatchingVersions(
762+
packages,
763+
mismatchingVersions
764+
);
765+
766+
// Read in package.json files.
767+
const packageJsonRootContents = readFileSync('package.json', 'utf8');
768+
const packageJson1Contents = readFileSync(
769+
'package1/package.json',
770+
'utf8'
771+
);
772+
const packageJsonRoot: PackageJson = JSON.parse(
773+
packageJsonRootContents
774+
);
775+
const packageJson1: PackageJson = JSON.parse(packageJson1Contents);
776+
777+
expect(
778+
packageJsonRoot.devDependencies &&
779+
packageJsonRoot.devDependencies['foo']
780+
).toStrictEqual('^2.0.0');
781+
782+
expect(
783+
packageJsonRoot.resolutions && packageJsonRoot.resolutions['foo']
784+
).toStrictEqual('^2.0.0');
785+
786+
expect(
787+
packageJson1.dependencies && packageJson1.dependencies['foo']
788+
).toStrictEqual('^2.0.0');
789+
790+
expect(notFixed).toStrictEqual([]);
791+
792+
expect(fixed).toStrictEqual([
793+
{
794+
dependency: 'foo',
795+
versions: [
796+
{
797+
version: '^1.0.0',
798+
packages: [
799+
expect.objectContaining({
800+
path: '.',
801+
}),
802+
],
803+
},
804+
{
805+
version: '^1.2.0',
806+
packages: [
807+
expect.objectContaining({
808+
path: '.',
809+
}),
810+
],
811+
},
812+
{
813+
version: '^2.0.0',
814+
packages: [
815+
expect.objectContaining({
816+
path: 'package1',
817+
}),
818+
],
819+
},
820+
],
821+
},
822+
]);
823+
});
824+
});
825+
688826
describe('increasable range', function () {
689827
beforeEach(function () {
690828
// Create a mock workspace filesystem for temporary usage in this test because changes will be written to some files.

0 commit comments

Comments
 (0)