Пример #1
0
 public function __invoke(ValidationContext $context)
 {
     return [Node::FIELD => function (Field $fieldAST) use($context) {
         $fieldDef = $context->getFieldDef();
         if (!$fieldDef) {
             return Visitor::skipNode();
         }
         $errors = [];
         $argASTs = $fieldAST->arguments ?: [];
         $argASTMap = Utils::keyMap($argASTs, function (Argument $arg) {
             return $arg->name->value;
         });
         foreach ($fieldDef->args as $argDef) {
             $argAST = isset($argASTMap[$argDef->name]) ? $argASTMap[$argDef->name] : null;
             if (!$argAST && $argDef->getType() instanceof NonNull) {
                 $errors[] = new Error(Messages::missingArgMessage($fieldAST->name->value, $argDef->name, $argDef->getType()), [$fieldAST]);
             }
         }
         $argDefMap = Utils::keyMap($fieldDef->args, function ($def) {
             return $def->name;
         });
         foreach ($argASTs as $argAST) {
             $argDef = $argDefMap[$argAST->name->value];
             if ($argDef && !DocumentValidator::isValidLiteralValue($argAST->value, $argDef->getType())) {
                 $errors[] = new Error(Messages::badValueMessage($argAST->name->value, $argDef->getType(), Printer::doPrint($argAST->value)), [$argAST->value]);
             }
         }
         return !empty($errors) ? $errors : null;
     }];
 }
 public function __invoke(ValidationContext $context)
 {
     $operation = null;
     $visitedFragmentNames = [];
     $definedVariableNames = [];
     return ['visitSpreadFragments' => true, Node::OPERATION_DEFINITION => function (OperationDefinition $node, $key, $parent, $path, $ancestors) use(&$operation, &$visitedFragmentNames, &$definedVariableNames) {
         $operation = $node;
         $visitedFragmentNames = [];
         $definedVariableNames = [];
     }, Node::VARIABLE_DEFINITION => function (VariableDefinition $def) use(&$definedVariableNames) {
         $definedVariableNames[$def->variable->name->value] = true;
     }, Node::VARIABLE => function (Variable $variable, $key, $parent, $path, $ancestors) use(&$definedVariableNames, &$visitedFragmentNames, &$operation) {
         $varName = $variable->name->value;
         if (empty($definedVariableNames[$varName])) {
             $withinFragment = false;
             foreach ($ancestors as $ancestor) {
                 if ($ancestor instanceof FragmentDefinition) {
                     $withinFragment = true;
                     break;
                 }
             }
             if ($withinFragment && $operation && $operation->name) {
                 return new Error(self::undefinedVarByOpMessage($varName, $operation->name->value), [$variable, $operation]);
             }
             return new Error(self::undefinedVarMessage($varName), [$variable]);
         }
     }, Node::FRAGMENT_SPREAD => function (FragmentSpread $spreadAST) use(&$visitedFragmentNames) {
         // Only visit fragments of a particular name once per operation
         if (!empty($visitedFragmentNames[$spreadAST->name->value])) {
             return Visitor::skipNode();
         }
         $visitedFragmentNames[$spreadAST->name->value] = true;
     }];
 }
Пример #3
0
 public function __invoke(ValidationContext $context)
 {
     $visitedFragmentNames = new \stdClass();
     $variableDefs = [];
     $variableNameUsed = new \stdClass();
     return ['visitSpreadFragments' => true, Node::OPERATION_DEFINITION => ['enter' => function () use(&$visitedFragmentNames, &$variableDefs, &$variableNameUsed) {
         $visitedFragmentNames = new \stdClass();
         $variableDefs = [];
         $variableNameUsed = new \stdClass();
     }, 'leave' => function () use(&$visitedFragmentNames, &$variableDefs, &$variableNameUsed) {
         $errors = [];
         foreach ($variableDefs as $def) {
             if (empty($variableNameUsed->{$def->variable->name->value})) {
                 $errors[] = new Error(Messages::unusedVariableMessage($def->variable->name->value), [$def]);
             }
         }
         return !empty($errors) ? $errors : null;
     }], Node::VARIABLE_DEFINITION => function ($def) use(&$variableDefs) {
         $variableDefs[] = $def;
         return Visitor::skipNode();
     }, Node::VARIABLE => function ($variable) use(&$variableNameUsed) {
         $variableNameUsed->{$variable->name->value} = true;
     }, Node::FRAGMENT_SPREAD => function ($spreadAST) use(&$visitedFragmentNames) {
         // Only visit fragments of a particular name once per operation
         if (!empty($visitedFragmentNames->{$spreadAST->name->value})) {
             return Visitor::skipNode();
         }
         $visitedFragmentNames->{$spreadAST->name->value} = true;
     }];
 }
 public function __invoke(ValidationContext $context)
 {
     $varDefMap = new \ArrayObject();
     $visitedFragmentNames = new \ArrayObject();
     return ['visitSpreadFragments' => true, Node::OPERATION_DEFINITION => function () use(&$varDefMap, &$visitedFragmentNames) {
         $varDefMap = new \ArrayObject();
         $visitedFragmentNames = new \ArrayObject();
     }, Node::VARIABLE_DEFINITION => function (VariableDefinition $varDefAST) use($varDefMap) {
         $varDefMap[$varDefAST->variable->name->value] = $varDefAST;
     }, Node::FRAGMENT_SPREAD => function (FragmentSpread $spreadAST) use($visitedFragmentNames) {
         // Only visit fragments of a particular name once per operation
         if (!empty($visitedFragmentNames[$spreadAST->name->value])) {
             return Visitor::skipNode();
         }
         $visitedFragmentNames[$spreadAST->name->value] = true;
     }, Node::VARIABLE => function (Variable $variableAST) use($context, $varDefMap) {
         $varName = $variableAST->name->value;
         $varDef = isset($varDefMap[$varName]) ? $varDefMap[$varName] : null;
         $varType = $varDef ? TypeInfo::typeFromAST($context->getSchema(), $varDef->type) : null;
         $inputType = $context->getInputType();
         if ($varType && $inputType && !$this->varTypeAllowedForType($this->effectiveType($varType, $varDef), $inputType)) {
             return new Error(Messages::badVarPosMessage($varName, $varType, $inputType), [$variableAST]);
         }
     }];
 }
