From 972031752cb5986597293deec1c8e1dd90f2429c Mon Sep 17 00:00:00 2001 From: Vladimir Vagaytsev <10628074+vvagaytsev@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:00:02 +0100 Subject: [PATCH] fix(template): fix template string escaping A follow-up for #6685. Replays #6408 on top of #6685. Co-authored-by: Steffen Neubauer --- core/src/template-string/parser.pegjs | 2 +- core/test/unit/src/template-string.ts | 54 +++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/core/src/template-string/parser.pegjs b/core/src/template-string/parser.pegjs index 2cee60fccc..e57d248f11 100644 --- a/core/src/template-string/parser.pegjs +++ b/core/src/template-string/parser.pegjs @@ -208,7 +208,7 @@ TemplateStrings } FormatString - = EscapeStart SourceCharacter* FormatEndWithOptional { + = EscapeStart (!FormatEndWithOptional SourceCharacter)* FormatEndWithOptional { if (options.unescape) { return new ast.LiteralExpression(location(), text().slice(1)) } else { diff --git a/core/test/unit/src/template-string.ts b/core/test/unit/src/template-string.ts index 72dd746422..d9859d915c 100644 --- a/core/test/unit/src/template-string.ts +++ b/core/test/unit/src/template-string.ts @@ -128,6 +128,60 @@ describe("resolveTemplateString", () => { expect(res).to.equal("${bar}") }) + it("should resolve other template variables after escaped one with unescape=false", () => { + const res = resolveTemplateString({ + string: "foo $${} ${bar}", + context: new GenericContext({ bar: "bar" }), + contextOpts: { unescape: false }, + }) + expect(res).to.equal("foo $${} bar") + }) + + it("should resolve other template variables after escaped one with unescape=true", () => { + const res = resolveTemplateString({ + string: "foo $${} ${bar}", + context: new GenericContext({ bar: "bar" }), + contextOpts: { unescape: true }, + }) + expect(res).to.equal("foo ${} bar") + }) + + it("should not unescape inner template variables with unescape=false", () => { + const res = resolveTemplateString({ + string: 'foo ${"$${}"} ${bar}', + context: new GenericContext({ bar: "bar" }), + contextOpts: { unescape: false }, + }) + expect(res).to.equal("foo $${} bar") + }) + + it("should unescape inner template variables with unescape=true", () => { + const res = resolveTemplateString({ + string: 'foo ${"$${}"} ${bar}', + context: new GenericContext({ bar: "bar" }), + contextOpts: { unescape: true }, + }) + expect(res).to.equal("foo ${} bar") + }) + + it("should not unescape outer template variables with unescape=false", () => { + const res = resolveTemplateString({ + string: 'foo $${"${}"} ${bar}', + context: new GenericContext({ bar: "bar" }), + contextOpts: { unescape: false }, + }) + expect(res).to.equal('foo $${"${}"} bar') + }) + + it("should unescape outer template variables with unescape=true", () => { + const res = resolveTemplateString({ + string: 'foo $${"${}"} ${bar}', + context: new GenericContext({ bar: "bar" }), + contextOpts: { unescape: true }, + }) + expect(res).to.equal('foo ${"${}"} bar') + }) + it("should unescape a template string with a double $$ prefix if allowPartial=false", () => { const res = resolveTemplateString({ string: "$${bar}",