Failed Conditions
Push — master ( ea13c9...49ec89 )
by Vladimir
07:25
created

Parser::parseUnionMemberTypes()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 11
ccs 7
cts 7
cp 1
rs 10
c 0
b 0
f 0
cc 3
nc 2
nop 0
crap 3
1
<?php
2
namespace GraphQL\Language;
3
4
use GraphQL\Language\AST\ArgumentNode;
5
use GraphQL\Language\AST\DirectiveDefinitionNode;
6
use GraphQL\Language\AST\EnumTypeDefinitionNode;
7
use GraphQL\Language\AST\EnumTypeExtensionNode;
8
use GraphQL\Language\AST\EnumValueDefinitionNode;
9
use GraphQL\Language\AST\ExecutableDefinitionNode;
10
use GraphQL\Language\AST\FieldDefinitionNode;
11
use GraphQL\Language\AST\InputObjectTypeDefinitionNode;
12
use GraphQL\Language\AST\InputObjectTypeExtensionNode;
13
use GraphQL\Language\AST\InputValueDefinitionNode;
14
use GraphQL\Language\AST\InterfaceTypeDefinitionNode;
15
use GraphQL\Language\AST\InterfaceTypeExtensionNode;
16
use GraphQL\Language\AST\ListValueNode;
17
use GraphQL\Language\AST\BooleanValueNode;
18
use GraphQL\Language\AST\DirectiveNode;
19
use GraphQL\Language\AST\DocumentNode;
20
use GraphQL\Language\AST\EnumValueNode;
21
use GraphQL\Language\AST\FieldNode;
22
use GraphQL\Language\AST\FloatValueNode;
23
use GraphQL\Language\AST\FragmentDefinitionNode;
24
use GraphQL\Language\AST\FragmentSpreadNode;
25
use GraphQL\Language\AST\InlineFragmentNode;
26
use GraphQL\Language\AST\IntValueNode;
27
use GraphQL\Language\AST\ListTypeNode;
28
use GraphQL\Language\AST\Location;
29
use GraphQL\Language\AST\NameNode;
30
use GraphQL\Language\AST\NamedTypeNode;
31
use GraphQL\Language\AST\NodeList;
32
use GraphQL\Language\AST\NonNullTypeNode;
33
use GraphQL\Language\AST\NullValueNode;
34
use GraphQL\Language\AST\ObjectFieldNode;
35
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
36
use GraphQL\Language\AST\ObjectValueNode;
37
use GraphQL\Language\AST\OperationDefinitionNode;
38
use GraphQL\Language\AST\OperationTypeDefinitionNode;
39
use GraphQL\Language\AST\ScalarTypeDefinitionNode;
40
use GraphQL\Language\AST\ScalarTypeExtensionNode;
41
use GraphQL\Language\AST\SchemaDefinitionNode;
42
use GraphQL\Language\AST\SelectionSetNode;
43
use GraphQL\Language\AST\StringValueNode;
44
use GraphQL\Language\AST\ObjectTypeExtensionNode;
45
use GraphQL\Language\AST\TypeExtensionNode;
46
use GraphQL\Language\AST\TypeSystemDefinitionNode;
47
use GraphQL\Language\AST\UnionTypeDefinitionNode;
48
use GraphQL\Language\AST\UnionTypeExtensionNode;
49
use GraphQL\Language\AST\VariableNode;
50
use GraphQL\Language\AST\VariableDefinitionNode;
51
use GraphQL\Error\SyntaxError;
52
53
/**
54
 * Parses string containing GraphQL query or [type definition](type-system/type-language.md) to Abstract Syntax Tree.
55
 */