Пример #5
0
 public function __invoke(ValidationContext $context)
 {
     $this->operationDefs = [];
     $this->fragmentDefs = [];
     return [NodeKind::OPERATION_DEFINITION => function ($node) {
         $this->operationDefs[] = $node;
         return Visitor::skipNode();
     }, NodeKind::FRAGMENT_DEFINITION => function (FragmentDefinitionNode $def) {
         $this->fragmentDefs[] = $def;
         return Visitor::skipNode();
     }, NodeKind::DOCUMENT => ['leave' => function () use($context) {
         $fragmentNameUsed = [];
         foreach ($this->operationDefs as $operation) {
             foreach ($context->getRecursivelyReferencedFragments($operation) as $fragment) {
                 $fragmentNameUsed[$fragment->name->value] = true;
             }
         }
         foreach ($this->fragmentDefs as $fragmentDef) {
             $fragName = $fragmentDef->name->value;
             if (empty($fragmentNameUsed[$fragName])) {
                 $context->reportError(new Error(self::unusedFragMessage($fragName), [$fragmentDef]));
             }
         }
     }]];
 }
Пример #6
0
 private function gatherSpreads($node)
 {
     $spreadNodes = [];
     Visitor::visit($node, [Node::FRAGMENT_SPREAD => function (FragmentSpread $spread) use(&$spreadNodes) {
         $spreadNodes[] = $spread;
     }]);
     return $spreadNodes;
 }
Пример #7
0
 public static function doPrint($ast)
 {
     return Visitor::visit($ast, array('leave' => array(Node::NAME => function ($node) {
         return $node->value . '';
     }, Node::VARIABLE => function ($node) {
         return '$' . $node->name;
     }, Node::DOCUMENT => function (Document $node) {
         return self::join($node->definitions, "\n\n") . "\n";
     }, Node::OPERATION_DEFINITION => function (OperationDefinition $node) {
         $op = $node->operation;
         $name = $node->name;
         $defs = Printer::manyList('(', $node->variableDefinitions, ', ', ')');
         $directives = self::join($node->directives, ' ');
         $selectionSet = $node->selectionSet;
         return !$name ? $selectionSet : self::join([$op, self::join([$name, $defs]), $directives, $selectionSet], ' ');
     }, Node::VARIABLE_DEFINITION => function (VariableDefinition $node) {
         return self::join([$node->variable . ': ' . $node->type, $node->defaultValue], ' = ');
     }, Node::SELECTION_SET => function (SelectionSet $node) {
         return self::blockList($node->selections, ",\n");
     }, Node::FIELD => function (Field $node) {
         $r11 = self::join([$node->alias, $node->name], ': ');
         $r1 = self::join([$r11, self::manyList('(', $node->arguments, ', ', ')')]);
         $r2 = self::join($node->directives, ' ');
         return self::join([$r1, $r2, $node->selectionSet], ' ');
     }, Node::ARGUMENT => function (Argument $node) {
         return $node->name . ': ' . $node->value;
     }, Node::FRAGMENT_SPREAD => function (FragmentSpread $node) {
         return self::join(['...' . $node->name, self::join($node->directives, '')], ' ');
     }, Node::INLINE_FRAGMENT => function (InlineFragment $node) {
         return self::join(['... on', $node->typeCondition, self::join($node->directives, ' '), $node->selectionSet], ' ');
     }, Node::FRAGMENT_DEFINITION => function (FragmentDefinition $node) {
         return self::join(['fragment', $node->name, 'on', $node->typeCondition, self::join($node->directives, ' '), $node->selectionSet], ' ');
     }, Node::INT => function (IntValue $node) {
         return $node->value;
     }, Node::FLOAT => function (FloatValue $node) {
         return $node->value;
     }, Node::STRING => function (StringValue $node) {
         return json_encode($node->value);
     }, Node::BOOLEAN => function (BooleanValue $node) {
         return $node->value ? 'true' : 'false';
     }, Node::ENUM => function (EnumValue $node) {
         return $node->value;
     }, Node::ARR => function (ArrayValue $node) {
         return '[' . self::join($node->values, ', ') . ']';
     }, Node::OBJECT => function (ObjectValue $node) {
         return '{' . self::join($node->fields, ', ') . '}';
     }, Node::OBJECT_FIELD => function (ObjectField $node) {
         return $node->name . ': ' . $node->value;
     }, Node::DIRECTIVE => function (Directive $node) {
         return self::join(['@' . $node->name, $node->value], ': ');
     }, Node::LIST_TYPE => function (ListType $node) {
         return '[' . $node->type . ']';
     }, Node::NON_NULL_TYPE => function (NonNullType $node) {
         return $node->type . '!';
     })));
 }
Пример #8
0
 public function __invoke(ValidationContext $context)
 {
     return [Node::ARGUMENT => function (Argument $argAST) use($context) {
         $argDef = $context->getArgument();
         if ($argDef) {
             $errors = DocumentValidator::isValidLiteralValue($argDef->getType(), $argAST->value);
             if (!empty($errors)) {
                 $context->reportError(new Error(self::badValueMessage($argAST->name->value, $argDef->getType(), Printer::doPrint($argAST->value), $errors), [$argAST->value]));
             }
         }
         return Visitor::skipNode();
     }];
 }
Пример #9
0
 public function __invoke(ValidationContext $context)
 {
     $skip = function () {
         return Visitor::skipNode();
     };
     return [Node::OBJECT_TYPE_DEFINITION => $skip, Node::INTERFACE_TYPE_DEFINITION => $skip, Node::UNION_TYPE_DEFINITION => $skip, Node::INPUT_OBJECT_TYPE_DEFINITION => $skip, Node::NAMED_TYPE => function (NamedType $node, $key) use($context) {
         $typeName = $node->name->value;
         $type = $context->getSchema()->getType($typeName);
         if (!$type) {
             $context->reportError(new Error(self::unknownTypeMessage($typeName), [$node]));
         }
     }];
 }
Пример #10
0
 public function __invoke(ValidationContext $context)
 {
     $this->knownFragmentNames = [];
     return [Node::OPERATION_DEFINITION => function () {
         return Visitor::skipNode();
     }, Node::FRAGMENT_DEFINITION => function (FragmentDefinition $node) use($context) {
         $fragmentName = $node->name->value;
         if (!empty($this->knownFragmentNames[$fragmentName])) {
             $context->reportError(new Error(self::duplicateFragmentNameMessage($fragmentName), [$this->knownFragmentNames[$fragmentName], $node->name]));
         } else {
             $this->knownFragmentNames[$fragmentName] = $node->name;
         }
         return Visitor::skipNode();
     }];
 }
