Skip to content

Commit 44aa240

Browse files
committed
fix(core): Fix undefined type issue with nested fragment spreads
Relates to #3337.
1 parent 717abac commit 44aa240

File tree

1 file changed

+50
-21
lines changed

1 file changed

+50
-21
lines changed

packages/core/src/api/common/graphql-value-transformer.ts

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -188,30 +188,56 @@ export class GraphqlValueTransformer {
188188
inputType: GraphQLInputObjectType,
189189
parent: TypeTreeNode,
190190
): { [name: string]: TypeTreeNode } {
191-
return Object.entries(inputType.getFields()).reduce((result, [key, field]) => {
192-
const namedType = getNamedType(field.type);
193-
if (namedType === parent.type) {
194-
// prevent recursion-induced stack overflow
195-
return result;
196-
}
197-
const child: TypeTreeNode = {
198-
type: namedType,
199-
isList: this.isList(field.type),
200-
parent,
201-
fragmentRefs: [],
202-
children: {},
203-
};
204-
if (isInputObjectType(namedType)) {
205-
child.children = this.getChildrenTreeNodes(namedType, child);
206-
}
207-
return { ...result, [key]: child };
208-
}, {} as { [name: string]: TypeTreeNode });
191+
return Object.entries(inputType.getFields()).reduce(
192+
(result, [key, field]) => {
193+
const namedType = getNamedType(field.type);
194+
if (namedType === parent.type) {
195+
// prevent recursion-induced stack overflow
196+
return result;
197+
}
198+
const child: TypeTreeNode = {
199+
type: namedType,
200+
isList: this.isList(field.type),
201+
parent,
202+
fragmentRefs: [],
203+
children: {},
204+
};
205+
if (isInputObjectType(namedType)) {
206+
child.children = this.getChildrenTreeNodes(namedType, child);
207+
}
208+
return { ...result, [key]: child };
209+
},
210+
{} as { [name: string]: TypeTreeNode },
211+
);
209212
}
210213

211214
private isList(t: any): boolean {
212215
return isListType(t) || (isNonNullType(t) && isListType(t.ofType));
213216
}
214217

218+
private deepMergeChildren(
219+
target: { [name: string]: TypeTreeNode },
220+
source: { [name: string]: TypeTreeNode },
221+
): { [name: string]: TypeTreeNode } {
222+
const merged = { ...target };
223+
for (const key in source) {
224+
if (source.hasOwnProperty(key)) {
225+
if (merged[key]) {
226+
// If the key already exists, merge recursively
227+
if (source[key].children && Object.keys(source[key].children).length > 0) {
228+
merged[key].children = this.deepMergeChildren(
229+
merged[key].children,
230+
source[key].children,
231+
);
232+
}
233+
} else {
234+
merged[key] = source[key];
235+
}
236+
}
237+
}
238+
return merged;
239+
}
240+
215241
private getTypeNodeByPath(typeTree: TypeTree, path: Array<string | number>): TypeTreeNode | undefined {
216242
let targetNode: TypeTreeNode | undefined = typeTree.operation;
217243
for (const segment of path) {
@@ -224,9 +250,12 @@ export class GraphqlValueTransformer {
224250
const ref = fragmentRefs.pop();
225251
if (ref) {
226252
const fragment = typeTree.fragments[ref];
227-
children = { ...children, ...fragment.children };
228-
if (fragment.fragmentRefs) {
229-
fragmentRefs.push(...fragment.fragmentRefs);
253+
if (fragment) {
254+
// Deeply merge the children
255+
children = this.deepMergeChildren(children, fragment.children);
256+
if (fragment.fragmentRefs) {
257+
fragmentRefs.push(...fragment.fragmentRefs);
258+
}
230259
}
231260
}
232261
}

0 commit comments

Comments
 (0)