aboutsummaryrefslogtreecommitdiff
make_sequences_1: {
    options = {
        sequences: true,
    }
    input: {
        foo();
        bar();
        baz();
    }
    expect: {
        foo(),bar(),baz();
    }
}

make_sequences_2: {
    options = {
        sequences: true,
    }
    input: {
        if (boo) {
            foo();
            bar();
            baz();
        } else {
            x();
            y();
            z();
        }
    }
    expect: {
        if (boo) foo(),bar(),baz();
        else x(),y(),z();
    }
}

make_sequences_3: {
    options = {
        sequences: true,
    }
    input: {
        function f() {
            foo();
            bar();
            return baz();
        }
        function g() {
            foo();
            bar();
            throw new Error();
        }
    }
    expect: {
        function f() {
            return foo(), bar(), baz();
        }
        function g() {
            throw foo(), bar(), new Error();
        }
    }
}

make_sequences_4: {
    options = {
        sequences: true,
    }
    input: {
        x = 5;
        if (y) z();

        x = 5;
        for (i = 0; i < 5; i++) console.log(i);

        x = 5;
        for (; i < 5; i++) console.log(i);

        x = 5;
        switch (y) {}

        x = 5;
        with (obj) {}
    }
    expect: {
        if (x = 5, y) z();
        for (x = 5, i = 0; i < 5; i++) console.log(i);
        for (x = 5; i < 5; i++) console.log(i);
        switch (x = 5, y) {}
        with (x = 5, obj);
    }
    expect_stdout: true
}

lift_sequences_1: {
    options = {
        sequences: true,
    }
    input: {
        var foo, x, y, bar;
        foo = !(x(), y(), bar());
    }
    expect: {
        var foo, x, y, bar;
        x(), y(), foo = !bar();
    }
}

lift_sequences_2: {
    options = {
        evaluate: true,
        sequences: true,
    }
    input: {
        var foo = 1, bar;
        foo.x = (foo = {}, 10);
        bar = (bar = {}, 10);
        console.log(foo, bar);
    }
    expect: {
        var foo = 1, bar;
        foo.x = (foo = {}, 10),
        bar = {}, bar = 10,
        console.log(foo, bar);
    }
    expect_stdout: true
}

lift_sequences_3: {
    options = {
        conditionals: true,
        sequences: true,
    }
    input: {
        var x, foo, bar, baz;
        x = (foo(), bar(), baz()) ? 10 : 20;
    }
    expect: {
        var x, foo, bar, baz;
        foo(), bar(), x = baz() ? 10 : 20;
    }
}

lift_sequences_4: {
    options = {
        side_effects: true,
    }
    input: {
        var x, foo, bar, baz;
        x = (foo, bar, baz);
    }
    expect: {
        var x, foo, bar, baz;
        x = baz;
    }
}

lift_sequences_5: {
    options = {
        sequences: true,
    }
    input: {
        var a = 2, b;
        a *= (b, a = 4, 3);
        console.log(a);
    }
    expect: {
        var a = 2, b;
        b, a *= (a = 4, 3),
        console.log(a);
    }
    expect_stdout: "6"
}

for_sequences: {
    options = {
        sequences: true,
    }
    input: {
        // 1
        foo();
        bar();
        for (; false;);
        // 2
        foo();
        bar();
        for (x = 5; false;);
        // 3
        x = (foo in bar);
        for (; false;);
        // 4
        x = (foo in bar);
        for (y = 5; false;);
        // 5
        x = function() {
            foo in bar;
        };
        for (y = 5; false;);
    }
    expect: {
        // 1
        for (foo(), bar(); false;);
        // 2
        for (foo(), bar(), x = 5; false;);
        // 3
        x = (foo in bar);
        for (; false;);
        // 4
        x = (foo in bar);
        for (y = 5; false;);
        // 5
        for (x = function() {
            foo in bar;
        }, y = 5; false;);
    }
}