Пример #11
0
 public function __invoke(ValidationContext $context)
 {
     $this->knownArgNames = [];
     return [Node::FIELD => function () {
         $this->knownArgNames = [];
     }, Node::DIRECTIVE => function () {
         $this->knownArgNames = [];
     }, Node::ARGUMENT => function (Argument $node) use($context) {
         $argName = $node->name->value;
         if (!empty($this->knownArgNames[$argName])) {
             $context->reportError(new Error(self::duplicateArgMessage($argName), [$this->knownArgNames[$argName], $node->name]));
         } else {
             $this->knownArgNames[$argName] = $node->name;
         }
         return Visitor::skipNode();
     }];
 }
Пример #12
0
 public function __invoke(ValidationContext $context)
 {
     $this->knownOperationNames = [];
     return [NodeKind::OPERATION_DEFINITION => function (OperationDefinitionNode $node) use($context) {
         $operationName = $node->name;
         if ($operationName) {
             if (!empty($this->knownOperationNames[$operationName->value])) {
                 $context->reportError(new Error(self::duplicateOperationNameMessage($operationName->value), [$this->knownOperationNames[$operationName->value], $operationName]));
             } else {
                 $this->knownOperationNames[$operationName->value] = $operationName;
             }
         }
         return Visitor::skipNode();
     }, NodeKind::FRAGMENT_DEFINITION => function () {
         return Visitor::skipNode();
     }];
 }
Пример #13
0
 public function __invoke(ValidationContext $context)
 {
     // Tracks already visited fragments to maintain O(N) and to ensure that cycles
     // are not redundantly reported.
     $this->visitedFrags = [];
     // Array of AST nodes used to produce meaningful errors
     $this->spreadPath = [];
     // Position in the spread path
     $this->spreadPathIndexByName = [];
     return [Node::OPERATION_DEFINITION => function () {
         return Visitor::skipNode();
     }, Node::FRAGMENT_DEFINITION => function (FragmentDefinition $node) use($context) {
         if (!isset($this->visitedFrags[$node->name->value])) {
             $this->detectCycleRecursive($node, $context);
         }
         return Visitor::skipNode();
     }];
 }
Пример #14
0
 public function __invoke(ValidationContext $context)
 {
     $this->context = $context;
     $this->variableDefs = new \ArrayObject();
     $this->fieldNodeAndDefs = new \ArrayObject();
     $complexity = 0;
     return $this->invokeIfNeeded($context, [NodeKind::SELECTION_SET => function (SelectionSetNode $selectionSet) use($context) {
         $this->fieldNodeAndDefs = $this->collectFieldASTsAndDefs($context, $context->getParentType(), $selectionSet, null, $this->fieldNodeAndDefs);
     }, NodeKind::VARIABLE_DEFINITION => function ($def) {
         $this->variableDefs[] = $def;
         return Visitor::skipNode();
     }, NodeKind::OPERATION_DEFINITION => ['leave' => function (OperationDefinitionNode $operationDefinition) use($context, &$complexity) {
         $complexity = $this->fieldComplexity($operationDefinition, $complexity);
         if ($complexity > $this->getMaxQueryComplexity()) {
             $context->reportError(new Error($this->maxQueryComplexityErrorMessage($this->getMaxQueryComplexity(), $complexity)));
         }
     }]]);
 }
 public function __invoke(ValidationContext $context)
 {
     return [Node::FIELD => ['leave' => function (Field $fieldAST) use($context) {
         $fieldDef = $context->getFieldDef();
         if (!$fieldDef) {
             return Visitor::skipNode();
         }
         $errors = [];
         $argASTs = $fieldAST->arguments ?: [];
         $argASTMap = [];
         foreach ($argASTs as $argAST) {
             $argASTMap[$argAST->name->value] = $argASTs;
         }
         foreach ($fieldDef->args as $argDef) {
             $argAST = isset($argASTMap[$argDef->name]) ? $argASTMap[$argDef->name] : null;
             if (!$argAST && $argDef->getType() instanceof NonNull) {
                 $errors[] = new Error(self::missingFieldArgMessage($fieldAST->name->value, $argDef->name, $argDef->getType()), [$fieldAST]);
             }
         }
         if (!empty($errors)) {
             return $errors;
         }
     }], Node::DIRECTIVE => ['leave' => function (Directive $directiveAST) use($context) {
         $directiveDef = $context->getDirective();
         if (!$directiveDef) {
             return Visitor::skipNode();
         }
         $errors = [];
         $argASTs = $directiveAST->arguments ?: [];
         $argASTMap = [];
         foreach ($argASTs as $argAST) {
             $argASTMap[$argAST->name->value] = $argASTs;
         }
         foreach ($directiveDef->args as $argDef) {
             $argAST = isset($argASTMap[$argDef->name]) ? $argASTMap[$argDef->name] : null;
             if (!$argAST && $argDef->getType() instanceof NonNull) {
                 $errors[] = new Error(self::missingDirectiveArgMessage($directiveAST->name->value, $argDef->name, $argDef->getType()), [$directiveAST]);
             }
         }
         if (!empty($errors)) {
             return $errors;
         }
     }]];
 }
Пример #16
0
 public function __invoke(ValidationContext $context)
 {
     $this->knownNames = [];
     $this->knownNameStack = [];
     return [NodeKind::OBJECT => ['enter' => function () {
         $this->knownNameStack[] = $this->knownNames;
         $this->knownNames = [];
     }, 'leave' => function () {
         $this->knownNames = array_pop($this->knownNameStack);
     }], NodeKind::OBJECT_FIELD => function (ObjectFieldNode $node) use($context) {
         $fieldName = $node->name->value;
         if (!empty($this->knownNames[$fieldName])) {
             $context->reportError(new Error(self::duplicateInputFieldMessage($fieldName), [$this->knownNames[$fieldName], $node->name]));
         } else {
             $this->knownNames[$fieldName] = $node->name;
         }
         return Visitor::skipNode();
     }];
 }
