11import type { ObjMap } from '../jsutils/ObjMap' ;
22
33import type {
4- SelectionSetNode ,
4+ ArgumentNode ,
55 FieldNode ,
66 FragmentSpreadNode ,
77 InlineFragmentNode ,
88 FragmentDefinitionNode ,
9+ SelectionSetNode ,
10+ ValueNode ,
911} from '../language/ast' ;
1012import { Kind } from '../language/kinds' ;
1113
@@ -19,6 +21,8 @@ import { isAbstractType } from '../type/definition';
1921
2022import { typeFromAST } from '../utilities/typeFromAST' ;
2123
24+ import { visit } from '../language/visitor' ;
25+
2226import { getDirectiveValues } from './values' ;
2327
2428/**
@@ -89,12 +93,14 @@ export function collectFields(
8993 ) {
9094 continue ;
9195 }
96+ const selectionSetWithArgumentsApplied =
97+ selectionSetWithFragmentArgumentsApplied ( fragment , selection ) ;
9298 collectFields (
9399 schema ,
94100 fragments ,
95101 variableValues ,
96102 runtimeType ,
97- fragment . selectionSet ,
103+ selectionSetWithArgumentsApplied ,
98104 fields ,
99105 visitedFragmentNames ,
100106 ) ;
@@ -157,3 +163,44 @@ function doesFragmentConditionMatch(
157163function getFieldEntryKey ( node : FieldNode ) : string {
158164 return node . alias ? node . alias . value : node . name . value ;
159165}
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