56
class Parser
57
{
58
    /**
59
     * Given a GraphQL source, parses it into a `GraphQL\Language\AST\DocumentNode`.
60
     * Throws `GraphQL\Error\SyntaxError` if a syntax error is encountered.
61
     *
62
     * Available options:
63
     *
64
     * noLocation: boolean,
65
     *   (By default, the parser creates AST nodes that know the location
66
     *   in the source that they correspond to. This configuration flag
67
     *   disables that behavior for performance or testing.)
68
     *
69
     * allowLegacySDLEmptyFields: boolean
70
     *   If enabled, the parser will parse empty fields sets in the Schema
71
     *   Definition Language. Otherwise, the parser will follow the current
72
     *   specification.
73
     *
74
     *   This option is provided to ease adoption of the final SDL specification
75
     *   and will be removed in a future major release.
76
     *
77
     * allowLegacySDLImplementsInterfaces: boolean
78
     *   If enabled, the parser will parse implemented interfaces with no `&`
79
     *   character between each interface. Otherwise, the parser will follow the
80
     *   current specification.
81
     *
82
     *   This option is provided to ease adoption of the final SDL specification
83
     *   and will be removed in a future major release.
84
     *
85
     * experimentalFragmentVariables: boolean,
86
     *   (If enabled, the parser will understand and parse variable definitions
87
     *   contained in a fragment definition. They'll be represented in the
88
     *   `variableDefinitions` field of the FragmentDefinitionNode.
89
     *
90
     *   The syntax is identical to normal, query-defined variables. For example:
91
     *
92
     *     fragment A($var: Boolean = false) on T  {
93
     *       ...
94
     *     }
95
     *
96
     *   Note: this feature is experimental and may change or be removed in the
97
     *   future.)
98
     *
99
     * @api
100
     * @param Source|string $source
101
     * @param array $options
102
     * @return DocumentNode
103
     * @throws SyntaxError
104
     */
105 815
    public static function parse($source, array $options = [])
106
    {
107 815
        $sourceObj = $source instanceof Source ? $source : new Source($source);
108 812
        $parser = new self($sourceObj, $options);
109 812
        return $parser->parseDocument();
110
    }
111
112
    /**
113
     * Given a string containing a GraphQL value (ex. `[42]`), parse the AST for
114
     * that value.
115
     * Throws `GraphQL\Error\SyntaxError` if a syntax error is encountered.
116
     *
117
     * This is useful within tools that operate upon GraphQL Values directly and
118
     * in isolation of complete GraphQL documents.
119
     *
120
     * Consider providing the results to the utility function: `GraphQL\Utils\AST::valueFromAST()`.
121
     *
122
     * @api
123
     * @param Source|string $source
124
     * @param array $options
125
     * @return BooleanValueNode|EnumValueNode|FloatValueNode|IntValueNode|ListValueNode|ObjectValueNode|StringValueNode|VariableNode
126
     */
127 21
    public static function parseValue($source, array $options = [])
128
    {
129 21
        $sourceObj = $source instanceof Source ? $source : new Source($source);
130 21
        $parser = new Parser($sourceObj, $options);
131 21
        $parser->expect(Token::SOF);
132 21
        $value = $parser->parseValueLiteral(false);
133 21
        $parser->expect(Token::EOF);
134 21
        return $value;
135
    }
136
137
    /**
138
     * Given a string containing a GraphQL Type (ex. `[Int!]`), parse the AST for
139
     * that type.
140
     * Throws `GraphQL\Error\SyntaxError` if a syntax error is encountered.
141
     *
142
     * This is useful within tools that operate upon GraphQL Types directly and
143
     * in isolation of complete GraphQL documents.
144
     *
145
     * Consider providing the results to the utility function: `GraphQL\Utils\AST::typeFromAST()`.
146
     *
147
     * @api
148
     * @param Source|string $source
149
     * @param array $options
150
     * @return ListTypeNode|NameNode|NonNullTypeNode
151
     */
152 5
    public static function parseType($source, array $options = [])
153
    {
154 5
        $sourceObj = $source instanceof Source ? $source : new Source($source);
155 5
        $parser = new Parser($sourceObj, $options);
156 5
        $parser->expect(Token::SOF);
157 5
        $type = $parser->parseTypeReference();
158 5
        $parser->expect(Token::EOF);
159 5
        return $type;
160
    }
161
162
    /**
163
     * @var Lexer
164
     */
165
    private $lexer;
166
167
    /**
168
     * Parser constructor.
169
     * @param Source $source
170
     * @param array $options
171
     */
172 838
    function __construct(Source $source, array $options = [])
173
    {
174 838
        $this->lexer = new Lexer($source, $options);
175 838
    }
176
177
    /**
178
     * Returns a location object, used to identify the place in
179
     * the source that created a given parsed object.
180
     *
181
     * @param Token $startToken
182
     * @return Location|null
183
     */
184 830
    function loc(Token $startToken)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
185
    {
186 830
        if (empty($this->lexer->options['noLocation'])) {
187 813
            return new Location($startToken, $this->lexer->lastToken, $this->lexer->source);
188
        }
189 17
        return null;
190
    }
191
192
    /**
193
     * Determines if the next token is of a given kind
194
     *
195
     * @param $kind
196
     * @return bool
197
     */
198 812
    function peek($kind)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
199
    {
200 812
        return $this->lexer->token->kind === $kind;
201
    }
202
203
    /**
204
     * If the next token is of the given kind, return true after advancing
205
     * the parser. Otherwise, do not change the parser state and return false.
206
     *
207
     * @param $kind
208
     * @return bool
209
     */
210 818
    function skip($kind)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
211
    {
212 818
        $match = $this->lexer->token->kind === $kind;
213
214 818
        if ($match) {
215 814
            $this->lexer->advance();
216
        }
217 818
        return $match;
218
    }
219
220
    /**
221
     * If the next token is of the given kind, return that token after advancing
222
     * the parser. Otherwise, do not change the parser state and return false.
223
     * @param string $kind
224
     * @return Token
225
     * @throws SyntaxError
226
     */
227 838
    function expect($kind)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
228
    {
229 838
        $token = $this->lexer->token;
230
231 838
        if ($token->kind === $kind) {
232 838
            $this->lexer->advance();
233 838
            return $token;
234
        }
235
236 11
        throw new SyntaxError(
237 11
            $this->lexer->source,
238 11
            $token->start,
239 11
            "Expected $kind, found " . $token->getDescription()
240
        );
241
    }
242
243
    /**
244
     * If the next token is a keyword with the given value, return that token after
245
     * advancing the parser. Otherwise, do not change the parser state and return
246
     * false.
247
     *
248
     * @param string $value
249
     * @return Token
250
     * @throws SyntaxError
251
     */
252 330
    function expectKeyword($value)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
253
    {
254 330
        $token = $this->lexer->token;
255
256 330
        if ($token->kind === Token::NAME && $token->value === $value) {
257 330
            $this->lexer->advance();
258 330
            return $token;
259
        }
260 2
        throw new SyntaxError(
261 2
            $this->lexer->source,
262 2
            $token->start,
263 2
            'Expected "' . $value . '", found ' . $token->getDescription()
264
        );
265
    }
266
267
    /**
268
     * @param Token|null $atToken
269
     * @return SyntaxError
270
     */
271 9
    function unexpected(Token $atToken = null)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
272
    {
273 9
        $token = $atToken ?: $this->lexer->token;
274 9
        return new SyntaxError($this->lexer->source, $token->start, "Unexpected " . $token->getDescription());
275
    }
276
277
    /**
278
     * Returns a possibly empty list of parse nodes, determined by
279
     * the parseFn. This list begins with a lex token of openKind
280
     * and ends with a lex token of closeKind. Advances the parser
281
     * to the next lex token after the closing token.
282
     *
283
     * @param int $openKind
284
     * @param callable $parseFn
285
     * @param int $closeKind
286
     * @return NodeList
287
     * @throws SyntaxError
288
     */
289 34
    function any($openKind, $parseFn, $closeKind)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
290
    {
291 34
        $this->expect($openKind);
292
293 34
        $nodes = [];
294 34
        while (!$this->skip($closeKind)) {
295 32
            $nodes[] = $parseFn($this);
296
        }
297 33
        return new NodeList($nodes);
298
    }
299
300
    /**
301
     * Returns a non-empty list of parse nodes, determined by
302
     * the parseFn. This list begins with a lex token of openKind
303
     * and ends with a lex token of closeKind. Advances the parser
304
     * to the next lex token after the closing token.
305
     *
306
     * @param $openKind
307
     * @param $parseFn
308
     * @param $closeKind
309
     * @return NodeList
310
     * @throws SyntaxError
311
     */
312 793
    function many($openKind, $parseFn, $closeKind)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
313
    {
314 793
        $this->expect($openKind);
315
316 792
        $nodes = [$parseFn($this)];
317 786
        while (!$this->skip($closeKind)) {
318 314
            $nodes[] = $parseFn($this);
319
        }
320 785
        return new NodeList($nodes);
321
    }
322
323
    /**
324
     * Converts a name lex token into a name parse node.
325
     *
326
     * @return NameNode
327
     * @throws SyntaxError
328
     */
329 818
    function parseName()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
330
    {
331 818
        $token = $this->expect(Token::NAME);
332
333 816
        return new NameNode([
334 816
            'value' => $token->value,
335 816
            'loc' => $this->loc($token)
336
        ]);
337
    }
338
339
    /**
340
     * Implements the parsing rules in the Document section.
341
     *
342
     * @return DocumentNode
343
     * @throws SyntaxError
344
     */
345 812
    function parseDocument()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
346
    {
347 812
        $start = $this->lexer->token;
348 812
        $this->expect(Token::SOF);
349
350 812
        $definitions = [];
351
        do {
352 812
            $definitions[] = $this->parseDefinition();
353 793
        } while (!$this->skip(Token::EOF));
354
355 791
        return new DocumentNode([
356 791
            'definitions' => new NodeList($definitions),
357 791
            'loc' => $this->loc($start)
358
        ]);
359
    }
360
361
    /**
362
     * @return ExecutableDefinitionNode|TypeSystemDefinitionNode
363
     * @throws SyntaxError
364
     */
365 812
    function parseDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
366
    {
367 812
        if ($this->peek(Token::NAME)) {
368 528
            switch ($this->lexer->token->value) {
369 528
                case 'query':
370 347
                case 'mutation':
371 335
                case 'subscription':
372 330
                case 'fragment':
373 402
                    return $this->parseExecutableDefinition();
374
375
                // Note: The schema definition language is an experimental addition.
376 130
                case 'schema':
377 127
                case 'scalar':
378 126
                case 'type':
379 78
                case 'interface':
380 57
                case 'union':
381 40
                case 'enum':
382 31
                case 'input':
383 16
                case 'extend':
384 9
                case 'directive':
385
                    // Note: The schema definition language is an experimental addition.
386 130
                    return $this->parseTypeSystemDefinition();
387
            }
388 323
        } else if ($this->peek(Token::BRACE_L)) {
389 316
            return $this->parseExecutableDefinition();
390 7
        } else if ($this->peekDescription()) {
391
            // Note: The schema definition language is an experimental addition.
392 6
            return $this->parseTypeSystemDefinition();
393
        }
394
395 3
        throw $this->unexpected();
396
    }
397
398
    /**
399
     * @return ExecutableDefinitionNode
400
     * @throws SyntaxError
401
     */
402 687
    function parseExecutableDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
403
    {
404 687
        if ($this->peek(Token::NAME)) {
405 402
            switch ($this->lexer->token->value) {
406 402
                case 'query':
407 218
                case 'mutation':
408 206
                case 'subscription':
409 265
                    return $this->parseOperationDefinition();
410
411 201
                case 'fragment':
412 201
                    return $this->parseFragmentDefinition();
413
            }
414 316
        } else if ($this->peek(Token::BRACE_L)) {
415 316
            return $this->parseOperationDefinition();
416
        }
417
418
        throw $this->unexpected();
419
    }
420
421
    // Implements the parsing rules in the Operations section.
422
423
    /**
424
     * @return OperationDefinitionNode
425
     * @throws SyntaxError
426
     */
427 570
    function parseOperationDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
428
    {
429 570
        $start = $this->lexer->token;
430 570
        if ($this->peek(Token::BRACE_L)) {
431 316
            return new OperationDefinitionNode([
432 316
                'operation' => 'query',
433
                'name' => null,
434 316
                'variableDefinitions' => new NodeList([]),
435 316
                'directives' => new NodeList([]),
436 316
                'selectionSet' => $this->parseSelectionSet(),
437 312
                'loc' => $this->loc($start)
438
            ]);
439
        }
440
441 265
        $operation = $this->parseOperationType();
442
443 265
        $name = null;
444 265
        if ($this->peek(Token::NAME)) {
445 249
            $name = $this->parseName();
446
        }
447
448 265
        return new OperationDefinitionNode([
449 265
            'operation' => $operation,
450 265
            'name' => $name,
451 265
            'variableDefinitions' => $this->parseVariableDefinitions(),
452 264
            'directives' => $this->parseDirectives(false),
453 264
            'selectionSet' => $this->parseSelectionSet(),
454 263
            'loc' => $this->loc($start)
455
        ]);
456
    }
457
458
    /**
459
     * @return string
460
     * @throws SyntaxError
461
     */
462 317
    function parseOperationType()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
463
    {
464 317
        $operationToken = $this->expect(Token::NAME);
465 317
        switch ($operationToken->value) {
466 317
            case 'query': return 'query';
467 38
            case 'mutation': return 'mutation';
468 18
            case 'subscription': return 'subscription';
469
        }
470
471
        throw $this->unexpected($operationToken);
472
    }
473
474
    /**
475
     * @return VariableDefinitionNode[]|NodeList
476
     */
477 268
    function parseVariableDefinitions()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
478
    {
479 268
        return $this->peek(Token::PAREN_L) ?
480 123
            $this->many(
481 123
                Token::PAREN_L,
482 123
                [$this, 'parseVariableDefinition'],
483 123
                Token::PAREN_R
484
            ) :
485 267
            new NodeList([]);
486
    }
487
488
    /**
489
     * @return VariableDefinitionNode
490
     * @throws SyntaxError
491
     */
492 123
    function parseVariableDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
493
    {
494 123
        $start = $this->lexer->token;
495 123
        $var = $this->parseVariable();
496
497 123
        $this->expect(Token::COLON);
498 123
        $type = $this->parseTypeReference();
499
500 123
        return new VariableDefinitionNode([
501 123
            'variable' => $var,
502 123
            'type' => $type,
503
            'defaultValue' =>
504 123
                ($this->skip(Token::EQUALS) ? $this->parseValueLiteral(true) : null),
505 122
            'loc' => $this->loc($start)
506
        ]);
507
    }
508
509
    /**
510
     * @return VariableNode
511
     * @throws SyntaxError
512
     */
513 132
    function parseVariable()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
514
    {
515 132
        $start = $this->lexer->token;
516 132
        $this->expect(Token::DOLLAR);
517
518 132
        return new VariableNode([
519 132
            'name' => $this->parseName(),
520 132
            'loc' => $this->loc($start)
521
        ]);
522
    }
523
524
    /**
525
     * @return SelectionSetNode
526
     */
527 685
    function parseSelectionSet()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
528
    {
529 685
        $start = $this->lexer->token;
530 685
        return new SelectionSetNode([
531 685
            'selections' => $this->many(Token::BRACE_L, [$this, 'parseSelection'], Token::BRACE_R),
532 680
            'loc' => $this->loc($start)
533
        ]);
534
    }
535
536
    /**
537
     *  Selection :
538
     *   - Field
539
     *   - FragmentSpread
540
     *   - InlineFragment
541
     *
542
     * @return mixed
543
     */
544 684
    function parseSelection()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
545
    {
546 684
        return $this->peek(Token::SPREAD) ?
547 189
            $this->parseFragment() :
548 683
            $this->parseField();
549
    }
550
551
    /**
552
     * @return FieldNode
553
     * @throws SyntaxError
554
     */
555 672
    function parseField()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
556
    {
557 672
        $start = $this->lexer->token;
558 672
        $nameOrAlias = $this->parseName();
559
560 671
        if ($this->skip(Token::COLON)) {
561 60
            $alias = $nameOrAlias;
562 60
            $name = $this->parseName();
563
        } else {
564 653
            $alias = null;
565 653
            $name = $nameOrAlias;
566
        }
567
568 670
        return new FieldNode([
569 670
            'alias' => $alias,
570 670
            'name' => $name,
571 670
            'arguments' => $this->parseArguments(false),
572 670
            'directives' => $this->parseDirectives(false),
573 670
            'selectionSet' => $this->peek(Token::BRACE_L) ? $this->parseSelectionSet() : null,
574 670
            'loc' => $this->loc($start)
575
        ]);
576
    }
577
578
    /**
579
     * @param bool $isConst
580
     * @return ArgumentNode[]|NodeList
581
     * @throws SyntaxError
582
     */
583 675
    function parseArguments($isConst)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
584
    {
585 675
        $item = $isConst ? 'parseConstArgument' : 'parseArgument';
586 675
        return $this->peek(Token::PAREN_L) ?
587 314
            $this->many(Token::PAREN_L, [$this, $item], Token::PAREN_R) :
588 675
            new NodeList([]);
589
    }
590
591
    /**
592
     * @return ArgumentNode
593
     * @throws SyntaxError
594
     */
595 311
    function parseArgument()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
596
    {
597 311
        $start = $this->lexer->token;
598 311
        $name = $this->parseName();
599
600 311
        $this->expect(Token::COLON);
601 311
        $value = $this->parseValueLiteral(false);
602
603 311
        return new ArgumentNode([
604 311
            'name' => $name,
605 311
            'value' => $value,
606 311
            'loc' => $this->loc($start)
607
        ]);
608
    }
609
610
    /**
611
     * @return ArgumentNode
612
     * @throws SyntaxError
613
     */
614 3
    function parseConstArgument()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
615
    {
616 3
        $start = $this->lexer->token;
617 3
        $name = $this->parseName();
618
619 3
        $this->expect(Token::COLON);
620 3
        $value = $this->parseConstValue();
621
622 3
        return new ArgumentNode([
623 3
            'name' => $name,
624 3
            'value' => $value,
625 3
            'loc' => $this->loc($start)
626
        ]);
627
    }
628
629
    // Implements the parsing rules in the Fragments section.
630
631
    /**
632
     * @return FragmentSpreadNode|InlineFragmentNode
633
     * @throws SyntaxError
634
     */
635 189
    function parseFragment()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
636
    {
637 189
        $start = $this->lexer->token;
638 189
        $this->expect(Token::SPREAD);
639
640 189
        if ($this->peek(Token::NAME) && $this->lexer->token->value !== 'on') {
641 124
            return new FragmentSpreadNode([
642 124
                'name' => $this->parseFragmentName(),
643 124
                'directives' => $this->parseDirectives(false),
644 124
                'loc' => $this->loc($start)
645
            ]);
646
        }
647
648 87
        $typeCondition = null;
649 87
        if ($this->lexer->token->value === 'on') {
650 83
            $this->lexer->advance();
651 83
            $typeCondition = $this->parseNamedType();
652
        }
653
654 86
        return new InlineFragmentNode([
655 86
            'typeCondition' => $typeCondition,
656 86
            'directives' => $this->parseDirectives(false),
657 86
            'selectionSet' => $this->parseSelectionSet(),
658 86
            'loc' => $this->loc($start)
659
        ]);
660
    }
661
662
    /**
663
     * @return FragmentDefinitionNode
664
     * @throws SyntaxError
665
     */
666 201
    function parseFragmentDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
667
    {
668 201
        $start = $this->lexer->token;
669 201
        $this->expectKeyword('fragment');
670
671 201
        $name = $this->parseFragmentName();
672
673
        // Experimental support for defining variables within fragments changes
674
        // the grammar of FragmentDefinition:
675
        //   - fragment FragmentName VariableDefinitions? on TypeCondition Directives? SelectionSet
676 200
        $variableDefinitions = null;
677 200
        if (isset($this->lexer->options['experimentalFragmentVariables'])) {
678 3
            $variableDefinitions = $this->parseVariableDefinitions();
679
        }
680 200
        $this->expectKeyword('on');
681 199
        $typeCondition = $this->parseNamedType();
682 199
        return new FragmentDefinitionNode([
683 199
            'name' => $name,
684 199
            'variableDefinitions' => $variableDefinitions,
685 199
            'typeCondition' => $typeCondition,
686 199
            'directives' => $this->parseDirectives(false),
687 199
            'selectionSet' => $this->parseSelectionSet(),
688 199
            'loc' => $this->loc($start)
689
        ]);
690
    }
691
692
    /**
693
     * @return NameNode
694
     * @throws SyntaxError
695
     */
696 203
    function parseFragmentName()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
697
    {
698 203
        if ($this->lexer->token->value === 'on') {
699 1
            throw $this->unexpected();
700
        }
701 202
        return $this->parseName();
702
    }
703
704
    // Implements the parsing rules in the Values section.
705
706
    /**
707
     * Value[Const] :
708
     *   - [~Const] Variable
709
     *   - IntValue
710
     *   - FloatValue
711
     *   - StringValue
712
     *   - BooleanValue
713
     *   - NullValue
714
     *   - EnumValue
715
     *   - ListValue[?Const]
716
     *   - ObjectValue[?Const]
717
     *
718
     * BooleanValue : one of `true` `false`
719
     *
720
     * NullValue : `null`
721
     *
722
     * EnumValue : Name but not `true`, `false` or `null`
723
     *
724
     * @param $isConst
725
     * @return BooleanValueNode|EnumValueNode|FloatValueNode|IntValueNode|StringValueNode|VariableNode|ListValueNode|ObjectValueNode|NullValueNode
726
     * @throws SyntaxError
727
     */
728 352
    function parseValueLiteral($isConst)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
729
    {
730 352
        $token = $this->lexer->token;
731 352
        switch ($token->kind) {
732 352
            case Token::BRACKET_L:
733 34
                return $this->parseArray($isConst);
734 351
            case Token::BRACE_L:
735 42
                return $this->parseObject($isConst);
736 351
            case Token::INT:
737 91
                $this->lexer->advance();
738 91
                return new IntValueNode([
739 91
                    'value' => $token->value,
740 91
                    'loc' => $this->loc($token)
741
                ]);
742 299
            case Token::FLOAT:
743 14
                $this->lexer->advance();
744 14
                return new FloatValueNode([
745 14
                    'value' => $token->value,
746 14
                    'loc' => $this->loc($token)
747
                ]);
748 291
            case Token::STRING:
749 223
            case Token::BLOCK_STRING:
750 106
                return $this->parseStringLiteral();
751 220
            case Token::NAME:
752 122
                if ($token->value === 'true' || $token->value === 'false') {
753 81
                    $this->lexer->advance();
754 81
                    return new BooleanValueNode([
755 81
                        'value' => $token->value === 'true',
756 81
                        'loc' => $this->loc($token)
757
                    ]);
758 63
                } else if ($token->value === 'null') {
759 29
                    $this->lexer->advance();
760 29
                    return new NullValueNode([
761 29
                        'loc' => $this->loc($token)
762
                    ]);
763
                } else {
764 44
                    $this->lexer->advance();
765 44
                    return new EnumValueNode([
766 44
                        'value' => $token->value,
767 44
                        'loc' => $this->loc($token)
768
                    ]);
769
                }
770
                break;
771
772 111
            case Token::DOLLAR:
773 111
                if (!$isConst) {
774 110
                    return $this->parseVariable();
775
                }
776 1
                break;
777
        }
778 1
        throw $this->unexpected();
779
    }
780
781
    /**
782
     * @return StringValueNode
783
     */
784 112
    function parseStringLiteral() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
785 112
        $token = $this->lexer->token;
786 112
        $this->lexer->advance();
787
788 112
        return new StringValueNode([
789 112
            'value' => $token->value,
790 112
            'block' => $token->kind === Token::BLOCK_STRING,
791 112
            'loc' => $this->loc($token)
792
        ]);
793
    }
