From fde7df534d78551d97049be8136de52a4d6c0a42 Mon Sep 17 00:00:00 2001 From: Daniel Tschinder Date: Thu, 15 Feb 2018 12:22:29 +0100 Subject: [PATCH] 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 --- src/Utils/TypeInfo.php | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/Utils/TypeInfo.php b/src/Utils/TypeInfo.php index cb00234..34a48cb 100644 --- a/src/Utils/TypeInfo.php +++ b/src/Utils/TypeInfo.php @@ -4,6 +4,7 @@ namespace GraphQL\Utils; use GraphQL\Error\InvariantViolation; use GraphQL\Error\Warning; use GraphQL\Language\AST\FieldNode; +use GraphQL\Language\AST\ListType; use GraphQL\Language\AST\ListTypeNode; use GraphQL\Language\AST\NamedTypeNode; use GraphQL\Language\AST\Node; @@ -296,6 +297,10 @@ class TypeInfo { $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) { case NodeKind::SELECTION_SET: $namedType = Type::getNamedType($this->getType()); @@ -308,8 +313,12 @@ class TypeInfo if ($parentType) { $fieldDef = self::getFieldDefinition($schema, $parentType, $node); } - $this->fieldDefStack[] = $fieldDef; // push - $this->typeStack[] = $fieldDef ? $fieldDef->getType() : null; // push + $fieldType = null; + if ($fieldDef) { + $fieldType = $fieldDef->getType(); + } + $this->fieldDefStack[] = $fieldDef; + $this->typeStack[] = Type::isOutputType($fieldType) ? $fieldType : null; break; case NodeKind::DIRECTIVE: @@ -325,14 +334,14 @@ class TypeInfo } else if ($node->operation === 'subscription') { $type = $schema->getSubscriptionType(); } - $this->typeStack[] = $type; // push + $this->typeStack[] = Type::isOutputType($type) ? $type : null; break; case NodeKind::INLINE_FRAGMENT: case NodeKind::FRAGMENT_DEFINITION: $typeConditionNode = $node->typeCondition; $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; case NodeKind::VARIABLE_DEFINITION: @@ -350,23 +359,28 @@ class TypeInfo } } $this->argument = $argDef; - $this->inputTypeStack[] = $argType; // push + $this->inputTypeStack[] = Type::isInputType($argType) ? $argType : null; break; case NodeKind::LST: $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; case NodeKind::OBJECT_FIELD: $objectType = Type::getNamedType($this->getInputType()); $fieldType = null; + $inputFieldType = null; if ($objectType instanceof InputObjectType) { $tmp = $objectType->getFields(); $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; case NodeKind::ENUM: