Repository: swc-project/swc (rust)

Issue:
Minification of `(-(-'0x1000000000000081')).toString(16)` is wrong
### Describe the bug

Follow-up of https://github.com/swc-project/swc/pull/6960#discussion_r1111244201

### Input code

```typescript
assertEquals("1000000000000100", (-(-'0x1000000000000081')).toString(16));
```


### Config

```json
{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": false
    },
    "target": "es2022",
    "loose": false,
    "minify": {
      "compress": {
        "arguments": false,
        "arrows": true,
        "booleans": true,
        "booleans_as_integers": false,
        "collapse_vars": true,
        "comparisons": true,
        "computed_props": true,
        "conditionals": true,
        "dead_code": true,
        "directives": true,
        "drop_console": false,
        "drop_debugger": true,
        "evaluate": true,
        "expression": false,
        "hoist_funs": false,
        "hoist_props": true,
        "hoist_vars": false,
        "if_return": true,
        "join_vars": true,
        "keep_classnames": false,
        "keep_fargs": true,
        "keep_fnames": false,
        "keep_infinity": false,
        "loops": true,
        "negate_iife": true,
        "properties": true,
        "reduce_funcs": false,
        "reduce_vars": false,
        "side_effects": true,
        "switches": true,
        "typeofs": true,
        "unsafe": false,
        "unsafe_arrows": false,
        "unsafe_comps": false,
        "unsafe_Function": false,
        "unsafe_math": false,
        "unsafe_symbols": false,
        "unsafe_methods": false,
        "unsafe_proto": false,
        "unsafe_regexp": false,
        "unsafe_undefined": false,
        "unused": true,
        "const_to_let": true,
        "pristine_globals": true
      },
      "mangle": false
    }
  },
  "module": {
    "type": "es6"
  },
  "minify": false,
  "isModule": true
}
```


### Playground link

https://play.swc.rs/?version=1.3.35&code=H4sIAAAAAAAAA0ssLk4tKnEtLE3MKdZQMjRAAkCOko6Chq6GrrpBBYqMgYWhuqamXkl%2BcElRZl66hqGZpqY1AAUpUdlKAAAA&config=H4sIAAAAAAAAA22TQZLjIAxF78K6F11ZzKIP0Ls%2BA0VAOGQwciGRjiuVu49wbIiT2VnPX0J8iZs6k1VfNzWZTJDrF82JzVV9KZ4nIJvDxOpDMQnyJhLcJTB5ABYJ0OHzcJDfEZFgFXyoMaTg51rM4jhlIKrfklRGSExNZ3LGXwk5F4mOiBFMeou1IR0SwwC5p1qM0UwE%2BmJyy6inmRwI0w4VBqenjNMTTS5wwCTFNubAOG3RQQMhg%2BVwgS6RGiJJJI21Thbo4FiGoRr4UMLFxGK41YLrYoOc2PJOGIi1L4le0K7TB3pcclUFrzNwyWnTnDGknQ9%2FAaTPaIiSGaFnLtzLHPZK%2Fx9VSF6GyHOjMuHeVYJBLqdD8O2GtWvIHLpbGVyxUG9oe%2FEV7i5EwYEG78Xtlky%2Fge2pF6vLiL6F4prxfQaPUG%2F7tKd1Bd7gt3TFz%2BNY%2BWj49MpoHo8Y30qMwCd0b1iMYHyFWbb3Or3SkhyIzeCefhSqYVtTGT6jjvW1bT7LQkiOHiIe2%2FrKoxxNGtpa3itAVyq4LeYtr%2FWPuvfXua0T%2FazCpdA%2FOW4Z9xIEAAA%3D

### Expected behavior

It should be identical

### Actual behavior

_No response_

### Version

1.3.35

### Additional context

_No response_

Pull request:
fix(es/minifier): optimize expr in num context
<!-- Note: CI script will automatically rebase your PR so please do not rebase unless required -->

<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. -->

**Description:**

<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->

**BREAKING CHANGE:**

<!--
If this PR introduces a breaking change, it must contain a notice for it to be included in the CHANGELOG. Add description or remove entirely if not breaking.

You may need to update `MIGRATION.md` for the breaking changes.
-->

