Skip to content

Commit 9628498

Browse files
Citoclaude
andcommitted
Expose tokenCount on the DocumentNode
Replicates graphql/graphql-js@10cc0aca Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent fec6b57 commit 9628498

3 files changed

Lines changed: 21 additions & 4 deletions

File tree

‎src/graphql/language/ast.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,11 @@ class DocumentNode(Node):
411411
__slots__ = ("definitions",)
412412

413413
definitions: Tuple["DefinitionNode", ...]
414+
# The number of tokens in the parsed document. Set by the parser per instance
415+
# and deliberately kept out of ``__slots__`` (and therefore out of ``keys``) so
416+
# that it is not treated as a traversable attribute, the equivalent of the
417+
# non-enumerable ``tokenCount`` property in graphql-js.
418+
token_count: int = 0
414419

415420

416421
class DefinitionNode(Node):

‎src/graphql/language/parser.py‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -234,13 +234,21 @@ def parse_name(self) -> NameNode:
234234

235235
# Implement the parsing rules in the Document section.
236236

237+
@property
238+
def token_count(self) -> int:
239+
"""Get the number of tokens that have been parsed so far."""
240+
return self._token_counter
241+
237242
def parse_document(self) -> DocumentNode:
238243
"""Document: Definition+"""
239244
start = self._lexer.token
240-
return DocumentNode(
245+
document = DocumentNode(
241246
definitions=self.many(TokenKind.SOF, self.parse_definition, TokenKind.EOF),
242247
loc=self.loc(start),
243248
)
249+
# Expose the token count as a (non-traversable) attribute on the document.
250+
document.token_count = self.token_count
251+
return document
244252

245253
_parse_type_system_definition_method_names: Dict[str, str] = {
246254
"schema": "schema_definition",
@@ -1177,12 +1185,12 @@ def delimited_many(
11771185
return nodes
11781186

11791187
def advance_lexer(self) -> None:
1180-
max_tokens = self._max_tokens
11811188
token = self._lexer.advance()
11821189

1183-
if max_tokens is not None and token.kind != TokenKind.EOF:
1190+
if token.kind != TokenKind.EOF:
11841191
self._token_counter += 1
1185-
if self._token_counter > max_tokens:
1192+
max_tokens = self._max_tokens
1193+
if max_tokens is not None and self._token_counter > max_tokens:
11861194
raise GraphQLSyntaxError(
11871195
self._lexer.source,
11881196
token.start,

‎tests/language/test_parser.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ def parse_provides_useful_error_when_using_source():
8787
| ^
8888
""")
8989

90+
def exposes_the_token_count():
91+
assert parse("{ foo }").token_count == 3
92+
assert parse('{ foo(bar: "baz") }').token_count == 8
93+
9094
def limits_maximum_number_of_tokens():
9195
assert parse("{ foo }", max_tokens=3)
9296
with raises(

0 commit comments

Comments
 (0)