limit_1: {
    options = {
        sequences: 3,
    }
    input: {
        a;
        b;
        c;
        d;
        e;
        f;
        g;
        h;
        i;
        j;
        k;
    }
    expect: {
        a, b, c;
        d, e, f;
        g, h, i;
        j, k;
    }
}

limit_2: {
    options = {
        sequences: 3,
    }
    input: {
        a, b;
        c, d;
        e, f;
        g, h;
        i, j;
        k;
    }
    expect: {
        a, b, c, d;
        e, f, g, h;
        i, j, k;
    }
}

negate_iife_for: {
    options = {
        negate_iife: true,
        sequences: true,
    }
    input: {
        (function() {})();
        for (i = 0; i < 5; i++) console.log(i);
        (function() {})();
        for (; i < 10; i++) console.log(i);
    }
    expect: {
        for (!function() {}(), i = 0; i < 5; i++) console.log(i);
        for (!function() {}(); i < 10; i++) console.log(i);
    }
    expect_stdout: true
}

iife: {
    options = {
        sequences: true,
    }
    input: {
        x = 42;
        (function a() {})();
        !function b() {}();
        ~function c() {}();
        +function d() {}();
        -function e() {}();
        void function f() {}();
        typeof function g() {}();
    }
    expect: {
        x = 42, function a() {}(), function b() {}(), function c() {}(),
        function d() {}(), function e() {}(), function f() {}(), function g() {}();
    }
}

unsafe_undefined: {
    options = {
        conditionals: true,
        if_return: true,
        sequences: true,
        side_effects: true,
        unsafe_undefined: true,
    }
    input: {
        function f(undefined) {
            if (a)
                return b;
            if (c)
                return d;
        }
        function g(undefined) {
            if (a)
                return b;
            if (c)
                return d;
            e();
        }
    }
    expect: {
        function f(undefined) {
            return a ? b : c ? d : undefined;
        }
        function g(undefined) {
            return a ? b : c ? d : void e();
        }
    }
}

issue_1685: {
    options = {
        collapse_vars: true,
        side_effects: true,
    }
    input: {
        var a = 100, b = 10;
        function f() {
            var a = (a--, delete a && --b);
        }
        f();
        console.log(a, b);
    }
    expect: {
        var a = 100, b = 10;
        function f() {
            var a = (a--, delete a && --b);
        }
        f();
        console.log(a, b);
    }
    expect_stdout: true
}

func_def_1: {
    options = {
        collapse_vars: true,
        side_effects: true,
    }
    input: {
        function f() {
            return f = 0, !!f;
        }
        console.log(f());
    }
    expect: {
        function f() {
            return !!(f = 0);
        }
        console.log(f());
    }
    expect_stdout: "false"
}

func_def_2: {
    options = {
        collapse_vars: true,
        side_effects: true,
    }
    input: {
        console.log(function f() {
            return f = 0, !!f;
        }());
    }
    expect: {
        console.log(function f() {
            return f = 0, !!f;
        }());
    }
    expect_stdout: "true"
}

func_def_3: {
    options = {
        collapse_vars: true,
        side_effects: true,
    }
    input: {
        function f() {
            function g() {}
            return g = 0, !!g;
        }
        console.log(f());
    }
    expect: {
        function f() {
            function g() {}
            return !!(g = 0);
        }
        console.log(f());
    }
    expect_stdout: "false"
}

func_def_4: {
    options = {
        collapse_vars: true,
        side_effects: true,
    }
    input: {
        function f() {
            function g() {
                return g = 0, !!g;
            }
            return g();
        }
        console.log(f());
    }
    expect: {
        function f() {
            function g() {
                return !!(g = 0);
            }
            return g();
        }
        console.log(f());
    }
    expect_stdout: "false"
}

func_def_5: {
    options = {
        collapse_vars: true,
        side_effects: true,
    }
    input: {
        function f() {
            return function g(){
                return g = 0, !!g;
            }();
        }
        console.log(f());
    }
    expect: {
        function f() {
            return function g(){
                return g = 0, !!g;
            }();
        }
        console.log(f());
    }
    expect_stdout: "true"
}

