diff --git a/crates/oxc_ecmascript/src/constant_evaluation/value_type.rs b/crates/oxc_ecmascript/src/constant_evaluation/value_type.rs index 5812a21c92aa1..4873bf5e6eb80 100644 --- a/crates/oxc_ecmascript/src/constant_evaluation/value_type.rs +++ b/crates/oxc_ecmascript/src/constant_evaluation/value_type.rs @@ -44,6 +44,10 @@ impl ValueType { pub fn is_object(self) -> bool { self == Self::Object } + + pub fn is_undetermined(self) -> bool { + self == Self::Undetermined + } } /// `get_known_value_type` diff --git a/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs b/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs index 56feb06d586e7..67d94e76fc69d 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs @@ -2,6 +2,7 @@ use oxc_ast::ast::*; use oxc_ecmascript::{ constant_evaluation::{ConstantEvaluation, ConstantValue, ValueType}, side_effects::MayHaveSideEffects, + ToJsString, }; use oxc_span::{GetSpan, SPAN}; use oxc_syntax::{ @@ -35,7 +36,8 @@ impl<'a> Traverse<'a> for PeepholeFoldConstants { Expression::StaticMemberExpression(e) => Self::try_fold_static_member_expr(e, ctx), Expression::LogicalExpression(e) => Self::try_fold_logical_expr(e, ctx), Expression::ChainExpression(e) => Self::try_fold_optional_chain(e, ctx), - Expression::CallExpression(e) => Self::try_fold_number_constructor(e, ctx), + Expression::CallExpression(e) => Self::try_fold_number_constructor(e, ctx) + .or_else(|| Self::try_fold_to_string(e, ctx)), _ => None, } { *expr = folded_expr; @@ -601,6 +603,26 @@ impl<'a, 'b> PeepholeFoldConstants { }), )) } + + fn try_fold_to_string(e: &CallExpression<'a>, ctx: Ctx<'a, 'b>) -> Option> { + let Expression::StaticMemberExpression(member_expr) = &e.callee else { return None }; + if member_expr.property.name != "toString" { + return None; + } + if !e.arguments.is_empty() { + return None; + } + let object = &member_expr.object; + if !matches!( + ValueType::from(object), + ValueType::String | ValueType::Boolean | ValueType::Number + ) { + return None; + } + object + .to_js_string() + .map(|value| ctx.ast.expression_string_literal(object.span(), value, None)) + } } /// @@ -1733,4 +1755,12 @@ mod test { test("Number('1')", "1"); test_same("var Number; Number(1)"); } + + #[test] + fn test_fold_to_string() { + test("'x'.toString()", "'x'"); + test("1 .toString()", "'1'"); + test("true.toString()", "'true'"); + test("false.toString()", "'false'"); + } }