diff --git a/crates/oxc_minifier/src/peephole/replace_known_methods.rs b/crates/oxc_minifier/src/peephole/replace_known_methods.rs index 686bdd16e6f57..e1463f8a6b831 100644 --- a/crates/oxc_minifier/src/peephole/replace_known_methods.rs +++ b/crates/oxc_minifier/src/peephole/replace_known_methods.rs @@ -23,6 +23,7 @@ impl<'a> PeepholeOptimizations { ) { self.try_fold_concat_chain(node, ctx); self.try_fold_known_string_methods(node, ctx); + self.try_fold_known_property_access(node, ctx); } fn try_fold_known_string_methods( @@ -472,6 +473,63 @@ impl<'a> PeepholeOptimizations { None } } + + fn try_fold_known_property_access( + &mut self, + node: &mut Expression<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + let (name, object, span) = match &node { + Expression::StaticMemberExpression(member) if !member.optional => { + (member.property.name.as_str(), &member.object, member.span) + } + Expression::ComputedMemberExpression(member) if !member.optional => { + match &member.expression { + Expression::StringLiteral(s) => (s.value.as_str(), &member.object, member.span), + _ => return, + } + } + _ => return, + }; + let replacement = match name { + "POSITIVE_INFINITY" | "NEGATIVE_INFINITY" | "NaN" => { + Self::try_fold_number_constants(object, name, span, ctx) + } + _ => None, + }; + if let Some(replacement) = replacement { + self.mark_current_function_as_changed(); + *node = replacement; + } + } + + /// replace `Number.*` constants + fn try_fold_number_constants( + object: &Expression<'a>, + name: &str, + span: Span, + ctx: &mut TraverseCtx<'a>, + ) -> Option> { + let ctx = Ctx(ctx); + let Expression::Identifier(ident) = object else { return None }; + if ident.name != "Number" || !ctx.is_global_reference(ident) { + return None; + } + + Some(match name { + "POSITIVE_INFINITY" => { + ctx.ast.expression_numeric_literal(span, f64::INFINITY, None, NumberBase::Decimal) + } + "NEGATIVE_INFINITY" => ctx.ast.expression_numeric_literal( + span, + f64::NEG_INFINITY, + None, + NumberBase::Decimal, + ), + "NaN" => ctx.ast.expression_numeric_literal(span, f64::NAN, None, NumberBase::Decimal), + _ => return None, + }) + } } /// Port from: @@ -1346,4 +1404,15 @@ mod test { test("1e99.toString(b)", "1e99.toString(b)"); test("/./.toString(b)", "/./.toString(b)"); } + + #[test] + fn test_number_constants() { + test("v = Number.POSITIVE_INFINITY", "v = Infinity"); + test("v = Number.NEGATIVE_INFINITY", "v = -Infinity"); + test("v = Number.NaN", "v = NaN"); + + test_same("Number.POSITIVE_INFINITY = 1"); + test_same("Number.NEGATIVE_INFINITY = 1"); + test_same("Number.NaN = 1"); + } } diff --git a/tasks/minsize/minsize.snap b/tasks/minsize/minsize.snap index 6e3e37eae0b43..e8495b1e4244f 100644 --- a/tasks/minsize/minsize.snap +++ b/tasks/minsize/minsize.snap @@ -17,11 +17,11 @@ Original | minified | minified | gzip | gzip | Fixture 1.25 MB | 652.85 kB | 646.76 kB | 163.53 kB | 163.73 kB | three.js -2.14 MB | 724 kB | 724.14 kB | 179.93 kB | 181.07 kB | victory.js +2.14 MB | 723.96 kB | 724.14 kB | 179.91 kB | 181.07 kB | victory.js -3.20 MB | 1.01 MB | 1.01 MB | 332.02 kB | 331.56 kB | echarts.js +3.20 MB | 1.01 MB | 1.01 MB | 331.98 kB | 331.56 kB | echarts.js 6.69 MB | 2.31 MB | 2.31 MB | 491.94 kB | 488.28 kB | antd.js -10.95 MB | 3.48 MB | 3.49 MB | 905.33 kB | 915.50 kB | typescript.js +10.95 MB | 3.48 MB | 3.49 MB | 905.29 kB | 915.50 kB | typescript.js