issue_1758: {
    options = {
        sequences: true,
        side_effects: true,
    }
    input: {
        console.log(function(c) {
            var undefined = 42;
            return function() {
                c--;
                c--, c.toString();
                return;
            }();
        }());
    }
    expect: {
        console.log(function(c) {
            var undefined = 42;
            return function() {
                return c--, c--, void c.toString();
            }();
        }());
    }
    expect_stdout: "undefined"
}

delete_seq_1: {
    options = {
        booleans: true,
        evaluate: true,
        side_effects: true,
    }
    input: {
        console.log(delete (1, undefined));
        console.log(delete (1, void 0));
        console.log(delete (1, Infinity));
        console.log(delete (1, 1 / 0));
        console.log(delete (1, NaN));
        console.log(delete (1, 0 / 0));
    }
    expect: {
        console.log(!0);
        console.log(!0);
        console.log(!0);
        console.log(!0);
        console.log(!0);
        console.log(!0);
    }
    expect_stdout: true
}

delete_seq_2: {
    options = {
        booleans: true,
        evaluate: true,
        side_effects: true,
    }
    input: {
        console.log(delete (1, 2, undefined));
        console.log(delete (1, 2, void 0));
        console.log(delete (1, 2, Infinity));
        console.log(delete (1, 2, 1 / 0));
        console.log(delete (1, 2, NaN));
        console.log(delete (1, 2, 0 / 0));
    }
    expect: {
        console.log(!0);
        console.log(!0);
        console.log(!0);
        console.log(!0);
        console.log(!0);
        console.log(!0);
    }
    expect_stdout: true
}

delete_seq_3: {
    options = {
        booleans: true,
        evaluate: true,
        keep_infinity: true,
        side_effects: true,
    }
    input: {
        console.log(delete (1, 2, undefined));
        console.log(delete (1, 2, void 0));
        console.log(delete (1, 2, Infinity));
        console.log(delete (1, 2, 1 / 0));
        console.log(delete (1, 2, NaN));
        console.log(delete (1, 2, 0 / 0));
    }
    expect: {
        console.log(!0);
        console.log(!0);
        console.log(!0);
        console.log(!0);
        console.log(!0);
        console.log(!0);
    }
    expect_stdout: true
}

delete_seq_4: {
    options = {
        booleans: true,
        evaluate: false,
        sequences: true,
        side_effects: true,
    }
    input: {
        function f() {}
        console.log(delete (f(), undefined));
        console.log(delete (f(), void 0));
        console.log(delete (f(), Infinity));
        console.log(delete (f(), 1 / 0));
        console.log(delete (f(), NaN));
        console.log(delete (f(), 0 / 0));
    }
    expect: {
        function f() {}
        console.log(delete void f()),
        console.log(delete void f()),
        console.log((f(), delete (1 / 0))),
        console.log((f(), delete (1 / 0))),
        console.log(delete (f(), NaN)),
        console.log((f(), delete(0 / 0)));
    }
    expect_stdout: true
}

delete_seq_4_evaluate: {
    options = {
        booleans: true,
        evaluate: true,
        sequences: true,
        side_effects: true,
    }
    input: {
        function f() {}
        console.log(delete (f(), undefined));
        console.log(delete (f(), void 0));
        console.log(delete (f(), Infinity));
        console.log(delete (f(), 1 / 0));
        console.log(delete (f(), NaN));
        console.log(delete (f(), 0 / 0));
    }
    expect: {
        function f() {}
        console.log((f(), !0)),
        console.log((f(), !0)),
        console.log((f(), !0)),
        console.log((f(), !0)),
        console.log((f(), !0)),
        console.log((f(), !0));
    }
    expect_stdout: true
}

