Skip to content

Commit b50a172

Browse files
committed
Fix: Type safety for TypeInfo.
Previously we just coerce these values to the expected types, record them and carry on. However that is not safe and results in TypeInfo potentially returning invalid types when traversing an invalid query. This instead checks the type before inserting it, upholding type safety. There was one validator which was taking advantage of the unsafe behavior, so I re-wrote it slightly to be type safe.
1 parent 8122ba7 commit b50a172

File tree

2 files changed

+27
-15
lines changed

2 files changed

+27
-15
lines changed

src/utilities/TypeInfo.js

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import {
1919
GraphQLInputObjectType,
2020
GraphQLEnumType,
2121
GraphQLList,
22+
isInputType,
23+
isOutputType,
2224
} from '../type/definition';
2325
import type {
2426
GraphQLType,
@@ -117,12 +119,11 @@ export class TypeInfo {
117119
switch (node.kind) {
118120
case Kind.SELECTION_SET:
119121
const namedType = getNamedType(this.getType());
120-
let compositeType: ?GraphQLCompositeType;
121-
if (isCompositeType(namedType)) {
122-
// isCompositeType is a type refining predicate, so this is safe.
123-
compositeType = ((namedType: any): GraphQLCompositeType);
124-
}
125-
this._parentTypeStack.push(compositeType);
122+
this._parentTypeStack.push(
123+
isCompositeType(namedType) ?
124+
((namedType: any): GraphQLCompositeType) :
125+
undefined
126+
);
126127
break;
127128
case Kind.FIELD:
128129
const parentType = this.getParentType();
@@ -153,11 +154,19 @@ export class TypeInfo {
153154
const outputType = typeConditionAST ?
154155
typeFromAST(schema, typeConditionAST) :
155156
this.getType();
156-
this._typeStack.push(((outputType: any): GraphQLOutputType));
157+
this._typeStack.push(
158+
isOutputType(outputType) ?
159+
((outputType: any): GraphQLOutputType) :
160+
undefined
161+
);
157162
break;
158163
case Kind.VARIABLE_DEFINITION:
159164
const inputType = typeFromAST(schema, node.type);
160-
this._inputTypeStack.push(((inputType: any): GraphQLInputType));
165+
this._inputTypeStack.push(
166+
isInputType(inputType) ?
167+
((inputType: any): GraphQLInputType) :
168+
undefined
169+
);
161170
break;
162171
case Kind.ARGUMENT:
163172
let argDef;

src/validation/rules/FragmentsOnCompositeTypes.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { GraphQLError } from '../../error';
1313
import { print } from '../../language/printer';
1414
import { isCompositeType } from '../../type/definition';
1515
import type { GraphQLType } from '../../type/definition';
16+
import { typeFromAST } from '../../utilities/typeFromAST';
1617

1718

1819
export function inlineFragmentOnNonCompositeErrorMessage(
@@ -39,16 +40,18 @@ export function fragmentOnNonCompositeErrorMessage(
3940
export function FragmentsOnCompositeTypes(context: ValidationContext): any {
4041
return {
4142
InlineFragment(node) {
42-
const type = context.getType();
43-
if (node.typeCondition && type && !isCompositeType(type)) {
44-
context.reportError(new GraphQLError(
45-
inlineFragmentOnNonCompositeErrorMessage(print(node.typeCondition)),
46-
[ node.typeCondition ]
47-
));
43+
if (node.typeCondition) {
44+
const type = typeFromAST(context.getSchema(), node.typeCondition);
45+
if (type && !isCompositeType(type)) {
46+
context.reportError(new GraphQLError(
47+
inlineFragmentOnNonCompositeErrorMessage(print(node.typeCondition)),
48+
[ node.typeCondition ]
49+
));
50+
}
4851
}
4952
},
5053
FragmentDefinition(node) {
51-
const type = context.getType();
54+
const type = typeFromAST(context.getSchema(), node.typeCondition);
5255
if (type && !isCompositeType(type)) {
5356
context.reportError(new GraphQLError(
5457
fragmentOnNonCompositeErrorMessage(

0 commit comments

Comments
 (0)