From b3a7897df92c5aa3619729d796a56544dcf1be77 Mon Sep 17 00:00:00 2001 From: Gyanu Mayank Date: Fri, 9 Oct 2026 20:22:46 +0530 Subject: [PATCH] Serialize decimals that round to a whole number with a fractional digit serializeDecimal rounds with toFixed(3) and strips trailing zeros, so 1.0001 became "1." and 9.9999 became "10.". RFC 9651 section 4.1.5 requires a 0 after the period when the fractional component is zero, and parseItem rejects both strings with "Decimal cannot end on a period". --- changelog.md | 8 ++++++++ src/serializer.ts | 3 ++- test/serializer-tests.js | 10 ++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index f15acbc..618a83e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,14 @@ ChangeLog ========= +2.1.1 (????-??-??) +------------------ + +* Decimals that round to a whole number, such as `1.0001`, now serialize as + `1.0` instead of `1.`, which is invalid and was rejected by the parser. + (@gyanu2507) + + 2.1.0 (2026-09-11) ------------------ diff --git a/src/serializer.ts b/src/serializer.ts index 27e81d3..0c75f12 100644 --- a/src/serializer.ts +++ b/src/serializer.ts @@ -129,7 +129,8 @@ export function serializeDecimal(input: number): string { if (signifantDigits > 12) { throw new SerializeError('Fractional numbers are not allowed to have more than 12 significant digits before the decimal point'); } - return out; + // A decimal must have at least one fractional digit. + return out.endsWith('.') ? out + '0' : out; } export function serializeString(input: string): string { diff --git a/test/serializer-tests.js b/test/serializer-tests.js index 6991d9a..54894e9 100644 --- a/test/serializer-tests.js +++ b/test/serializer-tests.js @@ -101,6 +101,16 @@ describe('serializer shorthands', () => { describe('serializeItem', () => { + it('should keep a fractional digit when a decimal rounds to a whole number', () => { + + for (const [input, expected] of [[1.0001, '1.0'], [9.9999, '10.0'], [-0.0001, '-0.0']]) { + const str = serializeItem(input); + assert.equal(str, expected); + assert.deepEqual(parseItem(str), [Number(expected), new Map()]); + } + + }); + it('should error when passing a type that\'s not recognized', () => { let caught = false;