@@ -64,6 +64,7 @@ import {
6464 GraphQLOneOfDirective ,
6565 GraphQLSpecifiedByDirective ,
6666 isSpecifiedDirective ,
67+ specifiedDirectives ,
6768} from '../type/directives.js' ;
6869import {
6970 introspectionTypes ,
@@ -116,7 +117,7 @@ export function extendSchema(
116117 }
117118
118119 const schemaConfig = schema . toConfig ( ) ;
119- const extendedConfig = extendSchemaImpl ( schemaConfig , documentAST , options ) ;
120+ const extendedConfig = extendSchemaImpl ( documentAST , schemaConfig , options ) ;
120121 return schemaConfig === extendedConfig
121122 ? schema
122123 : new GraphQLSchema ( extendedConfig ) ;
@@ -126,10 +127,19 @@ export function extendSchema(
126127 * @internal
127128 */
128129export function extendSchemaImpl (
129- schemaConfig : GraphQLSchemaNormalizedConfig ,
130130 documentAST : DocumentNode ,
131+ originalSchemaConfig : GraphQLSchemaNormalizedConfig | undefined ,
131132 options ?: Options ,
132133) : GraphQLSchemaNormalizedConfig {
134+ const schemaConfig : GraphQLSchemaNormalizedConfig = originalSchemaConfig ?? {
135+ description : undefined ,
136+ types : [ ] ,
137+ directives : [ ...specifiedDirectives ] ,
138+ extensions : Object . create ( null ) ,
139+ extensionASTNodes : [ ] ,
140+ assumeValid : false ,
141+ } ;
142+
133143 // Collect the type definitions and extensions found in the document.
134144 const typeDefs : Array < TypeDefinitionNode > = [ ] ;
135145
@@ -211,7 +221,12 @@ export function extendSchemaImpl(
211221 // If this document contains no new types, extensions, or directives then
212222 // return the same unmodified GraphQLSchema instance.
213223 if ( ! isSchemaChanged ) {
214- return schemaConfig ;
224+ return originalSchemaConfig
225+ ? originalSchemaConfig
226+ : {
227+ ...schemaConfig ,
228+ directives : [ ...specifiedDirectives ] ,
229+ } ;
215230 }
216231
217232 const typeMap = new Map < string , GraphQLNamedType > (
@@ -230,19 +245,31 @@ export function extendSchemaImpl(
230245 subscription :
231246 schemaConfig . subscription && replaceNamedType ( schemaConfig . subscription ) ,
232247 // Then, incorporate schema definition and all schema extensions.
233- ...( schemaDef && getOperationTypes ( [ schemaDef ] ) ) ,
248+ ...( schemaDef
249+ ? getOperationTypes ( [ schemaDef ] )
250+ : ! originalSchemaConfig && getDefaultOperationTypes ( ) ) ,
234251 ...getOperationTypes ( schemaExtensions ) ,
235252 } ;
236253
254+ const newDirectives = directiveDefs . map ( buildDirective ) ;
255+ const directives = originalSchemaConfig
256+ ? [ ...schemaConfig . directives . map ( replaceDirective ) , ...newDirectives ]
257+ : [
258+ ...newDirectives ,
259+ // If specified directives were not explicitly declared, add them.
260+ ...specifiedDirectives . filter ( ( stdDirective ) =>
261+ newDirectives . every (
262+ ( directive ) => directive . name !== stdDirective . name ,
263+ ) ,
264+ ) ,
265+ ] ;
266+
237267 // Then produce and return a Schema config with these types.
238268 return {
239269 description : schemaDef ?. description ?. value ?? schemaConfig . description ,
240270 ...operationTypes ,
241271 types : Array . from ( typeMap . values ( ) ) ,
242- directives : [
243- ...schemaConfig . directives . map ( replaceDirective ) ,
244- ...directiveDefs . map ( buildDirective ) ,
245- ] ,
272+ directives,
246273 extensions : schemaConfig . extensions ,
247274 astNode : schemaDef ?? schemaConfig . astNode ,
248275 extensionASTNodes : schemaConfig . extensionASTNodes . concat ( schemaExtensions ) ,
@@ -431,6 +458,27 @@ export function extendSchemaImpl(
431458 } ;
432459 }
433460
461+ function getDefaultOperationTypes ( ) : {
462+ query ?: Maybe < GraphQLObjectType > ;
463+ mutation ?: Maybe < GraphQLObjectType > ;
464+ subscription ?: Maybe < GraphQLObjectType > ;
465+ } {
466+ const opTypes = { } ;
467+ for ( const typeName of [ 'Query' , 'Mutation' , 'Subscription' ] ) {
468+ const operationType = typeMap . get ( typeName ) ;
469+
470+ if ( operationType ) {
471+ // Note: While this could make early assertions to get the correctly
472+ // typed values below, that would throw immediately while type system
473+ // validation with validateSchema() will produce more actionable results.
474+ // @ts -expect-error
475+ opTypes [ typeName . toLowerCase ( ) ] = operationType ;
476+ }
477+ }
478+
479+ return opTypes ;
480+ }
481+
434482 function getOperationTypes (
435483 nodes : ReadonlyArray < SchemaDefinitionNode | SchemaExtensionNode > ,
436484 ) : {
0 commit comments