Skip to content

Commit 43e36cc

Browse files
committed
stack iterator depth first
1 parent 006e077 commit 43e36cc

File tree

1 file changed

+56
-62
lines changed

1 file changed

+56
-62
lines changed

src/execution/collectFields.ts

+56-62
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,18 @@ import { typeFromAST } from '../utilities/typeFromAST';
2121

2222
import { getDirectiveValues } from './values';
2323

24-
interface FragmentEntry {
25-
fragment: FragmentDefinitionNode;
24+
interface FieldEntry {
25+
selection: FieldNode;
26+
name: string
27+
}
28+
29+
interface EntryWithSelectionset {
30+
selectionSet: SelectionSetNode;
2631
runtimeType: GraphQLObjectType;
2732
}
2833

34+
type StackEntry = EntryWithSelectionset | FieldEntry;
35+
2936
/**
3037
* Given a selectionSet, collects all of the fields and returns them.
3138
*
@@ -42,32 +49,30 @@ export function collectFields(
4249
runtimeType: GraphQLObjectType,
4350
selectionSet: SelectionSetNode,
4451
): Map<string, ReadonlyArray<FieldNode>> {
45-
const foundFragments: Array<FragmentEntry> = [];
52+
const stack: Array<StackEntry> = [{ selectionSet, runtimeType }];
4653
const fields = new Map();
4754
const visited = new Set<string>();
48-
collectFieldsImpl(
49-
schema,
50-
fragments,
51-
variableValues,
52-
runtimeType,
53-
selectionSet,
54-
fields,
55-
visited,
56-
foundFragments,
57-
);
5855

5956
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+
}
7176
}
7277

7378
return fields;
@@ -91,37 +96,36 @@ export function collectSubfields(
9196
fieldNodes: ReadonlyArray<FieldNode>,
9297
): Map<string, ReadonlyArray<FieldNode>> {
9398
const subFieldNodes = new Map();
94-
const foundFragments: Array<FragmentEntry> = [];
99+
const stack: Array<StackEntry> = [];
95100
const visitedFragmentNames = new Set<string>();
96101
for (const node of fieldNodes) {
97102
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) {
98110
collectFieldsImpl(
99111
schema,
100112
fragments,
101113
variableValues,
102-
returnType,
103-
node.selectionSet,
104-
subFieldNodes,
114+
entry.runtimeType,
115+
entry.selectionSet,
105116
visitedFragmentNames,
106-
foundFragments,
117+
stack,
107118
);
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+
}
108126
}
109127
}
110128

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-
125129
return subFieldNodes;
126130
}
127131

@@ -131,23 +135,18 @@ function collectFieldsImpl(
131135
variableValues: { [variable: string]: unknown },
132136
runtimeType: GraphQLObjectType,
133137
selectionSet: SelectionSetNode,
134-
fields: Map<string, Array<FieldNode>>,
135138
visitedFragmentNames: Set<string>,
136-
foundFragments: Array<FragmentEntry>,
139+
stack: Array<StackEntry>,
137140
): void {
141+
const discovered = [];
138142
for (const selection of selectionSet.selections) {
139143
switch (selection.kind) {
140144
case Kind.FIELD: {
141145
if (!shouldIncludeNode(variableValues, selection)) {
142146
continue;
143147
}
144148
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 });
151150
break;
152151
}
153152
case Kind.INLINE_FRAGMENT: {
@@ -157,16 +156,7 @@ function collectFieldsImpl(
157156
) {
158157
continue;
159158
}
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 });
170160
break;
171161
}
172162
case Kind.FRAGMENT_SPREAD: {
@@ -186,11 +176,15 @@ function collectFieldsImpl(
186176
continue;
187177
}
188178

189-
foundFragments.push({ runtimeType, fragment });
179+
discovered.push({ selectionSet: fragment.selectionSet, runtimeType });
190180
break;
191181
}
192182
}
193183
}
184+
185+
if (discovered.length !== 0) {
186+
stack.unshift(...discovered);
187+
}
194188
}
195189

196190
/**

0 commit comments

Comments
 (0)