From cf1c080c7e5dd6c1925c5bf0f61a529e8bab6a3c Mon Sep 17 00:00:00 2001 From: Jovi De Croock Date: Fri, 25 Oct 2024 07:17:11 +0200 Subject: [PATCH] Expose `tokenCount` on the `DocumentNode` (#4251) This way people can add this to metrics and inform themselves about sane values to use with the `maxTokens` option on `parse`. This was added as a non-enumerable property to increase backwards compatability. Currently there is now way to know the tokens and by extension set sane defaults. --- src/language/__tests__/parser-test.ts | 5 +++++ src/language/ast.ts | 1 + src/language/parser.ts | 15 ++++++++++++--- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/language/__tests__/parser-test.ts b/src/language/__tests__/parser-test.ts index 71efd7b8eb..d98b6a6f41 100644 --- a/src/language/__tests__/parser-test.ts +++ b/src/language/__tests__/parser-test.ts @@ -100,6 +100,11 @@ describe('Parser', () => { ); }); + it('exposes the tokenCount', () => { + expect(parse('{ foo }').tokenCount).to.equal(3); + expect(parse('{ foo(bar: "baz") }').tokenCount).to.equal(8); + }); + it('parses variable inline values', () => { expect(() => parse('{ field(complex: { a: { b: [ $var ] } }) }'), diff --git a/src/language/ast.ts b/src/language/ast.ts index e7ea84fd79..e10a4fe119 100644 --- a/src/language/ast.ts +++ b/src/language/ast.ts @@ -312,6 +312,7 @@ export interface DocumentNode { readonly kind: Kind.DOCUMENT; readonly loc?: Location | undefined; readonly definitions: ReadonlyArray; + readonly tokenCount?: number | undefined; } export type DefinitionNode = diff --git a/src/language/parser.ts b/src/language/parser.ts index 5e70bcb9f0..3d2018ba4b 100644 --- a/src/language/parser.ts +++ b/src/language/parser.ts @@ -119,7 +119,12 @@ export function parse( options?: ParseOptions | undefined, ): DocumentNode { const parser = new Parser(source, options); - return parser.parseDocument(); + const document = parser.parseDocument(); + Object.defineProperty(document, 'tokenCount', { + enumerable: false, + value: parser.tokenCount, + }); + return document; } /** @@ -201,6 +206,10 @@ export class Parser { this._tokenCounter = 0; } + get tokenCount(): number { + return this._tokenCounter; + } + /** * Converts a name lex token into a name parse node. */ @@ -1601,9 +1610,9 @@ export class Parser { const { maxTokens } = this._options; const token = this._lexer.advance(); - if (maxTokens !== undefined && token.kind !== TokenKind.EOF) { + if (token.kind !== TokenKind.EOF) { ++this._tokenCounter; - if (this._tokenCounter > maxTokens) { + if (maxTokens !== undefined && this._tokenCounter > maxTokens) { throw syntaxError( this._lexer.source, token.start,