Skip to content

Commit a91fdd5

Browse files
committed
Avoid parse ambiguity on type extensions
Partial fix to #564, adds lookahead constraints to type system extensions to remove ambiguity or inefficiency from the grammar. The GraphQL grammar should be parsed in linear type with at most one lookahead. Since extensions have an optional `{ }` body, finding the token `{` should always attempt to parse the relevant portion of the type extension rather than completing the type extension and attempting to parse the query shorthand SelectionSet.
1 parent adee896 commit a91fdd5

File tree

2 files changed

+42
-22
lines changed

2 files changed

+42
-22
lines changed

spec/Appendix B -- Grammar Summary.md

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ SchemaDefinition : Description? schema Directives[Const]? { RootOperationTypeDef
222222

223223
SchemaExtension :
224224
- extend schema Directives[Const]? { RootOperationTypeDefinition+ }
225-
- extend schema Directives[Const]
225+
- extend schema Directives[Const] [lookahead != `{`]
226226

227227
RootOperationTypeDefinition : OperationType : NamedType
228228

@@ -249,12 +249,14 @@ ScalarTypeDefinition : Description? scalar Name Directives[Const]?
249249
ScalarTypeExtension :
250250
- extend scalar Name Directives[Const]
251251

252-
ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition?
252+
ObjectTypeDefinition :
253+
- Description? type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition
254+
- Description? type Name ImplementsInterfaces? Directives[Const]? [lookahead != `{`]
253255

254256
ObjectTypeExtension :
255257
- extend type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition
256-
- extend type Name ImplementsInterfaces? Directives[Const]
257-
- extend type Name ImplementsInterfaces
258+
- extend type Name ImplementsInterfaces? Directives[Const] [lookahead != `{`]
259+
- extend type Name ImplementsInterfaces [lookahead != `{`]
258260

259261
ImplementsInterfaces :
260262
- ImplementsInterfaces & NamedType
@@ -268,12 +270,14 @@ ArgumentsDefinition : ( InputValueDefinition+ )
268270

269271
InputValueDefinition : Description? Name : Type DefaultValue? Directives[Const]?
270272

271-
InterfaceTypeDefinition : Description? interface Name ImplementsInterfaces? Directives[Const]? FieldsDefinition?
273+
InterfaceTypeDefinition :
274+
- Description? interface Name ImplementsInterfaces? Directives[Const]? FieldsDefinition
275+
- Description? interface Name ImplementsInterfaces? Directives[Const]? [lookahead != `{`]
272276

273277
InterfaceTypeExtension :
274278
- extend interface Name ImplementsInterfaces? Directives[Const]? FieldsDefinition
275-
- extend interface Name ImplementsInterfaces? Directives[Const]
276-
- extend interface Name ImplementsInterfaces
279+
- extend interface Name ImplementsInterfaces? Directives[Const] [lookahead != `{`]
280+
- extend interface Name ImplementsInterfaces [lookahead != `{`]
277281

278282
UnionTypeDefinition : Description? union Name Directives[Const]? UnionMemberTypes?
279283

@@ -285,23 +289,27 @@ UnionTypeExtension :
285289
- extend union Name Directives[Const]? UnionMemberTypes
286290
- extend union Name Directives[Const]
287291

288-
EnumTypeDefinition : Description? enum Name Directives[Const]? EnumValuesDefinition?
292+
EnumTypeDefinition :
293+
- Description? enum Name Directives[Const]? EnumValuesDefinition
294+
- Description? enum Name Directives[Const]? [lookahead != `{`]
289295

290296
EnumValuesDefinition : { EnumValueDefinition+ }
291297

292298
EnumValueDefinition : Description? EnumValue Directives[Const]?
293299

294300
EnumTypeExtension :
295301
- extend enum Name Directives[Const]? EnumValuesDefinition
296-
- extend enum Name Directives[Const]
302+
- extend enum Name Directives[Const] [lookahead != `{`]
297303

298-
InputObjectTypeDefinition : Description? input Name Directives[Const]? InputFieldsDefinition?
304+
InputObjectTypeDefinition :
305+
- Description? input Name Directives[Const]? InputFieldsDefinition
306+
- Description? input Name Directives[Const]? [lookahead != `{`]
299307

300308
InputFieldsDefinition : { InputValueDefinition+ }
301309

302310
InputObjectTypeExtension :
303311
- extend input Name Directives[Const]? InputFieldsDefinition
304-
- extend input Name Directives[Const]
312+
- extend input Name Directives[Const] [lookahead != `{`]
305313

306314
DirectiveDefinition : Description? directive @ Name ArgumentsDefinition? `repeatable`? on DirectiveLocations
307315

spec/Section 3 -- Type System.md

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,16 @@ type Query {
222222

223223
SchemaExtension :
224224
- extend schema Directives[Const]? { RootOperationTypeDefinition+ }
225-
- extend schema Directives[Const]
225+
- extend schema Directives[Const] [lookahead != `{`]
226226

227227
Schema extensions are used to represent a schema which has been extended from
228228
an original schema. For example, this might be used by a GraphQL service which
229229
adds additional operation types, or additional directives to an existing schema.
230230

231+
Note: Schema extensions without additional operation type definitions must not
232+
be followed by a {`{`} (such as a query shorthand) to avoid parsing ambiguity.
233+
This same limitation applies to the type definitions and extensions below.
234+
231235
**Schema Validation**
232236

233237
Schema extensions have the potential to be invalid if incorrectly defined.
@@ -574,7 +578,9 @@ Scalar type extensions have the potential to be invalid if incorrectly defined.
574578

575579
## Objects
576580

577-
ObjectTypeDefinition : Description? type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition?
581+
ObjectTypeDefinition :
582+
- Description? type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition
583+
- Description? type Name ImplementsInterfaces? Directives[Const]? [lookahead != `{`]
578584

579585
ImplementsInterfaces :
580586
- ImplementsInterfaces & NamedType
@@ -949,8 +955,8 @@ type ExampleType {
949955

950956
ObjectTypeExtension :
951957
- extend type Name ImplementsInterfaces? Directives[Const]? FieldsDefinition
952-
- extend type Name ImplementsInterfaces? Directives[Const]
953-
- extend type Name ImplementsInterfaces
958+
- extend type Name ImplementsInterfaces? Directives[Const] [lookahead != `{`]
959+
- extend type Name ImplementsInterfaces [lookahead != `{`]
954960

955961
Object type extensions are used to represent a type which has been extended from
956962
some original type. For example, this might be used to represent local data, or
@@ -992,7 +998,9 @@ Object type extensions have the potential to be invalid if incorrectly defined.
992998

993999
## Interfaces
9941000

995-
InterfaceTypeDefinition : Description? interface Name ImplementsInterfaces? Directives[Const]? FieldsDefinition?
1001+
InterfaceTypeDefinition :
1002+
- Description? interface Name ImplementsInterfaces? Directives[Const]? FieldsDefinition
1003+
- Description? interface Name ImplementsInterfaces? Directives[Const]? [lookahead != `{`]
9961004

9971005
GraphQL interfaces represent a list of named fields and their arguments. GraphQL
9981006
objects and interfaces can then implement these interfaces which requires that
@@ -1182,8 +1190,8 @@ Interface types have the potential to be invalid if incorrectly defined.
11821190

11831191
InterfaceTypeExtension :
11841192
- extend interface Name ImplementsInterfaces? Directives[Const]? FieldsDefinition
1185-
- extend interface Name ImplementsInterfaces? Directives[Const]
1186-
- extend interface Name ImplementsInterfaces
1193+
- extend interface Name ImplementsInterfaces? Directives[Const] [lookahead != `{`]
1194+
- extend interface Name ImplementsInterfaces [lookahead != `{`]
11871195

11881196
Interface type extensions are used to represent an interface which has been
11891197
extended from some original interface. For example, this might be used to
@@ -1361,7 +1369,9 @@ Union type extensions have the potential to be invalid if incorrectly defined.
13611369

13621370
## Enums
13631371

1364-
EnumTypeDefinition : Description? enum Name Directives[Const]? EnumValuesDefinition?
1372+
EnumTypeDefinition :
1373+
- Description? enum Name Directives[Const]? EnumValuesDefinition
1374+
- Description? enum Name Directives[Const]? [lookahead != `{`]
13651375

13661376
EnumValuesDefinition : { EnumValueDefinition+ }
13671377

@@ -1411,7 +1421,7 @@ Enum types have the potential to be invalid if incorrectly defined.
14111421

14121422
EnumTypeExtension :
14131423
- extend enum Name Directives[Const]? EnumValuesDefinition
1414-
- extend enum Name Directives[Const]
1424+
- extend enum Name Directives[Const] [lookahead != `{`]
14151425

14161426
Enum type extensions are used to represent an enum type which has been
14171427
extended from some original enum type. For example, this might be used to
@@ -1432,7 +1442,9 @@ Enum type extensions have the potential to be invalid if incorrectly defined.
14321442

14331443
## Input Objects
14341444

1435-
InputObjectTypeDefinition : Description? input Name Directives[Const]? InputFieldsDefinition?
1445+
InputObjectTypeDefinition :
1446+
- Description? input Name Directives[Const]? InputFieldsDefinition
1447+
- Description? input Name Directives[Const]? [lookahead != `{`]
14361448

14371449
InputFieldsDefinition : { InputValueDefinition+ }
14381450

@@ -1599,7 +1611,7 @@ Literal Value | Variables | Coerced Value
15991611

16001612
InputObjectTypeExtension :
16011613
- extend input Name Directives[Const]? InputFieldsDefinition
1602-
- extend input Name Directives[Const]
1614+
- extend input Name Directives[Const] [lookahead != `{`]
16031615

16041616
Input object type extensions are used to represent an input object type which
16051617
has been extended from some original input object type. For example, this might

0 commit comments

Comments
 (0)