794
795
    /**
796
     * @return BooleanValueNode|EnumValueNode|FloatValueNode|IntValueNode|StringValueNode|VariableNode
797
     * @throws SyntaxError
798
     */
799 9
    function parseConstValue()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
800
    {
801 9
        return $this->parseValueLiteral(true);
802
    }
803
804
    /**
805
     * @return BooleanValueNode|EnumValueNode|FloatValueNode|IntValueNode|ListValueNode|ObjectValueNode|StringValueNode|VariableNode
806
     */
807 27
    function parseVariableValue()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
808
    {
809 27
        return $this->parseValueLiteral(false);
810
    }
811
812
    /**
813
     * @param bool $isConst
814
     * @return ListValueNode
815
     */
816 34
    function parseArray($isConst)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
817
    {
818 34
        $start = $this->lexer->token;
819 34
        $item = $isConst ? 'parseConstValue' : 'parseVariableValue';
820 34
        return new ListValueNode([
821 34
            'values' => $this->any(Token::BRACKET_L, [$this, $item], Token::BRACKET_R),
0 ignored issues
show
Bug introduced by
GraphQL\Language\Token::BRACKET_R of type string is incompatible with the type integer expected by parameter $closeKind of GraphQL\Language\Parser::any(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

821
            'values' => $this->any(Token::BRACKET_L, [$this, $item], /** @scrutinizer ignore-type */ Token::BRACKET_R),
Loading history...
Bug introduced by
GraphQL\Language\Token::BRACKET_L of type string is incompatible with the type integer expected by parameter $openKind of GraphQL\Language\Parser::any(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

821
            'values' => $this->any(/** @scrutinizer ignore-type */ Token::BRACKET_L, [$this, $item], Token::BRACKET_R),
Loading history...
822 33
            'loc' => $this->loc($start)
823
        ]);
824
    }
825
826
    /**
827
     * @param $isConst
828
     * @return ObjectValueNode
829
     */
830 42
    function parseObject($isConst)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
831
    {
832 42
        $start = $this->lexer->token;
833 42
        $this->expect(Token::BRACE_L);
834 42
        $fields = [];
835 42
        while (!$this->skip(Token::BRACE_R)) {
836 42
            $fields[] = $this->parseObjectField($isConst);
837
        }
838 41
        return new ObjectValueNode([
839 41
            'fields' => new NodeList($fields),
840 41
            'loc' => $this->loc($start)
841
        ]);
842
    }
843
844
    /**
845
     * @param $isConst
846
     * @return ObjectFieldNode
847
     */
848 42
    function parseObjectField($isConst)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
849
    {
850 42
        $start = $this->lexer->token;
851 42
        $name = $this->parseName();
852
853 42
        $this->expect(Token::COLON);
854
855 42
        return new ObjectFieldNode([
856 42
            'name' => $name,
857 42
            'value' => $this->parseValueLiteral($isConst),
858 41
            'loc' => $this->loc($start)
859
        ]);
860
    }
861
862
    // Implements the parsing rules in the Directives section.
863
864
    /**
865
     * @param bool $isConst
866
     * @return DirectiveNode[]|NodeList
867
     * @throws SyntaxError
868
     */
869 802
    function parseDirectives($isConst)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
870
    {
871 802
        $directives = [];
872 802
        while ($this->peek(Token::AT)) {
873 62
            $directives[] = $this->parseDirective($isConst);
874
        }
875 802
        return new NodeList($directives);
876
    }
877
878
    /**
879
     * @param bool $isConst
880
     * @return DirectiveNode
881
     * @throws SyntaxError
882
     */
883 62
    function parseDirective($isConst)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
884
    {
885 62
        $start = $this->lexer->token;
886 62
        $this->expect(Token::AT);
887 62
        return new DirectiveNode([
888 62
            'name' => $this->parseName(),
889 62
            'arguments' => $this->parseArguments($isConst),
890 62
            'loc' => $this->loc($start)
891
        ]);
892
    }
893
894
    // Implements the parsing rules in the Types section.
895
896
    /**
897
     * Handles the Type: TypeName, ListType, and NonNullType parsing rules.
898
     *
899
     * @return ListTypeNode|NameNode|NonNullTypeNode
900
     * @throws SyntaxError
901
     */
902 237
    function parseTypeReference()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
903
    {
904 237
        $start = $this->lexer->token;
905
906 237
        if ($this->skip(Token::BRACKET_L)) {
907 30
            $type = $this->parseTypeReference();
908 30
            $this->expect(Token::BRACKET_R);
909 30
            $type = new ListTypeNode([
910 30
                'type' => $type,
911 30
                'loc' => $this->loc($start)
912
            ]);
913
        } else {
914 237
            $type = $this->parseNamedType();
915
        }
916 237
        if ($this->skip(Token::BANG)) {
917 55
            return new NonNullTypeNode([
918 55
                'type' => $type,
919 55
                'loc' => $this->loc($start)
920
            ]);
921
922
        }
923 202
        return $type;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $type also could return the type GraphQL\Language\AST\NamedTypeNode which is incompatible with the documented return type GraphQL\Language\AST\Lis...age\AST\NonNullTypeNode.
Loading history...
924
    }
925
926 458
    function parseNamedType()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
927
    {
928 458
        $start = $this->lexer->token;
929
930 458
        return new NamedTypeNode([
931 458
            'name' => $this->parseName(),
932 455
            'loc' => $this->loc($start)
933
        ]);
934
    }
935
936
    // Implements the parsing rules in the Type Definition section.
937
938
    /**
939
     * TypeSystemDefinition :
940
     *   - SchemaDefinition
941
     *   - TypeDefinition
942
     *   - TypeExtension
943
     *   - DirectiveDefinition
944
     *
945
     * TypeDefinition :
946
     *   - ScalarTypeDefinition
947
     *   - ObjectTypeDefinition
948
     *   - InterfaceTypeDefinition
949
     *   - UnionTypeDefinition
950
     *   - EnumTypeDefinition
951
     *   - InputObjectTypeDefinition
952
     *
953
     * @return TypeSystemDefinitionNode
954
     * @throws SyntaxError
955
     */
956 132
    function parseTypeSystemDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
957
    {
958
        // Many definitions begin with a description and require a lookahead.
959 132
        $keywordToken = $this->peekDescription()
960 6
            ? $this->lexer->lookahead()
961 132
            : $this->lexer->token;
962
963 132
        if ($keywordToken->kind === Token::NAME) {
964 132
            switch ($keywordToken->value) {
965 132
                case 'schema': return $this->parseSchemaDefinition();
966 130
                case 'scalar': return $this->parseScalarTypeDefinition();
967 129
                case 'type': return $this->parseObjectTypeDefinition();
968 78
                case 'interface': return $this->parseInterfaceTypeDefinition();
969 57
                case 'union': return $this->parseUnionTypeDefinition();
970 40
                case 'enum': return $this->parseEnumTypeDefinition();
971 31
                case 'input': return $this->parseInputObjectTypeDefinition();
972 16
                case 'extend': return $this->parseTypeExtension();
973 8
                case 'directive': return $this->parseDirectiveDefinition();
974
            }
975
        }
976
977
        throw $this->unexpected($keywordToken);
978
    }
979
980
    /**
981
     * @return bool
982
     */
983 133
    function peekDescription() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
984 133
        return $this->peek(Token::STRING) || $this->peek(Token::BLOCK_STRING);
985
    }
986
987
    /**
988
     * @return StringValueNode|null
989
     */
990 125
    function parseDescription() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
991 125
        if ($this->peekDescription()) {
992 8
            return $this->parseStringLiteral();
993
        }
994 125
    }
