@eternl/formats
v0.9.13
Published
Locale-aware display and CSV formatting helpers for numeric data.
Maintainers
Readme
@eternl/formats
Locale-aware display formatting and CSV-safe number helpers for browser-based dashboards and exports.
Installation
npm install @eternl/formatsQuick Start
import Big from 'big.js'
import {
buildCsv,
csvCurrencyCode,
formatCsvDate,
formatCsvNumber,
formatCsvPercent,
formatDisplayCurrency,
formatDisplayPercent,
formatDisplayCompact
} from '@eternl/formats'
const amount = new Big('1234567.890123')
const priceUS = formatDisplayCurrency(amount, {
locale: 'en-US',
currencyCode: 'USD',
minDecimals: 2,
maxDecimals: 2,
useSymbol: true
}) // "$1,234,567.89"
const priceDE = formatDisplayCurrency(amount, {
locale: 'de-DE',
currencyCode: 'EUR',
minDecimals: 2,
maxDecimals: 2,
useSymbol: true
}) // "1.234.567,89 €"
const adaDisplay = formatDisplayCurrency('123456789.123456', {
locale: 'en-US',
currencyCode: 'ADA',
customSymbols: { ADA: '₳' },
minDecimals: 2,
maxDecimals: 6
}) // "₳123,456,789.123456"
const masked = formatDisplayCurrency('1234.5', {
locale: 'en-US',
currencyCode: 'USD',
minDecimals: 2,
maxDecimals: 2,
isHidden: true
}) // "$*.**"
const maskedWithDash = formatDisplayCurrency('1234.5', {
locale: 'en-US',
currencyCode: 'USD',
minDecimals: 2,
maxDecimals: 2,
isHidden: true,
hiddenCharacter: '-'
}) // "$-.--"
const pctDisplay = formatDisplayPercent('0.125', {
locale: 'en-US',
minDecimals: 1,
maxDecimals: 2
}) // "12.5%"
const compact = formatDisplayCompact('9876543', {
locale: 'en-US',
compact: true,
maxDecimals: 1
}) // "9.9M"
const csvNumber = formatCsvNumber(amount, { maxDecimals: 6, trimTrailingZeros: true })
const csvPercent = formatCsvPercent('0.125')
const csvCurrency = csvCurrencyCode('ADA', { ADA: '₳' }, false)
const rows = [
{ ts: new Date('2025-10-06T12:00:00Z'), amount, currency: 'ADA', ratio: '0.125' }
]
const csv = buildCsv(rows, [
{ header: 'date', accessor: (row) => row.ts, formatter: (value) => formatCsvDate(value as Date) },
{ header: 'amount', accessor: (row) => row.amount, formatter: (value) => formatCsvNumber(value as Big, { maxDecimals: 6 }) },
{ header: 'currency', accessor: (row) => row.currency, formatter: (value) => csvCurrencyCode(String(value), { ADA: '₳' }, false) },
{ header: 'percent', accessor: (row) => row.ratio, formatter: (value) => formatCsvPercent(value as string, { maxDecimals: 4 }) }
])The generated CSV is fully ASCII (. decimal separator, no grouping) and imports cleanly into Google Sheets, Koinly, and CoinTracking.
Display Formatting
formatDisplayNumberhandles localized decimals with grouping, optional sign display, and rounding controls.formatDisplayCurrencycombinesIntl.NumberFormatwith optional custom symbols (₳, ₿, etc.). Spacing from the host locale is preserved unless a custom symbol removes it.formatDisplayPercentmultiplies by 100 for display while respecting locale decimal and percent symbols.formatDisplayCompactapplies configurable K/M/B/T suffixes using precisebig.jsarithmetic (no scientific notation).
Common options:
{
minDecimals?: number
maxDecimals?: number
precision?: number // significant digits
roundingMode?: 'roundDown' | 'roundHalfUp' | 'roundHalfEven' | 'roundUp'
trimTrailingZeros?: boolean (default: false)
signDisplay?: 'auto' | 'always' | 'exceptZero' | 'never' | 'negative'
useGrouping?: boolean
isHidden?: boolean // mask digits with maskCharacter (default '*')
hiddenCharacter?: string
}CSV Formatting
formatCsvNumberoutputs plain ASCII digits and a dot decimal separator, honoring min/max decimals, precision, and trimming.formatCsvPercentmultiplies the ratio by 100 and emits an unadorned numeric string (no%).csvCurrencyCodekeeps currency symbols or codes in a dedicated column so numeric fields stay clean.
formatCsvNumber('0.00000001', { maxDecimals: 8 }) // "0.00000001"
formatCsvPercent('0.125', { maxDecimals: 4 }) // "12.5"
csvCurrencyCode('btc', { BTC: '₿' }, true) // "₿"CSV Builder
buildCsv(rows, columns, delimiter = ',', lineEnding = '\n') applies per-column accessors and formatters, quoting fields with delimiters, quotes, or newlines (RFC 4180). Numeric results produced by formatCsvNumber never require quoting, so imports remain numeric.
Date Helpers
formatDisplayDate(input, locale, options)cachesIntl.DateTimeFormatinstances.formatCsvDate(input)emits ISO-8601 strings:YYYY-MM-DDfor midnight UTC, otherwiseYYYY-MM-DDTHH:mm:ssZ.
Development
npm run lint # type-check
npm test # run Vitest suite
npm run build # emit ESM + CJS bundles into dist/The test suite covers locale differences, rounding edge cases, percent handling, large/small magnitudes, and CSV quoting rules.