delete_seq_5: {
    options = {
        booleans: true,
        evaluate: false,
        keep_infinity: true,
        sequences: true,
        side_effects: true,
    }
    input: {
        function f() {}
        console.log(delete (f(), undefined));
        console.log(delete (f(), void 0));
        console.log(delete (f(), Infinity));
        console.log(delete (f(), 1 / 0));
        console.log(delete (f(), NaN));
        console.log(delete (f(), 0 / 0));
    }
    expect: {
        function f() {}
        console.log(delete void f()),
        console.log(delete void f()),
        console.log(delete (f(), Infinity)),
        console.log((f(), delete (1 / 0))),
        console.log(delete (f(), NaN)),
        console.log((f(), delete (0 / 0)));
    }
    expect_stdout: true
}

delete_seq_5_evaluate: {
    options = {
        booleans: true,
        evaluate: true,
        keep_infinity: true,
        sequences: true,
        side_effects: true,
    }
    input: {
        function f() {}
        console.log(delete (f(), undefined));
        console.log(delete (f(), void 0));
        console.log(delete (f(), Infinity));
        console.log(delete (f(), 1 / 0));
        console.log(delete (f(), NaN));
        console.log(delete (f(), 0 / 0));
    }
    expect: {
        function f() {}
        console.log((f(), !0)),
        console.log((f(), !0)),
        console.log((f(), !0)),
        console.log((f(), !0)),
        console.log((f(), !0)),
        console.log((f(), !0));
    }
    expect_stdout: true
}

delete_seq_6: {
    options = {
        booleans: true,
        evaluate: true,
        side_effects: true,
    }
    input: {
        var a;
        console.log(delete (1, a));
    }
    expect: {
        var a;
        console.log(!0);
    }
    expect_stdout: true
}

side_effects: {
    options = {
        sequences: true,
        side_effects: true,
    }
    input: {
        0, a(), 1, b(), 2, c(), 3;
    }
    expect: {
        a(), b(), c();
    }
}

side_effects_cascade_1: {
    options = {
        collapse_vars: true,
        conditionals: true,
        sequences: true,
        side_effects: true,
    }
    input: {
        function f(a, b) {
            a -= 42;
            if (a < 0) a = 0;
            b.a = a;
        }
        var m = {}, n = {};
        f(13, m);
        f("foo", n);
        console.log(m.a, n.a);
    }
    expect: {
        function f(a, b) {
            b.a = a = (a -= 42) < 0 ? 0 : a;
        }
        var m = {}, n = {};
        f(13, m),
        f("foo", n),
        console.log(m.a, n.a);
    }
    expect_stdout: "0 NaN"
}

side_effects_cascade_2: {
    options = {
        collapse_vars: true,
        side_effects: true,
    }
    input: {
        function f(a, b) {
            b = a,
            !a + (b += a) || (b += a),
            b = a,
            b;
        }
    }
    expect: {
        function f(a, b) {
            !(b = a) + (b += a) || (b += a),
            b = a;
        }
    }
}

side_effects_cascade_3: {
    options = {
        collapse_vars: true,
        conditionals: true,
        side_effects: true,
    }
    input: {
        function f(a, b) {
            "foo" ^ (b += a),
            b ? false : (b = a) ? -1 : (b -= a) - (b ^= a),
            a-- || !a,
            a;
        }
    }
    expect: {
        function f(a, b) {
            (b += a) || (b = a) || (b -= a, b ^= a),
            a--;
        }
    }
}

issue_27: {
    options = {
        collapse_vars: true,
        passes: 2,
        sequences: true,
        side_effects: true,
        unused: true,
    }
    input: {
        (function(jQuery) {
            var $;
            $ = jQuery;
            $("body").addClass("foo");
        })(jQuery);
    }
    expect: {
        (function(jQuery) {
            jQuery("body").addClass("foo");
        })(jQuery);
    }
}

issue_2062: {
    options = {
        booleans: true,
        collapse_vars: true,
        conditionals: true,
        side_effects: true,
    }
    input: {
        var a = 1;
        if ([ a || a++ + a--, a++ + a--, a && a.var ]);
        console.log(a);
    }
    expect: {
        var a = 1;
        a || (a++, a--), a++, --a && a.var;
        console.log(a);
    }
    expect_stdout: "1"
}

