format-money-js
Version:
Zero dependency tiny JavaScript library (1kB bytes) by CurrencyRate.today, providing simple way and advanced number, money and currency formatting and removes all formatting/cruft and returns the raw float value.
144 lines (126 loc) • 3.79 kB
text/typescript
/*!
* format-money-js v1.6.3
* (c) 2020-2023 Yurii Derevych
* URL: https://github.com/dejurin/format-money-js
* Sponsored:
* https://cr.today/
* https://currencyrate.today/
* Released under the BSD-2-Clause License.
*/
export interface FormatMoneyOptions { // (default)
grouping?: boolean; // Example: 1,000 vs 1000 (true)
separator?: string; // Grouping separator (,)
decimalPoint?: string; // Sets the separator for the decimal point.
decimals?: number; // Sets the number of decimal points.
symbol?: string;
append?: boolean;
leadZeros?: boolean;
}
export interface FormatMoneyParse { // Parse
source: number;
negative: boolean;
fullAmount: string;
amount: string;
decimals: string;
symbol: string;
}
export class FormatMoney {
version = '1.6.3';
private defaults: FormatMoneyOptions = {
grouping: true,
separator: ',',
decimalPoint: '.',
decimals: 0,
symbol: '',
append: false,
leadZeros: true,
};
constructor(
private options?: FormatMoneyOptions,
) {
// Merge options
this.options = {
...this.defaults,
...options,
};
}
// Format
from = (
value: number,
options: FormatMoneyOptions | {} = {},
parse: boolean = false,
): FormatMoneyParse | string | undefined => {
// Merge custom options
const customOptions = {
...this.options,
...options,
};
// If value not number return undefined
if (typeof value !== 'number') return undefined;
// If value is NaN
if (Number.isNaN(value)) return undefined;
// Set a sign for negative number
let negativeSign: string = (value < 0) ? '-' : '';
let result: string;
let left: string;
let body: string;
let prefix: string = '';
let suffix: string = '';
result = Math.abs(value).toFixed(customOptions.decimals);
if (parseFloat(result) === 0 || result === '0') {
negativeSign = '';
}
if (!customOptions.leadZeros) {
const resultFloat = parseFloat(result);
result = resultFloat.toString();
}
const resultArr: string[] = result.split('.');
[left] = resultArr;
const right = resultArr.length > 1 ? customOptions.decimalPoint + resultArr[1] : '';
if (customOptions.grouping) {
body = '';
for (let i = 0, len = left.length; i < len; i += 1) {
if (i !== 0 && (i % 3) === 0) {
body = customOptions.separator + body;
}
body = left[len - i - 1] + body;
}
left = body;
}
if (customOptions.append) {
suffix = customOptions.symbol as string;
} else {
prefix = customOptions.symbol as string;
}
if (parse) {
return {
source: value,
negative: (value < 0),
fullAmount: left + right,
amount: left,
decimals: right,
symbol: customOptions.symbol as string,
};
}
return negativeSign + prefix + left + right + suffix;
}
// Unformat
un = (value: (string | number), options: FormatMoneyOptions): number | undefined => {
// Merge custom options
const customOptions = {
...this.options,
...options,
};
if (typeof value === 'number') return value;
if (typeof value !== 'string') return undefined;
// Build regex to strip out everything except digits, decimal point and minus sign:
const regex: RegExp = new RegExp(`[^0-9-${customOptions.decimalPoint}]`, 'g');
const unFormatted = parseFloat(
(value)
.replace(/\((?=\d+)(.*)\)/, '-$1') // replace bracketed values with negatives
.replace(regex, '') // strip out any cruft
.replace(`${customOptions.decimalPoint}`, '.'), // make sure decimal point is standard
);
return !Number.isNaN(unFormatted) ? unFormatted : 0;
}
}