@@ -2,6 +2,7 @@ import { AccumulatorMap } from '../jsutils/AccumulatorMap.js';
22import type { ObjMap } from '../jsutils/ObjMap.js' ;
33
44import type {
5+ DirectiveNode ,
56 FieldNode ,
67 FragmentDefinitionNode ,
78 FragmentSpreadNode ,
@@ -23,7 +24,11 @@ import { typeFromAST } from '../utilities/typeFromAST.js';
2324
2425import type { GraphQLVariableSignature } from './getVariableSignature.js' ;
2526import type { VariableValues } from './values.js' ;
26- import { getDirectiveValues , getFragmentVariableValues } from './values.js' ;
27+ import {
28+ experimentalGetArgumentValues ,
29+ getDirectiveValues ,
30+ getFragmentVariableValues ,
31+ } from './values.js' ;
2732
2833export interface DeferUsage {
2934 label : string | undefined ;
@@ -52,6 +57,8 @@ interface CollectFieldsContext {
5257 runtimeType : GraphQLObjectType ;
5358 visitedFragmentNames : Set < string > ;
5459 hideSuggestions : boolean ;
60+ forbiddenDirectiveInstances : Array < DirectiveNode > ;
61+ forbidSkipAndInclude : boolean ;
5562}
5663
5764/**
@@ -71,9 +78,11 @@ export function collectFields(
7178 runtimeType : GraphQLObjectType ,
7279 selectionSet : SelectionSetNode ,
7380 hideSuggestions : boolean ,
81+ forbidSkipAndInclude = false ,
7482) : {
7583 groupedFieldSet : GroupedFieldSet ;
7684 newDeferUsages : ReadonlyArray < DeferUsage > ;
85+ forbiddenDirectiveInstances : ReadonlyArray < DirectiveNode > ;
7786} {
7887 const groupedFieldSet = new AccumulatorMap < string , FieldDetails > ( ) ;
7988 const newDeferUsages : Array < DeferUsage > = [ ] ;
@@ -84,10 +93,16 @@ export function collectFields(
8493 runtimeType,
8594 visitedFragmentNames : new Set ( ) ,
8695 hideSuggestions,
96+ forbiddenDirectiveInstances : [ ] ,
97+ forbidSkipAndInclude,
8798 } ;
8899
89100 collectFieldsImpl ( context , selectionSet , groupedFieldSet , newDeferUsages ) ;
90- return { groupedFieldSet, newDeferUsages } ;
101+ return {
102+ groupedFieldSet,
103+ newDeferUsages,
104+ forbiddenDirectiveInstances : context . forbiddenDirectiveInstances ,
105+ } ;
91106}
92107
93108/**
@@ -119,6 +134,8 @@ export function collectSubfields(
119134 runtimeType : returnType ,
120135 visitedFragmentNames : new Set ( ) ,
121136 hideSuggestions,
137+ forbiddenDirectiveInstances : [ ] ,
138+ forbidSkipAndInclude : false ,
122139 } ;
123140 const subGroupedFieldSet = new AccumulatorMap < string , FieldDetails > ( ) ;
124141 const newDeferUsages : Array < DeferUsage > = [ ] ;
@@ -166,7 +183,12 @@ function collectFieldsImpl(
166183 switch ( selection . kind ) {
167184 case Kind . FIELD : {
168185 if (
169- ! shouldIncludeNode ( selection , variableValues , fragmentVariableValues )
186+ ! shouldIncludeNode (
187+ context ,
188+ selection ,
189+ variableValues ,
190+ fragmentVariableValues ,
191+ )
170192 ) {
171193 continue ;
172194 }
@@ -180,6 +202,7 @@ function collectFieldsImpl(
180202 case Kind . INLINE_FRAGMENT : {
181203 if (
182204 ! shouldIncludeNode (
205+ context ,
183206 selection ,
184207 variableValues ,
185208 fragmentVariableValues ,
@@ -224,7 +247,12 @@ function collectFieldsImpl(
224247
225248 if (
226249 visitedFragmentNames . has ( fragName ) ||
227- ! shouldIncludeNode ( selection , variableValues , fragmentVariableValues )
250+ ! shouldIncludeNode (
251+ context ,
252+ selection ,
253+ variableValues ,
254+ fragmentVariableValues ,
255+ )
228256 ) {
229257 continue ;
230258 }
@@ -320,26 +348,47 @@ function getDeferUsage(
320348 * directives, where `@skip` has higher precedence than `@include`.
321349 */
322350function shouldIncludeNode (
351+ context : CollectFieldsContext ,
323352 node : FragmentSpreadNode | FieldNode | InlineFragmentNode ,
324353 variableValues : VariableValues ,
325354 fragmentVariableValues : VariableValues | undefined ,
326355) : boolean {
327- const skip = getDirectiveValues (
328- GraphQLSkipDirective ,
329- node ,
330- variableValues ,
331- fragmentVariableValues ,
356+ const skipDirectiveNode = node . directives ?. find (
357+ ( directive ) => directive . name . value === GraphQLSkipDirective . name ,
332358 ) ;
359+ if ( skipDirectiveNode && context . forbidSkipAndInclude ) {
360+ context . forbiddenDirectiveInstances . push ( skipDirectiveNode ) ;
361+ return false ;
362+ }
363+ const skip = skipDirectiveNode
364+ ? experimentalGetArgumentValues (
365+ skipDirectiveNode ,
366+ GraphQLSkipDirective . args ,
367+ variableValues ,
368+ fragmentVariableValues ,
369+ context . hideSuggestions ,
370+ )
371+ : undefined ;
333372 if ( skip ?. if === true ) {
334373 return false ;
335374 }
336375
337- const include = getDirectiveValues (
338- GraphQLIncludeDirective ,
339- node ,
340- variableValues ,
341- fragmentVariableValues ,
376+ const includeDirectiveNode = node . directives ?. find (
377+ ( directive ) => directive . name . value === GraphQLIncludeDirective . name ,
342378 ) ;
379+ if ( includeDirectiveNode && context . forbidSkipAndInclude ) {
380+ context . forbiddenDirectiveInstances . push ( includeDirectiveNode ) ;
381+ return false ;
382+ }
383+ const include = includeDirectiveNode
384+ ? experimentalGetArgumentValues (
385+ includeDirectiveNode ,
386+ GraphQLIncludeDirective . args ,
387+ variableValues ,
388+ fragmentVariableValues ,
389+ context . hideSuggestions ,
390+ )
391+ : undefined ;
343392 if ( include ?. if === false ) {
344393 return false ;
345394 }
0 commit comments