GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

KnownDirectives::getSDLVisitor()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Validator\Rules;
6
7
use Exception;
8
use GraphQL\Error\Error;
9
use GraphQL\Language\AST\DirectiveDefinitionNode;
10
use GraphQL\Language\AST\DirectiveNode;
11
use GraphQL\Language\AST\EnumTypeDefinitionNode;
12
use GraphQL\Language\AST\EnumTypeExtensionNode;
13
use GraphQL\Language\AST\EnumValueDefinitionNode;
14
use GraphQL\Language\AST\FieldDefinitionNode;
15
use GraphQL\Language\AST\FieldNode;
16
use GraphQL\Language\AST\FragmentDefinitionNode;
17
use GraphQL\Language\AST\FragmentSpreadNode;
18
use GraphQL\Language\AST\InlineFragmentNode;
19
use GraphQL\Language\AST\InputObjectTypeDefinitionNode;
20
use GraphQL\Language\AST\InputObjectTypeExtensionNode;
21
use GraphQL\Language\AST\InputValueDefinitionNode;
22
use GraphQL\Language\AST\InterfaceTypeDefinitionNode;
23
use GraphQL\Language\AST\InterfaceTypeExtensionNode;
24
use GraphQL\Language\AST\Node;
25
use GraphQL\Language\AST\NodeKind;
26
use GraphQL\Language\AST\NodeList;
27
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
28
use GraphQL\Language\AST\ObjectTypeExtensionNode;
29
use GraphQL\Language\AST\OperationDefinitionNode;
30
use GraphQL\Language\AST\ScalarTypeDefinitionNode;
31
use GraphQL\Language\AST\ScalarTypeExtensionNode;
32
use GraphQL\Language\AST\SchemaDefinitionNode;
33
use GraphQL\Language\AST\SchemaTypeExtensionNode;
34
use GraphQL\Language\AST\UnionTypeDefinitionNode;
35
use GraphQL\Language\AST\UnionTypeExtensionNode;
36
use GraphQL\Language\AST\VariableDefinitionNode;
37
use GraphQL\Language\DirectiveLocation;
38
use GraphQL\Type\Definition\Directive;
39
use GraphQL\Validator\ASTValidationContext;
40
use GraphQL\Validator\SDLValidationContext;
41
use GraphQL\Validator\ValidationContext;
42
use function array_map;
43
use function count;
44
use function get_class;
45
use function in_array;
46
use function sprintf;
47
48
class KnownDirectives extends ValidationRule
49
{
50 127
    public function getVisitor(ValidationContext $context)
51
    {
52 127
        return $this->getASTVisitor($context);
53
    }
54
55 207
    public function getSDLVisitor(SDLValidationContext $context)
56
    {
57 207
        return $this->getASTVisitor($context);
58
    }
59
60 319
    public function getASTVisitor(ASTValidationContext $context)
61
    {
62 319
        $locationsMap      = [];
63 319
        $schema            = $context->getSchema();
64 319
        $definedDirectives = $schema
0 ignored issues
show
introduced by
$schema is of type GraphQL\Type\Schema, thus it always evaluated to true.
Loading history...
65 194
            ? $schema->getDirectives()
66 319
            : Directive::getInternalDirectives();
67
68 319
        foreach ($definedDirectives as $directive) {
69 319
            $locationsMap[$directive->name] = $directive->locations;
70
        }
71
72 319
        $astDefinition = $context->getDocument()->definitions;
73
74 319
        foreach ($astDefinition as $def) {
75 319
            if (! ($def instanceof DirectiveDefinitionNode)) {
76 313
                continue;
77
            }
78
79 37
            $locationsMap[$def->name->value] = array_map(
80
                static function ($name) : string {
81 37
                    return $name->value;
82 37
                },
83 37
                $def->locations
84
            );
85
        }
86
87
        return [
88
            NodeKind::DIRECTIVE => function (
89
                DirectiveNode $node,
90
                $key,
91
                $parent,
92
                $path,
93
                $ancestors
94
            ) use (
95 32
                $context,
96 32
                $locationsMap
97
            ) : void {
98 32
                $name      = $node->name->value;
99 32
                $locations = $locationsMap[$name] ?? null;
100
101 32
                if (! $locations) {
102 5
                    $context->reportError(new Error(
103 5
                        self::unknownDirectiveMessage($name),
104 5
                        [$node]
105
                    ));
106
107 5
                    return;
108
                }
109
110 27
                $candidateLocation = $this->getDirectiveLocationForASTPath($ancestors);
111
112 27
                if (! $candidateLocation || in_array($candidateLocation, $locations, true)) {
113 25
                    return;
114
                }
115 3
                $context->reportError(
116 3
                    new Error(
117 3
                        self::misplacedDirectiveMessage($name, $candidateLocation),
118 3
                        [$node]
119
                    )
120
                );
121 319
            },
122
        ];
123
    }
124
125 5
    public static function unknownDirectiveMessage($directiveName)
126
    {
127 5
        return sprintf('Unknown directive "%s".', $directiveName);
128
    }
129
130
    /**
131
     * @param Node[]|NodeList[] $ancestors The type is actually (Node|NodeList)[] but this PSR-5 syntax is so far not supported by most of the tools
132
     *
133
     * @return string
134
     */
135 27
    private function getDirectiveLocationForASTPath(array $ancestors)
136
    {
137 27
        $appliedTo = $ancestors[count($ancestors) - 1];
138
        switch (true) {
139 27
            case $appliedTo instanceof OperationDefinitionNode:
140 2
                switch ($appliedTo->operation) {
141 2
                    case 'query':
142 2
                        return DirectiveLocation::QUERY;
143 2
                    case 'mutation':
144 2
                        return DirectiveLocation::MUTATION;
145
                    case 'subscription':
146
                        return DirectiveLocation::SUBSCRIPTION;
147
                }
148
                break;
149 27
            case $appliedTo instanceof FieldNode:
150 3
                return DirectiveLocation::FIELD;
151 26
            case $appliedTo instanceof FragmentSpreadNode:
152 2
                return DirectiveLocation::FRAGMENT_SPREAD;
153 24
            case $appliedTo instanceof InlineFragmentNode:
154
                return DirectiveLocation::INLINE_FRAGMENT;
155 24
            case $appliedTo instanceof FragmentDefinitionNode:
156
                return DirectiveLocation::FRAGMENT_DEFINITION;
157 24
            case $appliedTo instanceof VariableDefinitionNode:
158 2
                return DirectiveLocation::VARIABLE_DEFINITION;
159 22
            case $appliedTo instanceof SchemaDefinitionNode:
160 20
            case $appliedTo instanceof SchemaTypeExtensionNode:
161 6
                return DirectiveLocation::SCHEMA;
162 19
            case $appliedTo instanceof ScalarTypeDefinitionNode:
163 19
            case $appliedTo instanceof ScalarTypeExtensionNode:
164 6
                return DirectiveLocation::SCALAR;
165 17
            case $appliedTo instanceof ObjectTypeDefinitionNode:
166 17
            case $appliedTo instanceof ObjectTypeExtensionNode:
167 8
                return DirectiveLocation::OBJECT;
168 14
            case $appliedTo instanceof FieldDefinitionNode:
169 8
                return DirectiveLocation::FIELD_DEFINITION;
170 11
            case $appliedTo instanceof InterfaceTypeDefinitionNode:
171 11
            case $appliedTo instanceof InterfaceTypeExtensionNode:
172 5
                return DirectiveLocation::IFACE;
173 11
            case $appliedTo instanceof UnionTypeDefinitionNode:
174 11
            case $appliedTo instanceof UnionTypeExtensionNode:
175 6
                return DirectiveLocation::UNION;
176 10
            case $appliedTo instanceof EnumTypeDefinitionNode:
177 10
            case $appliedTo instanceof EnumTypeExtensionNode:
178 6
                return DirectiveLocation::ENUM;
179 9
            case $appliedTo instanceof EnumValueDefinitionNode:
180 6
                return DirectiveLocation::ENUM_VALUE;
181 6
            case $appliedTo instanceof InputObjectTypeDefinitionNode:
182 6
            case $appliedTo instanceof InputObjectTypeExtensionNode:
183 6
                return DirectiveLocation::INPUT_OBJECT;
184 3
            case $appliedTo instanceof InputValueDefinitionNode:
185 3
                $parentNode = $ancestors[count($ancestors) - 3];
186
187 3
                return $parentNode instanceof InputObjectTypeDefinitionNode
188 3
                    ? DirectiveLocation::INPUT_FIELD_DEFINITION
189 3
                    : DirectiveLocation::ARGUMENT_DEFINITION;
190
        }
191
192
        throw new Exception('Unknown directive location: ' . get_class($appliedTo));
193
    }
194
195 3
    public static function misplacedDirectiveMessage($directiveName, $location)
196
    {
197 3
        return sprintf('Directive "%s" may not be used on "%s".', $directiveName, $location);
198
    }
199
}
200