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
@@ -1,50 +1,75 @@
1
+ export const cardinalMax: bigint;
2
+ export const ordinalMax: bigint;
3
+ export const currencyMax: bigint;
4
+ /**
5
+ * @typedef {object} CardinalOptions
6
+ * @property {boolean} [formal] - Use formal/financial numerals
7
+ */
8
+ /** @type {Required<CardinalOptions>} */
9
+ export const cardinalDefaults: Required<CardinalOptions>;
10
+ /**
11
+ * @typedef {object} OrdinalOptions
12
+ * @property {boolean} [formal] - Use formal/financial numerals
13
+ */
14
+ /** @type {Required<OrdinalOptions>} */
15
+ export const ordinalDefaults: Required<OrdinalOptions>;
16
+ /**
17
+ * @typedef {object} CurrencyOptions
18
+ * @property {boolean} [formal] - Use formal/financial numerals
19
+ */
20
+ /** @type {Required<CurrencyOptions>} */
21
+ export const currencyDefaults: Required<CurrencyOptions>;
22
+ export type CardinalOptions = {
23
+ /**
24
+ * - Use formal/financial numerals
25
+ */
26
+ formal?: boolean | undefined;
27
+ };
28
+ export type OrdinalOptions = {
29
+ /**
30
+ * - Use formal/financial numerals
31
+ */
32
+ formal?: boolean | undefined;
33
+ };
34
+ export type CurrencyOptions = {
35
+ /**
36
+ * - Use formal/financial numerals
37
+ */
38
+ formal?: boolean | undefined;
39
+ };
1
40
  /**
2
41
  * Converts a numeric value to Traditional Chinese words.
3
- *
4
42
  * @param {number | string | bigint} value - The numeric value to convert
5
- * @param {Object} [options] - Optional configuration
6
- * @param {boolean} [options.formal=true] - Use formal/financial numerals
43
+ * @param {CardinalOptions} [options] - Optional configuration
7
44
  * @returns {string} The number in Traditional Chinese words
8
45
  */
9
- export function toCardinal(value: number | string | bigint, options?: {
10
- formal?: boolean | undefined;
11
- }): string;
46
+ export function toCardinal(value: number | string | bigint, options?: CardinalOptions): string;
12
47
  /**
13
48
  * Converts a numeric value to Traditional Chinese ordinal words.
14
- *
15
49
  * @param {number | string | bigint} value - The numeric value to convert (positive integer)
16
- * @param {Object} [options] - Optional configuration
17
- * @param {boolean} [options.formal=true] - Use formal/financial numerals
50
+ * @param {OrdinalOptions} [options] - Optional configuration
18
51
  * @returns {string} The number as ordinal words
19
52
  * @throws {TypeError} If value is not a valid numeric type
20
53
  * @throws {RangeError} If value is negative, zero, or has a decimal part
21
- *
22
54
  * @example
23
55
  * toOrdinal(1) // '第壹'
24
56
  * toOrdinal(2) // '第貳'
25
57
  * toOrdinal(1, { formal: false }) // '第一'
26
58
  */
27
- export function toOrdinal(value: number | string | bigint, options?: {
28
- formal?: boolean | undefined;
29
- }): string;
59
+ export function toOrdinal(value: number | string | bigint, options?: OrdinalOptions): string;
30
60
  /**
31
61
  * Converts a numeric value to Traditional Chinese currency words (New Taiwan Dollar).
32
62
  *
33
63
  * Uses 圓 (yuan), 角 (jiao, 1/10), 分 (fen, 1/100).
34
64
  * Formal writing adds 整 (zheng) for whole amounts.
35
- *
36
65
  * @param {number | string | bigint} value - The currency amount to convert
37
- * @param {Object} [options] - Optional configuration
38
- * @param {boolean} [options.formal=true] - Use formal/financial numerals
66
+ * @param {CurrencyOptions} [options] - Optional configuration
39
67
  * @returns {string} The amount in Traditional Chinese currency words
40
68
  * @throws {TypeError} If value is not a valid numeric type
41
69
  * @throws {Error} If value is not a valid number format
42
- *
43
70
  * @example
44
71
  * toCurrency(42) // '肆拾貳圓整'
45
72
  * toCurrency(1.50) // '壹圓伍角整'
46
73
  * toCurrency(42, { formal: false }) // '四十二元整'
47
74
  */
