| Current Path : /home/rtorresani/www/vendor/webonyx/graphql-php/src/Validator/Rules/ |
| Current File : //home/rtorresani/www/vendor/webonyx/graphql-php/src/Validator/Rules/PossibleTypeExtensions.php |
<?php declare(strict_types=1);
namespace GraphQL\Validator\Rules;
use GraphQL\Error\Error;
use GraphQL\Error\InvariantViolation;
use GraphQL\Language\AST\Node;
use GraphQL\Language\AST\NodeKind;
use GraphQL\Language\AST\TypeDefinitionNode;
use GraphQL\Language\VisitorOperation;
use GraphQL\Type\Definition\EnumType;
use GraphQL\Type\Definition\InputObjectType;
use GraphQL\Type\Definition\InterfaceType;
use GraphQL\Type\Definition\NamedType;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ScalarType;
use GraphQL\Type\Definition\UnionType;
use GraphQL\Utils\Utils;
use GraphQL\Validator\SDLValidationContext;
/**
* Possible type extensions.
*
* A type extension is only valid if the type is defined and has the same kind.
*/
class PossibleTypeExtensions extends ValidationRule
{
public function getSDLVisitor(SDLValidationContext $context): array
{
$schema = $context->getSchema();
/** @var array<string, TypeDefinitionNode&Node> $definedTypes */
$definedTypes = [];
foreach ($context->getDocument()->definitions as $def) {
if ($def instanceof TypeDefinitionNode) {
$name = $def->getName()->value;
$definedTypes[$name] = $def;
}
}
$checkTypeExtension = static function ($node) use ($context, $schema, &$definedTypes): ?VisitorOperation {
$typeName = $node->name->value;
$defNode = $definedTypes[$typeName] ?? null;
$existingType = $schema !== null
? $schema->getType($typeName)
: null;
$expectedKind = null;
if ($defNode !== null) {
$expectedKind = self::defKindToExtKind($defNode->kind);
} elseif ($existingType !== null) {
$expectedKind = self::typeToExtKind($existingType);
}
if ($expectedKind !== null) {
if ($expectedKind !== $node->kind) {
$kindStr = self::extensionKindToTypeName($node->kind);
$context->reportError(
new Error(
"Cannot extend non-{$kindStr} type \"{$typeName}\".",
$defNode !== null
? [$defNode, $node]
: $node,
),
);
}
} else {
$existingTypesMap = $schema !== null
? $schema->getTypeMap()
: [];
$allTypeNames = [
...array_keys($definedTypes),
...array_keys($existingTypesMap),
];
$suggestedTypes = Utils::suggestionList($typeName, $allTypeNames);
$didYouMean = $suggestedTypes === []
? ''
: ' Did you mean ' . Utils::quotedOrList($suggestedTypes) . '?';
$context->reportError(
new Error(
"Cannot extend type \"{$typeName}\" because it is not defined.{$didYouMean}",
$node->name,
),
);
}
return null;
};
return [
NodeKind::SCALAR_TYPE_EXTENSION => $checkTypeExtension,
NodeKind::OBJECT_TYPE_EXTENSION => $checkTypeExtension,
NodeKind::INTERFACE_TYPE_EXTENSION => $checkTypeExtension,
NodeKind::UNION_TYPE_EXTENSION => $checkTypeExtension,
NodeKind::ENUM_TYPE_EXTENSION => $checkTypeExtension,
NodeKind::INPUT_OBJECT_TYPE_EXTENSION => $checkTypeExtension,
];
}
/** @throws InvariantViolation */
private static function defKindToExtKind(string $kind): string
{
switch ($kind) {
case NodeKind::SCALAR_TYPE_DEFINITION:
return NodeKind::SCALAR_TYPE_EXTENSION;
case NodeKind::OBJECT_TYPE_DEFINITION:
return NodeKind::OBJECT_TYPE_EXTENSION;
case NodeKind::INTERFACE_TYPE_DEFINITION:
return NodeKind::INTERFACE_TYPE_EXTENSION;
case NodeKind::UNION_TYPE_DEFINITION:
return NodeKind::UNION_TYPE_EXTENSION;
case NodeKind::ENUM_TYPE_DEFINITION:
return NodeKind::ENUM_TYPE_EXTENSION;
case NodeKind::INPUT_OBJECT_TYPE_DEFINITION:
return NodeKind::INPUT_OBJECT_TYPE_EXTENSION;
default:
throw new InvariantViolation("Unexpected definition kind: {$kind}.");
}
}
/** @throws InvariantViolation */
private static function typeToExtKind(NamedType $type): string
{
switch (true) {
case $type instanceof ScalarType:
return NodeKind::SCALAR_TYPE_EXTENSION;
case $type instanceof ObjectType:
return NodeKind::OBJECT_TYPE_EXTENSION;
case $type instanceof InterfaceType:
return NodeKind::INTERFACE_TYPE_EXTENSION;
case $type instanceof UnionType:
return NodeKind::UNION_TYPE_EXTENSION;
case $type instanceof EnumType:
return NodeKind::ENUM_TYPE_EXTENSION;
case $type instanceof InputObjectType:
return NodeKind::INPUT_OBJECT_TYPE_EXTENSION;
default:
$unexpectedType = Utils::printSafe($type);
throw new InvariantViolation("Unexpected type: {$unexpectedType}.");
}
}
/** @throws InvariantViolation */
private static function extensionKindToTypeName(string $kind): string
{
switch ($kind) {
case NodeKind::SCALAR_TYPE_EXTENSION:
return 'scalar';
case NodeKind::OBJECT_TYPE_EXTENSION:
return 'object';
case NodeKind::INTERFACE_TYPE_EXTENSION:
return 'interface';
case NodeKind::UNION_TYPE_EXTENSION:
return 'union';
case NodeKind::ENUM_TYPE_EXTENSION:
return 'enum';
case NodeKind::INPUT_OBJECT_TYPE_EXTENSION:
return 'input object';
default:
throw new InvariantViolation("Unexpected extension kind: {$kind}.");
}
}
}