fix(linter/unicorn/no-zero-fractions): parenthesize separator and large integers in fixer (#27206)

### Bug

When `unicorn/no-zero-fractions` removes the fraction from a number that
is the object of a member access, the fix adds parentheses so the result
stays valid (`1.00.toFixed(2)` becomes `(1).toFixed(2)`). It decides
whether parentheses are needed with `fmt.parse::<i64>()`, which fails
for integers that contain numeric separators or don't fit in an `i64`.
Those cases get no parentheses, so the fix produces a syntax error:

```js
1_000.0.toFixed(2)                   // fixed to `1_000.toFixed(2)`: SyntaxError
10000000000000000000.0.toFixed(2)    // fixed to `10000000000000000000.toFixed(2)`: SyntaxError
```

The linter's own fixer test catches this: `Linter fixer produced invalid
syntax ... Invalid characters after number`.

### Fix

A literal needs the parentheses when the fixed text is only digits and
`_`. That matches the decimal-integer check in eslint-plugin-unicorn,
which accepts separators. Exponent forms such as `1e10.toFixed()` stay
unparenthesized, as they are today.

---------

Signed-off-by: Cameron <cameron.clark@hey.com>
Co-authored-by: breken-ai <312387581+breken-ai@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Cameron <cameron.clark@hey.com>
This commit is contained in:
authored and GitHub committed 2026-09-30 14:34:44 +00:00
1 parent 466ef10f3e
commit e928322e5f
1 file changed
+3 -1
@@ -76,7 +76,7 @@ impl Rule for NoZeroFractions {
},
|fixer| {
let mut fixed = fmt.clone();
let is_decimal_integer = fmt.parse::<i64>().is_ok();
let is_decimal_integer = fmt.bytes().all(|b| b.is_ascii_digit() || b == b'_');
let is_member_expression =
ctx.nodes().parent_kind(node.id()).is_member_expression_kind();
@@ -203,6 +203,8 @@ fn test() {
(r"1.00 .toFixed(2)", r"(1) .toFixed(2)"),
(r"(1.00).toFixed(2)", r"(1).toFixed(2)"),
(r"1.00?.toFixed(2)", r"(1)?.toFixed(2)"),
(r"1_000.0.toFixed(2)", r"(1_000).toFixed(2)"),
(r"10000000000000000000.0.toFixed(2)", r"(10000000000000000000).toFixed(2)"),
(r"a = .0;", r"a = 0;"),
(r"a = .0.toString()", r"a = (0).toString()"),
(r"function foo(){return.0}", r"function foo(){return 0}"),