@@ -20,11 +20,36 @@ import type { GraphQLSchema } from '../type/schema.js';
2020
2121import { typeFromAST } from '../utilities/typeFromAST.js' ;
2222
23- import { getDirectiveValues } from './values.js' ;
23+ import type { GraphQLVariableSignature } from './getVariableSignature.js' ;
24+ import { experimentalGetArgumentValues , getDirectiveValues } from './values.js' ;
2425
25- export type FieldGroup = ReadonlyArray < FieldNode > ;
26+ export interface FragmentVariables {
27+ signatures : ObjMap < GraphQLVariableSignature > ;
28+ values : ObjMap < unknown > ;
29+ }
30+
31+ export interface FieldDetails {
32+ node : FieldNode ;
33+ fragmentVariables ?: FragmentVariables | undefined ;
34+ }
2635
27- export type GroupedFieldSet = Map < string , FieldGroup > ;
36+ export type FieldGroup = ReadonlyArray < FieldDetails > ;
37+
38+ export type GroupedFieldSet = ReadonlyMap < string , FieldGroup > ;
39+
40+ export interface FragmentDetails {
41+ definition : FragmentDefinitionNode ;
42+ variableSignatures ?: ObjMap < GraphQLVariableSignature > | undefined ;
43+ }
44+
45+ interface CollectFieldsContext {
46+ schema : GraphQLSchema ;
47+ fragments : ObjMap < FragmentDetails > ;
48+ variableValues : { [ variable : string ] : unknown } ;
49+ fragmentVariableValues ?: FragmentVariables ;
50+ runtimeType : GraphQLObjectType ;
51+ visitedFragmentNames : Set < string > ;
52+ }
2853
2954/**
3055 * Given a selectionSet, collects all of the fields and returns them.
@@ -37,21 +62,21 @@ export type GroupedFieldSet = Map<string, FieldGroup>;
3762 */
3863export function collectFields (
3964 schema : GraphQLSchema ,
40- fragments : ObjMap < FragmentDefinitionNode > ,
65+ fragments : ObjMap < FragmentDetails > ,
4166 variableValues : { [ variable : string ] : unknown } ,
4267 runtimeType : GraphQLObjectType ,
4368 selectionSet : SelectionSetNode ,
4469) : GroupedFieldSet {
45- const groupedFieldSet = new AccumulatorMap < string , FieldNode > ( ) ;
46- collectFieldsImpl (
70+ const groupedFieldSet = new AccumulatorMap < string , FieldDetails > ( ) ;
71+ const context : CollectFieldsContext = {
4772 schema,
4873 fragments,
4974 variableValues,
5075 runtimeType,
51- selectionSet ,
52- groupedFieldSet ,
53- new Set ( ) ,
54- ) ;
76+ visitedFragmentNames : new Set ( ) ,
77+ } ;
78+
79+ collectFieldsImpl ( context , selectionSet , groupedFieldSet ) ;
5580 return groupedFieldSet ;
5681}
5782
@@ -67,90 +92,110 @@ export function collectFields(
6792 */
6893export function collectSubfields (
6994 schema : GraphQLSchema ,
70- fragments : ObjMap < FragmentDefinitionNode > ,
95+ fragments : ObjMap < FragmentDetails > ,
7196 variableValues : { [ variable : string ] : unknown } ,
7297 returnType : GraphQLObjectType ,
7398 fieldGroup : FieldGroup ,
7499) : GroupedFieldSet {
75- const subGroupedFieldSet = new AccumulatorMap < string , FieldNode > ( ) ;
76- const visitedFragmentNames = new Set < string > ( ) ;
77- for ( const node of fieldGroup ) {
100+ const context : CollectFieldsContext = {
101+ schema,
102+ fragments,
103+ variableValues,
104+ runtimeType : returnType ,
105+ visitedFragmentNames : new Set ( ) ,
106+ } ;
107+ const subGroupedFieldSet = new AccumulatorMap < string , FieldDetails > ( ) ;
108+
109+ for ( const fieldDetail of fieldGroup ) {
110+ const node = fieldDetail . node ;
78111 if ( node . selectionSet ) {
79- collectFieldsImpl (
80- schema ,
81- fragments ,
82- variableValues ,
83- returnType ,
84- node . selectionSet ,
85- subGroupedFieldSet ,
86- visitedFragmentNames ,
87- ) ;
112+ collectFieldsImpl ( context , node . selectionSet , subGroupedFieldSet ) ;
88113 }
89114 }
115+
90116 return subGroupedFieldSet ;
91117}
92118
93- // eslint-disable-next-line max-params
94119function collectFieldsImpl (
95- schema : GraphQLSchema ,
96- fragments : ObjMap < FragmentDefinitionNode > ,
97- variableValues : { [ variable : string ] : unknown } ,
98- runtimeType : GraphQLObjectType ,
120+ context : CollectFieldsContext ,
99121 selectionSet : SelectionSetNode ,
100- groupedFieldSet : AccumulatorMap < string , FieldNode > ,
101- visitedFragmentNames : Set < string > ,
122+ groupedFieldSet : AccumulatorMap < string , FieldDetails > ,
123+ fragmentVariables ?: FragmentVariables ,
102124) : void {
125+ const {
126+ schema,
127+ fragments,
128+ variableValues,
129+ runtimeType,
130+ visitedFragmentNames,
131+ } = context ;
132+
103133 for ( const selection of selectionSet . selections ) {
104134 switch ( selection . kind ) {
105135 case Kind . FIELD : {
106- if ( ! shouldIncludeNode ( variableValues , selection ) ) {
136+ if ( ! shouldIncludeNode ( selection , variableValues , fragmentVariables ) ) {
107137 continue ;
108138 }
109- groupedFieldSet . add ( getFieldEntryKey ( selection ) , selection ) ;
139+ groupedFieldSet . add ( getFieldEntryKey ( selection ) , {
140+ node : selection ,
141+ fragmentVariables,
142+ } ) ;
110143 break ;
111144 }
112145 case Kind . INLINE_FRAGMENT : {
113146 if (
114- ! shouldIncludeNode ( variableValues , selection ) ||
147+ ! shouldIncludeNode ( selection , variableValues , fragmentVariables ) ||
115148 ! doesFragmentConditionMatch ( schema , selection , runtimeType )
116149 ) {
117150 continue ;
118151 }
152+
119153 collectFieldsImpl (
120- schema ,
121- fragments ,
122- variableValues ,
123- runtimeType ,
154+ context ,
124155 selection . selectionSet ,
125156 groupedFieldSet ,
126- visitedFragmentNames ,
157+ fragmentVariables ,
127158 ) ;
128159 break ;
129160 }
130161 case Kind . FRAGMENT_SPREAD : {
131162 const fragName = selection . name . value ;
163+
132164 if (
133165 visitedFragmentNames . has ( fragName ) ||
134- ! shouldIncludeNode ( variableValues , selection )
166+ ! shouldIncludeNode ( selection , variableValues , fragmentVariables )
135167 ) {
136168 continue ;
137169 }
138- visitedFragmentNames . add ( fragName ) ;
170+
139171 const fragment = fragments [ fragName ] ;
140172 if (
141173 fragment == null ||
142- ! doesFragmentConditionMatch ( schema , fragment , runtimeType )
174+ ! doesFragmentConditionMatch ( schema , fragment . definition , runtimeType )
143175 ) {
144176 continue ;
145177 }
178+
179+ const fragmentVariableSignatures = fragment . variableSignatures ;
180+ let newFragmentVariables : FragmentVariables | undefined ;
181+ if ( fragmentVariableSignatures ) {
182+ newFragmentVariables = {
183+ signatures : fragmentVariableSignatures ,
184+ values : experimentalGetArgumentValues (
185+ selection ,
186+ Object . values ( fragmentVariableSignatures ) ,
187+ variableValues ,
188+ fragmentVariables ,
189+ ) ,
190+ } ;
191+ }
192+
193+ visitedFragmentNames . add ( fragName ) ;
146194 collectFieldsImpl (
147- schema ,
148- fragments ,
149- variableValues ,
150- runtimeType ,
151- fragment . selectionSet ,
195+ context ,
196+ fragment . definition . selectionSet ,
152197 groupedFieldSet ,
153- visitedFragmentNames ,
198+ newFragmentVariables ,
154199 ) ;
155200 break ;
156201 }
@@ -163,10 +208,16 @@ function collectFieldsImpl(
163208 * directives, where `@skip` has higher precedence than `@include`.
164209 */
165210function shouldIncludeNode (
166- variableValues : { [ variable : string ] : unknown } ,
167211 node : FragmentSpreadNode | FieldNode | InlineFragmentNode ,
212+ variableValues : { [ variable : string ] : unknown } ,
213+ fragmentVariables : FragmentVariables | undefined ,
168214) : boolean {
169- const skip = getDirectiveValues ( GraphQLSkipDirective , node , variableValues ) ;
215+ const skip = getDirectiveValues (
216+ GraphQLSkipDirective ,
217+ node ,
218+ variableValues ,
219+ fragmentVariables ,
220+ ) ;
170221 if ( skip ?. if === true ) {
171222 return false ;
172223 }
@@ -175,6 +226,7 @@ function shouldIncludeNode(
175226 GraphQLIncludeDirective ,
176227 node ,
177228 variableValues ,
229+ fragmentVariables ,
178230 ) ;
179231 if ( include ?. if === false ) {
180232 return false ;
0 commit comments