995
996
    /**
997
     * @return SchemaDefinitionNode
998
     * @throws SyntaxError
999
     */
1000 53
    function parseSchemaDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1001
    {
1002 53
        $start = $this->lexer->token;
1003 53
        $this->expectKeyword('schema');
1004 53
        $directives = $this->parseDirectives(true);
1005
1006 53
        $operationTypes = $this->many(
1007 53
            Token::BRACE_L,
1008 53
            [$this, 'parseOperationTypeDefinition'],
1009 53
            Token::BRACE_R
1010
        );
1011
1012 53
        return new SchemaDefinitionNode([
1013 53
            'directives' => $directives,
1014 53
            'operationTypes' => $operationTypes,
1015 53
            'loc' => $this->loc($start)
1016
        ]);
1017
    }
1018
1019
    /**
1020
     * @return OperationTypeDefinitionNode
1021
     * @throws SyntaxError
1022
     */
1023 53
    function parseOperationTypeDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1024
    {
1025 53
        $start = $this->lexer->token;
1026 53
        $operation = $this->parseOperationType();
1027 53
        $this->expect(Token::COLON);
1028 53
        $type = $this->parseNamedType();
1029
1030 53
        return new OperationTypeDefinitionNode([
1031 53
            'operation' => $operation,
1032 53
            'type' => $type,
1033 53
            'loc' => $this->loc($start)
1034
        ]);
1035
    }