**Related issue (if exists):**
- fix #6964 

Patch:
diff --git a/crates/swc_ecma_minifier/src/compress/pure/numbers.rs b/crates/swc_ecma_minifier/src/compress/pure/numbers.rs
index b2a782cd5e..25440a3f6d 100644
--- a/crates/swc_ecma_minifier/src/compress/pure/numbers.rs
+++ b/crates/swc_ecma_minifier/src/compress/pure/numbers.rs
@@ -1,12 +1,20 @@
 use swc_common::util::take::Take;
 use swc_ecma_ast::*;
+use swc_ecma_utils::num_from_str;
 
 use super::Pure;
 
 impl Pure<'_> {
     pub(super) fn optimize_expr_in_num_ctx(&mut self, e: &mut Expr) {
         if let Expr::Lit(Lit::Str(Str { span, value, .. })) = e {
-            let value = if value.is_empty() { 0f64 } else { 1f64 };
+            let value = if value.is_empty() {
+                0f64
+            } else {
+                match num_from_str(value).into_result() {
+                    Ok(f) if f.is_finite() => f,
+                    _ => return,
+                }
+            };
 
             self.changed = true;
             report_change!("numbers: Converting a string literal to {:?}", value);
diff --git a/crates/swc_ecma_utils/src/lib.rs b/crates/swc_ecma_utils/src/lib.rs
index 4ac50f0342..6d3e9a5c96 100644
--- a/crates/swc_ecma_utils/src/lib.rs
+++ b/crates/swc_ecma_utils/src/lib.rs
@@ -1575,7 +1575,7 @@ fn may_be_str(ty: Value<Type>) -> bool {
     }
 }
 
-fn num_from_str(s: &str) -> Value<f64> {
+pub fn num_from_str(s: &str) -> Value<f64> {
     if s.contains('\u{000b}') {
         return Unknown;
     }
@@ -1587,11 +1587,28 @@ fn num_from_str(s: &str) -> Value<f64> {
         return Known(0.0);
     }
 
-    if s.starts_with("0x") || s.starts_with("0X") {
-        return match s[2..4].parse() {
-            Ok(n) => Known(n),
-            Err(_) => Known(NAN),
-        };
+    if s.len() >= 2 {
+        match &s.as_bytes()[..2] {
+            b"0x" | b"0X" => {
+                return match u64::from_str_radix(&s[2..], 16) {
+                    Ok(n) => Known(n as f64),
+                    Err(_) => Known(NAN),
+                }
+            }
+            b"0o" | b"0O" => {
+                return match u64::from_str_radix(&s[2..], 8) {
+                    Ok(n) => Known(n as f64),
+                    Err(_) => Known(NAN),
+                };
+            }
+            b"0b" | b"0B" => {
+                return match u64::from_str_radix(&s[2..], 2) {
+                    Ok(n) => Known(n as f64),
+                    Err(_) => Known(NAN),
+                };
+            }
+            _ => {}
+        }
     }
 
     if (s.starts_with('-') || s.starts_with('+'))


Test patch:
diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/6957/number-tostring/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/6957/number-tostring/output.js
index 11f1f783c4..9daa869690 100644
--- a/crates/swc_ecma_minifier/tests/fixture/issues/6957/number-tostring/output.js
+++ b/crates/swc_ecma_minifier/tests/fixture/issues/6957/number-tostring/output.js
@@ -88,9 +88,9 @@ assertEquals("0", "0");
 assertEquals("100000000000000000000000000000000", "100000000000000000000000000000000");
 assertEquals("100000000000000000000000000000001", "100000000000000000000000000000001");
 assertEquals("100000000000080", "100000000000080");
-assertEquals("1000000000000100", "1");
-assertEquals("1000000000000000", "1");
-assertEquals("1000000000000000", "1");
+assertEquals("1000000000000100", "1000000000000100");
+assertEquals("1000000000000000", "1000000000000000");
+assertEquals("1000000000000000", "1000000000000000");
 assertEquals("100000000000000000000000000000000000000000000000010000000", "100000000000000000000000000000000000000000000000010000000");
 assertEquals("-11111111111111111111111111111111", "-11111111111111111111111111111111");
 assertEquals("-5yc1z", "-5yc1z");