From 9382bda786613abf15cecb0bf3531dd68bb6166b Mon Sep 17 00:00:00 2001 From: magic-akari Date: Sun, 19 Feb 2023 22:18:14 +0800 Subject: [PATCH] fix(es/minifier): Fix `toFixed`, `toPrecision`, `toExponential` and `toString` of Number (#6960) --- .prettierignore | 1 + Cargo.lock | 7 + .../arrowFunctionExpressions.2.minified.js | 1 - .../numberPropertyAccess.2.minified.js | 2 +- crates/swc_ecma_minifier/Cargo.toml | 1 + .../src/compress/pure/evaluate.rs | 399 ++++++++++++++++-- .../tests/fixture/issues/2257/full/output.js | 2 +- .../tests/fixture/issues/6957/1/config.json | 46 ++ .../tests/fixture/issues/6957/1/input.js | 21 + .../tests/fixture/issues/6957/1/output.js | 19 + .../issues/6957/exponential/config.json | 46 ++ .../fixture/issues/6957/exponential/input.js | 108 +++++ .../fixture/issues/6957/exponential/output.js | 74 ++++ .../issues/6957/number-tostring/config.json | 46 ++ .../issues/6957/number-tostring/input.js | 344 +++++++++++++++ .../issues/6957/number-tostring/output.js | 291 +++++++++++++ .../compress/evaluate/issue_2207_1/output.js | 2 +- crates/swc_ecma_transforms_base/src/fixer.rs | 7 + 18 files changed, 1373 insertions(+), 44 deletions(-) create mode 100644 crates/swc_ecma_minifier/tests/fixture/issues/6957/1/config.json create mode 100644 crates/swc_ecma_minifier/tests/fixture/issues/6957/1/input.js create mode 100644 crates/swc_ecma_minifier/tests/fixture/issues/6957/1/output.js create mode 100644 crates/swc_ecma_minifier/tests/fixture/issues/6957/exponential/config.json create mode 100644 crates/swc_ecma_minifier/tests/fixture/issues/6957/exponential/input.js create mode 100644 crates/swc_ecma_minifier/tests/fixture/issues/6957/exponential/output.js create mode 100644 crates/swc_ecma_minifier/tests/fixture/issues/6957/number-tostring/config.json create mode 100644 crates/swc_ecma_minifier/tests/fixture/issues/6957/number-tostring/input.js create mode 100644 crates/swc_ecma_minifier/tests/fixture/issues/6957/number-tostring/output.js diff --git a/.prettierignore b/.prettierignore index 9d7a7a820cb0..4f510488982a 100644 --- a/.prettierignore +++ b/.prettierignore @@ -19,6 +19,7 @@ crates/swc_css_parser/tests/ crates/swc_css_prefixer/tests/ crates/swc_ecma_codegen/tests/ crates/swc_ecma_lints/tests/ +crates/swc_ecma_minifier/tests/ crates/swc_ecma_parser/tests/ crates/swc_estree_compat/tests/ crates/swc_html_codegen/tests/ diff --git a/Cargo.lock b/Cargo.lock index 2bc15aabc0d8..e71e6df25b1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2676,6 +2676,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +[[package]] +name = "ryu-js" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6518fc26bced4d53678a22d6e423e9d8716377def84545fe328236e3af070e7f" + [[package]] name = "same-file" version = "1.0.6" @@ -3682,6 +3688,7 @@ dependencies = [ "rayon", "regex", "rustc-hash", + "ryu-js", "serde", "serde_json", "swc_atoms", diff --git a/crates/swc/tests/tsc-references/arrowFunctionExpressions.2.minified.js b/crates/swc/tests/tsc-references/arrowFunctionExpressions.2.minified.js index b23e2ed8dca3..9cba05a91f78 100644 --- a/crates/swc/tests/tsc-references/arrowFunctionExpressions.2.minified.js +++ b/crates/swc/tests/tsc-references/arrowFunctionExpressions.2.minified.js @@ -2,4 +2,3 @@ import _class_call_check from "@swc/helpers/src/_class_call_check.mjs"; import _sliced_to_array from "@swc/helpers/src/_sliced_to_array.mjs"; import _to_array from "@swc/helpers/src/_to_array.mjs"; -0..toExponential(); diff --git a/crates/swc/tests/tsc-references/numberPropertyAccess.2.minified.js b/crates/swc/tests/tsc-references/numberPropertyAccess.2.minified.js index 8257fecd5e9f..b38a4bc3c537 100644 --- a/crates/swc/tests/tsc-references/numberPropertyAccess.2.minified.js +++ b/crates/swc/tests/tsc-references/numberPropertyAccess.2.minified.js @@ -1,2 +1,2 @@ //// [numberPropertyAccess.ts] -1..toExponential(), 1..hasOwnProperty("toFixed"), 1..toExponential(), 1..hasOwnProperty("toFixed"); +1..hasOwnProperty("toFixed"), 1..hasOwnProperty("toFixed"); diff --git a/crates/swc_ecma_minifier/Cargo.toml b/crates/swc_ecma_minifier/Cargo.toml index dceb6e34577e..b27c3bda741f 100644 --- a/crates/swc_ecma_minifier/Cargo.toml +++ b/crates/swc_ecma_minifier/Cargo.toml @@ -42,6 +42,7 @@ radix_fmt = "=1.0.0" rayon = {version = "1.5.1", optional = true} regex = "1.5.3" rustc-hash = "1.1.0" +ryu-js = "0.2.2" serde = {version = "1.0.118", features = ["derive"]} serde_json = "1.0.61" swc_atoms = {version = "0.4.36", path = "../swc_atoms"} diff --git a/crates/swc_ecma_minifier/src/compress/pure/evaluate.rs b/crates/swc_ecma_minifier/src/compress/pure/evaluate.rs index b0b0cc2a1990..4e7230e59888 100644 --- a/crates/swc_ecma_minifier/src/compress/pure/evaluate.rs +++ b/crates/swc_ecma_minifier/src/compress/pure/evaluate.rs @@ -315,45 +315,212 @@ impl Pure<'_> { } if &*method.sym == "toFixed" { + // https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-number.prototype.tofixed + // + // Note 1: This method returns a String containing this Number value represented + // in decimal fixed-point notation with fractionDigits digits after the decimal + // point. If fractionDigits is undefined, 0 is assumed. + + // Note 2: The output of toFixed may be more precise than toString for some + // values because toString only prints enough significant digits to distinguish + // the number from adjacent Number values. For example, + // + // (1000000000000000128).toString() returns "1000000000000000100", while + // (1000000000000000128).toFixed(0) returns "1000000000000000128". + + // 1. Let x be ? thisNumberValue(this value). + // 2. Let f be ? ToIntegerOrInfinity(fractionDigits). if let Some(precision) = args .first() - // https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-number.prototype.tofixed // 3. Assert: If fractionDigits is undefined, then f is 0. .map_or(Some(0f64), |arg| eval_as_number(&self.expr_ctx, &arg.expr)) { - if precision.fract() == 0.0 { - let precision = precision.floor() as usize; - let value = num_to_fixed(num.value, precision + 1); + let f = precision.trunc() as usize; - self.changed = true; - report_change!( - "evaluate: Evaluating `{}.toFixed({})` as `{}`", - num, - precision, - value - ); + // 4. If f is not finite, throw a RangeError exception. + // 5. If f < 0 or f > 100, throw a RangeError exception. - *e = Expr::Lit(Lit::Str(Str { - span: e.span(), - raw: None, - value: value.into(), - })); + // Note: ES2018 increased the maximum number of fraction digits from 20 to 100. + // It relies on runtime behavior. + if !(0..=20).contains(&f) { + return; } + + // 6. If x is not finite, return Number::toString(x, 10). + + let x = { + let x = num.value; + // 7. Set x to ℝ(x). + if x == -0. { + 0. + } else { + x + } + }; + // 8. Let s be the empty String. + // 9. If x < 0, then + // a. Set s to "-". + // b. Set x to -x. + // 10. If x ≥ 10**21, then + // a. Let m be ! ToString(𝔽(x)). + let value = if x >= 1e21 || x <= -1e21 { + format!("{:e}", x).replace('e', "e+") + } else { + // 11. Else, + + if x.fract() != 0. && f != 0 { + // TODO: rust built-in format cannot handle ecma262 `1.25.toFixed(1)` + + return; + } else { + format!("{:.*}", f, x) + } + }; + + self.changed = true; + report_change!( + "evaluate: Evaluating `{}.toFixed({})` as `{}`", + num, + precision, + value + ); + + *e = Expr::Lit(Lit::Str(Str { + span: e.span(), + raw: None, + value: value.into(), + })); } return; } + if &*method.sym == "toPrecision" { + // TODO: handle num.toPrecision(undefined) + if args.first().is_none() { + // https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-number.prototype.toprecision + // 2. If precision is undefined, return ! ToString(x). + let value = ryu_js::Buffer::new().format(num.value).to_string().into(); + + self.changed = true; + report_change!( + "evaluate: Evaluating `{}.toPrecision()` as `{}`", + num, + value + ); + + *e = Expr::Lit(Lit::Str(Str { + span: e.span(), + raw: None, + value, + })); + return; + } + + if let Some(precision) = args + .first() + .and_then(|arg| eval_as_number(&self.expr_ctx, &arg.expr)) + { + let p = precision.trunc() as usize; + // 5. If p < 1 or p > 100, throw a RangeError exception. + if !(1..=21).contains(&p) { + return; + } + + let value = f64_to_precision(num.value, p); + self.changed = true; + report_change!( + "evaluate: Evaluating `{}.toPrecision()` as `{}`", + num, + value + ); + *e = Expr::Lit(Lit::Str(Str { + span: e.span(), + raw: None, + value: value.into(), + })); + return; + } + } + + if &*method.sym == "toExponential" { + // TODO: handle num.toExponential(undefined) + if args.first().is_none() { + let value = f64_to_exponential(num.value).into(); + + self.changed = true; + report_change!( + "evaluate: Evaluating `{}.toExponential()` as `{}`", + num, + value + ); + + *e = Expr::Lit(Lit::Str(Str { + span: e.span(), + raw: None, + value, + })); + return; + } else if let Some(precision) = args + .first() + .and_then(|arg| eval_as_number(&self.expr_ctx, &arg.expr)) + { + let p = precision.trunc() as usize; + // 5. If p < 1 or p > 100, throw a RangeError exception. + if !(0..=20).contains(&p) { + return; + } + + let value = f64_to_exponential_with_precision(num.value, p).into(); + + self.changed = true; + report_change!( + "evaluate: Evaluating `{}.toPrecision({})` as `{}`", + num, + precision, + value + ); + + *e = Expr::Lit(Lit::Str(Str { + span: e.span(), + raw: None, + value, + })); + return; + } + } + if &*method.sym == "toString" { if let Some(base) = args .first() .map_or(Some(10f64), |arg| eval_as_number(&self.expr_ctx, &arg.expr)) { + if base.trunc() == 10. { + let value = ryu_js::Buffer::new().format(num.value).to_string().into(); + *e = Expr::Lit(Lit::Str(Str { + span: e.span(), + raw: None, + value, + })); + return; + } + if num.value.fract() == 0.0 && (2.0..=36.0).contains(&base) && base.fract() == 0.0 { let base = base.floor() as u8; self.changed = true; - let value = Radix::new(num.value as usize, base).to_string().into(); + + let value = { + let x = num.value; + if x < 0. { + // I don't know if u128 is really needed, but it works. + format!("-{}", Radix::new(-x as u128, base)) + } else { + Radix::new(x as u128, base).to_string() + } + } + .into(); + *e = Expr::Lit(Lit::Str(Str { span: e.span(), raw: None, @@ -603,31 +770,183 @@ impl Pure<'_> { } } -/// https://stackoverflow.com/questions/60497397/how-do-you-format-a-float-to-the-first-significant-decimal-and-with-specified-pr -fn num_to_fixed(float: f64, precision: usize) -> String { - // compute absolute value - let a = float.abs(); - - // if abs value is greater than 1, then precision becomes less than "standard" - let precision = if a >= 1. { - // reduce by number of digits, minimum 0 - let n = (1. + a.log10().floor()) as usize; - if n <= precision { - precision - n +// Code from boa +// https://github.com/boa-dev/boa/blob/f8b682085d7fe0bbfcd0333038e93cf2f5aee710/boa_engine/src/builtins/number/mod.rs#L408 +fn f64_to_precision(value: f64, precision: usize) -> String { + let mut x = value; + let p_i32 = precision as i32; + + // 7. Let s be the empty String. + let mut s = String::new(); + let mut m: String; + let mut e: i32; + + // 8. If x < 0, then + // a. Set s to the code unit 0x002D (HYPHEN-MINUS). + // b. Set x to -x. + if x < 0. { + s.push('-'); + x = -x; + } + + // 9. If x = 0, then + // a. Let m be the String value consisting of p occurrences of the code unit + // 0x0030 (DIGIT ZERO). + // b. Let e be 0. + if x == 0.0 { + m = "0".repeat(precision); + e = 0; + // 10 + } else { + // Due to f64 limitations, this part differs a bit from the spec, + // but has the same effect. It manipulates the string constructed + // by `format`: digits with an optional dot between two of them. + m = format!("{x:.100}"); + + // a: getting an exponent + e = flt_str_to_exp(&m); + // b: getting relevant digits only + if e < 0 { + m = m.split_off((1 - e) as usize); + } else if let Some(n) = m.find('.') { + m.remove(n); + } + // impl: having exactly `precision` digits in `suffix` + if round_to_precision(&mut m, precision) { + e += 1; + } + + // c: switching to scientific notation + let great_exp = e >= p_i32; + if e < -6 || great_exp { + assert_ne!(e, 0); + + // ii + if precision > 1 { + m.insert(1, '.'); + } + // vi + m.push('e'); + // iii + if great_exp { + m.push('+'); + } + // iv, v + m.push_str(&e.to_string()); + + return s + &m; + } + } + + // 11 + let e_inc = e + 1; + if e_inc == p_i32 { + return s + &m; + } + + // 12 + if e >= 0 { + m.insert(e_inc as usize, '.'); + // 13 + } else { + s.push('0'); + s.push('.'); + s.push_str(&"0".repeat(-e_inc as usize)); + } + + // 14 + s + &m +} + +fn flt_str_to_exp(flt: &str) -> i32 { + let mut non_zero_encountered = false; + let mut dot_encountered = false; + for (i, c) in flt.chars().enumerate() { + if c == '.' { + if non_zero_encountered { + return (i as i32) - 1; + } + dot_encountered = true; + } else if c != '0' { + if dot_encountered { + return 1 - (i as i32); + } + non_zero_encountered = true; + } + } + (flt.len() as i32) - 1 +} + +fn round_to_precision(digits: &mut String, precision: usize) -> bool { + if digits.len() > precision { + let to_round = digits.split_off(precision); + let mut digit = digits + .pop() + .expect("already checked that length is bigger than precision") + as u8; + if let Some(first) = to_round.chars().next() { + if first > '4' { + digit += 1; + } + } + + if digit as char == ':' { + // ':' is '9' + 1 + // need to propagate the increment backward + let mut replacement = String::from("0"); + let mut propagated = false; + for c in digits.chars().rev() { + let d = match (c, propagated) { + ('0'..='8', false) => (c as u8 + 1) as char, + (_, false) => '0', + (_, true) => c, + }; + replacement.push(d); + if d != '0' { + propagated = true; + } + } + digits.clear(); + let replacement = if propagated { + replacement.as_str() + } else { + digits.push('1'); + &replacement.as_str()[1..] + }; + for c in replacement.chars().rev() { + digits.push(c); + } + !propagated } else { - 0 + digits.push(digit as char); + false } - // if precision is less than 1 (but non-zero), then precision becomes - // greater than "standard" - } else if a > 0. { - // increase number of digits - let n = -(1. + a.log10().floor()) as usize; - precision + n - // special case for 0 } else { - 0 - }; + digits.push_str(&"0".repeat(precision - digits.len())); + false + } +} + +/// Helper function that formats a float as a ES6-style exponential number +/// string. +fn f64_to_exponential(n: f64) -> String { + match n.abs() { + x if x >= 1.0 || x == 0.0 => format!("{n:e}").replace('e', "e+"), + _ => format!("{n:e}"), + } +} - // format with the given computed precision - format!("{0:.1$}", float, precision) +/// Helper function that formats a float as a ES6-style exponential number +/// string with a given precision. +// We can't use the same approach as in `f64_to_exponential` +// because in cases like (0.999).toExponential(0) the result will be 1e0. +// Instead we get the index of 'e', and if the next character is not '-' +// we insert the plus sign +fn f64_to_exponential_with_precision(n: f64, prec: usize) -> String { + let mut res = format!("{n:.prec$e}"); + let idx = res.find('e').expect("'e' not found in exponential string"); + if res.as_bytes()[idx + 1] != b'-' { + res.insert(idx + 1, '+'); + } + res } diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/2257/full/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/2257/full/output.js index f1fee14d4579..0f4276bc39f6 100644 --- a/crates/swc_ecma_minifier/tests/fixture/issues/2257/full/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/issues/2257/full/output.js @@ -6018,7 +6018,7 @@ $({ target: "Number", proto: !0, - forced: nativeToFixed && !0 || !fails(function() { + forced: nativeToFixed && ("0.000" !== 0.00008.toFixed(3) || "1.25" !== 1.255.toFixed(2)) || !fails(function() { nativeToFixed.call({}); }) }, { diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/6957/1/config.json b/crates/swc_ecma_minifier/tests/fixture/issues/6957/1/config.json new file mode 100644 index 000000000000..b38da13846ff --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/6957/1/config.json @@ -0,0 +1,46 @@ +{ + "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 +} \ No newline at end of file diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/6957/1/input.js b/crates/swc_ecma_minifier/tests/fixture/issues/6957/1/input.js new file mode 100644 index 000000000000..12189af2bef7 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/6957/1/input.js @@ -0,0 +1,21 @@ +// prettier-ignore +export function foo() { + // actual | expected + alert(1..toFixed(1)) // '1.0' '1.0' + alert(0..toFixed(0)) // '0' '0' + alert(0..toFixed(1)) // '0' '0.0' + alert(0..toFixed(2)) // '0' '0.00' + alert(0..toFixed(3)) // '0' '0.000' + alert(10..toFixed(1)) // '10' '10.0' + alert(20..toFixed(2)) // '20.0' '20.00' + alert(30..toFixed(3)) // '30.00' '30.000' + alert(100..toFixed(1)) // '100' '100.0' + alert(100..toFixed(2)) // '100' '100.00' + alert(100..toFixed(3)) // '100.0' '100.000' + alert(110..toFixed(1)) // '110' '110.0' + alert(110..toFixed(2)) // '110' '110.00' + alert(110..toFixed(3)) // '110.0' '110.000' + alert(110..toFixed(4)) // '110.00' '110.000' + alert(1110..toFixed(4)) // '1110.0' '1110.0000' + alert(11110..toFixed(4)) // '11110' '11110.0000' +} diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/6957/1/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/6957/1/output.js new file mode 100644 index 000000000000..22c7a794b406 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/6957/1/output.js @@ -0,0 +1,19 @@ +export function foo() { + alert("1.0"); + alert("0"); + alert("0.0"); + alert("0.00"); + alert("0.000"); + alert("10.0"); + alert("20.00"); + alert("30.000"); + alert("100.0"); + alert("100.00"); + alert("100.000"); + alert("110.0"); + alert("110.00"); + alert("110.000"); + alert("110.0000"); + alert("1110.0000"); + alert("11110.0000"); +} diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/6957/exponential/config.json b/crates/swc_ecma_minifier/tests/fixture/issues/6957/exponential/config.json new file mode 100644 index 000000000000..b38da13846ff --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/6957/exponential/config.json @@ -0,0 +1,46 @@ +{ + "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 +} \ No newline at end of file diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/6957/exponential/input.js b/crates/swc_ecma_minifier/tests/fixture/issues/6957/exponential/input.js new file mode 100644 index 000000000000..af862199aa09 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/6957/exponential/input.js @@ -0,0 +1,108 @@ +// Copyright (C) 2016 The V8 Project authors. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-number.prototype.toprecision +description: > + Return string values using exponential character +info: | + Number.prototype.toPrecision ( precision ) + + 1. Let x be ? thisNumberValue(this value). + [...] + 5. Let s be the empty String. + [...] + 9. If x = 0, then + [...] + 10. Else x ≠ 0, + [...] + c. If e < -6 or e ≥ p, then + [...] + vii. Return the concatenation of s, m, code unit 0x0065 (LATIN SMALL + LETTER E), c, and d. + [...] +---*/ + +assert.sameValue((10).toPrecision(1), "1e+1"); +assert.sameValue((11).toPrecision(1), "1e+1"); +assert.sameValue((17).toPrecision(1), "2e+1"); +assert.sameValue((19).toPrecision(1), "2e+1"); +assert.sameValue((20).toPrecision(1), "2e+1"); + +assert.sameValue((100).toPrecision(1), "1e+2"); +assert.sameValue((1000).toPrecision(1), "1e+3"); +assert.sameValue((10000).toPrecision(1), "1e+4"); +assert.sameValue((100000).toPrecision(1), "1e+5"); + +assert.sameValue((100).toPrecision(2), "1.0e+2"); +assert.sameValue((1000).toPrecision(2), "1.0e+3"); +assert.sameValue((10000).toPrecision(2), "1.0e+4"); +assert.sameValue((100000).toPrecision(2), "1.0e+5"); + +assert.sameValue((1000).toPrecision(3), "1.00e+3"); +assert.sameValue((10000).toPrecision(3), "1.00e+4"); +assert.sameValue((100000).toPrecision(3), "1.00e+5"); + +assert.sameValue((42).toPrecision(1), "4e+1"); +assert.sameValue((-42).toPrecision(1), "-4e+1"); + +assert.sameValue((1.2345e+27).toPrecision(1), "1e+27"); +assert.sameValue((1.2345e+27).toPrecision(2), "1.2e+27"); +assert.sameValue((1.2345e+27).toPrecision(3), "1.23e+27"); +assert.sameValue((1.2345e+27).toPrecision(4), "1.234e+27"); +assert.sameValue((1.2345e+27).toPrecision(5), "1.2345e+27"); +assert.sameValue((1.2345e+27).toPrecision(6), "1.23450e+27"); +assert.sameValue((1.2345e+27).toPrecision(7), "1.234500e+27"); +assert.sameValue((1.2345e+27).toPrecision(16), "1.234500000000000e+27"); +assert.sameValue((1.2345e+27).toPrecision(17), "1.2345000000000000e+27"); +assert.sameValue((1.2345e+27).toPrecision(18), "1.23449999999999996e+27"); +assert.sameValue((1.2345e+27).toPrecision(19), "1.234499999999999962e+27"); +assert.sameValue((1.2345e+27).toPrecision(20), "1.2344999999999999618e+27"); +assert.sameValue((1.2345e+27).toPrecision(21), "1.23449999999999996184e+27"); + +assert.sameValue((-1.2345e+27).toPrecision(1), "-1e+27"); +assert.sameValue((-1.2345e+27).toPrecision(2), "-1.2e+27"); +assert.sameValue((-1.2345e+27).toPrecision(3), "-1.23e+27"); +assert.sameValue((-1.2345e+27).toPrecision(4), "-1.234e+27"); +assert.sameValue((-1.2345e+27).toPrecision(5), "-1.2345e+27"); +assert.sameValue((-1.2345e+27).toPrecision(6), "-1.23450e+27"); +assert.sameValue((-1.2345e+27).toPrecision(7), "-1.234500e+27"); +assert.sameValue((-1.2345e+27).toPrecision(16), "-1.234500000000000e+27"); +assert.sameValue((-1.2345e+27).toPrecision(17), "-1.2345000000000000e+27"); +assert.sameValue((-1.2345e+27).toPrecision(18), "-1.23449999999999996e+27"); +assert.sameValue((-1.2345e+27).toPrecision(19), "-1.234499999999999962e+27"); +assert.sameValue((-1.2345e+27).toPrecision(20), "-1.2344999999999999618e+27"); +assert.sameValue((-1.2345e+27).toPrecision(21), "-1.23449999999999996184e+27"); + +var n = new Number("1000000000000000000000"); // 1e+21 +assert.sameValue((n).toPrecision(1), "1e+21"); +assert.sameValue((n).toPrecision(2), "1.0e+21"); +assert.sameValue((n).toPrecision(3), "1.00e+21"); +assert.sameValue((n).toPrecision(4), "1.000e+21"); +assert.sameValue((n).toPrecision(5), "1.0000e+21"); +assert.sameValue((n).toPrecision(6), "1.00000e+21"); +assert.sameValue((n).toPrecision(7), "1.000000e+21"); +assert.sameValue((n).toPrecision(16), "1.000000000000000e+21"); +assert.sameValue((n).toPrecision(17), "1.0000000000000000e+21"); +assert.sameValue((n).toPrecision(18), "1.00000000000000000e+21"); +assert.sameValue((n).toPrecision(19), "1.000000000000000000e+21"); +assert.sameValue((n).toPrecision(20), "1.0000000000000000000e+21"); +assert.sameValue((n).toPrecision(21), "1.00000000000000000000e+21"); + +var n = new Number("0.000000000000000000001"); // 1e-21 +assert.sameValue((n).toPrecision(1), "1e-21"); +assert.sameValue((n).toPrecision(2), "1.0e-21"); +assert.sameValue((n).toPrecision(3), "1.00e-21"); +assert.sameValue((n).toPrecision(4), "1.000e-21"); +assert.sameValue((n).toPrecision(5), "1.0000e-21"); +assert.sameValue((n).toPrecision(6), "1.00000e-21"); +assert.sameValue((n).toPrecision(7), "1.000000e-21"); +assert.sameValue((n).toPrecision(16), "9.999999999999999e-22"); +assert.sameValue((n).toPrecision(17), "9.9999999999999991e-22"); +assert.sameValue((n).toPrecision(18), "9.99999999999999908e-22"); +assert.sameValue((n).toPrecision(19), "9.999999999999999075e-22"); +assert.sameValue((n).toPrecision(20), "9.9999999999999990754e-22"); +assert.sameValue((n).toPrecision(21), "9.99999999999999907537e-22"); + +assert.sameValue((0.00000001).toPrecision(1), "1e-8"); +assert.sameValue((-0.00000001).toPrecision(1), "-1e-8"); diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/6957/exponential/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/6957/exponential/output.js new file mode 100644 index 000000000000..6f11ecbd8d0e --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/6957/exponential/output.js @@ -0,0 +1,74 @@ +assert.sameValue("1e+1", "1e+1"); +assert.sameValue("1e+1", "1e+1"); +assert.sameValue("2e+1", "2e+1"); +assert.sameValue("2e+1", "2e+1"); +assert.sameValue("2e+1", "2e+1"); +assert.sameValue("1e+2", "1e+2"); +assert.sameValue("1e+3", "1e+3"); +assert.sameValue("1e+4", "1e+4"); +assert.sameValue("1e+5", "1e+5"); +assert.sameValue("1.0e+2", "1.0e+2"); +assert.sameValue("1.0e+3", "1.0e+3"); +assert.sameValue("1.0e+4", "1.0e+4"); +assert.sameValue("1.0e+5", "1.0e+5"); +assert.sameValue("1.00e+3", "1.00e+3"); +assert.sameValue("1.00e+4", "1.00e+4"); +assert.sameValue("1.00e+5", "1.00e+5"); +assert.sameValue("4e+1", "4e+1"); +assert.sameValue("-4e+1", "-4e+1"); +assert.sameValue("1e+27", "1e+27"); +assert.sameValue("1.2e+27", "1.2e+27"); +assert.sameValue("1.23e+27", "1.23e+27"); +assert.sameValue("1.234e+27", "1.234e+27"); +assert.sameValue("1.2345e+27", "1.2345e+27"); +assert.sameValue("1.23450e+27", "1.23450e+27"); +assert.sameValue("1.234500e+27", "1.234500e+27"); +assert.sameValue("1.234500000000000e+27", "1.234500000000000e+27"); +assert.sameValue("1.2345000000000000e+27", "1.2345000000000000e+27"); +assert.sameValue("1.23449999999999996e+27", "1.23449999999999996e+27"); +assert.sameValue("1.234499999999999962e+27", "1.234499999999999962e+27"); +assert.sameValue("1.2344999999999999618e+27", "1.2344999999999999618e+27"); +assert.sameValue("1.23449999999999996184e+27", "1.23449999999999996184e+27"); +assert.sameValue("-1e+27", "-1e+27"); +assert.sameValue("-1.2e+27", "-1.2e+27"); +assert.sameValue("-1.23e+27", "-1.23e+27"); +assert.sameValue("-1.234e+27", "-1.234e+27"); +assert.sameValue("-1.2345e+27", "-1.2345e+27"); +assert.sameValue("-1.23450e+27", "-1.23450e+27"); +assert.sameValue("-1.234500e+27", "-1.234500e+27"); +assert.sameValue("-1.234500000000000e+27", "-1.234500000000000e+27"); +assert.sameValue("-1.2345000000000000e+27", "-1.2345000000000000e+27"); +assert.sameValue("-1.23449999999999996e+27", "-1.23449999999999996e+27"); +assert.sameValue("-1.234499999999999962e+27", "-1.234499999999999962e+27"); +assert.sameValue("-1.2344999999999999618e+27", "-1.2344999999999999618e+27"); +assert.sameValue("-1.23449999999999996184e+27", "-1.23449999999999996184e+27"); +var n = new Number("1000000000000000000000"); +assert.sameValue(n.toPrecision(1), "1e+21"); +assert.sameValue(n.toPrecision(2), "1.0e+21"); +assert.sameValue(n.toPrecision(3), "1.00e+21"); +assert.sameValue(n.toPrecision(4), "1.000e+21"); +assert.sameValue(n.toPrecision(5), "1.0000e+21"); +assert.sameValue(n.toPrecision(6), "1.00000e+21"); +assert.sameValue(n.toPrecision(7), "1.000000e+21"); +assert.sameValue(n.toPrecision(16), "1.000000000000000e+21"); +assert.sameValue(n.toPrecision(17), "1.0000000000000000e+21"); +assert.sameValue(n.toPrecision(18), "1.00000000000000000e+21"); +assert.sameValue(n.toPrecision(19), "1.000000000000000000e+21"); +assert.sameValue(n.toPrecision(20), "1.0000000000000000000e+21"); +assert.sameValue(n.toPrecision(21), "1.00000000000000000000e+21"); +var n = new Number("0.000000000000000000001"); +assert.sameValue(n.toPrecision(1), "1e-21"); +assert.sameValue(n.toPrecision(2), "1.0e-21"); +assert.sameValue(n.toPrecision(3), "1.00e-21"); +assert.sameValue(n.toPrecision(4), "1.000e-21"); +assert.sameValue(n.toPrecision(5), "1.0000e-21"); +assert.sameValue(n.toPrecision(6), "1.00000e-21"); +assert.sameValue(n.toPrecision(7), "1.000000e-21"); +assert.sameValue(n.toPrecision(16), "9.999999999999999e-22"); +assert.sameValue(n.toPrecision(17), "9.9999999999999991e-22"); +assert.sameValue(n.toPrecision(18), "9.99999999999999908e-22"); +assert.sameValue(n.toPrecision(19), "9.999999999999999075e-22"); +assert.sameValue(n.toPrecision(20), "9.9999999999999990754e-22"); +assert.sameValue(n.toPrecision(21), "9.99999999999999907537e-22"); +assert.sameValue("1e-8", "1e-8"); +assert.sameValue("-1e-8", "-1e-8"); diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/6957/number-tostring/config.json b/crates/swc_ecma_minifier/tests/fixture/issues/6957/number-tostring/config.json new file mode 100644 index 000000000000..b38da13846ff --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/6957/number-tostring/config.json @@ -0,0 +1,46 @@ +{ + "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 +} \ No newline at end of file diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/6957/number-tostring/input.js b/crates/swc_ecma_minifier/tests/fixture/issues/6957/number-tostring/input.js new file mode 100644 index 000000000000..d428b697fe88 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/6957/number-tostring/input.js @@ -0,0 +1,344 @@ +// Copyright 2008 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// ---------------------------------------------------------------------- +// toString +assertEquals("NaN", (NaN).toString()); +assertEquals("Infinity", (1/0).toString()); +assertEquals("-Infinity", (-1/0).toString()); +assertEquals("0", (0).toString()); +assertEquals("9", (9).toString()); +assertEquals("90", (90).toString()); +assertEquals("90.12", (90.12).toString()); +assertEquals("0.1", (0.1).toString()); +assertEquals("0.01", (0.01).toString()); +assertEquals("0.0123", (0.0123).toString()); +assertEquals("111111111111111110000", (111111111111111111111).toString()); +assertEquals("1.1111111111111111e+21", (1111111111111111111111).toString()); +assertEquals("1.1111111111111111e+22", (11111111111111111111111).toString()); +assertEquals("0.00001", (0.00001).toString()); +assertEquals("0.000001", (0.000001).toString()); +assertEquals("1e-7", (0.0000001).toString()); +assertEquals("1.2e-7", (0.00000012).toString()); +assertEquals("1.23e-7", (0.000000123).toString()); +assertEquals("1e-8", (0.00000001).toString()); +assertEquals("1.2e-8", (0.000000012).toString()); +assertEquals("1.23e-8", (0.0000000123).toString()); + +assertEquals("0", (-0).toString()); +assertEquals("-9", (-9).toString()); +assertEquals("-90", (-90).toString()); +assertEquals("-90.12", (-90.12).toString()); +assertEquals("-0.1", (-0.1).toString()); +assertEquals("-0.01", (-0.01).toString()); +assertEquals("-0.0123", (-0.0123).toString()); +assertEquals("-111111111111111110000", (-111111111111111111111).toString()); +assertEquals("-1.1111111111111111e+21", (-1111111111111111111111).toString()); +assertEquals("-1.1111111111111111e+22", (-11111111111111111111111).toString()); +assertEquals("-0.00001", (-0.00001).toString()); +assertEquals("-0.000001", (-0.000001).toString()); +assertEquals("-1e-7", (-0.0000001).toString()); +assertEquals("-1.2e-7", (-0.00000012).toString()); +assertEquals("-1.23e-7", (-0.000000123).toString()); +assertEquals("-1e-8", (-0.00000001).toString()); +assertEquals("-1.2e-8", (-0.000000012).toString()); +assertEquals("-1.23e-8", (-0.0000000123).toString()); + +assertEquals("NaN", (NaN).toString(16)); +assertEquals("Infinity", (1/0).toString(16)); +assertEquals("-Infinity", (-1/0).toString(16)); +assertEquals("0", (0).toString(16)); +assertEquals("9", (9).toString(16)); +assertEquals("5a", (90).toString(16)); +assertEquals("5a.1eb851eb852", (90.12).toString(16)); +assertEquals("0.1999999999999a", (0.1).toString(16)); +assertEquals("0.028f5c28f5c28f6", (0.01).toString(16)); +assertEquals("0.032617c1bda511a", (0.0123).toString(16)); +assertEquals("605f9f6dd18bc8000", (111111111111111111111).toString(16)); +assertEquals("3c3bc3a4a2f75c0000", (1111111111111111111111).toString(16)); +assertEquals("25a55a46e5da9a00000", (11111111111111111111111).toString(16)); +assertEquals("0.0000a7c5ac471b4788", (0.00001).toString(16)); +assertEquals("0.000010c6f7a0b5ed8d", (0.000001).toString(16)); +assertEquals("0.000001ad7f29abcaf48", (0.0000001).toString(16)); +assertEquals("0.000002036565348d256", (0.00000012).toString(16)); +assertEquals("0.0000021047ee22aa466", (0.000000123).toString(16)); +assertEquals("0.0000002af31dc4611874", (0.00000001).toString(16)); +assertEquals("0.000000338a23b87483be", (0.000000012).toString(16)); +assertEquals("0.00000034d3fe36aaa0a2", (0.0000000123).toString(16)); + +assertEquals("0", (-0).toString(16)); +assertEquals("-9", (-9).toString(16)); +assertEquals("-5a", (-90).toString(16)); +assertEquals("-5a.1eb851eb852", (-90.12).toString(16)); +assertEquals("-0.1999999999999a", (-0.1).toString(16)); +assertEquals("-0.028f5c28f5c28f6", (-0.01).toString(16)); +assertEquals("-0.032617c1bda511a", (-0.0123).toString(16)); +assertEquals("-605f9f6dd18bc8000", (-111111111111111111111).toString(16)); +assertEquals("-3c3bc3a4a2f75c0000", (-1111111111111111111111).toString(16)); +assertEquals("-25a55a46e5da9a00000", (-11111111111111111111111).toString(16)); +assertEquals("-0.0000a7c5ac471b4788", (-0.00001).toString(16)); +assertEquals("-0.000010c6f7a0b5ed8d", (-0.000001).toString(16)); +assertEquals("-0.000001ad7f29abcaf48", (-0.0000001).toString(16)); +assertEquals("-0.000002036565348d256", (-0.00000012).toString(16)); +assertEquals("-0.0000021047ee22aa466", (-0.000000123).toString(16)); +assertEquals("-0.0000002af31dc4611874", (-0.00000001).toString(16)); +assertEquals("-0.000000338a23b87483be", (-0.000000012).toString(16)); +assertEquals("-0.00000034d3fe36aaa0a2", (-0.0000000123).toString(16)); + +assertEquals("4294967296", Math.pow(2,32).toString()); +assertEquals("ffffffff", (Math.pow(2,32)-1).toString(16)); +assertEquals("11111111111111111111111111111111", (Math.pow(2,32)-1).toString(2)); +assertEquals("5yc1z", (10000007).toString(36)); +assertEquals("0", (0).toString(36)); +assertEquals("0", (0).toString(16)); +assertEquals("0", (0).toString(10)); +assertEquals("0", (0).toString(8)); +assertEquals("0", (0).toString(2)); +assertEquals("100000000000000000000000000000000", Math.pow(2,32).toString(2)); +assertEquals("100000000000000000000000000000001", (Math.pow(2,32) + 1).toString(2)); +assertEquals("100000000000080", (0x100000000000081).toString(16)); +assertEquals("1000000000000100", (-(-'0x1000000000000081')).toString(16)); +assertEquals("1000000000000000", (-(-'0x1000000000000080')).toString(16)); +assertEquals("1000000000000000", (-(-'0x100000000000007F')).toString(16)); +assertEquals("100000000000000000000000000000000000000000000000010000000", (0x100000000000081).toString(2)); +assertEquals("-11111111111111111111111111111111", (-(Math.pow(2,32)-1)).toString(2)); +assertEquals("-5yc1z", (-10000007).toString(36)); +assertEquals("-100000000000000000000000000000000", (-Math.pow(2,32)).toString(2)); +assertEquals("-100000000000000000000000000000001", (-(Math.pow(2,32) + 1)).toString(2)); +assertEquals("-100000000000080", (-0x100000000000081).toString(16)); +assertEquals("-100000000000000000000000000000000000000000000000010000000", (-0x100000000000081).toString(2)); +assertEquals("1000", (1000).toString()); +assertEquals("0.00001", (0.00001).toString()); +assertEquals("1000000000000000100", (1000000000000000128).toString()); +assertEquals("1e+21", (1000000000000000012800).toString()); +assertEquals("-1e+21", (-1000000000000000012800).toString()); +assertEquals("1e-7", (0.0000001).toString()); +assertEquals("-1e-7", (-0.0000001).toString()); +assertEquals("1.0000000000000001e+21", (1000000000000000128000).toString()); +assertEquals("0.000001", (0.000001).toString()); +assertEquals("1e-7", (0.0000001).toString()); +assertEquals("8.8", (8.5).toString(16)); +assertEquals("-8.8", (-8.5).toString(16)); + +assertEquals("1.1", (4/3).toString(3)); +assertEquals("11.1", (13/3).toString(3)); +assertEquals("0.01", (1/9).toString(3)); +assertEquals("10000", (81).toString(3)); +assertEquals("10000.01", (81 + 1/9).toString(3)); +assertEquals("0.0212010212010212010212010212010212", (2/7).toString(3)); + +// ---------------------------------------------------------------------- +// toFixed +assertEquals("NaN", (NaN).toFixed(2)); +assertEquals("Infinity", (1/0).toFixed(2)); +assertEquals("-Infinity", (-1/0).toFixed(2)); + +assertEquals("1.1111111111111111e+21", (1111111111111111111111).toFixed(8)); +assertEquals("0.1", (0.1).toFixed(1)); +assertEquals("0.10", (0.1).toFixed(2)); +assertEquals("0.100", (0.1).toFixed(3)); +assertEquals("0.01", (0.01).toFixed(2)); +assertEquals("0.010", (0.01).toFixed(3)); +assertEquals("0.0100", (0.01).toFixed(4)); +assertEquals("0.00", (0.001).toFixed(2)); +assertEquals("0.001", (0.001).toFixed(3)); +assertEquals("0.0010", (0.001).toFixed(4)); +assertEquals("1.0000", (1).toFixed(4)); +assertEquals("1.0", (1).toFixed(1)); +assertEquals("1", (1).toFixed(0)); +assertEquals("12", (12).toFixed(0)); +assertEquals("1", (1.1).toFixed(0)); +assertEquals("12", (12.1).toFixed(0)); +assertEquals("1", (1.12).toFixed(0)); +assertEquals("12", (12.12).toFixed(0)); +assertEquals("0.0000006", (0.0000006).toFixed(7)); +assertEquals("0.00000006", (0.00000006).toFixed(8)); +assertEquals("0.000000060", (0.00000006).toFixed(9)); +assertEquals("0.0000000600", (0.00000006).toFixed(10)); +assertEquals("0", (0).toFixed(0)); +assertEquals("0.0", (0).toFixed(1)); +assertEquals("0.00", (0).toFixed(2)); + +assertEquals("-1.1111111111111111e+21", (-1111111111111111111111).toFixed(8)); +assertEquals("-0.1", (-0.1).toFixed(1)); +assertEquals("-0.10", (-0.1).toFixed(2)); +assertEquals("-0.100", (-0.1).toFixed(3)); +assertEquals("-0.01", (-0.01).toFixed(2)); +assertEquals("-0.010", (-0.01).toFixed(3)); +assertEquals("-0.0100", (-0.01).toFixed(4)); +assertEquals("-0.00", (-0.001).toFixed(2)); +assertEquals("-0.001", (-0.001).toFixed(3)); +assertEquals("-0.0010", (-0.001).toFixed(4)); +assertEquals("-1.0000", (-1).toFixed(4)); +assertEquals("-1.0", (-1).toFixed(1)); +assertEquals("-1", (-1).toFixed(0)); +assertEquals("-1", (-1.1).toFixed(0)); +assertEquals("-12", (-12.1).toFixed(0)); +assertEquals("-1", (-1.12).toFixed(0)); +assertEquals("-12", (-12.12).toFixed(0)); +assertEquals("-0.0000006", (-0.0000006).toFixed(7)); +assertEquals("-0.00000006", (-0.00000006).toFixed(8)); +assertEquals("-0.000000060", (-0.00000006).toFixed(9)); +assertEquals("-0.0000000600", (-0.00000006).toFixed(10)); +assertEquals("0", (-0).toFixed(0)); +assertEquals("0.0", (-0).toFixed(1)); +assertEquals("0.00", (-0).toFixed(2)); + +assertEquals("1000", (1000).toFixed()); +assertEquals("0", (0.00001).toFixed()); +assertEquals("0.00001", (0.00001).toFixed(5)); +assertEquals("0.00000000000000000010", (0.0000000000000000001).toFixed(20)); +assertEquals("0.00001000000000000", (0.00001).toFixed(17)); +assertEquals("1.00000000000000000", (1).toFixed(17)); +assertEquals("1000000000000000128", (1000000000000000128).toFixed()); +assertEquals("100000000000000128.0", (100000000000000128).toFixed(1)); +assertEquals("10000000000000128.00", (10000000000000128).toFixed(2)); +assertEquals("10000000000000128.00000000000000000000", (10000000000000128).toFixed(20)); +assertEquals("0", (0).toFixed()); +assertEquals("-42.000", ((-42).toFixed(3))); +assertEquals("-1000000000000000128", (-1000000000000000128).toFixed()); +assertEquals("-0.00000000000000000010", (-0.0000000000000000001).toFixed(20)); +assertEquals("0.12312312312312299889", (0.123123123123123).toFixed(20)); +// Test that we round up even when the last digit generated is even. +// dtoa does not do this in its original form. +assertEquals("1", 0.5.toFixed(0), "0.5.toFixed(0)"); +assertEquals("-1", (-0.5).toFixed(0), "(-0.5).toFixed(0)"); +assertEquals("1.3", 1.25.toFixed(1), "1.25.toFixed(1)"); +// This is bizare, but Spidermonkey and KJS behave the same. +assertEquals("234.2040", (234.20405).toFixed(4), "234.2040.toFixed(4)"); +assertEquals("234.2041", (234.2040506).toFixed(4)); + +// ---------------------------------------------------------------------- +// toExponential +assertEquals("1e+0", (1).toExponential()); +assertEquals("1.1e+1", (11).toExponential()); +assertEquals("1.12e+2", (112).toExponential()); +assertEquals("1e+0", (1).toExponential(0)); +assertEquals("1e+1", (11).toExponential(0)); +assertEquals("1e+2", (112).toExponential(0)); +assertEquals("1.0e+0", (1).toExponential(1)); +assertEquals("1.1e+1", (11).toExponential(1)); +assertEquals("1.1e+2", (112).toExponential(1)); +assertEquals("1.00e+0", (1).toExponential(2)); +assertEquals("1.10e+1", (11).toExponential(2)); +assertEquals("1.12e+2", (112).toExponential(2)); +assertEquals("1.000e+0", (1).toExponential(3)); +assertEquals("1.100e+1", (11).toExponential(3)); +assertEquals("1.120e+2", (112).toExponential(3)); +assertEquals("1e-1", (0.1).toExponential()); +assertEquals("1.1e-1", (0.11).toExponential()); +assertEquals("1.12e-1", (0.112).toExponential()); +assertEquals("1e-1", (0.1).toExponential(0)); +assertEquals("1e-1", (0.11).toExponential(0)); +assertEquals("1e-1", (0.112).toExponential(0)); +assertEquals("1.0e-1", (0.1).toExponential(1)); +assertEquals("1.1e-1", (0.11).toExponential(1)); +assertEquals("1.1e-1", (0.112).toExponential(1)); +assertEquals("1.00e-1", (0.1).toExponential(2)); +assertEquals("1.10e-1", (0.11).toExponential(2)); +assertEquals("1.12e-1", (0.112).toExponential(2)); +assertEquals("1.000e-1", (0.1).toExponential(3)); +assertEquals("1.100e-1", (0.11).toExponential(3)); +assertEquals("1.120e-1", (0.112).toExponential(3)); + +assertEquals("-1e+0", (-1).toExponential()); +assertEquals("-1.1e+1", (-11).toExponential()); +assertEquals("-1.12e+2", (-112).toExponential()); +assertEquals("-1e+0", (-1).toExponential(0)); +assertEquals("-1e+1", (-11).toExponential(0)); +assertEquals("-1e+2", (-112).toExponential(0)); +assertEquals("-1.0e+0", (-1).toExponential(1)); +assertEquals("-1.1e+1", (-11).toExponential(1)); +assertEquals("-1.1e+2", (-112).toExponential(1)); +assertEquals("-1.00e+0", (-1).toExponential(2)); +assertEquals("-1.10e+1", (-11).toExponential(2)); +assertEquals("-1.12e+2", (-112).toExponential(2)); +assertEquals("-1.000e+0", (-1).toExponential(3)); +assertEquals("-1.100e+1", (-11).toExponential(3)); +assertEquals("-1.120e+2", (-112).toExponential(3)); +assertEquals("-1e-1", (-0.1).toExponential()); +assertEquals("-1.1e-1", (-0.11).toExponential()); +assertEquals("-1.12e-1", (-0.112).toExponential()); +assertEquals("-1e-1", (-0.1).toExponential(0)); +assertEquals("-1e-1", (-0.11).toExponential(0)); +assertEquals("-1e-1", (-0.112).toExponential(0)); +assertEquals("-1.0e-1", (-0.1).toExponential(1)); +assertEquals("-1.1e-1", (-0.11).toExponential(1)); +assertEquals("-1.1e-1", (-0.112).toExponential(1)); +assertEquals("-1.00e-1", (-0.1).toExponential(2)); +assertEquals("-1.10e-1", (-0.11).toExponential(2)); +assertEquals("-1.12e-1", (-0.112).toExponential(2)); +assertEquals("-1.000e-1", (-0.1).toExponential(3)); +assertEquals("-1.100e-1", (-0.11).toExponential(3)); +assertEquals("-1.120e-1", (-0.112).toExponential(3)); + +assertEquals("NaN", (NaN).toExponential(2)); +assertEquals("Infinity", (Infinity).toExponential(2)); +assertEquals("-Infinity", (-Infinity).toExponential(2)); +assertEquals("1e+0", (1).toExponential(0)); +assertEquals("0e+0", (0).toExponential()); +assertEquals("0.00e+0", (0).toExponential(2)); +assertEquals("1e+1", (11.2356).toExponential(0)); +assertEquals("1.1236e+1", (11.2356).toExponential(4)); +assertEquals("1.1236e-4", (0.000112356).toExponential(4)); +assertEquals("-1.1236e-4", (-0.000112356).toExponential(4)); +assertEquals("1.12356e-4", (0.000112356).toExponential()); +assertEquals("-1.12356e-4", (-0.000112356).toExponential()); + +// ---------------------------------------------------------------------- +// toPrecision +assertEquals("NaN", (NaN).toPrecision(1)); +assertEquals("Infinity", (Infinity).toPrecision(2)); +assertEquals("-Infinity", (-Infinity).toPrecision(2)); +assertEquals("0.000555000000000000", (0.000555).toPrecision(15)); +assertEquals("5.55000000000000e-7", (0.000000555).toPrecision(15)); +assertEquals("-5.55000000000000e-7", (-0.000000555).toPrecision(15)); +assertEquals("1e+8", (123456789).toPrecision(1)); +assertEquals("123456789", (123456789).toPrecision(9)); +assertEquals("1.2345679e+8", (123456789).toPrecision(8)); +assertEquals("1.234568e+8", (123456789).toPrecision(7)); +assertEquals("-1.234568e+8", (-123456789).toPrecision(7)); +assertEquals("-1.2e-9", Number(-.0000000012345).toPrecision(2)); +assertEquals("-1.2e-8", Number(-.000000012345).toPrecision(2)); +assertEquals("-1.2e-7", Number(-.00000012345).toPrecision(2)); +assertEquals("-0.0000012", Number(-.0000012345).toPrecision(2)); +assertEquals("-0.000012", Number(-.000012345).toPrecision(2)); +assertEquals("-0.00012", Number(-.00012345).toPrecision(2)); +assertEquals("-0.0012", Number(-.0012345).toPrecision(2)); +assertEquals("-0.012", Number(-.012345).toPrecision(2)); +assertEquals("-0.12", Number(-.12345).toPrecision(2)); +assertEquals("-1.2", Number(-1.2345).toPrecision(2)); +assertEquals("-12", Number(-12.345).toPrecision(2)); +assertEquals("-1.2e+2", Number(-123.45).toPrecision(2)); +assertEquals("-1.2e+3", Number(-1234.5).toPrecision(2)); +assertEquals("-1.2e+4", Number(-12345).toPrecision(2)); +assertEquals("-1.235e+4", Number(-12345.67).toPrecision(4)); +assertEquals("-1.234e+4", Number(-12344.67).toPrecision(4)); +// Test that we round up even when the last digit generated is even. +// dtoa does not do this in its original form. +assertEquals("1.3", 1.25.toPrecision(2), "1.25.toPrecision(2)"); +assertEquals("1.4", 1.35.toPrecision(2), "1.35.toPrecision(2)"); 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 new file mode 100644 index 000000000000..11f1f783c4d7 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/6957/number-tostring/output.js @@ -0,0 +1,291 @@ +assertEquals("NaN", NaN.toString()); +assertEquals("Infinity", (1 / 0).toString()); +assertEquals("-Infinity", (-1 / 0).toString()); +assertEquals("0", "0"); +assertEquals("9", "9"); +assertEquals("90", "90"); +assertEquals("90.12", "90.12"); +assertEquals("0.1", "0.1"); +assertEquals("0.01", "0.01"); +assertEquals("0.0123", "0.0123"); +assertEquals("111111111111111110000", "111111111111111110000"); +assertEquals("1.1111111111111111e+21", "1.1111111111111111e+21"); +assertEquals("1.1111111111111111e+22", "1.1111111111111111e+22"); +assertEquals("0.00001", "0.00001"); +assertEquals("0.000001", "0.000001"); +assertEquals("1e-7", "1e-7"); +assertEquals("1.2e-7", "1.2e-7"); +assertEquals("1.23e-7", "1.23e-7"); +assertEquals("1e-8", "1e-8"); +assertEquals("1.2e-8", "1.2e-8"); +assertEquals("1.23e-8", "1.23e-8"); +assertEquals("0", "0"); +assertEquals("-9", "-9"); +assertEquals("-90", "-90"); +assertEquals("-90.12", "-90.12"); +assertEquals("-0.1", "-0.1"); +assertEquals("-0.01", "-0.01"); +assertEquals("-0.0123", "-0.0123"); +assertEquals("-111111111111111110000", "-111111111111111110000"); +assertEquals("-1.1111111111111111e+21", "-1.1111111111111111e+21"); +assertEquals("-1.1111111111111111e+22", "-1.1111111111111111e+22"); +assertEquals("-0.00001", "-0.00001"); +assertEquals("-0.000001", "-0.000001"); +assertEquals("-1e-7", "-1e-7"); +assertEquals("-1.2e-7", "-1.2e-7"); +assertEquals("-1.23e-7", "-1.23e-7"); +assertEquals("-1e-8", "-1e-8"); +assertEquals("-1.2e-8", "-1.2e-8"); +assertEquals("-1.23e-8", "-1.23e-8"); +assertEquals("NaN", NaN.toString(16)); +assertEquals("Infinity", (1 / 0).toString(16)); +assertEquals("-Infinity", (-1 / 0).toString(16)); +assertEquals("0", "0"); +assertEquals("9", "9"); +assertEquals("5a", "5a"); +assertEquals("5a.1eb851eb852", 90.12.toString(16)); +assertEquals("0.1999999999999a", 0.1.toString(16)); +assertEquals("0.028f5c28f5c28f6", 0.01.toString(16)); +assertEquals("0.032617c1bda511a", 0.0123.toString(16)); +assertEquals("605f9f6dd18bc8000", "605f9f6dd18bc8000"); +assertEquals("3c3bc3a4a2f75c0000", "3c3bc3a4a2f75c0000"); +assertEquals("25a55a46e5da9a00000", "25a55a46e5da9a00000"); +assertEquals("0.0000a7c5ac471b4788", 0.00001.toString(16)); +assertEquals("0.000010c6f7a0b5ed8d", 0.000001.toString(16)); +assertEquals("0.000001ad7f29abcaf48", 0.0000001.toString(16)); +assertEquals("0.000002036565348d256", 0.00000012.toString(16)); +assertEquals("0.0000021047ee22aa466", 0.000000123.toString(16)); +assertEquals("0.0000002af31dc4611874", 0.00000001.toString(16)); +assertEquals("0.000000338a23b87483be", 0.000000012.toString(16)); +assertEquals("0.00000034d3fe36aaa0a2", 0.0000000123.toString(16)); +assertEquals("0", "0"); +assertEquals("-9", "-9"); +assertEquals("-5a", "-5a"); +assertEquals("-5a.1eb851eb852", (-90.12).toString(16)); +assertEquals("-0.1999999999999a", (-0.1).toString(16)); +assertEquals("-0.028f5c28f5c28f6", (-0.01).toString(16)); +assertEquals("-0.032617c1bda511a", (-0.0123).toString(16)); +assertEquals("-605f9f6dd18bc8000", "-605f9f6dd18bc8000"); +assertEquals("-3c3bc3a4a2f75c0000", "-3c3bc3a4a2f75c0000"); +assertEquals("-25a55a46e5da9a00000", "-25a55a46e5da9a00000"); +assertEquals("-0.0000a7c5ac471b4788", (-0.00001).toString(16)); +assertEquals("-0.000010c6f7a0b5ed8d", (-0.000001).toString(16)); +assertEquals("-0.000001ad7f29abcaf48", (-0.0000001).toString(16)); +assertEquals("-0.000002036565348d256", (-0.00000012).toString(16)); +assertEquals("-0.0000021047ee22aa466", (-0.000000123).toString(16)); +assertEquals("-0.0000002af31dc4611874", (-0.00000001).toString(16)); +assertEquals("-0.000000338a23b87483be", (-0.000000012).toString(16)); +assertEquals("-0.00000034d3fe36aaa0a2", (-0.0000000123).toString(16)); +assertEquals("4294967296", "4294967296"); +assertEquals("ffffffff", "ffffffff"); +assertEquals("11111111111111111111111111111111", "11111111111111111111111111111111"); +assertEquals("5yc1z", "5yc1z"); +assertEquals("0", "0"); +assertEquals("0", "0"); +assertEquals("0", "0"); +assertEquals("0", "0"); +assertEquals("0", "0"); +assertEquals("100000000000000000000000000000000", "100000000000000000000000000000000"); +assertEquals("100000000000000000000000000000001", "100000000000000000000000000000001"); +assertEquals("100000000000080", "100000000000080"); +assertEquals("1000000000000100", "1"); +assertEquals("1000000000000000", "1"); +assertEquals("1000000000000000", "1"); +assertEquals("100000000000000000000000000000000000000000000000010000000", "100000000000000000000000000000000000000000000000010000000"); +assertEquals("-11111111111111111111111111111111", "-11111111111111111111111111111111"); +assertEquals("-5yc1z", "-5yc1z"); +assertEquals("-100000000000000000000000000000000", "-100000000000000000000000000000000"); +assertEquals("-100000000000000000000000000000001", "-100000000000000000000000000000001"); +assertEquals("-100000000000080", "-100000000000080"); +assertEquals("-100000000000000000000000000000000000000000000000010000000", "-100000000000000000000000000000000000000000000000010000000"); +assertEquals("1000", "1000"); +assertEquals("0.00001", "0.00001"); +assertEquals("1000000000000000100", "1000000000000000100"); +assertEquals("1e+21", "1e+21"); +assertEquals("-1e+21", "-1e+21"); +assertEquals("1e-7", "1e-7"); +assertEquals("-1e-7", "-1e-7"); +assertEquals("1.0000000000000001e+21", "1.0000000000000001e+21"); +assertEquals("0.000001", "0.000001"); +assertEquals("1e-7", "1e-7"); +assertEquals("8.8", 8.5.toString(16)); +assertEquals("-8.8", (-8.5).toString(16)); +assertEquals("1.1", (4 / 3).toString(3)); +assertEquals("11.1", (13 / 3).toString(3)); +assertEquals("0.01", (1 / 9).toString(3)); +assertEquals("10000", "10000"); +assertEquals("10000.01", (81 + 1 / 9).toString(3)); +assertEquals("0.0212010212010212010212010212010212", (2 / 7).toString(3)); +assertEquals("NaN", NaN.toFixed(2)); +assertEquals("Infinity", (1 / 0).toFixed(2)); +assertEquals("-Infinity", (-1 / 0).toFixed(2)); +assertEquals("1.1111111111111111e+21", "1.1111111111111111e+21"); +assertEquals("0.1", 0.1.toFixed(1)); +assertEquals("0.10", 0.1.toFixed(2)); +assertEquals("0.100", 0.1.toFixed(3)); +assertEquals("0.01", 0.01.toFixed(2)); +assertEquals("0.010", 0.01.toFixed(3)); +assertEquals("0.0100", 0.01.toFixed(4)); +assertEquals("0.00", 0.001.toFixed(2)); +assertEquals("0.001", 0.001.toFixed(3)); +assertEquals("0.0010", 0.001.toFixed(4)); +assertEquals("1.0000", "1.0000"); +assertEquals("1.0", "1.0"); +assertEquals("1", "1"); +assertEquals("12", "12"); +assertEquals("1", "1"); +assertEquals("12", "12"); +assertEquals("1", "1"); +assertEquals("12", "12"); +assertEquals("0.0000006", 0.0000006.toFixed(7)); +assertEquals("0.00000006", 0.00000006.toFixed(8)); +assertEquals("0.000000060", 0.00000006.toFixed(9)); +assertEquals("0.0000000600", 0.00000006.toFixed(10)); +assertEquals("0", "0"); +assertEquals("0.0", "0.0"); +assertEquals("0.00", "0.00"); +assertEquals("-1.1111111111111111e+21", "-1.1111111111111111e+21"); +assertEquals("-0.1", (-0.1).toFixed(1)); +assertEquals("-0.10", (-0.1).toFixed(2)); +assertEquals("-0.100", (-0.1).toFixed(3)); +assertEquals("-0.01", (-0.01).toFixed(2)); +assertEquals("-0.010", (-0.01).toFixed(3)); +assertEquals("-0.0100", (-0.01).toFixed(4)); +assertEquals("-0.00", (-0.001).toFixed(2)); +assertEquals("-0.001", (-0.001).toFixed(3)); +assertEquals("-0.0010", (-0.001).toFixed(4)); +assertEquals("-1.0000", "-1.0000"); +assertEquals("-1.0", "-1.0"); +assertEquals("-1", "-1"); +assertEquals("-1", "-1"); +assertEquals("-12", "-12"); +assertEquals("-1", "-1"); +assertEquals("-12", "-12"); +assertEquals("-0.0000006", (-0.0000006).toFixed(7)); +assertEquals("-0.00000006", (-0.00000006).toFixed(8)); +assertEquals("-0.000000060", (-0.00000006).toFixed(9)); +assertEquals("-0.0000000600", (-0.00000006).toFixed(10)); +assertEquals("0", "0"); +assertEquals("0.0", "0.0"); +assertEquals("0.00", "0.00"); +assertEquals("1000", "1000"); +assertEquals("0", "0"); +assertEquals("0.00001", 0.00001.toFixed(5)); +assertEquals("0.00000000000000000010", 0.0000000000000000001.toFixed(20)); +assertEquals("0.00001000000000000", 0.00001.toFixed(17)); +assertEquals("1.00000000000000000", "1.00000000000000000"); +assertEquals("1000000000000000128", "1000000000000000128"); +assertEquals("100000000000000128.0", "100000000000000128.0"); +assertEquals("10000000000000128.00", "10000000000000128.00"); +assertEquals("10000000000000128.00000000000000000000", "10000000000000128.00000000000000000000"); +assertEquals("0", "0"); +assertEquals("-42.000", "-42.000"); +assertEquals("-1000000000000000128", "-1000000000000000128"); +assertEquals("-0.00000000000000000010", (-0.0000000000000000001).toFixed(20)); +assertEquals("0.12312312312312299889", 0.123123123123123.toFixed(20)); +assertEquals("1", "1", "0.5.toFixed(0)"); +assertEquals("-1", "-1", "(-0.5).toFixed(0)"); +assertEquals("1.3", 1.25.toFixed(1), "1.25.toFixed(1)"); +assertEquals("234.2040", 234.20405.toFixed(4), "234.2040.toFixed(4)"); +assertEquals("234.2041", 234.2040506.toFixed(4)); +assertEquals("1e+0", "1e+0"); +assertEquals("1.1e+1", "1.1e+1"); +assertEquals("1.12e+2", "1.12e+2"); +assertEquals("1e+0", "1e+0"); +assertEquals("1e+1", "1e+1"); +assertEquals("1e+2", "1e+2"); +assertEquals("1.0e+0", "1.0e+0"); +assertEquals("1.1e+1", "1.1e+1"); +assertEquals("1.1e+2", "1.1e+2"); +assertEquals("1.00e+0", "1.00e+0"); +assertEquals("1.10e+1", "1.10e+1"); +assertEquals("1.12e+2", "1.12e+2"); +assertEquals("1.000e+0", "1.000e+0"); +assertEquals("1.100e+1", "1.100e+1"); +assertEquals("1.120e+2", "1.120e+2"); +assertEquals("1e-1", "1e-1"); +assertEquals("1.1e-1", "1.1e-1"); +assertEquals("1.12e-1", "1.12e-1"); +assertEquals("1e-1", "1e-1"); +assertEquals("1e-1", "1e-1"); +assertEquals("1e-1", "1e-1"); +assertEquals("1.0e-1", "1.0e-1"); +assertEquals("1.1e-1", "1.1e-1"); +assertEquals("1.1e-1", "1.1e-1"); +assertEquals("1.00e-1", "1.00e-1"); +assertEquals("1.10e-1", "1.10e-1"); +assertEquals("1.12e-1", "1.12e-1"); +assertEquals("1.000e-1", "1.000e-1"); +assertEquals("1.100e-1", "1.100e-1"); +assertEquals("1.120e-1", "1.120e-1"); +assertEquals("-1e+0", "-1e+0"); +assertEquals("-1.1e+1", "-1.1e+1"); +assertEquals("-1.12e+2", "-1.12e+2"); +assertEquals("-1e+0", "-1e+0"); +assertEquals("-1e+1", "-1e+1"); +assertEquals("-1e+2", "-1e+2"); +assertEquals("-1.0e+0", "-1.0e+0"); +assertEquals("-1.1e+1", "-1.1e+1"); +assertEquals("-1.1e+2", "-1.1e+2"); +assertEquals("-1.00e+0", "-1.00e+0"); +assertEquals("-1.10e+1", "-1.10e+1"); +assertEquals("-1.12e+2", "-1.12e+2"); +assertEquals("-1.000e+0", "-1.000e+0"); +assertEquals("-1.100e+1", "-1.100e+1"); +assertEquals("-1.120e+2", "-1.120e+2"); +assertEquals("-1e-1", "-1e-1"); +assertEquals("-1.1e-1", "-1.1e-1"); +assertEquals("-1.12e-1", "-1.12e-1"); +assertEquals("-1e-1", "-1e-1"); +assertEquals("-1e-1", "-1e-1"); +assertEquals("-1e-1", "-1e-1"); +assertEquals("-1.0e-1", "-1.0e-1"); +assertEquals("-1.1e-1", "-1.1e-1"); +assertEquals("-1.1e-1", "-1.1e-1"); +assertEquals("-1.00e-1", "-1.00e-1"); +assertEquals("-1.10e-1", "-1.10e-1"); +assertEquals("-1.12e-1", "-1.12e-1"); +assertEquals("-1.000e-1", "-1.000e-1"); +assertEquals("-1.100e-1", "-1.100e-1"); +assertEquals("-1.120e-1", "-1.120e-1"); +assertEquals("NaN", NaN.toExponential(2)); +assertEquals("Infinity", (1 / 0).toExponential(2)); +assertEquals("-Infinity", (-1 / 0).toExponential(2)); +assertEquals("1e+0", "1e+0"); +assertEquals("0e+0", "0e+0"); +assertEquals("0.00e+0", "0.00e+0"); +assertEquals("1e+1", "1e+1"); +assertEquals("1.1236e+1", "1.1236e+1"); +assertEquals("1.1236e-4", "1.1236e-4"); +assertEquals("-1.1236e-4", "-1.1236e-4"); +assertEquals("1.12356e-4", "1.12356e-4"); +assertEquals("-1.12356e-4", "-1.12356e-4"); +assertEquals("NaN", NaN.toPrecision(1)); +assertEquals("Infinity", (1 / 0).toPrecision(2)); +assertEquals("-Infinity", (-1 / 0).toPrecision(2)); +assertEquals("0.000555000000000000", "0.000555000000000000"); +assertEquals("5.55000000000000e-7", "5.55000000000000e-7"); +assertEquals("-5.55000000000000e-7", "-5.55000000000000e-7"); +assertEquals("1e+8", "1e+8"); +assertEquals("123456789", "123456789"); +assertEquals("1.2345679e+8", "1.2345679e+8"); +assertEquals("1.234568e+8", "1.234568e+8"); +assertEquals("-1.234568e+8", "-1.234568e+8"); +assertEquals("-1.2e-9", Number(-0.0000000012345).toPrecision(2)); +assertEquals("-1.2e-8", Number(-0.000000012345).toPrecision(2)); +assertEquals("-1.2e-7", Number(-0.00000012345).toPrecision(2)); +assertEquals("-0.0000012", Number(-0.0000012345).toPrecision(2)); +assertEquals("-0.000012", Number(-0.000012345).toPrecision(2)); +assertEquals("-0.00012", Number(-0.00012345).toPrecision(2)); +assertEquals("-0.0012", Number(-0.0012345).toPrecision(2)); +assertEquals("-0.012", Number(-0.012345).toPrecision(2)); +assertEquals("-0.12", Number(-0.12345).toPrecision(2)); +assertEquals("-1.2", Number(-1.2345).toPrecision(2)); +assertEquals("-12", Number(-12.345).toPrecision(2)); +assertEquals("-1.2e+2", Number(-123.45).toPrecision(2)); +assertEquals("-1.2e+3", Number(-1234.5).toPrecision(2)); +assertEquals("-1.2e+4", Number(-12345).toPrecision(2)); +assertEquals("-1.235e+4", Number(-12345.67).toPrecision(4)); +assertEquals("-1.234e+4", Number(-12344.67).toPrecision(4)); +assertEquals("1.3", "1.3", "1.25.toPrecision(2)"); +assertEquals("1.4", "1.4", "1.35.toPrecision(2)"); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/evaluate/issue_2207_1/output.js b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/issue_2207_1/output.js index 5ad7a3669c19..938065d16e54 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/evaluate/issue_2207_1/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/evaluate/issue_2207_1/output.js @@ -2,4 +2,4 @@ console.log("A"); console.log(7); console.log(0.32999315767856785); console.log(1.2543732512566947); -console.log("1.609398451447204"); +console.log(1.6093984514472044.toFixed(15)); diff --git a/crates/swc_ecma_transforms_base/src/fixer.rs b/crates/swc_ecma_transforms_base/src/fixer.rs index 1837608d0ed1..324ef76948d2 100644 --- a/crates/swc_ecma_transforms_base/src/fixer.rs +++ b/crates/swc_ecma_transforms_base/src/fixer.rs @@ -944,6 +944,13 @@ impl Fixer<'_> { _ => self.wrap(callee), }, + + Expr::Member(MemberExpr { obj, .. }) => match &**obj { + Expr::Lit(Lit::Num(num)) if num.value.signum() == -1. => { + self.wrap(obj); + } + _ => {} + }, _ => {} } }