@@ -6,20 +6,24 @@ import keyMap from '../jsutils/keyMap';
6
6
import inspect from '../jsutils/inspect' ;
7
7
import invariant from '../jsutils/invariant' ;
8
8
import devAssert from '../jsutils/devAssert' ;
9
- import { type ObjMap } from '../jsutils/ObjMap' ;
9
+ import { type ObjMap , type ReadOnlyObjMap } from '../jsutils/ObjMap' ;
10
10
11
11
import { Kind } from '../language/kinds' ;
12
12
import { type Source } from '../language/source' ;
13
13
import { TokenKind } from '../language/tokenKind' ;
14
14
import { type ParseOptions , parse } from '../language/parser' ;
15
- import { isTypeDefinitionNode } from '../language/predicates' ;
16
15
import { dedentBlockStringValue } from '../language/blockString' ;
17
16
import { type DirectiveLocationEnum } from '../language/directiveLocation' ;
17
+ import {
18
+ isTypeDefinitionNode ,
19
+ isTypeExtensionNode ,
20
+ } from '../language/predicates' ;
18
21
import {
19
22
type Location ,
20
23
type StringValueNode ,
21
24
type DocumentNode ,
22
25
type TypeNode ,
26
+ type TypeExtensionNode ,
23
27
type NamedTypeNode ,
24
28
type SchemaDefinitionNode ,
25
29
type SchemaExtensionNode ,
@@ -127,15 +131,26 @@ export function buildASTSchema(
127
131
assertValidSDL ( documentAST ) ;
128
132
}
129
133
134
+ // Collect the definitions and extensions found in the document.
130
135
let schemaDef : ?SchemaDefinitionNode ;
136
+ const schemaExts : Array < SchemaExtensionNode > = [ ] ;
131
137
const typeDefs : Array < TypeDefinitionNode > = [ ] ;
138
+ const typeExtsMap : ObjMap < Array < TypeExtensionNode >> = Object . create ( null ) ;
132
139
const directiveDefs : Array < DirectiveDefinitionNode > = [ ] ;
133
140
134
141
for ( const def of documentAST . definitions ) {
135
142
if ( def . kind === Kind . SCHEMA_DEFINITION ) {
136
143
schemaDef = def ;
144
+ } else if ( def . kind === Kind . SCHEMA_EXTENSION ) {
145
+ schemaExts . push ( def ) ;
137
146
} else if ( isTypeDefinitionNode ( def ) ) {
138
147
typeDefs . push ( def ) ;
148
+ } else if ( isTypeExtensionNode ( def ) ) {
149
+ const extendedTypeName = def . name . value ;
150
+ const existingTypeExts = typeExtsMap [ extendedTypeName ] ;
151
+ typeExtsMap [ extendedTypeName ] = existingTypeExts
152
+ ? existingTypeExts . concat ( [ def ] )
153
+ : [ def ] ;
139
154
} else if ( def . kind === Kind . DIRECTIVE_DEFINITION ) {
140
155
directiveDefs . push ( def ) ;
141
156
}
@@ -149,7 +164,7 @@ export function buildASTSchema(
149
164
return type ;
150
165
} ) ;
151
166
152
- const typeMap = astBuilder . buildTypeMap ( typeDefs ) ;
167
+ const typeMap = astBuilder . buildTypeMap ( typeDefs , typeExtsMap ) ;
153
168
const operationTypes = schemaDef
154
169
? astBuilder . getOperationTypes ( [ schemaDef ] )
155
170
: {
@@ -394,63 +409,97 @@ export class ASTDefinitionBuilder {
394
409
395
410
buildTypeMap (
396
411
nodes : $ReadOnlyArray < TypeDefinitionNode > ,
412
+ extensionMap : ReadOnlyObjMap < $ReadOnlyArray < TypeExtensionNode >> ,
397
413
) : ObjMap < GraphQLNamedType > {
398
414
const typeMap = Object . create ( null ) ;
399
415
for ( const node of nodes ) {
400
416
const name = node . name . value ;
401
- typeMap [ name ] = stdTypeMap [ name ] || this . _buildType ( node ) ;
417
+ typeMap [ name ] =
418
+ stdTypeMap [ name ] || this . _buildType ( node , extensionMap [ name ] || [ ] ) ;
402
419
}
403
420
return typeMap ;
404
421
}
405
422
406
- _buildType ( astNode : TypeDefinitionNode ) : GraphQLNamedType {
423
+ _buildType (
424
+ astNode : TypeDefinitionNode ,
425
+ extensionNodes : $ReadOnlyArray < TypeExtensionNode > ,
426
+ ) : GraphQLNamedType {
407
427
const name = astNode . name . value ;
408
428
const description = getDescription ( astNode , this . _options ) ;
409
429
410
430
switch ( astNode . kind ) {
411
- case Kind . OBJECT_TYPE_DEFINITION :
431
+ case Kind . OBJECT_TYPE_DEFINITION : {
432
+ const extensionASTNodes = ( extensionNodes : any ) ;
433
+ const allNodes = [ astNode , ...extensionASTNodes ] ;
434
+
412
435
return new GraphQLObjectType ( {
413
436
name,
414
437
description,
415
- interfaces : ( ) => this . buildInterfaces ( [ astNode ] ) ,
416
- fields : ( ) => this . buildFieldMap ( [ astNode ] ) ,
438
+ interfaces : ( ) => this . buildInterfaces ( allNodes ) ,
439
+ fields : ( ) => this . buildFieldMap ( allNodes ) ,
417
440
astNode,
441
+ extensionASTNodes,
418
442
} ) ;
419
- case Kind . INTERFACE_TYPE_DEFINITION :
443
+ }
444
+ case Kind . INTERFACE_TYPE_DEFINITION : {
445
+ const extensionASTNodes = ( extensionNodes : any ) ;
446
+ const allNodes = [ astNode , ...extensionASTNodes ] ;
447
+
420
448
return new GraphQLInterfaceType ( {
421
449
name,
422
450
description,
423
- interfaces : ( ) => this . buildInterfaces ( [ astNode ] ) ,
424
- fields : ( ) => this . buildFieldMap ( [ astNode ] ) ,
451
+ interfaces : ( ) => this . buildInterfaces ( allNodes ) ,
452
+ fields : ( ) => this . buildFieldMap ( allNodes ) ,
425
453
astNode,
454
+ extensionASTNodes,
426
455
} ) ;
427
- case Kind . ENUM_TYPE_DEFINITION :
456
+ }
457
+ case Kind . ENUM_TYPE_DEFINITION : {
458
+ const extensionASTNodes = ( extensionNodes : any ) ;
459
+ const allNodes = [ astNode , ...extensionASTNodes ] ;
460
+
428
461
return new GraphQLEnumType ( {
429
462
name,
430
463
description,
431
- values : this . buildEnumValueMap ( [ astNode ] ) ,
464
+ values : this . buildEnumValueMap ( allNodes ) ,
432
465
astNode,
466
+ extensionASTNodes,
433
467
} ) ;
434
- case Kind . UNION_TYPE_DEFINITION :
468
+ }
469
+ case Kind . UNION_TYPE_DEFINITION : {
470
+ const extensionASTNodes = ( extensionNodes : any ) ;
471
+ const allNodes = [ astNode , ...extensionASTNodes ] ;
472
+
435
473
return new GraphQLUnionType ( {
436
474
name,
437
475
description,
438
- types : ( ) => this . buildUnionTypes ( [ astNode ] ) ,
476
+ types : ( ) => this . buildUnionTypes ( allNodes ) ,
439
477
astNode,
478
+ extensionASTNodes,
440
479
} ) ;
441
- case Kind . SCALAR_TYPE_DEFINITION :
480
+ }
481
+ case Kind . SCALAR_TYPE_DEFINITION : {
482
+ const extensionASTNodes = ( extensionNodes : any ) ;
483
+
442
484
return new GraphQLScalarType ( {
443
485
name,
444
486
description,
445
487
astNode,
488
+ extensionASTNodes,
446
489
} ) ;
447
- case Kind . INPUT_OBJECT_TYPE_DEFINITION :
490
+ }
491
+ case Kind . INPUT_OBJECT_TYPE_DEFINITION : {
492
+ const extensionASTNodes = ( extensionNodes : any ) ;
493
+ const allNodes = [ astNode , ...extensionASTNodes ] ;
494
+
448
495
return new GraphQLInputObjectType ( {
449
496
name,
450
497
description,
451
- fields : ( ) => this . buildInputFieldMap ( [ astNode ] ) ,
498
+ fields : ( ) => this . buildInputFieldMap ( allNodes ) ,
452
499
astNode,
500
+ extensionASTNodes,
453
501
} ) ;
502
+ }
454
503
}
455
504
456
505
// Not reachable. All possible type definition nodes have been considered.
0 commit comments