diff --git a/src/checks/checkDirectPeerDependencies.test.ts b/src/checks/checkDirectPeerDependencies.test.ts index 7e2d2a46..1f59ec6d 100644 --- a/src/checks/checkDirectPeerDependencies.test.ts +++ b/src/checks/checkDirectPeerDependencies.test.ts @@ -245,4 +245,32 @@ describe('checkDirectPeerDependencies', () => { false, ); }); + + it('should not report error when peer dependency is provided by another dependency', async () => { + await checkDirectPeerDependencies( + false, + { + name: 'test', + dependencies: { + 'some-lib-using-rollup': '1.0.0', + 'some-lib-providing-rollup': '1.0.0', + }, + }, + 'path', + jest + .fn() + .mockImplementationOnce(() => ({ + name: 'some-lib-providing-rollup', + dependencies: { rollup: '^1.0.0' }, + })) + .mockImplementationOnce(() => ({ + name: 'some-lib-using-rollup', + peerDependencies: { rollup: '^1.0.0' }, + })), + createOnlyWarnsForMappingCheck('test', []), + createOnlyWarnsForMappingCheck('test', []), + createReportError, + ); + expect(mockReportError).not.toHaveBeenCalled(); + }); }); diff --git a/src/checks/checkDirectPeerDependencies.ts b/src/checks/checkDirectPeerDependencies.ts index eafda446..fbaa72f1 100644 --- a/src/checks/checkDirectPeerDependencies.ts +++ b/src/checks/checkDirectPeerDependencies.ts @@ -47,28 +47,45 @@ export async function checkDirectPeerDependencies( ): Promise { const reportError = customCreateReportError('Peer Dependencies', pkgPathName); + const allDepPkgs: { + name: string; + type: RegularDependencyTypes; + pkg: PackageJson; + }[] = []; + const allDirectDependenciesDependencies: [string, string][] = []; + await Promise.all( regularDependencyTypes.map(async (depType) => { const dependencies = pkg[depType]; if (!dependencies) return; for (const depName of getKeys(dependencies)) { const depPkg = await getDependencyPackageJson(depName); + allDepPkgs.push({ name: depName, type: depType, pkg: depPkg }); - if (depPkg.peerDependencies) { - checkPeerDependencies( - pkg, - reportError, - depType, - getAllowedPeerInFromType(depType, isLibrary), - depPkg, - missingOnlyWarnsForCheck.createFor(depName), - invalidOnlyWarnsForCheck.createFor(depName), + if (depPkg.dependencies) { + allDirectDependenciesDependencies.push( + ...Object.entries(depPkg.dependencies), ); } } }), ); + for (const { name: depName, type: depType, pkg: depPkg } of allDepPkgs) { + if (depPkg.peerDependencies) { + checkPeerDependencies( + pkg, + reportError, + depType, + getAllowedPeerInFromType(depType, isLibrary), + allDirectDependenciesDependencies, + depPkg, + missingOnlyWarnsForCheck.createFor(depName), + invalidOnlyWarnsForCheck.createFor(depName), + ); + } + } + reportNotWarnedForMapping(reportError, missingOnlyWarnsForCheck); if (missingOnlyWarnsForCheck !== invalidOnlyWarnsForCheck) { reportNotWarnedForMapping(reportError, invalidOnlyWarnsForCheck); diff --git a/src/checks/checkPeerDependencies.ts b/src/checks/checkPeerDependencies.ts index 177803ea..04f889e7 100644 --- a/src/checks/checkPeerDependencies.ts +++ b/src/checks/checkPeerDependencies.ts @@ -8,6 +8,7 @@ export function checkPeerDependencies( reportError: ReportError, type: DependencyTypes, allowedPeerIn: DependencyTypes[], + providedDependencies: [string, string][], depPkg: PackageJson, missingOnlyWarnsForCheck: OnlyWarnsForCheck, invalidOnlyWarnsForCheck: OnlyWarnsForCheck, @@ -29,6 +30,17 @@ export function checkPeerDependencies( if (peerDependenciesMetaPeerDep?.optional) { continue; } + + // satisfied by another direct dependency + if ( + providedDependencies.some( + ([depName, depRange]) => + depName === peerDepName && semver.intersects(range, depRange), + ) + ) { + continue; + } + reportError( `Missing "${peerDepName}" peer dependency from "${depPkg.name}" in ${type}`, `it should satisfies "${range}" and be in ${allowedPeerIn.join(