diff --git a/src/lib/getIgnoredUpgrades.ts b/src/lib/getIgnoredUpgrades.ts index f46cd6a2..90d74f9c 100644 --- a/src/lib/getIgnoredUpgrades.ts +++ b/src/lib/getIgnoredUpgrades.ts @@ -1,9 +1,10 @@ -import { satisfies } from 'semver' +import semver, { satisfies } from 'semver' import { IgnoredUpgrade } from '../types/IgnoredUpgrade' import { Index } from '../types/IndexType' import { Options } from '../types/Options' import { Version } from '../types/Version' import { VersionSpec } from '../types/VersionSpec' +import getPeerDependenciesFromRegistry from './getPeerDependenciesFromRegistry' import upgradePackageDefinitions from './upgradePackageDefinitions' /** Get all upgrades that are ignored due to incompatible peer dependencies. */ @@ -13,36 +14,54 @@ export async function getIgnoredUpgrades( upgradedPeerDependencies: Index>, options: Options = {}, ) { + const upgradedPackagesWithPeerRestriction = Object.fromEntries( + Object.entries({ + ...current, + ...upgraded, + }).map(([packageName, versionSpec]) => { + return [packageName, semver.minVersion(versionSpec)?.version ?? versionSpec] + }), + ) const [upgradedLatestVersions, latestVersionResults] = await upgradePackageDefinitions(current, { ...options, peer: false, peerDependencies: undefined, loglevel: 'silent', }) - + const upgradedPeerDependenciesLatest = await getPeerDependenciesFromRegistry(upgradedLatestVersions, options) return Object.entries(upgradedLatestVersions) .filter(([pkgName, newVersion]) => upgraded[pkgName] !== newVersion) - .reduce( - (accum, [pkgName, newVersion]) => ({ + .reduce((accum, [pkgName, newVersion]) => { + let reason = Object.entries(upgradedPeerDependencies) + .filter( + ([, peers]) => + peers[pkgName] !== undefined && + latestVersionResults[pkgName]?.version && + !satisfies(latestVersionResults[pkgName].version!, peers[pkgName]), + ) + .reduce((accumReason, [peerPkg, peers]) => ({ ...accumReason, [peerPkg]: peers[pkgName] }), {} as Index) + if (Object.keys(reason).length === 0) { + const peersOfPkg = upgradedPeerDependenciesLatest?.[pkgName] || {} + reason = Object.entries(peersOfPkg) + .filter( + ([peer, peerSpec]) => + upgradedPackagesWithPeerRestriction[peer] && + !satisfies(upgradedPackagesWithPeerRestriction[peer], peerSpec), + ) + .reduce( + (accumReason, [peerPkg, peerSpec]) => ({ ...accumReason, [pkgName]: `${peerPkg} ${peerSpec}` }), + {} as Index, + ) + } + return { ...accum, [pkgName]: { from: current[pkgName], to: newVersion, - reason: Object.entries(upgradedPeerDependencies) - .filter( - ([, peers]) => - peers[pkgName] !== undefined && - latestVersionResults[pkgName]?.version && - !satisfies(latestVersionResults[pkgName].version!, peers[pkgName]), - ) - .reduce( - (accumReason, [peerPkg, peers]) => ({ ...accumReason, [peerPkg]: peers[pkgName] }), - {} as Index, - ), + reason, }, - }), - {} as Index, - ) + } + }, {} as Index) } export default getIgnoredUpgrades diff --git a/test/peer.test.ts b/test/peer.test.ts index 1cfed6e4..af80d283 100644 --- a/test/peer.test.ts +++ b/test/peer.test.ts @@ -45,6 +45,6 @@ describe('peer dependencies', function () { return packageName === 'eslint-plugin-unused-imports' ? 'latest' : 'minor' }, }) - upgrades!.should.contain.keys('@vitest/ui', 'vitest') + upgrades!.should.have.all.keys('@vitest/ui', 'vitest') }) })