@stll/stdnum 1.0.0 → 2.0.1

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 (705) hide show
  1. package/README.md +1 -4
  2. package/dist/_checksums/luhn.js.map +1 -1
  3. package/dist/_checksums/mod1110.js +1 -1
  4. package/dist/_checksums/mod1110.js.map +1 -1
  5. package/dist/_checksums/mod112.js.map +1 -1
  6. package/dist/_checksums/mod97.js.map +1 -1
  7. package/dist/_checksums/verhoeff.js.map +1 -1
  8. package/dist/_checksums/weighted-sum.js.map +1 -1
  9. package/dist/_util/arabic.js.map +1 -1
  10. package/dist/_util/clean.js.map +1 -1
  11. package/dist/_util/date.js.map +1 -1
  12. package/dist/_util/generate.js.map +1 -1
  13. package/dist/_util/result.js.map +1 -1
  14. package/dist/_util/strings.js.map +1 -1
  15. package/dist/ad/nrt.d.ts +16 -2
  16. package/dist/ad/nrt.js +1 -14
  17. package/dist/ad/nrt.js.map +1 -1
  18. package/dist/ae/eid.d.ts +2 -2
  19. package/dist/ae/eid.js +2 -12
  20. package/dist/ae/eid.js.map +1 -1
  21. package/dist/ai/tin.d.ts +20 -2
  22. package/dist/ai/tin.js +1 -18
  23. package/dist/ai/tin.js.map +1 -1
  24. package/dist/al/nipt.d.ts +13 -2
  25. package/dist/al/nipt.js +1 -11
  26. package/dist/al/nipt.js.map +1 -1
  27. package/dist/am/tin.d.ts +16 -2
  28. package/dist/am/tin.js +1 -14
  29. package/dist/am/tin.js.map +1 -1
  30. package/dist/ar/cbu.d.ts +2 -2
  31. package/dist/ar/cbu.js +1 -9
  32. package/dist/ar/cbu.js.map +1 -1
  33. package/dist/ar/cuit.d.ts +2 -2
  34. package/dist/ar/cuit.js +1 -17
  35. package/dist/ar/cuit.js.map +1 -1
  36. package/dist/ar/dni.d.ts +11 -2
  37. package/dist/ar/dni.js +1 -9
  38. package/dist/ar/dni.js.map +1 -1
  39. package/dist/at/businessid.d.ts +10 -2
  40. package/dist/at/businessid.js +1 -8
  41. package/dist/at/businessid.js.map +1 -1
  42. package/dist/at/tin.d.ts +2 -2
  43. package/dist/at/tin.js +1 -11
  44. package/dist/at/tin.js.map +1 -1
  45. package/dist/at/uid.d.ts +2 -2
  46. package/dist/at/uid.js +2 -10
  47. package/dist/at/uid.js.map +1 -1
  48. package/dist/at/vnr.d.ts +2 -2
  49. package/dist/at/vnr.js +4 -14
  50. package/dist/at/vnr.js.map +1 -1
  51. package/dist/au/abn.d.ts +2 -2
  52. package/dist/au/abn.js +1 -10
  53. package/dist/au/abn.js.map +1 -1
  54. package/dist/au/acn.d.ts +2 -2
  55. package/dist/au/acn.js +1 -10
  56. package/dist/au/acn.js.map +1 -1
  57. package/dist/au/tfn.d.ts +2 -2
  58. package/dist/au/tfn.js +1 -10
  59. package/dist/au/tfn.js.map +1 -1
  60. package/dist/az/voen.d.ts +2 -2
  61. package/dist/az/voen.js +1 -14
  62. package/dist/az/voen.js.map +1 -1
  63. package/dist/ba/jmbg.d.ts +2 -2
  64. package/dist/ba/jmbg.js +3 -11
  65. package/dist/ba/jmbg.js.map +1 -1
  66. package/dist/bd/nid.d.ts +23 -2
  67. package/dist/bd/nid.js +1 -21
  68. package/dist/bd/nid.js.map +1 -1
  69. package/dist/be/bis.d.ts +2 -2
  70. package/dist/be/bis.js +1 -11
  71. package/dist/be/bis.js.map +1 -1
  72. package/dist/be/nn.d.ts +2 -2
  73. package/dist/be/nn.js +1 -11
  74. package/dist/be/nn.js.map +1 -1
  75. package/dist/be/vat.d.ts +2 -2
  76. package/dist/be/vat.js +1 -9
  77. package/dist/be/vat.js.map +1 -1
  78. package/dist/bg/egn.d.ts +2 -2
  79. package/dist/bg/egn.js +3 -18
  80. package/dist/bg/egn.js.map +1 -1
  81. package/dist/bg/pnf.d.ts +2 -2
  82. package/dist/bg/pnf.js +1 -8
  83. package/dist/bg/pnf.js.map +1 -1
  84. package/dist/bg/vat.d.ts +2 -2
  85. package/dist/bg/vat.js +3 -9
  86. package/dist/bg/vat.js.map +1 -1
  87. package/dist/bh/cpr.d.ts +2 -2
  88. package/dist/bh/cpr.js +1 -17
  89. package/dist/bh/cpr.js.map +1 -1
  90. package/dist/bic.d.ts +13 -2
  91. package/dist/bic.js +1 -11
  92. package/dist/bic.js.map +1 -1
  93. package/dist/br/cnpj.d.ts +2 -2
  94. package/dist/br/cnpj.js +1 -20
  95. package/dist/br/cnpj.js.map +1 -1
  96. package/dist/br/cpf.d.ts +2 -2
  97. package/dist/br/cpf.js +1 -14
  98. package/dist/br/cpf.js.map +1 -1
  99. package/dist/by/unp.d.ts +2 -2
  100. package/dist/by/unp.js +3 -14
  101. package/dist/by/unp.js.map +1 -1
  102. package/dist/bz/tin.d.ts +2 -2
  103. package/dist/bz/tin.js +1 -26
  104. package/dist/bz/tin.js.map +1 -1
  105. package/dist/ca/bn.d.ts +2 -2
  106. package/dist/ca/bn.js +2 -10
  107. package/dist/ca/bn.js.map +1 -1
  108. package/dist/ca/sin.d.ts +2 -2
  109. package/dist/ca/sin.js +2 -10
  110. package/dist/ca/sin.js.map +1 -1
  111. package/dist/ch/ssn.d.ts +2 -2
  112. package/dist/ch/ssn.js +1 -9
  113. package/dist/ch/ssn.js.map +1 -1
  114. package/dist/ch/uid.d.ts +2 -2
  115. package/dist/ch/uid.js +1 -9
  116. package/dist/ch/uid.js.map +1 -1
  117. package/dist/ch/vat.d.ts +2 -2
  118. package/dist/ch/vat.js +1 -9
  119. package/dist/ch/vat.js.map +1 -1
  120. package/dist/cl/rut.d.ts +2 -2
  121. package/dist/cl/rut.js +1 -14
  122. package/dist/cl/rut.js.map +1 -1
  123. package/dist/cn/ric.d.ts +2 -2
  124. package/dist/cn/ric.js +3 -14
  125. package/dist/cn/ric.js.map +1 -1
  126. package/dist/cn/uscc.d.ts +2 -2
  127. package/dist/cn/uscc.js +1 -10
  128. package/dist/cn/uscc.js.map +1 -1
  129. package/dist/co/nit.d.ts +2 -2
  130. package/dist/co/nit.js +2 -12
  131. package/dist/co/nit.js.map +1 -1
  132. package/dist/cr/cpf.d.ts +18 -2
  133. package/dist/cr/cpf.js +1 -16
  134. package/dist/cr/cpf.js.map +1 -1
  135. package/dist/creditcard.d.ts +2 -2
  136. package/dist/creditcard.js +5 -14
  137. package/dist/creditcard.js.map +1 -1
  138. package/dist/cu/ni.d.ts +2 -2
  139. package/dist/cu/ni.js +2 -17
  140. package/dist/cu/ni.js.map +1 -1
  141. package/dist/cy/vat.d.ts +2 -2
  142. package/dist/cy/vat.js +1 -8
  143. package/dist/cy/vat.js.map +1 -1
  144. package/dist/cz/dic.d.ts +2 -2
  145. package/dist/cz/dic.js +7 -13
  146. package/dist/cz/dic.js.map +1 -1
  147. package/dist/cz/ico.d.ts +2 -2
  148. package/dist/cz/ico.js +2 -10
  149. package/dist/cz/ico.js.map +1 -1
  150. package/dist/cz/rc.d.ts +2 -2
  151. package/dist/cz/rc.js +2 -26
  152. package/dist/cz/rc.js.map +1 -1
  153. package/dist/de/handelsreg.d.ts +19 -2
  154. package/dist/de/handelsreg.js +1 -17
  155. package/dist/de/handelsreg.js.map +1 -1
  156. package/dist/de/idnr.d.ts +2 -2
  157. package/dist/de/idnr.js +2 -12
  158. package/dist/de/idnr.js.map +1 -1
  159. package/dist/de/stnr.d.ts +17 -2
  160. package/dist/de/stnr.js +1 -15
  161. package/dist/de/stnr.js.map +1 -1
  162. package/dist/de/svnr.d.ts +2 -2
  163. package/dist/de/svnr.js +2 -11
  164. package/dist/de/svnr.js.map +1 -1
  165. package/dist/de/vat.d.ts +2 -2
  166. package/dist/de/vat.js +2 -11
  167. package/dist/de/vat.js.map +1 -1
  168. package/dist/dk/cpr.d.ts +2 -2
  169. package/dist/dk/cpr.js +2 -10
  170. package/dist/dk/cpr.js.map +1 -1
  171. package/dist/dk/cvr.d.ts +2 -2
  172. package/dist/dk/cvr.js +2 -15
  173. package/dist/dk/cvr.js.map +1 -1
  174. package/dist/dk/vat.d.ts +2 -2
  175. package/dist/dk/vat.js +3 -13
  176. package/dist/dk/vat.js.map +1 -1
  177. package/dist/do/rnc.d.ts +2 -2
  178. package/dist/do/rnc.js +2 -16
  179. package/dist/do/rnc.js.map +1 -1
  180. package/dist/ec/ruc.d.ts +2 -2
  181. package/dist/ec/ruc.js +1 -18
  182. package/dist/ec/ruc.js.map +1 -1
  183. package/dist/ee/ik.d.ts +2 -2
  184. package/dist/ee/ik.js +3 -20
  185. package/dist/ee/ik.js.map +1 -1
  186. package/dist/ee/registrikood.d.ts +2 -2
  187. package/dist/ee/registrikood.js +1 -8
  188. package/dist/ee/registrikood.js.map +1 -1
  189. package/dist/ee/vat.d.ts +2 -2
  190. package/dist/ee/vat.js +2 -10
  191. package/dist/ee/vat.js.map +1 -1
  192. package/dist/eg/tn.d.ts +11 -2
  193. package/dist/eg/tn.js +1 -9
  194. package/dist/eg/tn.js.map +1 -1
  195. package/dist/es/cif.d.ts +2 -2
  196. package/dist/es/cif.js +1 -10
  197. package/dist/es/cif.js.map +1 -1
  198. package/dist/es/dni.d.ts +2 -2
  199. package/dist/es/dni.js +1 -9
  200. package/dist/es/dni.js.map +1 -1
  201. package/dist/es/nie.d.ts +2 -2
  202. package/dist/es/nie.js +1 -9
  203. package/dist/es/nie.js.map +1 -1
  204. package/dist/es/nss.d.ts +2 -2
  205. package/dist/es/nss.js +1 -16
  206. package/dist/es/nss.js.map +1 -1
  207. package/dist/es/vat.d.ts +2 -2
  208. package/dist/es/vat.js +5 -10
  209. package/dist/es/vat.js.map +1 -1
  210. package/dist/eu/vat.d.ts +2 -2
  211. package/dist/eu/vat.js +1 -0
  212. package/dist/eu/vat.js.map +1 -1
  213. package/dist/fi/hetu.d.ts +2 -2
  214. package/dist/fi/hetu.js +2 -10
  215. package/dist/fi/hetu.js.map +1 -1
  216. package/dist/fi/vat.d.ts +2 -2
  217. package/dist/fi/vat.js +3 -10
  218. package/dist/fi/vat.js.map +1 -1
  219. package/dist/fi/ytunnus.d.ts +2 -2
  220. package/dist/fi/ytunnus.js +2 -10
  221. package/dist/fi/ytunnus.js.map +1 -1
  222. package/dist/fr/nif.d.ts +2 -2
  223. package/dist/fr/nif.js +1 -9
  224. package/dist/fr/nif.js.map +1 -1
  225. package/dist/fr/nir.d.ts +2 -2
  226. package/dist/fr/nir.js +2 -14
  227. package/dist/fr/nir.js.map +1 -1
  228. package/dist/fr/siren.d.ts +2 -2
  229. package/dist/fr/siren.js +2 -10
  230. package/dist/fr/siren.js.map +1 -1
  231. package/dist/fr/siret.d.ts +2 -2
  232. package/dist/fr/siret.js +2 -11
  233. package/dist/fr/siret.js.map +1 -1
  234. package/dist/fr/tva.d.ts +2 -2
  235. package/dist/fr/tva.js +2 -12
  236. package/dist/fr/tva.js.map +1 -1
  237. package/dist/gb/nino.d.ts +12 -2
  238. package/dist/gb/nino.js +1 -10
  239. package/dist/gb/nino.js.map +1 -1
  240. package/dist/gb/sedol.d.ts +2 -2
  241. package/dist/gb/sedol.js +1 -11
  242. package/dist/gb/sedol.js.map +1 -1
  243. package/dist/gb/utr.d.ts +2 -2
  244. package/dist/gb/utr.js +2 -10
  245. package/dist/gb/utr.js.map +1 -1
  246. package/dist/gb/vat.d.ts +2 -2
  247. package/dist/gb/vat.js +2 -11
  248. package/dist/gb/vat.js.map +1 -1
  249. package/dist/ge/pin.d.ts +14 -2
  250. package/dist/ge/pin.js +1 -12
  251. package/dist/ge/pin.js.map +1 -1
  252. package/dist/gh/tin.d.ts +2 -2
  253. package/dist/gh/tin.js +1 -15
  254. package/dist/gh/tin.js.map +1 -1
  255. package/dist/gr/amka.d.ts +2 -2
  256. package/dist/gr/amka.js +3 -11
  257. package/dist/gr/amka.js.map +1 -1
  258. package/dist/gr/vat.d.ts +2 -2
  259. package/dist/gr/vat.js +1 -10
  260. package/dist/gr/vat.js.map +1 -1
  261. package/dist/gt/nit.d.ts +2 -2
  262. package/dist/gt/nit.js +1 -12
  263. package/dist/gt/nit.js.map +1 -1
  264. package/dist/hk/hkid.d.ts +2 -2
  265. package/dist/hk/hkid.js +1 -10
  266. package/dist/hk/hkid.js.map +1 -1
  267. package/dist/hr/vat.d.ts +2 -2
  268. package/dist/hr/vat.js +2 -9
  269. package/dist/hr/vat.js.map +1 -1
  270. package/dist/hu/vat.d.ts +2 -2
  271. package/dist/hu/vat.js +3 -10
  272. package/dist/hu/vat.js.map +1 -1
  273. package/dist/iban.d.ts +2 -2
  274. package/dist/iban.js +2 -8
  275. package/dist/iban.js.map +1 -1
  276. package/dist/id/npwp.d.ts +2 -2
  277. package/dist/id/npwp.js +3 -13
  278. package/dist/id/npwp.js.map +1 -1
  279. package/dist/ie/pps.d.ts +2 -2
  280. package/dist/ie/pps.js +1 -10
  281. package/dist/ie/pps.js.map +1 -1
  282. package/dist/ie/vat.d.ts +2 -2
  283. package/dist/ie/vat.js +1 -9
  284. package/dist/ie/vat.js.map +1 -1
  285. package/dist/il/idnr.d.ts +2 -2
  286. package/dist/il/idnr.js +2 -9
  287. package/dist/il/idnr.js.map +1 -1
  288. package/dist/in/aadhaar.d.ts +2 -2
  289. package/dist/in/aadhaar.js +2 -12
  290. package/dist/in/aadhaar.js.map +1 -1
  291. package/dist/in/gstin.d.ts +2 -2
  292. package/dist/in/gstin.js +1 -10
  293. package/dist/in/gstin.js.map +1 -1
  294. package/dist/in/pan.d.ts +15 -2
  295. package/dist/in/pan.js +1 -13
  296. package/dist/in/pan.js.map +1 -1
  297. package/dist/index.d.ts +2 -2
  298. package/dist/index.js +6 -6
  299. package/dist/iq/nid.d.ts +16 -2
  300. package/dist/iq/nid.js +2 -15
  301. package/dist/iq/nid.js.map +1 -1
  302. package/dist/ir/nid.d.ts +2 -2
  303. package/dist/ir/nid.js +2 -24
  304. package/dist/ir/nid.js.map +1 -1
  305. package/dist/is/kennitala.d.ts +2 -2
  306. package/dist/is/kennitala.js +2 -13
  307. package/dist/is/kennitala.js.map +1 -1
  308. package/dist/is/vsk.d.ts +9 -2
  309. package/dist/is/vsk.js +1 -7
  310. package/dist/is/vsk.js.map +1 -1
  311. package/dist/isin.d.ts +2 -2
  312. package/dist/isin.js +2 -12
  313. package/dist/isin.js.map +1 -1
  314. package/dist/it/codicefiscale.d.ts +2 -2
  315. package/dist/it/codicefiscale.js +1 -21
  316. package/dist/it/codicefiscale.js.map +1 -1
  317. package/dist/it/iva.d.ts +2 -2
  318. package/dist/it/iva.js +2 -9
  319. package/dist/it/iva.js.map +1 -1
  320. package/dist/jp/cn.d.ts +2 -2
  321. package/dist/jp/cn.js +1 -9
  322. package/dist/jp/cn.js.map +1 -1
  323. package/dist/jp/mynumber.d.ts +2 -2
  324. package/dist/jp/mynumber.js +1 -10
  325. package/dist/jp/mynumber.js.map +1 -1
  326. package/dist/kr/brn.d.ts +11 -2
  327. package/dist/kr/brn.js +1 -9
  328. package/dist/kr/brn.js.map +1 -1
  329. package/dist/kr/rrn.d.ts +2 -2
  330. package/dist/kr/rrn.js +2 -11
  331. package/dist/kr/rrn.js.map +1 -1
  332. package/dist/kw/civil.d.ts +2 -2
  333. package/dist/kw/civil.js +2 -14
  334. package/dist/kw/civil.js.map +1 -1
  335. package/dist/kz/iin.d.ts +2 -2
  336. package/dist/kz/iin.js +3 -18
  337. package/dist/kz/iin.js.map +1 -1
  338. package/dist/lei.d.ts +2 -2
  339. package/dist/lei.js +2 -11
  340. package/dist/lei.js.map +1 -1
  341. package/dist/li/peid.d.ts +11 -2
  342. package/dist/li/peid.js +1 -9
  343. package/dist/li/peid.js.map +1 -1
  344. package/dist/lk/nic.d.ts +2 -2
  345. package/dist/lk/nic.js +2 -14
  346. package/dist/lk/nic.js.map +1 -1
  347. package/dist/lt/asmens.d.ts +2 -2
  348. package/dist/lt/asmens.js +2 -1
  349. package/dist/lt/asmens.js.map +1 -1
  350. package/dist/lt/vat.d.ts +2 -2
  351. package/dist/lt/vat.js +2 -10
  352. package/dist/lt/vat.js.map +1 -1
  353. package/dist/lu/vat.d.ts +2 -2
  354. package/dist/lu/vat.js +2 -8
  355. package/dist/lu/vat.js.map +1 -1
  356. package/dist/luhn.d.ts +2 -2
  357. package/dist/luhn.js +2 -9
  358. package/dist/luhn.js.map +1 -1
  359. package/dist/lv/vat.d.ts +2 -2
  360. package/dist/lv/vat.js +2 -28
  361. package/dist/lv/vat.js.map +1 -1
  362. package/dist/ma/ice.d.ts +2 -2
  363. package/dist/ma/ice.js +2 -11
  364. package/dist/ma/ice.js.map +1 -1
  365. package/dist/mc/tva.d.ts +2 -2
  366. package/dist/mc/tva.js +1 -0
  367. package/dist/mc/tva.js.map +1 -1
  368. package/dist/md/idno.d.ts +2 -2
  369. package/dist/md/idno.js +1 -10
  370. package/dist/md/idno.js.map +1 -1
  371. package/dist/me/pib.d.ts +2 -2
  372. package/dist/me/pib.js +2 -10
  373. package/dist/me/pib.js.map +1 -1
  374. package/dist/mk/edb.d.ts +2 -2
  375. package/dist/mk/edb.js +2 -11
  376. package/dist/mk/edb.js.map +1 -1
  377. package/dist/mt/vat.d.ts +2 -2
  378. package/dist/mt/vat.js +3 -10
  379. package/dist/mt/vat.js.map +1 -1
  380. package/dist/mu/brn.d.ts +23 -2
  381. package/dist/mu/brn.js +1 -21
  382. package/dist/mu/brn.js.map +1 -1
  383. package/dist/mx/clabe.d.ts +2 -2
  384. package/dist/mx/clabe.js +1 -14
  385. package/dist/mx/clabe.js.map +1 -1
  386. package/dist/mx/curp.d.ts +2 -2
  387. package/dist/mx/curp.js +3 -17
  388. package/dist/mx/curp.js.map +1 -1
  389. package/dist/mx/rfc.d.ts +2 -2
  390. package/dist/mx/rfc.js +3 -19
  391. package/dist/mx/rfc.js.map +1 -1
  392. package/dist/my/nric.d.ts +2 -2
  393. package/dist/my/nric.js +2 -14
  394. package/dist/my/nric.js.map +1 -1
  395. package/dist/ng/nin.d.ts +13 -2
  396. package/dist/ng/nin.js +1 -11
  397. package/dist/ng/nin.js.map +1 -1
  398. package/dist/ni/ruc.d.ts +2 -2
  399. package/dist/ni/ruc.js +1 -23
  400. package/dist/ni/ruc.js.map +1 -1
  401. package/dist/nl/bsn.d.ts +2 -2
  402. package/dist/nl/bsn.js +2 -10
  403. package/dist/nl/bsn.js.map +1 -1
  404. package/dist/nl/kvk.d.ts +9 -2
  405. package/dist/nl/kvk.js +1 -7
  406. package/dist/nl/kvk.js.map +1 -1
  407. package/dist/nl/vat.d.ts +2 -2
  408. package/dist/nl/vat.js +1 -13
  409. package/dist/nl/vat.js.map +1 -1
  410. package/dist/no/fodselsnummer.d.ts +2 -2
  411. package/dist/no/fodselsnummer.js +2 -10
  412. package/dist/no/fodselsnummer.js.map +1 -1
  413. package/dist/no/mva.d.ts +2 -2
  414. package/dist/no/mva.js +1 -8
  415. package/dist/no/mva.js.map +1 -1
  416. package/dist/no/orgnr.d.ts +2 -2
  417. package/dist/no/orgnr.js +2 -8
  418. package/dist/no/orgnr.js.map +1 -1
  419. package/dist/nz/ird.d.ts +2 -2
  420. package/dist/nz/ird.js +2 -11
  421. package/dist/nz/ird.js.map +1 -1
  422. package/dist/pa/ruc.d.ts +2 -2
  423. package/dist/pa/ruc.js +1 -18
  424. package/dist/pa/ruc.js.map +1 -1
  425. package/dist/patterns.d.ts +8 -7
  426. package/dist/patterns.js +3 -5
  427. package/dist/patterns.js.map +1 -1
  428. package/dist/pe/ruc.d.ts +2 -2
  429. package/dist/pe/ruc.js +1 -15
  430. package/dist/pe/ruc.js.map +1 -1
  431. package/dist/ph/philid.d.ts +14 -2
  432. package/dist/ph/philid.js +1 -12
  433. package/dist/ph/philid.js.map +1 -1
  434. package/dist/pk/cnic.d.ts +14 -2
  435. package/dist/pk/cnic.js +1 -12
  436. package/dist/pk/cnic.js.map +1 -1
  437. package/dist/pl/nip.d.ts +2 -2
  438. package/dist/pl/nip.js +2 -10
  439. package/dist/pl/nip.js.map +1 -1
  440. package/dist/pl/pesel.d.ts +2 -2
  441. package/dist/pl/pesel.js +3 -13
  442. package/dist/pl/pesel.js.map +1 -1
  443. package/dist/pl/regon.d.ts +2 -2
  444. package/dist/pl/regon.js +2 -11
  445. package/dist/pl/regon.js.map +1 -1
  446. package/dist/pt/cc.d.ts +2 -2
  447. package/dist/pt/cc.js +1 -9
  448. package/dist/pt/cc.js.map +1 -1
  449. package/dist/pt/vat.d.ts +2 -2
  450. package/dist/pt/vat.js +3 -11
  451. package/dist/pt/vat.js.map +1 -1
  452. package/dist/ro/cnp.d.ts +2 -2
  453. package/dist/ro/cnp.js +4 -14
  454. package/dist/ro/cnp.js.map +1 -1
  455. package/dist/ro/vat.d.ts +2 -2
  456. package/dist/ro/vat.js +13 -11
  457. package/dist/ro/vat.js.map +1 -1
  458. package/dist/rs/pib.d.ts +2 -2
  459. package/dist/rs/pib.js +1 -9
  460. package/dist/rs/pib.js.map +1 -1
  461. package/dist/ru/inn.d.ts +2 -2
  462. package/dist/ru/inn.js +1 -11
  463. package/dist/ru/inn.js.map +1 -1
  464. package/dist/se/orgnr.d.ts +2 -2
  465. package/dist/se/orgnr.js +2 -9
  466. package/dist/se/orgnr.js.map +1 -1
  467. package/dist/se/personnummer.d.ts +2 -2
  468. package/dist/se/personnummer.js +7 -15
  469. package/dist/se/personnummer.js.map +1 -1
  470. package/dist/se/vat.d.ts +2 -2
  471. package/dist/se/vat.js +3 -10
  472. package/dist/se/vat.js.map +1 -1
  473. package/dist/sg/uen.d.ts +2 -2
  474. package/dist/sg/uen.js +1 -15
  475. package/dist/sg/uen.js.map +1 -1
  476. package/dist/si/emso.d.ts +2 -2
  477. package/dist/si/emso.js +3 -18
  478. package/dist/si/emso.js.map +1 -1
  479. package/dist/si/vat.d.ts +2 -2
  480. package/dist/si/vat.js +3 -12
  481. package/dist/si/vat.js.map +1 -1
  482. package/dist/sk/dic.d.ts +2 -2
  483. package/dist/sk/dic.js +1 -0
  484. package/dist/sk/dic.js.map +1 -1
  485. package/dist/sk/ico.d.ts +2 -2
  486. package/dist/sk/ico.js +1 -0
  487. package/dist/sk/ico.js.map +1 -1
  488. package/dist/sk/rc.d.ts +2 -2
  489. package/dist/sk/rc.js +1 -0
  490. package/dist/sk/rc.js.map +1 -1
  491. package/dist/th/tin.d.ts +2 -2
  492. package/dist/th/tin.js +1 -11
  493. package/dist/th/tin.js.map +1 -1
  494. package/dist/tr/tckimlik.d.ts +2 -2
  495. package/dist/tr/tckimlik.js +1 -20
  496. package/dist/tr/tckimlik.js.map +1 -1
  497. package/dist/tr/vkn.d.ts +2 -2
  498. package/dist/tr/vkn.js +1 -20
  499. package/dist/tr/vkn.js.map +1 -1
  500. package/dist/tw/ubn.d.ts +2 -2
  501. package/dist/tw/ubn.js +1 -11
  502. package/dist/tw/ubn.js.map +1 -1
  503. package/dist/types.d.ts +26 -4
  504. package/dist/ua/edrpou.d.ts +2 -2
  505. package/dist/ua/edrpou.js +1 -11
  506. package/dist/ua/edrpou.js.map +1 -1
  507. package/dist/us/ein.d.ts +12 -2
  508. package/dist/us/ein.js +1 -10
  509. package/dist/us/ein.js.map +1 -1
  510. package/dist/us/itin.d.ts +13 -2
  511. package/dist/us/itin.js +1 -11
  512. package/dist/us/itin.js.map +1 -1
  513. package/dist/us/rtn.d.ts +2 -2
  514. package/dist/us/rtn.js +3 -18
  515. package/dist/us/rtn.js.map +1 -1
  516. package/dist/us/ssn.d.ts +13 -2
  517. package/dist/us/ssn.js +1 -11
  518. package/dist/us/ssn.js.map +1 -1
  519. package/dist/uy/rut.d.ts +2 -2
  520. package/dist/uy/rut.js +1 -14
  521. package/dist/uy/rut.js.map +1 -1
  522. package/dist/ve/rif.d.ts +2 -2
  523. package/dist/ve/rif.js +2 -15
  524. package/dist/ve/rif.js.map +1 -1
  525. package/dist/vn/mst.d.ts +2 -2
  526. package/dist/vn/mst.js +1 -12
  527. package/dist/vn/mst.js.map +1 -1
  528. package/dist/za/idnr.d.ts +2 -2
  529. package/dist/za/idnr.js +3 -16
  530. package/dist/za/idnr.js.map +1 -1
  531. package/package.json +22 -12
  532. package/src/_checksums/mod1110.ts +1 -1
  533. package/src/ad/nrt.ts +7 -3
  534. package/src/ae/eid.ts +7 -3
  535. package/src/ai/tin.ts +7 -3
  536. package/src/al/nipt.ts +7 -3
  537. package/src/am/tin.ts +7 -3
  538. package/src/ar/cbu.ts +7 -3
  539. package/src/ar/cuit.ts +7 -3
  540. package/src/ar/dni.ts +7 -3
  541. package/src/at/businessid.ts +7 -3
  542. package/src/at/tin.ts +7 -3
  543. package/src/at/uid.ts +7 -3
  544. package/src/at/vnr.ts +37 -9
  545. package/src/au/abn.ts +7 -3
  546. package/src/au/acn.ts +7 -3
  547. package/src/au/tfn.ts +7 -3
  548. package/src/az/voen.ts +7 -3
  549. package/src/ba/jmbg.ts +8 -7
  550. package/src/bd/nid.ts +7 -3
  551. package/src/be/bis.ts +8 -4
  552. package/src/be/nn.ts +7 -3
  553. package/src/be/vat.ts +7 -3
  554. package/src/bg/egn.ts +8 -7
  555. package/src/bg/pnf.ts +7 -3
  556. package/src/bg/vat.ts +8 -3
  557. package/src/bh/cpr.ts +7 -3
  558. package/src/bic.ts +7 -3
  559. package/src/br/cnpj.ts +7 -3
  560. package/src/br/cpf.ts +7 -3
  561. package/src/by/unp.ts +10 -5
  562. package/src/bz/tin.ts +7 -3
  563. package/src/ca/bn.ts +7 -3
  564. package/src/ca/sin.ts +7 -3
  565. package/src/ch/ssn.ts +7 -3
  566. package/src/ch/uid.ts +7 -3
  567. package/src/ch/vat.ts +9 -5
  568. package/src/cl/rut.ts +7 -3
  569. package/src/cn/ric.ts +8 -7
  570. package/src/cn/uscc.ts +7 -3
  571. package/src/co/nit.ts +8 -4
  572. package/src/cr/cpf.ts +7 -3
  573. package/src/creditcard.ts +10 -6
  574. package/src/cu/ni.ts +8 -7
  575. package/src/cy/vat.ts +7 -3
  576. package/src/cz/dic.ts +9 -4
  577. package/src/cz/ico.ts +7 -3
  578. package/src/cz/rc.ts +8 -7
  579. package/src/de/handelsreg.ts +7 -3
  580. package/src/de/idnr.ts +7 -3
  581. package/src/de/stnr.ts +7 -3
  582. package/src/de/svnr.ts +7 -3
  583. package/src/de/vat.ts +7 -3
  584. package/src/dk/cpr.ts +8 -7
  585. package/src/dk/cvr.ts +7 -3
  586. package/src/dk/vat.ts +8 -3
  587. package/src/do/rnc.ts +7 -3
  588. package/src/ec/ruc.ts +7 -3
  589. package/src/ee/ik.ts +8 -7
  590. package/src/ee/registrikood.ts +8 -4
  591. package/src/ee/vat.ts +7 -3
  592. package/src/eg/tn.ts +7 -3
  593. package/src/es/cif.ts +8 -4
  594. package/src/es/dni.ts +7 -3
  595. package/src/es/nie.ts +8 -4
  596. package/src/es/nss.ts +7 -3
  597. package/src/es/vat.ts +13 -5
  598. package/src/eu/vat.ts +10 -6
  599. package/src/fi/hetu.ts +8 -7
  600. package/src/fi/vat.ts +8 -3
  601. package/src/fi/ytunnus.ts +7 -3
  602. package/src/fr/nif.ts +7 -3
  603. package/src/fr/nir.ts +8 -7
  604. package/src/fr/siren.ts +7 -3
  605. package/src/fr/siret.ts +7 -3
  606. package/src/fr/tva.ts +7 -3
  607. package/src/gb/nino.ts +7 -3
  608. package/src/gb/sedol.ts +7 -3
  609. package/src/gb/utr.ts +7 -3
  610. package/src/gb/vat.ts +7 -3
  611. package/src/ge/pin.ts +7 -3
  612. package/src/gh/tin.ts +7 -3
  613. package/src/gr/amka.ts +7 -3
  614. package/src/gr/vat.ts +7 -3
  615. package/src/gt/nit.ts +7 -3
  616. package/src/hk/hkid.ts +7 -3
  617. package/src/hr/vat.ts +7 -3
  618. package/src/hu/vat.ts +8 -3
  619. package/src/iban.ts +7 -3
  620. package/src/id/npwp.ts +7 -3
  621. package/src/ie/pps.ts +7 -3
  622. package/src/ie/vat.ts +7 -3
  623. package/src/il/idnr.ts +7 -3
  624. package/src/in/aadhaar.ts +7 -3
  625. package/src/in/gstin.ts +7 -3
  626. package/src/in/pan.ts +7 -3
  627. package/src/index.ts +3 -0
  628. package/src/iq/nid.ts +7 -3
  629. package/src/ir/nid.ts +7 -3
  630. package/src/is/kennitala.ts +7 -3
  631. package/src/is/vsk.ts +7 -3
  632. package/src/isin.ts +7 -3
  633. package/src/it/codicefiscale.ts +11 -7
  634. package/src/it/iva.ts +7 -3
  635. package/src/jp/cn.ts +7 -3
  636. package/src/jp/mynumber.ts +7 -3
  637. package/src/kr/brn.ts +7 -3
  638. package/src/kr/rrn.ts +8 -7
  639. package/src/kw/civil.ts +8 -7
  640. package/src/kz/iin.ts +8 -8
  641. package/src/lei.ts +7 -3
  642. package/src/li/peid.ts +7 -3
  643. package/src/lk/nic.ts +8 -7
  644. package/src/lt/asmens.ts +8 -4
  645. package/src/lt/vat.ts +8 -3
  646. package/src/lu/vat.ts +8 -3
  647. package/src/luhn.ts +7 -3
  648. package/src/lv/vat.ts +7 -3
  649. package/src/ma/ice.ts +7 -3
  650. package/src/mc/tva.ts +9 -5
  651. package/src/md/idno.ts +7 -3
  652. package/src/me/pib.ts +7 -3
  653. package/src/mk/edb.ts +7 -3
  654. package/src/mt/vat.ts +8 -3
  655. package/src/mu/brn.ts +7 -3
  656. package/src/mx/clabe.ts +7 -3
  657. package/src/mx/curp.ts +9 -8
  658. package/src/mx/rfc.ts +8 -4
  659. package/src/my/nric.ts +8 -7
  660. package/src/ng/nin.ts +7 -3
  661. package/src/ni/ruc.ts +7 -3
  662. package/src/nl/bsn.ts +7 -3
  663. package/src/nl/kvk.ts +7 -3
  664. package/src/nl/vat.ts +7 -3
  665. package/src/no/fodselsnummer.ts +11 -7
  666. package/src/no/mva.ts +9 -5
  667. package/src/no/orgnr.ts +7 -3
  668. package/src/nz/ird.ts +8 -4
  669. package/src/pa/ruc.ts +7 -3
  670. package/src/patterns.ts +49 -18
  671. package/src/pe/ruc.ts +7 -3
  672. package/src/ph/philid.ts +7 -3
  673. package/src/pk/cnic.ts +7 -3
  674. package/src/pl/nip.ts +7 -3
  675. package/src/pl/pesel.ts +8 -7
  676. package/src/pl/regon.ts +7 -3
  677. package/src/pt/cc.ts +7 -3
  678. package/src/pt/vat.ts +8 -3
  679. package/src/ro/cnp.ts +15 -8
  680. package/src/ro/vat.ts +8 -3
  681. package/src/rs/pib.ts +7 -3
  682. package/src/ru/inn.ts +7 -3
  683. package/src/se/orgnr.ts +7 -3
  684. package/src/se/personnummer.ts +35 -33
  685. package/src/se/vat.ts +8 -3
  686. package/src/sg/uen.ts +7 -3
  687. package/src/si/emso.ts +8 -7
  688. package/src/si/vat.ts +8 -3
  689. package/src/sk/dic.ts +8 -4
  690. package/src/sk/ico.ts +3 -2
  691. package/src/sk/rc.ts +6 -2
  692. package/src/th/tin.ts +7 -3
  693. package/src/tr/tckimlik.ts +7 -3
  694. package/src/tr/vkn.ts +7 -3
  695. package/src/tw/ubn.ts +7 -3
  696. package/src/types.ts +34 -3
  697. package/src/ua/edrpou.ts +7 -3
  698. package/src/us/ein.ts +7 -3
  699. package/src/us/itin.ts +7 -3
  700. package/src/us/rtn.ts +16 -8
  701. package/src/us/ssn.ts +7 -3
  702. package/src/uy/rut.ts +7 -3
  703. package/src/ve/rif.ts +8 -6
  704. package/src/vn/mst.ts +7 -3
  705. package/src/za/idnr.ts +8 -7
