fix: Handle unicode minus in number parsing (#6247)

* fix(core): handle unicode minus in number parsing

Fixes #6206. Added support for Unicode minus (U+2212) in looselyParseAmount, currencyToAmount, and stringToInteger. Added unit tests.

* Refactor: Improve currency parsing logic

Co-authored-by: matiss <matiss@mja.lv>

* Refactor: Simplify currency parsing logic

Co-authored-by: matiss <matiss@mja.lv>

* [autofix.ci] apply automated fixes

* fix: Handle Unicode minus inside parentheses correctly

Fixed bug where amounts with both parentheses and Unicode minus (e.g.,
(−3.45)) were parsed as null instead of negative numbers. The Unicode minus
is now removed from within parentheses before the parentheses-to-minus
conversion, preventing double minus signs that caused parseFloat to return NaN.

Added test cases for parenthesized amounts containing Unicode minus.

* Add release notes for PR #6247

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Matiss Janis Aboltins
2025-12-04 21:42:37 +00:00
committed by GitHub
parent 809ab503d7
commit 43970c14b1
3 changed files with 35 additions and 1 deletions

View File

@@ -3,6 +3,7 @@ import {
getNumberFormat,
setNumberFormat,
currencyToAmount,
stringToInteger,
titleFirst,
} from './util';
@@ -49,11 +50,18 @@ describe('utility functions', () => {
expect(looselyParseAmount('-3')).toBe(-3);
expect(looselyParseAmount('-3.45')).toBe(-3.45);
expect(looselyParseAmount('-3,45')).toBe(-3.45);
// Unicode minus
expect(looselyParseAmount('3')).toBe(-3);
expect(looselyParseAmount('3.45')).toBe(-3.45);
expect(looselyParseAmount('3,45')).toBe(-3.45);
});
test('looseParseAmount works with parentheses (negative)', () => {
expect(looselyParseAmount('(3.45)')).toBe(-3.45);
expect(looselyParseAmount('(3)')).toBe(-3);
// Parentheses with Unicode minus
expect(looselyParseAmount('(3.45)')).toBe(-3.45);
expect(looselyParseAmount('(3)')).toBe(-3);
});
test('looseParseAmount ignores non-numeric characters', () => {
@@ -142,6 +150,10 @@ describe('utility functions', () => {
expect(currencyToAmount('-3')).toBe(-3);
expect(currencyToAmount('-3.45')).toBe(-3.45);
expect(currencyToAmount('-3,45')).toBe(-3.45);
// Unicode minus
expect(currencyToAmount('3')).toBe(-3);
expect(currencyToAmount('3.45')).toBe(-3.45);
expect(currencyToAmount('3,45')).toBe(-3.45);
});
test('currencyToAmount works with non-fractional numbers', () => {
@@ -181,4 +193,10 @@ describe('utility functions', () => {
expect(titleFirst('a')).toBe('A');
expect(titleFirst('abc')).toBe('Abc');
});
test('stringToInteger works with negative numbers', () => {
expect(stringToInteger('-3')).toBe(-3);
// Unicode minus
expect(stringToInteger('3')).toBe(-3);
});
});

View File

@@ -461,6 +461,8 @@ export function amountToCurrencyNoDecimal(amount: Amount): CurrencyAmount {
}
export function currencyToAmount(currencyAmount: string): Amount | null {
currencyAmount = currencyAmount.replace(/\u2212/g, '-');
let integer, fraction;
// match the last dot or comma in the string
@@ -490,7 +492,9 @@ export function currencyToInteger(
}
export function stringToInteger(str: string): number | null {
const amount = parseInt(str.replace(/[^-0-9.,]/g, ''));
const amount = parseInt(
str.replace(/\u2212/g, '-').replace(/[^-0-9.,]/g, ''),
);
if (!isNaN(amount)) {
return amount;
}
@@ -536,7 +540,12 @@ export function looselyParseAmount(amount: string) {
}
if (amount.startsWith('(') && amount.endsWith(')')) {
// Remove Unicode minus inside parentheses before converting to ASCII minus
amount = amount.replace(/\u2212/g, '');
amount = amount.replace('(', '-').replace(')', '');
} else {
// Replace Unicode minus with ASCII minus for non-parenthesized amounts
amount = amount.replace(/\u2212/g, '-');
}
// Look for a decimal marker, then look for either 1-2 or 4-9 decimal places.

View File

@@ -0,0 +1,7 @@
---
category: Bugfix
authors: [MatissJanis]
---
Fix number parsing to recognize Unicode minus as a valid negative indicator.