aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Lam S.L <alexlamsl@gmail.com>2021-05-20 00:09:47 +0100
committerGitHub <noreply@github.com>2021-05-20 07:09:47 +0800
commite0695ef5492ac227c3c381683347f939f99a1021 (patch)
tree0cb1c425161ff56523abd64d5bca8d78993f401f
parentd6152e6a76908223cace651898e12a3b3c9a445d (diff)
downloadtracifyjs-e0695ef5492ac227c3c381683347f939f99a1021.tar.gz
tracifyjs-e0695ef5492ac227c3c381683347f939f99a1021.zip
enhance `pure_funcs` (#4945)
-rw-r--r--lib/compress.js102
-rw-r--r--test/compress/templates.js15
2 files changed, 87 insertions, 30 deletions
diff --git a/lib/compress.js b/lib/compress.js
index 9a6d0191..7b8e17b8 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -136,11 +136,23 @@ function Compressor(options, false_by_default) {
this.pure_funcs = pure_funcs;
} else if (typeof pure_funcs == "string") {
this.pure_funcs = function(node) {
- return pure_funcs !== node.expression.print_to_string();
+ var expr;
+ if (node instanceof AST_Call) {
+ expr = node.expression;
+ } else if (node instanceof AST_Template) {
+ expr = node.tag;
+ }
+ return !(expr && pure_funcs === expr.print_to_string());
};
} else if (Array.isArray(pure_funcs)) {
this.pure_funcs = function(node) {
- return !member(node.expression.print_to_string(), pure_funcs);
+ var expr;
+ if (node instanceof AST_Call) {
+ expr = node.expression;
+ } else if (node instanceof AST_Template) {
+ expr = node.tag;
+ }
+ return !(expr && member(expr.print_to_string(), pure_funcs));
};
} else {
this.pure_funcs = return_true;
@@ -2115,7 +2127,7 @@ merge(Compressor.prototype, {
def = fn.definition();
fn = fn.fixed_value();
}
- if (!(fn instanceof AST_Lambda)) return true;
+ if (!(fn instanceof AST_Lambda)) return !node.is_expr_pure(compressor);
if (def && recursive_ref(compressor, def)) return true;
if (fn.collapse_scanning) return false;
fn.collapse_scanning = true;
@@ -2175,7 +2187,7 @@ merge(Compressor.prototype, {
var def = node.definition();
return (in_try || def.scope.resolve() !== scope) && !can_drop_symbol(node);
}
- if (node instanceof AST_Template) return node.tag && !is_raw_tag(compressor, node.tag);
+ if (node instanceof AST_Template) return !node.is_expr_pure(compressor);
if (node instanceof AST_VarDef) {
if (check_destructured(node.name)) return true;
return (node.value || parent instanceof AST_Let) && node.name.match_symbol(function(node) {
@@ -4275,6 +4287,7 @@ merge(Compressor.prototype, {
],
String: [
"fromCharCode",
+ "raw",
],
});
@@ -4908,6 +4921,19 @@ merge(Compressor.prototype, {
}
return compressor.option("annotations") && this.pure || !compressor.pure_funcs(this);
});
+ AST_Template.DEFMETHOD("is_expr_pure", function(compressor) {
+ var tag = this.tag;
+ if (!tag) return true;
+ if (compressor.option("unsafe")) {
+ if (is_undeclared_ref(tag) && global_pure_fns[tag.name]) return true;
+ if (tag instanceof AST_Dot && is_undeclared_ref(tag.expression)) {
+ var static_fn = static_fns[tag.expression.name];
+ return static_fn && (static_fn[tag.property]
+ || tag.expression.name == "Math" && tag.property == "random");
+ }
+ }
+ return !compressor.pure_funcs(this);
+ });
AST_Node.DEFMETHOD("is_call_pure", return_false);
AST_Call.DEFMETHOD("is_call_pure", function(compressor) {
if (!compressor.option("unsafe")) return false;
@@ -5072,7 +5098,7 @@ merge(Compressor.prototype, {
return !this.is_declared(compressor) || !can_drop_symbol(this, compressor);
});
def(AST_Template, function(compressor) {
- return this.tag && !is_raw_tag(compressor, this.tag) || any(this.expressions, compressor);
+ return !this.is_expr_pure(compressor) || any(this.expressions, compressor);
});
def(AST_Try, function(compressor) {
return any(this.body, compressor)
@@ -7485,27 +7511,7 @@ merge(Compressor.prototype, {
if (!rhs) return lhs;
return make_sequence(this, [ lhs, rhs ]);
});
- def(AST_Call, function(compressor, first_in_statement) {
- var self = this;
- if (self.is_expr_pure(compressor)) {
- if (self.pure) AST_Node.warn("Dropping __PURE__ call [{file}:{line},{col}]", self.start);
- var args = trim(self.args, compressor, first_in_statement, array_spread);
- return args && make_sequence(self, args.map(convert_spread));
- }
- var exp = self.expression;
- if (self.is_call_pure(compressor)) {
- var exprs = self.args.slice();
- exprs.unshift(exp.expression);
- exprs = trim(exprs, compressor, first_in_statement, array_spread);
- return exprs && make_sequence(self, exprs.map(convert_spread));
- }
- if (compressor.option("yields") && is_generator(exp)) {
- var call = self.clone();
- call.expression = make_node(AST_Function, exp, exp);
- call.expression.body = [];
- var opt = call.transform(compressor);
- if (opt !== call) return opt.drop_side_effect_free(compressor, first_in_statement);
- }
+ function drop_returns(compressor, exp) {
var drop_body = false;
if (compressor.option("arrows") && is_arrow(exp)) {
if (!exp.value) {
@@ -7539,6 +7545,31 @@ merge(Compressor.prototype, {
node.value = value.drop_side_effect_free(compressor);
}
});
+ }
+ return drop_body;
+ }
+ def(AST_Call, function(compressor, first_in_statement) {
+ var self = this;
+ if (self.is_expr_pure(compressor)) {
+ if (self.pure) AST_Node.warn("Dropping __PURE__ call [{file}:{line},{col}]", self.start);
+ var args = trim(self.args, compressor, first_in_statement, array_spread);
+ return args && make_sequence(self, args.map(convert_spread));
+ }
+ var exp = self.expression;
+ if (self.is_call_pure(compressor)) {
+ var exprs = self.args.slice();
+ exprs.unshift(exp.expression);
+ exprs = trim(exprs, compressor, first_in_statement, array_spread);
+ return exprs && make_sequence(self, exprs.map(convert_spread));
+ }
+ if (compressor.option("yields") && is_generator(exp)) {
+ var call = self.clone();
+ call.expression = make_node(AST_Function, exp, exp);
+ call.expression.body = [];
+ var opt = call.transform(compressor);
+ if (opt !== call) return opt.drop_side_effect_free(compressor, first_in_statement);
+ }
+ if (drop_returns(compressor, exp)) {
// always shallow clone to ensure stripping of negated IIFEs
self = self.clone();
self.expression = exp.clone();
@@ -7734,10 +7765,21 @@ merge(Compressor.prototype, {
return this.is_declared(compressor) && can_drop_symbol(this, compressor) ? 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);
+ var self = this;
+ if (self.is_expr_pure(compressor)) {
+ var expressions = self.expressions;
+ if (expressions.length == 0) return null;
+ return make_sequence(self, expressions).drop_side_effect_free(compressor, first_in_statement);
+ }
+ var tag = self.tag;
+ if (drop_returns(compressor, tag)) {
+ // always shallow clone to signal internal changes
+ self = self.clone();
+ self.tag = tag.clone();
+ // avoid extraneous traversal
+ if (tag._squeezed) self.tag._squeezed = true;
+ }
+ return self;
});
def(AST_Unary, function(compressor, first_in_statement) {
var exp = this.expression;
diff --git a/test/compress/templates.js b/test/compress/templates.js
index 3df3efb7..3c1661fe 100644
--- a/test/compress/templates.js
+++ b/test/compress/templates.js
@@ -315,6 +315,21 @@ unsafe_side_effects: {
node_version: ">=4"
}
+pure_funcs: {
+ options = {
+ pure_funcs: "Math.random",
+ side_effects: true,
+ }
+ input: {
+ Math.random`${console.log("PASS")}`;
+ }
+ expect: {
+ console.log("PASS");
+ }
+ expect_stdout: "PASS"
+ node_version: ">=4"
+}
+
issue_4604: {
options = {
collapse_vars: true,