From 05c861fad2bbecb242cf875d7b1141d66c617a7b Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 5 Jun 2025 14:15:00 -0700 Subject: [PATCH 01/13] Add copilot-setup-steps --- .github/workflows/copilot-setup-steps.yml | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/copilot-setup-steps.yml diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml new file mode 100644 index 0000000000..f0f769d4f1 --- /dev/null +++ b/.github/workflows/copilot-setup-steps.yml @@ -0,0 +1,26 @@ +name: 'Copilot Setup Steps' + +on: workflow_dispatch + +jobs: + # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot. + copilot-setup-steps: + runs-on: ubuntu-latest + + # Set the permissions to the lowest permissions possible needed for your steps. + # Copilot will be given its own token for its operations. + permissions: + # If you want to clone the repository as part of your setup steps, for example to install dependencies, you'll need the `contents: read` permission. If you don't clone the repository in your setup steps, Copilot will do this for you automatically after the steps complete. + contents: read + + # You can define any steps you want, and they will run before the agent starts. + # If you do not check out your code, Copilot will do this for you. + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable + - uses: ./.github/actions/setup-go + with: + cache-name: copilot-setup-steps + - run: npm ci + - run: npx hereby build From 885beee9c7b0e49b01198590b238dcb6dbf7dd0b Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 5 Jun 2025 14:51:06 -0700 Subject: [PATCH 02/13] Clone submodule --- .github/workflows/copilot-setup-steps.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index f0f769d4f1..485244d239 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -17,6 +17,8 @@ jobs: # If you do not check out your code, Copilot will do this for you. steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + submodules: true - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable - uses: ./.github/actions/setup-go From 85627c807aabbbe52002fe3be6d57d04a67cf760 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 5 Jun 2025 15:00:12 -0700 Subject: [PATCH 03/13] Fetch submodule history --- .github/workflows/copilot-setup-steps.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 485244d239..5a2c33f718 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -19,6 +19,8 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: submodules: true + - run: git fetch # default fetch depth for submodules is 2 + working-directory: _submodules/TypeScript - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable - uses: ./.github/actions/setup-go From 8888e79ac0fcff1d4e6e5d93ab413de4d895b155 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 5 Jun 2025 15:13:13 -0700 Subject: [PATCH 04/13] Fix unshallowing? --- .github/workflows/copilot-setup-steps.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 5a2c33f718..f3e0405000 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -19,8 +19,10 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: submodules: true - - run: git fetch # default fetch depth for submodules is 2 - working-directory: _submodules/TypeScript + - run: | + cd _submodules/TypeScript + git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" + git fetch --unshallow - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable - uses: ./.github/actions/setup-go From 6f23361b17521c87f37dbe634b00dbbdc5fe3a66 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 5 Jun 2025 15:23:30 -0700 Subject: [PATCH 05/13] Fetch only back as far as the PR could be --- .github/workflows/copilot-setup-steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index f3e0405000..c1ecb609f2 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -22,7 +22,7 @@ jobs: - run: | cd _submodules/TypeScript git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - git fetch --unshallow + git fetch --depth 170 # git rev-list --count 0693cc7...746c232 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable - uses: ./.github/actions/setup-go From 20e97c3df15ec731ec355ac8010455fa84f597aa Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 5 Jun 2025 16:20:25 -0700 Subject: [PATCH 06/13] Try to shallow fetch better --- .github/workflows/copilot-setup-steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index c1ecb609f2..892cacccf2 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -22,7 +22,7 @@ jobs: - run: | cd _submodules/TypeScript git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - git fetch --depth 170 # git rev-list --count 0693cc7...746c232 + git fetch --depth 170 HEAD # git rev-list --count 0693cc7...746c232 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable - uses: ./.github/actions/setup-go From a897d9752588f116f93f90b61df3aa7ec061cc10 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 5 Jun 2025 16:31:17 -0700 Subject: [PATCH 07/13] Fix git fetch syntax --- .github/workflows/copilot-setup-steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 892cacccf2..994a2ed20f 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -22,7 +22,7 @@ jobs: - run: | cd _submodules/TypeScript git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - git fetch --depth 170 HEAD # git rev-list --count 0693cc7...746c232 + git fetch origin --depth 170 HEAD # git rev-list --count 0693cc7...746c232 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable - uses: ./.github/actions/setup-go From dcf4c574bd7249618608ed22a925f3bd9cb5c6a4 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 5 Jun 2025 17:01:44 -0700 Subject: [PATCH 08/13] Try one more fetch thing --- .github/workflows/copilot-setup-steps.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 994a2ed20f..9db251a984 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -22,7 +22,8 @@ jobs: - run: | cd _submodules/TypeScript git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - git fetch origin --depth 170 HEAD # git rev-list --count 0693cc7...746c232 + git fetch origin 0693cc7 + git fetch origin --shallow-exclude=0693cc7 746c232 - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable - uses: ./.github/actions/setup-go From 0747ab648c25991fb716cd42ee2e84ce0809f953 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 5 Jun 2025 17:06:33 -0700 Subject: [PATCH 09/13] Give up --- .github/workflows/copilot-setup-steps.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 9db251a984..10c63fc184 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -22,8 +22,7 @@ jobs: - run: | cd _submodules/TypeScript git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - git fetch origin 0693cc7 - git fetch origin --shallow-exclude=0693cc7 746c232 + git fetch origin --unshallow - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable - uses: ./.github/actions/setup-go From 05e5518a6ee09f3839e7aff38e02a7f8df56e65d Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Fri, 6 Jun 2025 08:35:24 -0700 Subject: [PATCH 10/13] Add Playwright MCP server --- .github/workflows/copilot-setup-steps.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 10c63fc184..d31fb6f46f 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -22,11 +22,12 @@ jobs: - run: | cd _submodules/TypeScript git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - git fetch origin --unshallow + git fetch --unshallow - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable - uses: ./.github/actions/setup-go with: cache-name: copilot-setup-steps + - run: npm install -g @playwright/mcp@0.0.28 - run: npm ci - run: npx hereby build From 887a2b495a7ec8466eeb756aaa3326acc3ed6ee7 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Fri, 6 Jun 2025 08:50:57 -0700 Subject: [PATCH 11/13] Remove submodule unshallowing --- .github/workflows/copilot-setup-steps.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index d31fb6f46f..f67a01892e 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -19,10 +19,6 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: submodules: true - - run: | - cd _submodules/TypeScript - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - git fetch --unshallow - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - uses: dtolnay/rust-toolchain@fcf085fcb4b4b8f63f96906cd713eb52181b5ea4 # stable - uses: ./.github/actions/setup-go From a31c03a6da537a624af83e555675a152cefbdf1f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Jun 2025 15:59:39 +0000 Subject: [PATCH 12/13] Initial plan for issue From da3175cdf328eb05083f0372486a54cebcfc09f5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Jun 2025 16:18:50 +0000 Subject: [PATCH 13/13] Port TypeScript PR #60303: Fix template string escaping for control characters Co-authored-by: andrewbranch <3277153+andrewbranch@users.noreply.github.com> --- internal/printer/utilities.go | 2 +- internal/printer/utilities_test.go | 28 ++++++++++++++++++- ...plateStringControlCharacterEscapes03.types | 2 +- ...StringControlCharacterEscapes03.types.diff | 8 ------ ...eStringControlCharacterEscapes03_ES6.types | 2 +- ...ngControlCharacterEscapes03_ES6.types.diff | 8 ------ 6 files changed, 30 insertions(+), 20 deletions(-) delete mode 100644 testdata/baselines/reference/submodule/conformance/templateStringControlCharacterEscapes03.types.diff delete mode 100644 testdata/baselines/reference/submodule/conformance/templateStringControlCharacterEscapes03_ES6.types.diff diff --git a/internal/printer/utilities.go b/internal/printer/utilities.go index 6561a5a95a..9eac7f1b89 100644 --- a/internal/printer/utilities.go +++ b/internal/printer/utilities.go @@ -103,7 +103,7 @@ func escapeStringWorker(s string, quoteChar QuoteChar, flags getLiteralTextFlags escape = true } default: - if ch < '\u001f' || flags&getLiteralTextFlagsNeverAsciiEscape == 0 && ch > '\u007f' { + if ch <= '\u001f' || flags&getLiteralTextFlagsNeverAsciiEscape == 0 && ch > '\u007f' { escape = true } } diff --git a/internal/printer/utilities_test.go b/internal/printer/utilities_test.go index cbe034f22d..fcd9ab3412 100644 --- a/internal/printer/utilities_test.go +++ b/internal/printer/utilities_test.go @@ -25,6 +25,14 @@ func TestEscapeString(t *testing.T) { {s: "ab'c", quoteChar: QuoteCharSingleQuote, expected: `ab\'c`}, {s: "ab\"c", quoteChar: QuoteCharSingleQuote, expected: `ab"c`}, {s: "ab`c", quoteChar: QuoteCharBacktick, expected: "ab\\`c"}, + // Test case for issue #59150: newlines in template strings should NOT be escaped + {s: "\n", quoteChar: QuoteCharBacktick, expected: "\n"}, + {s: "ab\nc", quoteChar: QuoteCharBacktick, expected: "ab\nc"}, + // Test other control characters that SHOULD be escaped in template strings + {s: "\u0001", quoteChar: QuoteCharBacktick, expected: "\\u0001"}, // control character should be escaped + {s: "\u0009", quoteChar: QuoteCharBacktick, expected: "\\t"}, // tab should be escaped + {s: "\u000b", quoteChar: QuoteCharBacktick, expected: "\\v"}, // vertical tab should be escaped + {s: "\u001f", quoteChar: QuoteCharBacktick, expected: "\\u001F"}, // unit separator should be escaped } for i, rec := range data { t.Run(fmt.Sprintf("[%d] escapeString(%q, %v)", i, rec.s, rec.quoteChar), func(t *testing.T) { @@ -51,7 +59,9 @@ func TestEscapeNonAsciiString(t *testing.T) { {s: "ab'c", quoteChar: QuoteCharSingleQuote, expected: `ab\'c`}, {s: "ab\"c", quoteChar: QuoteCharSingleQuote, expected: `ab"c`}, {s: "ab`c", quoteChar: QuoteCharBacktick, expected: "ab\\`c"}, - {s: "ab\u008fc", quoteChar: QuoteCharDoubleQuote, expected: `ab\u008Fc`}, + // Test case for issue #59150: newlines in template strings should NOT be escaped + {s: "\n", quoteChar: QuoteCharBacktick, expected: "\n"}, + {s: "ab\nc", quoteChar: QuoteCharBacktick, expected: "ab\nc"}, {s: "𝟘𝟙", quoteChar: QuoteCharDoubleQuote, expected: `\uD835\uDFD8\uD835\uDFD9`}, } for i, rec := range data { @@ -150,3 +160,19 @@ func TestIsRecognizedTripleSlashComment(t *testing.T) { }) } } + +func TestSyntheticTemplateLiteral(t *testing.T) { + t.Parallel() + + // Test the specific issue: LF character should not be escaped in template strings + // This mimics the TypeScript test case: ts.factory.createNoSubstitutionTemplateLiteral("\n") + + result := EscapeString("\n", QuoteCharBacktick) + expected := "\n" // LF should NOT be escaped for backticks + assert.Equal(t, result, expected) + + // Also test that other control characters are still escaped + result2 := EscapeString("\u0001", QuoteCharBacktick) + expected2 := "\\u0001" // Other control characters should still be escaped + assert.Equal(t, result2, expected2) +} diff --git a/testdata/baselines/reference/submodule/conformance/templateStringControlCharacterEscapes03.types b/testdata/baselines/reference/submodule/conformance/templateStringControlCharacterEscapes03.types index cb40439a14..aea47c3578 100644 --- a/testdata/baselines/reference/submodule/conformance/templateStringControlCharacterEscapes03.types +++ b/testdata/baselines/reference/submodule/conformance/templateStringControlCharacterEscapes03.types @@ -3,5 +3,5 @@ === templateStringControlCharacterEscapes03.ts === var x = `\x1F\u001f 1F 1f`; >x : string ->`\x1F\u001f 1F 1f` : " 1F 1f" +>`\x1F\u001f 1F 1f` : "\u001F\u001F 1F 1f" diff --git a/testdata/baselines/reference/submodule/conformance/templateStringControlCharacterEscapes03.types.diff b/testdata/baselines/reference/submodule/conformance/templateStringControlCharacterEscapes03.types.diff deleted file mode 100644 index 5fcd94380c..0000000000 --- a/testdata/baselines/reference/submodule/conformance/templateStringControlCharacterEscapes03.types.diff +++ /dev/null @@ -1,8 +0,0 @@ ---- old.templateStringControlCharacterEscapes03.types -+++ new.templateStringControlCharacterEscapes03.types -@@= skipped -2, +2 lines =@@ - === templateStringControlCharacterEscapes03.ts === - var x = `\x1F\u001f 1F 1f`; - >x : string -->`\x1F\u001f 1F 1f` : "\u001F\u001F 1F 1f" -+>`\x1F\u001f 1F 1f` : " 1F 1f" diff --git a/testdata/baselines/reference/submodule/conformance/templateStringControlCharacterEscapes03_ES6.types b/testdata/baselines/reference/submodule/conformance/templateStringControlCharacterEscapes03_ES6.types index f1e600e06b..42501f67b6 100644 --- a/testdata/baselines/reference/submodule/conformance/templateStringControlCharacterEscapes03_ES6.types +++ b/testdata/baselines/reference/submodule/conformance/templateStringControlCharacterEscapes03_ES6.types @@ -3,5 +3,5 @@ === templateStringControlCharacterEscapes03_ES6.ts === var x = `\x1F\u001f 1F 1f`; >x : string ->`\x1F\u001f 1F 1f` : " 1F 1f" +>`\x1F\u001f 1F 1f` : "\u001F\u001F 1F 1f" diff --git a/testdata/baselines/reference/submodule/conformance/templateStringControlCharacterEscapes03_ES6.types.diff b/testdata/baselines/reference/submodule/conformance/templateStringControlCharacterEscapes03_ES6.types.diff deleted file mode 100644 index 30a3c9a4e6..0000000000 --- a/testdata/baselines/reference/submodule/conformance/templateStringControlCharacterEscapes03_ES6.types.diff +++ /dev/null @@ -1,8 +0,0 @@ ---- old.templateStringControlCharacterEscapes03_ES6.types -+++ new.templateStringControlCharacterEscapes03_ES6.types -@@= skipped -2, +2 lines =@@ - === templateStringControlCharacterEscapes03_ES6.ts === - var x = `\x1F\u001f 1F 1f`; - >x : string -->`\x1F\u001f 1F 1f` : "\u001F\u001F 1F 1f" -+>`\x1F\u001f 1F 1f` : " 1F 1f"