n2words 4.0.0 → 5.1.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.
Files changed (309) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +14 -12
  3. package/dist/am-ET.js +2 -2
  4. package/dist/am-ET.umd.js +2 -2
  5. package/dist/am-Latn-ET.js +2 -2
  6. package/dist/am-Latn-ET.umd.js +2 -2
  7. package/dist/ar-SA.js +2 -2
  8. package/dist/ar-SA.umd.js +2 -2
  9. package/dist/az-AZ.js +2 -2
  10. package/dist/az-AZ.umd.js +2 -2
  11. package/dist/bn-BD.js +2 -2
  12. package/dist/bn-BD.umd.js +2 -2
  13. package/dist/cs-CZ.js +2 -2
  14. package/dist/cs-CZ.umd.js +2 -2
  15. package/dist/da-DK.js +2 -2
  16. package/dist/da-DK.umd.js +2 -2
  17. package/dist/de-DE.js +2 -2
  18. package/dist/de-DE.umd.js +2 -2
  19. package/dist/el-GR.js +2 -2
  20. package/dist/el-GR.umd.js +2 -2
  21. package/dist/en-AU.js +2 -2
  22. package/dist/en-AU.umd.js +2 -2
  23. package/dist/en-BD.js +2 -2
  24. package/dist/en-BD.umd.js +2 -2
  25. package/dist/en-CA.js +2 -2
  26. package/dist/en-CA.umd.js +2 -2
  27. package/dist/en-GB.js +2 -2
  28. package/dist/en-GB.umd.js +2 -2
  29. package/dist/en-GH.js +2 -2
  30. package/dist/en-GH.umd.js +2 -2
  31. package/dist/en-IE.js +2 -2
  32. package/dist/en-IE.umd.js +2 -2
  33. package/dist/en-IN.js +2 -2
  34. package/dist/en-IN.umd.js +2 -2
  35. package/dist/en-KE.js +2 -2
  36. package/dist/en-KE.umd.js +2 -2
  37. package/dist/en-MY.js +2 -2
  38. package/dist/en-MY.umd.js +2 -2
  39. package/dist/en-NG.js +2 -2
  40. package/dist/en-NG.umd.js +2 -2
  41. package/dist/en-NZ.js +2 -2
  42. package/dist/en-NZ.umd.js +2 -2
  43. package/dist/en-PH.js +2 -2
  44. package/dist/en-PH.umd.js +2 -2
  45. package/dist/en-PK.js +2 -2
  46. package/dist/en-PK.umd.js +2 -2
  47. package/dist/en-SG.js +2 -2
  48. package/dist/en-SG.umd.js +2 -2
  49. package/dist/en-US.js +2 -2
  50. package/dist/en-US.umd.js +2 -2
  51. package/dist/en-ZA.js +2 -2
  52. package/dist/en-ZA.umd.js +2 -2
  53. package/dist/es-ES.js +2 -2
  54. package/dist/es-ES.umd.js +2 -2
  55. package/dist/es-MX.js +2 -2
  56. package/dist/es-MX.umd.js +2 -2
  57. package/dist/es-US.js +2 -2
  58. package/dist/es-US.umd.js +2 -2
  59. package/dist/fa-IR.js +2 -2
  60. package/dist/fa-IR.umd.js +2 -2
  61. package/dist/fi-FI.js +2 -2
  62. package/dist/fi-FI.umd.js +2 -2
  63. package/dist/fil-PH.js +2 -2
  64. package/dist/fil-PH.umd.js +2 -2
  65. package/dist/fr-BE.js +2 -2
  66. package/dist/fr-BE.umd.js +2 -2
  67. package/dist/fr-FR.js +2 -2
  68. package/dist/fr-FR.umd.js +2 -2
  69. package/dist/gu-IN.js +2 -2
  70. package/dist/gu-IN.umd.js +2 -2
  71. package/dist/ha-NG.js +2 -2
  72. package/dist/ha-NG.umd.js +2 -2
  73. package/dist/hbo-IL.js +2 -2
  74. package/dist/hbo-IL.umd.js +2 -2
  75. package/dist/he-IL.js +2 -2
  76. package/dist/he-IL.umd.js +2 -2
  77. package/dist/hi-IN.js +2 -2
  78. package/dist/hi-IN.umd.js +2 -2
  79. package/dist/hr-HR.js +2 -2
  80. package/dist/hr-HR.umd.js +2 -2
  81. package/dist/hu-HU.js +2 -2
  82. package/dist/hu-HU.umd.js +2 -2
  83. package/dist/id-ID.js +2 -2
  84. package/dist/id-ID.umd.js +2 -2
  85. package/dist/it-IT.js +2 -2
  86. package/dist/it-IT.umd.js +2 -2
  87. package/dist/ja-JP.js +2 -2
  88. package/dist/ja-JP.umd.js +2 -2
  89. package/dist/ka-GE.js +2 -2
  90. package/dist/ka-GE.umd.js +2 -2
  91. package/dist/kn-IN.js +2 -2
  92. package/dist/kn-IN.umd.js +2 -2
  93. package/dist/ko-KR.js +2 -2
  94. package/dist/ko-KR.umd.js +2 -2
  95. package/dist/lt-LT.js +2 -2
  96. package/dist/lt-LT.umd.js +2 -2
  97. package/dist/lv-LV.js +2 -2
  98. package/dist/lv-LV.umd.js +2 -2
  99. package/dist/mr-IN.js +2 -2
  100. package/dist/mr-IN.umd.js +2 -2
  101. package/dist/ms-MY.js +2 -2
  102. package/dist/ms-MY.umd.js +2 -2
  103. package/dist/nb-NO.js +2 -2
  104. package/dist/nb-NO.umd.js +2 -2
  105. package/dist/nl-NL.js +2 -2
  106. package/dist/nl-NL.umd.js +2 -2
  107. package/dist/pa-IN.js +2 -2
  108. package/dist/pa-IN.umd.js +2 -2
  109. package/dist/pl-PL.js +2 -2
  110. package/dist/pl-PL.umd.js +2 -2
  111. package/dist/pt-BR.js +2 -0
  112. package/dist/pt-BR.umd.js +2 -0
  113. package/dist/pt-PT.js +2 -2
  114. package/dist/pt-PT.umd.js +2 -2
  115. package/dist/ro-RO.js +2 -2
  116. package/dist/ro-RO.umd.js +2 -2
  117. package/dist/ru-RU.js +2 -2
  118. package/dist/ru-RU.umd.js +2 -2
  119. package/dist/sr-Cyrl-RS.js +2 -2
  120. package/dist/sr-Cyrl-RS.umd.js +2 -2
  121. package/dist/sr-Latn-RS.js +2 -2
  122. package/dist/sr-Latn-RS.umd.js +2 -2
  123. package/dist/sv-SE.js +2 -2
  124. package/dist/sv-SE.umd.js +2 -2
  125. package/dist/sw-KE.js +2 -2
  126. package/dist/sw-KE.umd.js +2 -2
  127. package/dist/ta-IN.js +2 -2
  128. package/dist/ta-IN.umd.js +2 -2
  129. package/dist/te-IN.js +2 -2
  130. package/dist/te-IN.umd.js +2 -2
  131. package/dist/th-TH.js +2 -2
  132. package/dist/th-TH.umd.js +2 -2
  133. package/dist/tr-TR.js +2 -2
  134. package/dist/tr-TR.umd.js +2 -2
  135. package/dist/uk-UA.js +2 -2
  136. package/dist/uk-UA.umd.js +2 -2
  137. package/dist/ur-PK.js +2 -2
  138. package/dist/ur-PK.umd.js +2 -2
  139. package/dist/vi-VN.js +2 -2
  140. package/dist/vi-VN.umd.js +2 -2
  141. package/dist/yo-NG.js +2 -2
  142. package/dist/yo-NG.umd.js +2 -2
  143. package/dist/zh-Hans-CN.js +2 -2
  144. package/dist/zh-Hans-CN.umd.js +2 -2
  145. package/dist/zh-Hant-TW.js +2 -2
  146. package/dist/zh-Hant-TW.umd.js +2 -2
  147. package/package.json +53 -36
  148. package/src/am-ET.d.ts +3 -5
  149. package/src/am-ET.js +41 -16
  150. package/src/am-Latn-ET.d.ts +3 -5
  151. package/src/am-Latn-ET.js +45 -16
  152. package/src/ar-SA.d.ts +44 -18
  153. package/src/ar-SA.js +93 -40
  154. package/src/az-AZ.d.ts +3 -5
  155. package/src/az-AZ.js +58 -20
  156. package/src/bn-BD.d.ts +3 -5
  157. package/src/bn-BD.js +32 -16
  158. package/src/cs-CZ.d.ts +3 -6
  159. package/src/cs-CZ.js +66 -42
  160. package/src/da-DK.d.ts +3 -6
  161. package/src/da-DK.js +53 -48
  162. package/src/de-DE.d.ts +17 -11
  163. package/src/de-DE.js +88 -57
  164. package/src/el-GR.d.ts +3 -6
  165. package/src/el-GR.js +45 -32
  166. package/src/en-AU.d.ts +17 -11
  167. package/src/en-AU.js +56 -41
  168. package/src/en-BD.d.ts +17 -11
  169. package/src/en-BD.js +60 -41
  170. package/src/en-CA.d.ts +36 -18
  171. package/src/en-CA.js +67 -46
  172. package/src/en-GB.d.ts +17 -11
  173. package/src/en-GB.js +56 -41
  174. package/src/en-GH.d.ts +32 -3
  175. package/src/en-GH.js +104 -26
  176. package/src/en-IE.d.ts +17 -11
  177. package/src/en-IE.js +56 -41
  178. package/src/en-IN.d.ts +17 -11
  179. package/src/en-IN.js +60 -41
  180. package/src/en-KE.d.ts +28 -3
  181. package/src/en-KE.js +93 -26
  182. package/src/en-MY.d.ts +26 -3
  183. package/src/en-MY.js +91 -26
  184. package/src/en-NG.d.ts +17 -11
  185. package/src/en-NG.js +56 -41
  186. package/src/en-NZ.d.ts +32 -3
  187. package/src/en-NZ.js +85 -31
  188. package/src/en-PH.d.ts +32 -3
  189. package/src/en-PH.js +97 -26
  190. package/src/en-PK.d.ts +17 -11
  191. package/src/en-PK.js +60 -41
  192. package/src/en-SG.d.ts +28 -3
  193. package/src/en-SG.js +93 -26
  194. package/src/en-US.d.ts +36 -18
  195. package/src/en-US.js +70 -47
  196. package/src/en-ZA.d.ts +17 -11
  197. package/src/en-ZA.js +56 -41
  198. package/src/es-ES.d.ts +53 -21
  199. package/src/es-ES.js +104 -56
  200. package/src/es-MX.d.ts +53 -21
  201. package/src/es-MX.js +104 -56
  202. package/src/es-US.d.ts +53 -21
  203. package/src/es-US.js +92 -51
  204. package/src/fa-IR.d.ts +3 -5
  205. package/src/fa-IR.js +28 -13
  206. package/src/fi-FI.d.ts +3 -6
  207. package/src/fi-FI.js +47 -29
  208. package/src/fil-PH.d.ts +3 -5
  209. package/src/fil-PH.js +61 -28
  210. package/src/fr-BE.d.ts +31 -15
  211. package/src/fr-BE.js +128 -57
  212. package/src/fr-FR.d.ts +31 -16
  213. package/src/fr-FR.js +97 -60
  214. package/src/gu-IN.d.ts +3 -5
  215. package/src/gu-IN.js +31 -16
  216. package/src/ha-NG.d.ts +3 -5
  217. package/src/ha-NG.js +55 -27
  218. package/src/hbo-IL.d.ts +26 -12
  219. package/src/hbo-IL.js +92 -51
  220. package/src/he-IL.d.ts +17 -10
  221. package/src/he-IL.js +92 -50
  222. package/src/hi-IN.d.ts +3 -5
  223. package/src/hi-IN.js +30 -17
  224. package/src/hr-HR.d.ts +21 -10
  225. package/src/hr-HR.js +89 -33
  226. package/src/hu-HU.d.ts +3 -5
  227. package/src/hu-HU.js +57 -23
  228. package/src/id-ID.d.ts +3 -5
  229. package/src/id-ID.js +56 -23
  230. package/src/it-IT.d.ts +17 -11
  231. package/src/it-IT.js +74 -43
  232. package/src/ja-JP.d.ts +3 -6
  233. package/src/ja-JP.js +39 -26
  234. package/src/ka-GE.d.ts +3 -6
  235. package/src/ka-GE.js +38 -26
  236. package/src/kn-IN.d.ts +3 -5
  237. package/src/kn-IN.js +31 -16
  238. package/src/ko-KR.d.ts +3 -6
  239. package/src/ko-KR.js +34 -26
  240. package/src/lt-LT.d.ts +21 -11
  241. package/src/lt-LT.js +64 -42
  242. package/src/lv-LV.d.ts +21 -11
  243. package/src/lv-LV.js +79 -51
  244. package/src/mr-IN.d.ts +3 -5
  245. package/src/mr-IN.js +31 -16
  246. package/src/ms-MY.d.ts +3 -5
  247. package/src/ms-MY.js +58 -24
  248. package/src/nb-NO.d.ts +3 -6
  249. package/src/nb-NO.js +54 -34
  250. package/src/nl-NL.d.ts +41 -20
  251. package/src/nl-NL.js +111 -69
  252. package/src/pa-IN.d.ts +3 -5
  253. package/src/pa-IN.js +32 -16
  254. package/src/pl-PL.d.ts +21 -11
  255. package/src/pl-PL.js +69 -45
  256. package/src/pt-BR.d.ts +42 -0
  257. package/src/pt-BR.js +574 -0
  258. package/src/pt-PT.d.ts +17 -11
  259. package/src/pt-PT.js +80 -48
  260. package/src/ro-RO.d.ts +21 -11
  261. package/src/ro-RO.js +77 -39
  262. package/src/ru-RU.d.ts +35 -15
  263. package/src/ru-RU.js +100 -38
  264. package/src/sr-Cyrl-RS.d.ts +35 -15
  265. package/src/sr-Cyrl-RS.js +100 -38
  266. package/src/sr-Latn-RS.d.ts +35 -15
  267. package/src/sr-Latn-RS.js +100 -38
  268. package/src/sv-SE.d.ts +3 -6
  269. package/src/sv-SE.js +53 -34
  270. package/src/sw-KE.d.ts +3 -5
  271. package/src/sw-KE.js +50 -20
  272. package/src/ta-IN.d.ts +3 -5
  273. package/src/ta-IN.js +29 -17
  274. package/src/te-IN.d.ts +3 -5
  275. package/src/te-IN.js +31 -16
  276. package/src/th-TH.d.ts +3 -5
  277. package/src/th-TH.js +42 -19
  278. package/src/tr-TR.d.ts +17 -11
  279. package/src/tr-TR.js +63 -37
  280. package/src/uk-UA.d.ts +21 -10
  281. package/src/uk-UA.js +89 -33
  282. package/src/ur-PK.d.ts +3 -5
  283. package/src/ur-PK.js +32 -16
  284. package/src/utils/check-max.d.ts +26 -0
  285. package/src/utils/check-max.js +33 -0
  286. package/src/utils/expand-scientific.d.ts +0 -4
  287. package/src/utils/expand-scientific.js +7 -9
  288. package/src/utils/is-plain-object.d.ts +3 -4
  289. package/src/utils/is-plain-object.js +3 -4
  290. package/src/utils/parse-cardinal.d.ts +1 -2
  291. package/src/utils/parse-cardinal.js +12 -9
  292. package/src/utils/parse-currency.d.ts +1 -2
  293. package/src/utils/parse-currency.js +9 -11
  294. package/src/utils/parse-ordinal.d.ts +0 -1
  295. package/src/utils/parse-ordinal.js +9 -10
  296. package/src/utils/resolve-options.d.ts +17 -0
  297. package/src/utils/resolve-options.js +56 -0
  298. package/src/utils/scale.d.ts +49 -0
  299. package/src/utils/scale.js +65 -0
  300. package/src/vi-VN.d.ts +3 -6
  301. package/src/vi-VN.js +41 -28
  302. package/src/yo-NG.d.ts +3 -5
  303. package/src/yo-NG.js +49 -33
  304. package/src/zh-Hans-CN.d.ts +45 -20
  305. package/src/zh-Hans-CN.js +84 -31
  306. package/src/zh-Hant-TW.d.ts +45 -20
  307. package/src/zh-Hant-TW.js +85 -34
  308. package/src/utils/validate-options.d.ts +0 -8
  309. package/src/utils/validate-options.js +0 -16
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "n2words",
3
- "version": "4.0.0",
4
- "description": "Convert numbers to words in 71 languages with zero dependencies. Supports BigInt, decimals, and browser/Node.js environments.",
3
+ "version": "5.1.0",
4
+ "description": "Convert numbers to words in 70+ languages with zero dependencies. Supports BigInt, decimals, and browser/Node.js environments.",
5
5
  "keywords": [
6
6
  "number-to-words",
7
7
  "num2words",
@@ -46,6 +46,14 @@
46
46
  "./utils/*": null,
47
47
  "./package.json": "./package.json"
48
48
  },