Пример #17
0
 public function __invoke(ValidationContext $context)
 {
     return [Node::VARIABLE_DEFINITION => function (VariableDefinition $varDefAST) use($context) {
         $name = $varDefAST->variable->name->value;
         $defaultValue = $varDefAST->defaultValue;
         $type = $context->getInputType();
         if ($type instanceof NonNull && $defaultValue) {
             $context->reportError(new Error(static::defaultForNonNullArgMessage($name, $type, $type->getWrappedType()), [$defaultValue]));
         }
         if ($type && $defaultValue) {
             $errors = DocumentValidator::isValidLiteralValue($type, $defaultValue);
             if (!empty($errors)) {
                 $context->reportError(new Error(static::badValueForDefaultArgMessage($name, $type, Printer::doPrint($defaultValue), $errors), [$defaultValue]));
             }
         }
         return Visitor::skipNode();
     }, Node::SELECTION_SET => function () {
         return Visitor::skipNode();
     }, Node::FRAGMENT_DEFINITION => function () {
         return Visitor::skipNode();
     }];
 }
 public function __invoke(ValidationContext $context)
 {
     return [NodeKind::FIELD => ['leave' => function (FieldNode $fieldNode) use($context) {
         $fieldDef = $context->getFieldDef();
         if (!$fieldDef) {
             return Visitor::skipNode();
         }
         $argNodes = $fieldNode->arguments ?: [];
         $argNodeMap = [];
         foreach ($argNodes as $argNode) {
             $argNodeMap[$argNode->name->value] = $argNodes;
         }
         foreach ($fieldDef->args as $argDef) {
             $argNode = isset($argNodeMap[$argDef->name]) ? $argNodeMap[$argDef->name] : null;
             if (!$argNode && $argDef->getType() instanceof NonNull) {
                 $context->reportError(new Error(self::missingFieldArgMessage($fieldNode->name->value, $argDef->name, $argDef->getType()), [$fieldNode]));
             }
         }
     }], NodeKind::DIRECTIVE => ['leave' => function (DirectiveNode $directiveNode) use($context) {
         $directiveDef = $context->getDirective();
         if (!$directiveDef) {
             return Visitor::skipNode();
         }
         $argNodes = $directiveNode->arguments ?: [];
         $argNodeMap = [];
         foreach ($argNodes as $argNode) {
             $argNodeMap[$argNode->name->value] = $argNodes;
         }
         foreach ($directiveDef->args as $argDef) {
             $argNode = isset($argNodeMap[$argDef->name]) ? $argNodeMap[$argDef->name] : null;
             if (!$argNode && $argDef->getType() instanceof NonNull) {
                 $context->reportError(new Error(self::missingDirectiveArgMessage($directiveNode->name->value, $argDef->name, $argDef->getType()), [$directiveNode]));
             }
         }
     }]];
 }
Пример #19
0
 public static function doPrint($ast)
 {
     return Visitor::visit($ast, array('leave' => array(Node::NAME => function ($node) {
         return '' . $node->value;
     }, Node::VARIABLE => function ($node) {
         return '$' . $node->name;
     }, Node::DOCUMENT => function (Document $node) {
         return self::join($node->definitions, "\n\n") . "\n";
     }, Node::OPERATION_DEFINITION => function (OperationDefinition $node) {
         $op = $node->operation;
         $name = $node->name;
         $varDefs = self::wrap('(', self::join($node->variableDefinitions, ', '), ')');
         $directives = self::join($node->directives, ' ');
         $selectionSet = $node->selectionSet;
         // Anonymous queries with no directives or variable definitions can use
         // the query short form.
         return !$name && !$directives && !$varDefs && $op === 'query' ? $selectionSet : self::join([$op, self::join([$name, $varDefs]), $directives, $selectionSet], ' ');
     }, Node::VARIABLE_DEFINITION => function (VariableDefinition $node) {
         return $node->variable . ': ' . $node->type . self::wrap(' = ', $node->defaultValue);
     }, Node::SELECTION_SET => function (SelectionSet $node) {
         return self::block($node->selections);
     }, Node::FIELD => function (Field $node) {
         return self::join([self::wrap('', $node->alias, ': ') . $node->name . self::wrap('(', self::join($node->arguments, ', '), ')'), self::join($node->directives, ' '), $node->selectionSet], ' ');
     }, Node::ARGUMENT => function (Argument $node) {
         return $node->name . ': ' . $node->value;
     }, Node::FRAGMENT_SPREAD => function (FragmentSpread $node) {
         return '...' . $node->name . self::wrap(' ', self::join($node->directives, ' '));
     }, Node::INLINE_FRAGMENT => function (InlineFragment $node) {
         return self::join(["...", self::wrap('on ', $node->typeCondition), self::join($node->directives, ' '), $node->selectionSet], ' ');
     }, Node::FRAGMENT_DEFINITION => function (FragmentDefinition $node) {
         return "fragment {$node->name} on {$node->typeCondition} " . self::wrap('', self::join($node->directives, ' '), ' ') . $node->selectionSet;
     }, Node::INT => function (IntValue $node) {
         return $node->value;
     }, Node::FLOAT => function (FloatValue $node) {
         return $node->value;
     }, Node::STRING => function (StringValue $node) {
         return json_encode($node->value);
     }, Node::BOOLEAN => function (BooleanValue $node) {
         return $node->value ? 'true' : 'false';
     }, Node::ENUM => function (EnumValue $node) {
         return $node->value;
     }, Node::LST => function (ListValue $node) {
         return '[' . self::join($node->values, ', ') . ']';
     }, Node::OBJECT => function (ObjectValue $node) {
         return '{' . self::join($node->fields, ', ') . '}';
     }, Node::OBJECT_FIELD => function (ObjectField $node) {
         return $node->name . ': ' . $node->value;
     }, Node::DIRECTIVE => function (Directive $node) {
         return '@' . $node->name . self::wrap('(', self::join($node->arguments, ', '), ')');
     }, Node::NAMED_TYPE => function (NamedType $node) {
         return $node->name;
     }, Node::LIST_TYPE => function (ListType $node) {
         return '[' . $node->type . ']';
     }, Node::NON_NULL_TYPE => function (NonNullType $node) {
         return $node->type . '!';
     }, Node::SCHEMA_DEFINITION => function (SchemaDefinition $def) {
         return self::join(['schema', self::join($def->directives, ' '), self::block($def->operationTypes)], ' ');
     }, Node::OPERATION_TYPE_DEFINITION => function (OperationTypeDefinition $def) {
         return $def->operation . ': ' . $def->type;
     }, Node::SCALAR_TYPE_DEFINITION => function (ScalarTypeDefinition $def) {
         return self::join(['scalar', $def->name, self::join($def->directives, ' ')], ' ');
     }, Node::OBJECT_TYPE_DEFINITION => function (ObjectTypeDefinition $def) {
         return self::join(['type', $def->name, self::wrap('implements ', self::join($def->interfaces, ', ')), self::join($def->directives, ' '), self::block($def->fields)], ' ');
     }, Node::FIELD_DEFINITION => function (FieldDefinition $def) {
         return $def->name . self::wrap('(', self::join($def->arguments, ', '), ')') . ': ' . $def->type . self::wrap(' ', self::join($def->directives, ' '));
     }, Node::INPUT_VALUE_DEFINITION => function (InputValueDefinition $def) {
         return self::join([$def->name . ': ' . $def->type, self::wrap('= ', $def->defaultValue), self::join($def->directives, ' ')], ' ');
     }, Node::INTERFACE_TYPE_DEFINITION => function (InterfaceTypeDefinition $def) {
         return self::join(['interface', $def->name, self::join($def->directives, ' '), self::block($def->fields)], ' ');
     }, Node::UNION_TYPE_DEFINITION => function (UnionTypeDefinition $def) {
         return self::join(['union', $def->name, self::join($def->directives, ' '), '= ' . self::join($def->types, ' | ')], ' ');
     }, Node::ENUM_TYPE_DEFINITION => function (EnumTypeDefinition $def) {
         return self::join(['enum', $def->name, self::join($def->directives, ' '), self::block($def->values)], ' ');
     }, Node::ENUM_VALUE_DEFINITION => function (EnumValueDefinition $def) {
         return self::join([$def->name, self::join($def->directives, ' ')], ' ');
     }, Node::INPUT_OBJECT_TYPE_DEFINITION => function (InputObjectTypeDefinition $def) {
         return self::join(['input', $def->name, self::join($def->directives, ' '), self::block($def->fields)], ' ');
     }, Node::TYPE_EXTENSION_DEFINITION => function (TypeExtensionDefinition $def) {
         return "extend {$def->definition}";
     }, Node::DIRECTIVE_DEFINITION => function (DirectiveDefinition $def) {
         return 'directive @' . $def->name . self::wrap('(', self::join($def->arguments, ', '), ')') . ' on ' . self::join($def->locations, ' | ');
     })));
 }