issue_2313: {
    options = {
        collapse_vars: true,
        sequences: true,
        side_effects: true,
    }
    input: {
        var a = 0, b = 0;
        var foo = {
            get c() {
                a++;
                return 42;
            },
            set c(c) {
                b++;
            },
            d: function() {
                this.c++;
                if (this.c) console.log(a, b);
            }
        }
        foo.d();
    }
    expect: {
        var a = 0, b = 0;
        var foo = {
            get c() {
                return a++, 42;
            },
            set c(c) {
                b++;
            },
            d: function() {
                if (this.c++, this.c) console.log(a, b);
            }
        }
        foo.d();
    }
    expect_stdout: "2 1"
}

cascade_assignment_in_return: {
    options = {
        collapse_vars: true,
        unused: true,
    }
    input: {
        function f(a, b) {
            return a = x(), b(a);
        }
    }
    expect: {
        function f(a, b) {
            return b(x());
        }
    }
}

hoist_defun: {
    options = {
        join_vars: true,
        sequences: true,
    }
    input: {
        x();
        function f() {}
        y();
    }
    expect: {
        function f() {}
        x(), y();
    }
}

hoist_decl: {
    options = {
        join_vars: true,
        sequences: true,
    }
    input: {
        var a;
        w();
        var b = x();
        y();
        for (var c; 0;) z();
        var d;
    }
    expect: {
        var a;
        w();
        var b = x(), c, d;
        for (y(); 0;) z();
    }
}

for_init_var: {
    options = {
        join_vars: true,
        unused: false,
    }
    input: {
        var a = "PASS";
        (function() {
            var b = 42;
            for (var c = 5; c > 0;) c--;
            a = "FAIL";
            var a;
        })();
        console.log(a);
    }
    expect: {
        var a = "PASS";
        (function() {
            for (var b = 42, c = 5, a; c > 0;) c--;
            a = "FAIL";
        })();
        console.log(a);
    }
    expect_stdout: "PASS"
}

forin_1: {
    options = {
        sequences: true,
    }
    input: {
        var o = [];
        o.push("PASS");
        for (var a in o)
            console.log(o[a]);
    }
    expect: {
        var o = [];
        for (var a in o.push("PASS"), o)
            console.log(o[a]);
    }
    expect_stdout: "PASS"
}

forin_2: {
    options = {
        evaluate: true,
        inline: true,
        reduce_vars: true,
        sequences: true,
        toplevel: true,
        unused: true,
    }
    input: {
        var o = {
            p: 1,
            q: 2,
        };
        var k = "k";
        for ((console.log("exp"), o)[function() {
            console.log("prop");
            return k;
        }()] in function() {
            console.log("obj");
            return o;
        }())
            console.log(o.k, o[o.k]);
    }
    expect: {
        var o = {
            p: 1,
            q: 2,
        };
        for ((console.log("exp"), o)[console.log("prop"), "k"] in console.log("obj"), o)
            console.log(o.k, o[o.k]);
    }
    expect_stdout: [
        "obj",
        "exp",
        "prop",
        "p 1",
        "exp",
        "prop",
        "q 2",
    ]
}

