@@ -21,11 +21,18 @@ import { typeFromAST } from '../utilities/typeFromAST';
21
21
22
22
import { getDirectiveValues } from './values' ;
23
23
24
- interface FragmentEntry {
25
- fragment : FragmentDefinitionNode ;
24
+ interface FieldEntry {
25
+ selection : FieldNode ;
26
+ name : string
27
+ }
28
+
29
+ interface EntryWithSelectionset {
30
+ selectionSet : SelectionSetNode ;
26
31
runtimeType : GraphQLObjectType ;
27
32
}
28
33
34
+ type StackEntry = EntryWithSelectionset | FieldEntry ;
35
+
29
36
/**
30
37
* Given a selectionSet, collects all of the fields and returns them.
31
38
*
@@ -42,32 +49,30 @@ export function collectFields(
42
49
runtimeType : GraphQLObjectType ,
43
50
selectionSet : SelectionSetNode ,
44
51
) : Map < string , ReadonlyArray < FieldNode > > {
45
- const foundFragments : Array < FragmentEntry > = [ ] ;
52
+ const stack : Array < StackEntry > = [ { selectionSet , runtimeType } ] ;
46
53
const fields = new Map ( ) ;
47
54
const visited = new Set < string > ( ) ;
48
- collectFieldsImpl (
49
- schema ,
50
- fragments ,
51
- variableValues ,
52
- runtimeType ,
53
- selectionSet ,
54
- fields ,
55
- visited ,
56
- foundFragments ,
57
- ) ;
58
55
59
56
let entry ;
60
- while ( ( entry = foundFragments . pop ( ) ) !== undefined ) {
61
- collectFieldsImpl (
62
- schema ,
63
- fragments ,
64
- variableValues ,
65
- entry . runtimeType ,
66
- entry . fragment . selectionSet ,
67
- fields ,
68
- visited ,
69
- foundFragments ,
70
- ) ;
57
+ while ( ( entry = stack . shift ( ) ) !== undefined ) {
58
+ if ( 'selectionSet' in entry ) {
59
+ collectFieldsImpl (
60
+ schema ,
61
+ fragments ,
62
+ variableValues ,
63
+ entry . runtimeType ,
64
+ entry . selectionSet ,
65
+ visited ,
66
+ stack ,
67
+ ) ;
68
+ } else {
69
+ const fieldList = fields . get ( entry . name ) ;
70
+ if ( fieldList !== undefined ) {
71
+ fieldList . push ( entry . selection ) ;
72
+ } else {
73
+ fields . set ( entry . name , [ entry . selection ] ) ;
74
+ }
75
+ }
71
76
}
72
77
73
78
return fields ;
@@ -91,37 +96,36 @@ export function collectSubfields(
91
96
fieldNodes : ReadonlyArray < FieldNode > ,
92
97
) : Map < string , ReadonlyArray < FieldNode > > {
93
98
const subFieldNodes = new Map ( ) ;
94
- const foundFragments : Array < FragmentEntry > = [ ] ;
99
+ const stack : Array < StackEntry > = [ ] ;
95
100
const visitedFragmentNames = new Set < string > ( ) ;
96
101
for ( const node of fieldNodes ) {
97
102
if ( node . selectionSet ) {
103
+ stack . push ( { selectionSet : node . selectionSet , runtimeType : returnType } ) ;
104
+ }
105
+ }
106
+
107
+ let entry ;
108
+ while ( ( entry = stack . shift ( ) ) !== undefined ) {
109
+ if ( 'selectionSet' in entry ) {
98
110
collectFieldsImpl (
99
111
schema ,
100
112
fragments ,
101
113
variableValues ,
102
- returnType ,
103
- node . selectionSet ,
104
- subFieldNodes ,
114
+ entry . runtimeType ,
115
+ entry . selectionSet ,
105
116
visitedFragmentNames ,
106
- foundFragments ,
117
+ stack ,
107
118
) ;
119
+ } else {
120
+ const fieldList = subFieldNodes . get ( entry . name ) ;
121
+ if ( fieldList !== undefined ) {
122
+ fieldList . push ( entry . selection ) ;
123
+ } else {
124
+ subFieldNodes . set ( entry . name , [ entry . selection ] ) ;
125
+ }
108
126
}
109
127
}
110
128
111
- let entry ;
112
- while ( ( entry = foundFragments . pop ( ) ) !== undefined ) {
113
- collectFieldsImpl (
114
- schema ,
115
- fragments ,
116
- variableValues ,
117
- entry . runtimeType ,
118
- entry . fragment . selectionSet ,
119
- subFieldNodes ,
120
- visitedFragmentNames ,
121
- foundFragments ,
122
- ) ;
123
- }
124
-
125
129
return subFieldNodes ;
126
130
}
127
131
@@ -131,23 +135,18 @@ function collectFieldsImpl(
131
135
variableValues : { [ variable : string ] : unknown } ,
132
136
runtimeType : GraphQLObjectType ,
133
137
selectionSet : SelectionSetNode ,
134
- fields : Map < string , Array < FieldNode > > ,
135
138
visitedFragmentNames : Set < string > ,
136
- foundFragments : Array < FragmentEntry > ,
139
+ stack : Array < StackEntry > ,
137
140
) : void {
141
+ const discovered = [ ] ;
138
142
for ( const selection of selectionSet . selections ) {
139
143
switch ( selection . kind ) {
140
144
case Kind . FIELD : {
141
145
if ( ! shouldIncludeNode ( variableValues , selection ) ) {
142
146
continue ;
143
147
}
144
148
const name = getFieldEntryKey ( selection ) ;
145
- const fieldList = fields . get ( name ) ;
146
- if ( fieldList !== undefined ) {
147
- fieldList . push ( selection ) ;
148
- } else {
149
- fields . set ( name , [ selection ] ) ;
150
- }
149
+ discovered . push ( { selection, name } ) ;
151
150
break ;
152
151
}
153
152
case Kind . INLINE_FRAGMENT : {
@@ -157,16 +156,7 @@ function collectFieldsImpl(
157
156
) {
158
157
continue ;
159
158
}
160
- collectFieldsImpl (
161
- schema ,
162
- fragments ,
163
- variableValues ,
164
- runtimeType ,
165
- selection . selectionSet ,
166
- fields ,
167
- visitedFragmentNames ,
168
- foundFragments ,
169
- ) ;
159
+ discovered . push ( { selectionSet : selection . selectionSet , runtimeType } ) ;
170
160
break ;
171
161
}
172
162
case Kind . FRAGMENT_SPREAD : {
@@ -186,11 +176,15 @@ function collectFieldsImpl(
186
176
continue ;
187
177
}
188
178
189
- foundFragments . push ( { runtimeType , fragment } ) ;
179
+ discovered . push ( { selectionSet : fragment . selectionSet , runtimeType } ) ;
190
180
break ;
191
181
}
192
182
}
193
183
}
184
+
185
+ if ( discovered . length !== 0 ) {
186
+ stack . unshift ( ...discovered ) ;
187
+ }
194
188
}
195
189
196
190
/**
0 commit comments