From 7dbd47fb3015117c420f984181bfcb48e533525a Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Tue, 10 Oct 2023 14:26:05 +0200 Subject: [PATCH] fix(compiler): allow newlines in track and let expressions (#52137) Fixes that the template parser didn't allow for newlines in the `track` and `let` expressions of `@for` blocks. Fixes #52132. PR Close #52137 --- .../compiler/src/render3/r3_control_flow.ts | 4 +-- .../render3/r3_template_transform_spec.ts | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/packages/compiler/src/render3/r3_control_flow.ts b/packages/compiler/src/render3/r3_control_flow.ts index 1e01ab5b4dea9..199fa3e329220 100644 --- a/packages/compiler/src/render3/r3_control_flow.ts +++ b/packages/compiler/src/render3/r3_control_flow.ts @@ -17,7 +17,7 @@ import * as t from './r3_ast'; const FOR_LOOP_EXPRESSION_PATTERN = /^\s*([0-9A-Za-z_$]*)\s+of\s+(.*)/; /** Pattern for the tracking expression in a for loop block. */ -const FOR_LOOP_TRACK_PATTERN = /^track\s+(.*)/; +const FOR_LOOP_TRACK_PATTERN = /^track\s+([\S\s]*)/; /** Pattern for the `as` expression in a conditional block. */ const CONDITIONAL_ALIAS_PATTERN = /^as\s+(.*)/; @@ -26,7 +26,7 @@ const CONDITIONAL_ALIAS_PATTERN = /^as\s+(.*)/; const ELSE_IF_PATTERN = /^else[^\S\r\n]+if/; /** Pattern used to identify a `let` parameter. */ -const FOR_LOOP_LET_PATTERN = /^let\s+(.*)/; +const FOR_LOOP_LET_PATTERN = /^let\s+([\S\s]*)/; /** Names of variables that are allowed to be used in the `let` expression of a `for` loop. */ const ALLOWED_FOR_LOOP_LET_VARIABLES = diff --git a/packages/compiler/test/render3/r3_template_transform_spec.ts b/packages/compiler/test/render3/r3_template_transform_spec.ts index af64263ec9e02..1e7cef62facf0 100644 --- a/packages/compiler/test/render3/r3_template_transform_spec.ts +++ b/packages/compiler/test/render3/r3_template_transform_spec.ts @@ -1516,6 +1516,24 @@ describe('R3 template transform', () => { ]); }); + it('should parse a for loop block with newlines in its let parameters', () => { + expectFromHtml(` + @for (item of items.foo.bar; track item.id; let\nidx = $index,\nf = $first,\nc = $count,\nl = $last,\nev = $even,\nod = $odd) { + {{ item }} + } + `).toEqual([ + ['ForLoopBlock', 'items.foo.bar', 'item.id'], + ['Variable', 'item', '$implicit'], + ['Variable', 'idx', '$index'], + ['Variable', 'f', '$first'], + ['Variable', 'c', '$count'], + ['Variable', 'l', '$last'], + ['Variable', 'ev', '$even'], + ['Variable', 'od', '$odd'], + ['BoundText', ' {{ item }} '], + ]); + }); + it('should parse nested for loop blocks', () => { expectFromHtml(` @for (item of items.foo.bar; track item.id) { @@ -1553,6 +1571,21 @@ describe('R3 template transform', () => { ]); }); + it('should parse a for loop block with newlines in its expression', () => { + const expectedResult = [ + ['ForLoopBlock', 'items.foo.bar', 'item.id + foo'], + ['Variable', 'item', '$implicit'], + ['BoundText', '{{ item }}'], + ]; + + expectFromHtml(` + @for (item\nof\nitems.foo.bar; track item.id +\nfoo) {{{ item }}} + `).toEqual(expectedResult); + expectFromHtml(` + @for ((item\nof\nitems.foo.bar); track (item.id +\nfoo)) {{{ item }}} + `).toEqual(expectedResult); + }); + describe('validations', () => { it('should report if for loop does not have an expression', () => { expect(() => parse(`@for {hello}`)).toThrowError(/@for loop does not have an expression/);