Пример #20
0
 public function testVisitsKitchenSink()
 {
     $kitchenSink = file_get_contents(__DIR__ . '/kitchen-sink.graphql');
     $ast = Parser::parse($kitchenSink);
     $visited = [];
     Visitor::visit($ast, ['enter' => function (Node $node, $key, $parent) use(&$visited) {
         $r = ['enter', $node->kind, $key, $parent instanceof Node ? $parent->kind : null];
         $visited[] = $r;
     }, 'leave' => function (Node $node, $key, $parent) use(&$visited) {
         $r = ['leave', $node->kind, $key, $parent instanceof Node ? $parent->kind : null];
         $visited[] = $r;
     }]);
     $expected = [['enter', 'Document', null, null], ['enter', 'OperationDefinition', 0, null], ['enter', 'Name', 'name', 'OperationDefinition'], ['leave', 'Name', 'name', 'OperationDefinition'], ['enter', 'VariableDefinition', 0, null], ['enter', 'Variable', 'variable', 'VariableDefinition'], ['enter', 'Name', 'name', 'Variable'], ['leave', 'Name', 'name', 'Variable'], ['leave', 'Variable', 'variable', 'VariableDefinition'], ['enter', 'NamedType', 'type', 'VariableDefinition'], ['enter', 'Name', 'name', 'NamedType'], ['leave', 'Name', 'name', 'NamedType'], ['leave', 'NamedType', 'type', 'VariableDefinition'], ['leave', 'VariableDefinition', 0, null], ['enter', 'VariableDefinition', 1, null], ['enter', 'Variable', 'variable', 'VariableDefinition'], ['enter', 'Name', 'name', 'Variable'], ['leave', 'Name', 'name', 'Variable'], ['leave', 'Variable', 'variable', 'VariableDefinition'], ['enter', 'NamedType', 'type', 'VariableDefinition'], ['enter', 'Name', 'name', 'NamedType'], ['leave', 'Name', 'name', 'NamedType'], ['leave', 'NamedType', 'type', 'VariableDefinition'], ['enter', 'EnumValue', 'defaultValue', 'VariableDefinition'], ['leave', 'EnumValue', 'defaultValue', 'VariableDefinition'], ['leave', 'VariableDefinition', 1, null], ['enter', 'SelectionSet', 'selectionSet', 'OperationDefinition'], ['enter', 'Field', 0, null], ['enter', 'Name', 'alias', 'Field'], ['leave', 'Name', 'alias', 'Field'], ['enter', 'Name', 'name', 'Field'], ['leave', 'Name', 'name', 'Field'], ['enter', 'Argument', 0, null], ['enter', 'Name', 'name', 'Argument'], ['leave', 'Name', 'name', 'Argument'], ['enter', 'ListValue', 'value', 'Argument'], ['enter', 'IntValue', 0, null], ['leave', 'IntValue', 0, null], ['enter', 'IntValue', 1, null], ['leave', 'IntValue', 1, null], ['leave', 'ListValue', 'value', 'Argument'], ['leave', 'Argument', 0, null], ['enter', 'SelectionSet', 'selectionSet', 'Field'], ['enter', 'Field', 0, null], ['enter', 'Name', 'name', 'Field'], ['leave', 'Name', 'name', 'Field'], ['leave', 'Field', 0, null], ['enter', 'InlineFragment', 1, null], ['enter', 'NamedType', 'typeCondition', 'InlineFragment'], ['enter', 'Name', 'name', 'NamedType'], ['leave', 'Name', 'name', 'NamedType'], ['leave', 'NamedType', 'typeCondition', 'InlineFragment'], ['enter', 'Directive', 0, null], ['enter', 'Name', 'name', 'Directive'], ['leave', 'Name', 'name', 'Directive'], ['leave', 'Directive', 0, null], ['enter', 'SelectionSet', 'selectionSet', 'InlineFragment'], ['enter', 'Field', 0, null], ['enter', 'Name', 'name', 'Field'], ['leave', 'Name', 'name', 'Field'], ['enter', 'SelectionSet', 'selectionSet', 'Field'], ['enter', 'Field', 0, null], ['enter', 'Name', 'name', 'Field'], ['leave', 'Name', 'name', 'Field'], ['leave', 'Field', 0, null], ['enter', 'Field', 1, null], ['enter', 'Name', 'alias', 'Field'], ['leave', 'Name', 'alias', 'Field'], ['enter', 'Name', 'name', 'Field'], ['leave', 'Name', 'name', 'Field'], ['enter', 'Argument', 0, null], ['enter', 'Name', 'name', 'Argument'], ['leave', 'Name', 'name', 'Argument'], ['enter', 'IntValue', 'value', 'Argument'], ['leave', 'IntValue', 'value', 'Argument'], ['leave', 'Argument', 0, null], ['enter', 'Argument', 1, null], ['enter', 'Name', 'name', 'Argument'], ['leave', 'Name', 'name', 'Argument'], ['enter', 'Variable', 'value', 'Argument'], ['enter', 'Name', 'name', 'Variable'], ['leave', 'Name', 'name', 'Variable'], ['leave', 'Variable', 'value', 'Argument'], ['leave', 'Argument', 1, null], ['enter', 'Directive', 0, null], ['enter', 'Name', 'name', 'Directive'], ['leave', 'Name', 'name', 'Directive'], ['enter', 'Argument', 0, null], ['enter', 'Name', 'name', 'Argument'], ['leave', 'Name', 'name', 'Argument'], ['enter', 'Variable', 'value', 'Argument'], ['enter', 'Name', 'name', 'Variable'], ['leave', 'Name', 'name', 'Variable'], ['leave', 'Variable', 'value', 'Argument'], ['leave', 'Argument', 0, null], ['leave', 'Directive', 0, null], ['enter', 'SelectionSet', 'selectionSet', 'Field'], ['enter', 'Field', 0, null], ['enter', 'Name', 'name', 'Field'], ['leave', 'Name', 'name', 'Field'], ['leave', 'Field', 0, null], ['enter', 'FragmentSpread', 1, null], ['enter', 'Name', 'name', 'FragmentSpread'], ['leave', 'Name', 'name', 'FragmentSpread'], ['leave', 'FragmentSpread', 1, null], ['leave', 'SelectionSet', 'selectionSet', 'Field'], ['leave', 'Field', 1, null], ['leave', 'SelectionSet', 'selectionSet', 'Field'], ['leave', 'Field', 0, null], ['leave', 'SelectionSet', 'selectionSet', 'InlineFragment'], ['leave', 'InlineFragment', 1, null], ['leave', 'SelectionSet', 'selectionSet', 'Field'], ['leave', 'Field', 0, null], ['leave', 'SelectionSet', 'selectionSet', 'OperationDefinition'], ['leave', 'OperationDefinition', 0, null], ['enter', 'OperationDefinition', 1, null], ['enter', 'Name', 'name', 'OperationDefinition'], ['leave', 'Name', 'name', 'OperationDefinition'], ['enter', 'SelectionSet', 'selectionSet', 'OperationDefinition'], ['enter', 'Field', 0, null], ['enter', 'Name', 'name', 'Field'], ['leave', 'Name', 'name', 'Field'], ['enter', 'Argument', 0, null], ['enter', 'Name', 'name', 'Argument'], ['leave', 'Name', 'name', 'Argument'], ['enter', 'IntValue', 'value', 'Argument'], ['leave', 'IntValue', 'value', 'Argument'], ['leave', 'Argument', 0, null], ['enter', 'Directive', 0, null], ['enter', 'Name', 'name', 'Directive'], ['leave', 'Name', 'name', 'Directive'], ['leave', 'Directive', 0, null], ['enter', 'SelectionSet', 'selectionSet', 'Field'], ['enter', 'Field', 0, null], ['enter', 'Name', 'name', 'Field'], ['leave', 'Name', 'name', 'Field'], ['enter', 'SelectionSet', 'selectionSet', 'Field'], ['enter', 'Field', 0, null], ['enter', 'Name', 'name', 'Field'], ['leave', 'Name', 'name', 'Field'], ['leave', 'Field', 0, null], ['leave', 'SelectionSet', 'selectionSet', 'Field'], ['leave', 'Field', 0, null], ['leave', 'SelectionSet', 'selectionSet', 'Field'], ['leave', 'Field', 0, null], ['leave', 'SelectionSet', 'selectionSet', 'OperationDefinition'], ['leave', 'OperationDefinition', 1, null], ['enter', 'FragmentDefinition', 2, null], ['enter', 'Name', 'name', 'FragmentDefinition'], ['leave', 'Name', 'name', 'FragmentDefinition'], ['enter', 'NamedType', 'typeCondition', 'FragmentDefinition'], ['enter', 'Name', 'name', 'NamedType'], ['leave', 'Name', 'name', 'NamedType'], ['leave', 'NamedType', 'typeCondition', 'FragmentDefinition'], ['enter', 'SelectionSet', 'selectionSet', 'FragmentDefinition'], ['enter', 'Field', 0, null], ['enter', 'Name', 'name', 'Field'], ['leave', 'Name', 'name', 'Field'], ['enter', 'Argument', 0, null], ['enter', 'Name', 'name', 'Argument'], ['leave', 'Name', 'name', 'Argument'], ['enter', 'Variable', 'value', 'Argument'], ['enter', 'Name', 'name', 'Variable'], ['leave', 'Name', 'name', 'Variable'], ['leave', 'Variable', 'value', 'Argument'], ['leave', 'Argument', 0, null], ['enter', 'Argument', 1, null], ['enter', 'Name', 'name', 'Argument'], ['leave', 'Name', 'name', 'Argument'], ['enter', 'Variable', 'value', 'Argument'], ['enter', 'Name', 'name', 'Variable'], ['leave', 'Name', 'name', 'Variable'], ['leave', 'Variable', 'value', 'Argument'], ['leave', 'Argument', 1, null], ['enter', 'Argument', 2, null], ['enter', 'Name', 'name', 'Argument'], ['leave', 'Name', 'name', 'Argument'], ['enter', 'ObjectValue', 'value', 'Argument'], ['enter', 'ObjectField', 0, null], ['enter', 'Name', 'name', 'ObjectField'], ['leave', 'Name', 'name', 'ObjectField'], ['enter', 'StringValue', 'value', 'ObjectField'], ['leave', 'StringValue', 'value', 'ObjectField'], ['leave', 'ObjectField', 0, null], ['leave', 'ObjectValue', 'value', 'Argument'], ['leave', 'Argument', 2, null], ['leave', 'Field', 0, null], ['leave', 'SelectionSet', 'selectionSet', 'FragmentDefinition'], ['leave', 'FragmentDefinition', 2, null], ['enter', 'OperationDefinition', 3, null], ['enter', 'SelectionSet', 'selectionSet', 'OperationDefinition'], ['enter', 'Field', 0, null], ['enter', 'Name', 'name', 'Field'], ['leave', 'Name', 'name', 'Field'], ['enter', 'Argument', 0, null], ['enter', 'Name', 'name', 'Argument'], ['leave', 'Name', 'name', 'Argument'], ['enter', 'BooleanValue', 'value', 'Argument'], ['leave', 'BooleanValue', 'value', 'Argument'], ['leave', 'Argument', 0, null], ['enter', 'Argument', 1, null], ['enter', 'Name', 'name', 'Argument'], ['leave', 'Name', 'name', 'Argument'], ['enter', 'BooleanValue', 'value', 'Argument'], ['leave', 'BooleanValue', 'value', 'Argument'], ['leave', 'Argument', 1, null], ['leave', 'Field', 0, null], ['enter', 'Field', 1, null], ['enter', 'Name', 'name', 'Field'], ['leave', 'Name', 'name', 'Field'], ['leave', 'Field', 1, null], ['leave', 'SelectionSet', 'selectionSet', 'OperationDefinition'], ['leave', 'OperationDefinition', 3, null], ['leave', 'Document', null, null]];
     $this->assertEquals($expected, $visited);
 }
