Ver Fonte

fix(core): Fix undefined type issue with nested fragment spreads (#3351)

Jan Hecker há 11 meses atrás
pai
commit
d0c04542ad
1 ficheiros alterados com 50 adições e 21 exclusões
  1. 50 21
      packages/core/src/api/common/graphql-value-transformer.ts

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

@@ -188,30 +188,56 @@ export class GraphqlValueTransformer {
         inputType: GraphQLInputObjectType,
         inputType: GraphQLInputObjectType,
         parent: TypeTreeNode,
         parent: TypeTreeNode,
     ): { [name: string]: TypeTreeNode } {
     ): { [name: string]: TypeTreeNode } {
-        return Object.entries(inputType.getFields()).reduce((result, [key, field]) => {
-            const namedType = getNamedType(field.type);
-            if (namedType === parent.type) {
-                // prevent recursion-induced stack overflow
-                return result;
-            }
-            const child: TypeTreeNode = {
-                type: namedType,
-                isList: this.isList(field.type),
-                parent,
-                fragmentRefs: [],
-                children: {},
-            };
-            if (isInputObjectType(namedType)) {
-                child.children = this.getChildrenTreeNodes(namedType, child);
-            }
-            return { ...result, [key]: child };
-        }, {} as { [name: string]: TypeTreeNode });
+        return Object.entries(inputType.getFields()).reduce(
+            (result, [key, field]) => {
+                const namedType = getNamedType(field.type);
+                if (namedType === parent.type) {
+                    // prevent recursion-induced stack overflow
+                    return result;
+                }
+                const child: TypeTreeNode = {
+                    type: namedType,
+                    isList: this.isList(field.type),
+                    parent,
+                    fragmentRefs: [],
+                    children: {},
+                };
+                if (isInputObjectType(namedType)) {
+                    child.children = this.getChildrenTreeNodes(namedType, child);
+                }
+                return { ...result, [key]: child };
+            },
+            {} as { [name: string]: TypeTreeNode },
+        );
     }
     }
 
 
     private isList(t: any): boolean {
     private isList(t: any): boolean {
         return isListType(t) || (isNonNullType(t) && isListType(t.ofType));
         return isListType(t) || (isNonNullType(t) && isListType(t.ofType));
     }
     }
 
 
+    private deepMergeChildren(
+        target: { [name: string]: TypeTreeNode },
+        source: { [name: string]: TypeTreeNode },
+    ): { [name: string]: TypeTreeNode } {
+        const merged = { ...target };
+        for (const key in source) {
+            if (source.hasOwnProperty(key)) {
+                if (merged[key]) {
+                    // If the key already exists, merge recursively
+                    if (source[key].children && Object.keys(source[key].children).length > 0) {
+                        merged[key].children = this.deepMergeChildren(
+                            merged[key].children,
+                            source[key].children,
+                        );
+                    }
+                } else {
+                    merged[key] = source[key];
+                }
+            }
+        }
+        return merged;
+    }
+
     private getTypeNodeByPath(typeTree: TypeTree, path: Array<string | number>): TypeTreeNode | undefined {
     private getTypeNodeByPath(typeTree: TypeTree, path: Array<string | number>): TypeTreeNode | undefined {
         let targetNode: TypeTreeNode | undefined = typeTree.operation;
         let targetNode: TypeTreeNode | undefined = typeTree.operation;
         for (const segment of path) {
         for (const segment of path) {
@@ -224,9 +250,12 @@ export class GraphqlValueTransformer {
                             const ref = fragmentRefs.pop();
                             const ref = fragmentRefs.pop();
                             if (ref) {
                             if (ref) {
                                 const fragment = typeTree.fragments[ref];
                                 const fragment = typeTree.fragments[ref];
-                                children = { ...children, ...fragment.children };
-                                if (fragment.fragmentRefs) {
-                                    fragmentRefs.push(...fragment.fragmentRefs);
+                                if (fragment) {
+                                    // Deeply merge the children
+                                    children = this.deepMergeChildren(children, fragment.children);
+                                    if (fragment.fragmentRefs) {
+                                        fragmentRefs.push(...fragment.fragmentRefs);
+                                    }
                                 }
                                 }
                             }
                             }
                         }
                         }