1036
1037
    /**
1038
     * @return ScalarTypeDefinitionNode
1039
     * @throws SyntaxError
1040
     */
1041 7
    function parseScalarTypeDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1042
    {
1043 7
        $start = $this->lexer->token;
1044 7
        $description = $this->parseDescription();
1045 7
        $this->expectKeyword('scalar');
1046 7
        $name = $this->parseName();
1047 7
        $directives = $this->parseDirectives(true);
1048
1049 7
        return new ScalarTypeDefinitionNode([
1050 7
            'name' => $name,
1051 7
            'directives' => $directives,
1052 7
            'loc' => $this->loc($start),
1053 7
            'description' => $description
1054
        ]);
1055
    }
1056
1057
    /**
1058
     * @return ObjectTypeDefinitionNode
1059
     * @throws SyntaxError
1060
     */
1061 109
    function parseObjectTypeDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1062
    {
1063 109
        $start = $this->lexer->token;
1064 109
        $description = $this->parseDescription();
1065 109
        $this->expectKeyword('type');
1066 109
        $name = $this->parseName();
1067 109
        $interfaces = $this->parseImplementsInterfaces();
1068 109
        $directives = $this->parseDirectives(true);
1069 109
        $fields = $this->parseFieldsDefinition();
1070
1071 108
        return new ObjectTypeDefinitionNode([
1072 108
            'name' => $name,
1073 108
            'interfaces' => $interfaces,
1074 108
            'directives' => $directives,
1075 108
            'fields' => $fields,
1076 108
            'loc' => $this->loc($start),
1077 108
            'description' => $description
1078
        ]);
1079
    }
