Skip to content

fix(helpers): keep fullform singular for negative one-magnitude values - #337

Open
dualfroz wants to merge 1 commit into
avoidwork:masterfrom
dualfroz:dualfroz/fix-fullform-negative-singular
Open

fix(helpers): keep fullform singular for negative one-magnitude values#337
dualfroz wants to merge 1 commit into
avoidwork:masterfrom
dualfroz:dualfroz/fix-fullform-negative-singular

Conversation

@dualfroz

@dualfroz dualfroz commented Sep 5, 2026

Copy link
Copy Markdown

Problem (self-found)

filesize(-1, { fullform: true }) returns "-1 bytes" instead of the
correct "-1 byte". The positive case is already correct and already
covered by an existing test, which is exactly why this asymmetry wasn't
caught before.

Reproduction (this fork, filesize@11.0.23, Node v22.23.1, on a fresh
clone before the fix):

-1 and -0.125 bits (magnitude 1) are wrongly pluralized; the plural
cases (-2, -0.25 bits) happen to look "correct" only because plural
was already the (wrong-for-the-wrong-reason) fallback.

Root cause

src/helpers.js, decorateResult():

  1. Lines 405-410 (pre-fix numbering): the negative sign is prefixed onto
    result[0] for display:
    if (neg) {
        result[0] = typeof result[0] === "string" ? `-${result[0]}` : -result[0];
    }
  2. Lines 419-424 (pre-fix numbering): numericValue — the value used a
    few lines later to decide singular vs. plural for the fullform
    suffix — is captured from result[0] after that sign has already
    been applied:
    let numericValue;
    if (typeof result[0] === "string") {
        numericValue = parseFloat(result[0]);
    } else {
        numericValue = result[0];
    }
  3. Lines 444-449 (pre-fix numbering): the suffix decision compares the
    signed value against 1:
    if (numericValue === 1) {
        suffix = EMPTY;
    } else {
        suffix = S;
    }
    For input -1, numericValue is -1, so -1 === 1 is false and
    the plural suffix is picked.

Note that by the time decorateResult() runs, result[0] is already the
magnitudefilesize.js negates num back to a positive value right
after computing neg (if (neg) { num = -num; }, around line 101-102)
and does every subsequent computation (exponent, rounding, precision) on
that magnitude. The sign is only reapplied for display inside
decorateResult(). So the singular/plural decision only needs to look at
the magnitude that was already available before the sign was reapplied —
it does not need an Math.abs() call or any other value transformation.

This is the same "capture the numeric magnitude before it gets
stringified/altered" pattern merged PR #312 introduced (to fix a
comma-decimal-separator variant of this same suffix-decision bug, where
parseFloat stopped at a locale comma and read "1,5" as 1). #312's
fix captures numericValue after formatting-relevant mutations but
still after the negation, so the sign case slipped through.

Fix

Move the numericValue capture above the if (neg) block, so it reads
the pre-negation magnitude instead of the signed, display-only value.
Nothing else changes: result[0] is still sign-prefixed afterward for
the displayed value, and the comma/locale handling numericValue exists
for is untouched (it's still computed the same way, just one block
earlier).

let numericValue;
if (typeof result[0] === "string") {
    numericValue = parseFloat(result[0]);
} else {
    numericValue = result[0];
}

if (neg) {
    result[0] = typeof result[0] === "string" ? `-${result[0]}` : -result[0];
}

Changes

  • src/helpers.js: in decorateResult(), capture numericValue before
    the negative sign is prefixed onto result[0], so the fullform
    singular/plural decision is based on magnitude, not the signed display
    value.
  • tests/unit/filesize.test.js: add two tests to the existing
    "Full form names" suite — negative magnitude-1 values (-1 bytes,
    -0.125 bits) stay singular; negative magnitude-2 values (-2 bytes,
    -0.25 bits) stay plural, guarding against a regression in the
    opposite direction.

Contribution terms

No AI/automation restriction was found in CONTRIBUTING.md, AGENTS.md,
README.md, or .github/ at the time of this change.

decorateResult() captured numericValue (used to pick the singular vs
plural fullform suffix) after the negative sign was already prefixed
onto result[0], so filesize(-1, {fullform: true}) compared -1 === 1
and wrongly pluralized to "-1 bytes" instead of "-1 byte". Capture the
magnitude before the sign is applied instead.
@dualfroz
dualfroz force-pushed the dualfroz/fix-fullform-negative-singular branch from cc6ad64 to 15b1dba Compare September 5, 2026 23:13
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.

1 participant