diff --git a/Cargo.toml b/Cargo.toml index f81b29ed7..1eff0ff66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,7 +98,6 @@ oxc_semantic = { version = "0.44.0", path = "crates/oxc_semantic" } oxc_span = { version = "0.44.0", path = "crates/oxc_span" } oxc_syntax = { version = "0.44.0", path = "crates/oxc_syntax" } oxc_transform_napi = { version = "0.44.0", path = "napi/transform" } -oxc_parser_napi = { version = "0.44.0", path = "napi/parser" } oxc_transformer = { version = "0.44.0", path = "crates/oxc_transformer" } oxc_traverse = { version = "0.44.0", path = "crates/oxc_traverse" } 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 81c52126a..0208c0c4b 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 @@ -97,6 +97,7 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax { Expression::NewExpression(e) => Self::try_fold_new_expression(e, ctx), Expression::TemplateLiteral(t) => Self::try_fold_template_literal(t, ctx), Expression::BinaryExpression(e) => Self::try_compress_typeof_undefined(e, ctx), + Expression::ConditionalExpression(e) => Self::try_compress_conditional(e, ctx), Expression::CallExpression(e) => { Self::try_fold_literal_constructor_call_expression(e, ctx) .or_else(|| Self::try_fold_simple_function_call(e, ctx)) @@ -265,6 +266,37 @@ impl<'a, 'b> PeepholeSubstituteAlternateSyntax { Some(ctx.ast.expression_binary(expr.span, left, new_comp_op, right)) } + fn try_compress_conditional( + expr: &mut ConditionalExpression<'a>, + ctx: Ctx<'a, 'b>, + ) -> Option> { + if let Expression::Identifier(ident_test) = &expr.test { + // `foo ? foo : bar` -> `foo || bar` + if let Expression::Identifier(ident_consequent) = &expr.consequent { + if ident_test.name == ident_consequent.name { + return Some(ctx.ast.expression_logical( + expr.span, + ctx.ast.move_expression(&mut expr.test), + LogicalOperator::Or, + ctx.ast.move_expression(&mut expr.alternate), + )); + } + } + // `foo ? bar : foo` -> `foo && bar` + if let Expression::Identifier(ident_alternate) = &expr.alternate { + if ident_test.name == ident_alternate.name { + return Some(ctx.ast.expression_logical( + expr.span, + ctx.ast.move_expression(&mut expr.test), + LogicalOperator::And, + ctx.ast.move_expression(&mut expr.consequent), + )); + } + } + } + None + } + /// Compress `foo === null || foo === undefined` into `foo == null`. /// /// `foo === null || foo === undefined` => `foo == null` @@ -1179,4 +1211,12 @@ mod test { test("typeof foo !== `number`", "typeof foo != 'number'"); test("`number` !== typeof foo", "typeof foo != 'number'"); } + + #[test] + fn compress_conditional() { + test("foo ? foo : bar", "foo || bar"); + test("foo ? bar : foo", "foo && bar"); + test_same("x.y ? x.y : bar"); + test_same("x.y ? bar : x.y"); + } } diff --git a/tasks/minsize/minsize.snap b/tasks/minsize/minsize.snap index b37893489..c7b5cabc4 100644 --- a/tasks/minsize/minsize.snap +++ b/tasks/minsize/minsize.snap @@ -7,13 +7,13 @@ Original | minified | minified | gzip | gzip | Fixture 287.63 kB | 90.16 kB | 90.07 kB | 32.08 kB | 31.95 kB | jquery.js -342.15 kB | 118.23 kB | 118.14 kB | 44.53 kB | 44.37 kB | vue.js +342.15 kB | 118.23 kB | 118.14 kB | 44.52 kB | 44.37 kB | vue.js 544.10 kB | 71.81 kB | 72.48 kB | 26.19 kB | 26.20 kB | lodash.js 555.77 kB | 273.19 kB | 270.13 kB | 90.99 kB | 90.80 kB | d3.js -1.01 MB | 460.32 kB | 458.89 kB | 126.85 kB | 126.71 kB | bundle.min.js +1.01 MB | 460.32 kB | 458.89 kB | 126.84 kB | 126.71 kB | bundle.min.js 1.25 MB | 652.73 kB | 646.76 kB | 163.55 kB | 163.73 kB | three.js @@ -23,5 +23,5 @@ Original | minified | minified | gzip | gzip | Fixture 6.69 MB | 2.32 MB | 2.31 MB | 492.81 kB | 488.28 kB | antd.js -10.95 MB | 3.50 MB | 3.49 MB | 909.54 kB | 915.50 kB | typescript.js +10.95 MB | 3.50 MB | 3.49 MB | 909.52 kB | 915.50 kB | typescript.js