1080
1081
    /**
1082
     * ImplementsInterfaces :
1083
     *   - implements `&`? NamedType
1084
     *   - ImplementsInterfaces & NamedType
1085
     *
1086
     * @return NamedTypeNode[]
1087
     */
1088 113
    function parseImplementsInterfaces()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1089
    {
1090 113
        $types = [];
1091 113
        if ($this->lexer->token->value === 'implements') {
1092 36
            $this->lexer->advance();
1093
            // Optional leading ampersand
1094 36
            $this->skip(Token::AMP);
1095
            do {
1096 36
                $types[] = $this->parseNamedType();
1097
            } while (
1098 36
                $this->skip(Token::AMP) ||
1099
                // Legacy support for the SDL?
1100 36
                (!empty($this->lexer->options['allowLegacySDLImplementsInterfaces']) && $this->peek(Token::NAME))
1101
            );
1102
        }
1103 113
        return $types;
1104
    }
1105
1106
    /**
1107
     * @return FieldDefinitionNode[]|NodeList
1108
     * @throws SyntaxError
1109
     */
1110 114
    function parseFieldsDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1111
    {
1112
        // Legacy support for the SDL?
1113
        if (
1114 114
            !empty($this->lexer->options['allowLegacySDLEmptyFields']) &&
1115 114
            $this->peek(Token::BRACE_L) &&
1116 114
            $this->lexer->lookahead()->kind === Token::BRACE_R
1117
        ) {
1118 1
            $this->lexer->advance();
1119 1
            $this->lexer->advance();
1120 1
            return [];
1121
        }
1122 113
        return $this->peek(Token::BRACE_L)
1123 109
            ? $this->many(
1124 109
                Token::BRACE_L,
1125 109
                [$this, 'parseFieldDefinition'],
1126 109
                Token::BRACE_R
1127
            )
1128 112
            : new NodeList([]);
1129
    }
1130
1131
    /**
1132
     * @return FieldDefinitionNode
1133
     * @throws SyntaxError
1134
     */
1135 109
    function parseFieldDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1136
    {
1137 109
        $start = $this->lexer->token;
1138 109
        $description = $this->parseDescription();
1139 109
        $name = $this->parseName();
1140 108
        $args = $this->parseArgumentDefs();
1141 108
        $this->expect(Token::COLON);
1142 108
        $type = $this->parseTypeReference();
1143 108
        $directives = $this->parseDirectives(true);
1144
1145 108
        return new FieldDefinitionNode([
1146 108
            'name' => $name,
1147 108
            'arguments' => $args,
1148 108
            'type' => $type,
1149 108
            'directives' => $directives,
1150 108
            'loc' => $this->loc($start),
1151 108
            'description' => $description
1152
        ]);
1153
    }
1154
1155
    /**
1156
     * @return InputValueDefinitionNode[]|NodeList
1157
     * @throws SyntaxError
1158
     */
1159 109
    function parseArgumentDefs()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1160
    {
1161 109
        if (!$this->peek(Token::PAREN_L)) {
1162 95
            return new NodeList([]);
1163
        }
1164 34
        return $this->many(Token::PAREN_L, [$this, 'parseInputValueDef'], Token::PAREN_R);
1165
    }
1166
1167
    /**
1168
     * @return InputValueDefinitionNode
1169
     * @throws SyntaxError
1170
     */
1171 43
    function parseInputValueDef()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1172
    {
1173 43
        $start = $this->lexer->token;
1174 43
        $description = $this->parseDescription();
1175 43
        $name = $this->parseName();
1176 43
        $this->expect(Token::COLON);
1177 42
        $type = $this->parseTypeReference();
1178 42
        $defaultValue = null;
1179 42
        if ($this->skip(Token::EQUALS)) {
1180 5
            $defaultValue = $this->parseConstValue();
1181
        }
1182 42
        $directives = $this->parseDirectives(true);
1183 42
        return new InputValueDefinitionNode([
1184 42
            'name' => $name,
1185 42
            'type' => $type,
1186 42
            'defaultValue' => $defaultValue,
1187 42
            'directives' => $directives,
1188 42
            'loc' => $this->loc($start),
1189 42
            'description' => $description
1190
        ]);
1191
    }
1192
1193
    /**
1194
     * @return InterfaceTypeDefinitionNode
1195
     * @throws SyntaxError
1196
     */
