From 14d0590b0b339f4db4ab025ec3f054cf7fcf9a0e Mon Sep 17 00:00:00 2001 From: camc314 <18101008+camc314@users.noreply.github.com> Date: Sun, 13 Oct 2024 06:26:31 +0000 Subject: [PATCH] feat(minifier): implement folding of simple function calls (`Boolean`) (#6484) Basically `Boolean(true)` -> `true` or `Boolean(foo)` -> `!!foo` --- .../peephole_substitute_alternate_syntax.rs | 27 ++++++++++++++++--- tasks/minsize/minsize.snap | 6 ++--- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/crates/oxc_minifier/src/ast_passes/peephole_substitute_alternate_syntax.rs b/crates/oxc_minifier/src/ast_passes/peephole_substitute_alternate_syntax.rs index 18c6c2e35efba..422bd65296fed 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_substitute_alternate_syntax.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_substitute_alternate_syntax.rs @@ -466,8 +466,30 @@ impl<'a> PeepholeSubstituteAlternateSyntax { return None; } if call_expr.callee.is_global_reference_name("Boolean", ctx.symbols()) { - // TODO - None + // `Boolean(a)` -> `!!(a)` + // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-boolean-constructor-boolean-value + // and + // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-logical-not-operator-runtime-semantics-evaluation + + let arg = call_expr.arguments.get_mut(0).and_then(|arg| arg.as_expression_mut())?; + + if let Expression::UnaryExpression(unary_expr) = arg { + if unary_expr.operator == UnaryOperator::LogicalNot { + return Some(ctx.ast.move_expression(arg)); + } + } + + Some(ctx.ast.expression_from_unary(ctx.ast.unary_expression( + call_expr.span, + UnaryOperator::LogicalNot, + ctx.ast.expression_from_unary(ctx.ast.unary_expression( + call_expr.span, + UnaryOperator::LogicalNot, + ctx.ast.move_expression( + call_expr.arguments.get_mut(0).and_then(|arg| arg.as_expression_mut())?, + ), + )), + ))) } else if call_expr.callee.is_global_reference_name("String", ctx.symbols()) { // `String(a)` -> `'' + (a)` let arg = call_expr.arguments.get_mut(0).and_then(|arg| arg.as_expression_mut())?; @@ -881,7 +903,6 @@ mod test { } #[test] - #[ignore] fn test_simple_function_call2() { test("var a = Boolean(true)", "var a = !0"); // Don't fold the existence check to preserve behavior diff --git a/tasks/minsize/minsize.snap b/tasks/minsize/minsize.snap index 66e16e5f5fe4c..635e557b4dacc 100644 --- a/tasks/minsize/minsize.snap +++ b/tasks/minsize/minsize.snap @@ -12,15 +12,15 @@ Original | Minified | esbuild | Gzip | esbuild 555.77 kB | 278.22 kB | 270.13 kB | 91.36 kB | 90.80 kB | d3.js -1.01 MB | 470.08 kB | 458.89 kB | 126.96 kB | 126.71 kB | bundle.min.js +1.01 MB | 470.07 kB | 458.89 kB | 126.95 kB | 126.71 kB | bundle.min.js 1.25 MB | 670.94 kB | 646.76 kB | 164.72 kB | 163.73 kB | three.js -2.14 MB | 756.32 kB | 724.14 kB | 182.74 kB | 181.07 kB | victory.js +2.14 MB | 756.31 kB | 724.14 kB | 182.74 kB | 181.07 kB | victory.js 3.20 MB | 1.05 MB | 1.01 MB | 334.08 kB | 331.56 kB | echarts.js -6.69 MB | 2.44 MB | 2.31 MB | 498.88 kB | 488.28 kB | antd.js +6.69 MB | 2.44 MB | 2.31 MB | 498.86 kB | 488.28 kB | antd.js 10.95 MB | 3.59 MB | 3.49 MB | 913.91 kB | 915.50 kB | typescript.js