From aadee2555714c4002ed2e21ae5c416b84af9a86f Mon Sep 17 00:00:00 2001 From: Arnav Mishra Date: Wed, 10 Mar 2021 15:08:24 -0800 Subject: [PATCH 1/2] Handle spread fragments for the required fields --- src/customGraphQLValidationRules.js | 24 ++++++++++++++++++++++++ test/validationRules/required-fields.js | 10 +--------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/customGraphQLValidationRules.js b/src/customGraphQLValidationRules.js index 0600bbab..030bf05d 100644 --- a/src/customGraphQLValidationRules.js +++ b/src/customGraphQLValidationRules.js @@ -18,6 +18,12 @@ function getFieldWasRequestedOnNode(node, field) { }); } +function getNodeHasSpreadFragment(node) { + return node.selectionSet.selections.some(n => { + return n.kind === "FragmentSpread" + }); +} + function fieldAvailableOnType(type, field) { if (!type) { return false; @@ -38,6 +44,12 @@ export function RequiredFields(context, options) { const type = context.getType(); if (fieldAvailableOnType(type, field)) { + // If there is a spread fragment, that spread fragment will already be checked for every field. + const nodeHasSpreadFragment = getNodeHasSpreadFragment(node); + if (nodeHasSpreadFragment) { + return + } + const fieldWasRequested = getFieldWasRequestedOnNode(node, field); if (!fieldWasRequested) { context.reportError( @@ -58,6 +70,12 @@ export function RequiredFields(context, options) { const type = context.getType(); if (fieldAvailableOnType(type, field)) { + // If there is a spread fragment, that spread fragment will already be checked for every field. + const nodeHasSpreadFragment = getNodeHasSpreadFragment(node); + if (nodeHasSpreadFragment) { + return + } + // First, check the selection set on this inline fragment if (node.selectionSet && getFieldWasRequestedOnNode(node, field)) { return true; @@ -118,6 +136,12 @@ export function RequiredFields(context, options) { requiredFields.forEach(field => { if (fieldAvailableOnType(def.type, field)) { + // If there is a spread fragment, that spread fragment will already be checked for every field. + const nodeHasSpreadFragment = getNodeHasSpreadFragment(node); + if (nodeHasSpreadFragment) { + return + } + const fieldWasRequested = getFieldWasRequestedOnNode(node, field); if (!fieldWasRequested) { context.reportError( diff --git a/test/validationRules/required-fields.js b/test/validationRules/required-fields.js index 5ba0118b..c9a62f12 100644 --- a/test/validationRules/required-fields.js +++ b/test/validationRules/required-fields.js @@ -18,6 +18,7 @@ const requiredFieldsTestCases = { "const x = gql`fragment Foo on FooBar { id, hello, foo }`", "const x = gql`fragment Id on Node { id ... on NodeA { fieldA } }`", "const x = gql`query { nodes { id ... on NodeA { fieldA } } }`", + "const x = gql`query { greetings { hello ...GreetingsFragment} }`" ], fail: [ { @@ -48,15 +49,6 @@ const requiredFieldsTestCases = { } ] }, - { - code: 'const x = gql`query { greetings { hello ...GreetingsFragment} }`', - errors: [ - { - message: `'id' field required on 'greetings'`, - type: 'TaggedTemplateExpression', - }, - ], - }, { code: 'const x = gql`fragment Name on Greetings { hello }`', errors: [ From ac7f110e8e942b280bd0f7f4b6f8d3f8c9544bfb Mon Sep 17 00:00:00 2001 From: Arnav Mishra Date: Mon, 10 May 2021 16:07:25 -0700 Subject: [PATCH 2/2] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6fdc92e..69df9bfa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### vNEXT -- _Nothing yet!_ +- Handle spread fragments for the required fields. [PR #300](https://github.com/apollographql/eslint-plugin-graphql/pull/300) by [Arnav Mishra](https://github.com/arnmishra). ### v4.0.0