1197 31
    function parseInterfaceTypeDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1198
    {
1199 31
        $start = $this->lexer->token;
1200 31
        $description = $this->parseDescription();
1201 31
        $this->expectKeyword('interface');
1202 31
        $name = $this->parseName();
1203 31
        $directives = $this->parseDirectives(true);
1204 31
        $fields = $this->parseFieldsDefinition();
1205
1206 31
        return new InterfaceTypeDefinitionNode([
1207 31
            'name' => $name,
1208 31
            'directives' => $directives,
1209 31
            'fields' => $fields,
1210 31
            'loc' => $this->loc($start),
1211 31
            'description' => $description
1212
        ]);
1213
    }
1214
1215
    /**
1216
     * UnionTypeDefinition :
1217
     *   - Description? union Name Directives[Const]? UnionMemberTypes?
1218
     *
1219
     * @return UnionTypeDefinitionNode
1220
     * @throws SyntaxError
1221
     */
1222 24
    function parseUnionTypeDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1223
    {
1224 24
        $start = $this->lexer->token;
1225 24
        $description = $this->parseDescription();
1226 24
        $this->expectKeyword('union');
1227 24
        $name = $this->parseName();
1228 24
        $directives = $this->parseDirectives(true);
1229 24
        $types = $this->parseUnionMemberTypes();
1230
1231 20
        return new UnionTypeDefinitionNode([
1232 20
            'name' => $name,
1233 20
            'directives' => $directives,
1234 20
            'types' => $types,
1235 20
            'loc' => $this->loc($start),
1236 20
            'description' => $description
1237
        ]);
1238
    }
1239
1240
    /**
1241
     * UnionMemberTypes :
1242
     *   - = `|`? NamedType
1243
     *   - UnionMemberTypes | NamedType
1244
     *
1245
     * @return NamedTypeNode[]
1246
     */
1247 24
    function parseUnionMemberTypes()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1248
    {
1249 24
        $types = [];
1250 24
        if ($this->skip(Token::EQUALS)) {
1251
            // Optional leading pipe
1252 23
            $this->skip(Token::PIPE);
1253
            do {
1254 23
                $types[] = $this->parseNamedType();
1255 21
            } while ($this->skip(Token::PIPE));
1256
        }
1257 20
        return $types;
1258
    }
1259
1260
    /**
1261
     * @return EnumTypeDefinitionNode
1262
     * @throws SyntaxError
1263
     */
1264 16
    function parseEnumTypeDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1265
    {
1266 16
        $start = $this->lexer->token;
1267 16
        $description = $this->parseDescription();
1268 16
        $this->expectKeyword('enum');
1269 16
        $name = $this->parseName();
1270 16
        $directives = $this->parseDirectives(true);
1271 16
        $values = $this->parseEnumValuesDefinition();
1272
1273 16
        return new EnumTypeDefinitionNode([
1274 16
            'name' => $name,
1275 16
            'directives' => $directives,
1276 16
            'values' => $values,
1277 16
            'loc' => $this->loc($start),
1278 16
            'description' => $description
1279
        ]);
1280
    }
1281
1282
    /**
1283
     * @return EnumValueDefinitionNode[]|NodeList
1284
     * @throws SyntaxError
1285
     */
1286 16
    function parseEnumValuesDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1287
    {
1288 16
        return $this->peek(Token::BRACE_L)
1289 15
            ? $this->many(
1290 15
                Token::BRACE_L,
1291 15
                [$this, 'parseEnumValueDefinition'],
1292 15
                Token::BRACE_R
1293
              )
1294 16
            : new NodeList([]);
1295
    }
1296
1297
    /**
1298
     * @return EnumValueDefinitionNode
1299
     * @throws SyntaxError
1300
     */
1301 15
    function parseEnumValueDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1302
    {
1303 15
        $start = $this->lexer->token;
1304 15
        $description = $this->parseDescription();
1305 15
        $name = $this->parseName();
1306 15
        $directives = $this->parseDirectives(true);
1307
1308 15
        return new EnumValueDefinitionNode([
1309 15
            'name' => $name,
1310 15
            'directives' => $directives,
1311 15
            'loc' => $this->loc($start),
1312 15
            'description' => $description
1313
        ]);
1314
    }
1315
1316
    /**
1317
     * @return InputObjectTypeDefinitionNode
1318
     * @throws SyntaxError
1319
     */
1320 19
    function parseInputObjectTypeDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1321
    {
1322 19
        $start = $this->lexer->token;
1323 19
        $description = $this->parseDescription();
1324 19
        $this->expectKeyword('input');
1325 19
        $name = $this->parseName();
1326 19
        $directives = $this->parseDirectives(true);
1327 19
        $fields = $this->parseInputFieldsDefinition();
1328
1329 18
        return new InputObjectTypeDefinitionNode([
1330 18
            'name' => $name,
1331 18
            'directives' => $directives,
1332 18
            'fields' => $fields,
1333 18
            'loc' => $this->loc($start),
1334 18
            'description' => $description
1335
        ]);
1336
    }
1337
1338
    /**
1339
     * @return InputValueDefinitionNode[]|NodeList
1340
     * @throws SyntaxError
1341
     */
1342 19
    function parseInputFieldsDefinition() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1343 19
        return $this->peek(Token::BRACE_L)
1344 18
            ? $this->many(
1345 18
                Token::BRACE_L,
1346 18
                [$this, 'parseInputValueDef'],
1347 18
                Token::BRACE_R
1348
            )
1349 18
            : new NodeList([]);
1350
    }
1351
1352
    /**
1353
     * TypeExtension :
1354
     *   - ScalarTypeExtension
1355
     *   - ObjectTypeExtension
1356
     *   - InterfaceTypeExtension
1357
     *   - UnionTypeExtension
1358
     *   - EnumTypeExtension
1359
     *   - InputObjectTypeDefinition
1360
     *
1361
     * @return TypeExtensionNode
1362
     * @throws SyntaxError
1363
     */
1364 10
    function parseTypeExtension()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1365
    {
1366 10
        $keywordToken = $this->lexer->lookahead();
1367
1368 10
        if ($keywordToken->kind === Token::NAME) {
1369 9
            switch ($keywordToken->value) {
1370 9
                case 'scalar':
1371 3
                    return $this->parseScalarTypeExtension();
1372 9
                case 'type':
1373 8
                    return $this->parseObjectTypeExtension();
1374 4
                case 'interface':
1375 3
                    return $this->parseInterfaceTypeExtension();
1376 4
                case 'union':
1377 3
                    return $this->parseUnionTypeExtension();
1378 4
                case 'enum':
1379 3
                    return $this->parseEnumTypeExtension();
1380 4
                case 'input':
1381 3
                    return $this->parseInputObjectTypeExtension();
1382
            }
1383
        }
1384
1385 2
        throw $this->unexpected($keywordToken);
1386
    }
1387
1388
    /**
1389
     * @return ScalarTypeExtensionNode
1390
     * @throws SyntaxError
1391
     */
1392 3
    function parseScalarTypeExtension() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1393 3
        $start = $this->lexer->token;
1394 3
        $this->expectKeyword('extend');
1395 3
        $this->expectKeyword('scalar');
1396 3
        $name = $this->parseName();
1397 3
        $directives = $this->parseDirectives(true);
1398 3
        if (count($directives) === 0) {
1399
            throw $this->unexpected();
1400
        }
1401
1402 3
        return new ScalarTypeExtensionNode([
1403 3
            'name' => $name,
1404 3
            'directives' => $directives,
1405 3
            'loc' => $this->loc($start)
1406
        ]);
