intl-currency-helper 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -0
- package/index.js +48 -0
- package/package.json +20 -0
- package/test.js +78 -0
- package/utils.js +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Intl Currency Helper
|
|
2
|
+
|
|
3
|
+
A lightweight, zero-dependency JavaScript library for formatting numbers to currency strings using the native `Intl.NumberFormat` API. Compatible with both **Node.js** and **React**.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ๐ **Universal**: Works in the browser and Node.js.
|
|
8
|
+
- ๐ฒ๐ฝ **Smart Defaults**: Pre-configured for Mexican Peso (`MXN`) and Spanish (Mexico) (`es-MX`).
|
|
9
|
+
- ๐ ๏ธ **Customizable**: Easy to override currency, locale, and decimal precision.
|
|
10
|
+
- ๐งช **Safe**: Includes input validation.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# If you published it to NPM
|
|
16
|
+
npm install intl-currency-helper
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or just copy the files into your project.
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### Basic Usage (ES Modules)
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
import { formatCurrency } from './index.js';
|
|
27
|
+
|
|
28
|
+
// Default: MXN / es-MX
|
|
29
|
+
console.log(formatCurrency(1234.56)); // Output: "$1,234.56"
|
|
30
|
+
console.log(formatCurrency("100")); // Output: "$100.00"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Advanced Usage
|
|
34
|
+
|
|
35
|
+
You can customize the formatting by passing an options object.
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
import { formatCurrency, CURRENCIES, LOCALES } from './index.js';
|
|
39
|
+
|
|
40
|
+
// US Dollars
|
|
41
|
+
formatCurrency(1234.56, {
|
|
42
|
+
currency: CURRENCIES.USD,
|
|
43
|
+
locale: LOCALES.US
|
|
44
|
+
});
|
|
45
|
+
// Output: "$1,234.56"
|
|
46
|
+
|
|
47
|
+
// Euros in Spain
|
|
48
|
+
formatCurrency(1234.56, {
|
|
49
|
+
currency: CURRENCIES.EUR,
|
|
50
|
+
locale: LOCALES.ES
|
|
51
|
+
});
|
|
52
|
+
// Output: "1.234,56 โฌ"
|
|
53
|
+
|
|
54
|
+
// No decimals
|
|
55
|
+
formatCurrency(1234.56, {
|
|
56
|
+
minimumFractionDigits: 0,
|
|
57
|
+
maximumFractionDigits: 0
|
|
58
|
+
});
|
|
59
|
+
// Output: "$1,235"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## API
|
|
63
|
+
|
|
64
|
+
### `formatCurrency(amount, options)`
|
|
65
|
+
|
|
66
|
+
| Argument | Type | Description |
|
|
67
|
+
| :--- | :--- | :--- |
|
|
68
|
+
| `amount` | `Number`\|`String` | The value to format. |
|
|
69
|
+
| `options` | `Object` | (Optional) Configuration object. |
|
|
70
|
+
|
|
71
|
+
#### Options
|
|
72
|
+
- `locale` (String): BCP 47 language tag (default: `'es-MX'`).
|
|
73
|
+
- `currency` (String): ISO 4217 currency code (default: `'MXN'`).
|
|
74
|
+
- `minimumFractionDigits` (Number): Default `2`.
|
|
75
|
+
- `maximumFractionDigits` (Number): Default `2`.
|
|
76
|
+
- `useGrouping` (Boolean): Whether to use thousand separators (default: `true`).
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT
|
package/index.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { validateNumber, normalizeOptions } from './utils.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Formats a number into a currency string using Intl.NumberFormat.
|
|
5
|
+
*
|
|
6
|
+
* @param {number|string} amount - The numeric value to format.
|
|
7
|
+
* @param {object} [options] - Optional configuration.
|
|
8
|
+
* @param {string} [options.locale='es-MX'] - The BCP 47 language tag (e.g., 'es-MX', 'en-US').
|
|
9
|
+
* @param {string} [options.currency='MXN'] - The ISO 4217 currency code (e.g., 'MXN', 'USD', 'EUR').
|
|
10
|
+
* @param {number} [options.minimumFractionDigits=2] - Minimum number of decimal places.
|
|
11
|
+
* @param {number} [options.maximumFractionDigits=2] - Maximum number of decimal places.
|
|
12
|
+
* @param {boolean} [options.useGrouping=true] - Whether to use thousand separators.
|
|
13
|
+
* @returns {string} The formatted currency string.
|
|
14
|
+
* @example
|
|
15
|
+
* formatCurrency(1234.56) // "$1,234.56" (default MXN)
|
|
16
|
+
* formatCurrency(1234.56, { currency: 'USD', locale: 'en-US' }) // "$1,234.56"
|
|
17
|
+
*/
|
|
18
|
+
export const formatCurrency = (amount, options = {}) => {
|
|
19
|
+
const number = validateNumber(amount);
|
|
20
|
+
const config = normalizeOptions(options);
|
|
21
|
+
|
|
22
|
+
return new Intl.NumberFormat(config.locale, config).format(number);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Common currency codes for easy reference.
|
|
27
|
+
*/
|
|
28
|
+
export const CURRENCIES = {
|
|
29
|
+
MXN: 'MXN',
|
|
30
|
+
USD: 'USD',
|
|
31
|
+
EUR: 'EUR',
|
|
32
|
+
GBP: 'GBP',
|
|
33
|
+
CAD: 'CAD',
|
|
34
|
+
JPY: 'JPY',
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Common locales for easy reference.
|
|
39
|
+
*/
|
|
40
|
+
export const LOCALES = {
|
|
41
|
+
MX: 'es-MX',
|
|
42
|
+
US: 'en-US',
|
|
43
|
+
ES: 'es-ES',
|
|
44
|
+
GB: 'en-GB',
|
|
45
|
+
JP: 'ja-JP',
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export default formatCurrency;
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "intl-currency-helper",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A lightweight library for formatting numbers to currency using Intl.NumberFormat, optimized for both Node.js and React.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "node test.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"currency",
|
|
12
|
+
"format",
|
|
13
|
+
"intl",
|
|
14
|
+
"money",
|
|
15
|
+
"react",
|
|
16
|
+
"nodejs"
|
|
17
|
+
],
|
|
18
|
+
"author": "Antigravity",
|
|
19
|
+
"license": "MIT"
|
|
20
|
+
}
|
package/test.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { formatCurrency, CURRENCIES, LOCALES } from './index.js';
|
|
2
|
+
|
|
3
|
+
const tests = [
|
|
4
|
+
{
|
|
5
|
+
name: 'Default formatting (MXN / es-MX)',
|
|
6
|
+
input: 1234.56,
|
|
7
|
+
expected: '$1,234.56', // Note: specific spacing can vary by environment, we'll check contains
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
name: 'USD / en-US',
|
|
11
|
+
input: 1234.56,
|
|
12
|
+
options: { currency: CURRENCIES.USD, locale: LOCALES.US },
|
|
13
|
+
expected: '$1,234.56',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: 'EUR / es-ES',
|
|
17
|
+
input: 1234.56,
|
|
18
|
+
options: { currency: CURRENCIES.EUR, locale: LOCALES.ES },
|
|
19
|
+
expected: '1.234,56\u00A0โฌ', // Note: \u00A0 is non-breaking space
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'Negative number',
|
|
23
|
+
input: -500,
|
|
24
|
+
expected: '-$500.00',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'Zero',
|
|
28
|
+
input: 0,
|
|
29
|
+
expected: '$0.00',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'String input',
|
|
33
|
+
input: "99.99",
|
|
34
|
+
expected: '$99.99',
|
|
35
|
+
}
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
let passed = 0;
|
|
39
|
+
let total = tests.length;
|
|
40
|
+
|
|
41
|
+
console.log('--- Starting Tests ---\n');
|
|
42
|
+
|
|
43
|
+
tests.forEach(test => {
|
|
44
|
+
try {
|
|
45
|
+
const result = formatCurrency(test.input, test.options);
|
|
46
|
+
// Use includes/regex/normalize to avoid tiny formatting discrepancies in different environments (like nbsp)
|
|
47
|
+
const normalizedResult = result.replace(/\u00A0/g, ' ').trim();
|
|
48
|
+
const normalizedExpected = test.expected.replace(/\u00A0/g, ' ').trim();
|
|
49
|
+
|
|
50
|
+
if (normalizedResult === normalizedExpected || normalizedResult.includes(normalizedExpected)) {
|
|
51
|
+
console.log(`โ
[PASS] ${test.name}`);
|
|
52
|
+
passed++;
|
|
53
|
+
} else {
|
|
54
|
+
console.log(`โ [FAIL] ${test.name}`);
|
|
55
|
+
console.log(` Expected: ${test.expected}`);
|
|
56
|
+
console.log(` Received: ${result}`);
|
|
57
|
+
}
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.log(`โ [ERROR] ${test.name}: ${error.message}`);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Error handling test
|
|
64
|
+
console.log('\n--- Error Handling Test ---');
|
|
65
|
+
try {
|
|
66
|
+
formatCurrency('not-a-number');
|
|
67
|
+
console.log('โ [FAIL] Should have thrown an error for invalid input');
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.log('โ
[PASS] Threw error for invalid input: ' + error.message);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.log(`\n--- Summary: ${passed}/${total} passed ---`);
|
|
73
|
+
|
|
74
|
+
if (passed === total) {
|
|
75
|
+
process.exit(0);
|
|
76
|
+
} else {
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
package/utils.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates if the input is a valid number.
|
|
3
|
+
* @param {any} value - The value to validate.
|
|
4
|
+
* @returns {number} The validated number.
|
|
5
|
+
* @throws {Error} if the value is not a valid number.
|
|
6
|
+
*/
|
|
7
|
+
export const validateNumber = (value) => {
|
|
8
|
+
const number = Number(value);
|
|
9
|
+
if (isNaN(number)) {
|
|
10
|
+
throw new Error(`Invalid input: expected a number, but received ${typeof value} (${value})`);
|
|
11
|
+
}
|
|
12
|
+
return number;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Normalizes options for Intl.NumberFormat.
|
|
17
|
+
* @param {object} options - User-provided options.
|
|
18
|
+
* @returns {object} Normalized options.
|
|
19
|
+
*/
|
|
20
|
+
export const normalizeOptions = (options = {}) => {
|
|
21
|
+
const defaults = {
|
|
22
|
+
locale: 'es-MX',
|
|
23
|
+
currency: 'MXN',
|
|
24
|
+
minimumFractionDigits: 2,
|
|
25
|
+
maximumFractionDigits: 2,
|
|
26
|
+
style: 'currency',
|
|
27
|
+
useGrouping: true,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
return { ...defaults, ...options };
|
|
31
|
+
};
|