Skip to content

Commit 4fb8c60

Browse files
committed
parser: add specialized error for extension with descriptions
Replicates graphql/graphql-js@4bb273d
1 parent 69899bc commit 4fb8c60

File tree

2 files changed

+50
-55
lines changed

2 files changed

+50
-55
lines changed

src/graphql/language/parser.py

+44-51
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
SelectionSetNode,
5050
StringValueNode,
5151
TypeNode,
52-
TypeSystemDefinitionNode,
5352
TypeSystemExtensionNode,
5453
UnionTypeDefinitionNode,
5554
UnionTypeExtensionNode,
@@ -224,46 +223,64 @@ def parse_document(self) -> DocumentNode:
224223
loc=self.loc(start),
225224
)
226225

227-
_parse_definition_method_names: Dict[str, str] = {
226+
_parse_type_system_definition_method_names: Dict[str, str] = {
227+
"schema": "schema_definition",
228+
"scalar": "scalar_type_definition",
229+
"type": "object_type_definition",
230+
"interface": "interface_type_definition",
231+
"union": "union_type_definition",
232+
"enum": "enum_type_definition",
233+
"input": "input_object_type_definition",
234+
"directive": "directive_definition",
235+
}
236+
237+
_parse_other_definition_method_names: Dict[str, str] = {
228238
**dict.fromkeys(("query", "mutation", "subscription"), "operation_definition"),
229239
"fragment": "fragment_definition",
230-
**dict.fromkeys(
231-
(
232-
"schema",
233-
"scalar",
234-
"type",
235-
"interface",
236-
"union",
237-
"enum",
238-
"input",
239-
"directive",
240-
),
241-
"type_system_definition",
242-
),
243240
"extend": "type_system_extension",
244241
}
245242

246243
def parse_definition(self) -> DefinitionNode:
247244
"""Definition: ExecutableDefinition or TypeSystemDefinition/Extension
248245
249246
ExecutableDefinition: OperationDefinition or FragmentDefinition
247+
248+
TypeSystemDefinition: SchemaDefinition, TypeDefinition or DirectiveDefinition
249+
250+
TypeDefinition: ScalarTypeDefinition, ObjectTypeDefinition,
251+
InterfaceTypeDefinition, UnionTypeDefinition,
252+
EnumTypeDefinition or InputObjectTypeDefinition
250253
"""
251-
if self.peek(TokenKind.NAME):
252-
method_name = self._parse_definition_method_names.get(
253-
cast(str, self._lexer.token.value)
254+
if self.peek(TokenKind.BRACE_L):
255+
return self.parse_operation_definition()
256+
257+
# Many definitions begin with a description and require a lookahead.
258+
has_description = self.peek_description()
259+
keyword_token = (
260+
self._lexer.lookahead() if has_description else self._lexer.token
261+
)
262+
263+
if keyword_token.kind is TokenKind.NAME:
264+
token_name = cast(str, keyword_token.value)
265+
method_name = self._parse_type_system_definition_method_names.get(
266+
token_name
254267
)
255268
if method_name:
256269
return getattr(self, f"parse_{method_name}")()
257-
elif self.peek(TokenKind.BRACE_L):
258-
return self.parse_operation_definition()
259-
elif self.peek_description():
260-
return self.parse_type_system_definition()
261-
raise self.unexpected()
262270

263-
_parse_executable_definition_method_names: Dict[str, str] = {
264-
**dict.fromkeys(("query", "mutation", "subscription"), "operation_definition"),
265-
**dict.fromkeys(("fragment",), "fragment_definition"),
266-
}
271+
if has_description:
272+
raise GraphQLSyntaxError(
273+
self._lexer.source,
274+
self._lexer.token.start,
275+
"Unexpected description,"
276+
" descriptions are supported only on type definitions.",
277+
)
278+
279+
method_name = self._parse_other_definition_method_names.get(token_name)
280+
if method_name:
281+
return getattr(self, f"parse_{method_name}")()
282+
283+
raise self.unexpected(keyword_token)
267284

268285
# Implement the parsing rules in the Operations section.
269286

@@ -580,30 +597,6 @@ def parse_named_type(self) -> NamedTypeNode:
580597

581598
# Implement the parsing rules in the Type Definition section.
582599

583-
_parse_type_system_definition_method_names: Dict[str, str] = {
584-
"schema": "schema_definition",
585-
"scalar": "scalar_type_definition",
586-
"type": "object_type_definition",
587-
"interface": "interface_type_definition",
588-
"union": "union_type_definition",
589-
"enum": "enum_type_definition",
590-
"input": "input_object_type_definition",
591-
"directive": "directive_definition",
592-
}
593-
594-
def parse_type_system_definition(self) -> TypeSystemDefinitionNode:
595-
"""TypeSystemDefinition"""
596-
# Many definitions begin with a description and require a lookahead.
597-
keyword_token = (
598-
self._lexer.lookahead() if self.peek_description() else self._lexer.token
599-
)
600-
method_name = self._parse_type_system_definition_method_names.get(
601-
cast(str, keyword_token.value)
602-
)
603-
if method_name:
604-
return getattr(self, f"parse_{method_name}")()
605-
raise self.unexpected(keyword_token)
606-
607600
_parse_type_extension_method_names: Dict[str, str] = {
608601
"schema": "schema_extension",
609602
"scalar": "scalar_type_extension",

tests/language/test_schema_parser.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,9 @@ def object_extension_do_not_include_descriptions():
298298
extend type Hello {
299299
world: String
300300
}""",
301-
"Unexpected Name 'extend'.",
302-
(3, 13),
301+
"Unexpected description,"
302+
" descriptions are supported only on type definitions.",
303+
(2, 13),
303304
)
304305
assert_syntax_error(
305306
"""
@@ -317,8 +318,9 @@ def interface_extension_do_not_include_descriptions():
317318
extend interface Hello {
318319
world: String
319320
}""",
320-
"Unexpected Name 'extend'.",
321-
(3, 13),
321+
"Unexpected description,"
322+
" descriptions are supported only on type definitions.",
323+
(2, 13),
322324
)
323325
assert_syntax_error(
324326
"""

0 commit comments

Comments
 (0)