1407
    }
1408
1409
    /**
1410
     * @return ObjectTypeExtensionNode
1411
     * @throws SyntaxError
1412
     */
1413 8
    function parseObjectTypeExtension() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1414 8
        $start = $this->lexer->token;
1415 8
        $this->expectKeyword('extend');
1416 8
        $this->expectKeyword('type');
1417 8
        $name = $this->parseName();
1418 8
        $interfaces = $this->parseImplementsInterfaces();
1419 8
        $directives = $this->parseDirectives(true);
1420 8
        $fields = $this->parseFieldsDefinition();
1421
1422
        if (
1423 8
            !$interfaces &&
0 ignored issues
show
Bug Best Practice introduced by
The expression $interfaces of type GraphQL\Language\AST\NamedTypeNode[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1424 8
            count($directives) === 0 &&
1425 8
            count($fields) === 0
1426
        ) {
1427 1
            throw $this->unexpected();
1428
        }
1429
1430 7
        return new ObjectTypeExtensionNode([
1431 7
            'name' => $name,
1432 7
            'interfaces' => $interfaces,
1433 7
            'directives' => $directives,
1434 7
            'fields' => $fields,
1435 7
            'loc' => $this->loc($start)
1436
        ]);
1437
    }
1438
1439
    /**
1440
     * @return InterfaceTypeExtensionNode
1441
     * @throws SyntaxError
1442
     */
1443 3
    function parseInterfaceTypeExtension() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1444 3
        $start = $this->lexer->token;
1445 3
        $this->expectKeyword('extend');
1446 3
        $this->expectKeyword('interface');
1447 3
        $name = $this->parseName();
1448 3
        $directives = $this->parseDirectives(true);
1449 3
        $fields = $this->parseFieldsDefinition();
1450
        if (
1451 3
            count($directives) === 0 &&
1452 3
            count($fields) === 0
1453
        ) {
1454
            throw $this->unexpected();
1455
        }
1456
1457 3
        return new InterfaceTypeExtensionNode([
1458 3
            'name' => $name,
1459 3
            'directives' => $directives,
1460 3
            'fields' => $fields,
1461 3
            'loc' => $this->loc($start)
1462
        ]);
1463
    }
1464
1465
    /**
1466
     * UnionTypeExtension :
1467
     *   - extend union Name Directives[Const]? UnionMemberTypes
1468
     *   - extend union Name Directives[Const]
1469
     *
1470
     * @return UnionTypeExtensionNode
1471
     * @throws SyntaxError
1472
     */
1473 3
    function parseUnionTypeExtension() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1474 3
        $start = $this->lexer->token;
1475 3
        $this->expectKeyword('extend');
1476 3
        $this->expectKeyword('union');
1477 3
        $name = $this->parseName();
1478 3
        $directives = $this->parseDirectives(true);
1479 3
        $types = $this->parseUnionMemberTypes();
1480
        if (
1481 3
            count($directives) === 0 &&
1482 3
            !$types
0 ignored issues
show
Bug Best Practice introduced by
The expression $types of type GraphQL\Language\AST\NamedTypeNode[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1483
        ) {
1484
            throw $this->unexpected();
1485
        }
1486
1487 3
        return new UnionTypeExtensionNode([
1488 3
            'name' => $name,
1489 3
            'directives' => $directives,
1490 3
            'types' => $types,
1491 3
            'loc' => $this->loc($start)
1492
        ]);
1493
    }
1494
1495
    /**
1496
     * @return EnumTypeExtensionNode
1497
     * @throws SyntaxError
1498
     */
1499 3
    function parseEnumTypeExtension() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1500 3
        $start = $this->lexer->token;
1501 3
        $this->expectKeyword('extend');
1502 3
        $this->expectKeyword('enum');
1503 3
        $name = $this->parseName();
1504 3
        $directives = $this->parseDirectives(true);
1505 3
        $values = $this->parseEnumValuesDefinition();
1506
        if (
1507 3
            count($directives) === 0 &&
1508 3
            count($values) === 0
1509
        ) {
1510
            throw $this->unexpected();
1511
        }
1512
1513 3
        return new EnumTypeExtensionNode([
1514 3
            'name' => $name,
1515 3
            'directives' => $directives,
1516 3
            'values' => $values,
1517 3
            'loc' => $this->loc($start)
1518
        ]);
1519
    }
1520
1521
    /**
1522
     * @return InputObjectTypeExtensionNode
1523
     * @throws SyntaxError
1524
     */
1525 3
    function parseInputObjectTypeExtension() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1526 3
        $start = $this->lexer->token;
1527 3
        $this->expectKeyword('extend');
1528 3
        $this->expectKeyword('input');
1529 3
        $name = $this->parseName();
1530 3
        $directives = $this->parseDirectives(true);
1531 3
        $fields = $this->parseInputFieldsDefinition();
1532
        if (
1533 3
            count($directives) === 0 &&
1534 3
            count($fields) === 0
1535
        ) {
1536
            throw $this->unexpected();
1537
        }
1538
1539 3
        return new InputObjectTypeExtensionNode([
1540 3
            'name' => $name,
1541 3
            'directives' => $directives,
1542 3
            'fields' => $fields,
1543 3
            'loc' => $this->loc($start)
1544
        ]);
1545
    }
1546
1547
    /**
1548
     * DirectiveDefinition :
1549
     *   - directive @ Name ArgumentsDefinition? on DirectiveLocations
1550
     *
1551
     * @return DirectiveDefinitionNode
1552
     * @throws SyntaxError
1553
     */
1554 8
    function parseDirectiveDefinition()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1555
    {
1556 8
        $start = $this->lexer->token;
1557 8
        $description = $this->parseDescription();
1558 8
        $this->expectKeyword('directive');
1559 8
        $this->expect(Token::AT);
1560 8
        $name = $this->parseName();
1561 8
        $args = $this->parseArgumentDefs();
1562 8
        $this->expectKeyword('on');
1563 8
        $locations = $this->parseDirectiveLocations();
1564
1565 7
        return new DirectiveDefinitionNode([
1566 7
            'name' => $name,
1567 7
            'arguments' => $args,
1568 7
            'locations' => $locations,
1569 7
            'loc' => $this->loc($start),
1570 7
            'description' => $description
1571
        ]);
1572
    }
1573
1574
    /**
1575
     * @return NameNode[]
1576
     * @throws SyntaxError
1577
     */
1578 8
    function parseDirectiveLocations()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1579
    {
1580
        // Optional leading pipe
1581 8
        $this->skip(Token::PIPE);
1582 8
        $locations = [];
1583
        do {
1584 8
            $locations[] = $this->parseDirectiveLocation();
1585 8
        } while ($this->skip(Token::PIPE));
1586 7
        return $locations;
1587
    }
1588
1589
    /**
1590
     * @return NameNode
1591
     * @throws SyntaxError
1592
     */
1593 8
    function parseDirectiveLocation()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1594
    {
1595 8
        $start = $this->lexer->token;
1596 8
        $name = $this->parseName();
1597 8
        if (DirectiveLocation::has($name->value)) {
1598 8
            return $name;
1599
        }
1600
1601 1
        throw $this->unexpected($start);
1602
    }
1603
}
1604