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.

TypeInfo::getDefaultValue()   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 0
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Utils;
6
7
use GraphQL\Error\InvariantViolation;
8
use GraphQL\Language\AST\ArgumentNode;
9
use GraphQL\Language\AST\DirectiveNode;
10
use GraphQL\Language\AST\EnumValueNode;
11
use GraphQL\Language\AST\FieldNode;
12
use GraphQL\Language\AST\FragmentDefinitionNode;
13
use GraphQL\Language\AST\InlineFragmentNode;
14
use GraphQL\Language\AST\ListTypeNode;
15
use GraphQL\Language\AST\ListValueNode;
16
use GraphQL\Language\AST\NamedTypeNode;
17
use GraphQL\Language\AST\Node;
18
use GraphQL\Language\AST\NonNullTypeNode;
19
use GraphQL\Language\AST\ObjectFieldNode;
20
use GraphQL\Language\AST\OperationDefinitionNode;
21
use GraphQL\Language\AST\SelectionSetNode;
22
use GraphQL\Language\AST\VariableDefinitionNode;
23
use GraphQL\Type\Definition\CompositeType;
24
use GraphQL\Type\Definition\Directive;
25
use GraphQL\Type\Definition\EnumType;
26
use GraphQL\Type\Definition\FieldArgument;
27
use GraphQL\Type\Definition\FieldDefinition;
28
use GraphQL\Type\Definition\InputObjectType;
29
use GraphQL\Type\Definition\InputType;
30
use GraphQL\Type\Definition\InterfaceType;
31
use GraphQL\Type\Definition\ListOfType;
32
use GraphQL\Type\Definition\ObjectType;
33
use GraphQL\Type\Definition\OutputType;
34
use GraphQL\Type\Definition\Type;
35
use GraphQL\Type\Definition\UnionType;
36
use GraphQL\Type\Definition\WrappingType;
37
use GraphQL\Type\Introspection;
38
use GraphQL\Type\Schema;
39
use function array_map;
40
use function array_merge;
41
use function array_pop;
42
use function count;
43
use function is_array;
44
use function sprintf;
45
46
class TypeInfo
47
{
48
    /** @var Schema */
49
    private $schema;
50
51
    /** @var array<(OutputType&Type)|null> */
52
    private $typeStack;
53
54
    /** @var array<(CompositeType&Type)|null> */
55
    private $parentTypeStack;
56
57
    /** @var array<(InputType&Type)|null> */
58
    private $inputTypeStack;
59
60
    /** @var array<FieldDefinition> */
61
    private $fieldDefStack;
62
63
    /** @var array<mixed> */
64
    private $defaultValueStack;
65
66
    /** @var Directive|null */
67
    private $directive;
68
69
    /** @var FieldArgument|null */
70
    private $argument;
71
72
    /** @var mixed */
73
    private $enumValue;
74
75
    /**
76
     * @param Type|null $initialType
77
     */
78 535
    public function __construct(Schema $schema, $initialType = null)
79
    {
80 535
        $this->schema            = $schema;
81 535
        $this->typeStack         = [];
82 535
        $this->parentTypeStack   = [];
83 535
        $this->inputTypeStack    = [];
84 535
        $this->fieldDefStack     = [];
85 535
        $this->defaultValueStack = [];
86
87 535
        if ($initialType === null) {
88 533
            return;
89
        }
90
91 2
        if (Type::isInputType($initialType)) {
92 2
            $this->inputTypeStack[] = $initialType;
93
        }
94 2
        if (Type::isCompositeType($initialType)) {
95
            $this->parentTypeStack[] = $initialType;
96
        }
97 2
        if (! Type::isOutputType($initialType)) {
98
            return;
99
        }
100
101 2
        $this->typeStack[] = $initialType;
102 2
    }
103
104
    /**
105
     * @deprecated moved to GraphQL\Utils\TypeComparators
106
     *
107
     * @codeCoverageIgnore
108
     */
109
    public static function isEqualType(Type $typeA, Type $typeB) : bool
110
    {
111
        return TypeComparators::isEqualType($typeA, $typeB);
112
    }
113
114
    /**
115
     * @deprecated moved to GraphQL\Utils\TypeComparators
116
     *
117
     * @codeCoverageIgnore
118
     */
119
    public static function isTypeSubTypeOf(Schema $schema, Type $maybeSubType, Type $superType)
120
    {
121
        return TypeComparators::isTypeSubTypeOf($schema, $maybeSubType, $superType);
122
    }
123
124
    /**
125
     * @deprecated moved to GraphQL\Utils\TypeComparators
126
     *
127
     * @codeCoverageIgnore
128
     */
129
    public static function doTypesOverlap(Schema $schema, CompositeType $typeA, CompositeType $typeB)
130
    {
131
        return TypeComparators::doTypesOverlap($schema, $typeA, $typeB);
132
    }
133
134
    /**
135
     * Given root type scans through all fields to find nested types. Returns array where keys are for type name
136
     * and value contains corresponding type instance.
137
     *
138
     * Example output:
139
     * [
140
     *     'String' => $instanceOfStringType,
141
     *     'MyType' => $instanceOfMyType,
142
     *     ...
143
     * ]
144
     *
145
     * @param Type|null   $type
146
     * @param Type[]|null $typeMap
147
     *
148
     * @return Type[]|null
149
     */
150 857
    public static function extractTypes($type, ?array $typeMap = null)
151
    {
152 857
        if (! $typeMap) {
153 857
            $typeMap = [];
154
        }
155 857
        if (! $type) {
156 1
            return $typeMap;
157
        }
158
159 857
        if ($type instanceof WrappingType) {
160 849
            return self::extractTypes($type->getWrappedType(true), $typeMap);
161
        }
162 857
        if (! $type instanceof Type) {
0 ignored issues
show
introduced by
$type is always a sub-type of GraphQL\Type\Definition\Type.
Loading history...
163
            // Preserve these invalid types in map (at numeric index) to make them
164
            // detectable during $schema->validate()
165
            $i            = 0;
166
            $alreadyInMap = false;
167
            while (isset($typeMap[$i])) {
168
                $alreadyInMap = $alreadyInMap || $typeMap[$i] === $type;
169
                $i++;
170
            }
171
            if (! $alreadyInMap) {
172
                $typeMap[$i] = $type;
173
            }
174
175
            return $typeMap;
176
        }
177
178 857
        if (! empty($typeMap[$type->name])) {
179 852
            Utils::invariant(
180 852
                $typeMap[$type->name] === $type,
181 852
                sprintf('Schema must contain unique named types but contains multiple types named "%s" ', $type) .
182 852
                '(see http://webonyx.github.io/graphql-php/type-system/#type-registry).'
183
            );
184
185 849
            return $typeMap;
186
        }
187 857
        $typeMap[$type->name] = $type;
188
189 857
        $nestedTypes = [];
190
191 857
        if ($type instanceof UnionType) {
192 446
            $nestedTypes = $type->getTypes();
193
        }
194 857
        if ($type instanceof ObjectType) {
195 857
            $nestedTypes = array_merge($nestedTypes, $type->getInterfaces());
196
        }
197 856
        if ($type instanceof ObjectType || $type instanceof InterfaceType) {
198 856
            foreach ($type->getFields() as $fieldName => $field) {
199 855
                if (! empty($field->args)) {
200 848
                    $fieldArgTypes = array_map(
201
                        static function (FieldArgument $arg) {
202 848
                            return $arg->getType();
203 848
                        },
204 848
                        $field->args
205
                    );
206
207 848
                    $nestedTypes = array_merge($nestedTypes, $fieldArgTypes);
208
                }
209 855
                $nestedTypes[] = $field->getType();
210
            }
211
        }
212 855
        if ($type instanceof InputObjectType) {
213 481
            foreach ($type->getFields() as $fieldName => $field) {
214 480
                $nestedTypes[] = $field->getType();
215
            }
216
        }
217 855
        foreach ($nestedTypes as $nestedType) {
218 855
            $typeMap = self::extractTypes($nestedType, $typeMap);
219
        }
220
221 852
        return $typeMap;
222
    }
223
224
    /**
225
     * @param Type[] $typeMap
226
     *
227
     * @return Type[]
228
     */
229 846
    public static function extractTypesFromDirectives(Directive $directive, array $typeMap = [])
230
    {
231 846
        if (is_array($directive->args)) {
0 ignored issues
show
introduced by
The condition is_array($directive->args) is always true.
Loading history...
232 846
            foreach ($directive->args as $arg) {
233 845
                $typeMap = self::extractTypes($arg->getType(), $typeMap);
234
            }
235
        }
236
237 846
        return $typeMap;
238
    }
239
240 19
    public function getParentInputType() : ?InputType
241
    {
242 19
        return $this->inputTypeStack[count($this->inputTypeStack) - 2] ?? null;
243
    }
244
245 107
    public function getArgument() : ?FieldArgument
246
    {
247 107
        return $this->argument;
248
    }
249
250
    /**
251
     * @return mixed
252
     */
253
    public function getEnumValue()
254
    {
255
        return $this->enumValue;
256
    }
257
258 535
    public function enter(Node $node)
259
    {
260 535
        $schema = $this->schema;
261
262
        // Note: many of the types below are explicitly typed as "mixed" to drop
263
        // any assumptions of a valid schema to ensure runtime types are properly
264
        // checked before continuing since TypeInfo is used as part of validation
265
        // which occurs before guarantees of schema and document validity.
266
        switch (true) {
267 535
            case $node instanceof SelectionSetNode:
268 533
                $namedType               = Type::getNamedType($this->getType());
269 533
                $this->parentTypeStack[] = Type::isCompositeType($namedType) ? $namedType : null;
270 533
                break;
271
272 535
            case $node instanceof FieldNode:
273 523
                $parentType = $this->getParentType();
274 523
                $fieldDef   = null;
275 523
                if ($parentType) {
276 476
                    $fieldDef = self::getFieldDefinition($schema, $parentType, $node);
277
                }
278 523
                $fieldType = null;
279 523
                if ($fieldDef) {
280 401
                    $fieldType = $fieldDef->getType();
281
                }
282 523
                $this->fieldDefStack[] = $fieldDef;
283 523
                $this->typeStack[]     = Type::isOutputType($fieldType) ? $fieldType : null;
284 523
                break;
285
286 535
            case $node instanceof DirectiveNode:
287 46
                $this->directive = $schema->getDirective($node->name->value);
288 46
                break;
289
290 535
            case $node instanceof OperationDefinitionNode:
291 421
                $type = null;
292 421
                if ($node->operation === 'query') {
293 419
                    $type = $schema->getQueryType();
294 9
                } elseif ($node->operation === 'mutation') {
295 6
                    $type = $schema->getMutationType();
296 4
                } elseif ($node->operation === 'subscription') {
297 4
                    $type = $schema->getSubscriptionType();
298
                }
299 421
                $this->typeStack[] = Type::isOutputType($type) ? $type : null;
300 421
                break;
301
302 535
            case $node instanceof InlineFragmentNode:
303 535
            case $node instanceof FragmentDefinitionNode:
304 231
                $typeConditionNode = $node->typeCondition;
305 231
                $outputType        = $typeConditionNode
306 229
                    ? self::typeFromAST(
307 229
                        $schema,
308 229
                        $typeConditionNode
309
                    )
310 231
                    : Type::getNamedType($this->getType());
311 231
                $this->typeStack[] = Type::isOutputType($outputType) ? $outputType : null;
312 231
                break;
313
314 535
            case $node instanceof VariableDefinitionNode:
315 87
                $inputType              = self::typeFromAST($schema, $node->type);
316 87
                $this->inputTypeStack[] = Type::isInputType($inputType) ? $inputType : null; // push
317 87
                break;
318
319 535
            case $node instanceof ArgumentNode:
320 267
                $fieldOrDirective = $this->getDirective() ?: $this->getFieldDef();
321 267
                $argDef           = $argType = null;
322 267
                if ($fieldOrDirective) {
323
                    /** @var FieldArgument $argDef */
324 215
                    $argDef = Utils::find(
325 215
                        $fieldOrDirective->args,
326
                        static function ($arg) use ($node) {
327 214
                            return $arg->name === $node->name->value;
328 215
                        }
329
                    );
330 215
                    if ($argDef !== null) {
331 206
                        $argType = $argDef->getType();
332
                    }
333
                }
334 267
                $this->argument            = $argDef;
335 267
                $this->defaultValueStack[] = $argDef && $argDef->defaultValueExists() ? $argDef->defaultValue : Utils::undefined();
336 267
                $this->inputTypeStack[]    = Type::isInputType($argType) ? $argType : null;
337 267
                break;
338
339 535
            case $node instanceof ListValueNode:
340 10
                $type     = $this->getInputType();
341 10
                $listType = $type === null ? null : Type::getNullableType($type);
342 10
                $itemType = $listType instanceof ListOfType
343 9
                    ? $listType->getWrappedType()
344 10
                    : $listType;
345
                // List positions never have a default value.
346 10
                $this->defaultValueStack[] = Utils::undefined();
347 10
                $this->inputTypeStack[]    = Type::isInputType($itemType) ? $itemType : null;
348 10
                break;
349
350 535
            case $node instanceof ObjectFieldNode:
351 23
                $objectType     = Type::getNamedType($this->getInputType());
352 23
                $fieldType      = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $fieldType is dead and can be removed.
Loading history...
353 23
                $inputField     = null;
354 23
                $inputFieldType = null;
355 23
                if ($objectType instanceof InputObjectType) {
356 15
                    $tmp            = $objectType->getFields();
357 15
                    $inputField     = $tmp[$node->name->value] ?? null;
358 15
                    $inputFieldType = $inputField ? $inputField->getType() : null;
359
                }
360 23
                $this->defaultValueStack[] = $inputField && $inputField->defaultValueExists() ? $inputField->defaultValue : Utils::undefined();
361 23
                $this->inputTypeStack[]    = Type::isInputType($inputFieldType) ? $inputFieldType : null;
362 23
                break;
363
364 535
            case $node instanceof EnumValueNode:
365 32
                $enumType  = Type::getNamedType($this->getInputType());
366 32
                $enumValue = null;
367 32
                if ($enumType instanceof EnumType) {
368 23
                    $this->enumValue = $enumType->getValue($node->value);
369
                }
370 32
                $this->enumValue = $enumValue;
371 32
                break;
372
        }
373 535
    }
374
375
    /**
376
     * @return (Type & OutputType) | null
0 ignored issues
show
Documentation Bug introduced by
The doc comment (Type at position 1 could not be parsed: Expected ')' at position 1, but found 'Type'.
Loading history...
377
     */
378 533
    public function getType() : ?OutputType
379
    {
380 533
        return $this->typeStack[count($this->typeStack) - 1] ?? null;
381
    }
382
383
    /**
384
     * @return (CompositeType & Type) | null
0 ignored issues
show
Documentation Bug introduced by
The doc comment (CompositeType at position 1 could not be parsed: Expected ')' at position 1, but found 'CompositeType'.
Loading history...
385
     */
386 523
    public function getParentType() : ?CompositeType
387
    {
388 523
        return $this->parentTypeStack[count($this->parentTypeStack) - 1] ?? null;
389
    }
390
391
    /**
392
     * Not exactly the same as the executor's definition of getFieldDef, in this
393
     * statically evaluated environment we do not always have an Object type,
394
     * and need to handle Interface and Union types.
395
     */
396 476
    private static function getFieldDefinition(Schema $schema, Type $parentType, FieldNode $fieldNode) : ?FieldDefinition
397
    {
398 476
        $name       = $fieldNode->name->value;
399 476
        $schemaMeta = Introspection::schemaMetaFieldDef();
400 476
        if ($name === $schemaMeta->name && $schema->getQueryType() === $parentType) {
0 ignored issues
show
introduced by
The condition $schema->getQueryType() === $parentType is always false.
Loading history...
401 9
            return $schemaMeta;
402
        }
403
404 476
        $typeMeta = Introspection::typeMetaFieldDef();
405 476
        if ($name === $typeMeta->name && $schema->getQueryType() === $parentType) {
0 ignored issues
show
introduced by
The condition $schema->getQueryType() === $parentType is always false.
Loading history...
406 21
            return $typeMeta;
407
        }
408 476
        $typeNameMeta = Introspection::typeNameMetaFieldDef();
409 476
        if ($name === $typeNameMeta->name && $parentType instanceof CompositeType) {
410 18
            return $typeNameMeta;
411
        }
412 466
        if ($parentType instanceof ObjectType ||
413 466
            $parentType instanceof InterfaceType) {
414 464
            $fields = $parentType->getFields();
415
416 464
            return $fields[$name] ?? null;
417
        }
418
419 2
        return null;
420
    }
421
422
    /**
423
     * @param NamedTypeNode|ListTypeNode|NonNullTypeNode $inputTypeNode
424
     *
425
     * @throws InvariantViolation
426
     */
427 349
    public static function typeFromAST(Schema $schema, $inputTypeNode) : ?Type
428
    {
429 349
        return AST::typeFromAST($schema, $inputTypeNode);
430
    }
431
432 269
    public function getDirective() : ?Directive
433
    {
434 269
        return $this->directive;
435
    }
436
437 337
    public function getFieldDef() : ?FieldDefinition
438
    {
439 337
        return $this->fieldDefStack[count($this->fieldDefStack) - 1] ?? null;
440
    }
441
442
    /**
443
     * @return mixed|null
444
     */
445 64
    public function getDefaultValue()
446
    {
447 64
        return $this->defaultValueStack[count($this->defaultValueStack) - 1] ?? null;
448
    }
449
450
    /**
451
     * @return (Type & InputType) | null
0 ignored issues
show
Documentation Bug introduced by
The doc comment (Type at position 1 could not be parsed: Expected ')' at position 1, but found 'Type'.
Loading history...
452
     */
453 205
    public function getInputType() : ?InputType
454
    {
455 205
        return $this->inputTypeStack[count($this->inputTypeStack) - 1] ?? null;
456
    }
457
458 535
    public function leave(Node $node)
459
    {
460
        switch (true) {
461 535
            case $node instanceof SelectionSetNode:
462 533
                array_pop($this->parentTypeStack);
463 533
                break;
464
465 535
            case $node instanceof FieldNode:
466 523
                array_pop($this->fieldDefStack);
467 523
                array_pop($this->typeStack);
468 523
                break;
469
470 535
            case $node instanceof DirectiveNode:
471 46
                $this->directive = null;
472 46
                break;
473
474 535
            case $node instanceof OperationDefinitionNode:
475 535
            case $node instanceof InlineFragmentNode:
476 535
            case $node instanceof FragmentDefinitionNode:
477 533
                array_pop($this->typeStack);
478 533
                break;
479 535
            case $node instanceof VariableDefinitionNode:
480 87
                array_pop($this->inputTypeStack);
481 87
                break;
482 535
            case $node instanceof ArgumentNode:
483 267
                $this->argument = null;
484 267
                array_pop($this->defaultValueStack);
485 267
                array_pop($this->inputTypeStack);
486 267
                break;
487 535
            case $node instanceof ListValueNode:
488 535
            case $node instanceof ObjectFieldNode:
489 29
                array_pop($this->defaultValueStack);
490 29
                array_pop($this->inputTypeStack);
491 29
                break;
492 535
            case $node instanceof EnumValueNode:
493 32
                $this->enumValue = null;
494 32
                break;
495
        }
496 535
    }
497
}
498