call: {
    options = {
        sequences: true,
    }
    input: {
        var a = function() {
            return this;
        }();
        function b() {
            console.log("foo");
        }
        b.c = function() {
            console.log(this === b ? "bar" : "baz");
        };
        (a, b)();
        (a, b).c();
        (a, b.c)();
        (a, b)["c"]();
        (a, b["c"])();
        (a, function() {
            console.log(this === a);
        })();
        new (a, b)();
        new (a, b).c();
        new (a, b.c)();
        new (a, b)["c"]();
        new (a, b["c"])();
        new (a, function() {
            console.log(this === a);
        })();
        console.log(typeof (a, b).c);
        console.log(typeof (a, b)["c"]);
    }
    expect: {
        var a = function() {
            return this;
        }();
        function b() {
            console.log("foo");
        }
        b.c = function() {
            console.log(this === b ? "bar" : "baz");
        },
        b(),
        b.c(),
        (a, b.c)(),
        b["c"](),
        (a, b["c"])(),
        function() {
            console.log(this === a);
        }(),
        new b(),
        new b.c(),
        new b.c(),
        new b["c"](),
        new b["c"](),
        new function() {
            console.log(this === a);
        }(),
        console.log((a, typeof b.c)),
        console.log((a, typeof b["c"]));
    }
    expect_stdout: [
        "foo",
        "bar",
        "baz",
        "bar",
        "baz",
        "true",
        "foo",
        "baz",
        "baz",
        "baz",
        "baz",
        "false",
        "function",
        "function",
    ]
}

missing_link: {
    options = {
        conditionals: true,
        evaluate: true,
        sequences: true,
    }
    input: {
        var a = 100;
        a;
        a++ + (0 ? 2 : 1);
        console.log(a);
    }
    expect: {
        var a = 100;
        a,
        a++,
        console.log(a);
    }
}

angularjs_chain: {
    options = {
        conditionals: true,
        sequences: true,
        side_effects: true,
    }
    input: {
        function nonComputedMember(left, right, context, create) {
            var lhs = left();
            if (create && create !== 1) {
                if (lhs && lhs[right] == null) {
                    lhs[right] = {};
                }
            }
            var value = lhs != null ? lhs[right] : undefined;
            if (context) {
                return { context: lhs, name: right, value: value };
            } else {
                return value;
            }
        }
    }
    expect: {
        function nonComputedMember(left, right, context, create) {
            var lhs = left();
            create && 1 !== create && lhs && null == lhs[right] && (lhs[right] = {});
            var value = null != lhs ? lhs[right] : void 0;
            return context ? {
                context: lhs,
                name: right,
                value: value
            } : value;
        }
    }
}

issue_3490_1: {
    options = {
        conditionals: true,
        dead_code: true,
        inline: true,
        sequences: true,
        side_effects: true,
        toplevel: true,
    }
    input: {
        var b = 42, c = "FAIL";
        if ({
            3: function() {
                var a;
                return (a && a.p) < this;
            }(),
        }) c = "PASS";
        if (b) while ("" == typeof d);
        console.log(c, b);
    }
    expect: {
        var b = 42, c = "FAIL";
        if (function() {
            var a;
            a && a.p;
        }(), c = "PASS", b) while ("" == typeof d);
        console.log(c, b);
    }
    expect_stdout: "PASS 42"
}

issue_3490_2: {
    options = {
        conditionals: true,
        dead_code: true,
        evaluate: true,
        inline: true,
        reduce_vars: true,
        sequences: true,
        side_effects: true,
        toplevel: true,
    }
    input: {
        var b = 42, c = "FAIL";
        if ({
            3: function() {
                var a;
                return (a && a.p) < this;
            }(),
        }) c = "PASS";
        if (b) for (; "" == typeof d;);
        console.log(c, b);
    }
    expect: {
        var b = 42, c = "FAIL";
        for (function() {
            var a;
        }(), c = "PASS", b; "" == typeof d;);
        console.log(c, b);
    }
    expect_stdout: "PASS 42"
}

issue_3703: {
    options = {
        evaluate: true,
        sequences: true,
        unsafe: true,
    }
    input: {
        var a = "FAIL";
        while ((a = "PASS", 0).foo = 0);
        console.log(a);
    }
    expect: {
        var a = "FAIL";
        while (a = "PASS", (0).foo = 0);
        console.log(a);
    }
    expect_stdout: "PASS"
}

issue_4079: {
    options = {
        sequences: true,
        side_effects: true,
    }
    input: {
        try {
            typeof (0, A);
        } catch (e) {
            console.log("PASS");
        }
    }
    expect: {
        try {
            A;
        } catch (e) {
            console.log("PASS");
        }
    }
    expect_stdout: "PASS"
}