diff --git a/lib/dependency-versions.ts b/lib/dependency-versions.ts index 27562c1e..da734e08 100644 --- a/lib/dependency-versions.ts +++ b/lib/dependency-versions.ts @@ -93,6 +93,19 @@ function recordDependencyVersionsForPackageJson( ); } } + + if (package_.packageJson.resolutions) { + for (const [dependency, dependencyVersion] of Object.entries( + package_.packageJson.resolutions + )) { + recordDependencyVersion( + dependenciesToVersionsSeen, + dependency, + dependencyVersion, + package_ + ); + } + } } function recordDependencyVersion( @@ -235,7 +248,7 @@ export function filterOutIgnoredDependencies( function writeDependencyVersion( packageJsonPath: string, packageJsonEndsInNewline: boolean, - isDependency: boolean, // true for dependency, false for dev-dependency. + type: 'dependencies' | 'devDependencies' | 'resolutions', dependencyName: string, newVersion: string ) { @@ -245,9 +258,7 @@ function writeDependencyVersion( }); packageJsonEditor.set( - `${ - isDependency ? 'dependencies' : 'devDependencies' - }.${dependencyName.replace( + `${type}.${dependencyName.replace( /\./g, // Escape dots to avoid creating unwanted nested properties. '\\.' )}`, @@ -314,7 +325,7 @@ export function fixMismatchingVersions( writeDependencyVersion( package_.pathPackageJson, package_.packageJsonEndsInNewline, - false, + 'devDependencies', mismatchingVersion.dependency, fixedVersion ); @@ -330,7 +341,23 @@ export function fixMismatchingVersions( writeDependencyVersion( package_.pathPackageJson, package_.packageJsonEndsInNewline, - true, + 'dependencies', + mismatchingVersion.dependency, + fixedVersion + ); + isFixed = true; + } + + if ( + package_.packageJson.resolutions && + package_.packageJson.resolutions[mismatchingVersion.dependency] && + package_.packageJson.resolutions[mismatchingVersion.dependency] !== + fixedVersion + ) { + writeDependencyVersion( + package_.pathPackageJson, + package_.packageJsonEndsInNewline, + 'resolutions', mismatchingVersion.dependency, fixedVersion ); diff --git a/test/fixtures/index.ts b/test/fixtures/index.ts index 77bf78eb..86d5a692 100644 --- a/test/fixtures/index.ts +++ b/test/fixtures/index.ts @@ -48,18 +48,16 @@ export const FIXTURE_PATH_INCREASABLE_RANGE = join( FIXTURE_PATH, 'increasable-range' ); - export const FIXTURE_PATH_VALID_WITH_PACKAGES = join( FIXTURE_PATH, 'valid-with-packages' ); - export const FIXTURE_PATH_WORKSPACE_PACKAGE_NOT_AN_ARRAY = join( FIXTURE_PATH, 'workspace-packages-not-an-array' ); - export const FIXTURE_PATH_NESTED_WORKSPACES = join( FIXTURE_PATH, 'nested-workspaces' ); +export const FIXTURE_PATH_RESOLUTIONS = join(FIXTURE_PATH, 'resolutions'); diff --git a/test/fixtures/resolutions/package.json b/test/fixtures/resolutions/package.json new file mode 100644 index 00000000..bcd8b46a --- /dev/null +++ b/test/fixtures/resolutions/package.json @@ -0,0 +1,12 @@ +{ + "workspaces": [ + "*" + ], + "devDependencies": { + "foo": "^1.2.0" + }, + "resolutions": { + "foo": "^2.0.0", + "bar": "^1.0.0" + } +} diff --git a/test/fixtures/resolutions/package1/package.json b/test/fixtures/resolutions/package1/package.json new file mode 100644 index 00000000..9a6bad6c --- /dev/null +++ b/test/fixtures/resolutions/package1/package.json @@ -0,0 +1,7 @@ +{ + "name": "package1", + "dependencies": { + "foo": "1.3.0", + "bar": "^1.0.0" + } +} diff --git a/test/lib/dependency-versions-test.ts b/test/lib/dependency-versions-test.ts index 8cfde863..1354729c 100644 --- a/test/lib/dependency-versions-test.ts +++ b/test/lib/dependency-versions-test.ts @@ -12,6 +12,7 @@ import { FIXTURE_PATH_NO_DEPENDENCIES, FIXTURE_PATH_PACKAGE_MISSING_PACKAGE_JSON, FIXTURE_PATH_INCONSISTENT_LOCAL_PACKAGE_VERSION, + FIXTURE_PATH_RESOLUTIONS, } from '../fixtures/index.js'; import mockFs from 'mock-fs'; import { readFileSync } from 'node:fs'; @@ -170,6 +171,43 @@ describe('Utils | dependency-versions', function () { }, ]); }); + + it('has mismatches with resolutions', function () { + const dependencyVersions = calculateVersionsForEachDependency( + getPackagesHelper(FIXTURE_PATH_RESOLUTIONS) + ); + expect(calculateMismatchingVersions(dependencyVersions)).toStrictEqual([ + { + dependency: 'foo', + versions: [ + { + version: '^1.2.0', + packages: [ + expect.objectContaining({ + path: FIXTURE_PATH_RESOLUTIONS, + }), + ], + }, + { + version: '1.3.0', + packages: [ + expect.objectContaining({ + path: join(FIXTURE_PATH_RESOLUTIONS, 'package1'), + }), + ], + }, + { + version: '^2.0.0', + packages: [ + expect.objectContaining({ + path: FIXTURE_PATH_RESOLUTIONS, + }), + ], + }, + ], + }, + ]); + }); }); describe('#filterOutIgnoredDependencies', function () { @@ -685,6 +723,106 @@ describe('Utils | dependency-versions', function () { }); }); + describe('resolutions', function () { + beforeEach(function () { + // Create a mock workspace filesystem for temporary usage in this test because changes will be written to some files. + mockFs({ + 'package.json': JSON.stringify({ + workspaces: ['*'], + devDependencies: { + foo: '^1.2.0', + }, + resolutions: { + foo: '^1.0.0', + bar: '^1.0.0', + }, + }), + package1: { + 'package.json': JSON.stringify({ + name: 'package1', + dependencies: { + foo: '^2.0.0', + bar: '^1.0.0', + }, + }), + }, + }); + }); + + afterEach(function () { + mockFs.restore(); + }); + + it('fixes the fixable inconsistencies', function () { + const packages = getPackagesHelper('.'); + const mismatchingVersions = calculateMismatchingVersions( + calculateVersionsForEachDependency(packages) + ); + const { fixed, notFixed } = fixMismatchingVersions( + packages, + mismatchingVersions + ); + + // Read in package.json files. + const packageJsonRootContents = readFileSync('package.json', 'utf8'); + const packageJson1Contents = readFileSync( + 'package1/package.json', + 'utf8' + ); + const packageJsonRoot: PackageJson = JSON.parse( + packageJsonRootContents + ); + const packageJson1: PackageJson = JSON.parse(packageJson1Contents); + + expect( + packageJsonRoot.devDependencies && + packageJsonRoot.devDependencies['foo'] + ).toStrictEqual('^2.0.0'); + + expect( + packageJsonRoot.resolutions && packageJsonRoot.resolutions['foo'] + ).toStrictEqual('^2.0.0'); + + expect( + packageJson1.dependencies && packageJson1.dependencies['foo'] + ).toStrictEqual('^2.0.0'); + + expect(notFixed).toStrictEqual([]); + + expect(fixed).toStrictEqual([ + { + dependency: 'foo', + versions: [ + { + version: '^1.0.0', + packages: [ + expect.objectContaining({ + path: '.', + }), + ], + }, + { + version: '^1.2.0', + packages: [ + expect.objectContaining({ + path: '.', + }), + ], + }, + { + version: '^2.0.0', + packages: [ + expect.objectContaining({ + path: 'package1', + }), + ], + }, + ], + }, + ]); + }); + }); + describe('increasable range', function () { beforeEach(function () { // Create a mock workspace filesystem for temporary usage in this test because changes will be written to some files.