Skip to content

Commit d515dcd

Browse files
committed
fix(tables): reject a non-leading sign so dates don't parse as amounts
Found by Cursor Bugbot. `parseCurrencyInput` dropped every `-` as decoration, so an ISO date's hyphens vanished and its digit groups joined: `2024-01-01` read as 20240101. With the gate now sharing the write path's parser, a date → currency conversion reported zero incompatible rows and silently turned every cell into a huge number. A sign is only meaningful at the front; an interior one means the string is not a single amount. Leading signs, accounting parentheses, symbols, ISO codes, grouping separators, and exponent form all still parse — covered by the existing cases plus new ones, verified to fail without the fix.
1 parent 4cf93cb commit d515dcd

2 files changed

Lines changed: 23 additions & 2 deletions

File tree

apps/sim/lib/table/__tests__/currency.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,20 @@ describe('parseCurrencyInput', () => {
8989
expect(parseCurrencyInput(formatCurrencyForInput(1e21))).toBe(1e21)
9090
})
9191

92+
it('rejects a sign that is not leading, so dates do not read as amounts', () => {
93+
// A date column converting to currency previously turned `2024-01-01` into
94+
// 20240101 — the hyphens were dropped as decoration and the digit groups
95+
// joined. Every cell in the column would have been silently corrupted.
96+
expect(parseCurrencyInput('2024-01-01')).toBeNull()
97+
expect(parseCurrencyInput('2024-01-01T10:30:00Z')).toBeNull()
98+
expect(parseCurrencyInput('1-2-3')).toBeNull()
99+
expect(parseCurrencyInput('12--3')).toBeNull()
100+
// A leading sign is still a sign.
101+
expect(parseCurrencyInput('-12')).toBe(-12)
102+
expect(parseCurrencyInput('+12')).toBe(12)
103+
expect(parseCurrencyInput('-$12.50')).toBe(-12.5)
104+
})
105+
92106
it('rejects values carrying no amount', () => {
93107
expect(parseCurrencyInput('')).toBeNull()
94108
expect(parseCurrencyInput(' ')).toBeNull()

apps/sim/lib/table/currency.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,15 @@ export function parseCurrencyInput(raw: unknown): number | null {
147147
const stripped = body.replace(/[^\d.,\-+]/g, '')
148148
if (!/\d/.test(stripped)) return null
149149

150-
const negative = parenthesized !== null || stripped.startsWith('-')
151-
const digitsAndSeps = stripped.replace(/[+-]/g, '')
150+
// A sign is only meaningful at the front. An interior one means this is not a
151+
// single amount, and dropping it would join unrelated digit groups — an ISO
152+
// date (`2024-01-01`) would otherwise read as 20240101, so converting a date
153+
// column to currency would silently turn every cell into a huge number.
154+
const signed = /^[+-]/.test(stripped)
155+
const digitsAndSeps = signed ? stripped.slice(1) : stripped
156+
if (/[+-]/.test(digitsAndSeps)) return null
157+
158+
const negative = parenthesized !== null || (signed && stripped.startsWith('-'))
152159

153160
const lastComma = digitsAndSeps.lastIndexOf(',')
154161
const lastDot = digitsAndSeps.lastIndexOf('.')

0 commit comments

Comments
 (0)