mirror of
https://github.com/retailcrm/graphql-php.git
synced 2025-02-06 15:59:24 +03:00
Added validation rule for unique directives per location
This commit is contained in:
parent
8a676cde99
commit
f672f0c90c
@ -43,6 +43,7 @@ use GraphQL\Validator\Rules\QueryComplexity;
|
|||||||
use GraphQL\Validator\Rules\QueryDepth;
|
use GraphQL\Validator\Rules\QueryDepth;
|
||||||
use GraphQL\Validator\Rules\ScalarLeafs;
|
use GraphQL\Validator\Rules\ScalarLeafs;
|
||||||
use GraphQL\Validator\Rules\UniqueArgumentNames;
|
use GraphQL\Validator\Rules\UniqueArgumentNames;
|
||||||
|
use GraphQL\Validator\Rules\UniqueDirectivesPerLocation;
|
||||||
use GraphQL\Validator\Rules\UniqueFragmentNames;
|
use GraphQL\Validator\Rules\UniqueFragmentNames;
|
||||||
use GraphQL\Validator\Rules\UniqueInputFieldNames;
|
use GraphQL\Validator\Rules\UniqueInputFieldNames;
|
||||||
use GraphQL\Validator\Rules\UniqueOperationNames;
|
use GraphQL\Validator\Rules\UniqueOperationNames;
|
||||||
@ -88,6 +89,7 @@ class DocumentValidator
|
|||||||
'NoUndefinedVariables' => new NoUndefinedVariables(),
|
'NoUndefinedVariables' => new NoUndefinedVariables(),
|
||||||
'NoUnusedVariables' => new NoUnusedVariables(),
|
'NoUnusedVariables' => new NoUnusedVariables(),
|
||||||
'KnownDirectives' => new KnownDirectives(),
|
'KnownDirectives' => new KnownDirectives(),
|
||||||
|
'UniqueDirectivesPerLocation' => new UniqueDirectivesPerLocation(),
|
||||||
'KnownArgumentNames' => new KnownArgumentNames(),
|
'KnownArgumentNames' => new KnownArgumentNames(),
|
||||||
'UniqueArgumentNames' => new UniqueArgumentNames(),
|
'UniqueArgumentNames' => new UniqueArgumentNames(),
|
||||||
'ArgumentsOfCorrectType' => new ArgumentsOfCorrectType(),
|
'ArgumentsOfCorrectType' => new ArgumentsOfCorrectType(),
|
||||||
|
38
src/Validator/Rules/UniqueDirectivesPerLocation.php
Normal file
38
src/Validator/Rules/UniqueDirectivesPerLocation.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
namespace GraphQL\Validator\Rules;
|
||||||
|
|
||||||
|
use GraphQL\Error\Error;
|
||||||
|
use GraphQL\Language\AST\Directive;
|
||||||
|
use GraphQL\Language\AST\Node;
|
||||||
|
use GraphQL\Validator\ValidationContext;
|
||||||
|
|
||||||
|
class UniqueDirectivesPerLocation
|
||||||
|
{
|
||||||
|
static function duplicateDirectiveMessage($directiveName)
|
||||||
|
{
|
||||||
|
return 'The directive "'.$directiveName.'" can only be used once at this location.';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __invoke(ValidationContext $context)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'enter' => function(Node $node) use ($context) {
|
||||||
|
if (isset($node->directives)) {
|
||||||
|
$knownDirectives = [];
|
||||||
|
foreach ($node->directives as $directive) {
|
||||||
|
/** @var Directive $directive */
|
||||||
|
$directiveName = $directive->name->value;
|
||||||
|
if (isset($knownDirectives[$directiveName])) {
|
||||||
|
$context->reportError(new Error(
|
||||||
|
self::duplicateDirectiveMessage($directiveName),
|
||||||
|
[$knownDirectives[$directiveName], $directive]
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
$knownDirectives[$directiveName] = $directive;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
138
tests/Validator/UniqueDirectivesPerLocationTest.php
Normal file
138
tests/Validator/UniqueDirectivesPerLocationTest.php
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
<?php
|
||||||
|
namespace GraphQL\Tests\Validator;
|
||||||
|
|
||||||
|
use GraphQL\Validator\Rules\UniqueDirectivesPerLocation;
|
||||||
|
|
||||||
|
class UniqueDirectivesPerLocationTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @it no directives
|
||||||
|
*/
|
||||||
|
public function testNoDirectives()
|
||||||
|
{
|
||||||
|
$this->expectPassesRule(new UniqueDirectivesPerLocation(), '
|
||||||
|
fragment Test on Type {
|
||||||
|
field
|
||||||
|
}
|
||||||
|
');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it unique directives in different locations
|
||||||
|
*/
|
||||||
|
public function testUniqueDirectivesInDifferentLocations()
|
||||||
|
{
|
||||||
|
$this->expectPassesRule(new UniqueDirectivesPerLocation(), '
|
||||||
|
fragment Test on Type @directiveA {
|
||||||
|
field @directiveB
|
||||||
|
}
|
||||||
|
');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it unique directives in same locations
|
||||||
|
*/
|
||||||
|
public function testUniqueDirectivesInSameLocations()
|
||||||
|
{
|
||||||
|
$this->expectPassesRule(new UniqueDirectivesPerLocation(), '
|
||||||
|
fragment Test on Type @directiveA @directiveB {
|
||||||
|
field @directiveA @directiveB
|
||||||
|
}
|
||||||
|
');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it same directives in different locations
|
||||||
|
*/
|
||||||
|
public function testSameDirectivesInDifferentLocations()
|
||||||
|
{
|
||||||
|
$this->expectPassesRule(new UniqueDirectivesPerLocation(), '
|
||||||
|
fragment Test on Type @directiveA {
|
||||||
|
field @directiveA
|
||||||
|
}
|
||||||
|
');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it same directives in similar locations
|
||||||
|
*/
|
||||||
|
public function testSameDirectivesInSimilarLocations()
|
||||||
|
{
|
||||||
|
$this->expectPassesRule(new UniqueDirectivesPerLocation(), '
|
||||||
|
fragment Test on Type {
|
||||||
|
field @directive
|
||||||
|
field @directive
|
||||||
|
}
|
||||||
|
');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it duplicate directives in one location
|
||||||
|
*/
|
||||||
|
public function testDuplicateDirectivesInOneLocation()
|
||||||
|
{
|
||||||
|
$this->expectFailsRule(new UniqueDirectivesPerLocation(), '
|
||||||
|
fragment Test on Type {
|
||||||
|
field @directive @directive
|
||||||
|
}
|
||||||
|
', [
|
||||||
|
$this->duplicateDirective('directive', 3, 15, 3, 26)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it many duplicate directives in one location
|
||||||
|
*/
|
||||||
|
public function testManyDuplicateDirectivesInOneLocation()
|
||||||
|
{
|
||||||
|
$this->expectFailsRule(new UniqueDirectivesPerLocation(), '
|
||||||
|
fragment Test on Type {
|
||||||
|
field @directive @directive @directive
|
||||||
|
}
|
||||||
|
', [
|
||||||
|
$this->duplicateDirective('directive', 3, 15, 3, 26),
|
||||||
|
$this->duplicateDirective('directive', 3, 15, 3, 37)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it different duplicate directives in one location
|
||||||
|
*/
|
||||||
|
public function testDifferentDuplicateDirectivesInOneLocation()
|
||||||
|
{
|
||||||
|
$this->expectFailsRule(new UniqueDirectivesPerLocation, '
|
||||||
|
fragment Test on Type {
|
||||||
|
field @directiveA @directiveB @directiveA @directiveB
|
||||||
|
}
|
||||||
|
', [
|
||||||
|
$this->duplicateDirective('directiveA', 3, 15, 3, 39),
|
||||||
|
$this->duplicateDirective('directiveB', 3, 27, 3, 51)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it duplicate directives in many locations
|
||||||
|
*/
|
||||||
|
public function testDuplicateDirectivesInManyLocations()
|
||||||
|
{
|
||||||
|
$this->expectFailsRule(new UniqueDirectivesPerLocation(), '
|
||||||
|
fragment Test on Type @directive @directive {
|
||||||
|
field @directive @directive
|
||||||
|
}
|
||||||
|
', [
|
||||||
|
$this->duplicateDirective('directive', 2, 29, 2, 40),
|
||||||
|
$this->duplicateDirective('directive', 3, 15, 3, 26)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function duplicateDirective($directiveName, $l1, $c1, $l2, $c2)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'message' =>UniqueDirectivesPerLocation::duplicateDirectiveMessage($directiveName),
|
||||||
|
'locations' => [
|
||||||
|
['line' => $l1, 'column' => $c1],
|
||||||
|
['line' => $l2, 'column' => $c2]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user