Skip to content

Commit 2a47867

Browse files
clemyanarcanis
andauthored
Fix peer warning message requester (#6376)
## What's the problem this PR addresses? When an incompatible peer warning occurs, the warning message shown during install simply uses the first peer requester found but that may not have any relation to the unsatisfied request. See #6205 (comment) (partial fix) ## How did you fix it? Actually find the first unsatisfied requester, prioritizing root requesters (i.e. direct dependencies). If an unsatisfied root requester is found, the warning message looks similar to 4.2.2 ![image](https://github.com/yarnpkg/berry/assets/41266433/08a3b91e-ed03-4002-9f60-e982a8d7189b) ``` ➤ YN0000: ┌ Post-resolution validation ➤ YN0060: │ react is listed by your project with version 18.3.1 (pfa021), which doesn't satisfy what reflux and other dependencies request (but they have non-overlapping ranges!). ➤ YN0086: │ Some peer dependencies are incorrectly met by your project; run yarn explain peer-requirements <hash> for details, where <hash> is the six-letter p-prefixed code. ➤ YN0000: └ Completed ``` If all root requesters are satisfied, then an unsatisfied requester is found and reported with one of the corresponding root requesters ![image](https://github.com/yarnpkg/berry/assets/41266433/753f7b94-2151-47b0-ac04-69621de8e355) ``` ➤ YN0000: ┌ Post-resolution validation ➤ YN0060: │ react is listed by your project with version 18.3.1 (pfa021), which doesn't satisfy what reflux (via @local/test-reflux-dependent) and other dependencies request (but they have non-overlapping ranges!). ➤ YN0086: │ Some peer dependencies are incorrectly met by your project; run yarn explain peer-requirements <hash> for details, where <hash> is the six-letter p-prefixed code. ➤ YN0000: └ Completed ``` One concern I had was that it will make the message longer, but we are already way past the common terminal width so I don't think that's a big issue. ## Checklist <!--- Don't worry if you miss something, chores are automatically tested. --> <!--- This checklist exists to help you remember doing the chores when you submit a PR. --> <!--- Put an `x` in all the boxes that apply. --> - [x] I have read the [Contributing Guide](https://yarnpkg.com/advanced/contributing). <!-- See https://yarnpkg.com/advanced/contributing#preparing-your-pr-to-be-released for more details. --> <!-- Check with `yarn version check` and fix with `yarn version check -i` --> - [x] I have set the packages that need to be released for my changes to be effective. <!-- The "Testing chores" workflow validates that your PR follows our guidelines. --> <!-- If it doesn't pass, click on it to see details as to what your PR might be missing. --> - [x] I will check that all automated PR checks pass before the PR gets reviewed. --------- Co-authored-by: Maël Nison <[email protected]>
1 parent 9daddcf commit 2a47867

File tree

3 files changed

+83
-5
lines changed

3 files changed

+83
-5
lines changed

.yarn/versions/db8fe3a1.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
releases:
2+
"@yarnpkg/cli": patch
3+
"@yarnpkg/core": patch
4+
5+
declined:
6+
- "@yarnpkg/plugin-compat"
7+
- "@yarnpkg/plugin-constraints"
8+
- "@yarnpkg/plugin-dlx"
9+
- "@yarnpkg/plugin-essentials"
10+
- "@yarnpkg/plugin-exec"
11+
- "@yarnpkg/plugin-file"
12+
- "@yarnpkg/plugin-git"
13+
- "@yarnpkg/plugin-github"
14+
- "@yarnpkg/plugin-http"
15+
- "@yarnpkg/plugin-init"
16+
- "@yarnpkg/plugin-interactive-tools"
17+
- "@yarnpkg/plugin-link"
18+
- "@yarnpkg/plugin-nm"
19+
- "@yarnpkg/plugin-npm"
20+
- "@yarnpkg/plugin-npm-cli"
21+
- "@yarnpkg/plugin-pack"
22+
- "@yarnpkg/plugin-patch"
23+
- "@yarnpkg/plugin-pnp"
24+
- "@yarnpkg/plugin-pnpm"
25+
- "@yarnpkg/plugin-stage"
26+
- "@yarnpkg/plugin-typescript"
27+
- "@yarnpkg/plugin-version"
28+
- "@yarnpkg/plugin-workspace-tools"
29+
- "@yarnpkg/builder"
30+
- "@yarnpkg/doctor"
31+
- "@yarnpkg/extensions"
32+
- "@yarnpkg/nm"
33+
- "@yarnpkg/pnpify"
34+
- "@yarnpkg/sdks"

packages/acceptance-tests/pkg-tests-specs/sources/features/peerDependenciesMeta.test.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,24 @@ describe(`Features`, () => {
2929
);
3030

3131
test(
32-
`it should report collapsed a peer dependency warning when a set of mismatched peerDependency requirements is detected`,
32+
`it should report collapsed a peer dependency warning when a direct peerDependency request is mismatched`,
33+
makeTemporaryEnv(
34+
{
35+
dependencies: {
36+
[`mismatched-peer-deps-lvl1`]: `1.0.0`,
37+
[`no-deps`]: `1.1.0`,
38+
},
39+
},
40+
async ({path, run, source}) => {
41+
const {stdout} = await run(`install`);
42+
43+
expect(stdout).toMatch(/no-deps is listed by your project with version 1\.1\.0 \(p[a-f0-9]{5}\), which doesn't satisfy what mismatched-peer-deps-lvl1 and other dependencies request \(1\.0\.0\)/);
44+
},
45+
),
46+
);
47+
48+
test(
49+
`it should report collapsed a peer dependency warning with corresponding root when a transitive peerDependency request is mismatched`,
3350
makeTemporaryEnv(
3451
{
3552
dependencies: {
@@ -40,7 +57,7 @@ describe(`Features`, () => {
4057
async ({path, run, source}) => {
4158
const {stdout} = await run(`install`);
4259

43-
expect(stdout).toMatch(/no-deps is listed by your project with version 1\.1\.0 \(p[a-f0-9]{5}\), which doesn't satisfy what mismatched-peer-deps-lvl0 and other dependencies request \(1\.0\.0\)/);
60+
expect(stdout).toMatch(/no-deps is listed by your project with version 1\.1\.0 \(p[a-f0-9]{5}\), which doesn't satisfy what mismatched-peer-deps-lvl[12] \(via mismatched-peer-deps-lvl0\) and other dependencies request \(1\.0\.0\)/);
4461
},
4562
),
4663
);

packages/yarnpkg-core/sources/Project.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2678,6 +2678,27 @@ function applyVirtualResolutionMutations({
26782678
}
26792679
}
26802680

2681+
function * allPeerRequestsWithRoot(root: PeerRequestNode | PeerRequirementNode) {
2682+
const roots = new Map<PeerRequestNode, PeerRequestNode>();
2683+
2684+
if (`children` in root) {
2685+
roots.set(root, root);
2686+
} else {
2687+
for (const request of root.requests.values()) {
2688+
roots.set(request, request);
2689+
}
2690+
}
2691+
2692+
for (const [request, root] of roots) {
2693+
yield {request, root};
2694+
for (const child of request.children.values()) {
2695+
if (!roots.has(child)) {
2696+
roots.set(child, root);
2697+
}
2698+
}
2699+
}
2700+
}
2701+
26812702
function emitPeerDependencyWarnings(project: Project, report: Report) {
26822703
const incompatibleWarnings: Array<string> = [];
26832704
const missingWarnings: Array<string> = [];
@@ -2701,6 +2722,14 @@ function emitPeerDependencyWarnings(project: Project, report: Report) {
27012722
if (typeof peerPackage === `undefined`)
27022723
throw new Error(`Assertion failed: Expected the package to be registered`);
27032724

2725+
const requester = miscUtils.mapAndFind(allPeerRequestsWithRoot(warning.node), ({request, root}) => {
2726+
if (!semverUtils.satisfiesWithPrereleases(peerPackage.version ?? `0.0.0`, request.descriptor.range))
2727+
return request === root
2728+
? structUtils.prettyIdent(project.configuration, request.requester)
2729+
: `${structUtils.prettyIdent(project.configuration, request.requester)} (via ${structUtils.prettyIdent(project.configuration, root.requester)})`;
2730+
2731+
return miscUtils.mapAndFind.skip;
2732+
});
27042733
const otherPackages = [...structUtils.allPeerRequests(warning.node)].length > 1
27052734
? `and other dependencies request`
27062735
: `requests`;
@@ -2715,9 +2744,7 @@ function emitPeerDependencyWarnings(project: Project, report: Report) {
27152744
structUtils.prettyReference(project.configuration, peerPackage.version ?? `0.0.0`)
27162745
} (${
27172746
formatUtils.pretty(project.configuration, warning.hash, formatUtils.Type.CODE)
2718-
}), which doesn't satisfy what ${
2719-
structUtils.prettyIdent(project.configuration, warning.node.requests.values().next().value.requester)
2720-
} ${otherPackages} (${rangeDescription}).`);
2747+
}), which doesn't satisfy what ${requester} ${otherPackages} (${rangeDescription}).`);
27212748
}
27222749

27232750
if (warning.type === PeerWarningType.NodeNotProvided) {

0 commit comments

Comments
 (0)