Skip to content

Commit

Permalink
enhance templates (#5131)
Browse files Browse the repository at this point in the history
closes #5125
  • Loading branch information
alexlamsl committed Sep 23, 2021
1 parent 436a293 commit f766bab
Show file tree
Hide file tree
Showing 4 changed files with 339 additions and 43 deletions.
106 changes: 73 additions & 33 deletions lib/compress.js
Original file line number Diff line number Diff line change
Expand Up @@ -4922,11 +4922,9 @@ merge(Compressor.prototype, {
return this;

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) {
var s = decode_escape_sequence(seq);
if (typeof s != "string") malformed = true;
return s;
});
str = decode_template(str);
if (typeof str != "string") malformed = true;
return str;
}
});
})(function(node, func) {
Expand Down Expand Up @@ -11336,42 +11334,84 @@ merge(Compressor.prototype, {
&& 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) {
if (!compressor.option("templates")) return self;
var tag = self.tag;
if (!tag || is_raw_tag(compressor, tag)) {
var exprs = self.expressions.slice();
var strs = self.strings.slice();
var CHANGED = false;
for (var i = exprs.length; --i >= 0;) {
var node = exprs[i];
var ev = node.evaluate(compressor);
if (ev === node) continue;
if (tag && /\r|\\|`/.test(ev)) continue;
ev = ("" + ev).replace(/\r|\\|`/g, function(s) {
return "\\" + (s == "\r" ? "r" : s);
});
if (ev.length > node.print_to_string().length + 3) continue;
var combined = strs[i] + ev + strs[i + 1];
if (typeof make_node(AST_Template, self, {
expressions: [],
strings: [ combined ],
tag: tag,
}).evaluate(compressor) != typeof make_node(AST_Template, self, {
expressions: [ node ],
strings: strs.slice(i, i + 2),
tag: tag,
}).evaluate(compressor)) continue;
exprs.splice(i, 1);
strs.splice(i, 2, combined);
CHANGED = true;
var exprs = [];
var strs = [];
for (var i = 0, status; i < self.strings.length; i++) {
var str = self.strings[i];
if (!tag) {
var trimmed = decode_template(str);
if (trimmed) str = escape_literal(trimmed);
}
if (i > 0) {
var node = self.expressions[i - 1];
var value = should_join(node);
if (value) {
var prev = strs[strs.length - 1];
var joined = prev + value + str;
var decoded;
if (tag || typeof (decoded = decode_template(joined)) == status) {
strs[strs.length - 1] = decoded ? escape_literal(decoded) : joined;
continue;
}
}
exprs.push(node);
}
strs.push(str);
if (!tag) status = typeof trimmed;
}
if (CHANGED) {
self.expressions = exprs;
self.strings = strs;
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);
}
self.expressions = exprs;
self.strings = strs;
}
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) {
Expand Down
9 changes: 7 additions & 2 deletions lib/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,10 +242,10 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
read_template : with_eof_error("Unterminated template literal", function(strings) {
var s = "";
for (;;) {
var ch = next(true, true);
var ch = read();
switch (ch) {
case "\\":
ch += next(true, true);
ch += read();
break;
case "`":
strings.push(s);
Expand All @@ -260,6 +260,11 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
}
s += ch;
}

function read() {
var ch = next(true, true);
return ch == "\r" ? "\n" : ch;
}
}),
};
var prev_was_dot = false;
Expand Down

0 comments on commit f766bab

Please sign in to comment.