48
- export function toCurrency(value: number | string | bigint, options?: {
49
- formal?: boolean | undefined;
50
- }): string;
75
+ export function toCurrency(value: number | string | bigint, options?: CurrencyOptions): string;
package/src/zh-Hant-TW.js CHANGED
@@ -17,7 +17,9 @@
17
17
  import { parseCardinalValue } from './utils/parse-cardinal.js'
18
18
  import { parseCurrencyValue } from './utils/parse-currency.js'
19
19
  import { parseOrdinalValue } from './utils/parse-ordinal.js'
20
- import { validateOptions } from './utils/validate-options.js'
20
+ import { checkMax } from './utils/check-max.js'
21
+ import { bounded } from './utils/scale.js'
22
+ import { resolveOptions } from './utils/resolve-options.js'
21
23
 
22
24
  // ============================================================================
23
25
  // Vocabulary
@@ -39,6 +41,15 @@ const THOUSAND_FORMAL = '仟'
39
41
  const WAN_WORD = '萬' // 10,000
40
42
  const YI_WORD = '億' // 100,000,000
41
43
 
44
+ // Supported magnitude ceiling (checked at the public entry points). Numbers
45
+ // >= 億 (10^8) split into n / 10^8, which is then spelled by convertBelowYi —
46
+ // itself only valid below 億. So the ceiling is 億² = 10^16. Ordinal (第 +
47
+ // cardinal) and currency build on the cardinal, so they share it. Decimals are
48
+ // spelled digit-by-digit, so they have no ceiling.
49
+ export const cardinalMax = bounded(16)
50
+ export const ordinalMax = bounded(16)
51
+ export const currencyMax = bounded(16)
52
+
42
53
  const ZERO = '零'
43
54
  const NEGATIVE = '負'
44
55
  const DECIMAL_SEP = '點'
@@ -66,7 +77,13 @@ const YUAN_COMMON = '元'
66
77
  // Conversion Functions
67
78
  // ============================================================================
68
79
 