49
+ "typesVersions": {
50
+ "*": {
51
+ "utils/*": [],
52
+ "*": [
53
+ "./src/*.d.ts"
54
+ ]
55
+ }
56
+ },
49
57
  "files": [
50
58
  "src/**/*.js",
51
59
  "src/**/*.d.ts",
@@ -58,24 +66,27 @@
58
66
  "bench": "node --expose-gc bench/index.js",
59
67
  "browserslist": "browserslist",
60
68
  "browserslist:coverage": "browserslist --coverage",
61
- "build": "npm run clean && npm run build:types && npm run build:dist",
62
- "build:dist": "npm run clean:dist && rollup -c",
63
- "build:types": "npm run clean:types && tsc --project tsconfig.build.json",
64
- "clean": "npm run clean:dist && npm run clean:types",
65
- "clean:all": "npm run clean && npm run clean:artifacts",
69
+ "build": "node --run clean && node --run build:types && node --run build:dist",
70
+ "build:dist": "node --run clean:dist && rollup -c",
71
+ "build:types": "node --run clean:types && tsc --project tsconfig.build.json",
72
+ "clean": "node --run clean:dist && node --run clean:types",
73
+ "clean:all": "node --run clean && node --run clean:artifacts",
66
74
  "clean:artifacts": "rimraf coverage .nyc_output",
67
75
  "clean:dist": "rimraf dist",
68
76
  "clean:types": "rimraf \"src/**/*.d.ts\" --glob",
69
- "coverage": "c8 npm run test:unit",
77
+ "coverage": "c8 node --run test:unit",
78
+ "coverage:check": "c8 check-coverage",
70
79
  "docs:languages": "node scripts/generate-languages-md.js",
71
80
  "lang:add": "node scripts/add-language.js",
72
- "lint": "npm run lint:js && npm run lint:md",
73
- "lint:fix": "npm run lint:js -- --fix && npm run lint:md -- --fix",
74
- "lint:js": "standard",
81
+ "lint": "node --run lint:js && node --run lint:md",
82
+ "lint:fix": "eslint --fix && markdownlint-cli2 --fix",
83
+ "lint:js": "eslint",
75
84
  "lint:md": "markdownlint-cli2",
85
+ "prepack": "node --run build",
76
86
  "prepare:husky": "husky",
77
- "test": "npm run test:unit && npm run build:types",
78
- "test:unit": "ava \"test/*.test.js\" \"test/utils/*.test.js\""
87
+ "test": "node --run test:unit && node --run build:types",
88
+ "test:unit": "ava \"test/*.test.js\" \"test/utils/*.test.js\"",
89
+ "typecheck": "tsc --project tsconfig.build.json --noEmit"
79
90
  },
