introduce templates (#4603)
This commit is contained in:
@@ -91,6 +91,7 @@ function Compressor(options, false_by_default) {
|
||||
spreads : !false_by_default,
|
||||
strings : !false_by_default,
|
||||
switches : !false_by_default,
|
||||
templates : !false_by_default,
|
||||
top_retain : null,
|
||||
toplevel : !!(options && options["top_retain"]),
|
||||
typeofs : !false_by_default,
|
||||
@@ -3689,6 +3690,9 @@ merge(Compressor.prototype, {
|
||||
delete this.is_string;
|
||||
return result;
|
||||
});
|
||||
def(AST_Template, function(compressor) {
|
||||
return !this.tag || is_raw_tag(compressor, this.tag);
|
||||
});
|
||||
def(AST_UnaryPrefix, function() {
|
||||
return this.operator == "typeof";
|
||||
});
|
||||
@@ -4298,6 +4302,16 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
return this;
|
||||
});
|
||||
function eval_all(nodes, compressor, ignore_side_effects, cached, depth) {
|
||||
var values = [];
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var node = nodes[i];
|
||||
var value = node._eval(compressor, ignore_side_effects, cached, depth);
|
||||
if (node === value) return;
|
||||
values.push(value);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
def(AST_Call, function(compressor, ignore_side_effects, cached, depth) {
|
||||
var exp = this.expression;
|
||||
var fn = exp instanceof AST_SymbolRef ? exp.fixed_value() : exp;
|
||||
@@ -4305,7 +4319,7 @@ merge(Compressor.prototype, {
|
||||
if (fn.evaluating) return this;
|
||||
if (fn.name && fn.name.definition().recursive_refs > 0) return this;
|
||||
if (this.is_expr_pure(compressor)) return this;
|
||||
var args = eval_args(this.args);
|
||||
var args = eval_all(this.args, compressor, ignore_side_effects, cached, depth);
|
||||
if (!all(fn.argnames, function(sym, index) {
|
||||
if (sym instanceof AST_DefaultValue) {
|
||||
if (!args) return false;
|
||||
@@ -4380,7 +4394,7 @@ merge(Compressor.prototype, {
|
||||
if (!native_fn || !native_fn[key]) return this;
|
||||
if (val instanceof RegExp && val.global && !(e instanceof AST_RegExp)) return this;
|
||||
}
|
||||
var args = eval_args(this.args);
|
||||
var args = eval_all(this.args, compressor, ignore_side_effects, cached, depth);
|
||||
if (!args) return this;
|
||||
if (key == "replace" && typeof args[1] == "function") return this;
|
||||
try {
|
||||
@@ -4397,19 +4411,35 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
}
|
||||
return this;
|
||||
|
||||
function eval_args(args) {
|
||||
var values = [];
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var arg = args[i];
|
||||
var value = arg._eval(compressor, ignore_side_effects, cached, depth);
|
||||
if (arg === value) return;
|
||||
values.push(value);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
});
|
||||
def(AST_New, return_this);
|
||||
def(AST_Template, function(compressor, ignore_side_effects, cached, depth) {
|
||||
if (!compressor.option("templates")) return this;
|
||||
if (this.tag) {
|
||||
if (!is_raw_tag(compressor, this.tag)) return this;
|
||||
decode = function(str) {
|
||||
return str;
|
||||
};
|
||||
}
|
||||
var exprs = eval_all(this.expressions, compressor, ignore_side_effects, cached, depth);
|
||||
if (!exprs) return this;
|
||||
var ret = decode(this.strings[0]);
|
||||
var malformed = false;
|
||||
for (var i = 0; i < exprs.length; i++) {
|
||||
ret += exprs[i] + decode(this.strings[i + 1]);
|
||||
}
|
||||
if (!malformed) return ret;
|
||||
this._eval = return_this;
|
||||
return this;
|
||||
|
||||
function decode(str) {
|
||||
return str.replace(/\\(u[0-9a-fA-F]{4}|u\{[0-9a-fA-F]+\}|x[0-9a-fA-F]{2}|[0-9]+|[\s\S])/g, function(match, seq) {
|
||||
var s = decode_escape_sequence(seq);
|
||||
if (typeof s != "string") malformed = true;
|
||||
return s;
|
||||
});
|
||||
}
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("_eval", func);
|
||||
});
|
||||
@@ -4664,7 +4694,7 @@ merge(Compressor.prototype, {
|
||||
return !this.is_declared(compressor) || !can_drop_symbol(this);
|
||||
});
|
||||
def(AST_Template, function(compressor) {
|
||||
return any(this.expressions, compressor);
|
||||
return this.tag && !is_raw_tag(compressor, this.tag) || any(this.expressions, compressor);
|
||||
});
|
||||
def(AST_This, return_false);
|
||||
def(AST_Try, function(compressor) {
|
||||
@@ -7019,6 +7049,7 @@ merge(Compressor.prototype, {
|
||||
return this.is_declared(compressor) && can_drop_symbol(this) ? null : this;
|
||||
});
|
||||
def(AST_Template, function(compressor, first_in_statement) {
|
||||
if (this.tag && !is_raw_tag(compressor, this.tag)) return this;
|
||||
var expressions = this.expressions;
|
||||
if (expressions.length == 0) return null;
|
||||
return make_sequence(this, expressions).drop_side_effect_free(compressor, first_in_statement);
|
||||
@@ -9907,6 +9938,32 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
});
|
||||
|
||||
function is_raw_tag(compressor, tag) {
|
||||
return compressor.option("unsafe")
|
||||
&& tag instanceof AST_Dot
|
||||
&& tag.property == "raw"
|
||||
&& is_undeclared_ref(tag.expression)
|
||||
&& tag.expression.name == "String";
|
||||
}
|
||||
|
||||
OPT(AST_Template, function(self, compressor) {
|
||||
if (!compressor.option("templates")) return self;
|
||||
if (!self.tag || is_raw_tag(compressor, self.tag)) {
|
||||
var exprs = self.expressions;
|
||||
var strs = self.strings;
|
||||
for (var i = exprs.length; --i >= 0;) {
|
||||
var node = exprs[i];
|
||||
var ev = node.evaluate(compressor);
|
||||
if (ev === node) continue;
|
||||
ev = "" + ev;
|
||||
if (ev.length > node.print_to_string().length + 3) continue;
|
||||
exprs.splice(i, 1);
|
||||
strs.splice(i, 2, strs[i] + ev + strs[i + 1]);
|
||||
}
|
||||
}
|
||||
return try_evaluate(compressor, self);
|
||||
});
|
||||
|
||||
function is_atomic(lhs, self) {
|
||||
return lhs instanceof AST_SymbolRef || lhs.TYPE === self.TYPE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user