Skip to content

Commit 0ad0e46

Browse files
committed
buildSchema: Fix infinite loop with recursive union
1 parent f370fc3 commit 0ad0e46

File tree

3 files changed

+19
-8
lines changed

3 files changed

+19
-8
lines changed

src/utilities/__tests__/buildASTSchema-test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,18 @@ describe('Schema Builder', () => {
356356
expect(output).to.equal(body);
357357
});
358358

359+
it('Can build recursive Union', () => {
360+
const schema = buildSchema(dedent`
361+
union Hello = Hello
362+
363+
type Query {
364+
hello: Hello
365+
}
366+
`);
367+
const errors = validateSchema(schema);
368+
expect(errors.length).to.be.above(0);
369+
});
370+
359371
it('Specifying Union type using __typename', () => {
360372
const schema = buildSchema(dedent`
361373
type Query {

src/utilities/buildASTSchema.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -244,10 +244,6 @@ export class ASTDefinitionBuilder {
244244
);
245245
}
246246

247-
buildTypes(nodes: $ReadOnlyArray<NamedTypeNode>): Array<GraphQLNamedType> {
248-
return nodes.map(node => this.buildType(node));
249-
}
250-
251247
buildType(node: NamedTypeNode | TypeDefinitionNode): GraphQLNamedType {
252248
const typeName = node.name.value;
253249
if (!this._cache[typeName]) {
@@ -345,15 +341,17 @@ export class ASTDefinitionBuilder {
345341
}
346342

347343
_makeTypeDef(def: ObjectTypeDefinitionNode) {
348-
const interfaces = def.interfaces;
344+
const interfaces: ?$ReadOnlyArray<NamedTypeNode> = def.interfaces;
349345
return new GraphQLObjectType({
350346
name: def.name.value,
351347
description: getDescription(def, this._options),
352348
fields: () => this._makeFieldDefMap(def),
353349
// Note: While this could make early assertions to get the correctly
354350
// typed values, that would throw immediately while type system
355351
// validation with validateSchema() will produce more actionable results.
356-
interfaces: interfaces ? () => (this.buildTypes(interfaces): any) : [],
352+
interfaces: interfaces
353+
? () => interfaces.map(ref => (this.buildType(ref): any))
354+
: [],
357355
astNode: def,
358356
});
359357
}
@@ -407,13 +405,14 @@ export class ASTDefinitionBuilder {
407405
}
408406

409407
_makeUnionDef(def: UnionTypeDefinitionNode) {
408+
const types: ?$ReadOnlyArray<NamedTypeNode> = def.types;
410409
return new GraphQLUnionType({
411410
name: def.name.value,
412411
description: getDescription(def, this._options),
413412
// Note: While this could make assertions to get the correctly typed
414413
// values below, that would throw immediately while type system
415414
// validation with validateSchema() will produce more actionable results.
416-
types: def.types ? (this.buildTypes(def.types): any) : [],
415+
types: types ? () => types.map(ref => (this.buildType(ref): any)) : [],
417416
astNode: def,
418417
});
419418
}

src/utilities/extendSchema.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ export function extendSchema(
243243
// that any type not directly referenced by a field will get created.
244244
...objectValues(schema.getTypeMap()).map(type => extendNamedType(type)),
245245
// Do the same with new types.
246-
...astBuilder.buildTypes(objectValues(typeDefinitionMap)),
246+
...objectValues(typeDefinitionMap).map(type => astBuilder.buildType(type)),
247247
];
248248

249249
// Support both original legacy names and extended legacy names.

0 commit comments

Comments
 (0)