Skip to content

Commit a79a51d

Browse files
committed
Schema Parsing: allow leading pipe for union type definitions
1 parent 3063205 commit a79a51d

File tree

4 files changed

+98
-20
lines changed

4 files changed

+98
-20
lines changed

src/Language/Parser.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1080,14 +1080,17 @@ function parseUnionTypeDefinition()
10801080

10811081
/**
10821082
* UnionMembers :
1083-
* - NamedType
1083+
* - `|`? NamedType
10841084
* - UnionMembers | NamedType
10851085
*
10861086
* @return NamedTypeNode[]
10871087
*/
10881088
function parseUnionMembers()
10891089
{
1090+
// Optional leading pipe
1091+
$this->skip(Token::PIPE);
10901092
$members = [];
1093+
10911094
do {
10921095
$members[] = $this->parseNamedType();
10931096
} while ($this->skip(Token::PIPE));
@@ -1213,6 +1216,8 @@ function parseDirectiveDefinition()
12131216
*/
12141217
function parseDirectiveLocations()
12151218
{
1219+
// Optional leading pipe
1220+
$this->skip(Token::PIPE);
12161221
$locations = [];
12171222
do {
12181223
$locations[] = $this->parseName();

tests/Language/SchemaParserTest.php

Lines changed: 81 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,9 @@
11
<?php
22
namespace GraphQL\Tests\Language;
33

4-
use GraphQL\Language\AST\BooleanValueNode;
5-
use GraphQL\Language\AST\DocumentNode;
6-
use GraphQL\Language\AST\EnumTypeDefinitionNode;
7-
use GraphQL\Language\AST\EnumValueDefinitionNode;
8-
use GraphQL\Language\AST\FieldDefinitionNode;
9-
use GraphQL\Language\AST\InputObjectTypeDefinitionNode;
10-
use GraphQL\Language\AST\InputValueDefinitionNode;
11-
use GraphQL\Language\AST\InterfaceTypeDefinitionNode;
12-
use GraphQL\Language\AST\ListTypeNode;
13-
use GraphQL\Language\AST\Location;
14-
use GraphQL\Language\AST\NameNode;
15-
use GraphQL\Language\AST\NamedTypeNode;
16-
use GraphQL\Language\AST\Node;
4+
use GraphQL\Error\SyntaxError;
175
use GraphQL\Language\AST\NodeKind;
18-
use GraphQL\Language\AST\NonNullTypeNode;
19-
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
20-
use GraphQL\Language\AST\ScalarTypeDefinitionNode;
21-
use GraphQL\Language\AST\TypeExtensionDefinitionNode;
22-
use GraphQL\Language\AST\UnionTypeDefinitionNode;
236
use GraphQL\Language\Parser;
24-
use GraphQL\Language\Source;
257

268
class SchemaParserTest extends \PHPUnit_Framework_TestCase
279
{
@@ -541,6 +523,86 @@ public function testUnionWithTwoTypes()
541523
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
542524
}
543525

526+
527+
/**
528+
* @it Union with two types and leading pipe
529+
*/
530+
public function testUnionWithTwoTypesAndLeadingPipe()
531+
{
532+
$body = 'union Hello = | Wo | Rld';
533+
$doc = Parser::parse($body);
534+
$expected = [
535+
'kind' => 'Document',
536+
'definitions' => [
537+
[
538+
'kind' => 'UnionTypeDefinition',
539+
'name' => $this->nameNode('Hello', ['start' => 6, 'end' => 11]),
540+
'directives' => [],
541+
'types' => [
542+
$this->typeNode('Wo', ['start' => 16, 'end' => 18]),
543+
$this->typeNode('Rld', ['start' => 21, 'end' => 24]),
544+
],
545+
'loc' => ['start' => 0, 'end' => 24],
546+
'description' => null
547+
]
548+
],
549+
'loc' => ['start' => 0, 'end' => 24],
550+
];
551+
$this->assertEquals($expected, TestUtils::nodeToArray($doc));
552+
}
553+
554+
/**
555+
* @it Union fails with no types
556+
*/
557+
public function testUnionFailsWithNoTypes()
558+
{
559+
$body = 'union Hello = |';
560+
try {
561+
Parser::parse($body);
562+
} catch (SyntaxError $e) {
563+
$this->assertContains('Syntax Error GraphQL (1:16) Expected Name, found <EOF>', $e->getMessage());
564+
}
565+
}
566+
567+
/**
568+
* @it Union fails with leading douple pipe
569+
*/
570+
public function testUnionFailsWithLeadingDoublePipe()
571+
{
572+
$body = 'union Hello = || Wo | Rld';
573+
try {
574+
Parser::parse($body);
575+
} catch (SyntaxError $e) {
576+
$this->assertContains('Syntax Error GraphQL (1:16) Expected Name, found |', $e->getMessage());
577+
}
578+
}
579+
580+
/**
581+
* @it Union fails with double pipe
582+
*/
583+
public function testUnionFailsWithDoublePipe()
584+
{
585+
$body = 'union Hello = Wo || Rld';
586+
try {
587+
Parser::parse($body);
588+
} catch (SyntaxError $e) {
589+
$this->assertContains('Syntax Error GraphQL (1:19) Expected Name, found |', $e->getMessage());
590+
}
591+
}
592+
593+
/**
594+
* @it Union fails with trailing pipe
595+
*/
596+
public function testUnionFailsWithTrailingPipe()
597+
{
598+
$body = 'union Hello = | Wo | Rld |';
599+
try {
600+
Parser::parse($body);
601+
} catch (SyntaxError $e) {
602+
$this->assertContains('Syntax Error GraphQL (1:27) Expected Name, found <EOF>', $e->getMessage());
603+
}
604+
}
605+
544606
/**
545607
* @it Scalar
546608
*/

tests/Language/SchemaPrinterTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ interface AnnotatedInterface @onInterface {
8383
8484
union AnnotatedUnion @onUnion = A | B
8585
86+
union AnnotatedUnionTwo @onUnion = A | B
87+
8688
scalar CustomScalar
8789
8890
scalar AnnotatedScalar @onScalar
@@ -117,6 +119,8 @@ enum AnnotatedEnum @onEnum {
117119
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
118120
119121
directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
122+
123+
directive @include2(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
120124
';
121125
$this->assertEquals($expected, $printed);
122126
}

tests/Language/schema-kitchen-sink.graphql

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ union Feed = Story | Article | Advert
3737

3838
union AnnotatedUnion @onUnion = A | B
3939

40+
union AnnotatedUnionTwo @onUnion = | A | B
41+
4042
scalar CustomScalar
4143

4244
scalar AnnotatedScalar @onScalar
@@ -74,3 +76,8 @@ directive @include(if: Boolean!)
7476
on FIELD
7577
| FRAGMENT_SPREAD
7678
| INLINE_FRAGMENT
79+
80+
directive @include2(if: Boolean!) on
81+
| FIELD
82+
| FRAGMENT_SPREAD
83+
| INLINE_FRAGMENT

0 commit comments

Comments
 (0)