support template literals (#4601)
This commit is contained in:
82
test/compress/templates.js
Normal file
82
test/compress/templates.js
Normal file
@@ -0,0 +1,82 @@
|
||||
simple: {
|
||||
input: {
|
||||
console.log(`foo
|
||||
bar\nbaz`);
|
||||
}
|
||||
expect_exact: "console.log(`foo\n bar\\nbaz`);"
|
||||
expect_stdout: [
|
||||
"foo",
|
||||
" bar",
|
||||
"baz",
|
||||
]
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
placeholder: {
|
||||
input: {
|
||||
console.log(`foo ${ function(a, b) {
|
||||
return a * b;
|
||||
}(6, 7) }`);
|
||||
}
|
||||
expect_exact: "console.log(`foo ${function(a,b){return a*b}(6,7)}`);"
|
||||
expect_stdout: "foo 42"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
nested: {
|
||||
input: {
|
||||
console.log(`P${`A${"S"}`}S`);
|
||||
}
|
||||
expect_exact: 'console.log(`P${`A${"S"}`}S`);'
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
tagged: {
|
||||
input: {
|
||||
console.log(String.raw`foo\nbar`);
|
||||
}
|
||||
expect_exact: "console.log(String.raw`foo\\nbar`);"
|
||||
expect_stdout: "foo\\nbar"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
tagged_chain: {
|
||||
input: {
|
||||
function f(strings) {
|
||||
return strings.join("") || f;
|
||||
}
|
||||
console.log(f```${42}``pass`.toUpperCase());
|
||||
}
|
||||
expect_exact: 'function f(strings){return strings.join("")||f}console.log(f```${42}``pass`.toUpperCase());'
|
||||
expect_stdout: "PASS"
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
malformed_escape: {
|
||||
input: {
|
||||
(function(s) {
|
||||
s.forEach((c, i) => console.log(i, c, s.raw[i]));
|
||||
return () => console.log(arguments);
|
||||
})`\uFo${42}`();
|
||||
}
|
||||
expect_exact: "(function(s){s.forEach((c,i)=>console.log(i,c,s.raw[i]));return()=>console.log(arguments)})`\\uFo${42}`();"
|
||||
expect_stdout: true
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
evaluate: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
}
|
||||
input: {
|
||||
console.log(`foo ${ function(a, b) {
|
||||
return a * b;
|
||||
}(6, 7) }`);
|
||||
}
|
||||
expect: {
|
||||
console.log(`foo ${42}`);
|
||||
}
|
||||
expect_stdout: "foo 42"
|
||||
node_version: ">=4"
|
||||
}
|
||||
64
test/mocha/templates.js
Normal file
64
test/mocha/templates.js
Normal file
@@ -0,0 +1,64 @@
|
||||
var assert = require("assert");
|
||||
var run_code = require("../sandbox").run_code;
|
||||
var semver = require("semver");
|
||||
var UglifyJS = require("../node");
|
||||
|
||||
describe("Template literals", function() {
|
||||
it("Should reject invalid literal", function() {
|
||||
[
|
||||
"`foo\\`",
|
||||
"`foo${bar`",
|
||||
"`foo${bar}",
|
||||
].forEach(function(input) {
|
||||
assert.throws(function() {
|
||||
UglifyJS.parse(input);
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error
|
||||
&& e.message === "Unterminated template literal";
|
||||
}, input);
|
||||
});
|
||||
});
|
||||
it("Should reject invalid expression", function() {
|
||||
[
|
||||
"`foo${bar;}`",
|
||||
"`foo${42bar}`",
|
||||
].forEach(function(input) {
|
||||
assert.throws(function() {
|
||||
UglifyJS.parse(input);
|
||||
}, function(e) {
|
||||
return e instanceof UglifyJS.JS_Parse_Error;
|
||||
}, input);
|
||||
});
|
||||
});
|
||||
it("Should process line-break characters correctly", function() {
|
||||
[
|
||||
// native line breaks
|
||||
[ "`foo\nbar`", "`foo\nbar`" ],
|
||||
[ "`foo\rbar`", "`foo\rbar`" ],
|
||||
[ "`foo\r\nbar`", "`foo\nbar`" ],
|
||||
[ "`foo\r\n\rbar`", "`foo\n\rbar`" ],
|
||||
// escaped line breaks
|
||||
[ "`foo\\nbar`", "`foo\\nbar`" ],
|
||||
[ "`foo\\rbar`", "`foo\\rbar`" ],
|
||||
[ "`foo\r\\nbar`", "`foo\r\\nbar`" ],
|
||||
[ "`foo\\r\nbar`", "`foo\\r\nbar`" ],
|
||||
[ "`foo\\r\\nbar`", "`foo\\r\\nbar`" ],
|
||||
// continuation
|
||||
[ "`foo\\\nbar`", "`foo\\\nbar`" ],
|
||||
[ "`foo\\\rbar`", "`foo\\\rbar`" ],
|
||||
[ "`foo\\\r\nbar`", "`foo\\\nbar`" ],
|
||||
[ "`foo\\\r\n\rbar`", "`foo\\\n\rbar`" ],
|
||||
[ "`foo\\\\nbar`", "`foo\\\\nbar`" ],
|
||||
[ "`foo\\\\rbar`", "`foo\\\\rbar`" ],
|
||||
[ "`foo\\\\r\nbar`", "`foo\\\\r\nbar`" ],
|
||||
].forEach(function(test) {
|
||||
var input = "console.log(" + test[0] + ");";
|
||||
var result = UglifyJS.minify(input);
|
||||
if (result.error) throw result.error;
|
||||
var expected = "console.log(" + test[1] + ");";
|
||||
assert.strictEqual(result.code, expected, test[0]);
|
||||
if (semver.satisfies(process.version, "<4")) return;
|
||||
assert.strictEqual(run_code(result.code), run_code(input), test[0]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -146,6 +146,7 @@ var SUPPORT = function(matrix) {
|
||||
rest_object: "var {...a} = {};",
|
||||
spread: "[...[]];",
|
||||
spread_object: "({...0});",
|
||||
template: "``",
|
||||
trailing_comma: "function f(a,) {}",
|
||||
});
|
||||
|
||||
@@ -1038,6 +1039,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
case p++:
|
||||
return rng(2) + " === 1 ? a : b";
|
||||
case p++:
|
||||
if (SUPPORT.template && rng(20) == 0) return createTemplateLiteral(recurmax, stmtDepth, canThrow);
|
||||
case p++:
|
||||
return createValue();
|
||||
case p++:
|
||||
@@ -1298,6 +1300,28 @@ function createArrayLiteral(recurmax, stmtDepth, canThrow) {
|
||||
return "[" + arr.join(", ") + "]";
|
||||
}
|
||||
|
||||
function createTemplateLiteral(recurmax, stmtDepth, canThrow) {
|
||||
recurmax--;
|
||||
var s = [];
|
||||
addText();
|
||||
for (var i = rng(6); --i >= 0;) {
|
||||
s.push("${", createExpression(recurmax, COMMA_OK, stmtDepth, canThrow), "}");
|
||||
addText();
|
||||
}
|
||||
return (rng(10) ? "`" : "String.raw`") + s.join(rng(5) ? "" : "\n") + "`";
|
||||
|
||||
function addText() {
|
||||
while (rng(5) == 0) s.push([
|
||||
" ",
|
||||
"$",
|
||||
"}",
|
||||
"\\`",
|
||||
"\\\\",
|
||||
"tmpl",
|
||||
][rng(6)]);
|
||||
}
|
||||
}
|
||||
|
||||
var SAFE_KEYS = [
|
||||
"length",
|
||||
"foo",
|
||||
|
||||
Reference in New Issue
Block a user