Skip to content

Commit c9de5be

Browse files
authored
Merge pull request #4383 from GeoffreyBooth/escape-template-literals
Escape backticks and `${` within template literals; fixes #4380
2 parents 5588658 + d45d780 commit c9de5be

File tree

3 files changed

+50
-3
lines changed

3 files changed

+50
-3
lines changed

lib/coffee-script/nodes.js

Lines changed: 10 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/nodes.coffee

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2274,7 +2274,14 @@ exports.StringWithInterpolations = class StringWithInterpolations extends Parens
22742274
fragments.push @makeCode '`'
22752275
for element in elements
22762276
if element instanceof StringLiteral
2277-
fragments.push @makeCode element.value.slice(1, -1)
2277+
value = element.value[1...-1]
2278+
# Backticks and `${` inside template literals must be escaped.
2279+
value = value.replace /(\\*)(`|\$\{)/g, (match, backslashes, toBeEscaped) ->
2280+
if backslashes.length % 2 is 0
2281+
"#{backslashes}\\#{toBeEscaped}"
2282+
else
2283+
match
2284+
fragments.push @makeCode value
22782285
else
22792286
fragments.push @makeCode '${'
22802287
fragments.push element.compileToFragments(o, LEVEL_PAREN)...

test/tagged_template_literals.coffee

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,35 @@ test "tagged template literal with an interpolated string that itself contains a
137137
test "tagged template literal with an interpolated string that contains a tagged template literal", ->
138138
eq 'text: [inner tagged | literal] expressions: [text: [|] expressions: [template]]',
139139
func"inner tagged #{func"#{'template'}"} literal"
140+
141+
test "tagged template literal with backticks", ->
142+
eq 'text: [ES template literals look like this: `foo bar`] expressions: []',
143+
func"ES template literals look like this: `foo bar`"
144+
145+
test "tagged template literal with escaped backticks", ->
146+
eq 'text: [ES template literals look like this: \\`foo bar\\`] expressions: []',
147+
func"ES template literals look like this: \\`foo bar\\`"
148+
149+
test "tagged template literal with unnecessarily escaped backticks", ->
150+
eq 'text: [ES template literals look like this: `foo bar`] expressions: []',
151+
func"ES template literals look like this: \`foo bar\`"
152+
153+
test "tagged template literal with ES interpolation", ->
154+
eq 'text: [ES template literals also look like this: `3 + 5 = ${3+5}`] expressions: []',
155+
func"ES template literals also look like this: `3 + 5 = ${3+5}`"
156+
157+
test "tagged template literal with both ES and CoffeeScript interpolation", ->
158+
eq "text: [ES template literals also look like this: `3 + 5 = ${3+5}` which equals |] expressions: [8]",
159+
func"ES template literals also look like this: `3 + 5 = ${3+5}` which equals #{3+5}"
160+
161+
test "tagged template literal with escaped ES interpolation", ->
162+
eq 'text: [ES template literals also look like this: `3 + 5 = \\${3+5}`] expressions: []',
163+
func"ES template literals also look like this: `3 + 5 = \\${3+5}`"
164+
165+
test "tagged template literal with unnecessarily escaped ES interpolation", ->
166+
eq 'text: [ES template literals also look like this: `3 + 5 = ${3+5}`] expressions: []',
167+
func"ES template literals also look like this: `3 + 5 = \${3+5}`"
168+
169+
test "tagged template literal special escaping", ->
170+
eq 'text: [` ` \\` \\` \\\\` $ { ${ ${ \\${ \\${ \\\\${ | ` ${] expressions: [1]',
171+
func"` \` \\` \\\` \\\\` $ { ${ \${ \\${ \\\${ \\\\${ #{1} ` ${"

0 commit comments

Comments
 (0)