if (aborts) push(tw);
reset_variables(tw, compressor, fn);
// Virtually turn IIFE parameters into variable definitions:
- // (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})()
+ // (function(a,b) {...})(c,d) ---> (function() {var a=c,b=d; ...})()
// So existing transformation rules can work on them.
var safe = !fn.uses_arguments || tw.has_directive("use strict");
fn.argnames.forEach(function(arg, i) {
var in_bool = stat.body.in_bool || next instanceof AST_Return && next.in_bool;
//---
// pretty silly case, but:
- // if (foo()) return; return; => foo(); return;
+ // if (foo()) return; return; ---> foo(); return;
if (!value && !stat.alternative
&& (in_lambda && !next || next instanceof AST_Return && !next.value)) {
CHANGED = true;
continue;
}
//---
- // if (foo()) return x; return y; => return foo() ? x : y;
+ // if (foo()) return x; return y; ---> return foo() ? x : y;
if (!stat.alternative && next instanceof AST_Return) {
CHANGED = true;
stat = stat.clone();
continue;
}
//---
- // if (foo()) return x; [ return ; ] => return foo() ? x : undefined;
+ // if (foo()) return x; [ return ; ] ---> return foo() ? x : undefined;
if (!stat.alternative && !next && in_lambda && (in_bool || value && multiple_if_returns)) {
CHANGED = true;
stat = stat.clone();
continue;
}
//---
- // if (a) return b; if (c) return d; e; => return a ? b : c ? d : void e;
+ // if (a) return b; if (c) return d; e; ---> return a ? b : c ? d : void e;
//
// if sequences is not enabled, this can lead to an endless loop (issue #866).
// however, with sequences on this helps producing slightly better output for
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
});
def(AST_Accessor, return_this);
+ def(AST_BigInt, return_this);
def(AST_Node, return_this);
def(AST_Constant, function() {
return this.value;
&& typeof result == "number"
&& (this.operator == "+" || this.operator == "-")) {
var digits = Math.max(0, decimals(left), decimals(right));
- // 53-bit significand => 15.95 decimal places
+ // 53-bit significand ---> 15.95 decimal places
if (digits < 16) return +result.toFixed(digits);
}
return result;
if (compressor.option("unsafe")) {
if (is_undeclared_ref(exp)) switch (exp.name) {
case "Array":
+ // Array(n) ---> [ , , ... , ]
if (self.args.length == 1) {
var first = self.args[0];
if (first instanceof AST_Number) try {
if (length > 6) break;
var elements = Array(length);
for (var i = 0; i < length; i++) elements[i] = make_node(AST_Hole, self);
- return make_node(AST_Array, self, {
- elements: elements
- });
+ return make_node(AST_Array, self, { elements: elements });
} catch (ex) {
AST_Node.warn("Invalid array length: {length} [{file}:{line},{col}]", {
length: length,
}
if (!first.is_boolean(compressor) && !first.is_string(compressor)) break;
}
- return make_node(AST_Array, self, {
- elements: self.args
- });
+ // Array(...) ---> [ ... ]
+ return make_node(AST_Array, self, { elements: self.args });
case "Object":
- if (self.args.length == 0) {
- return make_node(AST_Object, self, {
- properties: []
- });
- }
+ // Object() ---> {}
+ if (self.args.length == 0) return make_node(AST_Object, self, { properties: [] });
break;
case "String":
- if (self.args.length == 0) return make_node(AST_String, self, {
- value: ""
- });
- if (self.args.length <= 1) return make_node(AST_Binary, self, {
- left: self.args[0],
+ // String() ---> ""
+ if (self.args.length == 0) return make_node(AST_String, self, { value: "" });
+ // String(x) ---> "" + x
+ if (self.args.length == 1) return make_node(AST_Binary, self, {
operator: "+",
- right: make_node(AST_String, self, { value: "" })
+ left: make_node(AST_String, self, { value: "" }),
+ right: self.args[0],
}).optimize(compressor);
break;
case "Number":
- if (self.args.length == 0) return make_node(AST_Number, self, {
- value: 0
- });
+ // Number() ---> 0
+ if (self.args.length == 0) return make_node(AST_Number, self, { value: 0 });
+ // Number(x) ---> +("" + x)
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
- expression: self.args[0],
- operator: "+"
+ operator: "+",
+ expression: make_node(AST_Binary, self, {
+ operator: "+",
+ left: make_node(AST_String, self, { value: "" }),
+ right: self.args[0],
+ }),
}).optimize(compressor);
+ break;
case "Boolean":
- if (self.args.length == 0) return make_node(AST_False, self);
+ // Boolean() ---> false
+ if (self.args.length == 0) return make_node(AST_False, self).optimize(compressor);
+ // Boolean(x) ---> !!x
if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
+ operator: "!",
expression: make_node(AST_UnaryPrefix, self, {
+ operator: "!",
expression: self.args[0],
- operator: "!"
}),
- operator: "!"
}).optimize(compressor);
break;
case "RegExp":
+ // attempt to convert RegExp(...) to literal
var params = [];
if (all(self.args, function(arg) {
var value = arg.evaluate(compressor);
params.unshift(value);
return arg !== value;
- })) {
- try {
- return best_of(compressor, self, make_node(AST_RegExp, self, {
- value: RegExp.apply(RegExp, params),
- }));
- } catch (ex) {
- AST_Node.warn("Error converting {expr} [{file}:{line},{col}]", {
- expr: self,
- file: self.start.file,
- line: self.start.line,
- col: self.start.col,
- });
- }
+ })) try {
+ return best_of(compressor, self, make_node(AST_RegExp, self, {
+ value: RegExp.apply(RegExp, params),
+ }));
+ } catch (ex) {
+ AST_Node.warn("Error converting {expr} [{file}:{line},{col}]", {
+ expr: self,
+ file: self.start.file,
+ line: self.start.line,
+ col: self.start.col,
+ });
}
break;
- } else if (exp instanceof AST_Dot) switch(exp.property) {
+ } else if (exp instanceof AST_Dot) switch (exp.property) {
case "toString":
+ // x.toString() ---> "" + x
if (self.args.length == 0 && !exp.expression.may_throw_on_access(compressor)) {
return make_node(AST_Binary, self, {
- left: make_node(AST_String, self, { value: "" }),
operator: "+",
- right: exp.expression
+ left: make_node(AST_String, self, { value: "" }),
+ right: exp.expression,
}).optimize(compressor);
}
break;
case "join":
- if (exp.expression instanceof AST_Array) EXIT: {
- var separator;
- if (self.args.length > 0) {
- separator = self.args[0].evaluate(compressor);
- if (separator === self.args[0]) break EXIT; // not a constant
+ if (exp.expression instanceof AST_Array && self.args.length < 2) EXIT: {
+ var separator = self.args[0];
+ // [].join() ---> ""
+ // [].join(x) ---> (x, "")
+ if (exp.expression.elements.length == 0) return separator ? make_sequence(self, [
+ separator,
+ make_node(AST_String, self, { value: "" }),
+ ]).optimize(compressor) : make_node(AST_String, self, { value: "" });
+ if (separator) {
+ separator = separator.evaluate(compressor);
+ if (separator instanceof AST_Node) break EXIT; // not a constant
}
var elements = [];
var consts = [];
} else {
if (consts.length > 0) {
elements.push(make_node(AST_String, self, {
- value: consts.join(separator)
+ value: consts.join(separator),
}));
consts.length = 0;
}
elements.push(el);
}
});
- if (consts.length > 0) {
- elements.push(make_node(AST_String, self, {
- value: consts.join(separator)
- }));
- }
- if (elements.length == 0) return make_node(AST_String, self, { value: "" });
+ if (consts.length > 0) elements.push(make_node(AST_String, self, {
+ value: consts.join(separator),
+ }));
+ // [ x ].join() ---> "" + x
+ // [ x ].join(".") ---> "" + x
+ // [ 1, 2, 3 ].join() ---> "1,2,3"
+ // [ 1, 2, 3 ].join(".") ---> "1.2.3"
if (elements.length == 1) {
- if (elements[0].is_string(compressor)) {
- return elements[0];
- }
+ if (elements[0].is_string(compressor)) return elements[0];
return make_node(AST_Binary, elements[0], {
- operator : "+",
- left : make_node(AST_String, self, { value: "" }),
- right : elements[0]
+ operator: "+",
+ left: make_node(AST_String, self, { value: "" }),
+ right: elements[0],
});
}
+ // [ 1, 2, a, 3 ].join("") ---> "12" + a + "3"
if (separator == "") {
var first;
- if (elements[0].is_string(compressor)
- || elements[1].is_string(compressor)) {
+ if (elements[0].is_string(compressor) || elements[1].is_string(compressor)) {
first = elements.shift();
} else {
first = make_node(AST_String, self, { value: "" });
}
return elements.reduce(function(prev, el) {
return make_node(AST_Binary, el, {
- operator : "+",
- left : prev,
- right : el
+ operator: "+",
+ left: prev,
+ right: el,
});
}, first).optimize(compressor);
}
+ // [ x, "foo", "bar", y ].join() ---> [ x, "foo,bar", y ].join()
+ // [ x, "foo", "bar", y ].join("-") ---> [ x, "foo-bar", y ].join("-")
// need this awkward cloning to not affect original element
// best_of will decide which one to get through.
var node = self.clone();
if (compressor.option("unsafe_Function")
&& is_undeclared_ref(exp)
&& exp.name == "Function") {
- // new Function() => function(){}
+ // new Function() ---> function(){}
if (self.args.length == 0) return make_node(AST_Function, self, {
argnames: [],
body: []
return self;
});
- // (a = b, x && a = c) => a = x ? c : b
- // (a = b, x || a = c) => a = x ? b : c
+ // (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;
} else if (compressor.in_boolean_context()) switch (op) {
case "!":
if (exp instanceof AST_UnaryPrefix && exp.operator == "!") {
- // !!foo => foo, if we're in boolean context
+ // !!foo ---> foo, if we're in boolean context
return exp.expression;
}
if (exp instanceof AST_Binary) {
}
if (compressor.option("assignments") && lazy_op[self.operator]) {
var assign = self.right;
- // a || (a = x) => a = a || x
- // a && (a = x) => a = a && x
+ // a || (a = x) ---> a = a || x
+ // a && (a = x) ---> a = a && x
if (self.left instanceof AST_SymbolRef
&& assign instanceof AST_Assign
&& assign.operator == "="
// XXX: intentionally falling down to the next case
case "==":
case "!=":
- // void 0 == x => null == x
+ // void 0 == x ---> null == x
if (!is_strict_comparison && is_undefined(self.left, compressor)) {
self.left = make_node(AST_Null, self.left);
}
- // "undefined" == typeof x => undefined === x
+ // "undefined" == typeof x ---> undefined === x
else if (compressor.option("typeofs")
&& self.left instanceof AST_String
&& self.left.value == "undefined"
if (self.operator.length == 2) self.operator += "=";
}
}
- // obj !== obj => false
+ // obj !== obj ---> false
else if (self.left instanceof AST_SymbolRef
&& self.right instanceof AST_SymbolRef
&& self.left.definition() === self.right.definition()
break;
case "&&":
case "||":
- // void 0 !== x && null !== x => null != x
- // void 0 === x || null === x => null == x
+ // void 0 !== x && null !== x ---> null != x
+ // void 0 === x || null === x ---> null == x
var lhs = self.left;
if (lhs.operator == self.operator) {
lhs = lhs.right;
case ">=": reverse("<="); break;
}
}
- // x && (y && z) => x && y && z
- // x || (y || z) => x || y || z
+ // x && (y && z) ---> x && y && z
+ // x || (y || z) ---> x || y || z
if (compressor.option("conditionals")
&& lazy_op[self.operator]
&& self.right instanceof AST_Binary
swap_chain();
}
if (compressor.option("strings") && self.operator == "+") {
- // "foo" + 42 + "" => "foo" + 42
+ // "foo" + 42 + "" ---> "foo" + 42
if (self.right instanceof AST_String
&& self.right.value == ""
&& self.left.is_string(compressor)) {
return self.left.optimize(compressor);
}
- // "" + ("foo" + 42) => "foo" + 42
+ // "" + ("foo" + 42) ---> "foo" + 42
if (self.left instanceof AST_String
&& self.left.value == ""
&& self.right.is_string(compressor)) {
return self.right.optimize(compressor);
}
- // "" + 42 + "foo" => 42 + "foo"
+ // "" + 42 + "foo" ---> 42 + "foo"
if (self.left instanceof AST_Binary
&& self.left.operator == "+"
&& self.left.left instanceof AST_String
self.left = self.left.right;
return self.optimize(compressor);
}
- // "x" + (y + "z") => "x" + y + "z"
- // x + ("y" + z) => x + "y" + z
+ // "x" + (y + "z") ---> "x" + y + "z"
+ // x + ("y" + z) ---> x + "y" + z
if (self.right instanceof AST_Binary
&& self.operator == self.right.operator
&& (self.left.is_string(compressor) && self.right.is_string(compressor)
return self.left.optimize(compressor);
}
}
- // (x || false) && y => x ? y : false
+ // (x || false) && y ---> x ? y : false
if (self.left.operator == "||") {
var lr = self.left.right.evaluate(compressor, true);
if (!lr) return make_node(AST_Conditional, self, {
]).optimize(compressor);
} else self.truthy = true;
}
- // x && true || y => x ? true : y
+ // x && true || y ---> x ? true : y
if (self.left.operator == "&&") {
var lr = self.left.right.is_truthy() || self.left.right.evaluate(compressor, true);
if (lr && !(lr instanceof AST_Node)) return make_node(AST_Conditional, self, {
}
break;
case "+":
- // "foo" + ("bar" + x) => "foobar" + x
+ // "foo" + ("bar" + x) ---> "foobar" + x
if (self.left instanceof AST_Constant
&& self.right instanceof AST_Binary
&& self.right.operator == "+"
right: self.right.right
});
}
- // (x + "foo") + "bar" => x + "foobar"
+ // (x + "foo") + "bar" ---> x + "foobar"
if (self.right instanceof AST_Constant
&& self.left instanceof AST_Binary
&& self.left.operator == "+"
})
});
}
- // a + -b => a - b
+ // a + -b ---> a - b
if (self.right instanceof AST_UnaryPrefix
&& self.right.operator == "-"
&& self.left.is_number(compressor)) {
});
break;
}
- // -a + b => b - a
+ // -a + b ---> b - a
if (self.left instanceof AST_UnaryPrefix
&& self.left.operator == "-"
&& reversible()
});
break;
}
- // (a + b) + 3 => 3 + (a + b)
+ // (a + b) + 3 ---> 3 + (a + b)
if (compressor.option("unsafe_math")
&& self.left instanceof AST_Binary
&& PRECEDENCE[self.left.operator] == PRECEDENCE[self.operator]
break;
}
case "-":
- // a - -b => a + b
+ // a - -b ---> a + b
if (self.right instanceof AST_UnaryPrefix
&& self.right.operator == "-"
&& self.left.is_number(compressor)
case "*":
case "/":
associative = compressor.option("unsafe_math");
- // +a - b => a - b
- // a - +b => a - b
+ // +a - b ---> a - b
+ // a - +b ---> a - b
if (self.operator != "+") [ "left", "right" ].forEach(function(operand) {
var node = self[operand];
if (node instanceof AST_UnaryPrefix && node.operator == "+") {
case "&":
case "|":
case "^":
- // a + +b => +b + a
+ // a + +b ---> +b + a
if (self.operator != "-"
&& self.operator != "/"
&& (self.left.is_boolean(compressor) || self.left.is_number(compressor))
}
}
if (!associative || !self.is_number(compressor)) break;
- // a + (b + c) => (a + b) + c
+ // a + (b + c) ---> (a + b) + c
if (self.right instanceof AST_Binary
&& self.right.operator != "%"
&& PRECEDENCE[self.right.operator] == PRECEDENCE[self.operator]
});
}
}
- // (2 * n) * 3 => 6 * n
- // (n + 2) + 3 => n + 5
+ // (2 * n) * 3 ---> 6 * n
+ // (n + 2) + 3 ---> n + 5
if (self.right instanceof AST_Constant
&& self.left instanceof AST_Binary
&& self.left.operator != "%"
}
if (!(parent instanceof AST_UnaryPrefix && parent.operator == "delete")) {
if (self.left instanceof AST_Number && !self.right.is_constant()) switch (self.operator) {
- // 0 + n => n
+ // 0 + n ---> n
case "+":
if (self.left.value == 0) {
if (self.right.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, {
if (self.right.is_number(compressor) && !self.right.is_negative_zero()) return self.right;
}
break;
- // 1 * n => n
+ // 1 * n ---> n
case "*":
if (self.left.value == 1) {
return self.right.is_number(compressor) ? self.right : make_node(AST_UnaryPrefix, self, {
break;
}
if (self.right instanceof AST_Number && !self.left.is_constant()) switch (self.operator) {
- // n + 0 => n
+ // n + 0 ---> n
case "+":
if (self.right.value == 0) {
if (self.left.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, {
if (self.left.is_number(compressor) && !self.left.is_negative_zero()) return self.left;
}
break;
- // n - 0 => n
+ // n - 0 ---> n
case "-":
if (self.right.value == 0) {
return self.left.is_number(compressor) ? self.left : make_node(AST_UnaryPrefix, self, {
}).optimize(compressor);
}
break;
- // n / 1 => n
+ // n / 1 ---> n
case "/":
if (self.right.value == 1) {
return self.left.is_number(compressor) ? self.left : make_node(AST_UnaryPrefix, self, {
function is_indexOf_match_pattern() {
switch (self.operator) {
case "<=":
- // 0 <= array.indexOf(string) => !!~array.indexOf(string)
+ // 0 <= array.indexOf(string) ---> !!~array.indexOf(string)
return indexRight && self.left instanceof AST_Number && self.left.value == 0;
case "<":
- // array.indexOf(string) < 0 => !~array.indexOf(string)
+ // array.indexOf(string) < 0 ---> !~array.indexOf(string)
if (indexLeft && self.right instanceof AST_Number && self.right.value == 0) return true;
- // -1 < array.indexOf(string) => !!~array.indexOf(string)
+ // -1 < array.indexOf(string) ---> !!~array.indexOf(string)
case "==":
case "!=":
- // -1 == array.indexOf(string) => !~array.indexOf(string)
- // -1 != array.indexOf(string) => !!~array.indexOf(string)
+ // -1 == array.indexOf(string) ---> !~array.indexOf(string)
+ // -1 != array.indexOf(string) ---> !!~array.indexOf(string)
if (!indexRight) return false;
return self.left instanceof AST_Number && self.left.value == -1
|| self.left instanceof AST_UnaryPrefix && self.left.operator == "-"
if (self.right.left instanceof AST_SymbolRef
&& self.right.left.name == self.left.name
&& ASSIGN_OPS[self.right.operator]) {
- // x = x - 2 => x -= 2
+ // x = x - 2 ---> x -= 2
return make_node(AST_Assign, self, {
operator: self.right.operator + "=",
left: self.left,
&& self.right.right.name == self.left.name
&& ASSIGN_OPS_COMMUTATIVE[self.right.operator]
&& !self.right.left.has_side_effects(compressor)) {
- // x = 2 & x => x &= 2
+ // x = 2 & x ---> x &= 2
return make_node(AST_Assign, self, {
operator: self.right.operator + "=",
left: self.left,
var consequent = self.consequent;
var alternative = self.alternative;
if (repeatable(compressor, condition)) {
- // x ? x : y => x || y
+ // x ? x : y ---> x || y
if (condition.equivalent_to(consequent)) return make_node(AST_Binary, self, {
operator: "||",
left: condition,
right: alternative,
}).optimize(compressor);
- // x ? y : x => x && y
+ // x ? y : x ---> x && y
if (condition.equivalent_to(alternative)) return make_node(AST_Binary, self, {
operator: "&&",
left: condition,
});
}
}
- // x ? y : y => x, y
+ // x ? y : y ---> x, y
if (consequent.equivalent_to(alternative)) return make_sequence(self, [
condition,
consequent
]).optimize(compressor);
- // x ? y.p : z.p => (x ? y : z).p
- // x ? y(a) : z(a) => (x ? y : z)(a)
- // x ? y.f(a) : z.f(a) => (x ? y : z).f(a)
+ // x ? y.p : z.p ---> (x ? y : z).p
+ // x ? y(a) : z(a) ---> (x ? y : z)(a)
+ // x ? y.f(a) : z.f(a) ---> (x ? y : z).f(a)
var combined = combine_tail(consequent, alternative, true);
if (combined) return combined;
- // x ? y(a) : y(b) => y(x ? a : b)
+ // x ? y(a) : y(b) ---> y(x ? a : b)
var arg_index;
if (consequent instanceof AST_Call
&& alternative.TYPE == consequent.TYPE
});
return node;
}
- // x ? (y ? a : b) : b => x && y ? a : b
+ // x ? (y ? a : b) : b ---> x && y ? a : b
if (consequent instanceof AST_Conditional
&& consequent.alternative.equivalent_to(alternative)) {
return make_node(AST_Conditional, self, {
alternative: alternative
});
}
- // x ? (y ? a : b) : a => !x || y ? a : b
+ // x ? (y ? a : b) : a ---> !x || y ? a : b
if (consequent instanceof AST_Conditional
&& consequent.consequent.equivalent_to(alternative)) {
return make_node(AST_Conditional, self, {
alternative: consequent.alternative
});
}
- // x ? a : (y ? a : b) => x || y ? a : b
+ // x ? a : (y ? a : b) ---> x || y ? a : b
if (alternative instanceof AST_Conditional
&& consequent.equivalent_to(alternative.consequent)) {
return make_node(AST_Conditional, self, {
alternative: alternative.alternative
});
}
- // x ? b : (y ? a : b) => !x && y ? a : b
+ // x ? b : (y ? a : b) ---> !x && y ? a : b
if (alternative instanceof AST_Conditional
&& consequent.equivalent_to(alternative.alternative)) {
return make_node(AST_Conditional, self, {
alternative: consequent
});
}
- // x ? (a, c) : (b, c) => x ? a : b, c
+ // x ? (a, c) : (b, c) ---> x ? a : b, c
if ((consequent instanceof AST_Sequence || alternative instanceof AST_Sequence)
&& consequent.tail_node().equivalent_to(alternative.tail_node())) {
return make_sequence(self, [
consequent.tail_node()
]).optimize(compressor);
}
- // x ? y && a : a => (!x || y) && a
+ // x ? y && a : a ---> (!x || y) && a
if (consequent instanceof AST_Binary
&& consequent.operator == "&&"
&& consequent.right.equivalent_to(alternative)) {
right: alternative
}).optimize(compressor);
}
- // x ? y || a : a => x && y || a
+ // x ? y || a : a ---> x && y || a
if (consequent instanceof AST_Binary
&& consequent.operator == "||"
&& consequent.right.equivalent_to(alternative)) {
right: alternative
}).optimize(compressor);
}
- // x ? a : y && a => (x || y) && a
+ // x ? a : y && a ---> (x || y) && a
if (alternative instanceof AST_Binary
&& alternative.operator == "&&"
&& alternative.right.equivalent_to(consequent)) {
right: consequent
}).optimize(compressor);
}
- // x ? a : y || a => !x && y || a
+ // x ? a : y || a ---> !x && y || a
if (alternative instanceof AST_Binary
&& alternative.operator == "||"
&& alternative.right.equivalent_to(consequent)) {
var in_bool = compressor.option("booleans") && compressor.in_boolean_context();
if (is_true(consequent)) {
if (is_false(alternative)) {
- // c ? true : false => !!c
+ // c ? true : false ---> !!c
return booleanize(condition);
}
- // c ? true : x => !!c || x
+ // c ? true : x ---> !!c || x
return make_node(AST_Binary, self, {
operator: "||",
left: booleanize(condition),
}
if (is_false(consequent)) {
if (is_true(alternative)) {
- // c ? false : true => !c
+ // c ? false : true ---> !c
return booleanize(condition.negate(compressor));
}
- // c ? false : x => !c && x
+ // c ? false : x ---> !c && x
return make_node(AST_Binary, self, {
operator: "&&",
left: booleanize(condition.negate(compressor)),
});
}
if (is_true(alternative)) {
- // c ? x : true => !c || x
+ // c ? x : true ---> !c || x
return make_node(AST_Binary, self, {
operator: "||",
left: booleanize(condition.negate(compressor)),
});
}
if (is_false(alternative)) {
- // c ? x : false => !!c && x
+ // c ? x : false ---> !!c && x
return make_node(AST_Binary, self, {
operator: "&&",
left: booleanize(condition),