80
91
  "ava": {
81
92
  "extensions": [
@@ -89,11 +100,6 @@
89
100
  "concurrency": 8,
90
101
  "workerThreads": false
91
102
  },
92
- "standard": {
93
- "ignore": [
94
- "!.vscode/"
95
- ]
96
- },
97
103
  "c8": {
98
104
  "all": true,
99
105
  "include": [
@@ -106,41 +112,52 @@
106
112
  "lcov",
107
113
  "text",
108
114
  "json-summary"
109
- ]
115
+ ],
116
+ "lines": 90,
117
+ "statements": 90,
118
+ "functions": 90,
119
+ "branches": 85
110
120
  },
111
121
  "lint-staged": {
112
122
  "*.{js,cjs,mjs}": [
113
- "standard --fix"
123
+ "eslint --fix"
114
124
  ],
115
125
  "*.md": [
116
126
  "markdownlint-cli2 --fix"
117
127
  ]
118
128
  },
119
129
  "devDependencies": {
120
- "@babel/core": "^7.29.0",
121
- "@babel/preset-env": "^7.29.0",
122
- "@commitlint/cli": "^20.4.3",
123
- "@commitlint/config-conventional": "^20.4.3",
124
- "@commitlint/format": "^20.4.3",
125
- "@rollup/plugin-babel": "^7.0.0",
126
- "@rollup/plugin-node-resolve": "^16.0.3",
130
+ "@commitlint/cli": "^21.0.2",
131
+ "@commitlint/config-conventional": "^21.0.2",
132
+ "@eslint-community/eslint-plugin-eslint-comments": "^4.7.2",
133
+ "@eslint/js": "^10.0.1",
127
134
  "@rollup/plugin-terser": "^1.0.0",
128
135
  "@rollup/plugin-virtual": "^3.0.2",
129
- "ava": "^7.0.0",
130
- "benchmark": "^2.1.4",
131
- "browserslist": "^4.28.1",
136
+ "@stylistic/eslint-plugin": "^5.10.0",
137
+ "@types/node": "^24.13.2",
138
+ "ava": "^8.0.1",
139
+ "browserslist": "^4.28.2",
132
140
  "c8": "^11.0.0",
133
141
  "chalk": "^5.6.2",
142
+ "eslint": "^10.5.0",
143
+ "eslint-plugin-ava": "^17.0.1",
144
+ "eslint-plugin-compat": "^7.0.2",
145
+ "eslint-plugin-es-x": "^9.6.0",
146
+ "eslint-plugin-import-x": "^4.16.2",
147
+ "eslint-plugin-jsdoc": "^63.0.4",
148
+ "eslint-plugin-n": "^18.1.0",
149
+ "fast-check": "^4.8.0",
150
+ "globals": "^17.6.0",
134
151
  "husky": "^9.1.7",
135
- "lint-staged": "^16.3.2",
136
- "markdownlint-cli2": "^0.21.0",
152
+ "lint-staged": "^17.0.7",
153
+ "markdownlint-cli2": "^0.22.1",
137
154
  "rimraf": "^6.1.3",
138
- "rollup": "^4.59.0",
139
- "standard": "^17.1.2",
140
- "typescript": "^5.9.3"
155
+ "rollup": "^4.62.0",
156
+ "tinybench": "^6.0.2",
157
+ "typescript": "^6.0.3"
141
158
  },
