@@ -2,6 +2,7 @@ import { AccumulatorMap } from '../jsutils/AccumulatorMap.js';
2
2
import type { ObjMap } from '../jsutils/ObjMap.js' ;
3
3
4
4
import type {
5
+ DirectiveNode ,
5
6
FieldNode ,
6
7
FragmentDefinitionNode ,
7
8
FragmentSpreadNode ,
@@ -23,7 +24,11 @@ import { typeFromAST } from '../utilities/typeFromAST.js';
23
24
24
25
import type { GraphQLVariableSignature } from './getVariableSignature.js' ;
25
26
import type { VariableValues } from './values.js' ;
26
- import { getDirectiveValues , getFragmentVariableValues } from './values.js' ;
27
+ import {
28
+ experimentalGetArgumentValues ,
29
+ getDirectiveValues ,
30
+ getFragmentVariableValues ,
31
+ } from './values.js' ;
27
32
28
33
export interface DeferUsage {
29
34
label : string | undefined ;
@@ -52,6 +57,8 @@ interface CollectFieldsContext {
52
57
runtimeType : GraphQLObjectType ;
53
58
visitedFragmentNames : Set < string > ;
54
59
hideSuggestions : boolean ;
60
+ forbiddenDirectiveInstances : Array < DirectiveNode > ;
61
+ forbidSkipAndInclude : boolean ;
55
62
}
56
63
57
64
/**
@@ -71,9 +78,11 @@ export function collectFields(
71
78
runtimeType : GraphQLObjectType ,
72
79
selectionSet : SelectionSetNode ,
73
80
hideSuggestions : boolean ,
81
+ forbidSkipAndInclude = false ,
74
82
) : {
75
83
groupedFieldSet : GroupedFieldSet ;
76
84
newDeferUsages : ReadonlyArray < DeferUsage > ;
85
+ forbiddenDirectiveInstances : ReadonlyArray < DirectiveNode > ;
77
86
} {
78
87
const groupedFieldSet = new AccumulatorMap < string , FieldDetails > ( ) ;
79
88
const newDeferUsages : Array < DeferUsage > = [ ] ;
@@ -84,10 +93,16 @@ export function collectFields(
84
93
runtimeType,
85
94
visitedFragmentNames : new Set ( ) ,
86
95
hideSuggestions,
96
+ forbiddenDirectiveInstances : [ ] ,
97
+ forbidSkipAndInclude,
87
98
} ;
88
99
89
100
collectFieldsImpl ( context , selectionSet , groupedFieldSet , newDeferUsages ) ;
90
- return { groupedFieldSet, newDeferUsages } ;
101
+ return {
102
+ groupedFieldSet,
103
+ newDeferUsages,
104
+ forbiddenDirectiveInstances : context . forbiddenDirectiveInstances ,
105
+ } ;
91
106
}
92
107
93
108
/**
@@ -119,6 +134,8 @@ export function collectSubfields(
119
134
runtimeType : returnType ,
120
135
visitedFragmentNames : new Set ( ) ,
121
136
hideSuggestions,
137
+ forbiddenDirectiveInstances : [ ] ,
138
+ forbidSkipAndInclude : false ,
122
139
} ;
123
140
const subGroupedFieldSet = new AccumulatorMap < string , FieldDetails > ( ) ;
124
141
const newDeferUsages : Array < DeferUsage > = [ ] ;
@@ -166,7 +183,12 @@ function collectFieldsImpl(
166
183
switch ( selection . kind ) {
167
184
case Kind . FIELD : {
168
185
if (
169
- ! shouldIncludeNode ( selection , variableValues , fragmentVariableValues )
186
+ ! shouldIncludeNode (
187
+ context ,
188
+ selection ,
189
+ variableValues ,
190
+ fragmentVariableValues ,
191
+ )
170
192
) {
171
193
continue ;
172
194
}
@@ -180,6 +202,7 @@ function collectFieldsImpl(
180
202
case Kind . INLINE_FRAGMENT : {
181
203
if (
182
204
! shouldIncludeNode (
205
+ context ,
183
206
selection ,
184
207
variableValues ,
185
208
fragmentVariableValues ,
@@ -224,7 +247,12 @@ function collectFieldsImpl(
224
247
225
248
if (
226
249
visitedFragmentNames . has ( fragName ) ||
227
- ! shouldIncludeNode ( selection , variableValues , fragmentVariableValues )
250
+ ! shouldIncludeNode (
251
+ context ,
252
+ selection ,
253
+ variableValues ,
254
+ fragmentVariableValues ,
255
+ )
228
256
) {
229
257
continue ;
230
258
}
@@ -320,26 +348,47 @@ function getDeferUsage(
320
348
* directives, where `@skip` has higher precedence than `@include`.
321
349
*/
322
350
function shouldIncludeNode (
351
+ context : CollectFieldsContext ,
323
352
node : FragmentSpreadNode | FieldNode | InlineFragmentNode ,
324
353
variableValues : VariableValues ,
325
354
fragmentVariableValues : VariableValues | undefined ,
326
355
) : 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 ,
332
358
) ;
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 ;
333
372
if ( skip ?. if === true ) {
334
373
return false ;
335
374
}
336
375
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 ,
342
378
) ;
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 ;
343
392
if ( include ?. if === false ) {
344
393
return false ;
345
394
}
0 commit comments