@@ -1 +1 @@
1
- {"version":3,"file":"ric.js","names":[],"sources":["../../src/cn/ric.ts"],"sourcesContent":["/**\n * RIC (Resident Identity Card number, 居民身份证号码).\n *\n * Chinese national identifier. 18 characters:\n * 6 (area code) + 8 (YYYYMMDD birth) + 3 (sequence,\n * odd = male) + 1 (check, 0-9 or X).\n *\n * Also accepts the legacy 15-digit format (no check\n * digit, 2-digit year).\n *\n * @see https://en.wikipedia.org/wiki/Resident_Identity_Card\n */\n\nimport {\n mod112checkChar,\n mod112validate,\n} from \"#checksums/mod112\";\nimport { clean } from \"#util/clean\";\nimport { isValidDate } from \"#util/date\";\nimport { randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nimport type {\n ParsedPersonId,\n ValidateResult,\n Validator,\n} from \"../types\";\n\nconst compact = (value: string): string =>\n clean(value, \" -\").toUpperCase();\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 15 && v.length !== 18) {\n return err(\n \"INVALID_LENGTH\",\n \"RIC must be 15 or 18 characters\",\n );\n }\n\n if (v.length === 15) {\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"15-digit RIC must contain only digits\",\n );\n }\n // Validate date: digits 6-11 are YYMMDD\n const year = 1900 + Number(v.slice(6, 8));\n const month = Number(v.slice(8, 10));\n const day = Number(v.slice(10, 12));\n if (!isValidDate(year, month, day)) {\n return err(\n \"INVALID_COMPONENT\",\n \"RIC contains an invalid birth date\",\n );\n }\n return { valid: true, compact: v };\n }\n\n // 18-character format\n if (!isdigits(v.slice(0, 17))) {\n return err(\n \"INVALID_FORMAT\",\n \"RIC must contain only digits (plus check char)\",\n );\n }\n // SAFETY: 18-character branch guarantees v[17] exists.\n // eslint-disable-next-line no-non-null-assertion\n const lastChar = v[17]!;\n if (!isdigits(lastChar) && lastChar !== \"X\") {\n return err(\n \"INVALID_FORMAT\",\n \"RIC check character must be 0-9 or X\",\n );\n }\n\n // Validate date: digits 6-13 are YYYYMMDD\n const year = Number(v.slice(6, 10));\n const month = Number(v.slice(10, 12));\n const day = Number(v.slice(12, 14));\n if (!isValidDate(year, month, day)) {\n return err(\n \"INVALID_COMPONENT\",\n \"RIC contains an invalid birth date\",\n );\n }\n\n if (!mod112validate(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"RIC check character does not match\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => compact(value);\n\n/**\n * Extract birth date and gender from an RIC number.\n * Returns null if the value is not valid.\n */\nconst parse = (value: string): ParsedPersonId | null => {\n const result = validate(value);\n if (!result.valid) return null;\n\n const v = result.compact;\n\n let year: number;\n let month: number;\n let day: number;\n let seq: number;\n\n if (v.length === 15) {\n year = 1900 + Number(v.slice(6, 8));\n month = Number(v.slice(8, 10));\n day = Number(v.slice(10, 12));\n seq = Number(v.slice(12, 15));\n } else {\n year = Number(v.slice(6, 10));\n month = Number(v.slice(10, 12));\n day = Number(v.slice(12, 14));\n seq = Number(v.slice(14, 17));\n }\n\n const gender = seq % 2 === 1 ? \"male\" : \"female\";\n\n return {\n birthDate: new Date(year, month - 1, day),\n gender,\n };\n};\n\n/** Generate a random valid 18-digit RIC. */\nconst generate = (): string => {\n // Use a simple area code prefix\n const area = String(randomInt(110000, 659999));\n const year = randomInt(1950, 2005);\n const month = randomInt(1, 12);\n const day = randomInt(1, 28);\n const seqNum = randomInt(1, 999);\n const seq = String(seqNum).padStart(3, \"0\");\n\n const yStr = String(year);\n const mStr = String(month).padStart(2, \"0\");\n const dStr = String(day).padStart(2, \"0\");\n\n const payload = `${area}${yStr}${mStr}${dStr}${seq}`;\n const check = mod112checkChar(payload);\n return `${payload}${check}`;\n};\n\n/** Chinese Resident Identity Card number. */\nconst ric: Validator<ParsedPersonId> = {\n name: \"Chinese Resident Identity Card\",\n localName: \"居民身份证号码\",\n abbreviation: \"RIC\",\n aliases: [\"身份证\", \"居民身份证号码\", \"RIC\"] as const,\n candidatePattern: \"\\\\d{17}[\\\\dX]\",\n country: \"CN\",\n entityType: \"person\",\n description:\n \"18-character national ID encoding area, birth date, gender, and check digit\",\n sourceUrl:\n \"https://en.wikipedia.org/wiki/Resident_Identity_Card\",\n lengths: [15, 18] as const,\n examples: [\n \"11010519491231002X\",\n \"440524188001010014\",\n ] as const,\n compact,\n format,\n parse,\n validate,\n generate,\n};\n\nexport default ric;\nexport { compact, format, generate, parse, validate };\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA6BA,MAAM,WAAW,UACf,MAAM,OAAO,KAAK,CAAC,aAAa;AAElC,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,MAAM;AAExB,KAAI,EAAE,WAAW,MAAM,EAAE,WAAW,GAClC,QAAO,IACL,kBACA,kCACD;AAGH,KAAI,EAAE,WAAW,IAAI;AACnB,MAAI,CAAC,SAAS,EAAE,CACd,QAAO,IACL,kBACA,wCACD;AAMH,MAAI,CAAC,YAHQ,OAAO,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC,EAC3B,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,EACxB,OAAO,EAAE,MAAM,IAAI,GAAG,CAAC,CACD,CAChC,QAAO,IACL,qBACA,qCACD;AAEH,SAAO;GAAE,OAAO;GAAM,SAAS;GAAG;;AAIpC,KAAI,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,CAAC,CAC3B,QAAO,IACL,kBACA,iDACD;CAIH,MAAM,WAAW,EAAE;AACnB,KAAI,CAAC,SAAS,SAAS,IAAI,aAAa,IACtC,QAAO,IACL,kBACA,uCACD;AAOH,KAAI,CAAC,YAHQ,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,EACrB,OAAO,EAAE,MAAM,IAAI,GAAG,CAAC,EACzB,OAAO,EAAE,MAAM,IAAI,GAAG,CAAC,CACD,CAChC,QAAO,IACL,qBACA,qCACD;AAGH,KAAI,CAAC,eAAe,EAAE,CACpB,QAAO,IACL,oBACA,qCACD;AAGH,QAAO;EAAE,OAAO;EAAM,SAAS;EAAG;;AAGpC,MAAM,UAAU,UAA0B,QAAQ,MAAM;;;;;AAMxD,MAAM,SAAS,UAAyC;CACtD,MAAM,SAAS,SAAS,MAAM;AAC9B,KAAI,CAAC,OAAO,MAAO,QAAO;CAE1B,MAAM,IAAI,OAAO;CAEjB,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AAEJ,KAAI,EAAE,WAAW,IAAI;AACnB,SAAO,OAAO,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;AACnC,UAAQ,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC;AAC9B,QAAM,OAAO,EAAE,MAAM,IAAI,GAAG,CAAC;AAC7B,QAAM,OAAO,EAAE,MAAM,IAAI,GAAG,CAAC;QACxB;AACL,SAAO,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC;AAC7B,UAAQ,OAAO,EAAE,MAAM,IAAI,GAAG,CAAC;AAC/B,QAAM,OAAO,EAAE,MAAM,IAAI,GAAG,CAAC;AAC7B,QAAM,OAAO,EAAE,MAAM,IAAI,GAAG,CAAC;;CAG/B,MAAM,SAAS,MAAM,MAAM,IAAI,SAAS;AAExC,QAAO;EACL,WAAW,IAAI,KAAK,MAAM,QAAQ,GAAG,IAAI;EACzC;EACD;;;AAIH,MAAM,iBAAyB;CAE7B,MAAM,OAAO,OAAO,UAAU,MAAQ,OAAO,CAAC;CAC9C,MAAM,OAAO,UAAU,MAAM,KAAK;CAClC,MAAM,QAAQ,UAAU,GAAG,GAAG;CAC9B,MAAM,MAAM,UAAU,GAAG,GAAG;CAC5B,MAAM,SAAS,UAAU,GAAG,IAAI;CAChC,MAAM,MAAM,OAAO,OAAO,CAAC,SAAS,GAAG,IAAI;CAM3C,MAAM,UAAU,GAAG,OAJN,OAAO,KAAK,GACZ,OAAO,MAAM,CAAC,SAAS,GAAG,IAAI,GAC9B,OAAO,IAAI,CAAC,SAAS,GAAG,IAAI,GAEM;AAE/C,QAAO,GAAG,UADI,gBAAgB,QAAQ;;;AAKxC,MAAM,MAAiC;CACrC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS;EAAC;EAAO;EAAW;EAAM;CAClC,kBAAkB;CAClB,SAAS;CACT,YAAY;CACZ,aACE;CACF,WACE;CACF,SAAS,CAAC,IAAI,GAAG;CACjB,UAAU,CACR,sBACA,qBACD;CACD;CACA;CACA;CACA;CACA;CACD"}
1
+ {"version":3,"file":"ric.js","names":[],"sources":["../../src/cn/ric.ts"],"sourcesContent":["/**\n * RIC (Resident Identity Card number, 居民身份证号码).\n *\n * Chinese national identifier. 18 characters:\n * 6 (area code) + 8 (YYYYMMDD birth) + 3 (sequence,\n * odd = male) + 1 (check, 0-9 or X).\n *\n * Also accepts the legacy 15-digit format (no check\n * digit, 2-digit year).\n *\n * @see https://en.wikipedia.org/wiki/Resident_Identity_Card\n */\n\nimport type {\n ParsedPersonId,\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport {\n mod112checkChar,\n mod112validate,\n} from \"#checksums/mod112\";\nimport { clean } from \"#util/clean\";\nimport { isValidDate } from \"#util/date\";\nimport { randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst compact = (value: string): string =>\n clean(value, \" -\").toUpperCase();\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 15 && v.length !== 18) {\n return err(\n \"INVALID_LENGTH\",\n \"RIC must be 15 or 18 characters\",\n );\n }\n\n if (v.length === 15) {\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"15-digit RIC must contain only digits\",\n );\n }\n // Validate date: digits 6-11 are YYMMDD\n const year = 1900 + Number(v.slice(6, 8));\n const month = Number(v.slice(8, 10));\n const day = Number(v.slice(10, 12));\n if (!isValidDate(year, month, day)) {\n return err(\n \"INVALID_COMPONENT\",\n \"RIC contains an invalid birth date\",\n );\n }\n return { valid: true, compact: v };\n }\n\n // 18-character format\n if (!isdigits(v.slice(0, 17))) {\n return err(\n \"INVALID_FORMAT\",\n \"RIC must contain only digits (plus check char)\",\n );\n }\n // SAFETY: 18-character branch guarantees v[17] exists.\n // eslint-disable-next-line no-non-null-assertion\n const lastChar = v[17]!;\n if (!isdigits(lastChar) && lastChar !== \"X\") {\n return err(\n \"INVALID_FORMAT\",\n \"RIC check character must be 0-9 or X\",\n );\n }\n\n // Validate date: digits 6-13 are YYYYMMDD\n const year = Number(v.slice(6, 10));\n const month = Number(v.slice(10, 12));\n const day = Number(v.slice(12, 14));\n if (!isValidDate(year, month, day)) {\n return err(\n \"INVALID_COMPONENT\",\n \"RIC contains an invalid birth date\",\n );\n }\n\n if (!mod112validate(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"RIC check character does not match\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => compact(value);\n\n/**\n * Extract birth date and gender from an RIC number.\n * Returns null if the value is not valid.\n */\nconst parse = (value: string): ParsedPersonId | null => {\n const result = validate(value);\n if (!result.valid) return null;\n\n const v = result.compact;\n\n let year: number;\n let month: number;\n let day: number;\n let seq: number;\n\n if (v.length === 15) {\n year = 1900 + Number(v.slice(6, 8));\n month = Number(v.slice(8, 10));\n day = Number(v.slice(10, 12));\n seq = Number(v.slice(12, 15));\n } else {\n year = Number(v.slice(6, 10));\n month = Number(v.slice(10, 12));\n day = Number(v.slice(12, 14));\n seq = Number(v.slice(14, 17));\n }\n\n const gender = seq % 2 === 1 ? \"male\" : \"female\";\n\n return {\n birthDate: new Date(year, month - 1, day),\n gender,\n };\n};\n\n/** Generate a random valid 18-digit RIC. */\nconst generate = (): string => {\n // Use a simple area code prefix\n const area = String(randomInt(110000, 659999));\n const year = randomInt(1950, 2005);\n const month = randomInt(1, 12);\n const day = randomInt(1, 28);\n const seqNum = randomInt(1, 999);\n const seq = String(seqNum).padStart(3, \"0\");\n\n const yStr = String(year);\n const mStr = String(month).padStart(2, \"0\");\n const dStr = String(day).padStart(2, \"0\");\n\n const payload = `${area}${yStr}${mStr}${dStr}${seq}`;\n const check = mod112checkChar(payload);\n return `${payload}${check}`;\n};\n\n/** Chinese Resident Identity Card number. */\nconst ric: CountryValidator<\"CN\", ParsedPersonId> = {\n name: \"Chinese Resident Identity Card\",\n localName: \"居民身份证号码\",\n abbreviation: \"RIC\",\n aliases: [\"身份证\", \"居民身份证号码\", \"RIC\"] as const,\n candidatePattern: \"\\\\d{17}[\\\\dX]\",\n scope: \"country\",\n country: \"CN\",\n entityType: \"person\",\n description:\n \"18-character national ID encoding area, birth date, gender, and check digit\",\n sourceUrl:\n \"https://en.wikipedia.org/wiki/Resident_Identity_Card\",\n lengths: [15, 18] as const,\n examples: [\n \"11010519491231002X\",\n \"440524188001010014\",\n ] as const,\n compact,\n format,\n parse,\n validate,\n generate,\n};\n\nexport default ric;\nexport { compact, format, generate, parse, validate };\n"],"mappings":";;;;;;;AA6BA,MAAM,WAAW,UACf,MAAM,OAAO,IAAI,EAAE,YAAY;AAEjC,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CAEvB,IAAI,EAAE,WAAW,MAAM,EAAE,WAAW,IAClC,OAAO,IACL,kBACA,iCACF;CAGF,IAAI,EAAE,WAAW,IAAI;EACnB,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,uCACF;EAMF,IAAI,CAAC,YAHQ,OAAO,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC,GAC1B,OAAO,EAAE,MAAM,GAAG,EAAE,CAEP,GADf,OAAO,EAAE,MAAM,IAAI,EAAE,CACD,CAAC,GAC/B,OAAO,IACL,qBACA,oCACF;EAEF,OAAO;GAAE,OAAO;GAAM,SAAS;EAAE;CACnC;CAGA,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,EAAE,CAAC,GAC1B,OAAO,IACL,kBACA,gDACF;CAIF,MAAM,WAAW,EAAE;CACnB,IAAI,CAAC,SAAS,QAAQ,KAAK,aAAa,KACtC,OAAO,IACL,kBACA,sCACF;CAOF,IAAI,CAAC,YAHQ,OAAO,EAAE,MAAM,GAAG,EAAE,CAGb,GAFN,OAAO,EAAE,MAAM,IAAI,EAAE,CAER,GADf,OAAO,EAAE,MAAM,IAAI,EAAE,CACD,CAAC,GAC/B,OAAO,IACL,qBACA,oCACF;CAGF,IAAI,CAAC,eAAe,CAAC,GACnB,OAAO,IACL,oBACA,oCACF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B,QAAQ,KAAK;;;;;AAMvD,MAAM,SAAS,UAAyC;CACtD,MAAM,SAAS,SAAS,KAAK;CAC7B,IAAI,CAAC,OAAO,OAAO,OAAO;CAE1B,MAAM,IAAI,OAAO;CAEjB,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CAEJ,IAAI,EAAE,WAAW,IAAI;EACnB,OAAO,OAAO,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;EAClC,QAAQ,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;EAC7B,MAAM,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC;EAC5B,MAAM,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC;CAC9B,OAAO;EACL,OAAO,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;EAC5B,QAAQ,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC;EAC9B,MAAM,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC;EAC5B,MAAM,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC;CAC9B;CAEA,MAAM,SAAS,MAAM,MAAM,IAAI,SAAS;CAExC,OAAO;EACL,WAAW,IAAI,KAAK,MAAM,QAAQ,GAAG,GAAG;EACxC;CACF;AACF;;AAGA,MAAM,iBAAyB;CAE7B,MAAM,OAAO,OAAO,UAAU,MAAQ,MAAM,CAAC;CAC7C,MAAM,OAAO,UAAU,MAAM,IAAI;CACjC,MAAM,QAAQ,UAAU,GAAG,EAAE;CAC7B,MAAM,MAAM,UAAU,GAAG,EAAE;CAC3B,MAAM,SAAS,UAAU,GAAG,GAAG;CAC/B,MAAM,MAAM,OAAO,MAAM,EAAE,SAAS,GAAG,GAAG;CAM1C,MAAM,UAAU,GAAG,OAJN,OAAO,IAIS,IAHhB,OAAO,KAAK,EAAE,SAAS,GAAG,GAGH,IAFvB,OAAO,GAAG,EAAE,SAAS,GAAG,GAEM,IAAI;CAE/C,OAAO,GAAG,UADI,gBAAgB,OACN;AAC1B;;AAGA,MAAM,MAA8C;CAClD,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS;EAAC;EAAO;EAAW;CAAK;CACjC,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,aACE;CACF,WACE;CACF,SAAS,CAAC,IAAI,EAAE;CAChB,UAAU,CACR,sBACA,oBACF;CACA;CACA;CACA;CACA;CACA;AACF"}
package/dist/cn/uscc.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ValidateResult, Validator } from "../types.js";
1
+ import { CountryValidator, ValidateResult } from "../types.js";
2
2
 
3
3
  //#region src/cn/uscc.d.ts
4
4
  declare const compact: (value: string) => string;
@@ -7,7 +7,7 @@ declare const format: (value: string) => string;
7
7
  /** Generate a random valid USCC. */
8
8
  declare const generate: () => string;
9
9
  /** Chinese Unified Social Credit Code. */
10
- declare const uscc: Validator;
10
+ declare const uscc: CountryValidator<"CN">;
11
11
  //#endregion
12
12
  export { compact, uscc as default, format, generate, validate };
13
13
  //# sourceMappingURL=uscc.d.ts.map
package/dist/cn/uscc.js CHANGED
@@ -3,16 +3,6 @@ import { randomChar, randomDigits, randomInt } from "../_util/generate.js";
3
3
  import { err } from "../_util/result.js";
4
4
  import { isdigits } from "../_util/strings.js";
5
5
  //#region src/cn/uscc.ts
6
- /**
7
- * USCC (Unified Social Credit Code, 统一社会信用代码).
8
- *
9
- * 18 alphanumeric characters (excluding I, O, Z, S, V):
10
- * 1 (registering authority) + 1 (entity type) +
11
- * 6 (region code, digits only) + 9 (organisation code) +
12
- * 1 (mod 31 check character).
13
- *
14
- * @see https://zh.wikipedia.org/wiki/统一社会信用代码
15
- */
16
6
  const ALPHABET = "0123456789ABCDEFGHJKLMNPQRTUWXY";
17
7
  const WEIGHTS = [
18
8
  1,
@@ -72,6 +62,7 @@ const uscc = {
72
62
  abbreviation: "USCC",
73
63
  aliases: ["统一社会信用代码", "USCC"],
74
64
  candidatePattern: "[0-9A-HJ-NP-RTUW-Y]{2}\\d{6}[0-9A-HJ-NP-RTUW-Y]{10}",
65
+ scope: "country",
75
66
  country: "CN",
76
67
  entityType: "company",
77
68
  description: "18-character tax/registration code for Chinese entities",
@@ -1 +1 @@
1
- {"version":3,"file":"uscc.js","names":[],"sources":["../../src/cn/uscc.ts"],"sourcesContent":["/**\n * USCC (Unified Social Credit Code, 统一社会信用代码).\n *\n * 18 alphanumeric characters (excluding I, O, Z, S, V):\n * 1 (registering authority) + 1 (entity type) +\n * 6 (region code, digits only) + 9 (organisation code) +\n * 1 (mod 31 check character).\n *\n * @see https://zh.wikipedia.org/wiki/统一社会信用代码\n */\n\nimport { clean } from \"#util/clean\";\nimport {\n randomChar,\n randomDigits,\n randomInt,\n} from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nimport type { ValidateResult, Validator } from \"../types\";\n\nconst ALPHABET = \"0123456789ABCDEFGHJKLMNPQRTUWXY\";\n\nconst WEIGHTS = [\n 1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10,\n 30, 28,\n] as const;\n\nconst compact = (value: string): string =>\n clean(value, \" -\").toUpperCase();\n\nconst calcCheckChar = (value: string): string => {\n let total = 0;\n for (const [i, weight] of WEIGHTS.entries()) {\n const ch = value[i];\n if (ch === undefined) continue;\n total += ALPHABET.indexOf(ch) * weight;\n }\n // SAFETY: (31 - total % 31) % 31 is in 0..30 and\n // ALPHABET has 31 characters.\n // eslint-disable-next-line no-non-null-assertion\n return ALPHABET[(31 - (total % 31)) % 31]!;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 18) {\n return err(\n \"INVALID_LENGTH\",\n \"USCC must be 18 characters\",\n );\n }\n\n for (const ch of v) {\n if (!ALPHABET.includes(ch)) {\n return err(\n \"INVALID_FORMAT\",\n \"USCC contains invalid character\",\n );\n }\n }\n\n if (!isdigits(v.slice(2, 8))) {\n return err(\n \"INVALID_FORMAT\",\n \"USCC region code (positions 3-8) must be digits\",\n );\n }\n\n if (v[17] !== calcCheckChar(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"USCC check character does not match\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => compact(value);\n\n/** Generate a random valid USCC. */\nconst generate = (): string => {\n // SAFETY: indices 1..9 are within ALPHABET (31 chars).\n // eslint-disable-next-line no-non-null-assertion\n const reg = ALPHABET[randomInt(1, 9)]!;\n // eslint-disable-next-line no-non-null-assertion\n const etype = ALPHABET[randomInt(1, 9)]!;\n const region = randomDigits(6);\n let org = \"\";\n for (let i = 0; i < 9; i++) {\n org += randomChar(ALPHABET);\n }\n const payload = reg + etype + region + org;\n return payload + calcCheckChar(payload);\n};\n\n/** Chinese Unified Social Credit Code. */\nconst uscc: Validator = {\n name: \"Unified Social Credit Code\",\n localName: \"统一社会信用代码\",\n abbreviation: \"USCC\",\n aliases: [\"统一社会信用代码\", \"USCC\"] as const,\n candidatePattern:\n \"[0-9A-HJ-NP-RTUW-Y]{2}\\\\d{6}[0-9A-HJ-NP-RTUW-Y]{10}\",\n country: \"CN\",\n entityType: \"company\",\n description:\n \"18-character tax/registration code for Chinese entities\",\n sourceUrl:\n \"https://zh.wikipedia.org/wiki/统一社会信用代码\",\n lengths: [18] as const,\n examples: [\"91110000600037341L\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default uscc;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;;;;;;;;;;AAsBA,MAAM,WAAW;AAEjB,MAAM,UAAU;CACd;CAAG;CAAG;CAAG;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAG;CAAI;CACpD;CAAI;CACL;AAED,MAAM,WAAW,UACf,MAAM,OAAO,KAAK,CAAC,aAAa;AAElC,MAAM,iBAAiB,UAA0B;CAC/C,IAAI,QAAQ;AACZ,MAAK,MAAM,CAAC,GAAG,WAAW,QAAQ,SAAS,EAAE;EAC3C,MAAM,KAAK,MAAM;AACjB,MAAI,OAAO,KAAA,EAAW;AACtB,WAAS,SAAS,QAAQ,GAAG,GAAG;;AAKlC,QAAO,UAAU,KAAM,QAAQ,MAAO;;AAGxC,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,MAAM;AAExB,KAAI,EAAE,WAAW,GACf,QAAO,IACL,kBACA,6BACD;AAGH,MAAK,MAAM,MAAM,EACf,KAAI,CAAC,SAAS,SAAS,GAAG,CACxB,QAAO,IACL,kBACA,kCACD;AAIL,KAAI,CAAC,SAAS,EAAE,MAAM,GAAG,EAAE,CAAC,CAC1B,QAAO,IACL,kBACA,kDACD;AAGH,KAAI,EAAE,QAAQ,cAAc,EAAE,CAC5B,QAAO,IACL,oBACA,sCACD;AAGH,QAAO;EAAE,OAAO;EAAM,SAAS;EAAG;;AAGpC,MAAM,UAAU,UAA0B,QAAQ,MAAM;;AAGxD,MAAM,iBAAyB;CAG7B,MAAM,MAAM,SAAS,UAAU,GAAG,EAAE;CAEpC,MAAM,QAAQ,SAAS,UAAU,GAAG,EAAE;CACtC,MAAM,SAAS,aAAa,EAAE;CAC9B,IAAI,MAAM;AACV,MAAK,IAAI,IAAI,GAAG,IAAI,GAAG,IACrB,QAAO,WAAW,SAAS;CAE7B,MAAM,UAAU,MAAM,QAAQ,SAAS;AACvC,QAAO,UAAU,cAAc,QAAQ;;;AAIzC,MAAM,OAAkB;CACtB,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,YAAY,OAAO;CAC7B,kBACE;CACF,SAAS;CACT,YAAY;CACZ,aACE;CACF,WACE;CACF,SAAS,CAAC,GAAG;CACb,UAAU,CAAC,qBAAqB;CAChC;CACA;CACA;CACA;CACD"}
1
+ {"version":3,"file":"uscc.js","names":[],"sources":["../../src/cn/uscc.ts"],"sourcesContent":["/**\n * USCC (Unified Social Credit Code, 统一社会信用代码).\n *\n * 18 alphanumeric characters (excluding I, O, Z, S, V):\n * 1 (registering authority) + 1 (entity type) +\n * 6 (region code, digits only) + 9 (organisation code) +\n * 1 (mod 31 check character).\n *\n * @see https://zh.wikipedia.org/wiki/统一社会信用代码\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport {\n randomChar,\n randomDigits,\n randomInt,\n} from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst ALPHABET = \"0123456789ABCDEFGHJKLMNPQRTUWXY\";\n\nconst WEIGHTS = [\n 1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10,\n 30, 28,\n] as const;\n\nconst compact = (value: string): string =>\n clean(value, \" -\").toUpperCase();\n\nconst calcCheckChar = (value: string): string => {\n let total = 0;\n for (const [i, weight] of WEIGHTS.entries()) {\n const ch = value[i];\n if (ch === undefined) continue;\n total += ALPHABET.indexOf(ch) * weight;\n }\n // SAFETY: (31 - total % 31) % 31 is in 0..30 and\n // ALPHABET has 31 characters.\n // eslint-disable-next-line no-non-null-assertion\n return ALPHABET[(31 - (total % 31)) % 31]!;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 18) {\n return err(\n \"INVALID_LENGTH\",\n \"USCC must be 18 characters\",\n );\n }\n\n for (const ch of v) {\n if (!ALPHABET.includes(ch)) {\n return err(\n \"INVALID_FORMAT\",\n \"USCC contains invalid character\",\n );\n }\n }\n\n if (!isdigits(v.slice(2, 8))) {\n return err(\n \"INVALID_FORMAT\",\n \"USCC region code (positions 3-8) must be digits\",\n );\n }\n\n if (v[17] !== calcCheckChar(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"USCC check character does not match\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => compact(value);\n\n/** Generate a random valid USCC. */\nconst generate = (): string => {\n // SAFETY: indices 1..9 are within ALPHABET (31 chars).\n // eslint-disable-next-line no-non-null-assertion\n const reg = ALPHABET[randomInt(1, 9)]!;\n // eslint-disable-next-line no-non-null-assertion\n const etype = ALPHABET[randomInt(1, 9)]!;\n const region = randomDigits(6);\n let org = \"\";\n for (let i = 0; i < 9; i++) {\n org += randomChar(ALPHABET);\n }\n const payload = reg + etype + region + org;\n return payload + calcCheckChar(payload);\n};\n\n/** Chinese Unified Social Credit Code. */\nconst uscc: CountryValidator<\"CN\"> = {\n name: \"Unified Social Credit Code\",\n localName: \"统一社会信用代码\",\n abbreviation: \"USCC\",\n aliases: [\"统一社会信用代码\", \"USCC\"] as const,\n candidatePattern:\n \"[0-9A-HJ-NP-RTUW-Y]{2}\\\\d{6}[0-9A-HJ-NP-RTUW-Y]{10}\",\n scope: \"country\",\n country: \"CN\",\n entityType: \"company\",\n description:\n \"18-character tax/registration code for Chinese entities\",\n sourceUrl:\n \"https://zh.wikipedia.org/wiki/统一社会信用代码\",\n lengths: [18] as const,\n examples: [\"91110000600037341L\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default uscc;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;AAyBA,MAAM,WAAW;AAEjB,MAAM,UAAU;CACd;CAAG;CAAG;CAAG;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAG;CAAI;CACpD;CAAI;AACN;AAEA,MAAM,WAAW,UACf,MAAM,OAAO,IAAI,EAAE,YAAY;AAEjC,MAAM,iBAAiB,UAA0B;CAC/C,IAAI,QAAQ;CACZ,KAAK,MAAM,CAAC,GAAG,WAAW,QAAQ,QAAQ,GAAG;EAC3C,MAAM,KAAK,MAAM;EACjB,IAAI,OAAO,KAAA,GAAW;EACtB,SAAS,SAAS,QAAQ,EAAE,IAAI;CAClC;CAIA,OAAO,UAAU,KAAM,QAAQ,MAAO;AACxC;AAEA,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CAEvB,IAAI,EAAE,WAAW,IACf,OAAO,IACL,kBACA,4BACF;CAGF,KAAK,MAAM,MAAM,GACf,IAAI,CAAC,SAAS,SAAS,EAAE,GACvB,OAAO,IACL,kBACA,iCACF;CAIJ,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,CAAC,CAAC,GACzB,OAAO,IACL,kBACA,iDACF;CAGF,IAAI,EAAE,QAAQ,cAAc,CAAC,GAC3B,OAAO,IACL,oBACA,qCACF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B,QAAQ,KAAK;;AAGvD,MAAM,iBAAyB;CAG7B,MAAM,MAAM,SAAS,UAAU,GAAG,CAAC;CAEnC,MAAM,QAAQ,SAAS,UAAU,GAAG,CAAC;CACrC,MAAM,SAAS,aAAa,CAAC;CAC7B,IAAI,MAAM;CACV,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KACrB,OAAO,WAAW,QAAQ;CAE5B,MAAM,UAAU,MAAM,QAAQ,SAAS;CACvC,OAAO,UAAU,cAAc,OAAO;AACxC;;AAGA,MAAM,OAA+B;CACnC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,YAAY,MAAM;CAC5B,kBACE;CACF,OAAO;CACP,SAAS;CACT,YAAY;CACZ,aACE;CACF,WACE;CACF,SAAS,CAAC,EAAE;CACZ,UAAU,CAAC,oBAAoB;CAC/B;CACA;CACA;CACA;AACF"}
package/dist/co/nit.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ValidateResult, Validator } from "../types.js";
1
+ import { CountryValidator, ValidateResult } from "../types.js";
2
2
 
3
3
  //#region src/co/nit.d.ts
4
4
  declare const compact: (value: string) => string;
@@ -7,7 +7,7 @@ declare const format: (value: string) => string;
7
7
  /** Generate a random valid NIT (10 digits). */
8
8
  declare const generate: () => string;
9
9
  /** Colombian tax identification number. */
10
- declare const nit: Validator;
10
+ declare const nit: CountryValidator<"CO">;
11
11
  //#endregion
12
12
  export { compact, nit as default, format, generate, validate };
13
13
  //# sourceMappingURL=nit.d.ts.map
package/dist/co/nit.js CHANGED
@@ -3,17 +3,6 @@ import { randomDigits } from "../_util/generate.js";
3
3
  import { err } from "../_util/result.js";
4
4
  import { isdigits } from "../_util/strings.js";
5
5
  //#region src/co/nit.ts
6
- /**
7
- * NIT (Número de Identificación Tributaria).
8
- *
9
- * Colombian tax identification number, also known as
10
- * RUT (Registro Unico Tributario). The last digit is
11
- * a check digit computed via a weighted sum mod 11
12
- * with weights [3,7,13,17,19,23,29,37,41,43,47,53,
13
- * 59,67,71] applied right-to-left.
14
- *
15
- * @see https://es.wikipedia.org/wiki/Número_de_identificación_tributaria
16
- */
17
6
  const WEIGHTS = [
18
7
  3,
19
8
  7,
@@ -59,7 +48,7 @@ const validate = (value) => {
59
48
  const v = compact(value);
60
49
  if (v.length < 8 || v.length > 16) return err("INVALID_LENGTH", "NIT must be between 8 and 16 digits");
61
50
  if (!isdigits(v)) return err("INVALID_FORMAT", "NIT must contain only digits");
62
- if (calcCheckDigit(v.slice(0, -1)) !== Number(v[v.length - 1])) return err("INVALID_CHECKSUM", "NIT check digit does not match");
51
+ if (calcCheckDigit(v.slice(0, -1)) !== Number(v.at(-1))) return err("INVALID_CHECKSUM", "NIT check digit does not match");
63
52
  return {
64
53
  valid: true,
65
54
  compact: v
@@ -85,6 +74,7 @@ const nit = {
85
74
  abbreviation: "NIT",
86
75
  aliases: ["NIT", "Número de Identificación Tributaria"],
87
76
  candidatePattern: "\\d{9,10}-?\\d",
77
+ scope: "country",
88
78
  country: "CO",
89
79
  entityType: "any",
90
80
  description: "Tax identifier issued by the DIAN",
@@ -1 +1 @@
1
- {"version":3,"file":"nit.js","names":[],"sources":["../../src/co/nit.ts"],"sourcesContent":["/**\n * NIT (Número de Identificación Tributaria).\n *\n * Colombian tax identification number, also known as\n * RUT (Registro Unico Tributario). The last digit is\n * a check digit computed via a weighted sum mod 11\n * with weights [3,7,13,17,19,23,29,37,41,43,47,53,\n * 59,67,71] applied right-to-left.\n *\n * @see https://es.wikipedia.org/wiki/Número_de_identificación_tributaria\n */\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nimport type { ValidateResult, Validator } from \"../types\";\n\nconst WEIGHTS = [\n 3, 7, 13, 17, 19, 23, 29, 37, 41, 43, 47, 53, 59, 67, 71,\n] as const;\n\n/** Lookup table: remainder -> check digit. */\nconst CHECK_DIGITS = [0, 1, 9, 8, 7, 6, 5, 4, 3, 2, 1];\n\nconst compact = (value: string): string =>\n clean(value, \" -.,\");\n\nconst calcCheckDigit = (body: string): number => {\n let sum = 0;\n const len = body.length;\n for (const [i, weight] of WEIGHTS.entries()) {\n if (i >= len) break;\n sum += Number(body[len - 1 - i]) * weight;\n }\n // SAFETY: sum % 11 is in 0..10 and CHECK_DIGITS has\n // 11 entries.\n // eslint-disable-next-line no-non-null-assertion\n return CHECK_DIGITS[sum % 11]!;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length < 8 || v.length > 16) {\n return err(\n \"INVALID_LENGTH\",\n \"NIT must be between 8 and 16 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"NIT must contain only digits\",\n );\n }\n\n const body = v.slice(0, -1);\n const check = calcCheckDigit(body);\n if (check !== Number(v[v.length - 1])) {\n return err(\n \"INVALID_CHECKSUM\",\n \"NIT check digit does not match\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n const body = v.slice(0, -1);\n const checkChar = v.slice(-1);\n const groups: string[] = [];\n for (let i = body.length; i > 0; i -= 3) {\n groups.unshift(body.slice(Math.max(0, i - 3), i));\n }\n return `${groups.join(\".\")}-${checkChar}`;\n};\n\n/** Generate a random valid NIT (10 digits). */\nconst generate = (): string => {\n const body = randomDigits(9);\n const check = calcCheckDigit(body);\n return `${body}${check}`;\n};\n\n/** Colombian tax identification number. */\nconst nit: Validator = {\n name: \"Número de Identificación Tributaria\",\n localName: \"Número de Identificación Tributaria\",\n abbreviation: \"NIT\",\n aliases: [\n \"NIT\",\n \"Número de Identificación Tributaria\",\n ] as const,\n candidatePattern: \"\\\\d{9,10}-?\\\\d\",\n country: \"CO\",\n entityType: \"any\",\n description: \"Tax identifier issued by the DIAN\",\n sourceUrl:\n \"https://es.wikipedia.org/wiki/N%C3%BAmero_de_identificaci%C3%B3n_tributaria\",\n lengths: [8, 9, 10, 11, 12, 13, 14, 15, 16] as const,\n examples: [\"2131234321\", \"8001234565\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default nit;\nexport { compact, format, generate, validate };\n"],"mappings":";;;;;;;;;;;;;;;;AAmBA,MAAM,UAAU;CACd;CAAG;CAAG;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CACvD;;AAGD,MAAM,eAAe;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAE;AAEtD,MAAM,WAAW,UACf,MAAM,OAAO,OAAO;AAEtB,MAAM,kBAAkB,SAAyB;CAC/C,IAAI,MAAM;CACV,MAAM,MAAM,KAAK;AACjB,MAAK,MAAM,CAAC,GAAG,WAAW,QAAQ,SAAS,EAAE;AAC3C,MAAI,KAAK,IAAK;AACd,SAAO,OAAO,KAAK,MAAM,IAAI,GAAG,GAAG;;AAKrC,QAAO,aAAa,MAAM;;AAG5B,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,MAAM;AACxB,KAAI,EAAE,SAAS,KAAK,EAAE,SAAS,GAC7B,QAAO,IACL,kBACA,sCACD;AAEH,KAAI,CAAC,SAAS,EAAE,CACd,QAAO,IACL,kBACA,+BACD;AAKH,KADc,eADD,EAAE,MAAM,GAAG,GAAG,CACO,KACpB,OAAO,EAAE,EAAE,SAAS,GAAG,CACnC,QAAO,IACL,oBACA,iCACD;AAGH,QAAO;EAAE,OAAO;EAAM,SAAS;EAAG;;AAGpC,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,MAAM;CACxB,MAAM,OAAO,EAAE,MAAM,GAAG,GAAG;CAC3B,MAAM,YAAY,EAAE,MAAM,GAAG;CAC7B,MAAM,SAAmB,EAAE;AAC3B,MAAK,IAAI,IAAI,KAAK,QAAQ,IAAI,GAAG,KAAK,EACpC,QAAO,QAAQ,KAAK,MAAM,KAAK,IAAI,GAAG,IAAI,EAAE,EAAE,EAAE,CAAC;AAEnD,QAAO,GAAG,OAAO,KAAK,IAAI,CAAC,GAAG;;;AAIhC,MAAM,iBAAyB;CAC7B,MAAM,OAAO,aAAa,EAAE;AAE5B,QAAO,GAAG,OADI,eAAe,KAAK;;;AAKpC,MAAM,MAAiB;CACrB,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CACP,OACA,sCACD;CACD,kBAAkB;CAClB,SAAS;CACT,YAAY;CACZ,aAAa;CACb,WACE;CACF,SAAS;EAAC;EAAG;EAAG;EAAI;EAAI;EAAI;EAAI;EAAI;EAAI;EAAG;CAC3C,UAAU,CAAC,cAAc,aAAa;CACtC;CACA;CACA;CACA;CACD"}
1
+ {"version":3,"file":"nit.js","names":[],"sources":["../../src/co/nit.ts"],"sourcesContent":["/**\n * NIT (Número de Identificación Tributaria).\n *\n * Colombian tax identification number, also known as\n * RUT (Registro Unico Tributario). The last digit is\n * a check digit computed via a weighted sum mod 11\n * with weights [3,7,13,17,19,23,29,37,41,43,47,53,\n * 59,67,71] applied right-to-left.\n *\n * @see https://es.wikipedia.org/wiki/Número_de_identificación_tributaria\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst WEIGHTS = [\n 3, 7, 13, 17, 19, 23, 29, 37, 41, 43, 47, 53, 59, 67, 71,\n] as const;\n\n/** Lookup table: remainder -> check digit. */\nconst CHECK_DIGITS = [0, 1, 9, 8, 7, 6, 5, 4, 3, 2, 1];\n\nconst compact = (value: string): string =>\n clean(value, \" -.,\");\n\nconst calcCheckDigit = (body: string): number => {\n let sum = 0;\n const len = body.length;\n for (const [i, weight] of WEIGHTS.entries()) {\n if (i >= len) break;\n sum += Number(body[len - 1 - i]) * weight;\n }\n // SAFETY: sum % 11 is in 0..10 and CHECK_DIGITS has\n // 11 entries.\n // eslint-disable-next-line no-non-null-assertion\n return CHECK_DIGITS[sum % 11]!;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length < 8 || v.length > 16) {\n return err(\n \"INVALID_LENGTH\",\n \"NIT must be between 8 and 16 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"NIT must contain only digits\",\n );\n }\n\n const body = v.slice(0, -1);\n const check = calcCheckDigit(body);\n if (check !== Number(v.at(-1))) {\n return err(\n \"INVALID_CHECKSUM\",\n \"NIT check digit does not match\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n const body = v.slice(0, -1);\n const checkChar = v.slice(-1);\n const groups: string[] = [];\n for (let i = body.length; i > 0; i -= 3) {\n groups.unshift(body.slice(Math.max(0, i - 3), i));\n }\n return `${groups.join(\".\")}-${checkChar}`;\n};\n\n/** Generate a random valid NIT (10 digits). */\nconst generate = (): string => {\n const body = randomDigits(9);\n const check = calcCheckDigit(body);\n return `${body}${check}`;\n};\n\n/** Colombian tax identification number. */\nconst nit: CountryValidator<\"CO\"> = {\n name: \"Número de Identificación Tributaria\",\n localName: \"Número de Identificación Tributaria\",\n abbreviation: \"NIT\",\n aliases: [\n \"NIT\",\n \"Número de Identificación Tributaria\",\n ] as const,\n candidatePattern: \"\\\\d{9,10}-?\\\\d\",\n scope: \"country\",\n country: \"CO\",\n entityType: \"any\",\n description: \"Tax identifier issued by the DIAN\",\n sourceUrl:\n \"https://es.wikipedia.org/wiki/N%C3%BAmero_de_identificaci%C3%B3n_tributaria\",\n lengths: [8, 9, 10, 11, 12, 13, 14, 15, 16] as const,\n examples: [\"2131234321\", \"8001234565\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default nit;\nexport { compact, format, generate, validate };\n"],"mappings":";;;;;AAsBA,MAAM,UAAU;CACd;CAAG;CAAG;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;AACxD;;AAGA,MAAM,eAAe;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AAErD,MAAM,WAAW,UACf,MAAM,OAAO,MAAM;AAErB,MAAM,kBAAkB,SAAyB;CAC/C,IAAI,MAAM;CACV,MAAM,MAAM,KAAK;CACjB,KAAK,MAAM,CAAC,GAAG,WAAW,QAAQ,QAAQ,GAAG;EAC3C,IAAI,KAAK,KAAK;EACd,OAAO,OAAO,KAAK,MAAM,IAAI,EAAE,IAAI;CACrC;CAIA,OAAO,aAAa,MAAM;AAC5B;AAEA,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,SAAS,KAAK,EAAE,SAAS,IAC7B,OAAO,IACL,kBACA,qCACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,8BACF;CAKF,IADc,eADD,EAAE,MAAM,GAAG,EACQ,CACxB,MAAM,OAAO,EAAE,GAAG,EAAE,CAAC,GAC3B,OAAO,IACL,oBACA,gCACF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,KAAK;CACvB,MAAM,OAAO,EAAE,MAAM,GAAG,EAAE;CAC1B,MAAM,YAAY,EAAE,MAAM,EAAE;CAC5B,MAAM,SAAmB,CAAC;CAC1B,KAAK,IAAI,IAAI,KAAK,QAAQ,IAAI,GAAG,KAAK,GACpC,OAAO,QAAQ,KAAK,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;CAElD,OAAO,GAAG,OAAO,KAAK,GAAG,EAAE,GAAG;AAChC;;AAGA,MAAM,iBAAyB;CAC7B,MAAM,OAAO,aAAa,CAAC;CAE3B,OAAO,GAAG,OADI,eAAe,IACR;AACvB;;AAGA,MAAM,MAA8B;CAClC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CACP,OACA,qCACF;CACA,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,aAAa;CACb,WACE;CACF,SAAS;EAAC;EAAG;EAAG;EAAI;EAAI;EAAI;EAAI;EAAI;EAAI;CAAE;CAC1C,UAAU,CAAC,cAAc,YAAY;CACrC;CACA;CACA;CACA;AACF"}
package/dist/cr/cpf.d.ts CHANGED
@@ -1,8 +1,24 @@
1
- import { ValidateResult, Validator } from "../types.js";
1
+ import { CountryValidator, ValidateResult } from "../types.js";
2
2
 
3
3
  //#region src/cr/cpf.d.ts
4
4
  /** Generate a random valid Costa Rican CPF. */
5
5
  declare const generate: () => string;
6
+ /**
7
+ * CPF (Cédula de Persona Física, Costa Rican
8
+ * physical person ID number).
9
+ *
10
+ * 10 digits: 0P-TTTT-AAAA where:
11
+ * - 0 = fixed leading zero
12
+ * - P = province digit
13
+ * - TTTT = volume (tomo), zero-padded
14
+ * - AAAA = entry (asiento), zero-padded
15
+ *
16
+ * No check digit; validation is by format only.
17
+ *
18
+ * Ported from python-stdnum cr.cpf module.
19
+ *
20
+ * @see https://www.tse.go.cr/
21
+ */
6
22
  /**
7
23
  * Compact: strip spaces, pad hyphen-separated parts
8
24
  * (2-4-4), join, and prepend '0' if 9 digits.
@@ -15,7 +31,7 @@ declare const format: (value: string) => string;
15
31
  *
16
32
  * Examples sourced from python-stdnum test suite.
17
33
  */
18
- declare const cpf: Validator;
34
+ declare const cpf: CountryValidator<"CR">;
19
35
  //#endregion
20
36
  export { compact, cpf as default, format, generate, validate };
21
37
  //# sourceMappingURL=cpf.d.ts.map
package/dist/cr/cpf.js CHANGED
@@ -2,22 +2,6 @@ import { clean } from "../_util/clean.js";
2
2
  import { randomDigits, randomInt } from "../_util/generate.js";
3
3
  import { err } from "../_util/result.js";
4
4
  //#region src/cr/cpf.ts
5
- /**
6
- * CPF (Cédula de Persona Física, Costa Rican
7
- * physical person ID number).
8
- *
9
- * 10 digits: 0P-TTTT-AAAA where:
10
- * - 0 = fixed leading zero
11
- * - P = province digit
12
- * - TTTT = volume (tomo), zero-padded
13
- * - AAAA = entry (asiento), zero-padded
14
- *
15
- * No check digit; validation is by format only.
16
- *
17
- * Ported from python-stdnum cr.cpf module.
18
- *
19
- * @see https://www.tse.go.cr/
20
- */
21
5
  /** Generate a random valid Costa Rican CPF. */
22
6
  const generate = () => {
23
7
  return `0${String(randomInt(1, 9))}${randomDigits(4)}${randomDigits(4)}`;
@@ -64,6 +48,7 @@ const cpf = {
64
48
  abbreviation: "CPF",
65
49
  aliases: ["CPF", "cédula de persona física"],
66
50
  candidatePattern: "\\d{9,12}",
51
+ scope: "country",
67
52
  country: "CR",
68
53
  entityType: "person",
69
54
  lengths: [10],
@@ -1 +1 @@
1
- {"version":3,"file":"cpf.js","names":[],"sources":["../../src/cr/cpf.ts"],"sourcesContent":["/** Generate a random valid Costa Rican CPF. */\nconst generate = (): string => {\n const province = String(randomInt(1, 9));\n const volume = randomDigits(4);\n const entry = randomDigits(4);\n return `0${province}${volume}${entry}`;\n};\n\n/**\n * CPF (Cédula de Persona Física, Costa Rican\n * physical person ID number).\n *\n * 10 digits: 0P-TTTT-AAAA where:\n * - 0 = fixed leading zero\n * - P = province digit\n * - TTTT = volume (tomo), zero-padded\n * - AAAA = entry (asiento), zero-padded\n *\n * No check digit; validation is by format only.\n *\n * Ported from python-stdnum cr.cpf module.\n *\n * @see https://www.tse.go.cr/\n */\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits, randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\n\nimport type { ValidateResult, Validator } from \"../types\";\n\n/**\n * Compact: strip spaces, pad hyphen-separated parts\n * (2-4-4), join, and prepend '0' if 9 digits.\n */\nconst compact = (value: string): string => {\n let number = clean(value, \" \").trim().toUpperCase();\n\n const parts = number.split(\"-\");\n if (parts.length === 3) {\n const [raw0, raw1, raw2] = parts;\n const p0 = (raw0 ?? \"\").padStart(2, \"0\");\n const p1 = (raw1 ?? \"\").padStart(4, \"0\");\n const p2 = (raw2 ?? \"\").padStart(4, \"0\");\n number = p0 + p1 + p2;\n } else {\n number = number.replaceAll(\"-\", \"\");\n }\n\n if (number.length === 9) {\n number = \"0\" + number;\n }\n\n return number;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 10) {\n return err(\n \"INVALID_LENGTH\",\n \"Costa Rican CPF must be 10 digits\",\n );\n }\n\n if (!/^\\d{10}$/.test(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"Costa Rican CPF must contain only digits\",\n );\n }\n\n if (v[0] !== \"0\") {\n return err(\n \"INVALID_COMPONENT\",\n \"Costa Rican CPF must start with 0\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n return `${v.slice(0, 2)}-${v.slice(2, 6)}-${v.slice(6, 10)}`;\n};\n\n/**\n * Costa Rican physical person ID number (CPF).\n *\n * Examples sourced from python-stdnum test suite.\n */\nconst cpf: Validator = {\n name: \"Costa Rican Physical Person ID\",\n localName: \"Cédula de Persona Física\",\n abbreviation: \"CPF\",\n aliases: [\"CPF\", \"cédula de persona física\"] as const,\n candidatePattern: \"\\\\d{9,12}\",\n country: \"CR\",\n entityType: \"person\",\n lengths: [10] as const,\n examples: [\"0304550175\", \"0109130259\"] as const,\n compact,\n format,\n validate,\n sourceUrl: \"https://www.tse.go.cr/\",\n generate,\n};\n\nexport default cpf;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AACA,MAAM,iBAAyB;AAI7B,QAAO,IAHU,OAAO,UAAU,GAAG,EAAE,CAAC,GACzB,aAAa,EAAE,GAChB,aAAa,EAAE;;;;;;AA+B/B,MAAM,WAAW,UAA0B;CACzC,IAAI,SAAS,MAAM,OAAO,IAAI,CAAC,MAAM,CAAC,aAAa;CAEnD,MAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,KAAI,MAAM,WAAW,GAAG;EACtB,MAAM,CAAC,MAAM,MAAM,QAAQ;EAC3B,MAAM,MAAM,QAAQ,IAAI,SAAS,GAAG,IAAI;EACxC,MAAM,MAAM,QAAQ,IAAI,SAAS,GAAG,IAAI;EACxC,MAAM,MAAM,QAAQ,IAAI,SAAS,GAAG,IAAI;AACxC,WAAS,KAAK,KAAK;OAEnB,UAAS,OAAO,WAAW,KAAK,GAAG;AAGrC,KAAI,OAAO,WAAW,EACpB,UAAS,MAAM;AAGjB,QAAO;;AAGT,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,MAAM;AAExB,KAAI,EAAE,WAAW,GACf,QAAO,IACL,kBACA,oCACD;AAGH,KAAI,CAAC,WAAW,KAAK,EAAE,CACrB,QAAO,IACL,kBACA,2CACD;AAGH,KAAI,EAAE,OAAO,IACX,QAAO,IACL,qBACA,oCACD;AAGH,QAAO;EAAE,OAAO;EAAM,SAAS;EAAG;;AAGpC,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,MAAM;AACxB,QAAO,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG;;;;;;;AAQ5D,MAAM,MAAiB;CACrB,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,OAAO,2BAA2B;CAC5C,kBAAkB;CAClB,SAAS;CACT,YAAY;CACZ,SAAS,CAAC,GAAG;CACb,UAAU,CAAC,cAAc,aAAa;CACtC;CACA;CACA;CACA,WAAW;CACX;CACD"}
1
+ {"version":3,"file":"cpf.js","names":[],"sources":["../../src/cr/cpf.ts"],"sourcesContent":["/** Generate a random valid Costa Rican CPF. */\nconst generate = (): string => {\n const province = String(randomInt(1, 9));\n const volume = randomDigits(4);\n const entry = randomDigits(4);\n return `0${province}${volume}${entry}`;\n};\n\n/**\n * CPF (Cédula de Persona Física, Costa Rican\n * physical person ID number).\n *\n * 10 digits: 0P-TTTT-AAAA where:\n * - 0 = fixed leading zero\n * - P = province digit\n * - TTTT = volume (tomo), zero-padded\n * - AAAA = entry (asiento), zero-padded\n *\n * No check digit; validation is by format only.\n *\n * Ported from python-stdnum cr.cpf module.\n *\n * @see https://www.tse.go.cr/\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits, randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\n\n/**\n * Compact: strip spaces, pad hyphen-separated parts\n * (2-4-4), join, and prepend '0' if 9 digits.\n */\nconst compact = (value: string): string => {\n let number = clean(value, \" \").trim().toUpperCase();\n\n const parts = number.split(\"-\");\n if (parts.length === 3) {\n const [raw0, raw1, raw2] = parts;\n const p0 = (raw0 ?? \"\").padStart(2, \"0\");\n const p1 = (raw1 ?? \"\").padStart(4, \"0\");\n const p2 = (raw2 ?? \"\").padStart(4, \"0\");\n number = p0 + p1 + p2;\n } else {\n number = number.replaceAll(\"-\", \"\");\n }\n\n if (number.length === 9) {\n number = \"0\" + number;\n }\n\n return number;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 10) {\n return err(\n \"INVALID_LENGTH\",\n \"Costa Rican CPF must be 10 digits\",\n );\n }\n\n if (!/^\\d{10}$/.test(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"Costa Rican CPF must contain only digits\",\n );\n }\n\n if (v[0] !== \"0\") {\n return err(\n \"INVALID_COMPONENT\",\n \"Costa Rican CPF must start with 0\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n return `${v.slice(0, 2)}-${v.slice(2, 6)}-${v.slice(6, 10)}`;\n};\n\n/**\n * Costa Rican physical person ID number (CPF).\n *\n * Examples sourced from python-stdnum test suite.\n */\nconst cpf: CountryValidator<\"CR\"> = {\n name: \"Costa Rican Physical Person ID\",\n localName: \"Cédula de Persona Física\",\n abbreviation: \"CPF\",\n aliases: [\"CPF\", \"cédula de persona física\"] as const,\n candidatePattern: \"\\\\d{9,12}\",\n scope: \"country\",\n country: \"CR\",\n entityType: \"person\",\n lengths: [10] as const,\n examples: [\"0304550175\", \"0109130259\"] as const,\n compact,\n format,\n validate,\n sourceUrl: \"https://www.tse.go.cr/\",\n generate,\n};\n\nexport default cpf;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;AACA,MAAM,iBAAyB;CAI7B,OAAO,IAHU,OAAO,UAAU,GAAG,CAAC,CAGpB,IAFH,aAAa,CAED,IADb,aAAa,CACQ;AACrC;;;;;AAgCA,MAAM,WAAW,UAA0B;CACzC,IAAI,SAAS,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,YAAY;CAElD,MAAM,QAAQ,OAAO,MAAM,GAAG;CAC9B,IAAI,MAAM,WAAW,GAAG;EACtB,MAAM,CAAC,MAAM,MAAM,QAAQ;EAC3B,MAAM,MAAM,QAAQ,IAAI,SAAS,GAAG,GAAG;EACvC,MAAM,MAAM,QAAQ,IAAI,SAAS,GAAG,GAAG;EACvC,MAAM,MAAM,QAAQ,IAAI,SAAS,GAAG,GAAG;EACvC,SAAS,KAAK,KAAK;CACrB,OACE,SAAS,OAAO,WAAW,KAAK,EAAE;CAGpC,IAAI,OAAO,WAAW,GACpB,SAAS,MAAM;CAGjB,OAAO;AACT;AAEA,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CAEvB,IAAI,EAAE,WAAW,IACf,OAAO,IACL,kBACA,mCACF;CAGF,IAAI,CAAC,WAAW,KAAK,CAAC,GACpB,OAAO,IACL,kBACA,0CACF;CAGF,IAAI,EAAE,OAAO,KACX,OAAO,IACL,qBACA,mCACF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,KAAK;CACvB,OAAO,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,EAAE;AAC3D;;;;;;AAOA,MAAM,MAA8B;CAClC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,OAAO,0BAA0B;CAC3C,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,SAAS,CAAC,EAAE;CACZ,UAAU,CAAC,cAAc,YAAY;CACrC;CACA;CACA;CACA,WAAW;CACX;AACF"}
@@ -1,4 +1,4 @@
1
- import { ValidateResult, Validator } from "./types.js";
1
+ import { GlobalValidator, ValidateResult } from "./types.js";
2
2
 
3
3
  //#region src/creditcard.d.ts
4
4
  /**
@@ -18,7 +18,7 @@ declare const format: (value: string) => string;
18
18
  */
19
19
  declare const detectNetwork: (value: string) => CardNetwork | null;
20
20
  /** Credit Card Number (Luhn). */
21
- declare const creditCard: Validator;
21
+ declare const creditCard: GlobalValidator;
22
22
  //#endregion
23
23
  export { type CardNetwork, compact, creditCard as default, detectNetwork, format, validate };
24
24
  //# sourceMappingURL=creditcard.d.ts.map
@@ -1,19 +1,9 @@
1
+ import { luhnChecksum, luhnValidate } from "./_checksums/luhn.js";
1
2
  import { clean } from "./_util/clean.js";
2
3
  import { randomDigits, randomInt } from "./_util/generate.js";
3
4
  import { err } from "./_util/result.js";
4
- import { luhnChecksum, luhnValidate } from "./_checksums/luhn.js";
5
5
  import { isdigits } from "./_util/strings.js";
6
6
  //#region src/creditcard.ts
7
- /**
8
- * Credit card number validation (Luhn algorithm).
9
- *
10
- * Validates card numbers using the Luhn checksum
11
- * (ISO/IEC 7812-1). Supports Visa, Mastercard,
12
- * Amex, Discover, and other networks (13-19
13
- * digits).
14
- *
15
- * @see https://www.iso.org/standard/70484.html
16
- */
17
7
  const compact = (value) => clean(value, " -.");
18
8
  const validate = (value) => {
19
9
  const v = compact(value);
@@ -32,7 +22,7 @@ const format = (value) => {
32
22
  for (let i = 0; i < v.length; i += 4) groups.push(v.slice(i, i + 4));
33
23
  return groups.join(" ");
34
24
  };
35
- const MAESTRO_PREFIXES = [
25
+ const MAESTRO_PREFIXES = new Set([
36
26
  5018,
37
27
  5020,
38
28
  5038,
@@ -42,7 +32,7 @@ const MAESTRO_PREFIXES = [
42
32
  6761,
43
33
  6762,
44
34
  6763
45
- ];
35
+ ]);
46
36
  /**
47
37
  * Detect the card network from the BIN/IIN prefix.
48
38
  *
@@ -63,7 +53,7 @@ const detectNetwork = (value) => {
63
53
  if (d3 >= 300 && d3 <= 305) return "diners";
64
54
  if (d4 >= 3528 && d4 <= 3589) return "jcb";
65
55
  if (v[0] === "4") return "visa";
66
- if (MAESTRO_PREFIXES.includes(d4)) return "maestro";
56
+ if (MAESTRO_PREFIXES.has(d4)) return "maestro";
67
57
  if (d2 >= 51 && d2 <= 55) return "mastercard";
68
58
  if (d4 >= 2221 && d4 <= 2720) return "mastercard";
69
59
  if (d4 === 6011) return "discover";
@@ -97,6 +87,7 @@ const generate = () => {
97
87
  };
98
88
  /** Credit Card Number (Luhn). */
99
89
  const creditCard = {
90
+ scope: "global",
100
91
  name: "Credit Card Number",
101
92
  localName: "Credit Card Number",
102
93
  abbreviation: "CC",
@@ -1 +1 @@
1
- {"version":3,"file":"creditcard.js","names":[],"sources":["../src/creditcard.ts"],"sourcesContent":["/**\n * Credit card number validation (Luhn algorithm).\n *\n * Validates card numbers using the Luhn checksum\n * (ISO/IEC 7812-1). Supports Visa, Mastercard,\n * Amex, Discover, and other networks (13-19\n * digits).\n *\n * @see https://www.iso.org/standard/70484.html\n */\n\nimport {\n luhnChecksum,\n luhnValidate,\n} from \"#checksums/luhn\";\nimport { clean } from \"#util/clean\";\nimport { randomDigits, randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nimport type { ValidateResult, Validator } from \"./types\";\n\n/**\n * Card network identifiers returned by\n * {@link detectNetwork}.\n */\ntype CardNetwork =\n | \"visa\"\n | \"mastercard\"\n | \"amex\"\n | \"discover\"\n | \"diners\"\n | \"jcb\"\n | \"unionpay\"\n | \"maestro\";\n\nconst compact = (value: string): string =>\n clean(value, \" -.\");\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length < 13 || v.length > 19) {\n return err(\n \"INVALID_LENGTH\",\n \"Credit card number must be 13-19 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"Credit card number must contain only digits\",\n );\n }\n if (!luhnValidate(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Credit card number fails Luhn check\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n // Amex: 4-6-5 grouping\n if (v.length === 15 && v[0] === \"3\") {\n return `${v.slice(0, 4)} ${v.slice(4, 10)} ${v.slice(10)}`;\n }\n // Standard: groups of 4\n const groups: string[] = [];\n for (let i = 0; i < v.length; i += 4) {\n groups.push(v.slice(i, i + 4));\n }\n return groups.join(\" \");\n};\n\nconst MAESTRO_PREFIXES: readonly number[] = [\n 5018, 5020, 5038, 5893, 6304, 6759, 6761, 6762, 6763,\n];\n\n/**\n * Detect the card network from the BIN/IIN prefix.\n *\n * Accepts both formatted (\"4111 1111 1111 1111\")\n * and compact (\"4111111111111111\") inputs.\n * Returns null for unrecognized prefixes.\n */\nconst detectNetwork = (\n value: string,\n): CardNetwork | null => {\n const v = compact(value);\n if (v.length === 0) return null;\n if (!isdigits(v)) return null;\n\n const d2 = Number(v.slice(0, 2));\n const d3 = Number(v.slice(0, 3));\n const d4 = Number(v.slice(0, 4));\n const d6 = Number(v.slice(0, 6));\n\n // Amex: 34, 37\n if (d2 === 34 || d2 === 37) return \"amex\";\n\n // Diners Club: 300-305, 36, 38\n if (d2 === 36 || d2 === 38) return \"diners\";\n if (d3 >= 300 && d3 <= 305) return \"diners\";\n\n // JCB: 3528-3589\n if (d4 >= 3528 && d4 <= 3589) return \"jcb\";\n\n // Visa: starts with 4\n if (v[0] === \"4\") return \"visa\";\n\n // Maestro (check before Mastercard; some share\n // the 50xx prefix space)\n if (MAESTRO_PREFIXES.includes(d4)) return \"maestro\";\n\n // Mastercard: 51-55 or 2221-2720\n if (d2 >= 51 && d2 <= 55) return \"mastercard\";\n if (d4 >= 2221 && d4 <= 2720) return \"mastercard\";\n\n // Discover: 6011, 622126-622925, 644-649, 65\n if (d4 === 6011) return \"discover\";\n if (d6 >= 622126 && d6 <= 622925) return \"discover\";\n if (d3 >= 644 && d3 <= 649) return \"discover\";\n if (d2 === 65) return \"discover\";\n\n // UnionPay: starts with 62 (excluding Discover\n // ranges already matched above)\n if (d2 === 62) return \"unionpay\";\n\n return null;\n};\n\n/**\n * Visa/Mastercard IIN prefixes. Each entry is\n * [prefix, totalLength].\n */\nconst CARD_PREFIXES = [\n [\"4\", 16], // Visa\n [\"51\", 16], // Mastercard\n [\"52\", 16], // Mastercard\n [\"53\", 16], // Mastercard\n [\"54\", 16], // Mastercard\n [\"55\", 16], // Mastercard\n] as const;\n\n/**\n * Generate a random valid Visa or Mastercard\n * number (16 digits, Luhn-valid).\n */\nconst generate = (): string => {\n const idx = randomInt(0, CARD_PREFIXES.length - 1);\n const [prefix, length] = CARD_PREFIXES[\n idx\n ] as (typeof CARD_PREFIXES)[number];\n const remaining = length - prefix.length - 1;\n const payload = `${prefix}${randomDigits(remaining)}`;\n const partial = `${payload}0`;\n const remainder = luhnChecksum(partial);\n const check = (10 - remainder) % 10;\n return `${payload}${String(check)}`;\n};\n\n/** Credit Card Number (Luhn). */\nconst creditCard: Validator = {\n name: \"Credit Card Number\",\n localName: \"Credit Card Number\",\n abbreviation: \"CC\",\n aliases: [\n \"credit card\",\n \"card number\",\n \"kreditní karta\",\n \"Kreditkarte\",\n ] as const,\n candidatePattern: \"(?:\\\\d[\\\\s-]?){13,19}\",\n entityType: \"any\",\n sourceUrl: \"https://www.iso.org/standard/70484.html\",\n examples: [\n \"4111111111111111\",\n \"5500000000000004\",\n ] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default creditCard;\nexport { compact, detectNetwork, format, validate };\nexport type { CardNetwork };\n"],"mappings":";;;;;;;;;;;;;;;;AAoCA,MAAM,WAAW,UACf,MAAM,OAAO,MAAM;AAErB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,MAAM;AACxB,KAAI,EAAE,SAAS,MAAM,EAAE,SAAS,GAC9B,QAAO,IACL,kBACA,0CACD;AAEH,KAAI,CAAC,SAAS,EAAE,CACd,QAAO,IACL,kBACA,8CACD;AAEH,KAAI,CAAC,aAAa,EAAE,CAClB,QAAO,IACL,oBACA,sCACD;AAEH,QAAO;EAAE,OAAO;EAAM,SAAS;EAAG;;AAGpC,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,MAAM;AAExB,KAAI,EAAE,WAAW,MAAM,EAAE,OAAO,IAC9B,QAAO,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG;CAG1D,MAAM,SAAmB,EAAE;AAC3B,MAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK,EACjC,QAAO,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,CAAC;AAEhC,QAAO,OAAO,KAAK,IAAI;;AAGzB,MAAM,mBAAsC;CAC1C;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CACjD;;;;;;;;AASD,MAAM,iBACJ,UACuB;CACvB,MAAM,IAAI,QAAQ,MAAM;AACxB,KAAI,EAAE,WAAW,EAAG,QAAO;AAC3B,KAAI,CAAC,SAAS,EAAE,CAAE,QAAO;CAEzB,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;CAChC,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;CAChC,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;CAChC,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;AAGhC,KAAI,OAAO,MAAM,OAAO,GAAI,QAAO;AAGnC,KAAI,OAAO,MAAM,OAAO,GAAI,QAAO;AACnC,KAAI,MAAM,OAAO,MAAM,IAAK,QAAO;AAGnC,KAAI,MAAM,QAAQ,MAAM,KAAM,QAAO;AAGrC,KAAI,EAAE,OAAO,IAAK,QAAO;AAIzB,KAAI,iBAAiB,SAAS,GAAG,CAAE,QAAO;AAG1C,KAAI,MAAM,MAAM,MAAM,GAAI,QAAO;AACjC,KAAI,MAAM,QAAQ,MAAM,KAAM,QAAO;AAGrC,KAAI,OAAO,KAAM,QAAO;AACxB,KAAI,MAAM,UAAU,MAAM,OAAQ,QAAO;AACzC,KAAI,MAAM,OAAO,MAAM,IAAK,QAAO;AACnC,KAAI,OAAO,GAAI,QAAO;AAItB,KAAI,OAAO,GAAI,QAAO;AAEtB,QAAO;;;;;;AAOT,MAAM,gBAAgB;CACpB,CAAC,KAAK,GAAG;CACT,CAAC,MAAM,GAAG;CACV,CAAC,MAAM,GAAG;CACV,CAAC,MAAM,GAAG;CACV,CAAC,MAAM,GAAG;CACV,CAAC,MAAM,GAAG;CACX;;;;;AAMD,MAAM,iBAAyB;CAE7B,MAAM,CAAC,QAAQ,UAAU,cADb,UAAU,GAAG,cAAc,SAAS,EAAE;CAKlD,MAAM,UAAU,GAAG,SAAS,aADV,SAAS,OAAO,SAAS,EACQ;CAGnD,MAAM,SAAS,KADG,aADF,GAAG,QAAQ,GACY,IACN;AACjC,QAAO,GAAG,UAAU,OAAO,MAAM;;;AAInC,MAAM,aAAwB;CAC5B,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS;EACP;EACA;EACA;EACA;EACD;CACD,kBAAkB;CAClB,YAAY;CACZ,WAAW;CACX,UAAU,CACR,oBACA,mBACD;CACD;CACA;CACA;CACA;CACD"}
1
+ {"version":3,"file":"creditcard.js","names":[],"sources":["../src/creditcard.ts"],"sourcesContent":["/**\n * Credit card number validation (Luhn algorithm).\n *\n * Validates card numbers using the Luhn checksum\n * (ISO/IEC 7812-1). Supports Visa, Mastercard,\n * Amex, Discover, and other networks (13-19\n * digits).\n *\n * @see https://www.iso.org/standard/70484.html\n */\n\nimport type {\n ValidateResult,\n GlobalValidator,\n} from \"./types\";\n\nimport {\n luhnChecksum,\n luhnValidate,\n} from \"#checksums/luhn\";\nimport { clean } from \"#util/clean\";\nimport { randomDigits, randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\n/**\n * Card network identifiers returned by\n * {@link detectNetwork}.\n */\ntype CardNetwork =\n | \"visa\"\n | \"mastercard\"\n | \"amex\"\n | \"discover\"\n | \"diners\"\n | \"jcb\"\n | \"unionpay\"\n | \"maestro\";\n\nconst compact = (value: string): string =>\n clean(value, \" -.\");\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length < 13 || v.length > 19) {\n return err(\n \"INVALID_LENGTH\",\n \"Credit card number must be 13-19 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"Credit card number must contain only digits\",\n );\n }\n if (!luhnValidate(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Credit card number fails Luhn check\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n // Amex: 4-6-5 grouping\n if (v.length === 15 && v[0] === \"3\") {\n return `${v.slice(0, 4)} ${v.slice(4, 10)} ${v.slice(10)}`;\n }\n // Standard: groups of 4\n const groups: string[] = [];\n for (let i = 0; i < v.length; i += 4) {\n groups.push(v.slice(i, i + 4));\n }\n return groups.join(\" \");\n};\n\nconst MAESTRO_PREFIXES = new Set([\n 5018, 5020, 5038, 5893, 6304, 6759, 6761, 6762, 6763,\n]);\n\n/**\n * Detect the card network from the BIN/IIN prefix.\n *\n * Accepts both formatted (\"4111 1111 1111 1111\")\n * and compact (\"4111111111111111\") inputs.\n * Returns null for unrecognized prefixes.\n */\nconst detectNetwork = (\n value: string,\n): CardNetwork | null => {\n const v = compact(value);\n if (v.length === 0) return null;\n if (!isdigits(v)) return null;\n\n const d2 = Number(v.slice(0, 2));\n const d3 = Number(v.slice(0, 3));\n const d4 = Number(v.slice(0, 4));\n const d6 = Number(v.slice(0, 6));\n\n // Amex: 34, 37\n if (d2 === 34 || d2 === 37) return \"amex\";\n\n // Diners Club: 300-305, 36, 38\n if (d2 === 36 || d2 === 38) return \"diners\";\n if (d3 >= 300 && d3 <= 305) return \"diners\";\n\n // JCB: 3528-3589\n if (d4 >= 3528 && d4 <= 3589) return \"jcb\";\n\n // Visa: starts with 4\n if (v[0] === \"4\") return \"visa\";\n\n // Maestro (check before Mastercard; some share\n // the 50xx prefix space)\n if (MAESTRO_PREFIXES.has(d4)) return \"maestro\";\n\n // Mastercard: 51-55 or 2221-2720\n if (d2 >= 51 && d2 <= 55) return \"mastercard\";\n if (d4 >= 2221 && d4 <= 2720) return \"mastercard\";\n\n // Discover: 6011, 622126-622925, 644-649, 65\n if (d4 === 6011) return \"discover\";\n if (d6 >= 622126 && d6 <= 622925) return \"discover\";\n if (d3 >= 644 && d3 <= 649) return \"discover\";\n if (d2 === 65) return \"discover\";\n\n // UnionPay: starts with 62 (excluding Discover\n // ranges already matched above)\n if (d2 === 62) return \"unionpay\";\n\n return null;\n};\n\n/**\n * Visa/Mastercard IIN prefixes. Each entry is\n * [prefix, totalLength].\n */\nconst CARD_PREFIXES = [\n [\"4\", 16], // Visa\n [\"51\", 16], // Mastercard\n [\"52\", 16], // Mastercard\n [\"53\", 16], // Mastercard\n [\"54\", 16], // Mastercard\n [\"55\", 16], // Mastercard\n] as const;\n\n/**\n * Generate a random valid Visa or Mastercard\n * number (16 digits, Luhn-valid).\n */\nconst generate = (): string => {\n const idx = randomInt(0, CARD_PREFIXES.length - 1);\n const [prefix, length] = CARD_PREFIXES[\n idx\n ] as (typeof CARD_PREFIXES)[number];\n const remaining = length - prefix.length - 1;\n const payload = `${prefix}${randomDigits(remaining)}`;\n const partial = `${payload}0`;\n const remainder = luhnChecksum(partial);\n const check = (10 - remainder) % 10;\n return `${payload}${String(check)}`;\n};\n\n/** Credit Card Number (Luhn). */\nconst creditCard: GlobalValidator = {\n scope: \"global\",\n name: \"Credit Card Number\",\n localName: \"Credit Card Number\",\n abbreviation: \"CC\",\n aliases: [\n \"credit card\",\n \"card number\",\n \"kreditní karta\",\n \"Kreditkarte\",\n ] as const,\n candidatePattern: \"(?:\\\\d[\\\\s-]?){13,19}\",\n entityType: \"any\",\n sourceUrl: \"https://www.iso.org/standard/70484.html\",\n examples: [\n \"4111111111111111\",\n \"5500000000000004\",\n ] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default creditCard;\nexport { compact, detectNetwork, format, validate };\nexport type { CardNetwork };\n"],"mappings":";;;;;;AAuCA,MAAM,WAAW,UACf,MAAM,OAAO,KAAK;AAEpB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,SAAS,MAAM,EAAE,SAAS,IAC9B,OAAO,IACL,kBACA,yCACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,6CACF;CAEF,IAAI,CAAC,aAAa,CAAC,GACjB,OAAO,IACL,oBACA,qCACF;CAEF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,KAAK;CAEvB,IAAI,EAAE,WAAW,MAAM,EAAE,OAAO,KAC9B,OAAO,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE;CAGzD,MAAM,SAAmB,CAAC;CAC1B,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK,GACjC,OAAO,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;CAE/B,OAAO,OAAO,KAAK,GAAG;AACxB;AAEA,MAAM,mBAAmB,IAAI,IAAI;CAC/B;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;AAClD,CAAC;;;;;;;;AASD,MAAM,iBACJ,UACuB;CACvB,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,GAAG,OAAO;CAC3B,IAAI,CAAC,SAAS,CAAC,GAAG,OAAO;CAEzB,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/B,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/B,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/B,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAG/B,IAAI,OAAO,MAAM,OAAO,IAAI,OAAO;CAGnC,IAAI,OAAO,MAAM,OAAO,IAAI,OAAO;CACnC,IAAI,MAAM,OAAO,MAAM,KAAK,OAAO;CAGnC,IAAI,MAAM,QAAQ,MAAM,MAAM,OAAO;CAGrC,IAAI,EAAE,OAAO,KAAK,OAAO;CAIzB,IAAI,iBAAiB,IAAI,EAAE,GAAG,OAAO;CAGrC,IAAI,MAAM,MAAM,MAAM,IAAI,OAAO;CACjC,IAAI,MAAM,QAAQ,MAAM,MAAM,OAAO;CAGrC,IAAI,OAAO,MAAM,OAAO;CACxB,IAAI,MAAM,UAAU,MAAM,QAAQ,OAAO;CACzC,IAAI,MAAM,OAAO,MAAM,KAAK,OAAO;CACnC,IAAI,OAAO,IAAI,OAAO;CAItB,IAAI,OAAO,IAAI,OAAO;CAEtB,OAAO;AACT;;;;;AAMA,MAAM,gBAAgB;CACpB,CAAC,KAAK,EAAE;CACR,CAAC,MAAM,EAAE;CACT,CAAC,MAAM,EAAE;CACT,CAAC,MAAM,EAAE;CACT,CAAC,MAAM,EAAE;CACT,CAAC,MAAM,EAAE;AACX;;;;;AAMA,MAAM,iBAAyB;CAE7B,MAAM,CAAC,QAAQ,UAAU,cADb,UAAU,GAAG,cAAc,SAAS,CAE5C;CAGJ,MAAM,UAAU,GAAG,SAAS,aADV,SAAS,OAAO,SAAS,CACO;CAGlD,MAAM,SAAS,KADG,aAAa,GADZ,QAAQ,EAEC,KAAK;CACjC,OAAO,GAAG,UAAU,OAAO,KAAK;AAClC;;AAGA,MAAM,aAA8B;CAClC,OAAO;CACP,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS;EACP;EACA;EACA;EACA;CACF;CACA,kBAAkB;CAClB,YAAY;CACZ,WAAW;CACX,UAAU,CACR,oBACA,kBACF;CACA;CACA;CACA;CACA;AACF"}
package/dist/cu/ni.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ParsedPersonId, ValidateResult, Validator } from "../types.js";
1
+ import { CountryValidator, ParsedPersonId, ValidateResult } from "../types.js";
2
2
 
3
3
  //#region src/cu/ni.d.ts
4
4
  declare const compact: (value: string) => string;
@@ -16,7 +16,7 @@ declare const generate: () => string;
16
16
  *
17
17
  * Examples sourced from python-stdnum test suite.
18
18
  */
19
- declare const ni: Validator<ParsedPersonId>;
19
+ declare const ni: CountryValidator<"CU", ParsedPersonId>;
20
20
  //#endregion
21
21
  export { compact, ni as default, format, generate, parse, validate };
22
22
  //# sourceMappingURL=ni.d.ts.map
package/dist/cu/ni.js CHANGED
@@ -1,24 +1,8 @@
1
1
  import { clean } from "../_util/clean.js";
2
+ import { isValidDate } from "../_util/date.js";
2
3
  import { randomDigits, randomInt } from "../_util/generate.js";
3
4
  import { err } from "../_util/result.js";
4
- import { isValidDate } from "../_util/date.js";
5
5
  //#region src/cu/ni.ts
6
- /**
7
- * NI (Número de Identidad, Cuban identity card number).
8
- *
9
- * 11 digits encoding birth date, century, sequence, and
10
- * gender. Structure: YYMMDDXNNNN where:
11
- * - YYMMDD = birth date
12
- * - X = century digit (9=1800s, 0-5=1900s, 6-8=2000s)
13
- * - NNNN = sequence (digit at position 9 encodes gender:
14
- * even=male, odd=female)
15
- *
16
- * No check digit; validation is by date and format only.
17
- *
18
- * Ported from python-stdnum cu.ni module.
19
- *
20
- * @see https://www.ecured.cu/Carnet_de_Identidad
21
- */
22
6
  const compact = (value) => clean(value, " -").trim();
23
7
  /**
24
8
  * Derive the full birth year from the two-digit year
@@ -83,6 +67,7 @@ const ni = {
83
67
  "carnet de identidad"
84
68
  ],
85
69
  candidatePattern: "\\d{11}",
70
+ scope: "country",
86
71
  country: "CU",
87
72
  entityType: "person",
88
73
  lengths: [11],
package/dist/cu/ni.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ni.js","names":[],"sources":["../../src/cu/ni.ts"],"sourcesContent":["/**\n * NI (Número de Identidad, Cuban identity card number).\n *\n * 11 digits encoding birth date, century, sequence, and\n * gender. Structure: YYMMDDXNNNN where:\n * - YYMMDD = birth date\n * - X = century digit (9=1800s, 0-5=1900s, 6-8=2000s)\n * - NNNN = sequence (digit at position 9 encodes gender:\n * even=male, odd=female)\n *\n * No check digit; validation is by date and format only.\n *\n * Ported from python-stdnum cu.ni module.\n *\n * @see https://www.ecured.cu/Carnet_de_Identidad\n */\n\nimport { clean } from \"#util/clean\";\nimport { isValidDate } from \"#util/date\";\nimport { randomDigits, randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\n\nimport type {\n ParsedPersonId,\n ValidateResult,\n Validator,\n} from \"../types\";\n\nconst compact = (value: string): string =>\n clean(value, \" -\").trim();\n\n/**\n * Derive the full birth year from the two-digit year\n * and the century indicator at position 6.\n */\nconst centuryOffset = (digit: string): number => {\n if (digit === \"9\") return 1800;\n if (digit >= \"0\" && digit <= \"5\") return 1900;\n return 2000;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 11) {\n return err(\n \"INVALID_LENGTH\",\n \"Cuban NI must be 11 digits\",\n );\n }\n\n if (!/^\\d{11}$/.test(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"Cuban NI must contain only digits\",\n );\n }\n\n const yy = Number(v.slice(0, 2));\n const mm = Number(v.slice(2, 4));\n const dd = Number(v.slice(4, 6));\n // SAFETY: regex check above guarantees v.length === 11.\n // eslint-disable-next-line no-non-null-assertion\n const year = centuryOffset(v[6]!) + yy;\n\n if (!isValidDate(year, mm, dd)) {\n return err(\n \"INVALID_COMPONENT\",\n \"Cuban NI contains an invalid birth date\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => compact(value);\n\n/**\n * Extract birth date and gender from a Cuban NI.\n * Returns null if the value is not valid.\n */\nconst parse = (value: string): ParsedPersonId | null => {\n const result = validate(value);\n if (!result.valid) return null;\n\n const v = result.compact;\n const yy = Number(v.slice(0, 2));\n const mm = Number(v.slice(2, 4));\n const dd = Number(v.slice(4, 6));\n // SAFETY: regex check above guarantees v.length === 11.\n // eslint-disable-next-line no-non-null-assertion\n const year = centuryOffset(v[6]!) + yy;\n\n const genderDigit = Number(v[9]);\n const gender: \"male\" | \"female\" =\n genderDigit % 2 === 0 ? \"male\" : \"female\";\n\n return {\n birthDate: new Date(year, mm - 1, dd),\n gender,\n };\n};\n\n/** Generate a random valid Cuban NI. */\nconst generate = (): string => {\n const year = randomInt(1950, 2024);\n const month = String(randomInt(1, 12)).padStart(2, \"0\");\n const day = String(randomInt(1, 28)).padStart(2, \"0\");\n const yy = String(year % 100).padStart(2, \"0\");\n const century =\n year >= 2000\n ? String(randomInt(6, 8))\n : String(randomInt(0, 5));\n return `${yy}${month}${day}${century}${randomDigits(4)}`;\n};\n\n/**\n * Cuban identity card number (NI).\n *\n * Examples sourced from python-stdnum test suite.\n */\nconst ni: Validator<ParsedPersonId> = {\n name: \"Cuban Identity Card Number\",\n localName: \"Número de Identidad\",\n abbreviation: \"NI\",\n aliases: [\n \"NI\",\n \"número de identidad\",\n \"carnet de identidad\",\n ] as const,\n candidatePattern: \"\\\\d{11}\",\n country: \"CU\",\n entityType: \"person\",\n lengths: [11] as const,\n examples: [\"91021027775\", \"72062506561\"] as const,\n compact,\n format,\n parse,\n validate,\n generate,\n sourceUrl: \"https://www.ecured.cu/Carnet_de_Identidad\",\n};\n\nexport default ni;\nexport { compact, format, generate, parse, validate };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA4BA,MAAM,WAAW,UACf,MAAM,OAAO,KAAK,CAAC,MAAM;;;;;AAM3B,MAAM,iBAAiB,UAA0B;AAC/C,KAAI,UAAU,IAAK,QAAO;AAC1B,KAAI,SAAS,OAAO,SAAS,IAAK,QAAO;AACzC,QAAO;;AAGT,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,MAAM;AAExB,KAAI,EAAE,WAAW,GACf,QAAO,IACL,kBACA,6BACD;AAGH,KAAI,CAAC,WAAW,KAAK,EAAE,CACrB,QAAO,IACL,kBACA,oCACD;CAGH,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;CAChC,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;CAChC,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;AAKhC,KAAI,CAAC,YAFQ,cAAc,EAAE,GAAI,GAAG,IAEb,IAAI,GAAG,CAC5B,QAAO,IACL,qBACA,0CACD;AAGH,QAAO;EAAE,OAAO;EAAM,SAAS;EAAG;;AAGpC,MAAM,UAAU,UAA0B,QAAQ,MAAM;;;;;AAMxD,MAAM,SAAS,UAAyC;CACtD,MAAM,SAAS,SAAS,MAAM;AAC9B,KAAI,CAAC,OAAO,MAAO,QAAO;CAE1B,MAAM,IAAI,OAAO;CACjB,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;CAChC,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;CAChC,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;CAGhC,MAAM,OAAO,cAAc,EAAE,GAAI,GAAG;CAGpC,MAAM,SADc,OAAO,EAAE,GAAG,GAEhB,MAAM,IAAI,SAAS;AAEnC,QAAO;EACL,WAAW,IAAI,KAAK,MAAM,KAAK,GAAG,GAAG;EACrC;EACD;;;AAIH,MAAM,iBAAyB;CAC7B,MAAM,OAAO,UAAU,MAAM,KAAK;CAClC,MAAM,QAAQ,OAAO,UAAU,GAAG,GAAG,CAAC,CAAC,SAAS,GAAG,IAAI;CACvD,MAAM,MAAM,OAAO,UAAU,GAAG,GAAG,CAAC,CAAC,SAAS,GAAG,IAAI;AAMrD,QAAO,GALI,OAAO,OAAO,IAAI,CAAC,SAAS,GAAG,IAAI,GAK/B,QAAQ,MAHrB,QAAQ,MACJ,OAAO,UAAU,GAAG,EAAE,CAAC,GACvB,OAAO,UAAU,GAAG,EAAE,CAAC,GACU,aAAa,EAAE;;;;;;;AAQxD,MAAM,KAAgC;CACpC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS;EACP;EACA;EACA;EACD;CACD,kBAAkB;CAClB,SAAS;CACT,YAAY;CACZ,SAAS,CAAC,GAAG;CACb,UAAU,CAAC,eAAe,cAAc;CACxC;CACA;CACA;CACA;CACA;CACA,WAAW;CACZ"}
1
+ {"version":3,"file":"ni.js","names":[],"sources":["../../src/cu/ni.ts"],"sourcesContent":["/**\n * NI (Número de Identidad, Cuban identity card number).\n *\n * 11 digits encoding birth date, century, sequence, and\n * gender. Structure: YYMMDDXNNNN where:\n * - YYMMDD = birth date\n * - X = century digit (9=1800s, 0-5=1900s, 6-8=2000s)\n * - NNNN = sequence (digit at position 9 encodes gender:\n * even=male, odd=female)\n *\n * No check digit; validation is by date and format only.\n *\n * Ported from python-stdnum cu.ni module.\n *\n * @see https://www.ecured.cu/Carnet_de_Identidad\n */\n\nimport type {\n ParsedPersonId,\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { isValidDate } from \"#util/date\";\nimport { randomDigits, randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\n\nconst compact = (value: string): string =>\n clean(value, \" -\").trim();\n\n/**\n * Derive the full birth year from the two-digit year\n * and the century indicator at position 6.\n */\nconst centuryOffset = (digit: string): number => {\n if (digit === \"9\") return 1800;\n if (digit >= \"0\" && digit <= \"5\") return 1900;\n return 2000;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 11) {\n return err(\n \"INVALID_LENGTH\",\n \"Cuban NI must be 11 digits\",\n );\n }\n\n if (!/^\\d{11}$/.test(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"Cuban NI must contain only digits\",\n );\n }\n\n const yy = Number(v.slice(0, 2));\n const mm = Number(v.slice(2, 4));\n const dd = Number(v.slice(4, 6));\n // SAFETY: regex check above guarantees v.length === 11.\n // eslint-disable-next-line no-non-null-assertion\n const year = centuryOffset(v[6]!) + yy;\n\n if (!isValidDate(year, mm, dd)) {\n return err(\n \"INVALID_COMPONENT\",\n \"Cuban NI contains an invalid birth date\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => compact(value);\n\n/**\n * Extract birth date and gender from a Cuban NI.\n * Returns null if the value is not valid.\n */\nconst parse = (value: string): ParsedPersonId | null => {\n const result = validate(value);\n if (!result.valid) return null;\n\n const v = result.compact;\n const yy = Number(v.slice(0, 2));\n const mm = Number(v.slice(2, 4));\n const dd = Number(v.slice(4, 6));\n // SAFETY: regex check above guarantees v.length === 11.\n // eslint-disable-next-line no-non-null-assertion\n const year = centuryOffset(v[6]!) + yy;\n\n const genderDigit = Number(v[9]);\n const gender: \"male\" | \"female\" =\n genderDigit % 2 === 0 ? \"male\" : \"female\";\n\n return {\n birthDate: new Date(year, mm - 1, dd),\n gender,\n };\n};\n\n/** Generate a random valid Cuban NI. */\nconst generate = (): string => {\n const year = randomInt(1950, 2024);\n const month = String(randomInt(1, 12)).padStart(2, \"0\");\n const day = String(randomInt(1, 28)).padStart(2, \"0\");\n const yy = String(year % 100).padStart(2, \"0\");\n const century =\n year >= 2000\n ? String(randomInt(6, 8))\n : String(randomInt(0, 5));\n return `${yy}${month}${day}${century}${randomDigits(4)}`;\n};\n\n/**\n * Cuban identity card number (NI).\n *\n * Examples sourced from python-stdnum test suite.\n */\nconst ni: CountryValidator<\"CU\", ParsedPersonId> = {\n name: \"Cuban Identity Card Number\",\n localName: \"Número de Identidad\",\n abbreviation: \"NI\",\n aliases: [\n \"NI\",\n \"número de identidad\",\n \"carnet de identidad\",\n ] as const,\n candidatePattern: \"\\\\d{11}\",\n scope: \"country\",\n country: \"CU\",\n entityType: \"person\",\n lengths: [11] as const,\n examples: [\"91021027775\", \"72062506561\"] as const,\n compact,\n format,\n parse,\n validate,\n generate,\n sourceUrl: \"https://www.ecured.cu/Carnet_de_Identidad\",\n};\n\nexport default ni;\nexport { compact, format, generate, parse, validate };\n"],"mappings":";;;;;AA4BA,MAAM,WAAW,UACf,MAAM,OAAO,IAAI,EAAE,KAAK;;;;;AAM1B,MAAM,iBAAiB,UAA0B;CAC/C,IAAI,UAAU,KAAK,OAAO;CAC1B,IAAI,SAAS,OAAO,SAAS,KAAK,OAAO;CACzC,OAAO;AACT;AAEA,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CAEvB,IAAI,EAAE,WAAW,IACf,OAAO,IACL,kBACA,4BACF;CAGF,IAAI,CAAC,WAAW,KAAK,CAAC,GACpB,OAAO,IACL,kBACA,mCACF;CAGF,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/B,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/B,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAK/B,IAAI,CAAC,YAFQ,cAAc,EAAE,EAAG,IAAI,IAEb,IAAI,EAAE,GAC3B,OAAO,IACL,qBACA,yCACF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B,QAAQ,KAAK;;;;;AAMvD,MAAM,SAAS,UAAyC;CACtD,MAAM,SAAS,SAAS,KAAK;CAC7B,IAAI,CAAC,OAAO,OAAO,OAAO;CAE1B,MAAM,IAAI,OAAO;CACjB,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/B,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/B,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAG/B,MAAM,OAAO,cAAc,EAAE,EAAG,IAAI;CAGpC,MAAM,SADc,OAAO,EAAE,EAEjB,IAAI,MAAM,IAAI,SAAS;CAEnC,OAAO;EACL,WAAW,IAAI,KAAK,MAAM,KAAK,GAAG,EAAE;EACpC;CACF;AACF;;AAGA,MAAM,iBAAyB;CAC7B,MAAM,OAAO,UAAU,MAAM,IAAI;CACjC,MAAM,QAAQ,OAAO,UAAU,GAAG,EAAE,CAAC,EAAE,SAAS,GAAG,GAAG;CACtD,MAAM,MAAM,OAAO,UAAU,GAAG,EAAE,CAAC,EAAE,SAAS,GAAG,GAAG;CAMpD,OAAO,GALI,OAAO,OAAO,GAAG,EAAE,SAAS,GAAG,GAK/B,IAAI,QAAQ,MAHrB,QAAQ,MACJ,OAAO,UAAU,GAAG,CAAC,CAAC,IACtB,OAAO,UAAU,GAAG,CAAC,CAAC,IACW,aAAa,CAAC;AACvD;;;;;;AAOA,MAAM,KAA6C;CACjD,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS;EACP;EACA;EACA;CACF;CACA,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,SAAS,CAAC,EAAE;CACZ,UAAU,CAAC,eAAe,aAAa;CACvC;CACA;CACA;CACA;CACA;CACA,WAAW;AACb"}
package/dist/cy/vat.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ValidateResult, Validator } from "../types.js";
1
+ import { CountryValidator, ValidateResult } from "../types.js";
2
2
 
3
3
  //#region src/cy/vat.d.ts
4
4
  declare const compact: (value: string) => string;
@@ -7,7 +7,7 @@ declare const format: (value: string) => string;
7
7
  /** Generate a random valid Cypriot VAT number. */
8
8
  declare const generate: () => string;
9
9
  /** Cypriot VAT Number. */
10
- declare const vat: Validator;
10
+ declare const vat: CountryValidator<"CY">;
11
11
  //#endregion
12
12
  export { compact, vat as default, format, generate, validate };
13
13
  //# sourceMappingURL=vat.d.ts.map
package/dist/cy/vat.js CHANGED
@@ -3,14 +3,6 @@ import { randomDigits } from "../_util/generate.js";
3
3
  import { err } from "../_util/result.js";
4
4
  import { isdigits } from "../_util/strings.js";
5
5
  //#region src/cy/vat.ts
6
- /**
7
- * ΦΠΑ (Cypriot VAT number).
8
- *
9
- * 8 digits + 1 check letter. Cannot start with "12".
10
- *
11
- * @see https://www.vatify.eu/cyprus-vat-number.html
12
- * @see https://www.oecd.org/content/dam/oecd/en/topics/policy-issue-focus/aeoi/cyprus-tin.pdf
13
- */
14
6
  const ODD_MAP = {
15
7
  0: 1,
16
8
  1: 0,
@@ -73,6 +65,7 @@ const vat = {
73
65
  abbreviation: "ΦΠΑ",
74
66
  aliases: ["ΦΠΑ", "VAT CY"],
75
67
  candidatePattern: "CY\\d{8}[A-Z]",
68
+ scope: "country",
76
69
  country: "CY",
77
70
  entityType: "company",
78
71
  sourceUrl: "https://www.mof.gov.cy/",
@@ -1 +1 @@
1
- {"version":3,"file":"vat.js","names":[],"sources":["../../src/cy/vat.ts"],"sourcesContent":["/**\n * ΦΠΑ (Cypriot VAT number).\n *\n * 8 digits + 1 check letter. Cannot start with \"12\".\n *\n * @see https://www.vatify.eu/cyprus-vat-number.html\n * @see https://www.oecd.org/content/dam/oecd/en/topics/policy-issue-focus/aeoi/cyprus-tin.pdf\n */\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nimport type { ValidateResult, Validator } from \"../types\";\n\nconst ODD_MAP: Record<number, number> = {\n 0: 1,\n 1: 0,\n 2: 5,\n 3: 7,\n 4: 9,\n 5: 13,\n 6: 15,\n 7: 17,\n 8: 19,\n 9: 21,\n};\n\nconst LETTERS = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n\nconst compact = (value: string): string => {\n let v = clean(value, \" -/.\");\n if (v.startsWith(\"CY\") || v.startsWith(\"cy\")) {\n v = v.slice(2);\n }\n return v.toUpperCase();\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 9) {\n return err(\n \"INVALID_LENGTH\",\n \"Cypriot VAT number must be 8 digits + 1 letter\",\n );\n }\n const digits = v.slice(0, 8);\n const checkLetter = v[8];\n if (!isdigits(digits)) {\n return err(\n \"INVALID_FORMAT\",\n \"Cypriot VAT number must start with 8 digits\",\n );\n }\n if (\n checkLetter === undefined ||\n !LETTERS.includes(checkLetter)\n ) {\n return err(\n \"INVALID_FORMAT\",\n \"Cypriot VAT number must end with a letter\",\n );\n }\n if (v.startsWith(\"12\")) {\n return err(\n \"INVALID_COMPONENT\",\n \"Cypriot VAT number cannot start with 12\",\n );\n }\n let odd = 0;\n let even = 0;\n for (let i = 0; i < 8; i++) {\n const d = Number(digits.charAt(i));\n if (i % 2 === 0) {\n // Odd position (1-indexed: 1,3,5,7)\n odd += ODD_MAP[d] ?? 0;\n } else {\n // Even position (1-indexed: 2,4,6,8)\n even += d;\n }\n }\n const expected = LETTERS.charAt((odd + even) % 26);\n if (checkLetter !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Cypriot VAT number check letter mismatch\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string =>\n `CY${compact(value)}`;\n\n/** Generate a random valid Cypriot VAT number. */\nconst generate = (): string => {\n for (;;) {\n const digits = randomDigits(8);\n if (digits.startsWith(\"12\")) continue;\n let odd = 0;\n let even = 0;\n for (let i = 0; i < 8; i++) {\n const d = Number(digits.charAt(i));\n if (i % 2 === 0) odd += ODD_MAP[d] ?? 0;\n else even += d;\n }\n return digits + LETTERS.charAt((odd + even) % 26);\n }\n};\n\n/** Cypriot VAT Number. */\nconst vat: Validator = {\n name: \"Cypriot VAT Number\",\n localName: \"Αριθμός Εγγραφής Φ.Π.Α.\",\n abbreviation: \"ΦΠΑ\",\n aliases: [\"ΦΠΑ\", \"VAT CY\"] as const,\n candidatePattern: \"CY\\\\d{8}[A-Z]\",\n country: \"CY\",\n entityType: \"company\",\n sourceUrl: \"https://www.mof.gov.cy/\",\n examples: [\"10259033P\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default vat;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;;;;;;;;AAgBA,MAAM,UAAkC;CACtC,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACJ;AAED,MAAM,UAAU;AAEhB,MAAM,WAAW,UAA0B;CACzC,IAAI,IAAI,MAAM,OAAO,OAAO;AAC5B,KAAI,EAAE,WAAW,KAAK,IAAI,EAAE,WAAW,KAAK,CAC1C,KAAI,EAAE,MAAM,EAAE;AAEhB,QAAO,EAAE,aAAa;;AAGxB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,MAAM;AACxB,KAAI,EAAE,WAAW,EACf,QAAO,IACL,kBACA,iDACD;CAEH,MAAM,SAAS,EAAE,MAAM,GAAG,EAAE;CAC5B,MAAM,cAAc,EAAE;AACtB,KAAI,CAAC,SAAS,OAAO,CACnB,QAAO,IACL,kBACA,8CACD;AAEH,KACE,gBAAgB,KAAA,KAChB,CAAC,QAAQ,SAAS,YAAY,CAE9B,QAAO,IACL,kBACA,4CACD;AAEH,KAAI,EAAE,WAAW,KAAK,CACpB,QAAO,IACL,qBACA,0CACD;CAEH,IAAI,MAAM;CACV,IAAI,OAAO;AACX,MAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;EAC1B,MAAM,IAAI,OAAO,OAAO,OAAO,EAAE,CAAC;AAClC,MAAI,IAAI,MAAM,EAEZ,QAAO,QAAQ,MAAM;MAGrB,SAAQ;;AAIZ,KAAI,gBADa,QAAQ,QAAQ,MAAM,QAAQ,GAAG,CAEhD,QAAO,IACL,oBACA,2CACD;AAEH,QAAO;EAAE,OAAO;EAAM,SAAS;EAAG;;AAGpC,MAAM,UAAU,UACd,KAAK,QAAQ,MAAM;;AAGrB,MAAM,iBAAyB;AAC7B,UAAS;EACP,MAAM,SAAS,aAAa,EAAE;AAC9B,MAAI,OAAO,WAAW,KAAK,CAAE;EAC7B,IAAI,MAAM;EACV,IAAI,OAAO;AACX,OAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;GAC1B,MAAM,IAAI,OAAO,OAAO,OAAO,EAAE,CAAC;AAClC,OAAI,IAAI,MAAM,EAAG,QAAO,QAAQ,MAAM;OACjC,SAAQ;;AAEf,SAAO,SAAS,QAAQ,QAAQ,MAAM,QAAQ,GAAG;;;;AAKrD,MAAM,MAAiB;CACrB,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,OAAO,SAAS;CAC1B,kBAAkB;CAClB,SAAS;CACT,YAAY;CACZ,WAAW;CACX,UAAU,CAAC,YAAY;CACvB;CACA;CACA;CACA;CACD"}
1
+ {"version":3,"file":"vat.js","names":[],"sources":["../../src/cy/vat.ts"],"sourcesContent":["/**\n * ΦΠΑ (Cypriot VAT number).\n *\n * 8 digits + 1 check letter. Cannot start with \"12\".\n *\n * @see https://www.vatify.eu/cyprus-vat-number.html\n * @see https://www.oecd.org/content/dam/oecd/en/topics/policy-issue-focus/aeoi/cyprus-tin.pdf\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst ODD_MAP: Record<number, number> = {\n 0: 1,\n 1: 0,\n 2: 5,\n 3: 7,\n 4: 9,\n 5: 13,\n 6: 15,\n 7: 17,\n 8: 19,\n 9: 21,\n};\n\nconst LETTERS = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n\nconst compact = (value: string): string => {\n let v = clean(value, \" -/.\");\n if (v.startsWith(\"CY\") || v.startsWith(\"cy\")) {\n v = v.slice(2);\n }\n return v.toUpperCase();\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 9) {\n return err(\n \"INVALID_LENGTH\",\n \"Cypriot VAT number must be 8 digits + 1 letter\",\n );\n }\n const digits = v.slice(0, 8);\n const checkLetter = v[8];\n if (!isdigits(digits)) {\n return err(\n \"INVALID_FORMAT\",\n \"Cypriot VAT number must start with 8 digits\",\n );\n }\n if (\n checkLetter === undefined ||\n !LETTERS.includes(checkLetter)\n ) {\n return err(\n \"INVALID_FORMAT\",\n \"Cypriot VAT number must end with a letter\",\n );\n }\n if (v.startsWith(\"12\")) {\n return err(\n \"INVALID_COMPONENT\",\n \"Cypriot VAT number cannot start with 12\",\n );\n }\n let odd = 0;\n let even = 0;\n for (let i = 0; i < 8; i++) {\n const d = Number(digits.charAt(i));\n if (i % 2 === 0) {\n // Odd position (1-indexed: 1,3,5,7)\n odd += ODD_MAP[d] ?? 0;\n } else {\n // Even position (1-indexed: 2,4,6,8)\n even += d;\n }\n }\n const expected = LETTERS.charAt((odd + even) % 26);\n if (checkLetter !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Cypriot VAT number check letter mismatch\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string =>\n `CY${compact(value)}`;\n\n/** Generate a random valid Cypriot VAT number. */\nconst generate = (): string => {\n for (;;) {\n const digits = randomDigits(8);\n if (digits.startsWith(\"12\")) continue;\n let odd = 0;\n let even = 0;\n for (let i = 0; i < 8; i++) {\n const d = Number(digits.charAt(i));\n if (i % 2 === 0) odd += ODD_MAP[d] ?? 0;\n else even += d;\n }\n return digits + LETTERS.charAt((odd + even) % 26);\n }\n};\n\n/** Cypriot VAT Number. */\nconst vat: CountryValidator<\"CY\"> = {\n name: \"Cypriot VAT Number\",\n localName: \"Αριθμός Εγγραφής Φ.Π.Α.\",\n abbreviation: \"ΦΠΑ\",\n aliases: [\"ΦΠΑ\", \"VAT CY\"] as const,\n candidatePattern: \"CY\\\\d{8}[A-Z]\",\n scope: \"country\",\n country: \"CY\",\n entityType: \"company\",\n sourceUrl: \"https://www.mof.gov.cy/\",\n examples: [\"10259033P\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default vat;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;AAmBA,MAAM,UAAkC;CACtC,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;AACL;AAEA,MAAM,UAAU;AAEhB,MAAM,WAAW,UAA0B;CACzC,IAAI,IAAI,MAAM,OAAO,MAAM;CAC3B,IAAI,EAAE,WAAW,IAAI,KAAK,EAAE,WAAW,IAAI,GACzC,IAAI,EAAE,MAAM,CAAC;CAEf,OAAO,EAAE,YAAY;AACvB;AAEA,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,GACf,OAAO,IACL,kBACA,gDACF;CAEF,MAAM,SAAS,EAAE,MAAM,GAAG,CAAC;CAC3B,MAAM,cAAc,EAAE;CACtB,IAAI,CAAC,SAAS,MAAM,GAClB,OAAO,IACL,kBACA,6CACF;CAEF,IACE,gBAAgB,KAAA,KAChB,CAAC,QAAQ,SAAS,WAAW,GAE7B,OAAO,IACL,kBACA,2CACF;CAEF,IAAI,EAAE,WAAW,IAAI,GACnB,OAAO,IACL,qBACA,yCACF;CAEF,IAAI,MAAM;CACV,IAAI,OAAO;CACX,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;EAC1B,MAAM,IAAI,OAAO,OAAO,OAAO,CAAC,CAAC;EACjC,IAAI,IAAI,MAAM,GAEZ,OAAO,QAAQ,MAAM;OAGrB,QAAQ;CAEZ;CAEA,IAAI,gBADa,QAAQ,QAAQ,MAAM,QAAQ,EACpB,GACzB,OAAO,IACL,oBACA,0CACF;CAEF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UACd,KAAK,QAAQ,KAAK;;AAGpB,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,SAAS,aAAa,CAAC;EAC7B,IAAI,OAAO,WAAW,IAAI,GAAG;EAC7B,IAAI,MAAM;EACV,IAAI,OAAO;EACX,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;GAC1B,MAAM,IAAI,OAAO,OAAO,OAAO,CAAC,CAAC;GACjC,IAAI,IAAI,MAAM,GAAG,OAAO,QAAQ,MAAM;QACjC,QAAQ;EACf;EACA,OAAO,SAAS,QAAQ,QAAQ,MAAM,QAAQ,EAAE;CAClD;AACF;;AAGA,MAAM,MAA8B;CAClC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,OAAO,QAAQ;CACzB,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,WAAW;CACX,UAAU,CAAC,WAAW;CACtB;CACA;CACA;CACA;AACF"}
package/dist/cz/dic.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ValidateResult, Validator } from "../types.js";
1
+ import { CountryValidator, ValidateResult } from "../types.js";
2
2
 
3
3
  //#region src/cz/dic.d.ts
4
4
  declare const compact: (value: string) => string;
@@ -7,7 +7,7 @@ declare const format: (value: string) => string;
7
7
  /** Generate a random valid 8-digit DIČ. */
8
8
  declare const generate: () => string;
9
9
  /** Czech VAT Number. */
10
- declare const dic: Validator;
10
+ declare const dic: CountryValidator<"CZ">;
11
11
  //#endregion
12
12
  export { compact, dic as default, format, generate, validate };
13
13
  //# sourceMappingURL=dic.d.ts.map
package/dist/cz/dic.js CHANGED
@@ -1,22 +1,10 @@
1
+ import { weightedSum } from "../_checksums/weighted-sum.js";
1
2
  import { clean } from "../_util/clean.js";
2
3
  import { randomDigits, randomInt } from "../_util/generate.js";
3
4
  import { err } from "../_util/result.js";
4
5
  import { isdigits } from "../_util/strings.js";
5
- import { weightedSum } from "../_checksums/weighted-sum.js";
6
6
  import { validate as validate$1 } from "./rc.js";
7
7
  //#region src/cz/dic.ts
8
- /**
9
- * DIČ (Daňové identifikační číslo).
10
- *
11
- * Czech tax identification number / VAT number.
12
- * Format: "CZ" prefix + 8, 9, or 10 digits.
13
- * - 8 digits: company (same checksum as IČO,
14
- * but first digit cannot be 9)
15
- * - 9 digits starting with 6: special entity
16
- * - 9-10 digits: individual (birth number)
17
- *
18
- * @see https://adisspr.mfcr.cz/dpr/DphReg
19
- */
20
8
  const ICO_WEIGHTS = [
21
9
  8,
22
10
  7,
@@ -82,9 +70,15 @@ const dic = {
82
70
  abbreviation: "DIČ",
83
71
  aliases: ["DIČ", "daňové identifikační číslo"],
84
72
  candidatePattern: "CZ\\d{8,10}",
73
+ scope: "country",
85
74
  country: "CZ",
86
75
  entityType: "any",
87
76
  sourceUrl: "https://adisspr.mfcr.cz/dpr/DphReg",
77
+ lengths: [
78
+ 8,
79
+ 9,
80
+ 10
81
+ ],
88
82
  examples: ["25123891", "7103192745"],
89
83
  compact,
90
84
  format,