From e667a6f04adeedf7848a788020a1702bad872935 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Tue, 11 Mar 2025 22:37:11 +0100 Subject: [PATCH] fix(compiler): incorrect spans for template literals (#60323) Fixes that we were producing zero-length spans for template literals and template literal elements. Fixes #60320. Fixes #60319. PR Close #60323 --- .../compiler/src/expression_parser/parser.ts | 12 +++--- .../test/expression_parser/parser_spec.ts | 37 ++++++++++++++----- .../bundle.golden_symbols.json | 1 - .../animations/bundle.golden_symbols.json | 1 - .../cyclic_import/bundle.golden_symbols.json | 1 - .../forms_reactive/bundle.golden_symbols.json | 1 - .../bundle.golden_symbols.json | 1 - .../hydration/bundle.golden_symbols.json | 1 - .../router/bundle.golden_symbols.json | 1 - .../bundle.golden_symbols.json | 1 - .../bundling/todo/bundle.golden_symbols.json | 1 - 11 files changed, 34 insertions(+), 24 deletions(-) diff --git a/packages/compiler/src/expression_parser/parser.ts b/packages/compiler/src/expression_parser/parser.ts index 0661067e30f5..3b1a0d4441aa 100644 --- a/packages/compiler/src/expression_parser/parser.ts +++ b/packages/compiler/src/expression_parser/parser.ts @@ -1040,7 +1040,7 @@ class _ParseAST { this.advance(); return new LiteralPrimitive(this.span(start), this.sourceSpan(start), value); } else if (this.next.isTemplateLiteralEnd()) { - return this.parseNoInterpolationTemplateLiteral(start); + return this.parseNoInterpolationTemplateLiteral(); } else if (this.next.isTemplateLiteralPart()) { return this.parseTemplateLiteral(); } else if (this.next.isString() && this.next.kind === StringTokenKind.Plain) { @@ -1406,8 +1406,9 @@ class _ParseAST { return new VariableBinding(sourceSpan, key, value); } - private parseNoInterpolationTemplateLiteral(start: number): AST { + private parseNoInterpolationTemplateLiteral(): AST { const text = this.next.strValue; + const start = this.inputIndex; this.advance(); const span = this.span(start); const sourceSpan = this.sourceSpan(start); @@ -1428,14 +1429,15 @@ class _ParseAST { const token = this.next; if (token.isTemplateLiteralPart() || token.isTemplateLiteralEnd()) { + const partStart = this.inputIndex; + this.advance(); elements.push( new TemplateLiteralElement( - this.span(this.inputIndex), - this.sourceSpan(this.inputIndex), + this.span(partStart), + this.sourceSpan(partStart), token.strValue, ), ); - this.advance(); if (token.isTemplateLiteralEnd()) { break; } diff --git a/packages/compiler/test/expression_parser/parser_spec.ts b/packages/compiler/test/expression_parser/parser_spec.ts index 32f6e6b11314..8ddc2df278fc 100644 --- a/packages/compiler/test/expression_parser/parser_spec.ts +++ b/packages/compiler/test/expression_parser/parser_spec.ts @@ -18,6 +18,7 @@ import { PropertyRead, TemplateBinding, VariableBinding, + TemplateLiteral, } from '@angular/compiler/src/expression_parser/ast'; import {Lexer} from '@angular/compiler/src/expression_parser/lexer'; import {Parser, SplitInterpolation} from '@angular/compiler/src/expression_parser/parser'; @@ -496,18 +497,34 @@ describe('parser', () => { expect(unparseWithSpan(ast)).toContain(['a.b = c', '[nameSpan] b']); }); - it('should record template literal space', () => { + it('should record spans for untagged template literals with no interpolations', () => { + const ast = parseAction('`hello world`'); + const unparsed = unparseWithSpan(ast); + expect(unparsed).toEqual([ + ['`hello world`', '`hello world`'], + ['hello world', '`hello world`'], + ]); + }); + + it('should record spans for untagged template literals with interpolations', () => { const ast = parseAction('`before ${one} - ${two} - ${three} after`'); const unparsed = unparseWithSpan(ast); - expect(unparsed).toContain(['before ', '']); - expect(unparsed).toContain(['one', 'one']); - expect(unparsed).toContain(['one', '[nameSpan] one']); - expect(unparsed).toContain([' - ', '']); - expect(unparsed).toContain(['two', 'two']); - expect(unparsed).toContain(['two', '[nameSpan] two']); - expect(unparsed).toContain(['three', 'three']); - expect(unparsed).toContain(['three', '[nameSpan] three']); - expect(unparsed).toContain([' after', '']); + expect(unparsed).toEqual([ + ['`before ${one} - ${two} - ${three} after`', '`before ${one} - ${two} - ${three} after`'], + ['before ', '`before '], + ['one', 'one'], + ['one', '[nameSpan] one'], + ['', ''], // Implicit receiver + [' - ', ' - '], + ['two', 'two'], + ['two', '[nameSpan] two'], + ['', ''], // Implicit receiver + [' - ', ' - '], + ['three', 'three'], + ['three', '[nameSpan] three'], + ['', ''], // Implicit receiver + [' after', ' after`'], + ]); }); it('should include parenthesis in spans', () => { diff --git a/packages/core/test/bundling/animations-standalone/bundle.golden_symbols.json b/packages/core/test/bundling/animations-standalone/bundle.golden_symbols.json index 02ce6a795e90..6e58fcbad248 100644 --- a/packages/core/test/bundling/animations-standalone/bundle.golden_symbols.json +++ b/packages/core/test/bundling/animations-standalone/bundle.golden_symbols.json @@ -306,7 +306,6 @@ "getCurrentTNodePlaceholderOk", "getDOM", "getDeclarationTNode", - "getDirectiveDef", "getFactoryDef", "getFirstLContainer", "getInitialLViewFlagsFromDef", diff --git a/packages/core/test/bundling/animations/bundle.golden_symbols.json b/packages/core/test/bundling/animations/bundle.golden_symbols.json index 1940f1486843..17d75b16c054 100644 --- a/packages/core/test/bundling/animations/bundle.golden_symbols.json +++ b/packages/core/test/bundling/animations/bundle.golden_symbols.json @@ -327,7 +327,6 @@ "getCurrentTNodePlaceholderOk", "getDOM", "getDeclarationTNode", - "getDirectiveDef", "getFactoryDef", "getFirstLContainer", "getInitialLViewFlagsFromDef", diff --git a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json index 0c8a673496ee..a06b9dabf100 100644 --- a/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json +++ b/packages/core/test/bundling/cyclic_import/bundle.golden_symbols.json @@ -255,7 +255,6 @@ "getCurrentTNodePlaceholderOk", "getDOM", "getDeclarationTNode", - "getDirectiveDef", "getFactoryDef", "getFirstLContainer", "getInitialLViewFlagsFromDef", diff --git a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json index 83a7b4702093..747da126053a 100644 --- a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json @@ -369,7 +369,6 @@ "getCurrentTNodePlaceholderOk", "getDOM", "getDeclarationTNode", - "getDirectiveDef", "getFactoryDef", "getFactoryOf", "getFirstLContainer", diff --git a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json index 720e561db190..271a426c83df 100644 --- a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json @@ -356,7 +356,6 @@ "getCurrentTNodePlaceholderOk", "getDOM", "getDeclarationTNode", - "getDirectiveDef", "getFactoryDef", "getFactoryOf", "getFirstLContainer", diff --git a/packages/core/test/bundling/hydration/bundle.golden_symbols.json b/packages/core/test/bundling/hydration/bundle.golden_symbols.json index f67581823e04..a3e90a72b681 100644 --- a/packages/core/test/bundling/hydration/bundle.golden_symbols.json +++ b/packages/core/test/bundling/hydration/bundle.golden_symbols.json @@ -262,7 +262,6 @@ "getCurrentTNodePlaceholderOk", "getDOM", "getDeclarationTNode", - "getDirectiveDef", "getDocument", "getFactoryDef", "getFilteredHeaders", diff --git a/packages/core/test/bundling/router/bundle.golden_symbols.json b/packages/core/test/bundling/router/bundle.golden_symbols.json index a6b365f9a7ed..83277b2ecbc1 100644 --- a/packages/core/test/bundling/router/bundle.golden_symbols.json +++ b/packages/core/test/bundling/router/bundle.golden_symbols.json @@ -440,7 +440,6 @@ "getData", "getDataKeys", "getDeclarationTNode", - "getDirectiveDef", "getFactoryDef", "getFactoryOf", "getFirstLContainer", diff --git a/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json b/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json index 1d46cc56daef..94e49bdf222f 100644 --- a/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json +++ b/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json @@ -229,7 +229,6 @@ "getCurrentTNodePlaceholderOk", "getDOM", "getDeclarationTNode", - "getDirectiveDef", "getFactoryDef", "getFirstLContainer", "getInitialLViewFlagsFromDef", diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index 9a6b8bbc189f..a4cce9ce7f64 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -300,7 +300,6 @@ "getCurrentTNodePlaceholderOk", "getDOM", "getDeclarationTNode", - "getDirectiveDef", "getFactoryDef", "getFirstLContainer", "getFirstNativeNode",