@stll/stdnum 0.0.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (474) hide show
  1. package/LICENSE +1 -5
  2. package/README.md +28 -4
  3. package/dist/_checksums/mod112.js +5 -5
  4. package/dist/_checksums/mod112.js.map +1 -1
  5. package/dist/_util/generate.d.ts +13 -1
  6. package/dist/_util/generate.js +23 -1
  7. package/dist/_util/generate.js.map +1 -1
  8. package/dist/ad/mod.d.ts +3 -2
  9. package/dist/ad/nrt.js +3 -2
  10. package/dist/ad/nrt.js.map +1 -1
  11. package/dist/ae/eid.d.ts +0 -1
  12. package/dist/ae/mod.d.ts +3 -2
  13. package/dist/ai/mod.d.ts +3 -2
  14. package/dist/al/mod.d.ts +3 -2
  15. package/dist/am/mod.d.ts +3 -2
  16. package/dist/ar/cbu.d.ts +0 -1
  17. package/dist/ar/cbu.js +1 -1
  18. package/dist/ar/cbu.js.map +1 -1
  19. package/dist/ar/cuit.d.ts +0 -1
  20. package/dist/ar/cuit.js +12 -12
  21. package/dist/ar/cuit.js.map +1 -1
  22. package/dist/ar/mod.d.ts +3 -2
  23. package/dist/at/mod.d.ts +3 -2
  24. package/dist/at/tin.d.ts +0 -1
  25. package/dist/at/uid.d.ts +0 -1
  26. package/dist/at/vnr.d.ts +3 -2
  27. package/dist/at/vnr.js +20 -3
  28. package/dist/at/vnr.js.map +1 -1
  29. package/dist/au/abn.d.ts +0 -1
  30. package/dist/au/acn.d.ts +0 -1
  31. package/dist/au/mod.d.ts +3 -2
  32. package/dist/au/tfn.d.ts +0 -1
  33. package/dist/az/mod.d.ts +3 -2
  34. package/dist/az/voen.d.ts +0 -1
  35. package/dist/az/voen.js.map +1 -1
  36. package/dist/ba/jmbg.d.ts +1 -2
  37. package/dist/ba/jmbg.js +1 -0
  38. package/dist/ba/jmbg.js.map +1 -1
  39. package/dist/ba/mod.d.ts +3 -2
  40. package/dist/bd/mod.d.ts +3 -2
  41. package/dist/bd/nid.js +10 -11
  42. package/dist/bd/nid.js.map +1 -1
  43. package/dist/be/bis.d.ts +0 -1
  44. package/dist/be/mod.d.ts +3 -2
  45. package/dist/be/nn.d.ts +0 -1
  46. package/dist/be/vat.d.ts +0 -1
  47. package/dist/bg/egn.d.ts +1 -2
  48. package/dist/bg/egn.js +10 -3
  49. package/dist/bg/egn.js.map +1 -1
  50. package/dist/bg/mod.d.ts +3 -2
  51. package/dist/bg/pnf.d.ts +0 -1
  52. package/dist/bg/vat.d.ts +0 -1
  53. package/dist/bh/cpr.d.ts +3 -2
  54. package/dist/bh/cpr.js +8 -2
  55. package/dist/bh/cpr.js.map +1 -1
  56. package/dist/bh/mod.d.ts +3 -2
  57. package/dist/bic.js +13 -15
  58. package/dist/bic.js.map +1 -1
  59. package/dist/br/cnpj.d.ts +0 -1
  60. package/dist/br/cpf.d.ts +0 -1
  61. package/dist/br/mod.d.ts +3 -2
  62. package/dist/by/mod.d.ts +3 -2
  63. package/dist/by/unp.d.ts +0 -1
  64. package/dist/by/unp.js +6 -3
  65. package/dist/by/unp.js.map +1 -1
  66. package/dist/bz/mod.d.ts +3 -2
  67. package/dist/bz/tin.d.ts +3 -2
  68. package/dist/bz/tin.js +9 -1
  69. package/dist/bz/tin.js.map +1 -1
  70. package/dist/ca/bn.d.ts +0 -1
  71. package/dist/ca/mod.d.ts +3 -2
  72. package/dist/ca/sin.d.ts +0 -1
  73. package/dist/ch/mod.d.ts +3 -2
  74. package/dist/ch/ssn.d.ts +0 -1
  75. package/dist/ch/uid.d.ts +0 -1
  76. package/dist/ch/vat.d.ts +0 -1
  77. package/dist/cl/mod.d.ts +3 -2
  78. package/dist/cl/rut.d.ts +0 -1
  79. package/dist/cl/rut.js +1 -1
  80. package/dist/cl/rut.js.map +1 -1
  81. package/dist/cn/mod.d.ts +3 -2
  82. package/dist/cn/ric.d.ts +1 -2
  83. package/dist/cn/ric.js +1 -0
  84. package/dist/cn/ric.js.map +1 -1
  85. package/dist/cn/uscc.d.ts +0 -1
  86. package/dist/cn/uscc.js +7 -6
  87. package/dist/cn/uscc.js.map +1 -1
  88. package/dist/co/mod.d.ts +3 -2
  89. package/dist/co/nit.d.ts +0 -1
  90. package/dist/co/nit.js +4 -1
  91. package/dist/co/nit.js.map +1 -1
  92. package/dist/cr/cpf.js +4 -3
  93. package/dist/cr/cpf.js.map +1 -1
  94. package/dist/cr/mod.d.ts +3 -2
  95. package/dist/creditcard.d.ts +0 -1
  96. package/dist/cu/mod.d.ts +3 -2
  97. package/dist/cu/ni.d.ts +4 -3
  98. package/dist/cu/ni.js +11 -1
  99. package/dist/cu/ni.js.map +1 -1
  100. package/dist/cy/mod.d.ts +3 -2
  101. package/dist/cy/vat.d.ts +0 -1
  102. package/dist/cz/dic.d.ts +0 -1
  103. package/dist/cz/ico.d.ts +0 -1
  104. package/dist/cz/mod.d.ts +3 -2
  105. package/dist/cz/rc.d.ts +1 -2
  106. package/dist/cz/rc.js +33 -8
  107. package/dist/cz/rc.js.map +1 -1
  108. package/dist/de/handelsreg.js +9 -9
  109. package/dist/de/handelsreg.js.map +1 -1
  110. package/dist/de/idnr.d.ts +0 -1
  111. package/dist/de/idnr.js.map +1 -1
  112. package/dist/de/mod.d.ts +3 -2
  113. package/dist/de/stnr.d.ts +0 -1
  114. package/dist/de/stnr.js.map +1 -1
  115. package/dist/de/svnr.d.ts +0 -1
  116. package/dist/de/svnr.js +2 -2
  117. package/dist/de/svnr.js.map +1 -1
  118. package/dist/de/vat.d.ts +0 -1
  119. package/dist/dk/cpr.d.ts +4 -3
  120. package/dist/dk/cpr.js +12 -2
  121. package/dist/dk/cpr.js.map +1 -1
  122. package/dist/dk/cvr.d.ts +0 -1
  123. package/dist/dk/mod.d.ts +3 -2
  124. package/dist/dk/vat.d.ts +0 -1
  125. package/dist/do/mod.d.ts +3 -2
  126. package/dist/do/rnc.d.ts +0 -1
  127. package/dist/do/rnc.js +1 -1
  128. package/dist/do/rnc.js.map +1 -1
  129. package/dist/ec/mod.d.ts +3 -2
  130. package/dist/ec/ruc.d.ts +0 -1
  131. package/dist/ec/ruc.js +1 -1
  132. package/dist/ec/ruc.js.map +1 -1
  133. package/dist/ee/ik.d.ts +1 -2
  134. package/dist/ee/ik.js +12 -4
  135. package/dist/ee/ik.js.map +1 -1
  136. package/dist/ee/mod.d.ts +3 -2
  137. package/dist/ee/registrikood.d.ts +0 -1
  138. package/dist/ee/registrikood.js +8 -7
  139. package/dist/ee/registrikood.js.map +1 -1
  140. package/dist/ee/vat.d.ts +0 -1
  141. package/dist/eg/mod.d.ts +3 -2
  142. package/dist/es/cif.d.ts +0 -1
  143. package/dist/es/cif.js +2 -2
  144. package/dist/es/cif.js.map +1 -1
  145. package/dist/es/dni.d.ts +0 -1
  146. package/dist/es/mod.d.ts +3 -2
  147. package/dist/es/nie.d.ts +0 -1
  148. package/dist/es/nie.js +13 -13
  149. package/dist/es/nie.js.map +1 -1
  150. package/dist/es/nss.d.ts +0 -1
  151. package/dist/es/vat.d.ts +0 -1
  152. package/dist/eu/mod.d.ts +3 -2
  153. package/dist/eu/vat.d.ts +3 -2
  154. package/dist/eu/vat.js +43 -2
  155. package/dist/eu/vat.js.map +1 -1
  156. package/dist/fi/hetu.d.ts +4 -3
  157. package/dist/fi/hetu.js +17 -2
  158. package/dist/fi/hetu.js.map +1 -1
  159. package/dist/fi/mod.d.ts +3 -2
  160. package/dist/fi/vat.d.ts +0 -1
  161. package/dist/fi/ytunnus.d.ts +0 -1
  162. package/dist/fr/mod.d.ts +3 -2
  163. package/dist/fr/nif.d.ts +0 -1
  164. package/dist/fr/nir.d.ts +1 -2
  165. package/dist/fr/nir.js +1 -0
  166. package/dist/fr/nir.js.map +1 -1
  167. package/dist/fr/siren.d.ts +0 -1
  168. package/dist/fr/siret.d.ts +0 -1
  169. package/dist/fr/tva.d.ts +0 -1
  170. package/dist/gb/mod.d.ts +3 -2
  171. package/dist/gb/nino.js +7 -7
  172. package/dist/gb/nino.js.map +1 -1
  173. package/dist/gb/sedol.d.ts +0 -1
  174. package/dist/gb/sedol.js +8 -7
  175. package/dist/gb/sedol.js.map +1 -1
  176. package/dist/gb/utr.d.ts +0 -1
  177. package/dist/gb/vat.d.ts +0 -1
  178. package/dist/ge/mod.d.ts +3 -2
  179. package/dist/gh/mod.d.ts +3 -2
  180. package/dist/gh/tin.d.ts +0 -1
  181. package/dist/gh/tin.js +9 -9
  182. package/dist/gh/tin.js.map +1 -1
  183. package/dist/gr/amka.d.ts +0 -1
  184. package/dist/gr/mod.d.ts +3 -2
  185. package/dist/gr/vat.d.ts +0 -1
  186. package/dist/gt/mod.d.ts +3 -2
  187. package/dist/gt/nit.d.ts +0 -1
  188. package/dist/gt/nit.js +5 -2
  189. package/dist/gt/nit.js.map +1 -1
  190. package/dist/hk/hkid.d.ts +0 -1
  191. package/dist/hk/hkid.js +1 -0
  192. package/dist/hk/hkid.js.map +1 -1
  193. package/dist/hk/mod.d.ts +3 -2
  194. package/dist/hr/mod.d.ts +3 -2
  195. package/dist/hr/vat.d.ts +0 -1
  196. package/dist/hu/mod.d.ts +3 -2
  197. package/dist/hu/vat.d.ts +0 -1
  198. package/dist/iban.d.ts +0 -1
  199. package/dist/id/mod.d.ts +3 -2
  200. package/dist/id/npwp.d.ts +0 -1
  201. package/dist/ie/mod.d.ts +3 -2
  202. package/dist/ie/pps.d.ts +0 -1
  203. package/dist/ie/vat.d.ts +0 -1
  204. package/dist/il/idnr.d.ts +0 -1
  205. package/dist/il/mod.d.ts +3 -2
  206. package/dist/in/aadhaar.d.ts +0 -1
  207. package/dist/in/gstin.d.ts +0 -1
  208. package/dist/in/gstin.js +3 -1
  209. package/dist/in/gstin.js.map +1 -1
  210. package/dist/in/mod.d.ts +3 -2
  211. package/dist/in/pan.js +2 -2
  212. package/dist/in/pan.js.map +1 -1
  213. package/dist/index.d.ts +2 -2
  214. package/dist/iq/mod.d.ts +3 -2
  215. package/dist/ir/mod.d.ts +3 -2
  216. package/dist/ir/nid.d.ts +0 -1
  217. package/dist/is/kennitala.d.ts +0 -1
  218. package/dist/is/mod.d.ts +3 -2
  219. package/dist/isin.d.ts +0 -1
  220. package/dist/isin.js +9 -9
  221. package/dist/isin.js.map +1 -1
  222. package/dist/it/codicefiscale.d.ts +4 -3
  223. package/dist/it/codicefiscale.js +26 -2
  224. package/dist/it/codicefiscale.js.map +1 -1
  225. package/dist/it/iva.d.ts +0 -1
  226. package/dist/it/mod.d.ts +3 -2
  227. package/dist/jp/cn.d.ts +0 -1
  228. package/dist/jp/mod.d.ts +3 -2
  229. package/dist/jp/mynumber.d.ts +0 -1
  230. package/dist/kr/mod.d.ts +3 -2
  231. package/dist/kr/rrn.d.ts +4 -3
  232. package/dist/kr/rrn.js +13 -2
  233. package/dist/kr/rrn.js.map +1 -1
  234. package/dist/kw/civil.d.ts +6 -5
  235. package/dist/kw/civil.js +18 -3
  236. package/dist/kw/civil.js.map +1 -1
  237. package/dist/kw/mod.d.ts +3 -2
  238. package/dist/kz/iin.d.ts +1 -2
  239. package/dist/kz/iin.js +1 -0
  240. package/dist/kz/iin.js.map +1 -1
  241. package/dist/kz/mod.d.ts +3 -2
  242. package/dist/lei.d.ts +0 -1
  243. package/dist/li/mod.d.ts +3 -2
  244. package/dist/lk/mod.d.ts +3 -2
  245. package/dist/lk/nic.d.ts +4 -3
  246. package/dist/lk/nic.js +14 -2
  247. package/dist/lk/nic.js.map +1 -1
  248. package/dist/lt/asmens.d.ts +0 -1
  249. package/dist/lt/mod.d.ts +3 -2
  250. package/dist/lt/vat.d.ts +0 -1
  251. package/dist/lu/mod.d.ts +3 -2
  252. package/dist/lu/vat.d.ts +0 -1
  253. package/dist/luhn.d.ts +0 -1
  254. package/dist/luhn.js +7 -0
  255. package/dist/luhn.js.map +1 -1
  256. package/dist/lv/mod.d.ts +3 -2
  257. package/dist/lv/vat.d.ts +0 -1
  258. package/dist/lv/vat.js +39 -12
  259. package/dist/lv/vat.js.map +1 -1
  260. package/dist/ma/ice.d.ts +0 -1
  261. package/dist/ma/mod.d.ts +3 -2
  262. package/dist/mc/mod.d.ts +3 -2
  263. package/dist/mc/tva.d.ts +0 -1
  264. package/dist/md/idno.d.ts +0 -1
  265. package/dist/md/mod.d.ts +3 -2
  266. package/dist/me/mod.d.ts +3 -2
  267. package/dist/me/pib.d.ts +0 -1
  268. package/dist/mk/edb.d.ts +0 -1
  269. package/dist/mk/mod.d.ts +3 -2
  270. package/dist/mt/mod.d.ts +3 -2
  271. package/dist/mt/vat.d.ts +0 -1
  272. package/dist/mu/mod.d.ts +3 -2
  273. package/dist/mx/clabe.d.ts +0 -1
  274. package/dist/mx/curp.d.ts +4 -3
  275. package/dist/mx/curp.js +25 -3
  276. package/dist/mx/curp.js.map +1 -1
  277. package/dist/mx/mod.d.ts +3 -2
  278. package/dist/mx/rfc.d.ts +3 -2
  279. package/dist/mx/rfc.js +21 -2
  280. package/dist/mx/rfc.js.map +1 -1
  281. package/dist/my/mod.d.ts +3 -2
  282. package/dist/my/nric.d.ts +4 -3
  283. package/dist/my/nric.js +16 -2
  284. package/dist/my/nric.js.map +1 -1
  285. package/dist/ng/mod.d.ts +3 -2
  286. package/dist/ni/mod.d.ts +3 -2
  287. package/dist/ni/ruc.d.ts +0 -1
  288. package/dist/nl/bsn.d.ts +0 -1
  289. package/dist/nl/mod.d.ts +3 -2
  290. package/dist/nl/vat.d.ts +0 -1
  291. package/dist/nl/vat.js +9 -43
  292. package/dist/nl/vat.js.map +1 -1
  293. package/dist/no/fodselsnummer.d.ts +1 -2
  294. package/dist/no/fodselsnummer.js +1 -0
  295. package/dist/no/fodselsnummer.js.map +1 -1
  296. package/dist/no/mod.d.ts +3 -2
  297. package/dist/no/mva.d.ts +0 -1
  298. package/dist/no/orgnr.d.ts +0 -1
  299. package/dist/nz/ird.d.ts +0 -1
  300. package/dist/nz/ird.js +2 -2
  301. package/dist/nz/ird.js.map +1 -1
  302. package/dist/nz/mod.d.ts +3 -2
  303. package/dist/pa/mod.d.ts +3 -2
  304. package/dist/pa/ruc.d.ts +0 -1
  305. package/dist/pa/ruc.js +3 -1
  306. package/dist/pa/ruc.js.map +1 -1
  307. package/dist/patterns.d.ts +1 -4
  308. package/dist/patterns.js +80 -23
  309. package/dist/patterns.js.map +1 -1
  310. package/dist/pe/mod.d.ts +3 -2
  311. package/dist/pe/ruc.d.ts +0 -1
  312. package/dist/pe/ruc.js +9 -9
  313. package/dist/pe/ruc.js.map +1 -1
  314. package/dist/ph/mod.d.ts +3 -2
  315. package/dist/pk/cnic.js.map +1 -1
  316. package/dist/pk/mod.d.ts +3 -2
  317. package/dist/pl/mod.d.ts +3 -2
  318. package/dist/pl/nip.d.ts +0 -1
  319. package/dist/pl/pesel.d.ts +1 -2
  320. package/dist/pl/pesel.js +1 -0
  321. package/dist/pl/pesel.js.map +1 -1
  322. package/dist/pl/regon.d.ts +0 -1
  323. package/dist/pt/cc.d.ts +0 -1
  324. package/dist/pt/cc.js +6 -4
  325. package/dist/pt/cc.js.map +1 -1
  326. package/dist/pt/mod.d.ts +3 -2
  327. package/dist/pt/vat.d.ts +0 -1
  328. package/dist/ro/cnp.d.ts +1 -2
  329. package/dist/ro/cnp.js +1 -0
  330. package/dist/ro/cnp.js.map +1 -1
  331. package/dist/ro/mod.d.ts +3 -2
  332. package/dist/ro/vat.d.ts +0 -1
  333. package/dist/rs/mod.d.ts +3 -2
  334. package/dist/rs/pib.d.ts +0 -1
  335. package/dist/ru/inn.d.ts +0 -1
  336. package/dist/ru/inn.js +1 -1
  337. package/dist/ru/inn.js.map +1 -1
  338. package/dist/ru/mod.d.ts +3 -2
  339. package/dist/se/mod.d.ts +3 -2
  340. package/dist/se/orgnr.d.ts +0 -1
  341. package/dist/se/personnummer.d.ts +1 -2
  342. package/dist/se/personnummer.js +1 -0
  343. package/dist/se/personnummer.js.map +1 -1
  344. package/dist/se/vat.d.ts +0 -1
  345. package/dist/sg/mod.d.ts +3 -2
  346. package/dist/sg/uen.d.ts +0 -1
  347. package/dist/sg/uen.js +46 -55
  348. package/dist/sg/uen.js.map +1 -1
  349. package/dist/si/emso.d.ts +1 -2
  350. package/dist/si/emso.js +17 -4
  351. package/dist/si/emso.js.map +1 -1
  352. package/dist/si/mod.d.ts +3 -2
  353. package/dist/si/vat.d.ts +0 -1
  354. package/dist/sk/dic.d.ts +0 -1
  355. package/dist/sk/ico.d.ts +0 -1
  356. package/dist/sk/mod.d.ts +3 -2
  357. package/dist/sk/rc.d.ts +4 -5
  358. package/dist/sk/rc.js +5 -2
  359. package/dist/sk/rc.js.map +1 -1
  360. package/dist/th/mod.d.ts +3 -2
  361. package/dist/th/tin.d.ts +0 -1
  362. package/dist/tr/mod.d.ts +3 -2
  363. package/dist/tr/tckimlik.d.ts +0 -1
  364. package/dist/tr/vkn.d.ts +0 -1
  365. package/dist/tw/mod.d.ts +3 -2
  366. package/dist/tw/ubn.d.ts +0 -1
  367. package/dist/tw/ubn.js +1 -1
  368. package/dist/tw/ubn.js.map +1 -1
  369. package/dist/types.d.ts +35 -22
  370. package/dist/ua/edrpou.d.ts +0 -1
  371. package/dist/ua/edrpou.js +4 -1
  372. package/dist/ua/edrpou.js.map +1 -1
  373. package/dist/ua/mod.d.ts +3 -2
  374. package/dist/us/ein.js +87 -87
  375. package/dist/us/ein.js.map +1 -1
  376. package/dist/us/itin.js +3 -4
  377. package/dist/us/itin.js.map +1 -1
  378. package/dist/us/mod.d.ts +3 -2
  379. package/dist/us/rtn.d.ts +0 -1
  380. package/dist/us/rtn.js +8 -5
  381. package/dist/us/rtn.js.map +1 -1
  382. package/dist/uy/mod.d.ts +3 -2
  383. package/dist/uy/rut.d.ts +0 -1
  384. package/dist/uy/rut.js +1 -1
  385. package/dist/uy/rut.js.map +1 -1
  386. package/dist/ve/mod.d.ts +3 -2
  387. package/dist/ve/rif.d.ts +0 -1
  388. package/dist/ve/rif.js +11 -11
  389. package/dist/ve/rif.js.map +1 -1
  390. package/dist/vn/mod.d.ts +3 -2
  391. package/dist/vn/mst.d.ts +0 -1
  392. package/dist/za/idnr.d.ts +1 -2
  393. package/dist/za/idnr.js +1 -0
  394. package/dist/za/idnr.js.map +1 -1
  395. package/dist/za/mod.d.ts +3 -2
  396. package/package.json +18 -15
  397. package/src/_checksums/mod112.ts +7 -6
  398. package/src/_util/generate.ts +38 -0
  399. package/src/ad/nrt.ts +12 -4
  400. package/src/ar/cbu.ts +2 -2
  401. package/src/ar/cuit.ts +15 -7
  402. package/src/at/vnr.ts +26 -4
  403. package/src/az/voen.ts +2 -0
  404. package/src/ba/jmbg.ts +2 -1
  405. package/src/bd/nid.ts +4 -4
  406. package/src/bg/egn.ts +12 -4
  407. package/src/bh/cpr.ts +10 -1
  408. package/src/bic.ts +19 -17
  409. package/src/by/unp.ts +9 -4
  410. package/src/bz/tin.ts +12 -1
  411. package/src/cl/rut.ts +4 -2
  412. package/src/cn/ric.ts +4 -1
  413. package/src/cn/uscc.ts +20 -8
  414. package/src/co/nit.ts +6 -2
  415. package/src/cr/cpf.ts +4 -3
  416. package/src/cu/ni.ts +22 -2
  417. package/src/cz/rc.ts +54 -23
  418. package/src/de/handelsreg.ts +14 -3
  419. package/src/de/idnr.ts +3 -0
  420. package/src/de/stnr.ts +4 -0
  421. package/src/de/svnr.ts +7 -2
  422. package/src/dk/cpr.ts +16 -2
  423. package/src/do/rnc.ts +2 -2
  424. package/src/ec/ruc.ts +2 -2
  425. package/src/ee/ik.ts +14 -4
  426. package/src/ee/registrikood.ts +4 -3
  427. package/src/es/cif.ts +2 -3
  428. package/src/es/nie.ts +10 -5
  429. package/src/eu/vat.ts +46 -1
  430. package/src/fi/hetu.ts +19 -2
  431. package/src/fr/nir.ts +2 -1
  432. package/src/gb/nino.ts +11 -10
  433. package/src/gb/sedol.ts +14 -12
  434. package/src/gh/tin.ts +4 -3
  435. package/src/gt/nit.ts +6 -3
  436. package/src/hk/hkid.ts +2 -1
  437. package/src/in/gstin.ts +3 -1
  438. package/src/in/pan.ts +8 -3
  439. package/src/index.ts +3 -0
  440. package/src/isin.ts +10 -4
  441. package/src/it/codicefiscale.ts +40 -2
  442. package/src/kr/rrn.ts +20 -2
  443. package/src/kw/civil.ts +25 -9
  444. package/src/kz/iin.ts +2 -1
  445. package/src/lk/nic.ts +24 -2
  446. package/src/luhn.ts +3 -0
  447. package/src/lv/vat.ts +46 -20
  448. package/src/mx/curp.ts +41 -5
  449. package/src/mx/rfc.ts +35 -4
  450. package/src/my/nric.ts +26 -2
  451. package/src/nl/vat.ts +11 -66
  452. package/src/no/fodselsnummer.ts +2 -1
  453. package/src/nz/ird.ts +4 -4
  454. package/src/pa/ruc.ts +32 -8
  455. package/src/patterns.ts +135 -28
  456. package/src/pe/ruc.ts +6 -7
  457. package/src/pk/cnic.ts +2 -0
  458. package/src/pl/pesel.ts +2 -1
  459. package/src/pt/cc.ts +6 -4
  460. package/src/ro/cnp.ts +2 -1
  461. package/src/ru/inn.ts +2 -2
  462. package/src/se/personnummer.ts +2 -1
  463. package/src/sg/uen.ts +37 -20
  464. package/src/si/emso.ts +30 -5
  465. package/src/sk/rc.ts +13 -4
  466. package/src/tw/ubn.ts +2 -2
  467. package/src/types.ts +37 -6
  468. package/src/ua/edrpou.ts +3 -2
  469. package/src/us/ein.ts +88 -88
  470. package/src/us/itin.ts +7 -8
  471. package/src/us/rtn.ts +16 -11
  472. package/src/uy/rut.ts +2 -2
  473. package/src/ve/rif.ts +11 -6
  474. package/src/za/idnr.ts +2 -1
