From 982f90ff35255bbfa113e14c07c91552f56afa13 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 20 Jun 2025 15:00:11 +0200 Subject: [PATCH] refactor(compiler): remove TokenError (#62160) Replaces the `TokenError` class with `ParseError` to reduce the number of error classes we need to maintain. PR Close #62160 --- packages/compiler/src/ml_parser/lexer.ts | 32 ++----- packages/compiler/src/ml_parser/parser.ts | 5 +- .../test/ml_parser/html_parser_spec.ts | 5 +- .../compiler/test/ml_parser/lexer_spec.ts | 91 +++++++------------ 4 files changed, 44 insertions(+), 89 deletions(-) diff --git a/packages/compiler/src/ml_parser/lexer.ts b/packages/compiler/src/ml_parser/lexer.ts index 5f4b8565615..9b304aed4c0 100644 --- a/packages/compiler/src/ml_parser/lexer.ts +++ b/packages/compiler/src/ml_parser/lexer.ts @@ -21,20 +21,10 @@ import { TokenType, } from './tokens'; -export class TokenError extends ParseError { - constructor( - errorMsg: string, - public tokenType: TokenType | null, - span: ParseSourceSpan, - ) { - super(span, errorMsg); - } -} - export class TokenizeResult { constructor( public tokens: Token[], - public errors: TokenError[], + public errors: ParseError[], public nonNormalizedIcuExpressions: Token[], ) {} } @@ -171,7 +161,7 @@ class _Tokenizer { private readonly _tokenizeLet: boolean; private readonly _selectorlessEnabled: boolean; tokens: Token[] = []; - errors: TokenError[] = []; + errors: ParseError[] = []; nonNormalizedIcuExpressions: Token[] = []; /** @@ -499,17 +489,15 @@ class _Tokenizer { private _endToken(parts: string[], end?: CharacterCursor): Token { if (this._currentTokenStart === null) { - throw new TokenError( - 'Programming error - attempted to end a token when there was no start to the token', - this._currentTokenType, + throw new ParseError( this._cursor.getSpan(end), + 'Programming error - attempted to end a token when there was no start to the token', ); } if (this._currentTokenType === null) { - throw new TokenError( - 'Programming error - attempted to end a token which has no token type', - null, + throw new ParseError( this._cursor.getSpan(this._currentTokenStart), + 'Programming error - attempted to end a token which has no token type', ); } const token = { @@ -526,11 +514,11 @@ class _Tokenizer { return token; } - private _createError(msg: string, span: ParseSourceSpan): TokenError { + private _createError(msg: string, span: ParseSourceSpan): ParseError { if (this._isInExpansionForm()) { msg += ` (Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.)`; } - const error = new TokenError(msg, this._currentTokenType, span); + const error = new ParseError(span, msg); this._currentTokenStart = null; this._currentTokenType = null; return error; @@ -540,7 +528,7 @@ class _Tokenizer { if (e instanceof CursorError) { e = this._createError(e.msg, this._cursor.getSpan(e.cursor)); } - if (e instanceof TokenError) { + if (e instanceof ParseError) { this.errors.push(e); } else { throw e; @@ -816,7 +804,7 @@ class _Tokenizer { this._consumeTagOpenEnd(); } } catch (e) { - if (e instanceof TokenError) { + if (e instanceof ParseError) { if (openToken) { // We errored before we could close the opening tag, so it is incomplete. openToken.type = diff --git a/packages/compiler/src/ml_parser/parser.ts b/packages/compiler/src/ml_parser/parser.ts index faae6130b0e..b479d7cc830 100644 --- a/packages/compiler/src/ml_parser/parser.ts +++ b/packages/compiler/src/ml_parser/parser.ts @@ -79,10 +79,7 @@ export class Parser { const tokenizeResult = tokenize(source, url, this.getTagDefinition, options); const parser = new _TreeBuilder(tokenizeResult.tokens, this.getTagDefinition); parser.build(); - return new ParseTreeResult( - parser.rootNodes, - (tokenizeResult.errors as ParseError[]).concat(parser.errors), - ); + return new ParseTreeResult(parser.rootNodes, [...tokenizeResult.errors, ...parser.errors]); } } diff --git a/packages/compiler/test/ml_parser/html_parser_spec.ts b/packages/compiler/test/ml_parser/html_parser_spec.ts index 57da871063c..8b93f178d61 100644 --- a/packages/compiler/test/ml_parser/html_parser_spec.ts +++ b/packages/compiler/test/ml_parser/html_parser_spec.ts @@ -770,7 +770,6 @@ describe('HtmlParser', () => { }); expect(humanizeErrors(p.errors)).toEqual([ [ - TokenType.RAW_TEXT, 'Unexpected character "EOF" (Do you have an unescaped "{" in your template? Use "{{ \'{\' }}") to escape it.)', '0:36', ], @@ -1857,7 +1856,7 @@ describe('HtmlParser', () => { const errors = parser.parse('

', 'TestComp').errors; expect(errors.length).toEqual(2); expect(humanizeErrors(errors)).toEqual([ - [TokenType.COMMENT_START, 'Unexpected character "e"', '0:3'], + ['Unexpected character "e"', '0:3'], [ 'p', 'Unexpected closing tag "p". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags', @@ -1876,6 +1875,6 @@ export function humanizeErrors(errors: ParseError[]): any[] { return [e.elementName, e.msg, humanizeLineColumn(e.span.start)]; } // Tokenizer errors - return [(e).tokenType, e.msg, humanizeLineColumn(e.span.start)]; + return [e.msg, humanizeLineColumn(e.span.start)]; }); } diff --git a/packages/compiler/test/ml_parser/lexer_spec.ts b/packages/compiler/test/ml_parser/lexer_spec.ts index 03854999a78..71690078e8e 100644 --- a/packages/compiler/test/ml_parser/lexer_spec.ts +++ b/packages/compiler/test/ml_parser/lexer_spec.ts @@ -7,9 +7,9 @@ */ import {getHtmlTagDefinition} from '../../src/ml_parser/html_tags'; -import {TokenError, tokenize, TokenizeOptions, TokenizeResult} from '../../src/ml_parser/lexer'; +import {tokenize, TokenizeOptions, TokenizeResult} from '../../src/ml_parser/lexer'; import {Token, TokenType} from '../../src/ml_parser/tokens'; -import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_util'; +import {ParseError, ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_util'; describe('HtmlLexer', () => { describe('line/column numbers', () => { @@ -112,15 +112,11 @@ describe('HtmlLexer', () => { }); it('should report { - expect(tokenizeAndHumanizeErrors(' { - expect(tokenizeAndHumanizeErrors('