69
- function integerToWords (n, formal = true) {
80
+ /**
81
+ * Converts a non-negative integer to Traditional Chinese words.
82
+ * @param {bigint} n - The integer value to convert
83
+ * @param {boolean} [formal] - Use formal/financial numerals
84
+ * @returns {string} The integer in Traditional Chinese words
85
+ */
86
+ function integerToWords(n, formal = true) {
70
87
  if (n === 0n) return ZERO
71
88
 
72
89
  const ones = formal ? ONES_FORMAL : ONES_COMMON
@@ -75,7 +92,11 @@ function integerToWords (n, formal = true) {
75
92
  const thousand = formal ? THOUSAND_FORMAL : THOUSAND_COMMON
76
93
 
77
94
  // Convert number below 萬 (10,000)
78
- function convertBelowWan (value) {
95
+ /**
96
+ * @param {bigint} value The number below 10,000 to convert
97
+ * @returns {string} The number in Traditional Chinese words
98
+ */
99
+ function convertBelowWan(value) {
79
100
  if (value === 0n) return ''
80
101
 
81
102
  const parts = []
@@ -95,11 +116,11 @@ function integerToWords (n, formal = true) {
95
116
  if (hundredsVal > 0n) {
96
117
  if (needsZero) {
97
118
  parts.push(ZERO)
98
- needsZero = false
99
119
  }
100
120
  parts.push(ones[Number(hundredsVal)] + hundred)
101
121
  needsZero = hundredsRemainder > 0n && hundredsRemainder < 10n
102
- } else if (thousandsVal > 0n && hundredsRemainder > 0n) {
122
+ }
123
+ else if (thousandsVal > 0n && hundredsRemainder > 0n) {
103
124
  needsZero = true
104
125
  }
105
126
 
@@ -112,7 +133,8 @@ function integerToWords (n, formal = true) {
112
133
  needsZero = false
113
134
  }
114
135
  parts.push(ones[Number(tensVal)] + ten)
115
- } else if ((hundredsVal > 0n || thousandsVal > 0n) && onesVal > 0n) {
136
+ }
137
+ else if ((hundredsVal > 0n || thousandsVal > 0n) && onesVal > 0n) {
116
138
  needsZero = true
117
139
  }
118
140
 
@@ -128,7 +150,11 @@ function integerToWords (n, formal = true) {
128
150
  }
129
151
 
130
152
  // Convert number below 億 (100 million)
131
- function convertBelowYi (value) {
153
+ /**
154
+ * @param {bigint} value The number below 100,000,000 to convert
155
+ * @returns {string} The number in Traditional Chinese words
156
+ */
157
+ function convertBelowYi(value) {
132
158
  if (value === 0n) return ''
133
159
 
134
160
  const parts = []
@@ -148,7 +174,8 @@ function integerToWords (n, formal = true) {
148
174
  }
149
175
  parts.push(convertBelowWan(wanRemainder))
150
176
  }
151
- } else {
177
+ }
178
+ else {
152
179
  parts.push(convertBelowWan(value))
153
180
  }
154
181
 
@@ -172,14 +199,21 @@ function integerToWords (n, formal = true) {
172
199
  }
173
200
  parts.push(convertBelowYi(yiRemainder))
174
201
  }
175
- } else {
202
+ }
203
+ else {
176
204
  parts.push(convertBelowYi(n))
177
205
  }
178
206
 
179
207
  return parts.join('')
180
208
  }
181
209
 
182
- function decimalDigitsToWords (decimalString, formal = true) {
210
+ /**
211
+ * Converts each digit of a decimal string to Traditional Chinese words.
212
+ * @param {string} decimalString - The decimal digits to convert
213
+ * @param {boolean} [formal] - Use formal/financial numerals
214
+ * @returns {string[]} The decimal digits as Traditional Chinese words
215
+ */
216
+ function decimalDigitsToWords(decimalString, formal = true) {
183
217
  const ones = formal ? ONES_FORMAL : ONES_COMMON
184
218
  const words = []
185
219
  for (const char of decimalString) {
@@ -188,20 +222,26 @@ function decimalDigitsToWords (decimalString, formal = true) {
188
222
  return words
189
223
  }
190
224
 
225
+ /**
226
+ * @typedef {object} CardinalOptions
227
+ * @property {boolean} [formal] - Use formal/financial numerals
228
+ */
229
+
230
+ /** @type {Required<CardinalOptions>} */
231
+ export const cardinalDefaults = { formal: true }
232
+
191
233
  /**
192
234
  * Converts a numeric value to Traditional Chinese words.
193
- *
194
235
  * @param {number | string | bigint} value - The numeric value to convert
195
- * @param {Object} [options] - Optional configuration
196
- * @param {boolean} [options.formal=true] - Use formal/financial numerals
236
+ * @param {CardinalOptions} [options] - Optional configuration
197
237
  * @returns {string} The number in Traditional Chinese words
198
238
  */
199
- function toCardinal (value, options) {
200
- options = validateOptions(options)
239
+ function toCardinal(value, options) {
201
240
  const { isNegative, integerPart, decimalPart } = parseCardinalValue(value)
241
+ checkMax(integerPart, cardinalMax)
202
242
 
203
243
  // Apply option defaults
204
- const { formal = true } = options
244
+ const { formal } = resolveOptions(options, cardinalDefaults)
205
245
 
206
246
  let result = ''
207
247
 
@@ -226,34 +266,38 @@ function toCardinal (value, options) {
226
266
  * Converts a non-negative integer to Traditional Chinese ordinal words.
227
267
  *
228
268
  * Traditional Chinese ordinals use "第" prefix + cardinal number.
229
- *
230
269
  * @param {bigint} n - Positive integer to convert
231
270
  * @param {boolean} formal - Use formal/financial numerals
232
271
  * @returns {string} Traditional Chinese ordinal words
233
272
  */
234
- function integerToOrdinal (n, formal = true) {
273
+ function integerToOrdinal(n, formal = true) {
235
274
  return ORDINAL_PREFIX + integerToWords(n, formal)
236
275
  }
237
276
 
277
+ /**
278
+ * @typedef {object} OrdinalOptions
279
+ * @property {boolean} [formal] - Use formal/financial numerals
280
+ */
281
+
282
+ /** @type {Required<OrdinalOptions>} */
283
+ export const ordinalDefaults = { formal: true }
284
+
238
285
  /**
239
286
  * Converts a numeric value to Traditional Chinese ordinal words.
240
- *
241
287
  * @param {number | string | bigint} value - The numeric value to convert (positive integer)
242
- * @param {Object} [options] - Optional configuration
243
- * @param {boolean} [options.formal=true] - Use formal/financial numerals
288
+ * @param {OrdinalOptions} [options] - Optional configuration
244
289
  * @returns {string} The number as ordinal words
245
290
  * @throws {TypeError} If value is not a valid numeric type
246
291
  * @throws {RangeError} If value is negative, zero, or has a decimal part
247
- *
248
292
  * @example
249
293
  * toOrdinal(1) // '第壹'
250
294
  * toOrdinal(2) // '第貳'
251
295
  * toOrdinal(1, { formal: false }) // '第一'
252
296
  */
253
- function toOrdinal (value, options) {
254
- options = validateOptions(options)
297
+ function toOrdinal(value, options) {
255
298
  const integerPart = parseOrdinalValue(value)
256
- const { formal = true } = options
299
+ checkMax(integerPart, ordinalMax)
300
+ const { formal } = resolveOptions(options, ordinalDefaults)
257
301
  return integerToOrdinal(integerPart, formal)
258
302
  }
259
303
 
@@ -261,28 +305,33 @@ function toOrdinal (value, options) {
261
305
  // CURRENCY: toCurrency(value, options?)
262
306
  // ============================================================================
263
307
 
308
+ /**
309
+ * @typedef {object} CurrencyOptions
310
+ * @property {boolean} [formal] - Use formal/financial numerals
311
+ */
312
+
313
+ /** @type {Required<CurrencyOptions>} */
314
+ export const currencyDefaults = { formal: true }
315
+
264
316
  /**
265
317
  * Converts a numeric value to Traditional Chinese currency words (New Taiwan Dollar).
266
318
  *
267
319
  * Uses 圓 (yuan), 角 (jiao, 1/10), 分 (fen, 1/100).
268
320
  * Formal writing adds 整 (zheng) for whole amounts.
269
- *
270
321
  * @param {number | string | bigint} value - The currency amount to convert
271
- * @param {Object} [options] - Optional configuration
272
- * @param {boolean} [options.formal=true] - Use formal/financial numerals
322
+ * @param {CurrencyOptions} [options] - Optional configuration
273
323
  * @returns {string} The amount in Traditional Chinese currency words
274
324
  * @throws {TypeError} If value is not a valid numeric type
275
325
  * @throws {Error} If value is not a valid number format
276
- *
277
326
  * @example
278
327
  * toCurrency(42) // '肆拾貳圓整'
279
328
  * toCurrency(1.50) // '壹圓伍角整'
280
329
  * toCurrency(42, { formal: false }) // '四十二元整'
281
330
  */
282
- function toCurrency (value, options) {
283
- options = validateOptions(options)
331
+ function toCurrency(value, options) {
284
332
  const { isNegative, dollars: yuan, cents } = parseCurrencyValue(value)
285
- const { formal = true } = options
333
+ checkMax(yuan, currencyMax)
334
+ const { formal } = resolveOptions(options, currencyDefaults)
286
335
 
287
336
  const yuanWord = formal ? YUAN_FORMAL : YUAN_COMMON
288
337
 
@@ -315,10 +364,12 @@ function toCurrency (value, options) {
315
364
  result += ZERO
316
365
  }
317
366
  result += ones[Number(fen)] + FEN_FORMAL
318
- } else if (jiao > 0n) {
367
+ }
368
+ else if (jiao > 0n) {
319
369
  // Has jiao but no fen - add 整
320
370
  result += ZHENG_FORMAL
321
- } else {
371
+ }
372
+ else {
322
373
  // Whole yuan only - add 整
323
374
  result += ZHENG_FORMAL
324
375
  }
@@ -1,8 +0,0 @@
1
- /**
2
- * Validates and normalizes the options parameter.
3
- *
4
- * @param {*} options The options value to validate
5
- * @returns {Object} A valid options object (empty object if undefined)
6
- * @throws {TypeError} If options is not undefined or a plain object
7
- */
8
- export function validateOptions(options: any): Object;
@@ -1,16 +0,0 @@
1
- import { isPlainObject } from './is-plain-object.js'
2
-
3
- /**
4
- * Validates and normalizes the options parameter.
5
- *
6
- * @param {*} options The options value to validate
7
- * @returns {Object} A valid options object (empty object if undefined)
8
- * @throws {TypeError} If options is not undefined or a plain object
9
- */
10
- export function validateOptions (options) {
11
- if (options === undefined) return {}
12
- if (isPlainObject(options)) return options
13
- throw new TypeError(
14
- `Invalid options: expected plain object or undefined, got ${typeof options}`
15
- )
16
- }