@@ -11,20 +11,13 @@ import {
1111 GraphQLObjectType ,
1212} from 'graphql/type/definition' ;
1313
14- import {
15- type TypeDefinitionNode ,
16- type ASTNode ,
17- } from 'graphql/language/ast' ;
14+ import { type TypeDefinitionNode , type ASTNode } from 'graphql/language/ast' ;
1815
1916import { specifiedDirectives } from 'graphql/type/directives' ;
2017import find from 'graphql/jsutils/find' ;
2118import invariant from 'graphql/jsutils/invariant' ;
2219import { isEqualType , isTypeSubTypeOf } from 'graphql/utilities/typeComparators' ;
23- import {
24- type GQLError ,
25- SEVERITY ,
26- newGQLError ,
27- } from '../../shared/GQLError' ;
20+ import { type GQLError , SEVERITY , newGQLError } from '../../shared/GQLError' ;
2821import { PLACEHOLDER_TYPES } from './PlaceholderTypes' ;
2922import getNamedTypeNode from './getNamedTypeNode' ;
3023
@@ -73,7 +66,9 @@ export default class _GQLSchema {
7366
7467 // create typeMap and implementations map
7568 types.forEach((type) => {
76- if ( type ) { this . _typeMap [ type . name ] = type ; }
69+ if ( type ) {
70+ this . _typeMap [ type . name ] = type ;
71+ }
7772 // // NOTE: dont remove type.getFields()
7873 // // calling to resolve thunks which will add more errors
7974 // // also wrapping in try catch to suppress errors thrown inside getFields function
@@ -82,16 +77,12 @@ export default class _GQLSchema {
8277 try {
8378 // $FlowDisableNextLine
8479 type . getFields ( ) ; // resolve thunk
85- } catch (e) { } // eslint-disable-line no-empty
80+ } catch (e) { } // eslint-disable-line no-empty
8681 }
8782
8883 if ( type instanceof GQLObjectType ) {
8984 const _type = type ;
9085 type . getInterfaces ( ) . forEach ( ( iface ) => {
91- this . _errors . push (
92- // eslint-disable-next-line no-use-before-define
93- ...assertObjectImplementsInterface ( ( this : any ) , _type , iface ) ,
94- ) ;
9586 const impls = this . _implementations [ iface . name ] ;
9687 if ( impls ) {
9788 impls . push ( _type ) ;
@@ -101,6 +92,19 @@ export default class _GQLSchema {
10192 } ) ;
10293 }
10394 } ) ;
95+
96+ // validate GQLObjectType correctly implements interfaces
97+ Object . keys ( this . _typeMap ) . forEach ( ( typeName ) => {
98+ const type = this . _typeMap [ typeName ] ;
99+ if ( type instanceof GQLObjectType ) {
100+ type . getInterfaces ( ) . forEach ( ( iface ) => {
101+ this . _errors . push (
102+ // eslint-disable-next-line no-use-before-define
103+ ...assertObjectImplementsInterface ( ( this : any ) , type , iface ) ,
104+ ) ;
105+ } ) ;
106+ }
107+ } ) ;
104108 }
105109
106110 getQueryType ( ) : ?GQLObjectType {
@@ -143,10 +147,7 @@ export default class _GQLSchema {
143147 return (this._implementations[abstractType.name]: any);
144148 }
145149
146- isPossibleType (
147- abstractType : GraphQLAbstractType ,
148- possibleType : GraphQLObjectType ,
149- ) : boolean {
150+ isPossibleType ( abstractType : GraphQLAbstractType , possibleType : GraphQLObjectType ) : boolean {
150151 let possibleTypeMap = this . _possibleTypeMap ;
151152 if ( ! possibleTypeMap ) {
152153 possibleTypeMap = Object . create ( null ) ;
@@ -158,14 +159,13 @@ export default class _GQLSchema {
158159 invariant (
159160 Array . isArray ( possibleTypes ) ,
160161 `Could not find possible implementing types for ${ abstractType . name } ` +
161- 'in schema. Check that schema.types is defined and is an array of ' +
162- 'all possible types in the schema.' ,
162+ 'in schema. Check that schema.types is defined and is an array of ' +
163+ 'all possible types in the schema.' ,
164+ ) ;
165+ possibleTypeMap [ abstractType . name ] = possibleTypes . reduce (
166+ ( map , type ) => ( ( map [ type . name ] = true ) , map ) , // eslint-disable-line
167+ Object . create ( null ) ,
163168 ) ;
164- possibleTypeMap [ abstractType . name ] =
165- possibleTypes . reduce (
166- ( map , type ) => ( ( map [ type . name ] = true ) , map ) , // eslint-disable-line
167- Object . create ( null ) ,
168- ) ;
169169 }
170170
171171 return Boolean ( possibleTypeMap [ abstractType . name ] [ possibleType . name ] ) ;
@@ -209,13 +209,15 @@ function assertObjectImplementsInterface(
209209 // Assert interface field type is satisfied by object field type, by being
210210 // a valid subtype. (covariant)
211211 if (!isTypeSubTypeOf((schema: any), (objectField.type: any), (ifaceField.type: any))) {
212- errors . push ( newGQLError (
213- `${ iface . name } .${ fieldName } expects type "${ String ( ifaceField . type ) } " ` +
214- 'but ' +
215- `${ object . name } .${ fieldName } provides type "${ String ( objectField . type ) } ".` ,
216- [ getNamedTypeNode ( objectField . node . type ) ] ,
217- SEVERITY . error ,
218- ) ) ;
212+ errors . push (
213+ newGQLError (
214+ `${ iface . name } .${ fieldName } expects type "${ String ( ifaceField . type ) } " ` +
215+ 'but ' +
216+ `${ object . name } .${ fieldName } provides type "${ String ( objectField . type ) } ".` ,
217+ [ getNamedTypeNode ( objectField . node . type ) ] ,
218+ SEVERITY . error ,
219+ ) ,
220+ ) ;
219221 }
220222
221223 // Assert each interface field arg is implemented.
@@ -225,26 +227,30 @@ function assertObjectImplementsInterface(
225227
226228 // Assert interface field arg exists on object field.
227229 if ( ! objectArg ) {
228- errors . push ( newGQLError (
229- `${ iface . name } .${ fieldName } expects argument "${ argName } " but ` +
230- `${ object . name } .${ fieldName } does not provide it.` ,
231- [ objectField . node ] ,
232- SEVERITY . error ,
233- ) ) ;
230+ errors . push (
231+ newGQLError (
232+ `${ iface . name } .${ fieldName } expects argument "${ argName } " but ` +
233+ `${ object . name } .${ fieldName } does not provide it.` ,
234+ [ objectField . node ] ,
235+ SEVERITY . error ,
236+ ) ,
237+ ) ;
234238 return ;
235239 }
236240
237241 // Assert interface field arg type matches object field arg type.
238242 // (invariant)
239243 if (!isEqualType((ifaceArg.type: any), (objectArg.type: any))) {
240- errors . push ( newGQLError (
241- `${ iface . name } .${ fieldName } (${ argName } :) expects type ` +
242- `"${ String ( ifaceArg . type ) } " but ` +
243- `${ object . name } .${ fieldName } (${ argName } :) provides type ` +
244- `"${ String ( objectArg . type ) } ".` ,
245- [ getNamedTypeNode ( objectArg . node . type ) ] ,
246- SEVERITY . error ,
247- ) ) ;
244+ errors . push (
245+ newGQLError (
246+ `${ iface . name } .${ fieldName } (${ argName } :) expects type ` +
247+ `"${ String ( ifaceArg . type ) } " but ` +
248+ `${ object . name } .${ fieldName } (${ argName } :) provides type ` +
249+ `"${ String ( objectArg . type ) } ".` ,
250+ [ getNamedTypeNode ( objectArg . node . type ) ] ,
251+ SEVERITY . error ,
252+ ) ,
253+ ) ;
248254 }
249255 } ) ;
250256
@@ -253,23 +259,27 @@ function assertObjectImplementsInterface(
253259 const argName = objectArg . name ;
254260 const ifaceArg = find ( ifaceField . args , ( arg ) => arg . name === argName ) ;
255261 if ( ! ifaceArg && objectArg . type instanceof GraphQLNonNull ) {
256- errors . push ( newGQLError (
257- `${ object . name } .${ fieldName } (${ argName } :) is of required type ` +
258- `"${ String ( objectArg . type ) } " but is not also provided by the ` +
259- `interface ${ iface . name } .${ fieldName } .` ,
260- [ objectArg . node ] ,
261- SEVERITY . error ,
262- ) ) ;
262+ errors . push (
263+ newGQLError (
264+ `${ object . name } .${ fieldName } (${ argName } :) is of required type ` +
265+ `"${ String ( objectArg . type ) } " but is not also provided by the ` +
266+ `interface ${ iface . name } .${ fieldName } .` ,
267+ [ objectArg . node ] ,
268+ SEVERITY . error ,
269+ ) ,
270+ ) ;
263271 }
264272 } ) ;
265273 } ) ;
266274
267275 if ( missingFields . length > 0 ) {
268- errors . push ( newGQLError (
269- `Missing interface fields [${ missingFields . map ( ( field ) => field . name ) . join ( ', ' ) } ]` ,
270- [ object . node ] ,
271- SEVERITY . error ,
272- ) ) ;
276+ errors . push (
277+ newGQLError (
278+ `Missing interface fields [${ missingFields . map ( ( field ) => field . name ) . join ( ', ' ) } ]` ,
279+ [ object . node ] ,
280+ SEVERITY . error ,
281+ ) ,
282+ ) ;
273283 }
274284
275285 return errors;
0 commit comments