diff --git a/docs/class-reference.md b/docs/class-reference.md index 63102a358..b16254679 100644 --- a/docs/class-reference.md +++ b/docs/class-reference.md @@ -1298,8 +1298,103 @@ visitor API: ] ]); -@phpstan-type NodeVisitor callable(Node): (VisitorOperation|null|false|void) -@phpstan-type VisitorArray array|array> +@phpstan-type VisitorReturnType Node|VisitorOperation|null|false|void +@phpstan-type VisitorArray array{ +enter?: callable(Node, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(Node, string, null|Node|NodeList, array, array): VisitorReturnType, +Name?: array{ +enter?: callable(NameNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(NameNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(NameNode, string, null|Node|NodeList, array, array): VisitorReturnType, +Document?: array{ +enter?: callable(DocumentNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(DocumentNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(DocumentNode, string, null|Node|NodeList, array, array): VisitorReturnType, +OperationDefinition?: array{ +enter?: callable(OperationDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(OperationDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(OperationDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +VariableDefinition?: array{ +enter?: callable(VariableDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(VariableDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(VariableDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +SchemaDefinition?: array{ +enter?: callable(SchemaDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(SchemaDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(SchemaDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +OperationTypeDefinition?: array{ +enter?: callable(OperationTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(OperationTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(OperationTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +ScalarTypeDefinition?: array{ +enter?: callable(ScalarTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(ScalarTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(ScalarTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +ObjectTypeDefinition?: array{ +enter?: callable(ObjectTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(ObjectTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(ObjectTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +FieldDefinition?: array{ +enter?: callable(FieldDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(FieldDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(FieldDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +InputValueDefinition?: array{ +enter?: callable(InputValueDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(InputValueDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(InputValueDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +InterfaceTypeDefinition?: array{ +enter?: callable(InterfaceTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(InterfaceTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(InterfaceTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +UnionTypeDefinition?: array{ +enter?: callable(UnionTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(UnionTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(UnionTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +EnumTypeDefinition?: array{ +enter?: callable(EnumTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(EnumTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(EnumTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +EnumValueDefinition?: array{ +enter?: callable(EnumValueDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(EnumValueDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(EnumValueDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +InputObjectTypeDefinition?: array{ +enter?: callable(InputObjectTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(InputObjectTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(InputObjectTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +SchemaExtension?: array{ +enter?: callable(SchemaExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(SchemaExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(SchemaExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +DirectiveDefinition?: array{ +enter?: callable(DirectiveDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(DirectiveDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(DirectiveDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +ScalarTypeExtension?: array{ +enter?: callable(ScalarTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(ScalarTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(ScalarTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +ObjectTypeExtension?: array{ +enter?: callable(ObjectTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(ObjectTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(ObjectTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +InterfaceTypeExtension?: array{ +enter?: callable(InterfaceTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(InterfaceTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(InterfaceTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +UnionTypeExtension?: array{ +enter?: callable(UnionTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(UnionTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(UnionTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +EnumTypeExtension?: array{ +enter?: callable(EnumTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(EnumTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(EnumTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +InputObjectTypeExtension?: array{ +enter?: callable(InputObjectTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +leave?: callable(InputObjectTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +}|callable(InputObjectTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, +} @see \GraphQL\Tests\Language\VisitorTest diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index c9ad1df81..b28a860ba 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -75,11 +75,6 @@ parameters: count: 1 path: src/Utils/AST.php - - - message: "#^Method GraphQL\\\\Validator\\\\Rules\\\\KnownDirectives\\:\\:getDirectiveLocationForASTPath\\(\\) has parameter \\$ancestors with generic class GraphQL\\\\Language\\\\AST\\\\NodeList but does not specify its types\\: T$#" - count: 1 - path: src/Validator/Rules/KnownDirectives.php - - message: "#^Method GraphQL\\\\Validator\\\\Rules\\\\OverlappingFieldsCanBeMerged\\:\\:getFieldsAndFragmentNames\\(\\) should return array\\{array\\\\>, array\\\\} but returns array\\{mixed, array\\\\}\\.$#" count: 1 @@ -88,4 +83,4 @@ parameters: - message: "#^SplObjectStorage\\\\>, array\\\\}\\> does not accept array\\\\.$#" count: 1 - path: src/Validator/Rules/OverlappingFieldsCanBeMerged.php \ No newline at end of file + path: src/Validator/Rules/OverlappingFieldsCanBeMerged.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 4fd2c394e..9b19b9b8c 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -34,9 +34,6 @@ parameters: - message: "#^Property GraphQL\\\\Tests\\\\Type\\\\SchemaTest\\:\\:\\$implementingType is never read, only written\\.$#" path: tests - # Cannot satisfy input covariance - - '~(expects|should return) array\|\(callable\(GraphQL\\Language\\AST\\Node\): \(GraphQL\\Language\\VisitorOperation\|void\|false\|null\)\)>(,| but returns)?~' - # No need to have @throws in methods that are never called ## PHPUnit - message: "~Method GraphQL\\\\Tests\\\\.+?Test(CaseBase)?::(test.+?|setUp(BeforeClass)?|tearDown)\\(\\) throws checked exception .+? but it's missing from the PHPDoc @throws tag~" diff --git a/src/Language/AST/NodeList.php b/src/Language/AST/NodeList.php index 01071d476..6329de7fe 100644 --- a/src/Language/AST/NodeList.php +++ b/src/Language/AST/NodeList.php @@ -6,7 +6,7 @@ use GraphQL\Utils\AST; /** - * @template T of Node + * @template T of Node = Node * * @phpstan-implements \ArrayAccess * @phpstan-implements \IteratorAggregate diff --git a/src/Language/Visitor.php b/src/Language/Visitor.php index ad8892c7e..6582f8377 100644 --- a/src/Language/Visitor.php +++ b/src/Language/Visitor.php @@ -2,9 +2,32 @@ namespace GraphQL\Language; +use GraphQL\Language\AST\DirectiveDefinitionNode; +use GraphQL\Language\AST\DocumentNode; +use GraphQL\Language\AST\EnumTypeDefinitionNode; +use GraphQL\Language\AST\EnumTypeExtensionNode; +use GraphQL\Language\AST\EnumValueDefinitionNode; +use GraphQL\Language\AST\FieldDefinitionNode; +use GraphQL\Language\AST\InputObjectTypeDefinitionNode; +use GraphQL\Language\AST\InputObjectTypeExtensionNode; +use GraphQL\Language\AST\InputValueDefinitionNode; +use GraphQL\Language\AST\InterfaceTypeDefinitionNode; +use GraphQL\Language\AST\InterfaceTypeExtensionNode; +use GraphQL\Language\AST\NameNode; use GraphQL\Language\AST\Node; use GraphQL\Language\AST\NodeKind; use GraphQL\Language\AST\NodeList; +use GraphQL\Language\AST\ObjectTypeDefinitionNode; +use GraphQL\Language\AST\ObjectTypeExtensionNode; +use GraphQL\Language\AST\OperationDefinitionNode; +use GraphQL\Language\AST\OperationTypeDefinitionNode; +use GraphQL\Language\AST\ScalarTypeDefinitionNode; +use GraphQL\Language\AST\ScalarTypeExtensionNode; +use GraphQL\Language\AST\SchemaDefinitionNode; +use GraphQL\Language\AST\SchemaExtensionNode; +use GraphQL\Language\AST\UnionTypeDefinitionNode; +use GraphQL\Language\AST\UnionTypeExtensionNode; +use GraphQL\Language\AST\VariableDefinitionNode; use GraphQL\Utils\TypeInfo; use GraphQL\Utils\Utils; @@ -89,8 +112,103 @@ * ] * ]); * - * @phpstan-type NodeVisitor callable(Node): (VisitorOperation|null|false|void) - * @phpstan-type VisitorArray array|array> + * @phpstan-type VisitorReturnType Node|VisitorOperation|null|false|void + * @phpstan-type VisitorArray array{ + * enter?: callable(Node, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(Node, string, null|Node|NodeList, array, array): VisitorReturnType, + * Name?: array{ + * enter?: callable(NameNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(NameNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(NameNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * Document?: array{ + * enter?: callable(DocumentNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(DocumentNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(DocumentNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * OperationDefinition?: array{ + * enter?: callable(OperationDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(OperationDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(OperationDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * VariableDefinition?: array{ + * enter?: callable(VariableDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(VariableDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(VariableDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * SchemaDefinition?: array{ + * enter?: callable(SchemaDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(SchemaDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(SchemaDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * OperationTypeDefinition?: array{ + * enter?: callable(OperationTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(OperationTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(OperationTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * ScalarTypeDefinition?: array{ + * enter?: callable(ScalarTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(ScalarTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(ScalarTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * ObjectTypeDefinition?: array{ + * enter?: callable(ObjectTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(ObjectTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(ObjectTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * FieldDefinition?: array{ + * enter?: callable(FieldDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(FieldDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(FieldDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * InputValueDefinition?: array{ + * enter?: callable(InputValueDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(InputValueDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(InputValueDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * InterfaceTypeDefinition?: array{ + * enter?: callable(InterfaceTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(InterfaceTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(InterfaceTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * UnionTypeDefinition?: array{ + * enter?: callable(UnionTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(UnionTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(UnionTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * EnumTypeDefinition?: array{ + * enter?: callable(EnumTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(EnumTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(EnumTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * EnumValueDefinition?: array{ + * enter?: callable(EnumValueDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(EnumValueDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(EnumValueDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * InputObjectTypeDefinition?: array{ + * enter?: callable(InputObjectTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(InputObjectTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(InputObjectTypeDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * SchemaExtension?: array{ + * enter?: callable(SchemaExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(SchemaExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(SchemaExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * DirectiveDefinition?: array{ + * enter?: callable(DirectiveDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(DirectiveDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(DirectiveDefinitionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * ScalarTypeExtension?: array{ + * enter?: callable(ScalarTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(ScalarTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(ScalarTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * ObjectTypeExtension?: array{ + * enter?: callable(ObjectTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(ObjectTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(ObjectTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * InterfaceTypeExtension?: array{ + * enter?: callable(InterfaceTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(InterfaceTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(InterfaceTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * UnionTypeExtension?: array{ + * enter?: callable(UnionTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(UnionTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(UnionTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * EnumTypeExtension?: array{ + * enter?: callable(EnumTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(EnumTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(EnumTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * InputObjectTypeExtension?: array{ + * enter?: callable(InputObjectTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * leave?: callable(InputObjectTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * }|callable(InputObjectTypeExtensionNode, string, null|Node|NodeList, array, array): VisitorReturnType, + * } * * @see \GraphQL\Tests\Language\VisitorTest */ @@ -478,7 +596,7 @@ public static function visitWithTypeInfo(TypeInfo $typeInfo, array $visitor): ar /** * @phpstan-param VisitorArray $visitor * - * @return callable(Node $node, string $key, Node|NodeList $parent, array $ancestors): VisitorOperation|Node|null + * @return null|callable(Node, string, null|Node|NodeList, array, array): VisitorReturnType */ protected static function extractVisitFn(array $visitor, string $kind, bool $isLeaving): ?callable { @@ -491,6 +609,7 @@ protected static function extractVisitFn(array $visitor, string $kind, bool $isL } if ($kindVisitor !== null && ! $isLeaving) { + // @phpstan-ignore return.type return $kindVisitor; } diff --git a/src/Validator/Rules/CustomValidationRule.php b/src/Validator/Rules/CustomValidationRule.php index c0e659729..b2712286c 100644 --- a/src/Validator/Rules/CustomValidationRule.php +++ b/src/Validator/Rules/CustomValidationRule.php @@ -3,15 +3,15 @@ namespace GraphQL\Validator\Rules; use GraphQL\Language\AST\Node; +use GraphQL\Language\Visitor; use GraphQL\Language\VisitorOperation; use GraphQL\Validator\ValidationContext; /** * @see Node, VisitorOperation * - * @phpstan-type NodeVisitorFnResult VisitorOperation|mixed|null - * @phpstan-type VisitorFnResult array|array> - * @phpstan-type VisitorFn callable(ValidationContext): VisitorFnResult + * @phpstan-import-type VisitorArray from Visitor + * @phpstan-type VisitorFn callable(ValidationContext): VisitorArray */ class CustomValidationRule extends ValidationRule {