diff --git a/CHANGELOG.md b/CHANGELOG.md index 492cce8ce..d7e9728d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ You can find and compare releases at the [GitHub release page](https://github.co - Use `JSON_THROW_ON_ERROR` in `json_encode()` - Validate some internal invariants through `assert()` - `PromiseAdapter::all()` accepts `iterable` +- Reorganize AST interfaces related to schema and type extensions ### Added diff --git a/src/Language/AST/DefinitionNode.php b/src/Language/AST/DefinitionNode.php index 200f394a6..a514ce5f5 100644 --- a/src/Language/AST/DefinitionNode.php +++ b/src/Language/AST/DefinitionNode.php @@ -5,7 +5,8 @@ /** * export type DefinitionNode = * | ExecutableDefinitionNode - * | TypeSystemDefinitionNode;. + * | TypeSystemDefinitionNode + * | TypeSystemExtensionNode; */ interface DefinitionNode { diff --git a/src/Language/AST/SchemaTypeExtensionNode.php b/src/Language/AST/SchemaExtensionNode.php similarity index 79% rename from src/Language/AST/SchemaTypeExtensionNode.php rename to src/Language/AST/SchemaExtensionNode.php index ea1aed82a..ffff4adf7 100644 --- a/src/Language/AST/SchemaTypeExtensionNode.php +++ b/src/Language/AST/SchemaExtensionNode.php @@ -2,7 +2,7 @@ namespace GraphQL\Language\AST; -class SchemaTypeExtensionNode extends Node implements TypeExtensionNode +class SchemaExtensionNode extends Node implements TypeSystemExtensionNode { public string $kind = NodeKind::SCHEMA_EXTENSION; diff --git a/src/Language/AST/TypeDefinitionNode.php b/src/Language/AST/TypeDefinitionNode.php index 4eeb5d9a1..aa223879f 100644 --- a/src/Language/AST/TypeDefinitionNode.php +++ b/src/Language/AST/TypeDefinitionNode.php @@ -9,6 +9,8 @@ * | UnionTypeDefinitionNode * | EnumTypeDefinitionNode * | InputObjectTypeDefinitionNode. + * + * @property NameNode $name */ interface TypeDefinitionNode extends TypeSystemDefinitionNode { diff --git a/src/Language/AST/TypeExtensionNode.php b/src/Language/AST/TypeExtensionNode.php index 3875a0633..04d24860e 100644 --- a/src/Language/AST/TypeExtensionNode.php +++ b/src/Language/AST/TypeExtensionNode.php @@ -10,7 +10,9 @@ * | UnionTypeExtensionNode * | EnumTypeExtensionNode * | InputObjectTypeExtensionNode;. + * + * @property NameNode $name */ -interface TypeExtensionNode extends TypeSystemDefinitionNode +interface TypeExtensionNode extends TypeSystemExtensionNode { } diff --git a/src/Language/AST/TypeSystemDefinitionNode.php b/src/Language/AST/TypeSystemDefinitionNode.php index e4688f666..2fbbaa8c0 100644 --- a/src/Language/AST/TypeSystemDefinitionNode.php +++ b/src/Language/AST/TypeSystemDefinitionNode.php @@ -6,10 +6,7 @@ * export type TypeSystemDefinitionNode = * | SchemaDefinitionNode * | TypeDefinitionNode - * | TypeExtensionNode * | DirectiveDefinitionNode. - * - * @property NameNode $name */ interface TypeSystemDefinitionNode extends DefinitionNode { diff --git a/src/Language/AST/TypeSystemExtensionNode.php b/src/Language/AST/TypeSystemExtensionNode.php new file mode 100644 index 000000000..df45a2dfb --- /dev/null +++ b/src/Language/AST/TypeSystemExtensionNode.php @@ -0,0 +1,10 @@ + inputFieldsDefinition(Source|string $source, bool[] $options = []) * @method static TypeExtensionNode typeExtension(Source|string $source, bool[] $options = []) - * @method static SchemaTypeExtensionNode schemaTypeExtension(Source|string $source, bool[] $options = []) + * @method static SchemaExtensionNode schemaTypeExtension(Source|string $source, bool[] $options = []) * @method static ScalarTypeExtensionNode scalarTypeExtension(Source|string $source, bool[] $options = []) * @method static ObjectTypeExtensionNode objectTypeExtension(Source|string $source, bool[] $options = []) * @method static InterfaceTypeExtensionNode interfaceTypeExtension(Source|string $source, bool[] $options = []) @@ -508,10 +509,12 @@ private function parseDefinition(): DefinitionNode case 'union': case 'enum': case 'input': - case 'extend': case 'directive': // Note: The schema definition language is an experimental addition. return $this->parseTypeSystemDefinition(); + + case 'extend': + return $this->parseTypeSystemExtension(); } } elseif ($this->peek(Token::BRACE_L)) { return $this->parseExecutableDefinition(); @@ -1055,9 +1058,6 @@ private function parseTypeSystemDefinition(): TypeSystemDefinitionNode case 'input': return $this->parseInputObjectTypeDefinition(); - case 'extend': - return $this->parseTypeExtension(); - case 'directive': return $this->parseDirectiveDefinition(); } @@ -1404,9 +1404,9 @@ function (): InputValueDefinitionNode { } /** - * @return TypeExtensionNode&Node + * @return TypeSystemExtensionNode&Node */ - private function parseTypeExtension(): TypeExtensionNode + private function parseTypeSystemExtension(): TypeSystemExtensionNode { $keywordToken = $this->lexer->lookahead(); @@ -1438,7 +1438,7 @@ private function parseTypeExtension(): TypeExtensionNode throw $this->unexpected($keywordToken); } - private function parseSchemaTypeExtension(): SchemaTypeExtensionNode + private function parseSchemaTypeExtension(): SchemaExtensionNode { $start = $this->lexer->token; $this->expectKeyword('extend'); @@ -1456,7 +1456,7 @@ private function parseSchemaTypeExtension(): SchemaTypeExtensionNode $this->unexpected(); } - return new SchemaTypeExtensionNode([ + return new SchemaExtensionNode([ 'directives' => $directives, 'operationTypes' => $operationTypes, 'loc' => $this->loc($start), diff --git a/src/Language/Printer.php b/src/Language/Printer.php index be32e9f96..7f0a07d42 100644 --- a/src/Language/Printer.php +++ b/src/Language/Printer.php @@ -42,7 +42,7 @@ use GraphQL\Language\AST\ScalarTypeDefinitionNode; use GraphQL\Language\AST\ScalarTypeExtensionNode; use GraphQL\Language\AST\SchemaDefinitionNode; -use GraphQL\Language\AST\SchemaTypeExtensionNode; +use GraphQL\Language\AST\SchemaExtensionNode; use GraphQL\Language\AST\SelectionSetNode; use GraphQL\Language\AST\StringValueNode; use GraphQL\Language\AST\UnionTypeDefinitionNode; @@ -389,7 +389,7 @@ protected function p(?Node $node, bool $isDescription = false): string ' ' ); - case $node instanceof SchemaTypeExtensionNode: + case $node instanceof SchemaExtensionNode: return $this->join( [ 'extend schema', diff --git a/src/Type/Schema.php b/src/Type/Schema.php index ab2683a4d..d2c2313ca 100644 --- a/src/Type/Schema.php +++ b/src/Type/Schema.php @@ -7,7 +7,7 @@ use GraphQL\Error\InvariantViolation; use GraphQL\GraphQL; use GraphQL\Language\AST\SchemaDefinitionNode; -use GraphQL\Language\AST\SchemaTypeExtensionNode; +use GraphQL\Language\AST\SchemaExtensionNode; use GraphQL\Type\Definition\AbstractType; use GraphQL\Type\Definition\Directive; use GraphQL\Type\Definition\ImplementingType; @@ -70,7 +70,7 @@ class Schema /** @var array */ private array $validationErrors; - /** @var array */ + /** @var array */ public array $extensionASTNodes = []; /** diff --git a/src/Type/SchemaConfig.php b/src/Type/SchemaConfig.php index bf62da681..a7f6ec254 100644 --- a/src/Type/SchemaConfig.php +++ b/src/Type/SchemaConfig.php @@ -4,7 +4,7 @@ use function count; use GraphQL\Language\AST\SchemaDefinitionNode; -use GraphQL\Language\AST\SchemaTypeExtensionNode; +use GraphQL\Language\AST\SchemaExtensionNode; use GraphQL\Type\Definition\Directive; use GraphQL\Type\Definition\NamedType; use GraphQL\Type\Definition\ObjectType; @@ -56,7 +56,7 @@ class SchemaConfig public ?SchemaDefinitionNode $astNode = null; - /** @var array */ + /** @var array */ public array $extensionASTNodes = []; /** @@ -260,7 +260,7 @@ public function setAstNode(SchemaDefinitionNode $astNode): self } /** - * @return array + * @return array */ public function getExtensionASTNodes(): array { @@ -268,7 +268,7 @@ public function getExtensionASTNodes(): array } /** - * @param array $extensionASTNodes + * @param array $extensionASTNodes */ public function setExtensionASTNodes(array $extensionASTNodes): self { diff --git a/src/Type/SchemaValidationContext.php b/src/Type/SchemaValidationContext.php index 3992fe1e4..8f4fdbb8b 100644 --- a/src/Type/SchemaValidationContext.php +++ b/src/Type/SchemaValidationContext.php @@ -25,7 +25,7 @@ use GraphQL\Language\AST\ObjectTypeDefinitionNode; use GraphQL\Language\AST\ObjectTypeExtensionNode; use GraphQL\Language\AST\SchemaDefinitionNode; -use GraphQL\Language\AST\SchemaTypeExtensionNode; +use GraphQL\Language\AST\SchemaExtensionNode; use GraphQL\Language\AST\TypeNode; use GraphQL\Language\AST\UnionTypeDefinitionNode; use GraphQL\Language\AST\UnionTypeExtensionNode; @@ -468,7 +468,7 @@ private function validateFields(Type $type): void /** * @param Schema|ObjectType|InterfaceType|UnionType|EnumType|InputObjectType|Directive $obj * - * @return array|array|array|array|array|array|array + * @return array|array|array|array|array|array|array */ private function getAllNodes(object $obj): array { @@ -631,7 +631,7 @@ private function getDirectives(object $object): NodeList /** * Excluding directiveNode, since $object is not Directive. * - * @var SchemaDefinitionNode|SchemaTypeExtensionNode|ObjectTypeDefinitionNode|ObjectTypeExtensionNode|InterfaceTypeDefinitionNode|InterfaceTypeExtensionNode|UnionTypeDefinitionNode|UnionTypeExtensionNode|EnumTypeDefinitionNode|EnumTypeExtensionNode|InputObjectTypeDefinitionNode|InputObjectTypeExtensionNode $node + * @var SchemaDefinitionNode|SchemaExtensionNode|ObjectTypeDefinitionNode|ObjectTypeExtensionNode|InterfaceTypeDefinitionNode|InterfaceTypeExtensionNode|UnionTypeDefinitionNode|UnionTypeExtensionNode|EnumTypeDefinitionNode|EnumTypeExtensionNode|InputObjectTypeDefinitionNode|InputObjectTypeExtensionNode $node */ // @phpstan-ignore-next-line union types are not pervasive foreach ($this->getAllNodes($object) as $node) { diff --git a/src/Utils/SchemaExtender.php b/src/Utils/SchemaExtender.php index f780b176c..f0a3a2ccf 100644 --- a/src/Utils/SchemaExtender.php +++ b/src/Utils/SchemaExtender.php @@ -16,7 +16,7 @@ use GraphQL\Language\AST\ObjectTypeExtensionNode; use GraphQL\Language\AST\ScalarTypeExtensionNode; use GraphQL\Language\AST\SchemaDefinitionNode; -use GraphQL\Language\AST\SchemaTypeExtensionNode; +use GraphQL\Language\AST\SchemaExtensionNode; use GraphQL\Language\AST\TypeDefinitionNode; use GraphQL\Language\AST\TypeExtensionNode; use GraphQL\Language\AST\UnionTypeExtensionNode; @@ -567,13 +567,13 @@ public static function extend( /** @var SchemaDefinitionNode|null $schemaDef */ $schemaDef = null; - /** @var array $schemaExtensions */ + /** @var array $schemaExtensions */ $schemaExtensions = []; foreach ($documentAST->definitions as $def) { if ($def instanceof SchemaDefinitionNode) { $schemaDef = $def; - } elseif ($def instanceof SchemaTypeExtensionNode) { + } elseif ($def instanceof SchemaExtensionNode) { $schemaExtensions[] = $def; } elseif ($def instanceof TypeDefinitionNode) { $typeName = isset($def->name) diff --git a/src/Validator/Rules/ExecutableDefinitions.php b/src/Validator/Rules/ExecutableDefinitions.php index d0cdaebb2..8e3a642e1 100644 --- a/src/Validator/Rules/ExecutableDefinitions.php +++ b/src/Validator/Rules/ExecutableDefinitions.php @@ -6,6 +6,10 @@ use GraphQL\Language\AST\DocumentNode; use GraphQL\Language\AST\ExecutableDefinitionNode; use GraphQL\Language\AST\NodeKind; +use GraphQL\Language\AST\SchemaDefinitionNode; +use GraphQL\Language\AST\SchemaExtensionNode; +use GraphQL\Language\AST\TypeDefinitionNode; +use GraphQL\Language\AST\TypeExtensionNode; use GraphQL\Language\AST\TypeSystemDefinitionNode; use GraphQL\Language\Visitor; use GraphQL\Language\VisitorOperation; @@ -25,11 +29,19 @@ public function getVisitor(ValidationContext $context): array NodeKind::DOCUMENT => static function (DocumentNode $node) use ($context): VisitorOperation { foreach ($node->definitions as $definition) { if (! $definition instanceof ExecutableDefinitionNode) { - assert($definition instanceof TypeSystemDefinitionNode, 'only other option'); + if ($definition instanceof SchemaDefinitionNode || $definition instanceof SchemaExtensionNode) { + $defName = 'schema'; + } else { + assert( + $definition instanceof TypeDefinitionNode || $definition instanceof TypeExtensionNode, + 'only other option' + ); + $defName = "\"{$definition->name->value}\""; + } $context->reportError(new Error( - static::nonExecutableDefinitionMessage($definition->name->value), - [$definition->name] + static::nonExecutableDefinitionMessage($defName), + [$definition] )); } } @@ -41,6 +53,6 @@ public function getVisitor(ValidationContext $context): array public static function nonExecutableDefinitionMessage(string $defName): string { - return "The \"{$defName}\" definition is not executable."; + return "The {$defName} definition is not executable."; } } diff --git a/src/Validator/Rules/KnownDirectives.php b/src/Validator/Rules/KnownDirectives.php index 15dd3b2d3..a4191487d 100644 --- a/src/Validator/Rules/KnownDirectives.php +++ b/src/Validator/Rules/KnownDirectives.php @@ -30,7 +30,7 @@ use GraphQL\Language\AST\ScalarTypeDefinitionNode; use GraphQL\Language\AST\ScalarTypeExtensionNode; use GraphQL\Language\AST\SchemaDefinitionNode; -use GraphQL\Language\AST\SchemaTypeExtensionNode; +use GraphQL\Language\AST\SchemaExtensionNode; use GraphQL\Language\AST\UnionTypeDefinitionNode; use GraphQL\Language\AST\UnionTypeExtensionNode; use GraphQL\Language\AST\VariableDefinitionNode; @@ -166,7 +166,7 @@ protected function getDirectiveLocationForASTPath(array $ancestors): string return DirectiveLocation::VARIABLE_DEFINITION; case $appliedTo instanceof SchemaDefinitionNode: - case $appliedTo instanceof SchemaTypeExtensionNode: + case $appliedTo instanceof SchemaExtensionNode: return DirectiveLocation::SCHEMA; case $appliedTo instanceof ScalarTypeDefinitionNode: diff --git a/src/Validator/Rules/UniqueOperationTypes.php b/src/Validator/Rules/UniqueOperationTypes.php index f9b43adc1..0a7737a81 100644 --- a/src/Validator/Rules/UniqueOperationTypes.php +++ b/src/Validator/Rules/UniqueOperationTypes.php @@ -5,7 +5,7 @@ use GraphQL\Error\Error; use GraphQL\Language\AST\NodeKind; use GraphQL\Language\AST\SchemaDefinitionNode; -use GraphQL\Language\AST\SchemaTypeExtensionNode; +use GraphQL\Language\AST\SchemaExtensionNode; use GraphQL\Language\Visitor; use GraphQL\Language\VisitorOperation; use GraphQL\Validator\SDLValidationContext; @@ -30,7 +30,7 @@ public function getSDLVisitor(SDLValidationContext $context): array : []; /** - * @param SchemaDefinitionNode|SchemaTypeExtensionNode $node + * @param SchemaDefinitionNode|SchemaExtensionNode $node */ $checkOperationTypes = static function ($node) use ($context, &$definedOperationTypes, $existingOperationTypes): VisitorOperation { foreach ($node->operationTypes as $operationType) { diff --git a/tests/Validator/CustomRuleTest.php b/tests/Validator/CustomRuleTest.php index a547c7b23..20bbdfe4a 100644 --- a/tests/Validator/CustomRuleTest.php +++ b/tests/Validator/CustomRuleTest.php @@ -44,8 +44,8 @@ public static function nonExecutableDefinitionMessage(string $defName): string ', [ ErrorHelper::create( - 'Custom message including Cow', - [new SourceLocation(8, 12)] + 'Custom message including "Cow"', + [new SourceLocation(8, 7)] ), ] ); diff --git a/tests/Validator/ExecutableDefinitionsTest.php b/tests/Validator/ExecutableDefinitionsTest.php index 72f591dd2..6222a9d76 100644 --- a/tests/Validator/ExecutableDefinitionsTest.php +++ b/tests/Validator/ExecutableDefinitionsTest.php @@ -75,8 +75,8 @@ public function testWithTypeDefinition(): void } ', [ - $this->nonExecutableDefinition('Cow', 8, 12), - $this->nonExecutableDefinition('Dog', 12, 19), + $this->nonExecutableDefinition('"Cow"', 8, 7), + $this->nonExecutableDefinition('"Dog"', 12, 7), ] ); }