Пример #21
0
 /**
  * This uses a specialized visitor which runs multiple visitors in parallel,
  * while maintaining the visitor skip and break API.
  *
  * @param Schema $schema
  * @param Document $documentAST
  * @param array $rules
  * @return array
  */
 public static function visitUsingRules(Schema $schema, Document $documentAST, array $rules)
 {
     $typeInfo = new TypeInfo($schema);
     $context = new ValidationContext($schema, $documentAST, $typeInfo);
     $errors = [];
     // TODO: convert to class
     $visitInstances = function ($ast, $instances) use($typeInfo, $context, &$errors, &$visitInstances) {
         $skipUntil = new \SplFixedArray(count($instances));
         $skipCount = 0;
         Visitor::visit($ast, ['enter' => function ($node, $key) use($typeInfo, $instances, $skipUntil, &$skipCount, &$errors, $context, $visitInstances) {
             $typeInfo->enter($node);
             for ($i = 0; $i < count($instances); $i++) {
                 // Do not visit this instance if it returned false for a previous node
                 if ($skipUntil[$i]) {
                     continue;
                 }
                 $result = null;
                 // Do not visit top level fragment definitions if this instance will
                 // visit those fragments inline because it
                 // provided `visitSpreadFragments`.
                 if ($node->kind === Node::FRAGMENT_DEFINITION && $key !== null && !empty($instances[$i]['visitSpreadFragments'])) {
                     $result = Visitor::skipNode();
                 } else {
                     $enter = Visitor::getVisitFn($instances[$i], false, $node->kind);
                     if ($enter instanceof \Closure) {
                         // $enter = $enter->bindTo($instances[$i]);
                         $result = call_user_func_array($enter, func_get_args());
                     } else {
                         $result = null;
                     }
                 }
                 if ($result instanceof VisitorOperation) {
                     if ($result->doContinue) {
                         $skipUntil[$i] = $node;
                         $skipCount++;
                         // If all instances are being skipped over, skip deeper traversal
                         if ($skipCount === count($instances)) {
                             for ($k = 0; $k < count($instances); $k++) {
                                 if ($skipUntil[$k] === $node) {
                                     $skipUntil[$k] = null;
                                     $skipCount--;
                                 }
                             }
                             return Visitor::skipNode();
                         }
                     } else {
                         if ($result->doBreak) {
                             $instances[$i] = null;
                         }
                     }
                 } else {
                     if ($result && self::isError($result)) {
                         self::append($errors, $result);
                         for ($j = $i - 1; $j >= 0; $j--) {
                             $leaveFn = Visitor::getVisitFn($instances[$j], true, $node->kind);
                             if ($leaveFn) {
                                 // $leaveFn = $leaveFn->bindTo($instances[$j])
                                 $result = call_user_func_array($leaveFn, func_get_args());
                                 if ($result instanceof VisitorOperation) {
                                     if ($result->doBreak) {
                                         $instances[$j] = null;
                                     }
                                 } else {
                                     if (self::isError($result)) {
                                         self::append($errors, $result);
                                     } else {
                                         if ($result !== null) {
                                             throw new \Exception("Config cannot edit document.");
                                         }
                                     }
                                 }
                             }
                         }
                         $typeInfo->leave($node);
                         return Visitor::skipNode();
                     } else {
                         if ($result !== null) {
                             throw new \Exception("Config cannot edit document.");
                         }
                     }
                 }
             }
             // If any validation instances provide the flag `visitSpreadFragments`
             // and this node is a fragment spread, validate the fragment from
             // this point.
             if ($node instanceof FragmentSpread) {
                 $fragment = $context->getFragment($node->name->value);
                 if ($fragment) {
                     $fragVisitingInstances = [];
                     foreach ($instances as $idx => $inst) {
                         if (!empty($inst['visitSpreadFragments']) && !$skipUntil[$idx]) {
                             $fragVisitingInstances[] = $inst;
                         }
                     }
                     if (!empty($fragVisitingInstances)) {
                         $visitInstances($fragment, $fragVisitingInstances);
                     }
                 }
             }
         }, 'leave' => function ($node) use($instances, $typeInfo, $skipUntil, &$skipCount, &$errors) {
             for ($i = count($instances) - 1; $i >= 0; $i--) {
                 if ($skipUntil[$i]) {
                     if ($skipUntil[$i] === $node) {
                         $skipUntil[$i] = null;
                         $skipCount--;
                     }
                     continue;
                 }
                 $leaveFn = Visitor::getVisitFn($instances[$i], true, $node->kind);
                 if ($leaveFn) {
                     // $leaveFn = $leaveFn.bindTo($instances[$i]);
                     $result = call_user_func_array($leaveFn, func_get_args());
                     if ($result instanceof VisitorOperation) {
                         if ($result->doBreak) {
                             $instances[$i] = null;
                         }
                     } else {
                         if (self::isError($result)) {
                             self::append($errors, $result);
                         } else {
                             if ($result !== null) {
                                 throw new \Exception("Config cannot edit document.");
                             }
                         }
                     }
                 }
             }
             $typeInfo->leave($node);
         }]);
     };
     // Visit the whole document with instances of all provided rules.
     $allRuleInstances = [];
     foreach ($rules as $rule) {
         $allRuleInstances[] = $rule($context);
     }
     $visitInstances($documentAST, $allRuleInstances);
     return $errors;
 }
