Skip to content

Commit 43c4af1

Browse files
committed
Robust type info
There are possibilities for errors during validation if a schema is not valid when provided to TypeInfo. Most checks for validity existed, but some did not. This asks flow to make those checks required and adds the remaining ones. Important now that we allow construction of invalid schema.
1 parent 461392d commit 43c4af1

File tree

1 file changed

+29
-15
lines changed

1 file changed

+29
-15
lines changed

src/utilities/TypeInfo.js

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -113,53 +113,61 @@ export class TypeInfo {
113113
// Flow does not yet handle this case.
114114
enter(node: any /* ASTNode */) {
115115
const schema = this._schema;
116+
// Note: many of the types below are explicitly typed as "mixed" to drop
117+
// any assumptions of a valid schema to ensure runtime types are properly
118+
// checked before continuing since TypeInfo is used as part of validation
119+
// which occurs before guarantees of schema and document validity.
116120
switch (node.kind) {
117121
case Kind.SELECTION_SET:
118-
const namedType = getNamedType(this.getType());
122+
const namedType: mixed = getNamedType(this.getType());
119123
this._parentTypeStack.push(
120124
isCompositeType(namedType) ? namedType : undefined,
121125
);
122126
break;
123127
case Kind.FIELD:
124128
const parentType = this.getParentType();
125129
let fieldDef;
130+
let fieldType: mixed;
126131
if (parentType) {
127132
fieldDef = this._getFieldDef(schema, parentType, node);
133+
if (fieldDef) {
134+
fieldType = fieldDef.type;
135+
}
128136
}
129137
this._fieldDefStack.push(fieldDef);
130-
this._typeStack.push(fieldDef && fieldDef.type);
138+
this._typeStack.push(isOutputType(fieldType) ? fieldType : undefined);
131139
break;
132140
case Kind.DIRECTIVE:
133141
this._directive = schema.getDirective(node.name.value);
134142
break;
135143
case Kind.OPERATION_DEFINITION:
136-
let type;
144+
let type: mixed;
137145
if (node.operation === 'query') {
138146
type = schema.getQueryType();
139147
} else if (node.operation === 'mutation') {
140148
type = schema.getMutationType();
141149
} else if (node.operation === 'subscription') {
142150
type = schema.getSubscriptionType();
143151
}
144-
this._typeStack.push(type);
152+
this._typeStack.push(isOutputType(type) ? type : undefined);
145153
break;
146154
case Kind.INLINE_FRAGMENT:
147155
case Kind.FRAGMENT_DEFINITION:
148156
const typeConditionAST = node.typeCondition;
149-
const outputType = typeConditionAST
157+
const outputType: mixed = typeConditionAST
150158
? typeFromAST(schema, typeConditionAST)
151159
: getNamedType(this.getType());
152160
this._typeStack.push(isOutputType(outputType) ? outputType : undefined);
153161
break;
154162
case Kind.VARIABLE_DEFINITION:
155-
const inputType = typeFromAST(schema, node.type);
163+
const inputType: mixed = typeFromAST(schema, node.type);
156164
this._inputTypeStack.push(
157165
isInputType(inputType) ? inputType : undefined,
158166
);
159167
break;
160168
case Kind.ARGUMENT:
161169
let argDef;
162-
let argType;
170+
let argType: mixed;
163171
const fieldOrDirective = this.getDirective() || this.getFieldDef();
164172
if (fieldOrDirective) {
165173
argDef = find(
@@ -171,25 +179,31 @@ export class TypeInfo {
171179
}
172180
}
173181
this._argument = argDef;
174-
this._inputTypeStack.push(argType);
182+
this._inputTypeStack.push(isInputType(argType) ? argType : undefined);
175183
break;
176184
case Kind.LIST:
177-
const listType = getNullableType(this.getInputType());
185+
const listType: mixed = getNullableType(this.getInputType());
178186
this._inputTypeStack.push(
179-
isListType(listType) ? listType.ofType : undefined,
187+
isListType(listType) && isInputType(listType.ofType)
188+
? listType.ofType
189+
: undefined,
180190
);
181191
break;
182192
case Kind.OBJECT_FIELD:
183-
const objectType = getNamedType(this.getInputType());
184-
let fieldType;
193+
const objectType: mixed = getNamedType(this.getInputType());
194+
let inputFieldType: mixed;
185195
if (isInputObjectType(objectType)) {
186196
const inputField = objectType.getFields()[node.name.value];
187-
fieldType = inputField ? inputField.type : undefined;
197+
if (inputField) {
198+
inputFieldType = inputField.type;
199+
}
188200
}
189-
this._inputTypeStack.push(fieldType);
201+
this._inputTypeStack.push(
202+
isInputType(inputFieldType) ? inputFieldType : undefined,
203+
);
190204
break;
191205
case Kind.ENUM:
192-
const enumType = getNamedType(this.getInputType());
206+
const enumType: mixed = getNamedType(this.getInputType());
193207
let enumValue;
194208
if (isEnumType(enumType)) {
195209
enumValue = enumType.getValue(node.value);

0 commit comments

Comments
 (0)