parent
436a29367c
commit
f766babf5e
104
lib/compress.js
104
lib/compress.js
|
|
@ -4922,11 +4922,9 @@ merge(Compressor.prototype, {
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
function decode(str) {
|
function decode(str) {
|
||||||
return str.replace(/\\(u\{[^}]*\}?|u[\s\S]{0,4}|x[\s\S]{0,2}|[0-9]+|[\s\S])/g, function(match, seq) {
|
str = decode_template(str);
|
||||||
var s = decode_escape_sequence(seq);
|
if (typeof str != "string") malformed = true;
|
||||||
if (typeof s != "string") malformed = true;
|
return str;
|
||||||
return s;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})(function(node, func) {
|
})(function(node, func) {
|
||||||
|
|
@ -11336,42 +11334,84 @@ merge(Compressor.prototype, {
|
||||||
&& tag.expression.name == "String";
|
&& tag.expression.name == "String";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function decode_template(str) {
|
||||||
|
var malformed = false;
|
||||||
|
str = str.replace(/\\(u\{[^}]*\}?|u[\s\S]{0,4}|x[\s\S]{0,2}|[0-9]+|[\s\S])/g, function(match, seq) {
|
||||||
|
var ch = decode_escape_sequence(seq);
|
||||||
|
if (typeof ch == "string") return ch;
|
||||||
|
malformed = true;
|
||||||
|
});
|
||||||
|
if (!malformed) return str;
|
||||||
|
}
|
||||||
|
|
||||||
OPT(AST_Template, function(self, compressor) {
|
OPT(AST_Template, function(self, compressor) {
|
||||||
if (!compressor.option("templates")) return self;
|
if (!compressor.option("templates")) return self;
|
||||||
var tag = self.tag;
|
var tag = self.tag;
|
||||||
if (!tag || is_raw_tag(compressor, tag)) {
|
if (!tag || is_raw_tag(compressor, tag)) {
|
||||||
var exprs = self.expressions.slice();
|
var exprs = [];
|
||||||
var strs = self.strings.slice();
|
var strs = [];
|
||||||
var CHANGED = false;
|
for (var i = 0, status; i < self.strings.length; i++) {
|
||||||
for (var i = exprs.length; --i >= 0;) {
|
var str = self.strings[i];
|
||||||
var node = exprs[i];
|
if (!tag) {
|
||||||
var ev = node.evaluate(compressor);
|
var trimmed = decode_template(str);
|
||||||
if (ev === node) continue;
|
if (trimmed) str = escape_literal(trimmed);
|
||||||
if (tag && /\r|\\|`/.test(ev)) continue;
|
}
|
||||||
ev = ("" + ev).replace(/\r|\\|`/g, function(s) {
|
if (i > 0) {
|
||||||
return "\\" + (s == "\r" ? "r" : s);
|
var node = self.expressions[i - 1];
|
||||||
});
|
var value = should_join(node);
|
||||||
if (ev.length > node.print_to_string().length + 3) continue;
|
if (value) {
|
||||||
var combined = strs[i] + ev + strs[i + 1];
|
var prev = strs[strs.length - 1];
|
||||||
if (typeof make_node(AST_Template, self, {
|
var joined = prev + value + str;
|
||||||
expressions: [],
|
var decoded;
|
||||||
strings: [ combined ],
|
if (tag || typeof (decoded = decode_template(joined)) == status) {
|
||||||
tag: tag,
|
strs[strs.length - 1] = decoded ? escape_literal(decoded) : joined;
|
||||||
}).evaluate(compressor) != typeof make_node(AST_Template, self, {
|
continue;
|
||||||
expressions: [ node ],
|
}
|
||||||
strings: strs.slice(i, i + 2),
|
}
|
||||||
tag: tag,
|
exprs.push(node);
|
||||||
}).evaluate(compressor)) continue;
|
}
|
||||||
exprs.splice(i, 1);
|
strs.push(str);
|
||||||
strs.splice(i, 2, combined);
|
if (!tag) status = typeof trimmed;
|
||||||
CHANGED = true;
|
}
|
||||||
|
if (!tag && strs.length > 1) {
|
||||||
|
if (strs[0] == "") return make_node(AST_Binary, self, {
|
||||||
|
operator: "+",
|
||||||
|
left: exprs[0],
|
||||||
|
right: make_node(AST_Template, self, {
|
||||||
|
expressions: exprs.slice(1),
|
||||||
|
strings: strs.slice(1),
|
||||||
|
tag: tag,
|
||||||
|
}).transform(compressor),
|
||||||
|
}).optimize(compressor);
|
||||||
|
if (strs[strs.length - 1] == "") return make_node(AST_Binary, self, {
|
||||||
|
operator: "+",
|
||||||
|
left: make_node(AST_Template, self, {
|
||||||
|
expressions: exprs.slice(0, -1),
|
||||||
|
strings: strs.slice(0, -1),
|
||||||
|
tag: tag,
|
||||||
|
}).transform(compressor),
|
||||||
|
right: exprs[exprs.length - 1],
|
||||||
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
if (CHANGED) {
|
|
||||||
self.expressions = exprs;
|
self.expressions = exprs;
|
||||||
self.strings = strs;
|
self.strings = strs;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return try_evaluate(compressor, self);
|
return try_evaluate(compressor, self);
|
||||||
|
|
||||||
|
function escape_literal(str) {
|
||||||
|
return str.replace(/\r|\\|`|\${/g, function(s) {
|
||||||
|
return "\\" + (s == "\r" ? "r" : s);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function should_join(node) {
|
||||||
|
var ev = node.evaluate(compressor);
|
||||||
|
if (ev === node) return;
|
||||||
|
if (tag && /\r|\\|`/.test(ev)) return;
|
||||||
|
ev = escape_literal("" + ev);
|
||||||
|
if (ev.length > node.print_to_string().length + "${}".length) return;
|
||||||
|
return ev;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function is_atomic(lhs, self) {
|
function is_atomic(lhs, self) {
|
||||||
|
|
|
||||||
|
|
@ -242,10 +242,10 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||||
read_template : with_eof_error("Unterminated template literal", function(strings) {
|
read_template : with_eof_error("Unterminated template literal", function(strings) {
|
||||||
var s = "";
|
var s = "";
|
||||||
for (;;) {
|
for (;;) {
|
||||||
var ch = next(true, true);
|
var ch = read();
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case "\\":
|
case "\\":
|
||||||
ch += next(true, true);
|
ch += read();
|
||||||
break;
|
break;
|
||||||
case "`":
|
case "`":
|
||||||
strings.push(s);
|
strings.push(s);
|
||||||
|
|
@ -260,6 +260,11 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||||
}
|
}
|
||||||
s += ch;
|
s += ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function read() {
|
||||||
|
var ch = next(true, true);
|
||||||
|
return ch == "\r" ? "\n" : ch;
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
var prev_was_dot = false;
|
var prev_was_dot = false;
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,105 @@ malformed_escape: {
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
booleans: {
|
||||||
|
options = {
|
||||||
|
booleans: true,
|
||||||
|
evaluate: true,
|
||||||
|
templates: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
console.log(`$${a}${a}` ? "PASS" : "FAIL");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a;
|
||||||
|
console.log("$" + a + a ? "PASS" : "FAIL");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
escape_placeholder_1: {
|
||||||
|
options = {
|
||||||
|
templates: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(`\${\n`);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(`\${
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"${",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
escape_placeholder_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
templates: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(`\n${"${"}\n`);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(`
|
||||||
|
\${
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"",
|
||||||
|
"${",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
escape_placeholder_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
templates: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(`\n$${"{"}\n`);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(`
|
||||||
|
\${
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"",
|
||||||
|
"${",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
escape_placeholder_4: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
templates: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(`\n${"$"}${"{"}\n`);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(`
|
||||||
|
\${
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"",
|
||||||
|
"${",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
evaluate: {
|
evaluate: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
|
@ -174,7 +273,7 @@ partial_evaluate: {
|
||||||
console.log(`${6 * 7} foo ${console ? `PA` + "SS" : `FA` + `IL`}`);
|
console.log(`${6 * 7} foo ${console ? `PA` + "SS" : `FA` + `IL`}`);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(`42 foo ${console ? "PASS" : "FAIL"}`);
|
console.log("42 foo " + (console ? "PASS" : "FAIL"));
|
||||||
}
|
}
|
||||||
expect_stdout: "42 foo PASS"
|
expect_stdout: "42 foo PASS"
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
|
|
@ -204,7 +303,7 @@ malformed_evaluate_2: {
|
||||||
console.log(`\u0${0}b${5}`);
|
console.log(`\u0${0}b${5}`);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(`\u0${0}b5`);
|
console.log(`\u00b` + 5);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
|
|
@ -357,13 +456,14 @@ issue_4604: {
|
||||||
issue_4606: {
|
issue_4606: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
strings: true,
|
||||||
templates: true,
|
templates: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
console.log(`${typeof A} ${"\r"} ${"\\"} ${"`"}`);
|
console.log(`${typeof A} ${"\r"} ${"\\"} ${"`"}`);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(`${typeof A} \r \\ \``);
|
console.log(typeof A + " \r \\ `");
|
||||||
}
|
}
|
||||||
expect_stdout: "undefined \r \\ `"
|
expect_stdout: "undefined \r \\ `"
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
|
|
@ -434,3 +534,154 @@ issue_4931: {
|
||||||
]
|
]
|
||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_5125_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
strings: true,
|
||||||
|
templates: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(`PASS ${typeof A}`);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS " + typeof A);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS undefined"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5125_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
strings: true,
|
||||||
|
templates: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(`PASS
|
||||||
|
${typeof A}`);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(`PASS
|
||||||
|
` + typeof A);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"PASS",
|
||||||
|
"undefined",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5125_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
strings: true,
|
||||||
|
templates: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(`PASS\n${typeof A}`);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(`PASS
|
||||||
|
` + typeof A);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"PASS",
|
||||||
|
"undefined",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5125_4: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
strings: true,
|
||||||
|
templates: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(`PASS
|
||||||
|
|
||||||
|
${typeof A}`);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(`PASS
|
||||||
|
|
||||||
|
` + typeof A);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"PASS",
|
||||||
|
"",
|
||||||
|
"undefined",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5125_5: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
strings: true,
|
||||||
|
templates: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(`PASS\n\n${typeof A}`);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(`PASS
|
||||||
|
|
||||||
|
` + typeof A);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"PASS",
|
||||||
|
"",
|
||||||
|
"undefined",
|
||||||
|
]
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5125_6: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
strings: true,
|
||||||
|
templates: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(`${typeof A} ${typeof B} PASS`);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(typeof A + ` ${typeof B} PASS`);
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined undefined PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5125_7: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
strings: true,
|
||||||
|
templates: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(`${typeof A} ${typeof B} ${typeof C} PASS`);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(typeof A + ` ${typeof B} ${typeof C} PASS`);
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined undefined undefined PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_5125_8: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
strings: true,
|
||||||
|
templates: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(`${typeof A}${typeof B}${typeof C} PASS`);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(typeof A + typeof B + typeof C + " PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "undefinedundefinedundefined PASS"
|
||||||
|
node_version: ">=4"
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,20 +34,20 @@ describe("Template literals", function() {
|
||||||
[
|
[
|
||||||
// native line breaks
|
// native line breaks
|
||||||
[ "`foo\nbar`", "`foo\nbar`" ],
|
[ "`foo\nbar`", "`foo\nbar`" ],
|
||||||
[ "`foo\rbar`", "`foo\rbar`" ],
|
[ "`foo\rbar`", "`foo\nbar`" ],
|
||||||
[ "`foo\r\nbar`", "`foo\nbar`" ],
|
[ "`foo\r\nbar`", "`foo\nbar`" ],
|
||||||
[ "`foo\r\n\rbar`", "`foo\n\rbar`" ],
|
[ "`foo\r\n\rbar`", "`foo\n\nbar`" ],
|
||||||
// escaped line breaks
|
// escaped line breaks
|
||||||
[ "`foo\\nbar`", "`foo\\nbar`" ],
|
[ "`foo\\nbar`", "`foo\\nbar`" ],
|
||||||
[ "`foo\\rbar`", "`foo\\rbar`" ],
|
[ "`foo\\rbar`", "`foo\\rbar`" ],
|
||||||
[ "`foo\r\\nbar`", "`foo\r\\nbar`" ],
|
[ "`foo\r\\nbar`", "`foo\n\\nbar`" ],
|
||||||
[ "`foo\\r\nbar`", "`foo\\r\nbar`" ],
|
[ "`foo\\r\nbar`", "`foo\\r\nbar`" ],
|
||||||
[ "`foo\\r\\nbar`", "`foo\\r\\nbar`" ],
|
[ "`foo\\r\\nbar`", "`foo\\r\\nbar`" ],
|
||||||
// continuation
|
// continuation
|
||||||
[ "`foo\\\nbar`", "`foo\\\nbar`" ],
|
[ "`foo\\\nbar`", "`foo\\\nbar`" ],
|
||||||
[ "`foo\\\rbar`", "`foo\\\rbar`" ],
|
[ "`foo\\\rbar`", "`foo\\\nbar`" ],
|
||||||
[ "`foo\\\r\nbar`", "`foo\\\nbar`" ],
|
[ "`foo\\\r\nbar`", "`foo\\\nbar`" ],
|
||||||
[ "`foo\\\r\n\rbar`", "`foo\\\n\rbar`" ],
|
[ "`foo\\\r\n\rbar`", "`foo\\\n\nbar`" ],
|
||||||
[ "`foo\\\\nbar`", "`foo\\\\nbar`" ],
|
[ "`foo\\\\nbar`", "`foo\\\\nbar`" ],
|
||||||
[ "`foo\\\\rbar`", "`foo\\\\rbar`" ],
|
[ "`foo\\\\rbar`", "`foo\\\\rbar`" ],
|
||||||
[ "`foo\\\\r\nbar`", "`foo\\\\r\nbar`" ],
|
[ "`foo\\\\r\nbar`", "`foo\\\\r\nbar`" ],
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user