Skip to content

Commit

Permalink
Commutative undefined minify (oxc-project#2003)
Browse files Browse the repository at this point in the history
this should probably be squashed, i'm not familiar with code commit
norms here. we can expand a bunch of the commutative compressions later.

---------

Co-authored-by: Boshen <boshenc@gmail.com>
  • Loading branch information
2 people authored and IWANABETHATGUY committed May 29, 2024
1 parent e5809cc commit 823eeec
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 13 deletions.
63 changes: 53 additions & 10 deletions crates/oxc_minifier/src/compressor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,20 +203,63 @@ impl<'a> Compressor<'a> {
/// Transforms `typeof foo == "undefined"` into `foo === void 0`
/// Enabled by `compress.typeofs`
fn compress_typeof_undefined(&self, expr: &mut BinaryExpression<'a>) {
if expr.operator.is_equality() && self.options.typeofs {
if let Expression::UnaryExpression(unary_expr) = &expr.left {
if unary_expr.operator == UnaryOperator::Typeof {
if let Expression::Identifier(ident) = &unary_expr.argument {
if expr.right.is_specific_string_literal("undefined") {
let left = self.ast.identifier_reference_expression((*ident).clone());
let right = self.ast.void_0();
let operator = BinaryOperator::StrictEquality;
*expr = BinaryExpression { span: SPAN, left, operator, right };
if !self.options.typeofs {
return;
}
match expr.operator {
BinaryOperator::Equality | BinaryOperator::StrictEquality => {
let pair = self.commutative_pair(
(&expr.left, &expr.right),
|a| {
if a.is_specific_string_literal("undefined") {
return Some(());
}
}
None
},
|b| {
if let Expression::UnaryExpression(op) = b {
if op.operator == UnaryOperator::Typeof {
if let Expression::Identifier(id) = &op.argument {
return Some((*id).clone());
}
}
}
None
},
);
if let Some((_void_exp, id_ref)) = pair {
let span = expr.span;
let left = self.ast.void_0();
let operator = BinaryOperator::StrictEquality;
let right = self.ast.identifier_reference_expression(id_ref);
let cmp = BinaryExpression { span, left, operator, right };
*expr = cmp;
}
}
_ => {}
};
}

fn commutative_pair<A, F, G, RetF: 'a, RetG: 'a>(
&self,
pair: (&A, &A),
check_a: F,
check_b: G,
) -> Option<(RetF, RetG)>
where
F: Fn(&A) -> Option<RetF>,
G: Fn(&A) -> Option<RetG>,
{
if let Some(a) = check_a(pair.0) {
if let Some(b) = check_b(pair.1) {
return Some((a, b));
}
} else if let Some(a) = check_a(pair.1) {
if let Some(b) = check_b(pair.0) {
return Some((a, b));
}
}
None
}

/// Removes redundant argument of `ReturnStatement`
Expand Down
6 changes: 3 additions & 3 deletions crates/oxc_minifier/tests/closure/fold_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,10 +286,10 @@ fn test_string_string_comparison() {
test("typeof function() {} < typeof function() {}", "!1;");
test("'a' == 'a'", "!0;");
test("'b' != 'a'", "!0;");
test_same("'undefined'==typeof a;");
// test_same("'undefined'==typeof a;"); // compresses to void 0 === a
test_same("typeof a!='number';");
test_same("'undefined'==typeof a;");
test_same("'undefined'==typeof a;");
// test_same("'undefined'==typeof a;"); // compresses to void 0 === a
// test_same("'undefined'==typeof a;"); // compresses to void 0 === a
test("typeof a == typeof a", "!0;");
test("'a' === 'a'", "!0;");
test("'b' !== 'a'", "!0;");
Expand Down
6 changes: 6 additions & 0 deletions crates/oxc_minifier/tests/oxc/folding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ fn addition_folding() {
test("x+''", "x+'';");
}

#[test]
fn typeof_folding() {
test("typeof x === 'undefined'", "void 0===x;");
test("'undefined' === typeof x", "void 0===x;");
}

#[test]
fn addition_folding_snapshots() {
test_snapshot(
Expand Down

0 comments on commit 823eeec

Please sign in to comment.