142
159
  "engines": {
143
- "node": ">=20"
160
+ "node": ">=22"
144
161
  },
145
162
  "publishConfig": {
146
163
  "access": "public",
package/src/am-ET.d.ts CHANGED
@@ -1,6 +1,8 @@
1
+ export const cardinalMax: bigint;
2
+ export const ordinalMax: bigint;
3
+ export const currencyMax: bigint;
1
4
  /**
2
5
  * Converts a numeric value to Amharic words.
3
- *
4
6
  * @param {number | string | bigint} value - The numeric value to convert
5
7
  * @returns {string} The number in Amharic words
6
8
  */
@@ -10,12 +12,10 @@ export function toCardinal(value: number | string | bigint): string;
10
12
  *
11
13
  * Amharic ordinals: add -ኛ suffix to cardinal.
12
14
  * Special case: 1 → አንደኛ
13
- *
14
15
  * @param {number | string | bigint} value - The numeric value to convert (positive integer)
15
16
  * @returns {string} The number as ordinal words
16
17
  * @throws {TypeError} If value is not a valid numeric type
17
18
  * @throws {RangeError} If value is negative, zero, or has a decimal part
18
- *
19
19
  * @example
20
20
  * toOrdinal(1) // 'አንደኛ'
21
21
  * toOrdinal(2) // 'ሁለትኛ'
@@ -25,12 +25,10 @@ export function toCardinal(value: number | string | bigint): string;
25
25
  export function toOrdinal(value: number | string | bigint): string;
26
26
  /**
27
27
  * Converts a numeric value to Amharic currency words (Ethiopian Birr).
28
- *
29
28
  * @param {number | string | bigint} value - The currency amount to convert
30
29
  * @returns {string} The amount in Amharic currency words
31
30
  * @throws {TypeError} If value is not a valid numeric type
32
31
  * @throws {Error} If value is not a valid number format
33
- *
34
32
  * @example
35
33
  * toCurrency(42.50) // 'አርባ ሁለት ብር ሃምሳ ሳንቲም'
36
34
  * toCurrency(1) // 'አንድ ብር'
package/src/am-ET.js CHANGED
@@ -14,6 +14,8 @@
14
14
  import { parseCardinalValue } from './utils/parse-cardinal.js'
15
15
  import { parseCurrencyValue } from './utils/parse-currency.js'
16
16
  import { parseOrdinalValue } from './utils/parse-ordinal.js'
17
+ import { checkMax } from './utils/check-max.js'
18
+ import { western } from './utils/scale.js'
17
19
 
18
20
  // ============================================================================
19
21
  // Vocabulary
@@ -53,11 +55,23 @@ const SANTIM = 'ሳንቲም'
53
55
  // Short scale
54
56
  const SCALE_WORDS = ['', THOUSAND, 'ሚሊዮን', 'ቢሊዮን']
55
57
 
58
+ // Supported magnitude ceiling (checked at the public entry points). SCALE_WORDS
59
+ // reaches index SCALE_WORDS.length-1 (ቢሊዮን, 10^9), so values must stay below
60
+ // 10^(SCALE_WORDS.length * 3) = 10^12. Ordinal and currency build on the
61
+ // cardinal, so they share it. Decimals are read digit-by-digit (no ceiling).
62
+ export const cardinalMax = western(SCALE_WORDS.length - 1)
63
+ export const ordinalMax = western(SCALE_WORDS.length - 1)
64
+ export const currencyMax = western(SCALE_WORDS.length - 1)
65
+
56
66
  // ============================================================================
57
67
  // Precomputed Lookup Table
58
68
  // ============================================================================
59
69
 
60
- function buildSegment (n) {
70
+ /**
71
+ * @param {number} n The three-digit segment value (0-999) to convert.
72
+ * @returns {string} The segment in Amharic words.
73
+ */
74
+ function buildSegment(n) {
61
75
  if (n === 0) return ''
62
76
 
63
77
  const ones = n % 10
@@ -73,7 +87,8 @@ function buildSegment (n) {
73
87
 
74
88
  if (tensDigit === 1) {
75
89
  parts.push(TEENS[ones])
76
- } else {
90
+ }
91
+ else {
77
92
  if (tensDigit > 1) {
78
93
  parts.push(TENS[tensDigit])
79
94
  }
@@ -89,7 +104,11 @@ function buildSegment (n) {
89
104
  // Conversion Functions
90
105
  // ============================================================================
91
106
 
92
- function integerToWords (n) {
107
+ /**
108
+ * @param {bigint} n The non-negative integer to convert.
109
+ * @returns {string} The integer in Amharic words.
110
+ */
111
+ function integerToWords(n) {
93
112
  if (n === 0n) return ZERO
94
113
 
95
114
  if (n < 1000n) {
@@ -99,7 +118,11 @@ function integerToWords (n) {
99
118
  return buildLargeNumberWords(n)
100
119
  }
101
120
 
102
- function buildLargeNumberWords (n) {
121
+ /**
122
+ * @param {bigint} n The integer (>= 1000) to convert using scale words.
123
+ * @returns {string} The integer in Amharic words.
124
+ */
125
+ function buildLargeNumberWords(n) {
103
126
  const numStr = n.toString()
104
127
  const len = numStr.length
105
128
 
@@ -128,7 +151,8 @@ function buildLargeNumberWords (n) {
128
151
 
129
152
  if (scaleIndex === 0) {
130
153
  parts.push(buildSegment(segment))
131
- } else {
154
+ }
155
+ else {
132
156
  parts.push(buildSegment(segment) + ' ' + scaleWord)
133
157
  }
134
158
  }
@@ -139,7 +163,11 @@ function buildLargeNumberWords (n) {
139
163
  return parts.join(' ')
140
164
  }
141
165
 
142
- function decimalPartToWords (decimalPart) {
166
+ /**
167
+ * @param {string} decimalPart The digit string after the decimal point.
168
+ * @returns {string} The decimal digits read individually in Amharic words.
169
+ */
170
+ function decimalPartToWords(decimalPart) {
143
171
  // Per-digit decimal reading
144
172
  const digits = []
145
173
  for (const char of decimalPart) {
@@ -151,12 +179,12 @@ function decimalPartToWords (decimalPart) {
151
179
 
152
180
  /**
153
181
  * Converts a numeric value to Amharic words.
154
- *
155
182
  * @param {number | string | bigint} value - The numeric value to convert
156
183
  * @returns {string} The number in Amharic words
157
184
  */
158
- function toCardinal (value) {
185
+ function toCardinal(value) {
159
186
  const { isNegative, integerPart, decimalPart } = parseCardinalValue(value)
187
+ checkMax(integerPart, cardinalMax)
160
188
 
161
189
  let result = ''
162
190
 
@@ -182,11 +210,10 @@ function toCardinal (value) {
182
210
  *
183
211
  * In Amharic, ordinals are formed by adding -ኛ suffix to the cardinal.
184
212
  * Special case: 1 = አንደኛ (not አንድኛ)
185
- *
186
213
  * @param {bigint} n - Positive integer to convert
187
214
  * @returns {string} Amharic ordinal words
188
215
  */
189
- function integerToOrdinal (n) {
216
+ function integerToOrdinal(n) {
190
217
  // Special case: 1 → አንደኛ
191
218
  if (n === 1n) {
192
219
  return FIRST
@@ -202,20 +229,19 @@ function integerToOrdinal (n) {
202
229
  *
203
230
  * Amharic ordinals: add -ኛ suffix to cardinal.
204
231
  * Special case: 1 → አንደኛ
205
- *
206
232
  * @param {number | string | bigint} value - The numeric value to convert (positive integer)
207
233
  * @returns {string} The number as ordinal words
208
234
  * @throws {TypeError} If value is not a valid numeric type
209
235
  * @throws {RangeError} If value is negative, zero, or has a decimal part
210
- *
211
236
  * @example
212
237
  * toOrdinal(1) // 'አንደኛ'
213
238
  * toOrdinal(2) // 'ሁለትኛ'
214
239
  * toOrdinal(10) // 'አስርኛ'
215
240
  * toOrdinal(100) // 'አንድ መቶኛ'
216
241
  */
217
- function toOrdinal (value) {
242
+ function toOrdinal(value) {
218
243
  const integerPart = parseOrdinalValue(value)
244
+ checkMax(integerPart, ordinalMax)
219
245
  return integerToOrdinal(integerPart)
220
246
  }
221
247
 
@@ -225,20 +251,19 @@ function toOrdinal (value) {
225
251
 
226
252
  /**
227
253
  * Converts a numeric value to Amharic currency words (Ethiopian Birr).
228
- *
229
254
  * @param {number | string | bigint} value - The currency amount to convert
230
255
  * @returns {string} The amount in Amharic currency words
231
256
  * @throws {TypeError} If value is not a valid numeric type
232
257
  * @throws {Error} If value is not a valid number format
233
- *
234
258
  * @example
235
259
  * toCurrency(42.50) // 'አርባ ሁለት ብር ሃምሳ ሳንቲም'
236
260
  * toCurrency(1) // 'አንድ ብር'
237
261
  * toCurrency(0.99) // 'ዘጠና ዘጠኝ ሳንቲም'
238
262
  * toCurrency(0.01) // 'አንድ ሳንቲም'
239
263
  */
240
- function toCurrency (value) {
264
+ function toCurrency(value) {
241
265
  const { isNegative, dollars: birr, cents: santim } = parseCurrencyValue(value)
266
+ checkMax(birr, currencyMax)
242
267
 
243
268
  // Build result
244
269
  let result = ''
@@ -1,18 +1,18 @@
1
+ export const cardinalMax: bigint;
2
+ export const ordinalMax: bigint;
3
+ export const currencyMax: bigint;
1
4
  /**
2
5
  * Converts a numeric value to Amharic (Latin script) words.
3
- *
4
6
  * @param {number | string | bigint} value - The numeric value to convert
5
7
  * @returns {string} The number in Amharic Latin words
6
8
  */
7
9
  export function toCardinal(value: number | string | bigint): string;
8
10
  /**
9
11
  * Converts a numeric value to Amharic (Latin script) ordinal words.
10
- *
11
12
  * @param {number | string | bigint} value - The numeric value to convert (positive integer)
12
13
  * @returns {string} The number as ordinal words
13
14
  * @throws {TypeError} If value is not a valid numeric type
14
15
  * @throws {RangeError} If value is negative, zero, or has a decimal part
15
- *
16
16
  * @example
17
17
  * toOrdinal(1) // 'andenya'
18
18
  * toOrdinal(2) // 'huletnya'
@@ -21,12 +21,10 @@ export function toCardinal(value: number | string | bigint): string;
21
21
  export function toOrdinal(value: number | string | bigint): string;
22
22
  /**
23
23
  * Converts a numeric value to Amharic (Latin script) currency words (Ethiopian Birr).
24
- *
25
24
  * @param {number | string | bigint} value - The currency amount to convert
26
25
  * @returns {string} The amount in Amharic (Latin) currency words
27
26
  * @throws {TypeError} If value is not a valid numeric type
28
27
  * @throws {Error} If value is not a valid number format
29
- *
30
28
  * @example
31
29
  * toCurrency(42.50) // 'arba hulet birr hamsa santim'
32
30
  * toCurrency(1) // 'and birr'
package/src/am-Latn-ET.js CHANGED
@@ -14,6 +14,8 @@
14
14
  import { parseCardinalValue } from './utils/parse-cardinal.js'
15
15
  import { parseCurrencyValue } from './utils/parse-currency.js'
16
16
  import { parseOrdinalValue } from './utils/parse-ordinal.js'
17
+ import { checkMax } from './utils/check-max.js'
18
+ import { western } from './utils/scale.js'
17
19
 
18
20
  // ============================================================================
19
21
  // Vocabulary
@@ -53,11 +55,24 @@ const SANTIM = 'santim'
53
55
  // Short scale
54
56
  const SCALE_WORDS = ['', THOUSAND, 'miliyon', 'billiyon']
55
57
 
58
+ // Supported magnitude ceiling (checked at the public entry points). SCALE_WORDS
59
+ // reaches index SCALE_WORDS.length-1 (billiyon, 10^9), so values must stay below
60
+ // 10^(SCALE_WORDS.length * 3) = 10^12. Ordinal and currency build on the
61
+ // cardinal, so they share it. Decimals are read digit-by-digit (no ceiling).
62
+ export const cardinalMax = western(SCALE_WORDS.length - 1)
63
+ export const ordinalMax = western(SCALE_WORDS.length - 1)
64
+ export const currencyMax = western(SCALE_WORDS.length - 1)
65
+
56
66
  // ============================================================================
57
67
  // Precomputed Lookup Table
58
68
  // ============================================================================
59
69
 
60
- function buildSegment (n) {
70
+ /**
71
+ * Builds the words for a 3-digit segment (0-999).
72
+ * @param {number} n - Segment value (0-999)
73
+ * @returns {string} The segment in Amharic (Latin) words
74
+ */
75
+ function buildSegment(n) {
61
76
  if (n === 0) return ''
62
77
 
63
78
  const ones = n % 10
@@ -73,7 +88,8 @@ function buildSegment (n) {
73
88
 
74
89
  if (tensDigit === 1) {
75
90
  parts.push(TEENS[ones])
76
- } else {
91
+ }
92
+ else {
77
93
  if (tensDigit > 1) {
78
94
  parts.push(TENS[tensDigit])
79
95
  }
@@ -89,7 +105,12 @@ function buildSegment (n) {
89
105
  // Conversion Functions
90
106
  // ============================================================================
91
107
 
92
- function integerToWords (n) {
108
+ /**
109
+ * Converts a non-negative integer to Amharic (Latin script) words.
110
+ * @param {bigint} n - Non-negative integer to convert
111
+ * @returns {string} The integer in Amharic (Latin) words
112
+ */
113
+ function integerToWords(n) {
93
114
  if (n === 0n) return ZERO
94
115
 
95
116
  if (n < 1000n) {
@@ -99,7 +120,12 @@ function integerToWords (n) {
99
120
  return buildLargeNumberWords(n)
100
121
  }
101
122
 
102
- function buildLargeNumberWords (n) {
123
+ /**
124
+ * Builds the words for a number of 1000 or greater using short-scale grouping.
125
+ * @param {bigint} n - Integer of 1000 or greater
126
+ * @returns {string} The number in Amharic (Latin) words
127
+ */
128
+ function buildLargeNumberWords(n) {
103
129
  const numStr = n.toString()
104
130
  const len = numStr.length
105
131
 
@@ -128,7 +154,8 @@ function buildLargeNumberWords (n) {
128
154
 
129
155
  if (scaleIndex === 0) {
130
156
  parts.push(buildSegment(segment))
131
- } else {
157
+ }
158
+ else {
132
159
  parts.push(buildSegment(segment) + ' ' + scaleWord)
133
160
  }
134
161
  }
@@ -139,7 +166,12 @@ function buildLargeNumberWords (n) {
139
166
  return parts.join(' ')
140
167
  }
141
168
 
142
- function decimalPartToWords (decimalPart) {
169
+ /**
170
+ * Reads the decimal part digit by digit.
171
+ * @param {string} decimalPart - The fractional digits as a string
172
+ * @returns {string} The decimal digits in Amharic (Latin) words
173
+ */
174
+ function decimalPartToWords(decimalPart) {
143
175
  // Per-digit decimal reading
144
176
  const digits = []
145
177
  for (const char of decimalPart) {
@@ -151,12 +183,12 @@ function decimalPartToWords (decimalPart) {
151
183
 
152
184
  /**
153
185
  * Converts a numeric value to Amharic (Latin script) words.
154
- *
155
186
  * @param {number | string | bigint} value - The numeric value to convert
156
187
  * @returns {string} The number in Amharic Latin words
157
188
  */
158
- function toCardinal (value) {
189
+ function toCardinal(value) {
159
190
  const { isNegative, integerPart, decimalPart } = parseCardinalValue(value)
191
+ checkMax(integerPart, cardinalMax)
160
192
 
161
193
  let result = ''
162
194
 
@@ -182,11 +214,10 @@ function toCardinal (value) {
182
214
  *
183
215
  * In Amharic, ordinals are formed by adding -nya suffix to the cardinal.
184
216
  * Special case: 1 = andenya
185
- *
186
217
  * @param {bigint} n - Positive integer to convert
187
218
  * @returns {string} Amharic (Latin) ordinal words
188
219
  */
189
- function integerToOrdinal (n) {
220
+ function integerToOrdinal(n) {
190
221
  // Special case: 1 → andenya
191
222
  if (n === 1n) {
192
223
  return FIRST
@@ -199,19 +230,18 @@ function integerToOrdinal (n) {
199
230
 
200
231
  /**
201
232
  * Converts a numeric value to Amharic (Latin script) ordinal words.
202
- *
203
233
  * @param {number | string | bigint} value - The numeric value to convert (positive integer)
204
234
  * @returns {string} The number as ordinal words
205
235
  * @throws {TypeError} If value is not a valid numeric type
206
236
  * @throws {RangeError} If value is negative, zero, or has a decimal part
207
- *
208
237
  * @example
209
238
  * toOrdinal(1) // 'andenya'
210
239
  * toOrdinal(2) // 'huletnya'
211
240
  * toOrdinal(10) // 'asirnya'
212
241
  */
213
- function toOrdinal (value) {
242
+ function toOrdinal(value) {
214
243
  const integerPart = parseOrdinalValue(value)
244
+ checkMax(integerPart, ordinalMax)
215
245
  return integerToOrdinal(integerPart)
216
246
  }
217
247
 
@@ -221,19 +251,18 @@ function toOrdinal (value) {
221
251
 
222
252
  /**
223
253
  * Converts a numeric value to Amharic (Latin script) currency words (Ethiopian Birr).
224
- *
225
254
  * @param {number | string | bigint} value - The currency amount to convert
226
255
  * @returns {string} The amount in Amharic (Latin) currency words
227
256
  * @throws {TypeError} If value is not a valid numeric type
228
257
  * @throws {Error} If value is not a valid number format
229
- *
230
258
  * @example
231
259
  * toCurrency(42.50) // 'arba hulet birr hamsa santim'
232
260
  * toCurrency(1) // 'and birr'
233
261
  * toCurrency(0.01) // 'and santim'
234
262
  */
235
- function toCurrency (value) {
263
+ function toCurrency(value) {
236
264
  const { isNegative, dollars: birr, cents: santim } = parseCurrencyValue(value)
265
+ checkMax(birr, currencyMax)
237
266
 
238
267
  // Build result
239
268
  let result = ''
package/src/ar-SA.d.ts CHANGED
@@ -1,46 +1,72 @@
1
+ export const cardinalMax: bigint;
2
+ export const ordinalMax: bigint;
3
+ export const currencyMax: bigint;
4
+ /**
5
+ * @typedef {object} CardinalOptions
6
+ * @property {('masculine'|'feminine')} [gender] - Grammatical gender
7
+ * @property {string} [negativeWord] - Custom word for negative numbers
8
+ */
9
+ /** @type {Required<CardinalOptions>} */
10
+ export const cardinalDefaults: Required<CardinalOptions>;
11
+ /** @type {{ gender: ReadonlyArray<Required<CardinalOptions>['gender']> }} */
12
+ export const cardinalValues: {
13
+ gender: ReadonlyArray<Required<CardinalOptions>["gender"]>;
14
+ };
15
+ /**
16
+ * @typedef {object} OrdinalOptions
17
+ * @property {('masculine'|'feminine')} [gender] - Grammatical gender
18
+ */
19
+ /** @type {Required<OrdinalOptions>} */
20
+ export const ordinalDefaults: Required<OrdinalOptions>;
21
+ /** @type {{ gender: ReadonlyArray<Required<OrdinalOptions>['gender']> }} */
22
+ export const ordinalValues: {
23
+ gender: ReadonlyArray<Required<OrdinalOptions>["gender"]>;
24
+ };
25
+ export type CardinalOptions = {
26
+ /**
27
+ * - Grammatical gender
28
+ */
29
+ gender?: "feminine" | "masculine" | undefined;
30
+ /**
31
+ * - Custom word for negative numbers
32
+ */
33
+ negativeWord?: string | undefined;
34
+ };
35
+ export type OrdinalOptions = {
36
+ /**
37
+ * - Grammatical gender
38
+ */
39
+ gender?: "feminine" | "masculine" | undefined;
40
+ };
1
41
  /**
2
42
  * Converts a numeric value to Arabic words.
3
- *
4
43
  * @param {number | string | bigint} value - The numeric value to convert
5
- * @param {Object} [options] - Optional configuration
6
- * @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
7
- * @param {string} [options.negativeWord] - Custom word for negative numbers
44
+ * @param {CardinalOptions} [options] - Optional configuration
8
45
  * @returns {string} The number in Arabic words
9
- *
10
46
  * @example
11
47
  * toCardinal(1) // 'واحد'
12
48
  * toCardinal(1, {gender: 'feminine'}) // 'واحدة'
13
49
  */
14
- export function toCardinal(value: number | string | bigint, options?: {
15
- gender?: "masculine" | "feminine" | undefined;
16
- negativeWord?: string | undefined;
17
- }): string;
50
+ export function toCardinal(value: number | string | bigint, options?: CardinalOptions): string;
18
51
  /**
19
52
  * Converts a numeric value to Arabic ordinal words.
20
- *
21
53
  * @param {number | string | bigint} value - The numeric value to convert (positive integer)
22
- * @param {Object} [options] - Optional configuration
23
- * @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
54
+ * @param {OrdinalOptions} [options] - Optional configuration
24
55
  * @returns {string} The number as ordinal words
25
56
  * @throws {TypeError} If value is not a valid numeric type
26
57
  * @throws {RangeError} If value is negative, zero, or has a decimal part
27
- *
28
58
  * @example
29
59
  * toOrdinal(1) // 'الأول'
30
60
  * toOrdinal(1, {gender: 'feminine'}) // 'الأولى'
31
61
  * toOrdinal(3) // 'الثالث'
32
62
  */
33
- export function toOrdinal(value: number | string | bigint, options?: {
34
- gender?: "masculine" | "feminine" | undefined;
35
- }): string;
63
+ export function toOrdinal(value: number | string | bigint, options?: OrdinalOptions): string;
36
64
  /**
37
65
  * Converts a numeric value to Arabic currency words (Saudi Riyal).
38
- *
39
66
  * @param {number | string | bigint} value - The currency amount to convert
40
67
  * @returns {string} The amount in Arabic currency words
41
68
  * @throws {TypeError} If value is not a valid numeric type
42
69
  * @throws {Error} If value is not a valid number format
43
- *
44
70
  * @example
45
71
  * toCurrency(42.50) // 'اثنان وأربعون ريالاً وخمسون هللة'
46
72
  * toCurrency(1) // 'ريال واحد'