Пример #22
0
 /**
  * @param HasSelectionSet $node
  * @return array List of ['node' => Variable, 'type' => ?InputObjectType]
  */
 function getVariableUsages(HasSelectionSet $node)
 {
     $usages = isset($this->variableUsages[$node]) ? $this->variableUsages[$node] : null;
     if (!$usages) {
         $newUsages = [];
         $typeInfo = new TypeInfo($this->schema);
         Visitor::visit($node, Visitor::visitWithTypeInfo($typeInfo, [Node::VARIABLE_DEFINITION => function () {
             return false;
         }, Node::VARIABLE => function (Variable $variable) use(&$newUsages, $typeInfo) {
             $newUsages[] = ['node' => $variable, 'type' => $typeInfo->getInputType()];
         }]));
         $usages = $newUsages;
         $this->variableUsages[$node] = $usages;
     }
     return $usages;
 }
Пример #23
0
 /**
  * This uses a specialized visitor which runs multiple visitors in parallel,
  * while maintaining the visitor skip and break API.
  *
  * @param Schema $schema
  * @param TypeInfo $typeInfo
  * @param DocumentNode $documentNode
  * @param array $rules
  * @return array
  */
 public static function visitUsingRules(Schema $schema, TypeInfo $typeInfo, DocumentNode $documentNode, array $rules)
 {
     $context = new ValidationContext($schema, $documentNode, $typeInfo);
     $visitors = [];
     foreach ($rules as $rule) {
         $visitors[] = $rule($context);
     }
     Visitor::visit($documentNode, Visitor::visitWithTypeInfo($typeInfo, Visitor::visitInParallel($visitors)));
     return $context->getErrors();
 }
