global-currency-words 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shaik Esub
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,191 @@
1
+ # global-currency-words
2
+
3
+ > Convert numeric currency amounts to human-readable words.
4
+ > Supports **15-digit numbers**, **decimals/subunits**, **30+ countries**, and **currency codes**.
5
+
6
+ ```js
7
+ currencyWords(1234.56, { country: "India" })
8
+ // => "One Thousand Two Hundred Thirty Four Rupees and Fifty Six Paise"
9
+
10
+ currencyWords(999999999999999, { country: "USA", includeCode: true })
11
+ // => "Nine Hundred Ninety Nine Trillion ... Nine Hundred Ninety Nine Dollars (USD)"
12
+ ```
13
+
14
+ ---
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install global-currency-words
20
+ ```
21
+
22
+ ---
23
+
24
+ ## Quick Start
25
+
26
+ ```js
27
+ const { currencyWords } = require("global-currency-words");
28
+
29
+ // Default: United States (USD)
30
+ currencyWords(500);
31
+ // => "Five Hundred Dollars"
32
+
33
+ currencyWords(1050.75, { country: "India" });
34
+ // => "One Thousand Fifty Rupees and Seventy Five Paise"
35
+
36
+ currencyWords(99.01, { country: "UK" });
37
+ // => "Ninety Nine Pounds and One Penny"
38
+ ```
39
+
40
+ ---
41
+
42
+ ## API
43
+
44
+ ### `currencyWords(amount, options?)`
45
+
46
+ | Parameter | Type | Description |
47
+ |-----------|------|-------------|
48
+ | `amount` | `number \| string` | The monetary amount. Supports up to **15 digits** before the decimal. Can be negative. |
49
+ | `options` | `CurrencyWordsOptions` | Optional configuration (see below). |
50
+
51
+ **Returns:** `string`
52
+
53
+ #### Options
54
+
55
+ | Option | Type | Default | Description |
56
+ |--------|------|---------|-------------|
57
+ | `country` | `string` | `"United States"` | Country name **or** ISO 4217 currency code (e.g. `"India"`, `"INR"`, `"USD"`) |
58
+ | `includeDecimals` | `boolean` | `true` | Include subunit (cents/paise/etc.) in the output |
59
+ | `decimalPlaces` | `number` | `2` | How many decimal places to read (`1` or `2`) |
60
+ | `includeSymbol` | `boolean` | `false` | Prepend the currency symbol (e.g. `₹`, `$`) |
61
+ | `includeCode` | `boolean` | `false` | Append the ISO currency code (e.g. `(INR)`) |
62
+ | `andBeforeDecimals` | `boolean` | `true` | Use "and" between main amount and subunit |
63
+
64
+ ---
65
+
66
+ ### `getCurrencyInfo(countryOrCode)`
67
+
68
+ Returns metadata for a given country or currency code.
69
+
70
+ ```js
71
+ const { getCurrencyInfo } = require("global-currency-words");
72
+
73
+ getCurrencyInfo("Japan");
74
+ // {
75
+ // currency: "Yen", currencyPlural: "Yen",
76
+ // subunit: "Sen", subunitPlural: "Sen",
77
+ // symbol: "¥", code: "JPY", subunitFactor: 100
78
+ // }
79
+ ```
80
+
81
+ ---
82
+
83
+ ### `listCountries()`
84
+
85
+ Returns all supported country names as an array of strings.
86
+
87
+ ```js
88
+ const { listCountries } = require("global-currency-words");
89
+ listCountries();
90
+ // => ["India", "Pakistan", "United States", "United Kingdom", ...]
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Examples
96
+
97
+ ```js
98
+ const { currencyWords } = require("global-currency-words");
99
+
100
+ // Basic usage
101
+ currencyWords(0);
102
+ // => "Zero Dollars"
103
+
104
+ // Large number (15 digits)
105
+ currencyWords("999999999999999");
106
+ // => "Nine Hundred Ninety Nine Trillion ... Nine Hundred Ninety Nine Dollars"
107
+
108
+ // With symbol and code
109
+ currencyWords(1500, { country: "India", includeSymbol: true, includeCode: true });
110
+ // => "₹ One Thousand Five Hundred Rupees (INR)"
111
+
112
+ // Without "and"
113
+ currencyWords(10.50, { andBeforeDecimals: false });
114
+ // => "Ten Dollars Fifty Cents"
115
+
116
+ // Only 1 decimal place
117
+ currencyWords(10.5, { decimalPlaces: 1 });
118
+ // => "Ten Dollars and Five Cents"
119
+
120
+ // Ignore decimal part
121
+ currencyWords(100.99, { includeDecimals: false });
122
+ // => "One Hundred Dollars"
123
+
124
+ // Negative amount
125
+ currencyWords(-250.50, { country: "UK" });
126
+ // => "Negative Two Hundred Fifty Pounds and Fifty Pence"
127
+
128
+ // Lookup by currency code
129
+ currencyWords(100, { country: "EUR" });
130
+ // => "One Hundred Euros"
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Supported Countries
136
+
137
+ | Country | Code | Currency | Subunit |
138
+ |---------|------|----------|---------|
139
+ | India | INR | Rupee | Paisa |
140
+ | United States / USA | USD | Dollar | Cent |
141
+ | United Kingdom / UK | GBP | Pound | Penny/Pence |
142
+ | Euro Zone / Germany / France… | EUR | Euro | Cent |
143
+ | Japan | JPY | Yen | Sen |
144
+ | China | CNY | Yuan | Fen |
145
+ | Australia | AUD | Dollar | Cent |
146
+ | Canada | CAD | Dollar | Cent |
147
+ | UAE | AED | Dirham | Fils |
148
+ | Saudi Arabia | SAR | Riyal | Halala |
149
+ | Singapore | SGD | Dollar | Cent |
150
+ | South Africa | ZAR | Rand | Cent |
151
+ | Brazil | BRL | Real | Centavo |
152
+ | Russia | RUB | Ruble | Kopek |
153
+ | Pakistan | PKR | Rupee | Paisa |
154
+ | Bangladesh | BDT | Taka | Paisa |
155
+ | Indonesia | IDR | Rupiah | Sen |
156
+ | Malaysia | MYR | Ringgit | Sen |
157
+ | Thailand | THB | Baht | Satang |
158
+ | Switzerland | CHF | Franc | Centime |
159
+ | … and more | | | |
160
+
161
+ > Use `listCountries()` for the full list, or pass an ISO 4217 code directly.
162
+
163
+ ---
164
+
165
+ ## Limits & Validation
166
+
167
+ - Maximum **15 digits** in the integer part (up to 999,999,999,999,999)
168
+ - Throws `RangeError` if the integer part exceeds 15 digits
169
+ - Throws `TypeError` for invalid or missing amounts
170
+ - Throws `Error` for unsupported country names
171
+
172
+ ---
173
+
174
+ ## TypeScript
175
+
176
+ Full TypeScript definitions are included:
177
+
178
+ ```ts
179
+ import { currencyWords, getCurrencyInfo, listCountries, CurrencyWordsOptions } from "global-currency-words";
180
+
181
+ const result: string = currencyWords(1234.56, {
182
+ country: "India",
183
+ includeCode: true,
184
+ });
185
+ ```
186
+
187
+ ---
188
+
189
+ ## License
190
+
191
+ MIT
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "global-currency-words",
3
+ "version": "1.0.0",
4
+ "description": "Convert numeric currency amounts to words. Supports 15-digit numbers, decimal points, and 30+ countries/currencies.",
5
+ "main": "src/index.js",
6
+ "types": "src/index.d.ts",
7
+ "scripts": {
8
+ "test": "node test/index.test.js"
9
+ },
10
+ "keywords": [
11
+ "currency",
12
+ "words",
13
+ "number-to-words",
14
+ "currency-converter",
15
+ "amount-in-words",
16
+ "inr",
17
+ "usd",
18
+ "eur",
19
+ "rupees",
20
+ "dollars"
21
+ ],
22
+ "author": "codify",
23
+ "license": "MIT",
24
+ "engines": {
25
+ "node": ">=12.0.0"
26
+ }
27
+ }
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+
3
+ const ONES = [
4
+ "",
5
+ "One",
6
+ "Two",
7
+ "Three",
8
+ "Four",
9
+ "Five",
10
+ "Six",
11
+ "Seven",
12
+ "Eight",
13
+ "Nine",
14
+ "Ten",
15
+ "Eleven",
16
+ "Twelve",
17
+ "Thirteen",
18
+ "Fourteen",
19
+ "Fifteen",
20
+ "Sixteen",
21
+ "Seventeen",
22
+ "Eighteen",
23
+ "Nineteen",
24
+ ];
25
+
26
+ const TENS = [
27
+ "",
28
+ "",
29
+ "Twenty",
30
+ "Thirty",
31
+ "Forty",
32
+ "Fifty",
33
+ "Sixty",
34
+ "Seventy",
35
+ "Eighty",
36
+ "Ninety",
37
+ ];
38
+
39
+ /**
40
+ * Convert a number 0–999 to words.
41
+ */
42
+ function convertHundreds(n) {
43
+ if (n === 0) return "";
44
+ if (n < 20) return ONES[n];
45
+ if (n < 100) {
46
+ const rem = n % 10;
47
+ return TENS[Math.floor(n / 10)] + (rem ? " " + ONES[rem] : "");
48
+ }
49
+ const rem = n % 100;
50
+ return (
51
+ ONES[Math.floor(n / 100)] +
52
+ " Hundred" +
53
+ (rem ? " " + convertHundreds(rem) : "")
54
+ );
55
+ }
56
+
57
+ /**
58
+ * Convert an integer (BigInt-safe via string) up to 15 digits to words.
59
+ * Returns "" for 0.
60
+ */
61
+ function integerToWords(numStr) {
62
+ // Remove leading zeros
63
+ numStr = String(numStr).replace(/^0+/, "") || "0";
64
+
65
+ if (numStr === "0") return "Zero";
66
+ if (numStr.length > 15) {
67
+ throw new Error("Number exceeds 15-digit limit (max: 999,999,999,999,999)");
68
+ }
69
+
70
+ // Pad to 15 digits for slicing
71
+ const padded = numStr.padStart(15, "0");
72
+
73
+ // Groups (Indian system awareness + international)
74
+ // We split into: [trillions(3), billions(3), millions(3), thousands(3), hundreds(3)]
75
+ const groups = [
76
+ { value: parseInt(padded.slice(0, 3), 10), label: "Trillion" },
77
+ { value: parseInt(padded.slice(3, 6), 10), label: "Billion" },
78
+ { value: parseInt(padded.slice(6, 9), 10), label: "Million" },
79
+ { value: parseInt(padded.slice(9, 12), 10), label: "Thousand" },
80
+ { value: parseInt(padded.slice(12, 15), 10), label: "" },
81
+ ];
82
+
83
+ const parts = [];
84
+ for (const { value, label } of groups) {
85
+ if (value === 0) continue;
86
+ const words = convertHundreds(value);
87
+ parts.push(label ? words + " " + label : words);
88
+ }
89
+
90
+ return parts.join(" ");
91
+ }
92
+
93
+ module.exports = { integerToWords, convertHundreds };
@@ -0,0 +1,358 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Currency definitions by country name (case-insensitive lookup)
5
+ * Each entry: { currency, subunit, symbol, code, subunitFactor }
6
+ */
7
+ const CURRENCIES = {
8
+ // Asia
9
+ india: {
10
+ currency: "Rupee",
11
+ currencyPlural: "Rupees",
12
+ subunit: "Paisa",
13
+ subunitPlural: "Paise",
14
+ symbol: "₹",
15
+ code: "INR",
16
+ subunitFactor: 100,
17
+ },
18
+ pakistan: {
19
+ currency: "Rupee",
20
+ currencyPlural: "Rupees",
21
+ subunit: "Paisa",
22
+ subunitPlural: "Paise",
23
+ symbol: "₨",
24
+ code: "PKR",
25
+ subunitFactor: 100,
26
+ },
27
+ "sri lanka": {
28
+ currency: "Rupee",
29
+ currencyPlural: "Rupees",
30
+ subunit: "Cent",
31
+ subunitPlural: "Cents",
32
+ symbol: "Rs",
33
+ code: "LKR",
34
+ subunitFactor: 100,
35
+ },
36
+ nepal: {
37
+ currency: "Rupee",
38
+ currencyPlural: "Rupees",
39
+ subunit: "Paisa",
40
+ subunitPlural: "Paise",
41
+ symbol: "Rs",
42
+ code: "NPR",
43
+ subunitFactor: 100,
44
+ },
45
+ bangladesh: {
46
+ currency: "Taka",
47
+ currencyPlural: "Taka",
48
+ subunit: "Paisa",
49
+ subunitPlural: "Paise",
50
+ symbol: "৳",
51
+ code: "BDT",
52
+ subunitFactor: 100,
53
+ },
54
+ china: {
55
+ currency: "Yuan",
56
+ currencyPlural: "Yuan",
57
+ subunit: "Fen",
58
+ subunitPlural: "Fen",
59
+ symbol: "¥",
60
+ code: "CNY",
61
+ subunitFactor: 100,
62
+ },
63
+ japan: {
64
+ currency: "Yen",
65
+ currencyPlural: "Yen",
66
+ subunit: "Sen",
67
+ subunitPlural: "Sen",
68
+ symbol: "¥",
69
+ code: "JPY",
70
+ subunitFactor: 100,
71
+ },
72
+ "south korea": {
73
+ currency: "Won",
74
+ currencyPlural: "Won",
75
+ subunit: "Jeon",
76
+ subunitPlural: "Jeon",
77
+ symbol: "₩",
78
+ code: "KRW",
79
+ subunitFactor: 100,
80
+ },
81
+ indonesia: {
82
+ currency: "Rupiah",
83
+ currencyPlural: "Rupiah",
84
+ subunit: "Sen",
85
+ subunitPlural: "Sen",
86
+ symbol: "Rp",
87
+ code: "IDR",
88
+ subunitFactor: 100,
89
+ },
90
+ malaysia: {
91
+ currency: "Ringgit",
92
+ currencyPlural: "Ringgit",
93
+ subunit: "Sen",
94
+ subunitPlural: "Sen",
95
+ symbol: "RM",
96
+ code: "MYR",
97
+ subunitFactor: 100,
98
+ },
99
+ singapore: {
100
+ currency: "Dollar",
101
+ currencyPlural: "Dollars",
102
+ subunit: "Cent",
103
+ subunitPlural: "Cents",
104
+ symbol: "S$",
105
+ code: "SGD",
106
+ subunitFactor: 100,
107
+ },
108
+ thailand: {
109
+ currency: "Baht",
110
+ currencyPlural: "Baht",
111
+ subunit: "Satang",
112
+ subunitPlural: "Satang",
113
+ symbol: "฿",
114
+ code: "THB",
115
+ subunitFactor: 100,
116
+ },
117
+ "united arab emirates": {
118
+ currency: "Dirham",
119
+ currencyPlural: "Dirhams",
120
+ subunit: "Fils",
121
+ subunitPlural: "Fils",
122
+ symbol: "د.إ",
123
+ code: "AED",
124
+ subunitFactor: 100,
125
+ },
126
+ uae: {
127
+ currency: "Dirham",
128
+ currencyPlural: "Dirhams",
129
+ subunit: "Fils",
130
+ subunitPlural: "Fils",
131
+ symbol: "د.إ",
132
+ code: "AED",
133
+ subunitFactor: 100,
134
+ },
135
+ "saudi arabia": {
136
+ currency: "Riyal",
137
+ currencyPlural: "Riyals",
138
+ subunit: "Halala",
139
+ subunitPlural: "Halalas",
140
+ symbol: "﷼",
141
+ code: "SAR",
142
+ subunitFactor: 100,
143
+ },
144
+
145
+ // Americas
146
+ "united states": {
147
+ currency: "Dollar",
148
+ currencyPlural: "Dollars",
149
+ subunit: "Cent",
150
+ subunitPlural: "Cents",
151
+ symbol: "$",
152
+ code: "USD",
153
+ subunitFactor: 100,
154
+ },
155
+ usa: {
156
+ currency: "Dollar",
157
+ currencyPlural: "Dollars",
158
+ subunit: "Cent",
159
+ subunitPlural: "Cents",
160
+ symbol: "$",
161
+ code: "USD",
162
+ subunitFactor: 100,
163
+ },
164
+ canada: {
165
+ currency: "Dollar",
166
+ currencyPlural: "Dollars",
167
+ subunit: "Cent",
168
+ subunitPlural: "Cents",
169
+ symbol: "CA$",
170
+ code: "CAD",
171
+ subunitFactor: 100,
172
+ },
173
+ mexico: {
174
+ currency: "Peso",
175
+ currencyPlural: "Pesos",
176
+ subunit: "Centavo",
177
+ subunitPlural: "Centavos",
178
+ symbol: "MX$",
179
+ code: "MXN",
180
+ subunitFactor: 100,
181
+ },
182
+ brazil: {
183
+ currency: "Real",
184
+ currencyPlural: "Reais",
185
+ subunit: "Centavo",
186
+ subunitPlural: "Centavos",
187
+ symbol: "R$",
188
+ code: "BRL",
189
+ subunitFactor: 100,
190
+ },
191
+ argentina: {
192
+ currency: "Peso",
193
+ currencyPlural: "Pesos",
194
+ subunit: "Centavo",
195
+ subunitPlural: "Centavos",
196
+ symbol: "AR$",
197
+ code: "ARS",
198
+ subunitFactor: 100,
199
+ },
200
+
201
+ // Europe
202
+ "euro zone": {
203
+ currency: "Euro",
204
+ currencyPlural: "Euros",
205
+ subunit: "Cent",
206
+ subunitPlural: "Cents",
207
+ symbol: "€",
208
+ code: "EUR",
209
+ subunitFactor: 100,
210
+ },
211
+ germany: {
212
+ currency: "Euro",
213
+ currencyPlural: "Euros",
214
+ subunit: "Cent",
215
+ subunitPlural: "Cents",
216
+ symbol: "€",
217
+ code: "EUR",
218
+ subunitFactor: 100,
219
+ },
220
+ france: {
221
+ currency: "Euro",
222
+ currencyPlural: "Euros",
223
+ subunit: "Cent",
224
+ subunitPlural: "Cents",
225
+ symbol: "€",
226
+ code: "EUR",
227
+ subunitFactor: 100,
228
+ },
229
+ italy: {
230
+ currency: "Euro",
231
+ currencyPlural: "Euros",
232
+ subunit: "Cent",
233
+ subunitPlural: "Cents",
234
+ symbol: "€",
235
+ code: "EUR",
236
+ subunitFactor: 100,
237
+ },
238
+ spain: {
239
+ currency: "Euro",
240
+ currencyPlural: "Euros",
241
+ subunit: "Cent",
242
+ subunitPlural: "Cents",
243
+ symbol: "€",
244
+ code: "EUR",
245
+ subunitFactor: 100,
246
+ },
247
+ "united kingdom": {
248
+ currency: "Pound",
249
+ currencyPlural: "Pounds",
250
+ subunit: "Penny",
251
+ subunitPlural: "Pence",
252
+ symbol: "£",
253
+ code: "GBP",
254
+ subunitFactor: 100,
255
+ },
256
+ uk: {
257
+ currency: "Pound",
258
+ currencyPlural: "Pounds",
259
+ subunit: "Penny",
260
+ subunitPlural: "Pence",
261
+ symbol: "£",
262
+ code: "GBP",
263
+ subunitFactor: 100,
264
+ },
265
+ switzerland: {
266
+ currency: "Franc",
267
+ currencyPlural: "Francs",
268
+ subunit: "Centime",
269
+ subunitPlural: "Centimes",
270
+ symbol: "CHF",
271
+ code: "CHF",
272
+ subunitFactor: 100,
273
+ },
274
+ sweden: {
275
+ currency: "Krona",
276
+ currencyPlural: "Kronor",
277
+ subunit: "Öre",
278
+ subunitPlural: "Öre",
279
+ symbol: "kr",
280
+ code: "SEK",
281
+ subunitFactor: 100,
282
+ },
283
+ norway: {
284
+ currency: "Krone",
285
+ currencyPlural: "Kroner",
286
+ subunit: "Øre",
287
+ subunitPlural: "Øre",
288
+ symbol: "kr",
289
+ code: "NOK",
290
+ subunitFactor: 100,
291
+ },
292
+ russia: {
293
+ currency: "Ruble",
294
+ currencyPlural: "Rubles",
295
+ subunit: "Kopek",
296
+ subunitPlural: "Kopeks",
297
+ symbol: "₽",
298
+ code: "RUB",
299
+ subunitFactor: 100,
300
+ },
301
+
302
+ // Africa & Oceania
303
+ "south africa": {
304
+ currency: "Rand",
305
+ currencyPlural: "Rand",
306
+ subunit: "Cent",
307
+ subunitPlural: "Cents",
308
+ symbol: "R",
309
+ code: "ZAR",
310
+ subunitFactor: 100,
311
+ },
312
+ australia: {
313
+ currency: "Dollar",
314
+ currencyPlural: "Dollars",
315
+ subunit: "Cent",
316
+ subunitPlural: "Cents",
317
+ symbol: "A$",
318
+ code: "AUD",
319
+ subunitFactor: 100,
320
+ },
321
+ "new zealand": {
322
+ currency: "Dollar",
323
+ currencyPlural: "Dollars",
324
+ subunit: "Cent",
325
+ subunitPlural: "Cents",
326
+ symbol: "NZ$",
327
+ code: "NZD",
328
+ subunitFactor: 100,
329
+ },
330
+ };
331
+
332
+ /**
333
+ * Lookup by country name (case-insensitive) or currency code (e.g. "USD")
334
+ */
335
+ function getCurrency(countryOrCode) {
336
+ if (!countryOrCode) return CURRENCIES["united states"];
337
+ const key = countryOrCode.trim().toLowerCase();
338
+ if (CURRENCIES[key]) return CURRENCIES[key];
339
+
340
+ // Try matching by currency code
341
+ const byCode = Object.values(CURRENCIES).find(
342
+ (c) => c.code.toLowerCase() === key
343
+ );
344
+ if (byCode) return byCode;
345
+
346
+ throw new Error(
347
+ `Unsupported country or currency code: "${countryOrCode}". ` +
348
+ `Supported: ${getSupportedCountries().join(", ")}`
349
+ );
350
+ }
351
+
352
+ function getSupportedCountries() {
353
+ return Object.keys(CURRENCIES).map((k) =>
354
+ k.replace(/\b\w/g, (c) => c.toUpperCase())
355
+ );
356
+ }
357
+
358
+ module.exports = { getCurrency, getSupportedCountries, CURRENCIES };
package/src/index.d.ts ADDED
@@ -0,0 +1,79 @@
1
+ export interface CurrencyInfo {
2
+ currency: string;
3
+ currencyPlural: string;
4
+ subunit: string;
5
+ subunitPlural: string;
6
+ symbol: string;
7
+ code: string;
8
+ subunitFactor: number;
9
+ }
10
+
11
+ export interface CurrencyWordsOptions {
12
+ /**
13
+ * Country name (e.g. "India", "United States") or ISO 4217 currency code (e.g. "INR", "USD").
14
+ * @default "United States"
15
+ */
16
+ country?: string;
17
+
18
+ /**
19
+ * Whether to include the decimal/subunit part in the output.
20
+ * @default true
21
+ */
22
+ includeDecimals?: boolean;
23
+
24
+ /**
25
+ * Number of decimal places to read (1 or 2).
26
+ * @default 2
27
+ */
28
+ decimalPlaces?: number;
29
+
30
+ /**
31
+ * Prepend the currency symbol to the result (e.g. "₹ One Hundred Rupees").
32
+ * @default false
33
+ */
34
+ includeSymbol?: boolean;
35
+
36
+ /**
37
+ * Append the ISO currency code to the result (e.g. "One Hundred Dollars (USD)").
38
+ * @default false
39
+ */
40
+ includeCode?: boolean;
41
+
42
+ /**
43
+ * Use "and" between the main amount and the subunit amount.
44
+ * @default true
45
+ */
46
+ andBeforeDecimals?: boolean;
47
+ }
48
+
49
+ /**
50
+ * Convert a numeric currency amount to words.
51
+ *
52
+ * Supports up to 15 digits in the integer part.
53
+ *
54
+ * @param amount - Numeric amount as a number or string
55
+ * @param options - Conversion options
56
+ * @returns Human-readable currency string
57
+ *
58
+ * @example
59
+ * currencyWords(1050.75, { country: "India" })
60
+ * // => "One Thousand Fifty Rupees and Seventy Five Paise"
61
+ *
62
+ * @example
63
+ * currencyWords("999999999999999", { country: "USA", includeCode: true })
64
+ * // => "Nine Hundred Ninety Nine Trillion Nine Hundred Ninety Nine Billion ... Dollars (USD)"
65
+ */
66
+ export function currencyWords(
67
+ amount: number | string,
68
+ options?: CurrencyWordsOptions
69
+ ): string;
70
+
71
+ /**
72
+ * Get currency metadata for a given country or currency code.
73
+ */
74
+ export function getCurrencyInfo(countryOrCode: string): CurrencyInfo;
75
+
76
+ /**
77
+ * List all supported country names.
78
+ */
79
+ export function listCountries(): string[];
package/src/index.js ADDED
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+
3
+ const { getCurrency, getSupportedCountries } = require("./currencies");
4
+ const { integerToWords } = require("./converter");
5
+
6
+ /**
7
+ * @typedef {Object} CurrencyWordsOptions
8
+ * @property {string} [country="United States"] Country name or currency code (e.g. "India", "USD")
9
+ * @property {boolean} [includeDecimals=true] Whether to include decimal/subunit words
10
+ * @property {number} [decimalPlaces=2] Decimal places to consider (1 or 2)
11
+ * @property {boolean} [includeSymbol=false] Prepend the currency symbol
12
+ * @property {boolean} [includeCode=false] Append the currency ISO code
13
+ * @property {boolean} [andBeforeDecimals=true] Add "and" before subunit part
14
+ */
15
+
16
+ /**
17
+ * Convert a numeric amount to currency words.
18
+ *
19
+ * @param {number|string} amount - The amount (up to 15 digits before decimal)
20
+ * @param {CurrencyWordsOptions} options
21
+ * @returns {string}
22
+ *
23
+ * @example
24
+ * currencyWords(1234.56, { country: "India" })
25
+ * // => "One Thousand Two Hundred Thirty Four Rupees and Fifty Six Paise"
26
+ *
27
+ * @example
28
+ * currencyWords(500, { country: "USA" })
29
+ * // => "Five Hundred Dollars"
30
+ */
31
+ function currencyWords(amount, options = {}) {
32
+ const {
33
+ country = "United States",
34
+ includeDecimals = true,
35
+ decimalPlaces = 2,
36
+ includeSymbol = false,
37
+ includeCode = false,
38
+ andBeforeDecimals = true,
39
+ } = options;
40
+
41
+ // ── Validate & parse amount ──────────────────────────────────────────────
42
+ if (amount === null || amount === undefined || amount === "") {
43
+ throw new TypeError("amount is required");
44
+ }
45
+
46
+ const amountStr = String(amount).trim();
47
+ if (!/^-?\d+(\.\d+)?$/.test(amountStr)) {
48
+ throw new TypeError(`Invalid amount: "${amount}". Must be a numeric value.`);
49
+ }
50
+
51
+ const isNegative = amountStr.startsWith("-");
52
+ const absStr = isNegative ? amountStr.slice(1) : amountStr;
53
+
54
+ const dotIndex = absStr.indexOf(".");
55
+ const intPart = dotIndex === -1 ? absStr : absStr.slice(0, dotIndex);
56
+ const rawDecimalStr = dotIndex === -1 ? "" : absStr.slice(dotIndex + 1);
57
+
58
+ // Enforce 15-digit integer limit
59
+ const cleanInt = intPart.replace(/^0+/, "") || "0";
60
+ if (cleanInt.length > 15) {
61
+ throw new RangeError(
62
+ `Integer part exceeds 15 digits. Got ${cleanInt.length} digits.`
63
+ );
64
+ }
65
+
66
+ // ── Resolve currency ─────────────────────────────────────────────────────
67
+ const currency = getCurrency(country);
68
+
69
+ // ── Integer words ────────────────────────────────────────────────────────
70
+ const intWords = integerToWords(cleanInt);
71
+ const intValue = parseInt(cleanInt, 10);
72
+ const currencyLabel =
73
+ intValue === 1 ? currency.currency : currency.currencyPlural;
74
+
75
+ let result = intWords + " " + currencyLabel;
76
+
77
+ // ── Decimal / subunit words ──────────────────────────────────────────────
78
+ if (includeDecimals && rawDecimalStr) {
79
+ const places = Math.min(Math.max(parseInt(decimalPlaces, 10) || 2, 1), 2);
80
+
81
+ // Pad or trim decimal string to `places` digits
82
+ let decStr = rawDecimalStr.padEnd(places, "0").slice(0, places);
83
+ const decValue = parseInt(decStr, 10);
84
+
85
+ if (decValue > 0) {
86
+ const decWords = integerToWords(String(decValue));
87
+ const subLabel =
88
+ decValue === 1 ? currency.subunit : currency.subunitPlural;
89
+
90
+ result +=
91
+ (andBeforeDecimals ? " and " : " ") + decWords + " " + subLabel;
92
+ }
93
+ }
94
+
95
+ // ── Negative ─────────────────────────────────────────────────────────────
96
+ if (isNegative) {
97
+ result = "Negative " + result;
98
+ }
99
+
100
+ // ── Symbol / code affixes ─────────────────────────────────────────────────
101
+ if (includeSymbol) {
102
+ result = currency.symbol + " " + result;
103
+ }
104
+ if (includeCode) {
105
+ result = result + " (" + currency.code + ")";
106
+ }
107
+
108
+ return result;
109
+ }
110
+
111
+ /**
112
+ * Get currency info for a country.
113
+ *
114
+ * @param {string} country
115
+ * @returns {{ currency, currencyPlural, subunit, subunitPlural, symbol, code, subunitFactor }}
116
+ */
117
+ function getCurrencyInfo(country) {
118
+ return getCurrency(country);
119
+ }
120
+
121
+ /**
122
+ * List all supported countries.
123
+ * @returns {string[]}
124
+ */
125
+ function listCountries() {
126
+ return getSupportedCountries();
127
+ }
128
+
129
+ module.exports = { currencyWords, getCurrencyInfo, listCountries };