11import { AccumulatorMap } from '../jsutils/AccumulatorMap.js' ;
22import { invariant } from '../jsutils/invariant.js' ;
33import type { ObjMap } from '../jsutils/ObjMap.js' ;
4- import type { Path } from '../jsutils/Path.js' ;
5- import { pathToArray } from '../jsutils/Path.js' ;
64
75import type {
86 FieldNode ,
@@ -22,7 +20,11 @@ import {
2220} from '../type/directives.js' ;
2321import type { GraphQLSchema } from '../type/schema.js' ;
2422
25- import type { GraphQLVariableSignature } from '../execution/getVariableSignature.js' ;
23+ import type {
24+ FragmentDetails ,
25+ GroupedFieldSet ,
26+ } from '../execution/collectFields.js' ;
27+ import type { ValidatedExecutionArgs } from '../execution/execute.js' ;
2628import type { VariableValues } from '../execution/values.js' ;
2729import {
2830 getDirectiveValues ,
@@ -31,32 +33,24 @@ import {
3133
3234import { typeFromAST } from '../utilities/typeFromAST.js' ;
3335
34- import type { TransformationContext } from './buildTransformationContext.js' ;
35-
3636export interface FieldDetails {
3737 node : FieldNode ;
3838 fragmentVariableValues ?: VariableValues | undefined ;
3939}
4040
41- export type FieldDetailsList = ReadonlyArray < FieldDetails > ;
42-
43- export type GroupedFieldSet = ReadonlyMap < string , FieldDetailsList > ;
44-
45- export interface FragmentDetails {
46- definition : FragmentDefinitionNode ;
47- variableSignatures ?: ObjMap < GraphQLVariableSignature > | undefined ;
48- }
49-
5041interface CollectFieldsContext {
5142 schema : GraphQLSchema ;
5243 fragments : ObjMap < FragmentDetails > ;
5344 variableValues : VariableValues ;
5445 runtimeType : GraphQLObjectType ;
5546 visitedFragmentNames : Set < string > ;
56- pendingLabelsByPath : Map < string , Set < string > > ;
5747 hideSuggestions : boolean ;
5848}
5949
50+ export interface GroupedFieldSetTree {
51+ groupedFieldSet : GroupedFieldSet ;
52+ deferredGroupedFieldSets : Map < string , GroupedFieldSetTree > ;
53+ }
6054/**
6155 * Given a selectionSet, collects all of the fields and returns them.
6256 *
@@ -68,28 +62,25 @@ interface CollectFieldsContext {
6862 */
6963
7064export function collectFields (
71- transformationContext : TransformationContext ,
65+ validateExecutionArgs : ValidatedExecutionArgs ,
7266 runtimeType : GraphQLObjectType ,
7367 selectionSet : SelectionSetNode ,
74- path : Path | undefined ,
75- ) : GroupedFieldSet {
76- const {
77- transformedArgs : { schema, fragments, variableValues, hideSuggestions } ,
78- pendingLabelsByPath,
79- } = transformationContext ;
80- const groupedFieldSet = new AccumulatorMap < string , FieldDetails > ( ) ;
68+ ) : GroupedFieldSetTree {
8169 const context : CollectFieldsContext = {
82- schema,
83- fragments,
84- variableValues,
70+ ...validateExecutionArgs ,
8571 runtimeType,
8672 visitedFragmentNames : new Set ( ) ,
87- pendingLabelsByPath,
88- hideSuggestions,
8973 } ;
9074
91- collectFieldsImpl ( context , selectionSet , groupedFieldSet , path ) ;
92- return groupedFieldSet ;
75+ const groupedFieldSet = new AccumulatorMap < string , FieldDetails > ( ) ;
76+ const deferredGroupedFieldSets = new Map < string , GroupedFieldSetTree > ( ) ;
77+ collectFieldsImpl (
78+ context ,
79+ selectionSet ,
80+ groupedFieldSet ,
81+ deferredGroupedFieldSets ,
82+ ) ;
83+ return { groupedFieldSet, deferredGroupedFieldSets } ;
9384}
9485
9586/**
@@ -103,25 +94,17 @@ export function collectFields(
10394 * @internal
10495 */
10596export function collectSubfields (
106- transformationContext : TransformationContext ,
97+ validatedExecutionArgs : ValidatedExecutionArgs ,
10798 returnType : GraphQLObjectType ,
108- fieldDetailsList : FieldDetailsList ,
109- path : Path | undefined ,
110- ) : GroupedFieldSet {
111- const {
112- transformedArgs : { schema, fragments, variableValues, hideSuggestions } ,
113- pendingLabelsByPath,
114- } = transformationContext ;
99+ fieldDetailsList : ReadonlyArray < FieldDetails > ,
100+ ) : GroupedFieldSetTree {
115101 const context : CollectFieldsContext = {
116- schema,
117- fragments,
118- variableValues,
102+ ...validatedExecutionArgs ,
119103 runtimeType : returnType ,
120104 visitedFragmentNames : new Set ( ) ,
121- pendingLabelsByPath,
122- hideSuggestions,
123105 } ;
124- const subGroupedFieldSet = new AccumulatorMap < string , FieldDetails > ( ) ;
106+ const groupedFieldSet = new AccumulatorMap < string , FieldDetails > ( ) ;
107+ const deferredGroupedFieldSets = new Map < string , GroupedFieldSetTree > ( ) ;
125108
126109 for ( const fieldDetail of fieldDetailsList ) {
127110 const selectionSet = fieldDetail . node . selectionSet ;
@@ -130,21 +113,21 @@ export function collectSubfields(
130113 collectFieldsImpl (
131114 context ,
132115 selectionSet ,
133- subGroupedFieldSet ,
134- path ,
116+ groupedFieldSet ,
117+ deferredGroupedFieldSets ,
135118 fragmentVariableValues ,
136119 ) ;
137120 }
138121 }
139122
140- return subGroupedFieldSet ;
123+ return { groupedFieldSet , deferredGroupedFieldSets } ;
141124}
142125
143126function collectFieldsImpl (
144127 context : CollectFieldsContext ,
145128 selectionSet : SelectionSetNode ,
146129 groupedFieldSet : AccumulatorMap < string , FieldDetails > ,
147- path ?: Path | undefined ,
130+ deferredGroupedFieldSets : Map < string , GroupedFieldSetTree > ,
148131 fragmentVariableValues ?: VariableValues ,
149132) : void {
150133 const {
@@ -153,7 +136,6 @@ function collectFieldsImpl(
153136 variableValues,
154137 runtimeType,
155138 visitedFragmentNames,
156- pendingLabelsByPath,
157139 hideSuggestions,
158140 } = context ;
159141
@@ -172,8 +154,30 @@ function collectFieldsImpl(
172154 break ;
173155 }
174156 case Kind . INLINE_FRAGMENT : {
157+ const deferLabel = isDeferred ( selection ) ;
158+ if ( deferLabel !== undefined ) {
159+ const deferredGroupedFieldSet = new AccumulatorMap <
160+ string ,
161+ FieldDetails
162+ > ( ) ;
163+ const nestedDeferredGroupedFieldSets = new Map <
164+ string ,
165+ GroupedFieldSetTree
166+ > ( ) ;
167+ collectFieldsImpl (
168+ context ,
169+ selection . selectionSet ,
170+ deferredGroupedFieldSet ,
171+ nestedDeferredGroupedFieldSets ,
172+ ) ;
173+ deferredGroupedFieldSets . set ( deferLabel , {
174+ groupedFieldSet : deferredGroupedFieldSet ,
175+ deferredGroupedFieldSets : nestedDeferredGroupedFieldSets ,
176+ } ) ;
177+ continue ;
178+ }
179+
175180 if (
176- isDeferred ( selection , path , pendingLabelsByPath ) ||
177181 ! shouldIncludeNode (
178182 selection ,
179183 variableValues ,
@@ -188,7 +192,7 @@ function collectFieldsImpl(
188192 context ,
189193 selection . selectionSet ,
190194 groupedFieldSet ,
191- path ,
195+ deferredGroupedFieldSets ,
192196 fragmentVariableValues ,
193197 ) ;
194198
@@ -199,7 +203,6 @@ function collectFieldsImpl(
199203
200204 if (
201205 visitedFragmentNames . has ( fragName ) ||
202- isDeferred ( selection , path , pendingLabelsByPath ) ||
203206 ! shouldIncludeNode ( selection , variableValues , fragmentVariableValues )
204207 ) {
205208 continue ;
@@ -213,6 +216,29 @@ function collectFieldsImpl(
213216 continue ;
214217 }
215218
219+ const deferLabel = isDeferred ( selection ) ;
220+ if ( deferLabel !== undefined ) {
221+ const deferredGroupedFieldSet = new AccumulatorMap <
222+ string ,
223+ FieldDetails
224+ > ( ) ;
225+ const nestedDeferredGroupedFieldSets = new Map <
226+ string ,
227+ GroupedFieldSetTree
228+ > ( ) ;
229+ collectFieldsImpl (
230+ context ,
231+ fragment . definition . selectionSet ,
232+ deferredGroupedFieldSet ,
233+ nestedDeferredGroupedFieldSets ,
234+ ) ;
235+ deferredGroupedFieldSets . set ( deferLabel , {
236+ groupedFieldSet : deferredGroupedFieldSet ,
237+ deferredGroupedFieldSets : nestedDeferredGroupedFieldSets ,
238+ } ) ;
239+ continue ;
240+ }
241+
216242 const fragmentVariableSignatures = fragment . variableSignatures ;
217243 let newFragmentVariableValues : VariableValues | undefined ;
218244 if ( fragmentVariableSignatures ) {
@@ -230,7 +256,7 @@ function collectFieldsImpl(
230256 context ,
231257 fragment . definition . selectionSet ,
232258 groupedFieldSet ,
233- path ,
259+ deferredGroupedFieldSets ,
234260 newFragmentVariableValues ,
235261 ) ;
236262 break ;
@@ -305,26 +331,18 @@ function getFieldEntryKey(node: FieldNode): string {
305331 */
306332function isDeferred (
307333 selection : FragmentSpreadNode | InlineFragmentNode ,
308- path : Path | undefined ,
309- pendingLabelsByPath : Map < string , Set < string > > ,
310- ) : boolean {
334+ ) : string | undefined {
311335 const deferDirective = selection . directives ?. find (
312336 ( directive ) => directive . name . value === GraphQLDeferDirective . name ,
313337 ) ;
314338 if ( ! deferDirective ) {
315- return false ;
316- }
317- const pathStr = pathToArray ( path ) . join ( '.' ) ;
318- const labels = pendingLabelsByPath . get ( pathStr ) ;
319- if ( labels == null ) {
320- return false ;
339+ return ;
321340 }
322341 const labelArg = deferDirective . arguments ?. find (
323342 ( arg ) => arg . name . value === 'label' ,
324343 ) ;
325344 invariant ( labelArg != null ) ;
326345 const labelValue = labelArg . value ;
327346 invariant ( labelValue . kind === Kind . STRING ) ;
328- const label = labelValue . value ;
329- return labels . has ( label ) ;
347+ return labelValue . value ;
330348}
0 commit comments