From f1e1bb419ab642763c43dec95e07165f477a43be Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Thu, 11 Jan 2018 17:08:21 +0800 Subject: [PATCH] join object assignments (#2763) --- lib/compress.js | 48 +++++++++++++++++++++++++++- test/compress/properties.js | 62 +++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/lib/compress.js b/lib/compress.js index 3e7269d0..b093832c 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -869,6 +869,7 @@ merge(Compressor.prototype, { } function tighten_body(statements, compressor) { + var scope = compressor.find_parent(AST_Scope); var CHANGED, max_iter = 10; do { CHANGED = false; @@ -900,7 +901,6 @@ merge(Compressor.prototype, { // Will not attempt to collapse assignments into or past code blocks // which are not sequentially executed, e.g. loops and conditionals. function collapse(statements, compressor) { - var scope = compressor.find_parent(AST_Scope); if (scope.uses_eval || scope.uses_with) return statements; var args; var candidates = []; @@ -1696,6 +1696,41 @@ merge(Compressor.prototype, { statements.length = n; } + function join_object_assignments(defn, body) { + if (!(defn instanceof AST_Definitions)) return; + var exprs; + if (body instanceof AST_Assign) { + exprs = [ body ]; + } else if (body instanceof AST_Sequence) { + exprs = body.expressions.slice(); + } + if (!exprs) return; + do { + var node = exprs[0]; + if (!(node instanceof AST_Assign)) break; + if (!(node.left instanceof AST_PropAccess)) break; + var sym = node.left.expression; + if (!(sym instanceof AST_SymbolRef)) break; + var def = find_if(function(def) { + return def.name.name == sym.name + && def.value instanceof AST_Object; + }, defn.definitions); + if (!def) break; + if (!node.right.is_constant_expression(scope)) break; + var prop = node.left.property; + if (prop instanceof AST_Node) { + prop = prop.evaluate(compressor); + } + if (prop instanceof AST_Node) break; + def.value.properties.push(make_node(AST_ObjectKeyVal, node, { + key: prop, + value: node.right + })); + exprs.shift(); + } while (exprs.length); + return exprs; + } + function join_consecutive_vars(statements, compressor) { var defs; for (var i = 0, j = -1, len = statements.length; i < len; i++) { @@ -1728,6 +1763,17 @@ merge(Compressor.prototype, { } else { statements[++j] = stat; } + } else if (stat instanceof AST_SimpleStatement) { + var exprs = join_object_assignments(prev, stat.body); + if (exprs) { + if (exprs.length > 0) { + stat.body = make_sequence(stat.body, exprs); + statements[++j] = stat; + } + CHANGED = true; + } else { + statements[++j] = stat; + } } else { statements[++j] = stat; } diff --git a/test/compress/properties.js b/test/compress/properties.js index b2ce5f61..d70eb85a 100644 --- a/test/compress/properties.js +++ b/test/compress/properties.js @@ -1100,3 +1100,65 @@ const_prop_assign_pure: { x(); } } + +join_object_assignments_1: { + options = { + evaluate: true, + join_vars: true, + } + input: { + console.log(function() { + var x = { + a: 1, + c: (console.log("c"), "C"), + }; + x.b = 2; + x[3] = function() { + console.log(x); + }, + x["a"] = /foo/, + x.bar = x; + return x; + }()); + } + expect: { + console.log(function() { + var x = { + a: 1, + c: (console.log("c"), "C"), + b: 2, + 3: function() { + console.log(x); + }, + a: /foo/, + }; + x.bar = x; + return x; + }()); + } + expect_stdout: true +} + +join_object_assignments_2: { + options = { + evaluate: true, + hoist_props: true, + join_vars: true, + passes: 3, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var o = { + foo: 1, + }; + o.bar = 2; + o.baz = 3; + console.log(o.foo, o.bar + o.bar, o.foo * o.bar * o.baz); + } + expect: { + console.log(1, 4, 6); + } + expect_stdout: "1 4 6" +} -- 2.34.1