[go: nahoru, domu]

Skip to content

Commit

Permalink
fix(toDecimal): preserve negative sign for leading zeros
Browse files Browse the repository at this point in the history
Change #690 fixed the general case of formatting negative unit values,
but was one remaining case where formatting was still incorrect: when
the first unit is -0, the resulting string didn't include the leading
negative sign.

This change identifies that exact case (negative value, leading zero)
and pads the resulting string with a leading negative sign.

Fixes #692
  • Loading branch information
jparise committed Dec 10, 2022
1 parent c5b9173 commit 5e78040
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 2 deletions.
19 changes: 17 additions & 2 deletions packages/core/src/api/toDecimal.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { NON_DECIMAL_CURRENCY_MESSAGE } from '../checks';
import { assert } from '../helpers';
import type { Calculator, Dinero, Formatter, Transformer } from '../types';
import { absolute, computeBase, equal, isArray } from '../utils';
import {
absolute,
computeBase,
equal,
isArray,
lessThan,
sign,
} from '../utils';

import { toUnits } from './toUnits';

Expand All @@ -14,6 +21,8 @@ export function toDecimal<TAmount, TOutput>(calculator: Calculator<TAmount>) {
const toUnitsFn = toUnits<TAmount, readonly TAmount[]>(calculator);
const computeBaseFn = computeBase(calculator);
const equalFn = equal(calculator);
const lessThanFn = lessThan(calculator);
const signFn = sign(calculator);

return function toDecimalFn(
...[dineroObject, transformer]: ToDecimalParams<TAmount, TOutput>
Expand All @@ -32,9 +41,15 @@ export function toDecimal<TAmount, TOutput>(calculator: Calculator<TAmount>) {
assert(isDecimal, NON_DECIMAL_CURRENCY_MESSAGE);

const units = toUnitsFn(dineroObject);
const isNegative = units.some((unit) => lessThanFn(signFn(unit), zero));

const getDecimalFn = getDecimal(calculator, dineroObject.formatter);
const value = getDecimalFn(units, scale);
const decimalValue = getDecimalFn(units, scale);

// A leading negative zero is a special case because the toString
// formatter (generally String) won't preserve its negative sign.
const value =
isNegative && equalFn(units[0], zero) ? `-${decimalValue}` : decimalValue;

if (!transformer) {
return value;
Expand Down
30 changes: 30 additions & 0 deletions packages/dinero.js/src/api/__tests__/toDecimal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ describe('toDecimal', () => {

expect(toDecimal(d)).toEqual('-10.50');
});
it('returns the negative amount with a leading zero in decimal format', () => {
const d = dinero({ amount: -1, currency: USD });

expect(toDecimal(d)).toEqual('-0.01');
});
it('returns negative zero amount as a positive value in decimal format', () => {
const d = dinero({ amount: -0, currency: USD });

expect(toDecimal(d)).toEqual('0.00');
});
it('uses a custom transformer', () => {
const d = dinero({ amount: 1050, currency: USD });

Expand Down Expand Up @@ -118,6 +128,16 @@ describe('toDecimal', () => {

expect(toDecimal(d)).toEqual('-10.50');
});
it('returns the negative amount with a leading zero in decimal format', () => {
const d = dinero({ amount: -1n, currency: bigintUSD });

expect(toDecimal(d)).toEqual('-0.01');
});
it('returns negative zero amount as a positive value in decimal format', () => {
const d = dinero({ amount: -0n, currency: bigintUSD });

expect(toDecimal(d)).toEqual('0.00');
});
it('uses a custom transformer', () => {
const d = dinero({ amount: 1050n, currency: bigintUSD });

Expand Down Expand Up @@ -198,6 +218,16 @@ describe('toDecimal', () => {

expect(toDecimal(d)).toEqual('-10.05');
});
it('returns the negative amount with a leading zero in decimal format', () => {
const d = dinero({ amount: new Big(-1), currency: bigjsUSD });

expect(toDecimal(d)).toEqual('-0.01');
});
it('returns negative zero amount as a positive value in decimal format', () => {
const d = dinero({ amount: new Big(-0), currency: bigjsUSD });

expect(toDecimal(d)).toEqual('0.00');
});
it('uses a custom transformer', () => {
const d = dinero({ amount: new Big(1050), currency: bigjsUSD });

Expand Down

0 comments on commit 5e78040

Please sign in to comment.