Пример #24
0
 /**
  * @it maintains type info during edit
  */
 public function testMaintainsTypeInfoDuringEdit()
 {
     $visited = [];
     $typeInfo = new TypeInfo(TestCase::getDefaultSchema());
     $ast = Parser::parse('{ human(id: 4) { name, pets }, alien }');
     $editedAst = Visitor::visit($ast, Visitor::visitWithTypeInfo($typeInfo, ['enter' => function ($node) use($typeInfo, &$visited) {
         $parentType = $typeInfo->getParentType();
         $type = $typeInfo->getType();
         $inputType = $typeInfo->getInputType();
         $visited[] = ['enter', $node->kind, $node->kind === 'Name' ? $node->value : null, $parentType ? (string) $parentType : null, $type ? (string) $type : null, $inputType ? (string) $inputType : null];
         // Make a query valid by adding missing selection sets.
         if ($node->kind === 'Field' && !$node->selectionSet && Type::isCompositeType(Type::getNamedType($type))) {
             return new FieldNode(['alias' => $node->alias, 'name' => $node->name, 'arguments' => $node->arguments, 'directives' => $node->directives, 'selectionSet' => new SelectionSetNode(['kind' => 'SelectionSet', 'selections' => [new FieldNode(['name' => new NameNode(['value' => '__typename'])])]])]);
         }
     }, 'leave' => function ($node) use($typeInfo, &$visited) {
         $parentType = $typeInfo->getParentType();
         $type = $typeInfo->getType();
         $inputType = $typeInfo->getInputType();
         $visited[] = ['leave', $node->kind, $node->kind === 'Name' ? $node->value : null, $parentType ? (string) $parentType : null, $type ? (string) $type : null, $inputType ? (string) $inputType : null];
     }]));
     $this->assertEquals(Printer::doPrint(Parser::parse('{ human(id: 4) { name, pets }, alien }')), Printer::doPrint($ast));
     $this->assertEquals(Printer::doPrint(Parser::parse('{ human(id: 4) { name, pets { __typename } }, alien { __typename } }')), Printer::doPrint($editedAst));
     $this->assertEquals([['enter', 'Document', null, null, null, null], ['enter', 'OperationDefinition', null, null, 'QueryRoot', null], ['enter', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null], ['enter', 'Field', null, 'QueryRoot', 'Human', null], ['enter', 'Name', 'human', 'QueryRoot', 'Human', null], ['leave', 'Name', 'human', 'QueryRoot', 'Human', null], ['enter', 'Argument', null, 'QueryRoot', 'Human', 'ID'], ['enter', 'Name', 'id', 'QueryRoot', 'Human', 'ID'], ['leave', 'Name', 'id', 'QueryRoot', 'Human', 'ID'], ['enter', 'IntValue', null, 'QueryRoot', 'Human', 'ID'], ['leave', 'IntValue', null, 'QueryRoot', 'Human', 'ID'], ['leave', 'Argument', null, 'QueryRoot', 'Human', 'ID'], ['enter', 'SelectionSet', null, 'Human', 'Human', null], ['enter', 'Field', null, 'Human', 'String', null], ['enter', 'Name', 'name', 'Human', 'String', null], ['leave', 'Name', 'name', 'Human', 'String', null], ['leave', 'Field', null, 'Human', 'String', null], ['enter', 'Field', null, 'Human', '[Pet]', null], ['enter', 'Name', 'pets', 'Human', '[Pet]', null], ['leave', 'Name', 'pets', 'Human', '[Pet]', null], ['enter', 'SelectionSet', null, 'Pet', '[Pet]', null], ['enter', 'Field', null, 'Pet', 'String!', null], ['enter', 'Name', '__typename', 'Pet', 'String!', null], ['leave', 'Name', '__typename', 'Pet', 'String!', null], ['leave', 'Field', null, 'Pet', 'String!', null], ['leave', 'SelectionSet', null, 'Pet', '[Pet]', null], ['leave', 'Field', null, 'Human', '[Pet]', null], ['leave', 'SelectionSet', null, 'Human', 'Human', null], ['leave', 'Field', null, 'QueryRoot', 'Human', null], ['enter', 'Field', null, 'QueryRoot', 'Alien', null], ['enter', 'Name', 'alien', 'QueryRoot', 'Alien', null], ['leave', 'Name', 'alien', 'QueryRoot', 'Alien', null], ['enter', 'SelectionSet', null, 'Alien', 'Alien', null], ['enter', 'Field', null, 'Alien', 'String!', null], ['enter', 'Name', '__typename', 'Alien', 'String!', null], ['leave', 'Name', '__typename', 'Alien', 'String!', null], ['leave', 'Field', null, 'Alien', 'String!', null], ['leave', 'SelectionSet', null, 'Alien', 'Alien', null], ['leave', 'Field', null, 'QueryRoot', 'Alien', null], ['leave', 'SelectionSet', null, 'QueryRoot', 'QueryRoot', null], ['leave', 'OperationDefinition', null, null, 'QueryRoot', null], ['leave', 'Document', null, null, null, null]], $visited);
 }