diff options
author | Alex Lam S.L <alexlamsl@gmail.com> | 2020-04-20 02:42:13 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-20 09:42:13 +0800 |
commit | a2fc32c64b52ec5582c70e7e93bc9e6bb45eac3f (patch) | |
tree | 3db60627c91031d66c4937f1c5a042769984c09a /lib | |
parent | 88504ab86995b33b1c497e44ef314ab54fd57355 (diff) | |
download | tracifyjs-a2fc32c64b52ec5582c70e7e93bc9e6bb45eac3f.tar.gz tracifyjs-a2fc32c64b52ec5582c70e7e93bc9e6bb45eac3f.zip |
enhance `conditionals` (#3805)
Diffstat (limited to 'lib')
-rw-r--r-- | lib/compress.js | 85 |
1 files changed, 79 insertions, 6 deletions
diff --git a/lib/compress.js b/lib/compress.js index e40e1d2e..ef032b3f 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -2363,13 +2363,33 @@ merge(Compressor.prototype, { exprs = exprs.slice(0, i + 1).concat(tail); } if (defn instanceof AST_Definitions) { - var def = defn.definitions[defn.definitions.length - 1]; - if (trim_assigns(def.name, def.value, exprs)) trimmed = true; - if (join_var_assign(defn.definitions, exprs, keep || 0)) trimmed = true; + keep = keep || 0; + for (var i = defn.definitions.length; --i >= 0;) { + var def = defn.definitions[i]; + if (!def.value) continue; + if (trim_assigns(def.name, def.value, exprs)) trimmed = true; + if (merge_conditional_assignments(def, exprs, keep)) trimmed = true; + break; + } + if (join_var_assign(defn.definitions, exprs, keep)) trimmed = true; } return trimmed && exprs; } + function merge_conditional_assignments(var_def, exprs, keep) { + if (!compressor.option("conditionals")) return; + var trimmed = false; + var def = var_def.name.definition(); + while (exprs.length > keep) { + var cond = to_conditional_assignment(compressor, def, var_def.value, exprs[0]); + if (!cond) break; + var_def.value = cond; + exprs.shift(); + trimmed = true; + } + return trimmed; + } + function join_var_assign(definitions, exprs, keep) { var trimmed = false; while (exprs.length > keep) { @@ -6294,11 +6314,44 @@ merge(Compressor.prototype, { return self; }); + // (a = b, x && a = c) => a = x ? c : b + // (a = b, x || a = c) => a = x ? b : c + function to_conditional_assignment(compressor, def, value, node) { + if (!(node instanceof AST_Binary)) return; + if (!lazy_op[node.operator]) return; + if (!(node.right instanceof AST_Assign)) return; + if (node.right.operator != "=") return; + if (!(node.right.left instanceof AST_SymbolRef)) return; + if (node.right.left.definition() !== def) return; + if (value.has_side_effects(compressor)) return; + if (!safe_from_assignment(node.left)) return; + if (!safe_from_assignment(node.right.right)) return; + def.replaced++; + return node.operator == "&&" ? make_node(AST_Conditional, node, { + condition: node.left, + consequent: node.right.right, + alternative: value + }) : make_node(AST_Conditional, node, { + condition: node.left, + consequent: value, + alternative: node.right.right + }); + + function safe_from_assignment(node) { + if (node.has_side_effects(compressor)) return; + var hit = false; + node.walk(new TreeWalker(function(node) { + if (hit) return true; + if (node instanceof AST_SymbolRef && node.definition() === def) return hit = true; + })); + return !hit; + } + } + OPT(AST_Sequence, function(self, compressor) { - if (!compressor.option("side_effects")) return self; - var expressions = []; - filter_for_side_effects(); + var expressions = filter_for_side_effects(); var end = expressions.length - 1; + merge_conditional_assignments(); trim_right_for_undefined(); if (end == 0) { self = maintain_this_binding(compressor, compressor.parent(), compressor.self(), expressions[0]); @@ -6309,6 +6362,8 @@ merge(Compressor.prototype, { return self; function filter_for_side_effects() { + if (!compressor.option("side_effects")) return self.expressions; + var expressions = []; var first = first_in_statement(compressor); var last = self.expressions.length - 1; self.expressions.forEach(function(expr, index) { @@ -6318,9 +6373,11 @@ merge(Compressor.prototype, { first = false; } }); + return expressions; } function trim_right_for_undefined() { + if (!compressor.option("side_effects")) return; while (end > 0 && is_undefined(expressions[end], compressor)) end--; if (end < expressions.length - 1) { expressions[end] = make_node(AST_UnaryPrefix, self, { @@ -6330,6 +6387,22 @@ merge(Compressor.prototype, { expressions.length = end + 1; } } + + function merge_conditional_assignments() { + if (!compressor.option("conditionals")) return; + for (var i = 0; i < end; i++) { + var assign = expressions[i]; + if (!(assign instanceof AST_Assign)) continue; + if (assign.operator != "=") continue; + if (!(assign.left instanceof AST_SymbolRef)) continue; + var def = assign.left.definition(); + var cond = to_conditional_assignment(compressor, def, assign.right, expressions[i + 1]); + if (!cond) continue; + assign.right = cond; + expressions.splice(i + 1, 1); + end--; + } + } }); OPT(AST_UnaryPostfix, function(self, compressor) { |