From 3200259430b1d3be178f5943d9ba0f0b59307d34 Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Mon, 14 Nov 2016 17:33:20 -0800 Subject: [PATCH] Block inline JavaScript can end with an escaped backtick character --- lib/coffee-script/lexer.js | 18 ++++++------------ src/lexer.coffee | 15 +++++---------- test/javascript_literals.coffee | 7 +++++++ 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/lib/coffee-script/lexer.js b/lib/coffee-script/lexer.js index c3535458a2..831f8cf161 100644 --- a/lib/coffee-script/lexer.js +++ b/lib/coffee-script/lexer.js @@ -336,21 +336,15 @@ }; Lexer.prototype.jsToken = function() { - var here, js, length, match, script; + var js, match, script; if (!(this.chunk.charAt(0) === '`' && (match = JSTOKEN.exec(this.chunk)))) { return 0; } - js = match[0], here = match[1]; - if (here != null) { - script = here; - length = here.length + 6; - } else { - script = js.slice(1, -1); - length = js.length; - } + js = match[0]; + script = js.slice(0, 3) === '```' ? js.slice(3, -3) : js.slice(1, -1); script = script.replace(/\\`/g, '`'); - this.token('JS', script, 0, length); - return length; + this.token('JS', script, 0, js.length); + return js.length; }; Lexer.prototype.regexToken = function() { @@ -1018,7 +1012,7 @@ MULTI_DENT = /^(?:\n[^\n\S]*)+/; - JSTOKEN = /^```([\s\S]*?)```|^`[^\\`]*(?:\\.[^\\`]*)*`/; + JSTOKEN = /^```([\s\S]*?)(?:\\`(```)|```)|^`[^\\`]*(?:\\.[^\\`]*)*`/; STRING_START = /^(?:'''|"""|'|")/; diff --git a/src/lexer.coffee b/src/lexer.coffee index 4c17c1b3ed..d55bcc4ab4 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -293,16 +293,11 @@ exports.Lexer = class Lexer # Matches JavaScript interpolated directly into the source via backticks. jsToken: -> return 0 unless @chunk.charAt(0) is '`' and match = JSTOKEN.exec @chunk - [js, here] = match - if here? - script = here - length = here.length + 6 # 6 is the length of the six ` characters - else - script = js[1...-1] - length = js.length + [js] = match + script = if js[0..2] is '```' then js[3...-3] else js[1...-1] script = script.replace /\\`/g, '`' # Convert escaped backticks to backticks - @token 'JS', script, 0, length - length + @token 'JS', script, 0, js.length + js.length # Matches regular expression literals, as well as multiline extended ones. # Lexing regular expressions is difficult to distinguish from division, so we @@ -908,7 +903,7 @@ CODE = /^[-=]>/ MULTI_DENT = /^(?:\n[^\n\S]*)+/ -JSTOKEN = /^```([\s\S]*?)```|^`[^\\`]*(?:\\.[^\\`]*)*`/ +JSTOKEN = /^```([\s\S]*?)(?:\\`(```)|```)|^`[^\\`]*(?:\\.[^\\`]*)*`/ # String-matching-regexes. STRING_START = /^(?:'''|"""|'|")/ diff --git a/test/javascript_literals.coffee b/test/javascript_literals.coffee index 154443bf43..c6a95ce86e 100644 --- a/test/javascript_literals.coffee +++ b/test/javascript_literals.coffee @@ -38,3 +38,10 @@ test "block inline JavaScript containing backticks", -> eq a + c, 45 eq b, 'foo bar' eq d, 'foo`bar`' + +test "block JavaScript can end with an escaped backtick character", -> + ```var a = \`hello\```` + ``` + var b = \`world${'!'}\```` + eq a, 'hello' + eq b, 'world!'