@@ -1 +1 @@
1
- {"version":3,"file":"rif.js","names":[],"sources":["../../src/ve/rif.ts"],"sourcesContent":["/**\n * RIF (Registro de Información Fiscal).\n *\n * Venezuelan tax identification number issued by the\n * SENIAT. The number consists of 1 letter indicating\n * the entity type (J=juridical, G=government,\n * V=natural/Venezuelan, E=foreign, P=passport)\n * followed by 8 digits and a check digit computed\n * via weighted sum mod 11.\n *\n * Format: X-########-# or X######### (10 chars compact)\n *\n * @see https://en.wikipedia.org/wiki/Tax_Identification_Number#Venezuela\n */\n\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 * Map prefix letter to its numeric offset used\n * in the check digit computation.\n */\nconst PREFIX_VALUES: Record<string, number> = {\n V: 4,\n E: 8,\n J: 12,\n P: 16,\n G: 20,\n};\n\n/** Weights applied to the 8-digit body. */\nconst WEIGHTS = [3, 2, 7, 6, 5, 4, 3, 2] as const;\n\n/**\n * Lookup table for converting the mod 11 result\n * to the check character.\n */\nconst CHECK_LOOKUP = \"00987654321\";\n\nconst compact = (value: string): string =>\n clean(value, \" -.\").trim().toUpperCase();\n\nconst calcCheckDigit = (\n prefix: string,\n body: string,\n): string => {\n const pv = PREFIX_VALUES[prefix]!;\n let sum = 0;\n for (let i = 0; i < 8; i++) {\n sum += Number(body[i]) * WEIGHTS[i]!;\n }\n const digit = (pv + (sum % 11)) % 11;\n return CHECK_LOOKUP[digit]!;\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 \"RIF must be 10 characters\",\n );\n }\n\n const prefix = v[0]!;\n if (!(prefix in PREFIX_VALUES)) {\n return err(\n \"INVALID_COMPONENT\",\n \"RIF must start with V, E, J, P, or G\",\n );\n }\n\n const body = v.slice(1, 9);\n const check = v.slice(9);\n if (!isdigits(v.slice(1))) {\n return err(\n \"INVALID_FORMAT\",\n \"RIF body must contain only digits\",\n );\n }\n\n const expected = calcCheckDigit(prefix, body);\n if (check !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"RIF 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 return `${v[0]}-${v.slice(1, 9)}-${v.slice(9)}`;\n};\n\n/** Generate a random valid Venezuelan RIF. */\nconst generate = (): string => {\n const types = [\"V\", \"E\", \"J\", \"P\", \"G\"] as const;\n const prefix = types[randomInt(0, types.length - 1)]!;\n const body = randomDigits(8);\n return (\n prefix + body + String(calcCheckDigit(prefix, body))\n );\n};\n\n/**\n * Venezuelan RIF (tax identification number).\n *\n * Examples sourced from python-stdnum test suite.\n */\nconst rif: Validator = {\n name: \"Venezuelan Tax ID\",\n localName: \"Registro de Información Fiscal\",\n abbreviation: \"RIF\",\n aliases: [\n \"RIF\",\n \"Registro de Información Fiscal\",\n ] as const,\n candidatePattern: \"[VEJPG]-?\\\\d{8}-?\\\\d\",\n country: \"VE\",\n entityType: \"any\",\n lengths: [10] as const,\n examples: [\"V309876543\", \"J309876546\"] as const,\n compact,\n format,\n validate,\n sourceUrl:\n \"https://en.wikipedia.org/wiki/Tax_Identification_Number#Venezuela\",\n generate,\n};\n\nexport default rif;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAM,gBAAwC;CAC5C,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACJ;;AAGD,MAAM,UAAU;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAE;;;;;AAMxC,MAAM,eAAe;AAErB,MAAM,WAAW,UACf,MAAM,OAAO,MAAM,CAAC,MAAM,CAAC,aAAa;AAE1C,MAAM,kBACJ,QACA,SACW;CACX,MAAM,KAAK,cAAc;CACzB,IAAI,MAAM;AACV,MAAK,IAAI,IAAI,GAAG,IAAI,GAAG,IACrB,QAAO,OAAO,KAAK,GAAG,GAAG,QAAQ;AAGnC,QAAO,cADQ,KAAM,MAAM,MAAO;;AAIpC,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,MAAM;AAExB,KAAI,EAAE,WAAW,GACf,QAAO,IACL,kBACA,4BACD;CAGH,MAAM,SAAS,EAAE;AACjB,KAAI,EAAE,UAAU,eACd,QAAO,IACL,qBACA,uCACD;CAGH,MAAM,OAAO,EAAE,MAAM,GAAG,EAAE;CAC1B,MAAM,QAAQ,EAAE,MAAM,EAAE;AACxB,KAAI,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,CACvB,QAAO,IACL,kBACA,oCACD;AAIH,KAAI,UADa,eAAe,QAAQ,KAAK,CAE3C,QAAO,IACL,oBACA,iCACD;AAGH,QAAO;EAAE,OAAO;EAAM,SAAS;EAAG;;AAGpC,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,MAAM;AACxB,QAAO,GAAG,EAAE,GAAG,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE;;;AAI/C,MAAM,iBAAyB;CAC7B,MAAM,QAAQ;EAAC;EAAK;EAAK;EAAK;EAAK;EAAI;CACvC,MAAM,SAAS,MAAM,UAAU,GAAG,MAAM,SAAS,EAAE;CACnD,MAAM,OAAO,aAAa,EAAE;AAC5B,QACE,SAAS,OAAO,OAAO,eAAe,QAAQ,KAAK,CAAC;;;;;;;AASxD,MAAM,MAAiB;CACrB,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CACP,OACA,iCACD;CACD,kBAAkB;CAClB,SAAS;CACT,YAAY;CACZ,SAAS,CAAC,GAAG;CACb,UAAU,CAAC,cAAc,aAAa;CACtC;CACA;CACA;CACA,WACE;CACF;CACD"}
1
+ {"version":3,"file":"rif.js","names":[],"sources":["../../src/ve/rif.ts"],"sourcesContent":["/**\n * RIF (Registro de Información Fiscal).\n *\n * Venezuelan tax identification number issued by the\n * SENIAT. The number consists of 1 letter indicating\n * the entity type (J=juridical, G=government,\n * V=natural/Venezuelan, E=foreign, P=passport)\n * followed by 8 digits and a check digit computed\n * via weighted sum mod 11.\n *\n * Format: X-########-# or X######### (10 chars compact)\n *\n * @see https://en.wikipedia.org/wiki/Tax_Identification_Number#Venezuela\n */\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits, randomPick } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nimport type { ValidateResult, Validator } from \"../types\";\n\n/**\n * Map prefix letter to its numeric offset used\n * in the check digit computation.\n */\nconst PREFIX_VALUES: Record<string, number> = {\n V: 4,\n E: 8,\n J: 12,\n P: 16,\n G: 20,\n};\n\n/** Weights applied to the 8-digit body. */\nconst WEIGHTS = [3, 2, 7, 6, 5, 4, 3, 2] as const;\n\n/**\n * Lookup table for converting the mod 11 result\n * to the check character.\n */\nconst CHECK_LOOKUP = \"00987654321\";\n\nconst compact = (value: string): string =>\n clean(value, \" -.\").trim().toUpperCase();\n\nconst calcCheckDigit = (\n prefix: string,\n body: string,\n): string => {\n const pv = PREFIX_VALUES[prefix] ?? 0;\n let sum = 0;\n for (const [i, weight] of WEIGHTS.entries()) {\n sum += Number(body[i]) * weight;\n }\n const digit = (pv + (sum % 11)) % 11;\n // SAFETY: digit ∈ [0, 10] and CHECK_LOOKUP has 11 chars.\n // eslint-disable-next-line no-non-null-assertion\n return CHECK_LOOKUP[digit]!;\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 \"RIF must be 10 characters\",\n );\n }\n\n // SAFETY: length check above guarantees v[0] exists.\n // eslint-disable-next-line no-non-null-assertion\n const prefix = v[0]!;\n if (!(prefix in PREFIX_VALUES)) {\n return err(\n \"INVALID_COMPONENT\",\n \"RIF must start with V, E, J, P, or G\",\n );\n }\n\n const body = v.slice(1, 9);\n const check = v.slice(9);\n if (!isdigits(v.slice(1))) {\n return err(\n \"INVALID_FORMAT\",\n \"RIF body must contain only digits\",\n );\n }\n\n const expected = calcCheckDigit(prefix, body);\n if (check !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"RIF 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 return `${v[0]}-${v.slice(1, 9)}-${v.slice(9)}`;\n};\n\nconst GENERATE_TYPES = [\"V\", \"E\", \"J\", \"P\", \"G\"] as const;\n\n/** Generate a random valid Venezuelan RIF. */\nconst generate = (): string => {\n const prefix = randomPick(GENERATE_TYPES);\n const body = randomDigits(8);\n return (\n prefix + body + String(calcCheckDigit(prefix, body))\n );\n};\n\n/**\n * Venezuelan RIF (tax identification number).\n *\n * Examples sourced from python-stdnum test suite.\n */\nconst rif: Validator = {\n name: \"Venezuelan Tax ID\",\n localName: \"Registro de Información Fiscal\",\n abbreviation: \"RIF\",\n aliases: [\n \"RIF\",\n \"Registro de Información Fiscal\",\n ] as const,\n candidatePattern: \"[VEJPG]-?\\\\d{8}-?\\\\d\",\n country: \"VE\",\n entityType: \"any\",\n lengths: [10] as const,\n examples: [\"V309876543\", \"J309876546\"] as const,\n compact,\n format,\n validate,\n sourceUrl:\n \"https://en.wikipedia.org/wiki/Tax_Identification_Number#Venezuela\",\n generate,\n};\n\nexport default rif;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAM,gBAAwC;CAC5C,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACJ;;AAGD,MAAM,UAAU;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAE;;;;;AAMxC,MAAM,eAAe;AAErB,MAAM,WAAW,UACf,MAAM,OAAO,MAAM,CAAC,MAAM,CAAC,aAAa;AAE1C,MAAM,kBACJ,QACA,SACW;CACX,MAAM,KAAK,cAAc,WAAW;CACpC,IAAI,MAAM;AACV,MAAK,MAAM,CAAC,GAAG,WAAW,QAAQ,SAAS,CACzC,QAAO,OAAO,KAAK,GAAG,GAAG;AAK3B,QAAO,cAHQ,KAAM,MAAM,MAAO;;AAMpC,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,MAAM;AAExB,KAAI,EAAE,WAAW,GACf,QAAO,IACL,kBACA,4BACD;CAKH,MAAM,SAAS,EAAE;AACjB,KAAI,EAAE,UAAU,eACd,QAAO,IACL,qBACA,uCACD;CAGH,MAAM,OAAO,EAAE,MAAM,GAAG,EAAE;CAC1B,MAAM,QAAQ,EAAE,MAAM,EAAE;AACxB,KAAI,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,CACvB,QAAO,IACL,kBACA,oCACD;AAIH,KAAI,UADa,eAAe,QAAQ,KAAK,CAE3C,QAAO,IACL,oBACA,iCACD;AAGH,QAAO;EAAE,OAAO;EAAM,SAAS;EAAG;;AAGpC,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,MAAM;AACxB,QAAO,GAAG,EAAE,GAAG,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE;;AAG/C,MAAM,iBAAiB;CAAC;CAAK;CAAK;CAAK;CAAK;CAAI;;AAGhD,MAAM,iBAAyB;CAC7B,MAAM,SAAS,WAAW,eAAe;CACzC,MAAM,OAAO,aAAa,EAAE;AAC5B,QACE,SAAS,OAAO,OAAO,eAAe,QAAQ,KAAK,CAAC;;;;;;;AASxD,MAAM,MAAiB;CACrB,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CACP,OACA,iCACD;CACD,kBAAkB;CAClB,SAAS;CACT,YAAY;CACZ,SAAS,CAAC,GAAG;CACb,UAAU,CAAC,cAAc,aAAa;CACtC;CACA;CACA;CACA,WACE;CACF;CACD"}
package/dist/vn/mod.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- import { __exportAll } from "../_virtual/_rolldown/runtime.js";
2
1
  import mst from "./mst.js";
3
2
 
4
3
  //#region src/vn/mod.d.ts
5
-
4
+ declare namespace mod_d_exports {
5
+ export { mst };
6
+ }
6
7
  //#endregion
7
8
  export { mod_d_exports, mst };
8
9
  //# sourceMappingURL=mod.d.ts.map
package/dist/vn/mst.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { ValidateResult, Validator } from "../types.js";
2
2
 
3
3
  //#region src/vn/mst.d.ts
4
-
5
4
  declare const compact: (value: string) => string;
6
5
  declare const validate: (value: string) => ValidateResult;
7
6
  declare const format: (value: string) => string;
package/dist/za/idnr.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { ParsedPersonId, ValidateResult, Validator } from "../types.js";
2
2
 
3
3
  //#region src/za/idnr.d.ts
4
-
5
4
  declare const compact: (value: string) => string;
6
5
  declare const validate: (value: string) => ValidateResult;
7
6
  declare const format: (value: string) => string;
@@ -13,7 +12,7 @@ declare const parse: (value: string) => ParsedPersonId | null;
13
12
  /** Generate a random valid South African ID. */
14
13
  declare const generate: () => string;
15
14
  /** South African Identity Number. */
16
- declare const idnr: Validator;
15
+ declare const idnr: Validator<ParsedPersonId>;
17
16
  //#endregion
18
17
  export { compact, idnr as default, format, generate, parse, validate };
19
18
  //# sourceMappingURL=idnr.d.ts.map
package/dist/za/idnr.js CHANGED
@@ -97,6 +97,7 @@ const idnr = {
97
97
  entityType: "person",
98
98
  compact,
99
99
  format,
100
+ parse,
100
101
  validate,
101
102
  description: "South African personal identification number",
102
103
  sourceUrl: "https://en.wikipedia.org/wiki/South_African_identity_document",
@@ -1 +1 @@
1
- {"version":3,"file":"idnr.js","names":[],"sources":["../../src/za/idnr.ts"],"sourcesContent":["/**\n * South African Identity Number.\n *\n * 13-digit number encoding date of birth, gender,\n * citizenship, and a Luhn check digit.\n * Format: YYMMDD SSSS C A Z\n * - YYMMDD: date of birth\n * - SSSS: sequence (0000-4999 female, 5000-9999 male)\n * - C: citizenship (0 = citizen, 1 = permanent resident)\n * - A: was used for race (now always 8 or 9)\n * - Z: Luhn check digit\n *\n * @see https://en.wikipedia.org/wiki/South_African_identity_document\n */\n\nimport {\n luhnValidate,\n luhnChecksum,\n} from \"#checksums/luhn\";\nimport { clean } from \"#util/clean\";\nimport { isValidDate } from \"#util/date\";\nimport { randomDigits, 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, \" \");\n\n/**\n * Resolve the birth date from the 2-digit year.\n * Years after the current year are assumed to be\n * in the previous century.\n */\nconst resolveBirthDate = (\n v: string,\n): { year: number; month: number; day: number } | null => {\n const today = new Date();\n const century = Math.floor(today.getFullYear() / 100);\n let year = century * 100 + Number(v.slice(0, 2));\n const month = Number(v.slice(2, 4));\n const day = Number(v.slice(4, 6));\n if (year > today.getFullYear()) {\n year -= 100;\n }\n if (!isValidDate(year, month, day)) return null;\n return { year, month, day };\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 13) {\n return err(\n \"INVALID_LENGTH\",\n \"SA ID must be exactly 13 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"SA ID must contain only digits\",\n );\n }\n if (resolveBirthDate(v) === null) {\n return err(\n \"INVALID_COMPONENT\",\n \"SA ID contains an invalid date of birth\",\n );\n }\n const citizenship = v[10];\n if (citizenship !== \"0\" && citizenship !== \"1\") {\n return err(\n \"INVALID_COMPONENT\",\n \"SA ID citizenship digit must be 0 or 1\",\n );\n }\n if (!luhnValidate(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"SA ID Luhn check digit mismatch\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n if (v.length === 13) {\n return `${v.slice(0, 6)} ${v.slice(6, 10)} ${v.slice(10, 12)} ${v.slice(12)}`;\n }\n return v;\n};\n\n/**\n * Extract birth date and gender from a South African\n * ID number. 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 bd = resolveBirthDate(v);\n if (bd === null) return null;\n\n const sequence = Number(v.slice(6, 10));\n\n return {\n birthDate: new Date(bd.year, bd.month - 1, bd.day),\n gender: sequence < 5000 ? \"female\" : \"male\",\n };\n};\n\n/** Generate a random valid South African ID. */\nconst generate = (): string => {\n for (;;) {\n const yy = String(randomInt(50, 99)).padStart(2, \"0\");\n const mm = String(randomInt(1, 12)).padStart(2, \"0\");\n const dd = String(randomInt(1, 28)).padStart(2, \"0\");\n const serial = randomDigits(4);\n const citizen = String(randomInt(0, 1));\n const payload = yy + mm + dd + serial + citizen + \"8\";\n const cs = luhnChecksum(payload + \"0\");\n const c = payload + String((10 - cs) % 10);\n if (validate(c).valid) return c;\n }\n};\n\n/** South African Identity Number. */\nconst idnr: Validator = {\n name: \"South African Identity Number\",\n localName: \"South African Identity Number\",\n abbreviation: \"SA ID\",\n aliases: [\"ID number\", \"RSA ID\"] as const,\n candidatePattern: \"\\\\d{13}\",\n country: \"ZA\",\n entityType: \"person\",\n compact,\n format,\n validate,\n description:\n \"South African personal identification number\",\n sourceUrl:\n \"https://en.wikipedia.org/wiki/\" +\n \"South_African_identity_document\",\n lengths: [13] as const,\n examples: [\"7503305044089\", \"8001015009087\"] as const,\n generate,\n};\n\nexport default idnr;\nexport { compact, format, parse, validate, generate };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA+BA,MAAM,WAAW,UACf,MAAM,OAAO,IAAI;;;;;;AAOnB,MAAM,oBACJ,MACwD;CACxD,MAAM,wBAAQ,IAAI,MAAM;CAExB,IAAI,OADY,KAAK,MAAM,MAAM,aAAa,GAAG,IAAI,GAChC,MAAM,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;CAChD,MAAM,QAAQ,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;CACnC,MAAM,MAAM,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;AACjC,KAAI,OAAO,MAAM,aAAa,CAC5B,SAAQ;AAEV,KAAI,CAAC,YAAY,MAAM,OAAO,IAAI,CAAE,QAAO;AAC3C,QAAO;EAAE;EAAM;EAAO;EAAK;;AAG7B,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,MAAM;AACxB,KAAI,EAAE,WAAW,GACf,QAAO,IACL,kBACA,kCACD;AAEH,KAAI,CAAC,SAAS,EAAE,CACd,QAAO,IACL,kBACA,iCACD;AAEH,KAAI,iBAAiB,EAAE,KAAK,KAC1B,QAAO,IACL,qBACA,0CACD;CAEH,MAAM,cAAc,EAAE;AACtB,KAAI,gBAAgB,OAAO,gBAAgB,IACzC,QAAO,IACL,qBACA,yCACD;AAEH,KAAI,CAAC,aAAa,EAAE,CAClB,QAAO,IACL,oBACA,kCACD;AAEH,QAAO;EAAE,OAAO;EAAM,SAAS;EAAG;;AAGpC,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,MAAM;AACxB,KAAI,EAAE,WAAW,GACf,QAAO,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,GAAG,EAAE,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG;AAE7E,QAAO;;;;;;AAOT,MAAM,SAAS,UAAyC;CACtD,MAAM,SAAS,SAAS,MAAM;AAC9B,KAAI,CAAC,OAAO,MAAO,QAAO;CAE1B,MAAM,IAAI,OAAO;CACjB,MAAM,KAAK,iBAAiB,EAAE;AAC9B,KAAI,OAAO,KAAM,QAAO;CAExB,MAAM,WAAW,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC;AAEvC,QAAO;EACL,WAAW,IAAI,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,GAAG,IAAI;EAClD,QAAQ,WAAW,MAAO,WAAW;EACtC;;;AAIH,MAAM,iBAAyB;AAC7B,UAAS;EACP,MAAM,KAAK,OAAO,UAAU,IAAI,GAAG,CAAC,CAAC,SAAS,GAAG,IAAI;EACrD,MAAM,KAAK,OAAO,UAAU,GAAG,GAAG,CAAC,CAAC,SAAS,GAAG,IAAI;EACpD,MAAM,KAAK,OAAO,UAAU,GAAG,GAAG,CAAC,CAAC,SAAS,GAAG,IAAI;EACpD,MAAM,SAAS,aAAa,EAAE;EAC9B,MAAM,UAAU,OAAO,UAAU,GAAG,EAAE,CAAC;EACvC,MAAM,UAAU,KAAK,KAAK,KAAK,SAAS,UAAU;EAClD,MAAM,KAAK,aAAa,UAAU,IAAI;EACtC,MAAM,IAAI,UAAU,QAAQ,KAAK,MAAM,GAAG;AAC1C,MAAI,SAAS,EAAE,CAAC,MAAO,QAAO;;;;AAKlC,MAAM,OAAkB;CACtB,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,aAAa,SAAS;CAChC,kBAAkB;CAClB,SAAS;CACT,YAAY;CACZ;CACA;CACA;CACA,aACE;CACF,WACE;CAEF,SAAS,CAAC,GAAG;CACb,UAAU,CAAC,iBAAiB,gBAAgB;CAC5C;CACD"}
1
+ {"version":3,"file":"idnr.js","names":[],"sources":["../../src/za/idnr.ts"],"sourcesContent":["/**\n * South African Identity Number.\n *\n * 13-digit number encoding date of birth, gender,\n * citizenship, and a Luhn check digit.\n * Format: YYMMDD SSSS C A Z\n * - YYMMDD: date of birth\n * - SSSS: sequence (0000-4999 female, 5000-9999 male)\n * - C: citizenship (0 = citizen, 1 = permanent resident)\n * - A: was used for race (now always 8 or 9)\n * - Z: Luhn check digit\n *\n * @see https://en.wikipedia.org/wiki/South_African_identity_document\n */\n\nimport {\n luhnValidate,\n luhnChecksum,\n} from \"#checksums/luhn\";\nimport { clean } from \"#util/clean\";\nimport { isValidDate } from \"#util/date\";\nimport { randomDigits, 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, \" \");\n\n/**\n * Resolve the birth date from the 2-digit year.\n * Years after the current year are assumed to be\n * in the previous century.\n */\nconst resolveBirthDate = (\n v: string,\n): { year: number; month: number; day: number } | null => {\n const today = new Date();\n const century = Math.floor(today.getFullYear() / 100);\n let year = century * 100 + Number(v.slice(0, 2));\n const month = Number(v.slice(2, 4));\n const day = Number(v.slice(4, 6));\n if (year > today.getFullYear()) {\n year -= 100;\n }\n if (!isValidDate(year, month, day)) return null;\n return { year, month, day };\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 13) {\n return err(\n \"INVALID_LENGTH\",\n \"SA ID must be exactly 13 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"SA ID must contain only digits\",\n );\n }\n if (resolveBirthDate(v) === null) {\n return err(\n \"INVALID_COMPONENT\",\n \"SA ID contains an invalid date of birth\",\n );\n }\n const citizenship = v[10];\n if (citizenship !== \"0\" && citizenship !== \"1\") {\n return err(\n \"INVALID_COMPONENT\",\n \"SA ID citizenship digit must be 0 or 1\",\n );\n }\n if (!luhnValidate(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"SA ID Luhn check digit mismatch\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n if (v.length === 13) {\n return `${v.slice(0, 6)} ${v.slice(6, 10)} ${v.slice(10, 12)} ${v.slice(12)}`;\n }\n return v;\n};\n\n/**\n * Extract birth date and gender from a South African\n * ID number. 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 bd = resolveBirthDate(v);\n if (bd === null) return null;\n\n const sequence = Number(v.slice(6, 10));\n\n return {\n birthDate: new Date(bd.year, bd.month - 1, bd.day),\n gender: sequence < 5000 ? \"female\" : \"male\",\n };\n};\n\n/** Generate a random valid South African ID. */\nconst generate = (): string => {\n for (;;) {\n const yy = String(randomInt(50, 99)).padStart(2, \"0\");\n const mm = String(randomInt(1, 12)).padStart(2, \"0\");\n const dd = String(randomInt(1, 28)).padStart(2, \"0\");\n const serial = randomDigits(4);\n const citizen = String(randomInt(0, 1));\n const payload = yy + mm + dd + serial + citizen + \"8\";\n const cs = luhnChecksum(payload + \"0\");\n const c = payload + String((10 - cs) % 10);\n if (validate(c).valid) return c;\n }\n};\n\n/** South African Identity Number. */\nconst idnr: Validator<ParsedPersonId> = {\n name: \"South African Identity Number\",\n localName: \"South African Identity Number\",\n abbreviation: \"SA ID\",\n aliases: [\"ID number\", \"RSA ID\"] as const,\n candidatePattern: \"\\\\d{13}\",\n country: \"ZA\",\n entityType: \"person\",\n compact,\n format,\n parse,\n validate,\n description:\n \"South African personal identification number\",\n sourceUrl:\n \"https://en.wikipedia.org/wiki/\" +\n \"South_African_identity_document\",\n lengths: [13] as const,\n examples: [\"7503305044089\", \"8001015009087\"] as const,\n generate,\n};\n\nexport default idnr;\nexport { compact, format, parse, validate, generate };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA+BA,MAAM,WAAW,UACf,MAAM,OAAO,IAAI;;;;;;AAOnB,MAAM,oBACJ,MACwD;CACxD,MAAM,wBAAQ,IAAI,MAAM;CAExB,IAAI,OADY,KAAK,MAAM,MAAM,aAAa,GAAG,IAAI,GAChC,MAAM,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;CAChD,MAAM,QAAQ,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;CACnC,MAAM,MAAM,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;AACjC,KAAI,OAAO,MAAM,aAAa,CAC5B,SAAQ;AAEV,KAAI,CAAC,YAAY,MAAM,OAAO,IAAI,CAAE,QAAO;AAC3C,QAAO;EAAE;EAAM;EAAO;EAAK;;AAG7B,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,MAAM;AACxB,KAAI,EAAE,WAAW,GACf,QAAO,IACL,kBACA,kCACD;AAEH,KAAI,CAAC,SAAS,EAAE,CACd,QAAO,IACL,kBACA,iCACD;AAEH,KAAI,iBAAiB,EAAE,KAAK,KAC1B,QAAO,IACL,qBACA,0CACD;CAEH,MAAM,cAAc,EAAE;AACtB,KAAI,gBAAgB,OAAO,gBAAgB,IACzC,QAAO,IACL,qBACA,yCACD;AAEH,KAAI,CAAC,aAAa,EAAE,CAClB,QAAO,IACL,oBACA,kCACD;AAEH,QAAO;EAAE,OAAO;EAAM,SAAS;EAAG;;AAGpC,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,MAAM;AACxB,KAAI,EAAE,WAAW,GACf,QAAO,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,GAAG,EAAE,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG;AAE7E,QAAO;;;;;;AAOT,MAAM,SAAS,UAAyC;CACtD,MAAM,SAAS,SAAS,MAAM;AAC9B,KAAI,CAAC,OAAO,MAAO,QAAO;CAE1B,MAAM,IAAI,OAAO;CACjB,MAAM,KAAK,iBAAiB,EAAE;AAC9B,KAAI,OAAO,KAAM,QAAO;CAExB,MAAM,WAAW,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC;AAEvC,QAAO;EACL,WAAW,IAAI,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,GAAG,IAAI;EAClD,QAAQ,WAAW,MAAO,WAAW;EACtC;;;AAIH,MAAM,iBAAyB;AAC7B,UAAS;EACP,MAAM,KAAK,OAAO,UAAU,IAAI,GAAG,CAAC,CAAC,SAAS,GAAG,IAAI;EACrD,MAAM,KAAK,OAAO,UAAU,GAAG,GAAG,CAAC,CAAC,SAAS,GAAG,IAAI;EACpD,MAAM,KAAK,OAAO,UAAU,GAAG,GAAG,CAAC,CAAC,SAAS,GAAG,IAAI;EACpD,MAAM,SAAS,aAAa,EAAE;EAC9B,MAAM,UAAU,OAAO,UAAU,GAAG,EAAE,CAAC;EACvC,MAAM,UAAU,KAAK,KAAK,KAAK,SAAS,UAAU;EAClD,MAAM,KAAK,aAAa,UAAU,IAAI;EACtC,MAAM,IAAI,UAAU,QAAQ,KAAK,MAAM,GAAG;AAC1C,MAAI,SAAS,EAAE,CAAC,MAAO,QAAO;;;;AAKlC,MAAM,OAAkC;CACtC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,aAAa,SAAS;CAChC,kBAAkB;CAClB,SAAS;CACT,YAAY;CACZ;CACA;CACA;CACA;CACA,aACE;CACF,WACE;CAEF,SAAS,CAAC,GAAG;CACb,UAAU,CAAC,iBAAiB,gBAAgB;CAC5C;CACD"}
package/dist/za/mod.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- import { __exportAll } from "../_virtual/_rolldown/runtime.js";
2
1
  import idnr from "./idnr.js";
3
2
 
4
3
  //#region src/za/mod.d.ts
5
-
4
+ declare namespace mod_d_exports {
5
+ export { idnr };
6
+ }
6
7
  //#endregion
7
8
  export { idnr, mod_d_exports };
8
9
  //# sourceMappingURL=mod.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stll/stdnum",
3
- "version": "0.0.1",
4
- "description": "Validate, compact, and format standard identifiers (IČO, IBAN, VAT, birth numbers, credit cards). Pure TypeScript, zero dependencies.",
3
+ "version": "1.0.0",
4
+ "description": "Validate, compact, and format standard identifiers for Node.js and Bun. Pure TypeScript, zero dependencies, tree-shakeable per identifier.",
5
5
  "keywords": [
6
6
  "credit-card",
7
7
  "czech",
@@ -31,10 +31,6 @@
31
31
  "main": "dist/index.js",
32
32
  "module": "dist/index.js",
33
33
  "types": "dist/index.d.ts",
34
- "imports": {
35
- "#checksums/*": "./dist/_checksums/*.js",
36
- "#util/*": "./dist/_util/*.js"
37
- },
38
34
  "exports": {
39
35
  ".": {
40
36
  "types": "./dist/index.d.ts",
@@ -902,15 +898,24 @@
902
898
  "default": "./dist/za/idnr.js"
903
899
  }
904
900
  },
901
+ "publishConfig": {
902
+ "access": "public"
903
+ },
905
904
  "scripts": {
906
905
  "build": "tsdown",
907
- "prepublishOnly": "bun run build",
906
+ "prepublishOnly": "bun run typecheck && bun run build && bun run sync-exports:check",
908
907
  "catalog": "bun scripts/catalog.ts",
908
+ "sync-ai": "bash scripts/sync-ai-skills.sh",
909
909
  "sync-exports": "bun scripts/sync-exports.ts",
910
+ "sync-exports:check": "bun scripts/sync-exports.ts --check",
910
911
  "test": "bun test",
911
- "oracle": "bun scripts/oracle.ts",
912
- "lint": "oxlint .",
913
- "format": "oxfmt ."
912
+ "oracle": "bun scripts/oracle.ts --mode=gate",
913
+ "oracle:gate": "bun scripts/oracle.ts --mode=gate",
914
+ "oracle:survey": "bun scripts/oracle.ts --mode=survey",
915
+ "lint": "oxlint . --deny-warnings",
916
+ "format": "oxfmt .",
917
+ "format:check": "oxfmt --check .",
918
+ "typecheck": "tsc -p tsconfig.json"
914
919
  },
915
920
  "devDependencies": {
916
921
  "bun-types": "^1.3.10",
@@ -923,14 +928,12 @@
923
928
  "oxfmt": "^0.41.0",
924
929
  "oxlint": "^1.55.0",
925
930
  "stdnum": "^1.11.7",
926
- "tsdown": "^0.12.4",
931
+ "tsdown": "0.21.6",
927
932
  "typescript": "^5.9.3",
928
933
  "validate-polish": "^2.1.40"
929
934
  },
930
- "publishConfig": {
931
- "access": "restricted"
932
- },
933
935
  "engines": {
934
936
  "node": ">= 18"
935
- }
937
+ },
938
+ "packageManager": "bun@1.3.12"
936
939
  }
@@ -23,10 +23,11 @@ export const mod112checkChar = (
23
23
  payload: string,
24
24
  ): string => {
25
25
  let sum = 0;
26
- for (let i = 0; i < 17; i++) {
27
- sum += Number(payload[i]) * WEIGHTS[i]!;
26
+ for (const [i, weight] of WEIGHTS.entries()) {
27
+ sum += Number(payload[i]) * weight;
28
28
  }
29
- return CHECK_CHARS[sum % 11]!;
29
+ // SAFETY: sum % 11 is in 0..10 and CHECK_CHARS has 11 chars.
30
+ return CHECK_CHARS[sum % 11] ?? "";
30
31
  };
31
32
 
32
33
  /**
@@ -34,7 +35,7 @@ export const mod112checkChar = (
34
35
  * check character (last char is 0-9 or X).
35
36
  */
36
37
  export const mod112validate = (value: string): boolean => {
37
- const payload = value.slice(0, 17);
38
- const check = value[17]!.toUpperCase();
39
- return mod112checkChar(payload) === check;
38
+ const check = value[17]?.toUpperCase();
39
+ if (check === undefined) return false;
40
+ return mod112checkChar(value.slice(0, 17)) === check;
40
41
  };
@@ -22,3 +22,41 @@ export const randomInt = (
22
22
  max: number,
23
23
  ): number =>
24
24
  min + Math.floor(Math.random() * (max - min + 1));
25
+
26
+ /**
27
+ * Pick a random element from a non-empty array.
28
+ * Throws if the array is empty so generators that
29
+ * declare a fixed pool fail loudly instead of
30
+ * returning `undefined`.
31
+ */
32
+ export const randomPick = <T>(values: readonly T[]): T => {
33
+ if (values.length === 0) {
34
+ throw new Error("randomPick called with empty array");
35
+ }
36
+ const idx = randomInt(0, values.length - 1);
37
+ // SAFETY: idx is bounded by values.length and the
38
+ // array is non-empty (checked above).
39
+ const value = values[idx];
40
+ if (value === undefined) {
41
+ throw new Error("randomPick produced undefined");
42
+ }
43
+ return value;
44
+ };
45
+
46
+ /**
47
+ * Pick a random character from a non-empty string.
48
+ * Same contract as `randomPick` for arrays.
49
+ */
50
+ export const randomChar = (chars: string): string => {
51
+ if (chars.length === 0) {
52
+ throw new Error("randomChar called with empty string");
53
+ }
54
+ const idx = randomInt(0, chars.length - 1);
55
+ // SAFETY: idx is bounded by chars.length and the
56
+ // string is non-empty (checked above).
57
+ const ch = chars[idx];
58
+ if (ch === undefined) {
59
+ throw new Error("randomChar produced undefined");
60
+ }
61
+ return ch;
62
+ };
package/src/ad/nrt.ts CHANGED
@@ -1,8 +1,8 @@
1
+ const NRT_PREFIXES = "CDEGOPU";
2
+
1
3
  /** Generate a random valid Andorra NRT. */
2
4
  const generate = (): string => {
3
- const prefixes = "CDEGOPU";
4
- const prefix =
5
- prefixes[randomInt(0, prefixes.length - 1)]!;
5
+ const prefix = randomChar(NRT_PREFIXES);
6
6
  const digits = randomDigits(6);
7
7
  const suffix = String.fromCodePoint(
8
8
  65 + randomInt(0, 25),
@@ -26,7 +26,11 @@ const generate = (): string => {
26
26
  */
27
27
 
28
28
  import { clean } from "#util/clean";
29
- import { randomDigits, randomInt } from "#util/generate";
29
+ import {
30
+ randomChar,
31
+ randomDigits,
32
+ randomInt,
33
+ } from "#util/generate";
30
34
  import { err } from "#util/result";
31
35
  import { isdigits } from "#util/strings";
32
36
 
@@ -45,7 +49,11 @@ const validate = (value: string): ValidateResult => {
45
49
  "Andorra NRT must be 8 characters",
46
50
  );
47
51
  }
52
+ // SAFETY: v.length === 8 guarantees both positions
53
+ // exist; oxlint cannot see the length guard.
54
+ // eslint-disable-next-line no-non-null-assertion
48
55
  const prefix = v[0]!;
56
+ // eslint-disable-next-line no-non-null-assertion
49
57
  const tail = v[7]!;
50
58
  const digits = v.slice(1, 7);
51
59
  if (!/^[A-Z]$/.test(prefix) || !/^[A-Z]$/.test(tail)) {
package/src/ar/cbu.ts CHANGED
@@ -28,8 +28,8 @@ const calcCheck = (
28
28
  weights: readonly number[],
29
29
  ): number => {
30
30
  let sum = 0;
31
- for (let i = 0; i < digits.length; i++) {
32
- sum += Number(digits[i]) * weights[i]!;
31
+ for (const [i, weight] of weights.entries()) {
32
+ sum += Number(digits[i]) * weight;
33
33
  }
34
34
  return (10 - (sum % 10)) % 10;
35
35
  };
package/src/ar/cuit.ts CHANGED
@@ -17,7 +17,7 @@
17
17
  */
18
18
 
19
19
  import { clean } from "#util/clean";
20
- import { randomDigits } from "#util/generate";
20
+ import { randomDigits, randomPick } from "#util/generate";
21
21
  import { err } from "#util/result";
22
22
  import { isdigits } from "#util/strings";
23
23
 
@@ -36,7 +36,17 @@ const VALID_TYPES = new Set([
36
36
  "55",
37
37
  ]);
38
38
 
39
- const WEIGHTS = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];
39
+ const WEIGHTS = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2] as const;
40
+
41
+ const GENERATE_TYPES = [
42
+ "20",
43
+ "23",
44
+ "24",
45
+ "27",
46
+ "30",
47
+ "33",
48
+ "34",
49
+ ] as const;
40
50
 
41
51
  const compact = (value: string): string =>
42
52
  clean(value, " -.").trim();
@@ -49,8 +59,8 @@ const compact = (value: string): string =>
49
59
  */
50
60
  const calcCheckDigit = (body: string): number => {
51
61
  let sum = 0;
52
- for (let i = 0; i < 10; i++) {
53
- sum += Number(body[i]) * WEIGHTS[i]!;
62
+ for (const [i, weight] of WEIGHTS.entries()) {
63
+ sum += Number(body[i]) * weight;
54
64
  }
55
65
  const remainder = 11 - (sum % 11);
56
66
  if (remainder === 11) return 0;
@@ -98,9 +108,7 @@ const format = (value: string): string => {
98
108
 
99
109
  /** Generate a random valid CUIT. */
100
110
  const generate = (): string => {
101
- const types = ["20", "23", "24", "27", "30", "33", "34"];
102
- const type =
103
- types[Math.floor(Math.random() * types.length)]!;
111
+ const type = randomPick(GENERATE_TYPES);
104
112
  const body = type + randomDigits(8);
105
113
  const check = calcCheckDigit(body);
106
114
  return body + String(check);
package/src/at/vnr.ts CHANGED
@@ -11,6 +11,7 @@
11
11
  */
12
12
 
13
13
  import { clean } from "#util/clean";
14
+ import { randomDigits, randomInt } from "#util/generate";
14
15
  import { err } from "#util/result";
15
16
  import { isdigits } from "#util/strings";
16
17
 
@@ -21,7 +22,7 @@ import type { ValidateResult, Validator } from "../types";
21
22
  * 0,1,2, then 4,5,6,7,8,9). Check digit is at
22
23
  * position 3 and equals the weighted sum mod 11.
23
24
  */
24
- const WEIGHTS = [3, 7, 9, 5, 8, 4, 2, 1, 6];
25
+ const WEIGHTS = [3, 7, 9, 5, 8, 4, 2, 1, 6] as const;
25
26
 
26
27
  const compact = (value: string): string =>
27
28
  clean(value, " -/").trim();
@@ -58,8 +59,8 @@ const validate = (value: string): ValidateResult => {
58
59
  // number is invalid.
59
60
  const digits = v.slice(0, 3) + v.slice(4);
60
61
  let sum = 0;
61
- for (let i = 0; i < 9; i++) {
62
- sum += Number(digits[i]) * WEIGHTS[i]!;
62
+ for (const [i, weight] of WEIGHTS.entries()) {
63
+ sum += Number(digits[i]) * weight;
63
64
  }
64
65
  const check = sum % 11;
65
66
  if (check === 10) {
@@ -84,6 +85,26 @@ const format = (value: string): string => {
84
85
  return `${v.slice(0, 4)} ${v.slice(4, 6)}${v.slice(6, 8)}${v.slice(8)}`;
85
86
  };
86
87
 
88
+ /** Generate a random valid Austrian VNR. */
89
+ const generate = (): string => {
90
+ for (;;) {
91
+ const serial = randomDigits(3);
92
+ const day = String(randomInt(1, 28)).padStart(2, "0");
93
+ const month = String(randomInt(1, 12)).padStart(2, "0");
94
+ const year = String(randomInt(0, 99)).padStart(2, "0");
95
+ const digits = `${serial}${day}${month}${year}`;
96
+
97
+ let sum = 0;
98
+ for (const [i, weight] of WEIGHTS.entries()) {
99
+ sum += Number(digits[i]) * weight;
100
+ }
101
+
102
+ const check = sum % 11;
103
+ if (check === 10) continue;
104
+ return `${serial}${String(check)}${day}${month}${year}`;
105
+ }
106
+ };
107
+
87
108
  /** Austrian Social Insurance Number. */
88
109
  const vnr: Validator = {
89
110
  name: "Austrian Social Insurance Number",
@@ -105,7 +126,8 @@ const vnr: Validator = {
105
126
  compact,
106
127
  format,
107
128
  validate,
129
+ generate,
108
130
  };
109
131
 
110
132
  export default vnr;
111
- export { compact, format, validate };
133
+ export { compact, format, generate, validate };
package/src/az/voen.ts CHANGED
@@ -63,6 +63,8 @@ const validate = (value: string): ValidateResult => {
63
63
  );
64
64
  }
65
65
 
66
+ // SAFETY: regex above guarantees length === 10.
67
+ // eslint-disable-next-line no-non-null-assertion
66
68
  const lastDigit = v[9]!;
67
69
  if (lastDigit !== "1" && lastDigit !== "2") {
68
70
  return err(
package/src/ba/jmbg.ts CHANGED
@@ -106,7 +106,7 @@ const generate = (): string => {
106
106
  };
107
107
 
108
108
  /** Bosnian Unique Master Citizen Number. */
109
- const jmbg: Validator = {
109
+ const jmbg: Validator<ParsedPersonId> = {
110
110
  name: "Bosnian Personal ID",
111
111
  localName: "Jedinstveni matični broj građana",
112
112
  abbreviation: "JMBG",
@@ -120,6 +120,7 @@ const jmbg: Validator = {
120
120
  examples: ["0101006500006"] as const,
121
121
  compact,
122
122
  format,
123
+ parse,
123
124
  validate,
124
125
  generate,
125
126
  };
package/src/bd/nid.ts CHANGED
@@ -1,9 +1,9 @@
1
+ const RMO_VALUES = ["1", "2", "3", "4", "5", "9"] as const;
2
+
1
3
  /** Generate a random valid Bangladesh NID (13-digit). */
2
4
  const generate = (): string => {
3
5
  const district = randomDigits(2);
4
- const rmoValues = ["1", "2", "3", "4", "5", "9"];
5
- const rmo =
6
- rmoValues[randomInt(0, rmoValues.length - 1)]!;
6
+ const rmo = randomPick(RMO_VALUES);
7
7
  const rest = randomDigits(10);
8
8
  return `${district}${rmo}${rest}`;
9
9
  };
@@ -31,7 +31,7 @@ const generate = (): string => {
31
31
  */
32
32
 
33
33
  import { clean } from "#util/clean";
34
- import { randomDigits, randomInt } from "#util/generate";
34
+ import { randomDigits, randomPick } from "#util/generate";
35
35
  import { err } from "#util/result";
36
36
  import { isdigits } from "#util/strings";
37
37
 
package/src/bg/egn.ts CHANGED
@@ -5,8 +5,14 @@
5
5
  * 10 digits encoding date of birth, serial number,
6
6
  * and a check digit.
7
7
  *
8
- * @see https://en.wikipedia.org/wiki/Unique_citizenship_number
9
- * @see https://www.grao.bg/
8
+ * Canonical source:
9
+ * - GRAO regulation PDF describing the EGN structure.
10
+ *
11
+ * We treat this as authoritative over third-party
12
+ * oracle libraries when the checksum or date rules
13
+ * disagree.
14
+ *
15
+ * @see https://www.grao.bg/normact/NaredbaFunkcESGR.pdf
10
16
  */
11
17
 
12
18
  import { weightedSum } from "#checksums/weighted-sum";
@@ -131,7 +137,7 @@ const generate = (): string => {
131
137
  };
132
138
 
133
139
  /** Bulgarian Personal Identification Number. */
134
- const egn: Validator = {
140
+ const egn: Validator<ParsedPersonId> = {
135
141
  name: "Bulgarian Personal ID",
136
142
  localName: "Единен граждански номер",
137
143
  abbreviation: "ЕГН",
@@ -143,10 +149,12 @@ const egn: Validator = {
143
149
  candidatePattern: "\\d{10}",
144
150
  country: "BG",
145
151
  entityType: "person",
146
- sourceUrl: "https://www.grao.bg/",
152
+ sourceUrl:
153
+ "https://www.grao.bg/normact/NaredbaFunkcESGR.pdf",
147
154
  examples: ["7523169263"] as const,
148
155
  compact,
149
156
  format,
157
+ parse,
150
158
  validate,
151
159
  generate,
152
160
  };
package/src/bh/cpr.ts CHANGED
@@ -17,6 +17,7 @@
17
17
  */
18
18
 
19
19
  import { clean } from "#util/clean";
20
+ import { randomDigits, randomInt } from "#util/generate";
20
21
  import { err } from "#util/result";
21
22
  import { isdigits } from "#util/strings";
22
23
 
@@ -59,6 +60,13 @@ const format = (value: string): string => {
59
60
  return `${v.slice(0, 2)}-${v.slice(2, 4)}-${v.slice(4)}`;
60
61
  };
61
62
 
63
+ /** Generate a random structurally valid Bahrain CPR. */
64
+ const generate = (): string => {
65
+ const yy = String(randomInt(0, 99)).padStart(2, "0");
66
+ const mm = String(randomInt(1, 12)).padStart(2, "0");
67
+ return `${yy}${mm}${randomDigits(5)}`;
68
+ };
69
+
62
70
  /** Bahrain Central Population Registration number. */
63
71
  const cpr: Validator = {
64
72
  name: "Central Population Registration Number",
@@ -75,7 +83,8 @@ const cpr: Validator = {
75
83
  compact,
76
84
  format,
77
85
  validate,
86
+ generate,
78
87
  };
79
88
 
80
89
  export default cpr;
81
- export { compact, format, validate };
90
+ export { compact, format, generate, validate };
package/src/bic.ts CHANGED
@@ -1,28 +1,26 @@
1
+ const BIC_ALPHANUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
2
+ const BIC_COUNTRIES = [
3
+ "DE",
4
+ "GB",
5
+ "US",
6
+ "FR",
7
+ "CH",
8
+ "NL",
9
+ "AT",
10
+ ] as const;
11
+
1
12
  /** Generate a random valid BIC (8-character). */
2
13
  const generate = (): string => {
3
14
  const randomLetter = (): string =>
4
15
  String.fromCodePoint(65 + randomInt(0, 25));
5
- const randomAlphaNum = (): string => {
6
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
7
- return chars[randomInt(0, chars.length - 1)]!;
8
- };
9
- const countries = [
10
- "DE",
11
- "GB",
12
- "US",
13
- "FR",
14
- "CH",
15
- "NL",
16
- "AT",
17
- ];
18
- const country =
19
- countries[randomInt(0, countries.length - 1)]!;
16
+ const country = randomPick(BIC_COUNTRIES);
20
17
  const bank =
21
18
  randomLetter() +
22
19
  randomLetter() +
23
20
  randomLetter() +
24
21
  randomLetter();
25
- const location = randomAlphaNum() + randomAlphaNum();
22
+ const location =
23
+ randomChar(BIC_ALPHANUM) + randomChar(BIC_ALPHANUM);
26
24
  return `${bank}${country}${location}`;
27
25
  };
28
26
 
@@ -39,7 +37,11 @@ const generate = (): string => {
39
37
  */
40
38
 
41
39
  import { clean } from "#util/clean";
42
- import { randomInt } from "#util/generate";
40
+ import {
41
+ randomChar,
42
+ randomInt,
43
+ randomPick,
44
+ } from "#util/generate";
43
45
  import { err } from "#util/result";
44
46
 
45
47
  import type { ValidateResult, Validator } from "./types";
package/src/by/unp.ts CHANGED
@@ -52,16 +52,19 @@ const compact = (value: string): string => {
52
52
  const calcCheckDigit = (number: string): number | null => {
53
53
  let work = number;
54
54
  if (!isdigits(number)) {
55
- const idx = ALPHA_SET.indexOf(number[1]!);
55
+ const second = number[1];
56
+ if (second === undefined) return null;
57
+ const idx = ALPHA_SET.indexOf(second);
56
58
  if (idx === -1) return null;
57
59
  work = number[0] + String(idx) + number.slice(2);
58
60
  }
59
61
  let sum = 0;
60
- for (let i = 0; i < 8; i++) {
61
- const ch = work[i]!;
62
+ for (const [i, weight] of WEIGHTS.entries()) {
63
+ const ch = work[i];
64
+ if (ch === undefined) return null;
62
65
  const val = ALPHABET.indexOf(ch);
63
66
  if (val === -1) return null;
64
- sum += (WEIGHTS[i] ?? 0) * val;
67
+ sum += weight * val;
65
68
  }
66
69
  const remainder = sum % 11;
67
70
  if (remainder > 9) return null;
@@ -93,6 +96,8 @@ const validate = (value: string): ValidateResult => {
93
96
  " digits or letters from ABCEHKMOPT",
94
97
  );
95
98
  }
99
+ // SAFETY: v.length === 9 guarantees v[0] exists.
100
+ // eslint-disable-next-line no-non-null-assertion
96
101
  if (!VALID_FIRST.includes(v[0]!)) {
97
102
  return err(
98
103
  "INVALID_COMPONENT",