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.

ref: graphql/graphql-js#1143
This commit is contained in:
Daniel Tschinder 2018-02-15 12:22:29 +01:00
parent 97e8a9e200
commit fde7df534d

View File

@ -4,6 +4,7 @@ namespace GraphQL\Utils;
use GraphQL\Error\InvariantViolation; use GraphQL\Error\InvariantViolation;
use GraphQL\Error\Warning; use GraphQL\Error\Warning;
use GraphQL\Language\AST\FieldNode; use GraphQL\Language\AST\FieldNode;
use GraphQL\Language\AST\ListType;
use GraphQL\Language\AST\ListTypeNode; use GraphQL\Language\AST\ListTypeNode;
use GraphQL\Language\AST\NamedTypeNode; use GraphQL\Language\AST\NamedTypeNode;
use GraphQL\Language\AST\Node; use GraphQL\Language\AST\Node;
@ -296,6 +297,10 @@ class TypeInfo
{ {
$schema = $this->schema; $schema = $this->schema;
// Note: many of the types below are explicitly typed as "mixed" to drop
// any assumptions of a valid schema to ensure runtime types are properly
// checked before continuing since TypeInfo is used as part of validation
// which occurs before guarantees of schema and document validity.
switch ($node->kind) { switch ($node->kind) {
case NodeKind::SELECTION_SET: case NodeKind::SELECTION_SET:
$namedType = Type::getNamedType($this->getType()); $namedType = Type::getNamedType($this->getType());
@ -308,8 +313,12 @@ class TypeInfo
if ($parentType) { if ($parentType) {
$fieldDef = self::getFieldDefinition($schema, $parentType, $node); $fieldDef = self::getFieldDefinition($schema, $parentType, $node);
} }
$this->fieldDefStack[] = $fieldDef; // push $fieldType = null;
$this->typeStack[] = $fieldDef ? $fieldDef->getType() : null; // push if ($fieldDef) {
$fieldType = $fieldDef->getType();
}
$this->fieldDefStack[] = $fieldDef;
$this->typeStack[] = Type::isOutputType($fieldType) ? $fieldType : null;
break; break;
case NodeKind::DIRECTIVE: case NodeKind::DIRECTIVE:
@ -325,14 +334,14 @@ class TypeInfo
} else if ($node->operation === 'subscription') { } else if ($node->operation === 'subscription') {
$type = $schema->getSubscriptionType(); $type = $schema->getSubscriptionType();
} }
$this->typeStack[] = $type; // push $this->typeStack[] = Type::isOutputType($type) ? $type : null;
break; break;
case NodeKind::INLINE_FRAGMENT: case NodeKind::INLINE_FRAGMENT:
case NodeKind::FRAGMENT_DEFINITION: case NodeKind::FRAGMENT_DEFINITION:
$typeConditionNode = $node->typeCondition; $typeConditionNode = $node->typeCondition;
$outputType = $typeConditionNode ? self::typeFromAST($schema, $typeConditionNode) : Type::getNamedType($this->getType()); $outputType = $typeConditionNode ? self::typeFromAST($schema, $typeConditionNode) : Type::getNamedType($this->getType());
$this->typeStack[] = Type::isOutputType($outputType) ? $outputType : null; // push $this->typeStack[] = Type::isOutputType($outputType) ? $outputType : null;
break; break;
case NodeKind::VARIABLE_DEFINITION: case NodeKind::VARIABLE_DEFINITION:
@ -350,23 +359,28 @@ class TypeInfo
} }
} }
$this->argument = $argDef; $this->argument = $argDef;
$this->inputTypeStack[] = $argType; // push $this->inputTypeStack[] = Type::isInputType($argType) ? $argType : null;
break; break;
case NodeKind::LST: case NodeKind::LST:
$listType = Type::getNullableType($this->getInputType()); $listType = Type::getNullableType($this->getInputType());
$this->inputTypeStack[] = ($listType instanceof ListOfType ? $listType->getWrappedType() : null); // push $itemType = null;
if ($itemType instanceof ListType) {
$itemType = $listType->getWrappedType();
}
$this->inputTypeStack[] = Type::isInputType($itemType) ? $itemType : null;
break; break;
case NodeKind::OBJECT_FIELD: case NodeKind::OBJECT_FIELD:
$objectType = Type::getNamedType($this->getInputType()); $objectType = Type::getNamedType($this->getInputType());
$fieldType = null; $fieldType = null;
$inputFieldType = null;
if ($objectType instanceof InputObjectType) { if ($objectType instanceof InputObjectType) {
$tmp = $objectType->getFields(); $tmp = $objectType->getFields();
$inputField = isset($tmp[$node->name->value]) ? $tmp[$node->name->value] : null; $inputField = isset($tmp[$node->name->value]) ? $tmp[$node->name->value] : null;
$fieldType = $inputField ? $inputField->getType() : null; $inputFieldType = $inputField ? $inputField->getType() : null;
} }
$this->inputTypeStack[] = $fieldType; $this->inputTypeStack[] = Type::isInputType($inputFieldType) ? $inputFieldType : null;
break; break;
case NodeKind::ENUM: case NodeKind::ENUM: