Skip to content

Commit ed9a2ee

Browse files
committed
fix(es/optimization): preserve JSON numeric values
1 parent c4b8684 commit ed9a2ee

4 files changed

Lines changed: 29 additions & 10 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
swc_core: patch
3+
swc_ecma_transforms_optimization: patch
4+
---
5+
6+
fix(es/optimization): Preserve large integers and negative zero in JSON literals.

crates/swc_ecma_transforms_optimization/src/json_parse.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,21 @@ fn wtf8_to_json_string(value: &Wtf8Atom) -> String {
116116
result
117117
}
118118

119+
/// Converts a finite ECMAScript number without using a saturating integer cast.
120+
///
121+
/// JSON-literal eligibility guarantees that `value` is finite.
122+
fn json_number(value: f64) -> serde_json::Number {
123+
let is_i64 = value.fract() == 0.0 && value >= i64::MIN as f64 && value < i64::MAX as f64;
124+
let preserves_zero_sign = value != 0.0 || value.is_sign_positive();
125+
126+
if is_i64 && preserves_zero_sign {
127+
return (value as i64).into();
128+
}
129+
130+
serde_json::Number::from_f64(value)
131+
.unwrap_or_else(|| unreachable!("non-finite numbers are not JSON literals"))
132+
}
133+
119134
fn jsonify(e: Expr) -> Value {
120135
match e {
121136
Expr::Object(obj) => Value::Object(
@@ -144,16 +159,7 @@ fn jsonify(e: Expr) -> Value {
144159
.collect(),
145160
),
146161
Expr::Lit(Lit::Str(Str { value, .. })) => Value::String(wtf8_to_json_string(&value)),
147-
Expr::Lit(Lit::Num(Number { value, .. })) => {
148-
if value.fract() == 0.0 {
149-
Value::Number((value as i64).into())
150-
} else {
151-
match serde_json::Number::from_f64(value) {
152-
Some(n) => Value::Number(n),
153-
None => Value::Number((value as i64).into()),
154-
}
155-
}
156-
}
162+
Expr::Lit(Lit::Num(Number { value, .. })) => Value::Number(json_number(value)),
157163
Expr::Lit(Lit::Null(..)) => Value::Null,
158164
Expr::Lit(Lit::Bool(v)) => Value::Bool(v.value),
159165
Expr::Tpl(Tpl { quasis, .. }) => Value::String(match quasis.first() {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const values = {
2+
smallInteger: 42,
3+
largeInteger: 1e21,
4+
i64Boundary: 9223372036854775808,
5+
negativeZero: -0,
6+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
const values = JSON.parse('{"i64Boundary":9.223372036854776e18,"largeInteger":1e21,"negativeZero":-0.0,"smallInteger":42}');

0 commit comments

Comments
 (0)