Skip to content

Commit 48d5cbe

Browse files
authored
Backport "Prevent Infinite Loop in OverlappingFieldsCanBeMergedRule" to v15 (#4000)
fix from #3442
1 parent 12e30ad commit 48d5cbe

File tree

2 files changed

+63
-0
lines changed

2 files changed

+63
-0
lines changed

src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,18 +1011,63 @@ describe('Validate: Overlapping fields can be merged', () => {
10111011

10121012
it('does not infinite loop on recursive fragment', () => {
10131013
expectValid(`
1014+
{
1015+
...fragA
1016+
}
1017+
10141018
fragment fragA on Human { name, relatives { name, ...fragA } }
10151019
`);
10161020
});
10171021

10181022
it('does not infinite loop on immediately recursive fragment', () => {
10191023
expectValid(`
1024+
{
1025+
...fragA
1026+
}
1027+
10201028
fragment fragA on Human { name, ...fragA }
10211029
`);
10221030
});
10231031

1032+
it('does not infinite loop on recursive fragment with a field named after fragment', () => {
1033+
expectValid(`
1034+
{
1035+
...fragA
1036+
fragA
1037+
}
1038+
fragment fragA on Query { ...fragA }
1039+
`);
1040+
});
1041+
1042+
it('finds invalid cases even with field named after fragment', () => {
1043+
expectErrors(`
1044+
{
1045+
fragA
1046+
...fragA
1047+
}
1048+
1049+
fragment fragA on Type {
1050+
fragA: b
1051+
}
1052+
`).to.deep.equal([
1053+
{
1054+
message:
1055+
'Fields "fragA" conflict because "fragA" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.',
1056+
locations: [
1057+
{ line: 3, column: 9 },
1058+
{ line: 8, column: 9 },
1059+
],
1060+
},
1061+
]);
1062+
});
1063+
10241064
it('does not infinite loop on transitively recursive fragment', () => {
10251065
expectValid(`
1066+
{
1067+
...fragA
1068+
fragB
1069+
}
1070+
10261071
fragment fragA on Human { name, ...fragB }
10271072
fragment fragB on Human { name, ...fragC }
10281073
fragment fragC on Human { name, ...fragA }

src/validation/rules/OverlappingFieldsCanBeMergedRule.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,24 @@ function collectConflictsBetweenFieldsAndFragment(
264264
// (E) Then collect any conflicts between the provided collection of fields
265265
// and any fragment names found in the given fragment.
266266
for (let i = 0; i < fragmentNames2.length; i++) {
267+
const referencedFragmentName = fragmentNames2[i];
268+
269+
// Memoize so two fragments are not compared for conflicts more than once.
270+
if (
271+
comparedFragmentPairs.has(
272+
referencedFragmentName,
273+
fragmentName,
274+
areMutuallyExclusive,
275+
)
276+
) {
277+
continue;
278+
}
279+
comparedFragmentPairs.add(
280+
referencedFragmentName,
281+
fragmentName,
282+
areMutuallyExclusive,
283+
);
284+
267285
collectConflictsBetweenFieldsAndFragment(
268286
context,
269287
conflicts,

0 commit comments

Comments
 (0)