Skip to content

fix: keep small values and custom separators free of scientific notation - #369

Merged
avoidwork merged 1 commit into
avoidwork:masterfrom
ybai08:fix/scientific-notation-small-values
Oct 21, 2026
Merged

avoidwork merged 1 commit into
avoidwork:masterfrom
ybai08:fix/scientific-notation-small-values

Conversation

@ybai08

@ybai08 ybai08 commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

Summary

The scientific-notation expansion added in #344 has two gaps:

  1. It calls toLocaleString("en-US", { useGrouping: false }), and Intl's default maximumFractionDigits is 3. A rounded value small enough for toString() to give exponent form (below 1e-6) is therefore truncated to "0":
    • filesize(1, { exponent: 3, round: 10 }) returns "0 GB". The rounded value is 1e-9, so the expected result is "0.000000001 GB".
    • filesize(5, { exponent: 3, round: 9 }) returns "0 GB".
    • filesize(1, { exponent: 3, round: 10, pad: true }) returns "0.0000000000 GB".
  2. It runs after the custom separator has been applied, when the value is already a string, so the check never matches on that path:
    • filesize(1, { exponent: 3, round: 10, separator: "," }) returns "1e-9 GB".
    • filesize(1e22, { exponent: 0, separator: "," }) returns "1e+22 B". Without a separator it returns "10000000000000000000000 B".
    • filesize(Number.MAX_VALUE, { separator: "," }) returns "1,7976931348623158e+284 YB".

This PR moves the expansion into the non-locale branch, after the pad-rounding step and before the separator replacement, and passes maximumFractionDigits: 20. 20 is the largest value every Intl implementation accepts. The locale branches are unchanged: they already return strings, so the old check never ran on them. The precision path is also unchanged, because its value is a toPrecision() string.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature / enhancement
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Build / dependency / tooling change
  • Test additions or updates
  • Other

Related Issues

refs #343 (item 8, "Strip scientific notation in non-precision path"). No open issue or PR covers these two cases.

Testing

Two tests were added under "Edge case hardening (issue #343) › Sign handling", next to the existing Number.MAX_VALUE test:

  • should not truncate small values when expanding scientific notation
  • should not leak scientific notation with a custom separator

Before the fix, both fail on master (actual: '0 GB' and actual: '1e-9 GB'). With the fix, both pass:

node --test --test-name-pattern='truncate small values|leak scientific notation with a custom' tests/unit/filesize.test.js

npm test (oxlint + oxfmt check + node:test with coverage) passes: 271 tests, with 100% line, branch and function coverage for src/. npm run build succeeds, and the tracked dist/ files were regenerated. All of this was run on Node 26.10 (macOS).

A broader before/after probe of about 55 option combinations (locale, pad, separator, precision, bits, BigInt, fullform) changed only the 1e22 + separator case.

Known limit: a value that needs more than 20 fraction digits, which only happens with round > 20, still rounds to zero.

Checklist

  • npm test passes
  • npm run build succeeds
  • 100% test coverage maintained
  • No hardcoded secrets or credentials introduced
  • Zero external dependencies added
  • ES Modules only (no CommonJS in src/)
  • JSDoc comments added/updated (N/A: no function signatures changed; an inline comment was updated)
  • CHANGELOG.md updated (if applicable): N/A, the changelog is generated at release by auto-changelog

Screenshots (if applicable)

N/A

The scientific notation expansion in applyNumberFormatting used Intl's default of three fraction digits, so a forced exponent with a large round (filesize(1, { exponent: 3, round: 10 })) turned 1e-9 into "0 GB". It also ran after the separator replacement, so a custom separator left "1e-9" or "1e+22" in the output.

Expand the number before replacing the separator and allow up to 20 fraction digits.
@avoidwork
avoidwork merged commit 64b4a26 into avoidwork:master Oct 21, 2026
2 checks passed
@avoidwork avoidwork mentioned this pull request Oct 21, 2026
9 of 15 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants