1
1
import type { ObjMap } from '../jsutils/ObjMap' ;
2
2
3
3
import type {
4
- SelectionSetNode ,
4
+ ArgumentNode ,
5
5
FieldNode ,
6
6
FragmentSpreadNode ,
7
7
InlineFragmentNode ,
8
8
FragmentDefinitionNode ,
9
+ SelectionSetNode ,
10
+ ValueNode ,
9
11
} from '../language/ast' ;
10
12
import { Kind } from '../language/kinds' ;
11
13
@@ -19,6 +21,8 @@ import { isAbstractType } from '../type/definition';
19
21
20
22
import { typeFromAST } from '../utilities/typeFromAST' ;
21
23
24
+ import { visit } from '../language/visitor' ;
25
+
22
26
import { getDirectiveValues } from './values' ;
23
27
24
28
/**
@@ -89,12 +93,14 @@ export function collectFields(
89
93
) {
90
94
continue ;
91
95
}
96
+ const selectionSetWithArgumentsApplied =
97
+ selectionSetWithFragmentArgumentsApplied ( fragment , selection ) ;
92
98
collectFields (
93
99
schema ,
94
100
fragments ,
95
101
variableValues ,
96
102
runtimeType ,
97
- fragment . selectionSet ,
103
+ selectionSetWithArgumentsApplied ,
98
104
fields ,
99
105
visitedFragmentNames ,
100
106
) ;
@@ -157,3 +163,44 @@ function doesFragmentConditionMatch(
157
163
function getFieldEntryKey ( node : FieldNode ) : string {
158
164
return node . alias ? node . alias . value : node . name . value ;
159
165
}
166
+
167
+ /**
168
+ *
169
+ * When a fragment spread is provided with arguments,
170
+ * visit that fragment's definition and replace those arguments'
171
+ * variable usages with the provided argument value.
172
+ */
173
+ function selectionSetWithFragmentArgumentsApplied (
174
+ fragment : FragmentDefinitionNode ,
175
+ fragmentSpread : FragmentSpreadNode ,
176
+ ) : SelectionSetNode {
177
+ const variableDefinitions = fragment . variableDefinitions ;
178
+ if ( ! variableDefinitions ) {
179
+ return fragment . selectionSet ;
180
+ }
181
+
182
+ const providedArguments : Map < string , ArgumentNode > = new Map ( ) ;
183
+ if ( fragmentSpread . arguments ) {
184
+ for ( const argument of fragmentSpread . arguments ) {
185
+ providedArguments . set ( argument . name . value , argument ) ;
186
+ }
187
+ }
188
+
189
+ const fragmentVariableValues : Map < string , ValueNode > = new Map ( ) ;
190
+ for ( const variableDef of variableDefinitions ) {
191
+ const variableName = variableDef . variable . name . value ;
192
+ const providedArg = providedArguments . get ( variableName ) ;
193
+ if ( providedArg ) {
194
+ fragmentVariableValues . set ( variableName , providedArg . value ) ;
195
+ } else if ( variableDef . defaultValue ) {
196
+ fragmentVariableValues . set ( variableName , variableDef . defaultValue ) ;
197
+ }
198
+ // Otherwise just preserve the variable as-is: it will be treated as unset by the executor.
199
+ }
200
+
201
+ return visit ( fragment . selectionSet , {
202
+ Variable ( node ) {
203
+ return fragmentVariableValues . get ( node . name . value ) ;
204
+ } ,
205
+ } ) ;
206
+ }
0 commit comments