@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
package/dist/fi/hetu.js CHANGED
@@ -1,18 +1,9 @@
1
1
  import { clean } from "../_util/clean.js";
2
+ import { isValidDate } from "../_util/date.js";
2
3
  import { randomInt } from "../_util/generate.js";
3
4
  import { err } from "../_util/result.js";
4
5
  import { isdigits } from "../_util/strings.js";
5
- import { isValidDate } from "../_util/date.js";
6
6
  //#region src/fi/hetu.ts
7
- /**
8
- * HETU (Henkilötunnus).
9
- *
10
- * Finnish personal identity code. 11 characters in
11
- * format DDMMYY+CCC+X where the separator indicates
12
- * the century and X is a check character.
13
- *
14
- * @see https://dvv.fi/en/personal-identity-code
15
- */
16
7
  const CHECK_CHARS = "0123456789ABCDEFHJKLMNPRSTUVWXY";
17
8
  const SEPARATORS_1800 = new Set(["+"]);
18
9
  const SEPARATORS_1900 = new Set([
@@ -105,6 +96,7 @@ const hetu = {
105
96
  "sosiaaliturvatunnus"
106
97
  ],
107
98
  candidatePattern: "\\d{6}[-+A]\\d{3}[\\dA-Z]",
99
+ scope: "country",
108
100
  country: "FI",
109
101
  entityType: "person",
110
102
  sourceUrl: "https://dvv.fi/en/personal-identity-code",
@@ -1 +1 @@
1
- {"version":3,"file":"hetu.js","names":[],"sources":["../../src/fi/hetu.ts"],"sourcesContent":["/**\n * HETU (Henkilötunnus).\n *\n * Finnish personal identity code. 11 characters in\n * format DDMMYY+CCC+X where the separator indicates\n * the century and X is a check character.\n *\n * @see https://dvv.fi/en/personal-identity-code\n */\n\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 CHECK_CHARS = \"0123456789ABCDEFHJKLMNPRSTUVWXY\";\n\nconst SEPARATORS_1800 = new Set([\"+\"]);\nconst SEPARATORS_1900 = new Set([\n \"-\",\n \"Y\",\n \"X\",\n \"W\",\n \"V\",\n \"U\",\n]);\nconst SEPARATORS_2000 = new Set([\n \"A\",\n \"B\",\n \"C\",\n \"D\",\n \"E\",\n \"F\",\n]);\n\nconst compact = (value: string): string =>\n clean(value, \" \").toUpperCase();\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 11) {\n return err(\n \"INVALID_LENGTH\",\n \"HETU must be exactly 11 characters\",\n );\n }\n\n const dd = v.slice(0, 2);\n const mm = v.slice(2, 4);\n const yy = v.slice(4, 6);\n const separator = v.charAt(6);\n const serial = v.slice(7, 10);\n const checkChar = v.charAt(10);\n\n if (!isdigits(dd) || !isdigits(mm) || !isdigits(yy)) {\n return err(\n \"INVALID_FORMAT\",\n \"HETU date part must be digits\",\n );\n }\n if (!isdigits(serial)) {\n return err(\n \"INVALID_FORMAT\",\n \"HETU serial must be digits\",\n );\n }\n\n let century: number;\n if (SEPARATORS_1800.has(separator)) {\n century = 1800;\n } else if (SEPARATORS_1900.has(separator)) {\n century = 1900;\n } else if (SEPARATORS_2000.has(separator)) {\n century = 2000;\n } else {\n return err(\n \"INVALID_COMPONENT\",\n \"HETU separator is invalid\",\n );\n }\n\n const year = century + Number(yy);\n const month = Number(mm);\n const day = Number(dd);\n\n if (!isValidDate(year, month, day)) {\n return err(\n \"INVALID_COMPONENT\",\n \"HETU contains an invalid date\",\n );\n }\n\n // Individual number must be >= 002\n const serialNum = Number(serial);\n if (serialNum < 2) {\n return err(\n \"INVALID_COMPONENT\",\n \"HETU individual number must be >= 002\",\n );\n }\n // Temporary range 900-999 is not valid\n if (serialNum >= 900) {\n return err(\n \"INVALID_COMPONENT\",\n \"HETU temporary individual range 900-999\",\n );\n }\n\n const checkNum = Number(`${dd}${mm}${yy}${serial}`);\n const expected = CHECK_CHARS.charAt(checkNum % 31);\n if (checkChar !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"HETU 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 a HETU.\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 dd = Number(v.slice(0, 2));\n const mm = Number(v.slice(2, 4));\n const yy = Number(v.slice(4, 6));\n const separator = v.charAt(6);\n const serial = Number(v.slice(7, 10));\n\n let century: number;\n if (SEPARATORS_1800.has(separator)) {\n century = 1800;\n } else if (SEPARATORS_1900.has(separator)) {\n century = 1900;\n } else {\n century = 2000;\n }\n\n const year = century + yy;\n\n return {\n birthDate: new Date(year, mm - 1, dd),\n gender: serial % 2 === 0 ? \"female\" : \"male\",\n };\n};\n\n/** Generate a random valid HETU. */\nconst generate = (): string => {\n const year = randomInt(1900, 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 separator = year >= 2000 ? \"A\" : \"-\";\n const serial = String(randomInt(2, 899)).padStart(3, \"0\");\n const checkNum = Number(`${day}${month}${yy}${serial}`);\n const checkChar = CHECK_CHARS.charAt(checkNum % 31);\n return `${day}${month}${yy}${separator}${serial}${checkChar}`;\n};\n\n/** Finnish Personal Identity Code. */\nconst hetu: Validator<ParsedPersonId> = {\n name: \"Finnish Personal ID\",\n localName: \"Henkilötunnus\",\n abbreviation: \"HETU\",\n aliases: [\n \"henkilötunnus\",\n \"HETU\",\n \"sosiaaliturvatunnus\",\n ] as const,\n candidatePattern: \"\\\\d{6}[-+A]\\\\d{3}[\\\\dA-Z]\",\n country: \"FI\",\n entityType: \"person\",\n sourceUrl: \"https://dvv.fi/en/personal-identity-code\",\n lengths: [11] as const,\n examples: [\"131052-308T\"] as const,\n compact,\n format,\n parse,\n validate,\n generate,\n};\n\nexport default hetu;\nexport { compact, format, generate, parse, validate };\n"],"mappings":"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"}
1
+ {"version":3,"file":"hetu.js","names":[],"sources":["../../src/fi/hetu.ts"],"sourcesContent":["/**\n * HETU (Henkilötunnus).\n *\n * Finnish personal identity code. 11 characters in\n * format DDMMYY+CCC+X where the separator indicates\n * the century and X is a check character.\n *\n * @see https://dvv.fi/en/personal-identity-code\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 { randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst CHECK_CHARS = \"0123456789ABCDEFHJKLMNPRSTUVWXY\";\n\nconst SEPARATORS_1800 = new Set([\"+\"]);\nconst SEPARATORS_1900 = new Set([\n \"-\",\n \"Y\",\n \"X\",\n \"W\",\n \"V\",\n \"U\",\n]);\nconst SEPARATORS_2000 = new Set([\n \"A\",\n \"B\",\n \"C\",\n \"D\",\n \"E\",\n \"F\",\n]);\n\nconst compact = (value: string): string =>\n clean(value, \" \").toUpperCase();\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 11) {\n return err(\n \"INVALID_LENGTH\",\n \"HETU must be exactly 11 characters\",\n );\n }\n\n const dd = v.slice(0, 2);\n const mm = v.slice(2, 4);\n const yy = v.slice(4, 6);\n const separator = v.charAt(6);\n const serial = v.slice(7, 10);\n const checkChar = v.charAt(10);\n\n if (!isdigits(dd) || !isdigits(mm) || !isdigits(yy)) {\n return err(\n \"INVALID_FORMAT\",\n \"HETU date part must be digits\",\n );\n }\n if (!isdigits(serial)) {\n return err(\n \"INVALID_FORMAT\",\n \"HETU serial must be digits\",\n );\n }\n\n let century: number;\n if (SEPARATORS_1800.has(separator)) {\n century = 1800;\n } else if (SEPARATORS_1900.has(separator)) {\n century = 1900;\n } else if (SEPARATORS_2000.has(separator)) {\n century = 2000;\n } else {\n return err(\n \"INVALID_COMPONENT\",\n \"HETU separator is invalid\",\n );\n }\n\n const year = century + Number(yy);\n const month = Number(mm);\n const day = Number(dd);\n\n if (!isValidDate(year, month, day)) {\n return err(\n \"INVALID_COMPONENT\",\n \"HETU contains an invalid date\",\n );\n }\n\n // Individual number must be >= 002\n const serialNum = Number(serial);\n if (serialNum < 2) {\n return err(\n \"INVALID_COMPONENT\",\n \"HETU individual number must be >= 002\",\n );\n }\n // Temporary range 900-999 is not valid\n if (serialNum >= 900) {\n return err(\n \"INVALID_COMPONENT\",\n \"HETU temporary individual range 900-999\",\n );\n }\n\n const checkNum = Number(`${dd}${mm}${yy}${serial}`);\n const expected = CHECK_CHARS.charAt(checkNum % 31);\n if (checkChar !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"HETU 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 a HETU.\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 dd = Number(v.slice(0, 2));\n const mm = Number(v.slice(2, 4));\n const yy = Number(v.slice(4, 6));\n const separator = v.charAt(6);\n const serial = Number(v.slice(7, 10));\n\n let century: number;\n if (SEPARATORS_1800.has(separator)) {\n century = 1800;\n } else if (SEPARATORS_1900.has(separator)) {\n century = 1900;\n } else {\n century = 2000;\n }\n\n const year = century + yy;\n\n return {\n birthDate: new Date(year, mm - 1, dd),\n gender: serial % 2 === 0 ? \"female\" : \"male\",\n };\n};\n\n/** Generate a random valid HETU. */\nconst generate = (): string => {\n const year = randomInt(1900, 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 separator = year >= 2000 ? \"A\" : \"-\";\n const serial = String(randomInt(2, 899)).padStart(3, \"0\");\n const checkNum = Number(`${day}${month}${yy}${serial}`);\n const checkChar = CHECK_CHARS.charAt(checkNum % 31);\n return `${day}${month}${yy}${separator}${serial}${checkChar}`;\n};\n\n/** Finnish Personal Identity Code. */\nconst hetu: CountryValidator<\"FI\", ParsedPersonId> = {\n name: \"Finnish Personal ID\",\n localName: \"Henkilötunnus\",\n abbreviation: \"HETU\",\n aliases: [\n \"henkilötunnus\",\n \"HETU\",\n \"sosiaaliturvatunnus\",\n ] as const,\n candidatePattern: \"\\\\d{6}[-+A]\\\\d{3}[\\\\dA-Z]\",\n scope: \"country\",\n country: \"FI\",\n entityType: \"person\",\n sourceUrl: \"https://dvv.fi/en/personal-identity-code\",\n lengths: [11] as const,\n examples: [\"131052-308T\"] as const,\n compact,\n format,\n parse,\n validate,\n generate,\n};\n\nexport default hetu;\nexport { compact, format, generate, parse, validate };\n"],"mappings":"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"}
package/dist/fi/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/fi/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 Finnish VAT number. */
8
8
  declare const generate: () => string;
9
9
  /** Finnish VAT Number. */
10
- declare const vat: Validator;
10
+ declare const vat: CountryValidator<"FI">;
11
11
  //#endregion
12
12
  export { compact, vat as default, format, generate, validate };
13
13
  //# sourceMappingURL=vat.d.ts.map
package/dist/fi/vat.js CHANGED
@@ -1,18 +1,9 @@
1
+ import { weightedSum } from "../_checksums/weighted-sum.js";
1
2
  import { clean } from "../_util/clean.js";
2
3
  import { randomDigits } 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
  //#region src/fi/vat.ts
7
- /**
8
- * ALV nro (Finnish VAT number).
9
- *
10
- * 8 digits. Weights [7,9,10,5,8,4,2,1],
11
- * sum % 11 === 0.
12
- *
13
- * @see https://www.vatify.eu/finland-vat-number.html
14
- * @see https://www.ytj.fi/en/index/businessid.html
15
- */
16
7
  const WEIGHTS = [
17
8
  7,
18
9
  9,
@@ -53,9 +44,11 @@ const vat = {
53
44
  abbreviation: "ALV nro",
54
45
  aliases: ["ALV-numero", "Y-tunnus"],
55
46
  candidatePattern: "FI\\d{8}",
47
+ scope: "country",
56
48
  country: "FI",
57
49
  entityType: "company",
58
50
  sourceUrl: "https://www.ytj.fi/en/index/businessid.html",
51
+ lengths: [8],
59
52
  examples: ["20774740"],
60
53
  compact,
61
54
  format,
@@ -1 +1 @@
1
- {"version":3,"file":"vat.js","names":[],"sources":["../../src/fi/vat.ts"],"sourcesContent":["/**\n * ALV nro (Finnish VAT number).\n *\n * 8 digits. Weights [7,9,10,5,8,4,2,1],\n * sum % 11 === 0.\n *\n * @see https://www.vatify.eu/finland-vat-number.html\n * @see https://www.ytj.fi/en/index/businessid.html\n */\n\nimport { weightedSum } from \"#checksums/weighted-sum\";\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 = [7, 9, 10, 5, 8, 4, 2, 1];\n\nconst compact = (value: string): string => {\n let v = clean(value, \" -/.\");\n if (v.startsWith(\"FI\") || v.startsWith(\"fi\")) {\n v = v.slice(2);\n }\n return v;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 8) {\n return err(\n \"INVALID_LENGTH\",\n \"Finnish VAT number must be 8 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"Finnish VAT number must contain only digits\",\n );\n }\n const sum = weightedSum(v, WEIGHTS, 11);\n if (sum !== 0) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Finnish VAT number check digit mismatch\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string =>\n `FI${compact(value)}`;\n\n/** Generate a random valid Finnish VAT number. */\nconst generate = (): string => {\n for (;;) {\n const c = randomDigits(8);\n if (validate(c).valid) return c;\n }\n};\n\n/** Finnish VAT Number. */\nconst vat: Validator = {\n name: \"Finnish VAT Number\",\n localName: \"Arvonlisäveronumero\",\n abbreviation: \"ALV nro\",\n aliases: [\"ALV-numero\", \"Y-tunnus\"] as const,\n candidatePattern: \"FI\\\\d{8}\",\n country: \"FI\",\n entityType: \"company\",\n sourceUrl: \"https://www.ytj.fi/en/index/businessid.html\",\n examples: [\"20774740\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default vat;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;;;;;;;;;;AAkBA,MAAM,UAAU;CAAC;CAAG;CAAG;CAAI;CAAG;CAAG;CAAG;CAAG;CAAE;AAEzC,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;;AAGT,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,MAAM;AACxB,KAAI,EAAE,WAAW,EACf,QAAO,IACL,kBACA,sCACD;AAEH,KAAI,CAAC,SAAS,EAAE,CACd,QAAO,IACL,kBACA,8CACD;AAGH,KADY,YAAY,GAAG,SAAS,GAAG,KAC3B,EACV,QAAO,IACL,oBACA,0CACD;AAEH,QAAO;EAAE,OAAO;EAAM,SAAS;EAAG;;AAGpC,MAAM,UAAU,UACd,KAAK,QAAQ,MAAM;;AAGrB,MAAM,iBAAyB;AAC7B,UAAS;EACP,MAAM,IAAI,aAAa,EAAE;AACzB,MAAI,SAAS,EAAE,CAAC,MAAO,QAAO;;;;AAKlC,MAAM,MAAiB;CACrB,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,cAAc,WAAW;CACnC,kBAAkB;CAClB,SAAS;CACT,YAAY;CACZ,WAAW;CACX,UAAU,CAAC,WAAW;CACtB;CACA;CACA;CACA;CACD"}
1
+ {"version":3,"file":"vat.js","names":[],"sources":["../../src/fi/vat.ts"],"sourcesContent":["/**\n * ALV nro (Finnish VAT number).\n *\n * 8 digits. Weights [7,9,10,5,8,4,2,1],\n * sum % 11 === 0.\n *\n * @see https://www.vatify.eu/finland-vat-number.html\n * @see https://www.ytj.fi/en/index/businessid.html\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { weightedSum } from \"#checksums/weighted-sum\";\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst WEIGHTS = [7, 9, 10, 5, 8, 4, 2, 1];\n\nconst compact = (value: string): string => {\n let v = clean(value, \" -/.\");\n if (v.startsWith(\"FI\") || v.startsWith(\"fi\")) {\n v = v.slice(2);\n }\n return v;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 8) {\n return err(\n \"INVALID_LENGTH\",\n \"Finnish VAT number must be 8 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"Finnish VAT number must contain only digits\",\n );\n }\n const sum = weightedSum(v, WEIGHTS, 11);\n if (sum !== 0) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Finnish VAT number check digit mismatch\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string =>\n `FI${compact(value)}`;\n\n/** Generate a random valid Finnish VAT number. */\nconst generate = (): string => {\n for (;;) {\n const c = randomDigits(8);\n if (validate(c).valid) return c;\n }\n};\n\n/** Finnish VAT Number. */\nconst vat: CountryValidator<\"FI\"> = {\n name: \"Finnish VAT Number\",\n localName: \"Arvonlisäveronumero\",\n abbreviation: \"ALV nro\",\n aliases: [\"ALV-numero\", \"Y-tunnus\"] as const,\n candidatePattern: \"FI\\\\d{8}\",\n scope: \"country\",\n country: \"FI\",\n entityType: \"company\",\n sourceUrl: \"https://www.ytj.fi/en/index/businessid.html\",\n lengths: [8] as const,\n examples: [\"20774740\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default vat;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;AAqBA,MAAM,UAAU;CAAC;CAAG;CAAG;CAAI;CAAG;CAAG;CAAG;CAAG;AAAC;AAExC,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;AACT;AAEA,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,GACf,OAAO,IACL,kBACA,qCACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,6CACF;CAGF,IADY,YAAY,GAAG,SAAS,EAC9B,MAAM,GACV,OAAO,IACL,oBACA,yCACF;CAEF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UACd,KAAK,QAAQ,KAAK;;AAGpB,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,IAAI,aAAa,CAAC;EACxB,IAAI,SAAS,CAAC,EAAE,OAAO,OAAO;CAChC;AACF;;AAGA,MAAM,MAA8B;CAClC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,cAAc,UAAU;CAClC,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,WAAW;CACX,SAAS,CAAC,CAAC;CACX,UAAU,CAAC,UAAU;CACrB;CACA;CACA;CACA;AACF"}
@@ -1,4 +1,4 @@
1
- import { ValidateResult, Validator } from "../types.js";
1
+ import { CountryValidator, ValidateResult } from "../types.js";
2
2
 
3
3
  //#region src/fi/ytunnus.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 Finnish Y-tunnus. */
8
8
  declare const generate: () => string;
9
9
  /** Finnish Business ID. */
10
- declare const ytunnus: Validator;
10
+ declare const ytunnus: CountryValidator<"FI">;
11
11
  //#endregion
12
12
  export { compact, ytunnus as default, format, generate, validate };
13
13
  //# sourceMappingURL=ytunnus.d.ts.map
@@ -1,18 +1,9 @@
1
+ import { weightedSum } from "../_checksums/weighted-sum.js";
1
2
  import { clean } from "../_util/clean.js";
2
3
  import { randomDigits } 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
  //#region src/fi/ytunnus.ts
7
- /**
8
- * Y-tunnus (Finnish Business ID).
9
- *
10
- * 8 digits. Weights [7,9,10,5,8,4,2,1],
11
- * sum % 11 === 0. Same algorithm as FI VAT.
12
- * Display format: NNNNNNN-C.
13
- *
14
- * @see https://www.ytj.fi/en/index/businessid.html
15
- */
16
7
  const WEIGHTS = [
17
8
  7,
18
9
  9,
@@ -56,6 +47,7 @@ const ytunnus = {
56
47
  "FO-nummer"
57
48
  ],
58
49
  candidatePattern: "\\d{7}-\\d",
50
+ scope: "country",
59
51
  country: "FI",
60
52
  entityType: "company",
61
53
  sourceUrl: "https://www.ytj.fi/en/index/businessid.html",
@@ -1 +1 @@
1
- {"version":3,"file":"ytunnus.js","names":[],"sources":["../../src/fi/ytunnus.ts"],"sourcesContent":["/**\n * Y-tunnus (Finnish Business ID).\n *\n * 8 digits. Weights [7,9,10,5,8,4,2,1],\n * sum % 11 === 0. Same algorithm as FI VAT.\n * Display format: NNNNNNN-C.\n *\n * @see https://www.ytj.fi/en/index/businessid.html\n */\n\nimport { weightedSum } from \"#checksums/weighted-sum\";\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 = [7, 9, 10, 5, 8, 4, 2, 1];\n\nconst compact = (value: string): string =>\n clean(value, \" -/.\");\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 8) {\n return err(\n \"INVALID_LENGTH\",\n \"Finnish Y-tunnus must be 8 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"Finnish Y-tunnus must contain only digits\",\n );\n }\n const sum = weightedSum(v, WEIGHTS, 11);\n if (sum !== 0) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Finnish Y-tunnus check digit mismatch\",\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, 7)}-${v[7]}`;\n};\n\n/** Generate a random valid Finnish Y-tunnus. */\nconst generate = (): string => {\n for (;;) {\n const c = randomDigits(8);\n if (validate(c).valid) return c;\n }\n};\n\n/** Finnish Business ID. */\nconst ytunnus: Validator = {\n name: \"Finnish Business ID\",\n localName: \"Y-tunnus\",\n abbreviation: \"Y-tunnus\",\n aliases: [\n \"Y-tunnus\",\n \"yritystunnus\",\n \"FO-nummer\",\n ] as const,\n candidatePattern: \"\\\\d{7}-\\\\d\",\n country: \"FI\",\n entityType: \"company\",\n sourceUrl: \"https://www.ytj.fi/en/index/businessid.html\",\n examples: [\"20774740\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default ytunnus;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;;;;;;;;;;AAkBA,MAAM,UAAU;CAAC;CAAG;CAAG;CAAI;CAAG;CAAG;CAAG;CAAG;CAAE;AAEzC,MAAM,WAAW,UACf,MAAM,OAAO,OAAO;AAEtB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,MAAM;AACxB,KAAI,EAAE,WAAW,EACf,QAAO,IACL,kBACA,oCACD;AAEH,KAAI,CAAC,SAAS,EAAE,CACd,QAAO,IACL,kBACA,4CACD;AAGH,KADY,YAAY,GAAG,SAAS,GAAG,KAC3B,EACV,QAAO,IACL,oBACA,wCACD;AAEH,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;;;AAI/B,MAAM,iBAAyB;AAC7B,UAAS;EACP,MAAM,IAAI,aAAa,EAAE;AACzB,MAAI,SAAS,EAAE,CAAC,MAAO,QAAO;;;;AAKlC,MAAM,UAAqB;CACzB,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS;EACP;EACA;EACA;EACD;CACD,kBAAkB;CAClB,SAAS;CACT,YAAY;CACZ,WAAW;CACX,UAAU,CAAC,WAAW;CACtB;CACA;CACA;CACA;CACD"}
1
+ {"version":3,"file":"ytunnus.js","names":[],"sources":["../../src/fi/ytunnus.ts"],"sourcesContent":["/**\n * Y-tunnus (Finnish Business ID).\n *\n * 8 digits. Weights [7,9,10,5,8,4,2,1],\n * sum % 11 === 0. Same algorithm as FI VAT.\n * Display format: NNNNNNN-C.\n *\n * @see https://www.ytj.fi/en/index/businessid.html\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { weightedSum } from \"#checksums/weighted-sum\";\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst WEIGHTS = [7, 9, 10, 5, 8, 4, 2, 1];\n\nconst compact = (value: string): string =>\n clean(value, \" -/.\");\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 8) {\n return err(\n \"INVALID_LENGTH\",\n \"Finnish Y-tunnus must be 8 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"Finnish Y-tunnus must contain only digits\",\n );\n }\n const sum = weightedSum(v, WEIGHTS, 11);\n if (sum !== 0) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Finnish Y-tunnus check digit mismatch\",\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, 7)}-${v[7]}`;\n};\n\n/** Generate a random valid Finnish Y-tunnus. */\nconst generate = (): string => {\n for (;;) {\n const c = randomDigits(8);\n if (validate(c).valid) return c;\n }\n};\n\n/** Finnish Business ID. */\nconst ytunnus: CountryValidator<\"FI\"> = {\n name: \"Finnish Business ID\",\n localName: \"Y-tunnus\",\n abbreviation: \"Y-tunnus\",\n aliases: [\n \"Y-tunnus\",\n \"yritystunnus\",\n \"FO-nummer\",\n ] as const,\n candidatePattern: \"\\\\d{7}-\\\\d\",\n scope: \"country\",\n country: \"FI\",\n entityType: \"company\",\n sourceUrl: \"https://www.ytj.fi/en/index/businessid.html\",\n examples: [\"20774740\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default ytunnus;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;AAqBA,MAAM,UAAU;CAAC;CAAG;CAAG;CAAI;CAAG;CAAG;CAAG;CAAG;AAAC;AAExC,MAAM,WAAW,UACf,MAAM,OAAO,MAAM;AAErB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,GACf,OAAO,IACL,kBACA,mCACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,2CACF;CAGF,IADY,YAAY,GAAG,SAAS,EAC9B,MAAM,GACV,OAAO,IACL,oBACA,uCACF;CAEF,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;AAC/B;;AAGA,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,IAAI,aAAa,CAAC;EACxB,IAAI,SAAS,CAAC,EAAE,OAAO,OAAO;CAChC;AACF;;AAGA,MAAM,UAAkC;CACtC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS;EACP;EACA;EACA;CACF;CACA,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,WAAW;CACX,UAAU,CAAC,UAAU;CACrB;CACA;CACA;CACA;AACF"}
package/dist/fr/nif.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/fr/nif.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 French NIF. */
8
8
  declare const generate: () => string;
9
9
  /** French Tax Identification Number. */
10
- declare const nif: Validator;
10
+ declare const nif: CountryValidator<"FR">;
11
11
  //#endregion
12
12
  export { compact, nif as default, format, generate, validate };
13
13
  //# sourceMappingURL=nif.d.ts.map
package/dist/fr/nif.js CHANGED
@@ -3,15 +3,6 @@ import { 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/fr/nif.ts
6
- /**
7
- * NIF (Numéro d'Identification Fiscale).
8
- *
9
- * French tax identification number. 13 digits;
10
- * first digit is 0-3. Last 3 digits are a
11
- * check: first_10_digits % 511 == last_3.
12
- *
13
- * @see https://www.impots.gouv.fr/
14
- */
15
6
  const compact = (value) => clean(value, " -");
16
7
  const validate = (value) => {
17
8
  const v = compact(value);
@@ -49,6 +40,7 @@ const nif = {
49
40
  "numéro d'identification fiscale"
50
41
  ],
51
42
  candidatePattern: "\\d{13}",
43
+ scope: "country",
52
44
  country: "FR",
53
45
  entityType: "person",
54
46
  sourceUrl: "https://www.impots.gouv.fr/",
@@ -1 +1 @@
1
- {"version":3,"file":"nif.js","names":[],"sources":["../../src/fr/nif.ts"],"sourcesContent":["/**\n * NIF (Numéro d'Identification Fiscale).\n *\n * French tax identification number. 13 digits;\n * first digit is 0-3. Last 3 digits are a\n * check: first_10_digits % 511 == last_3.\n *\n * @see https://www.impots.gouv.fr/\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\nconst compact = (value: string): string =>\n clean(value, \" -\");\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 13) {\n return err(\n \"INVALID_LENGTH\",\n \"French NIF must be exactly 13 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"French NIF must contain only digits\",\n );\n }\n const first = v[0];\n if (\n first !== \"0\" &&\n first !== \"1\" &&\n first !== \"2\" &&\n first !== \"3\"\n ) {\n return err(\n \"INVALID_COMPONENT\",\n \"French NIF must start with 0-3\",\n );\n }\n const front = Number(v.slice(0, 10));\n const check = Number(v.slice(10));\n if (front % 511 !== check) {\n return err(\n \"INVALID_CHECKSUM\",\n \"French NIF check digits mismatch\",\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, 4)} ${v.slice(4, 7)} ${v.slice(7, 10)} ${v.slice(10)}`;\n};\n\n/** Generate a random valid French NIF. */\nconst generate = (): string => {\n for (;;) {\n const c = String(randomInt(0, 3)) + randomDigits(12);\n if (validate(c).valid) return c;\n }\n};\n\n/** French Tax Identification Number. */\nconst nif: Validator = {\n name: \"French Tax ID\",\n localName: \"Numéro d'Identification Fiscale\",\n abbreviation: \"NIF\",\n aliases: [\n \"numéro fiscal\",\n \"NIF\",\n \"numéro d'identification fiscale\",\n ] as const,\n candidatePattern: \"\\\\d{13}\",\n country: \"FR\",\n entityType: \"person\",\n sourceUrl: \"https://www.impots.gouv.fr/\",\n examples: [\"3023217600053\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default nif;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;;;;;;;;;AAiBA,MAAM,WAAW,UACf,MAAM,OAAO,KAAK;AAEpB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,MAAM;AACxB,KAAI,EAAE,WAAW,GACf,QAAO,IACL,kBACA,uCACD;AAEH,KAAI,CAAC,SAAS,EAAE,CACd,QAAO,IACL,kBACA,sCACD;CAEH,MAAM,QAAQ,EAAE;AAChB,KACE,UAAU,OACV,UAAU,OACV,UAAU,OACV,UAAU,IAEV,QAAO,IACL,qBACA,iCACD;CAEH,MAAM,QAAQ,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC;CACpC,MAAM,QAAQ,OAAO,EAAE,MAAM,GAAG,CAAC;AACjC,KAAI,QAAQ,QAAQ,MAClB,QAAO,IACL,oBACA,mCACD;AAEH,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,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG;;;AAI5F,MAAM,iBAAyB;AAC7B,UAAS;EACP,MAAM,IAAI,OAAO,UAAU,GAAG,EAAE,CAAC,GAAG,aAAa,GAAG;AACpD,MAAI,SAAS,EAAE,CAAC,MAAO,QAAO;;;;AAKlC,MAAM,MAAiB;CACrB,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS;EACP;EACA;EACA;EACD;CACD,kBAAkB;CAClB,SAAS;CACT,YAAY;CACZ,WAAW;CACX,UAAU,CAAC,gBAAgB;CAC3B;CACA;CACA;CACA;CACD"}
1
+ {"version":3,"file":"nif.js","names":[],"sources":["../../src/fr/nif.ts"],"sourcesContent":["/**\n * NIF (Numéro d'Identification Fiscale).\n *\n * French tax identification number. 13 digits;\n * first digit is 0-3. Last 3 digits are a\n * check: first_10_digits % 511 == last_3.\n *\n * @see https://www.impots.gouv.fr/\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\";\nimport { isdigits } from \"#util/strings\";\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) {\n return err(\n \"INVALID_LENGTH\",\n \"French NIF must be exactly 13 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"French NIF must contain only digits\",\n );\n }\n const first = v[0];\n if (\n first !== \"0\" &&\n first !== \"1\" &&\n first !== \"2\" &&\n first !== \"3\"\n ) {\n return err(\n \"INVALID_COMPONENT\",\n \"French NIF must start with 0-3\",\n );\n }\n const front = Number(v.slice(0, 10));\n const check = Number(v.slice(10));\n if (front % 511 !== check) {\n return err(\n \"INVALID_CHECKSUM\",\n \"French NIF check digits mismatch\",\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, 4)} ${v.slice(4, 7)} ${v.slice(7, 10)} ${v.slice(10)}`;\n};\n\n/** Generate a random valid French NIF. */\nconst generate = (): string => {\n for (;;) {\n const c = String(randomInt(0, 3)) + randomDigits(12);\n if (validate(c).valid) return c;\n }\n};\n\n/** French Tax Identification Number. */\nconst nif: CountryValidator<\"FR\"> = {\n name: \"French Tax ID\",\n localName: \"Numéro d'Identification Fiscale\",\n abbreviation: \"NIF\",\n aliases: [\n \"numéro fiscal\",\n \"NIF\",\n \"numéro d'identification fiscale\",\n ] as const,\n candidatePattern: \"\\\\d{13}\",\n scope: \"country\",\n country: \"FR\",\n entityType: \"person\",\n sourceUrl: \"https://www.impots.gouv.fr/\",\n examples: [\"3023217600053\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default nif;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;AAoBA,MAAM,WAAW,UACf,MAAM,OAAO,IAAI;AAEnB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,IACf,OAAO,IACL,kBACA,sCACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,qCACF;CAEF,MAAM,QAAQ,EAAE;CAChB,IACE,UAAU,OACV,UAAU,OACV,UAAU,OACV,UAAU,KAEV,OAAO,IACL,qBACA,gCACF;CAEF,MAAM,QAAQ,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;CACnC,MAAM,QAAQ,OAAO,EAAE,MAAM,EAAE,CAAC;CAChC,IAAI,QAAQ,QAAQ,OAClB,OAAO,IACL,oBACA,kCACF;CAEF,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,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE;AAC3F;;AAGA,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,IAAI,OAAO,UAAU,GAAG,CAAC,CAAC,IAAI,aAAa,EAAE;EACnD,IAAI,SAAS,CAAC,EAAE,OAAO,OAAO;CAChC;AACF;;AAGA,MAAM,MAA8B;CAClC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS;EACP;EACA;EACA;CACF;CACA,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,WAAW;CACX,UAAU,CAAC,eAAe;CAC1B;CACA;CACA;CACA;AACF"}
package/dist/fr/nir.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/fr/nir.d.ts
4
4
  declare const compact: (value: string) => string;
@@ -8,7 +8,7 @@ declare const parse: (value: string) => ParsedPersonId | null;
8
8
  /** Generate a random valid French NIR. */
9
9
  declare const generate: () => string;
10
10
  /** French Social Security Number. */
11
- declare const nir: Validator<ParsedPersonId>;
11
+ declare const nir: CountryValidator<"FR", ParsedPersonId>;
12
12
  //#endregion
13
13
  export { compact, nir as default, format, generate, parse, validate };
14
14
  //# sourceMappingURL=nir.d.ts.map
package/dist/fr/nir.js CHANGED
@@ -1,21 +1,8 @@
1
1
  import { clean } from "../_util/clean.js";
2
+ import { resolveTwoDigitYear } from "../_util/date.js";
2
3
  import { randomInt } from "../_util/generate.js";
3
4
  import { err } from "../_util/result.js";
4
- import { resolveTwoDigitYear } from "../_util/date.js";
5
5
  //#region src/fr/nir.ts
6
- /**
7
- * NIR (Numero d'Inscription au Repertoire).
8
- *
9
- * French social security number (numero de securite
10
- * sociale). 15 digits: 13 identity digits + 2 check
11
- * digits. Encodes gender, year/month of birth, and
12
- * department of birth.
13
- *
14
- * Corsican departments 2A/2B are encoded as 19/18
15
- * for the mod-97 checksum computation.
16
- *
17
- * @see https://en.wikipedia.org/wiki/INSEE_code
18
- */
19
6
  const compact = (value) => clean(value, " -.");
20
7
  const validate = (value) => {
21
8
  const v = compact(value).toUpperCase();
@@ -89,6 +76,7 @@ const nir = {
89
76
  "sécu"
90
77
  ],
91
78
  candidatePattern: "[12]\\s?\\d{2}\\s?\\d{2}\\s?\\d{2}\\s?\\d{3}\\s?\\d{3}\\s?\\d{2}",
79
+ scope: "country",
92
80
  country: "FR",
93
81
  entityType: "person",
94
82
  description: "French social security number encoding gender, birth date, and department",
@@ -1 +1 @@
1
- {"version":3,"file":"nir.js","names":[],"sources":["../../src/fr/nir.ts"],"sourcesContent":["/**\n * NIR (Numero d'Inscription au Repertoire).\n *\n * French social security number (numero de securite\n * sociale). 15 digits: 13 identity digits + 2 check\n * digits. Encodes gender, year/month of birth, and\n * department of birth.\n *\n * Corsican departments 2A/2B are encoded as 19/18\n * for the mod-97 checksum computation.\n *\n * @see https://en.wikipedia.org/wiki/INSEE_code\n */\n\nimport { clean } from \"#util/clean\";\nimport { resolveTwoDigitYear } from \"#util/date\";\nimport { 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, \" -.\");\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value).toUpperCase();\n if (v.length !== 15) {\n return err(\n \"INVALID_LENGTH\",\n \"French NIR must be 15 characters\",\n );\n }\n\n const gender = v[0];\n if (gender !== \"1\" && gender !== \"2\") {\n return err(\n \"INVALID_COMPONENT\",\n \"French NIR first digit must be 1 or 2\",\n );\n }\n\n const yearPart = v.slice(1, 3);\n if (!/^\\d{2}$/.test(yearPart)) {\n return err(\n \"INVALID_FORMAT\",\n \"French NIR year must be 2 digits\",\n );\n }\n\n const monthPart = v.slice(3, 5);\n if (!/^\\d{2}$/.test(monthPart) || monthPart === \"00\") {\n return err(\n \"INVALID_FORMAT\",\n \"French NIR month must be 01-99\",\n );\n }\n\n const deptPart = v.slice(5, 7);\n const isCorsica = deptPart === \"2A\" || deptPart === \"2B\";\n if (!isCorsica && !/^\\d{2}$/.test(deptPart)) {\n return err(\n \"INVALID_FORMAT\",\n \"French NIR department must be 2 digits or 2A/2B\",\n );\n }\n\n const communePart = v.slice(7, 10);\n if (!/^\\d{3}$/.test(communePart)) {\n return err(\n \"INVALID_FORMAT\",\n \"French NIR commune must be 3 digits\",\n );\n }\n\n const serialPart = v.slice(10, 13);\n if (!/^\\d{3}$/.test(serialPart)) {\n return err(\n \"INVALID_FORMAT\",\n \"French NIR serial must be 3 digits\",\n );\n }\n\n const checkPart = v.slice(13, 15);\n if (!/^\\d{2}$/.test(checkPart)) {\n return err(\n \"INVALID_FORMAT\",\n \"French NIR check must be 2 digits\",\n );\n }\n\n let numericBase: string;\n if (deptPart === \"2A\") {\n numericBase = v.slice(0, 5) + \"19\" + v.slice(7, 13);\n } else if (deptPart === \"2B\") {\n numericBase = v.slice(0, 5) + \"18\" + v.slice(7, 13);\n } else {\n numericBase = v.slice(0, 13);\n }\n\n const base = BigInt(numericBase);\n const expected = 97n - (base % 97n);\n const actual = BigInt(checkPart);\n\n if (expected !== actual) {\n return err(\n \"INVALID_CHECKSUM\",\n \"French NIR check digits mismatch\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value).toUpperCase();\n return (\n `${v.slice(0, 1)} ${v.slice(1, 3)}` +\n ` ${v.slice(3, 5)} ${v.slice(5, 7)}` +\n ` ${v.slice(7, 10)} ${v.slice(10, 13)}` +\n ` ${v.slice(13)}`\n );\n};\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 genderDigit = v[0];\n const yy = Number(v.slice(1, 3));\n const mm = Number(v.slice(3, 5));\n\n if (mm < 1 || mm > 12) return null;\n\n const year = resolveTwoDigitYear(yy);\n const gender = genderDigit === \"1\" ? \"male\" : \"female\";\n\n return {\n birthDate: new Date(year, mm - 1, 1),\n gender,\n };\n};\n\n/** Generate a random valid French NIR. */\nconst generate = (): string => {\n for (;;) {\n const g = String(randomInt(1, 2));\n const yy = String(randomInt(50, 99)).padStart(2, \"0\");\n const mm = String(randomInt(1, 12)).padStart(2, \"0\");\n const dept = String(randomInt(1, 95)).padStart(2, \"0\");\n const com = String(randomInt(1, 999)).padStart(3, \"0\");\n const s = String(randomInt(1, 999)).padStart(3, \"0\");\n const base = g + yy + mm + dept + com + s;\n const check = String(97 - (Number(base) % 97)).padStart(\n 2,\n \"0\",\n );\n const c = base + check;\n if (validate(c).valid) return c;\n }\n};\n\n/** French Social Security Number. */\nconst nir: Validator<ParsedPersonId> = {\n name: \"French Social Security Number\",\n localName: \"Numero d'Inscription au Repertoire\",\n abbreviation: \"NIR\",\n aliases: [\n \"NIR\",\n \"numéro de sécurité sociale\",\n \"numéro SS\",\n \"sécu\",\n ] as const,\n candidatePattern:\n \"[12]\\\\s?\\\\d{2}\\\\s?\\\\d{2}\\\\s?\\\\d{2}\\\\s?\\\\d{3}\\\\s?\\\\d{3}\\\\s?\\\\d{2}\",\n country: \"FR\",\n entityType: \"person\",\n description:\n \"French social security number encoding \" +\n \"gender, birth date, and department\",\n sourceUrl: \"https://en.wikipedia.org/wiki/INSEE_code\",\n lengths: [15] as const,\n examples: [\"295117823456784\"] as const,\n compact,\n format,\n parse,\n validate,\n generate,\n};\n\nexport default nir;\nexport { compact, format, parse, validate, generate };\n"],"mappings":"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"}
1
+ {"version":3,"file":"nir.js","names":[],"sources":["../../src/fr/nir.ts"],"sourcesContent":["/**\n * NIR (Numero d'Inscription au Repertoire).\n *\n * French social security number (numero de securite\n * sociale). 15 digits: 13 identity digits + 2 check\n * digits. Encodes gender, year/month of birth, and\n * department of birth.\n *\n * Corsican departments 2A/2B are encoded as 19/18\n * for the mod-97 checksum computation.\n *\n * @see https://en.wikipedia.org/wiki/INSEE_code\n */\n\nimport type {\n ParsedPersonId,\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { resolveTwoDigitYear } from \"#util/date\";\nimport { randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\n\nconst compact = (value: string): string =>\n clean(value, \" -.\");\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value).toUpperCase();\n if (v.length !== 15) {\n return err(\n \"INVALID_LENGTH\",\n \"French NIR must be 15 characters\",\n );\n }\n\n const gender = v[0];\n if (gender !== \"1\" && gender !== \"2\") {\n return err(\n \"INVALID_COMPONENT\",\n \"French NIR first digit must be 1 or 2\",\n );\n }\n\n const yearPart = v.slice(1, 3);\n if (!/^\\d{2}$/.test(yearPart)) {\n return err(\n \"INVALID_FORMAT\",\n \"French NIR year must be 2 digits\",\n );\n }\n\n const monthPart = v.slice(3, 5);\n if (!/^\\d{2}$/.test(monthPart) || monthPart === \"00\") {\n return err(\n \"INVALID_FORMAT\",\n \"French NIR month must be 01-99\",\n );\n }\n\n const deptPart = v.slice(5, 7);\n const isCorsica = deptPart === \"2A\" || deptPart === \"2B\";\n if (!isCorsica && !/^\\d{2}$/.test(deptPart)) {\n return err(\n \"INVALID_FORMAT\",\n \"French NIR department must be 2 digits or 2A/2B\",\n );\n }\n\n const communePart = v.slice(7, 10);\n if (!/^\\d{3}$/.test(communePart)) {\n return err(\n \"INVALID_FORMAT\",\n \"French NIR commune must be 3 digits\",\n );\n }\n\n const serialPart = v.slice(10, 13);\n if (!/^\\d{3}$/.test(serialPart)) {\n return err(\n \"INVALID_FORMAT\",\n \"French NIR serial must be 3 digits\",\n );\n }\n\n const checkPart = v.slice(13, 15);\n if (!/^\\d{2}$/.test(checkPart)) {\n return err(\n \"INVALID_FORMAT\",\n \"French NIR check must be 2 digits\",\n );\n }\n\n let numericBase: string;\n if (deptPart === \"2A\") {\n numericBase = v.slice(0, 5) + \"19\" + v.slice(7, 13);\n } else if (deptPart === \"2B\") {\n numericBase = v.slice(0, 5) + \"18\" + v.slice(7, 13);\n } else {\n numericBase = v.slice(0, 13);\n }\n\n const base = BigInt(numericBase);\n const expected = 97n - (base % 97n);\n const actual = BigInt(checkPart);\n\n if (expected !== actual) {\n return err(\n \"INVALID_CHECKSUM\",\n \"French NIR check digits mismatch\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value).toUpperCase();\n return (\n `${v.slice(0, 1)} ${v.slice(1, 3)}` +\n ` ${v.slice(3, 5)} ${v.slice(5, 7)}` +\n ` ${v.slice(7, 10)} ${v.slice(10, 13)}` +\n ` ${v.slice(13)}`\n );\n};\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 genderDigit = v[0];\n const yy = Number(v.slice(1, 3));\n const mm = Number(v.slice(3, 5));\n\n if (mm < 1 || mm > 12) return null;\n\n const year = resolveTwoDigitYear(yy);\n const gender = genderDigit === \"1\" ? \"male\" : \"female\";\n\n return {\n birthDate: new Date(year, mm - 1, 1),\n gender,\n };\n};\n\n/** Generate a random valid French NIR. */\nconst generate = (): string => {\n for (;;) {\n const g = String(randomInt(1, 2));\n const yy = String(randomInt(50, 99)).padStart(2, \"0\");\n const mm = String(randomInt(1, 12)).padStart(2, \"0\");\n const dept = String(randomInt(1, 95)).padStart(2, \"0\");\n const com = String(randomInt(1, 999)).padStart(3, \"0\");\n const s = String(randomInt(1, 999)).padStart(3, \"0\");\n const base = g + yy + mm + dept + com + s;\n const check = String(97 - (Number(base) % 97)).padStart(\n 2,\n \"0\",\n );\n const c = base + check;\n if (validate(c).valid) return c;\n }\n};\n\n/** French Social Security Number. */\nconst nir: CountryValidator<\"FR\", ParsedPersonId> = {\n name: \"French Social Security Number\",\n localName: \"Numero d'Inscription au Repertoire\",\n abbreviation: \"NIR\",\n aliases: [\n \"NIR\",\n \"numéro de sécurité sociale\",\n \"numéro SS\",\n \"sécu\",\n ] as const,\n candidatePattern:\n \"[12]\\\\s?\\\\d{2}\\\\s?\\\\d{2}\\\\s?\\\\d{2}\\\\s?\\\\d{3}\\\\s?\\\\d{3}\\\\s?\\\\d{2}\",\n scope: \"country\",\n country: \"FR\",\n entityType: \"person\",\n description:\n \"French social security number encoding \" +\n \"gender, birth date, and department\",\n sourceUrl: \"https://en.wikipedia.org/wiki/INSEE_code\",\n lengths: [15] as const,\n examples: [\"295117823456784\"] as const,\n compact,\n format,\n parse,\n validate,\n generate,\n};\n\nexport default nir;\nexport { compact, format, parse, validate, generate };\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { ValidateResult, Validator } from "../types.js";
1
+ import { CountryValidator, ValidateResult } from "../types.js";
2
2
 
3
3
  //#region src/fr/siren.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 French SIREN. */
8
8
  declare const generate: () => string;
9
9
  /** French Company Identification Number. */
10
- declare const siren: Validator;
10
+ declare const siren: CountryValidator<"FR">;
11
11
  //#endregion
12
12
  export { compact, siren as default, format, generate, validate };
13
13
  //# sourceMappingURL=siren.d.ts.map
package/dist/fr/siren.js CHANGED
@@ -1,18 +1,9 @@
1
+ import { luhnChecksum, luhnValidate } from "../_checksums/luhn.js";
1
2
  import { clean } from "../_util/clean.js";
2
3
  import { randomDigits } 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/fr/siren.ts
7
- /**
8
- * SIREN (Système d'Identification du Répertoire
9
- * des Entreprises).
10
- *
11
- * French company identification number. 9 digits
12
- * validated with standard Luhn algorithm.
13
- *
14
- * @see https://www.insee.fr/fr/information/2549588
15
- */
16
7
  const compact = (value) => clean(value, " -.");
17
8
  const validate = (value) => {
18
9
  const v = compact(value);
@@ -41,6 +32,7 @@ const siren = {
41
32
  abbreviation: "SIREN",
42
33
  aliases: ["SIREN", "numéro SIREN"],
43
34
  candidatePattern: "\\d{3}\\s?\\d{3}\\s?\\d{3}",
35
+ scope: "country",
44
36
  country: "FR",
45
37
  entityType: "company",
46
38
  sourceUrl: "https://www.insee.fr/fr/information/2549588",
@@ -1 +1 @@
1
- {"version":3,"file":"siren.js","names":[],"sources":["../../src/fr/siren.ts"],"sourcesContent":["/**\n * SIREN (Système d'Identification du Répertoire\n * des Entreprises).\n *\n * French company identification number. 9 digits\n * validated with standard Luhn algorithm.\n *\n * @see https://www.insee.fr/fr/information/2549588\n */\n\nimport {\n luhnValidate,\n luhnChecksum,\n} from \"#checksums/luhn\";\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 compact = (value: string): string =>\n clean(value, \" -.\");\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 9) {\n return err(\n \"INVALID_LENGTH\",\n \"SIREN must be exactly 9 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"SIREN must contain only digits\",\n );\n }\n if (!luhnValidate(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"SIREN fails Luhn check\",\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, 3)} ${v.slice(3, 6)} ${v.slice(6)}`;\n};\n\n/** Generate a random valid French SIREN. */\nconst generate = (): string => {\n const payload = randomDigits(8);\n const cs = luhnChecksum(payload + \"0\");\n return payload + String((10 - cs) % 10);\n};\n\n/** French Company Identification Number. */\nconst siren: Validator = {\n name: \"French Company ID\",\n localName:\n \"Système d'Identification du Répertoire des Entreprises\",\n abbreviation: \"SIREN\",\n aliases: [\"SIREN\", \"numéro SIREN\"] as const,\n candidatePattern: \"\\\\d{3}\\\\s?\\\\d{3}\\\\s?\\\\d{3}\",\n country: \"FR\",\n entityType: \"company\",\n sourceUrl: \"https://www.insee.fr/fr/information/2549588\",\n examples: [\"552008443\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default siren;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;;;;;;;;;;AAqBA,MAAM,WAAW,UACf,MAAM,OAAO,MAAM;AAErB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,MAAM;AACxB,KAAI,EAAE,WAAW,EACf,QAAO,IACL,kBACA,iCACD;AAEH,KAAI,CAAC,SAAS,EAAE,CACd,QAAO,IACL,kBACA,iCACD;AAEH,KAAI,CAAC,aAAa,EAAE,CAClB,QAAO,IACL,oBACA,yBACD;AAEH,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,EAAE;;;AAIxD,MAAM,iBAAyB;CAC7B,MAAM,UAAU,aAAa,EAAE;CAC/B,MAAM,KAAK,aAAa,UAAU,IAAI;AACtC,QAAO,UAAU,QAAQ,KAAK,MAAM,GAAG;;;AAIzC,MAAM,QAAmB;CACvB,MAAM;CACN,WACE;CACF,cAAc;CACd,SAAS,CAAC,SAAS,eAAe;CAClC,kBAAkB;CAClB,SAAS;CACT,YAAY;CACZ,WAAW;CACX,UAAU,CAAC,YAAY;CACvB;CACA;CACA;CACA;CACD"}
1
+ {"version":3,"file":"siren.js","names":[],"sources":["../../src/fr/siren.ts"],"sourcesContent":["/**\n * SIREN (Système d'Identification du Répertoire\n * des Entreprises).\n *\n * French company identification number. 9 digits\n * validated with standard Luhn algorithm.\n *\n * @see https://www.insee.fr/fr/information/2549588\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport {\n luhnValidate,\n luhnChecksum,\n} from \"#checksums/luhn\";\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst compact = (value: string): string =>\n clean(value, \" -.\");\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 9) {\n return err(\n \"INVALID_LENGTH\",\n \"SIREN must be exactly 9 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"SIREN must contain only digits\",\n );\n }\n if (!luhnValidate(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"SIREN fails Luhn check\",\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, 3)} ${v.slice(3, 6)} ${v.slice(6)}`;\n};\n\n/** Generate a random valid French SIREN. */\nconst generate = (): string => {\n const payload = randomDigits(8);\n const cs = luhnChecksum(payload + \"0\");\n return payload + String((10 - cs) % 10);\n};\n\n/** French Company Identification Number. */\nconst siren: CountryValidator<\"FR\"> = {\n name: \"French Company ID\",\n localName:\n \"Système d'Identification du Répertoire des Entreprises\",\n abbreviation: \"SIREN\",\n aliases: [\"SIREN\", \"numéro SIREN\"] as const,\n candidatePattern: \"\\\\d{3}\\\\s?\\\\d{3}\\\\s?\\\\d{3}\",\n scope: \"country\",\n country: \"FR\",\n entityType: \"company\",\n sourceUrl: \"https://www.insee.fr/fr/information/2549588\",\n examples: [\"552008443\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default siren;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;AAwBA,MAAM,WAAW,UACf,MAAM,OAAO,KAAK;AAEpB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,GACf,OAAO,IACL,kBACA,gCACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,gCACF;CAEF,IAAI,CAAC,aAAa,CAAC,GACjB,OAAO,IACL,oBACA,wBACF;CAEF,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,CAAC;AACvD;;AAGA,MAAM,iBAAyB;CAC7B,MAAM,UAAU,aAAa,CAAC;CAC9B,MAAM,KAAK,aAAa,UAAU,GAAG;CACrC,OAAO,UAAU,QAAQ,KAAK,MAAM,EAAE;AACxC;;AAGA,MAAM,QAAgC;CACpC,MAAM;CACN,WACE;CACF,cAAc;CACd,SAAS,CAAC,SAAS,cAAc;CACjC,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,WAAW;CACX,UAAU,CAAC,WAAW;CACtB;CACA;CACA;CACA;AACF"}
@@ -1,4 +1,4 @@
1
- import { ValidateResult, Validator } from "../types.js";
1
+ import { CountryValidator, ValidateResult } from "../types.js";
2
2
 
3
3
  //#region src/fr/siret.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 French SIRET. */
8
8
  declare const generate: () => string;
9
9
  /** French Establishment Identification Number. */
10
- declare const siret: Validator;
10
+ declare const siret: CountryValidator<"FR">;
11
11
  //#endregion
12
12
  export { compact, siret as default, format, generate, validate };
13
13
  //# sourceMappingURL=siret.d.ts.map
package/dist/fr/siret.js CHANGED
@@ -1,19 +1,9 @@
1
+ import { luhnChecksum, luhnValidate } from "../_checksums/luhn.js";
1
2
  import { clean } from "../_util/clean.js";
2
3
  import { randomDigits } 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/fr/siret.ts
7
- /**
8
- * SIRET (Système d'Identification du Répertoire
9
- * des Établissements).
10
- *
11
- * French establishment identification number.
12
- * 14 digits: SIREN (9) + NIC (5). Validated
13
- * with Luhn, with a special case for La Poste.
14
- *
15
- * @see https://www.insee.fr/fr/information/2549588
16
- */
17
7
  const compact = (value) => clean(value, " -.");
18
8
  /**
19
9
  * La Poste SIRET uses digit sum % 5 instead of
@@ -58,6 +48,7 @@ const siret = {
58
48
  abbreviation: "SIRET",
59
49
  aliases: ["SIRET", "numéro SIRET"],
60
50
  candidatePattern: "\\d{3}\\s?\\d{3}\\s?\\d{3}\\s?\\d{5}",
51
+ scope: "country",
61
52
  country: "FR",
62
53
  entityType: "company",
63
54
  sourceUrl: "https://www.insee.fr/fr/information/2549588",
@@ -1 +1 @@
1
- {"version":3,"file":"siret.js","names":[],"sources":["../../src/fr/siret.ts"],"sourcesContent":["/**\n * SIRET (Système d'Identification du Répertoire\n * des Établissements).\n *\n * French establishment identification number.\n * 14 digits: SIREN (9) + NIC (5). Validated\n * with Luhn, with a special case for La Poste.\n *\n * @see https://www.insee.fr/fr/information/2549588\n */\n\nimport {\n luhnValidate,\n luhnChecksum,\n} from \"#checksums/luhn\";\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 compact = (value: string): string =>\n clean(value, \" -.\");\n\n/**\n * La Poste SIRET uses digit sum % 5 instead of\n * Luhn, EXCEPT the head office (35600000000048)\n * which uses standard Luhn.\n */\nconst isLaPoste = (v: string): boolean =>\n v.startsWith(\"356000000\") && v !== \"35600000000048\";\n\nconst digitSum = (v: string): number => {\n let sum = 0;\n for (let i = 0; i < v.length; i++) {\n sum += Number(v[i]);\n }\n return sum;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 14) {\n return err(\n \"INVALID_LENGTH\",\n \"SIRET must be exactly 14 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"SIRET must contain only digits\",\n );\n }\n\n // Validate SIREN part (first 9 digits)\n const siren = v.slice(0, 9);\n if (!luhnValidate(siren) && !isLaPoste(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"SIRET SIREN part fails Luhn check\",\n );\n }\n\n // La Poste: digit sum mod 5\n if (isLaPoste(v)) {\n if (digitSum(v) % 5 !== 0) {\n return err(\n \"INVALID_CHECKSUM\",\n \"SIRET La Poste digit sum check failed\",\n );\n }\n } else {\n // Standard: full 14-digit Luhn\n if (!luhnValidate(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"SIRET fails Luhn check\",\n );\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, 3)} ${v.slice(3, 6)} ${v.slice(6, 9)} ${v.slice(9)}`;\n};\n\n/** Generate a random valid French SIRET. */\nconst generate = (): string => {\n const sp = randomDigits(8);\n const sc = luhnChecksum(sp + \"0\");\n const siren = sp + String((10 - sc) % 10);\n const nic = randomDigits(4);\n const payload = siren + nic;\n const cs = luhnChecksum(payload + \"0\");\n return payload + String((10 - cs) % 10);\n};\n\n/** French Establishment Identification Number. */\nconst siret: Validator = {\n name: \"French Establishment ID\",\n localName:\n \"Système d'Identification du Répertoire des Établissements\",\n abbreviation: \"SIRET\",\n aliases: [\"SIRET\", \"numéro SIRET\"] as const,\n candidatePattern: \"\\\\d{3}\\\\s?\\\\d{3}\\\\s?\\\\d{3}\\\\s?\\\\d{5}\",\n country: \"FR\",\n entityType: \"company\",\n sourceUrl: \"https://www.insee.fr/fr/information/2549588\",\n examples: [\"73282932000074\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default siret;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;;;;;;;;;;;AAsBA,MAAM,WAAW,UACf,MAAM,OAAO,MAAM;;;;;;AAOrB,MAAM,aAAa,MACjB,EAAE,WAAW,YAAY,IAAI,MAAM;AAErC,MAAM,YAAY,MAAsB;CACtC,IAAI,MAAM;AACV,MAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,IAC5B,QAAO,OAAO,EAAE,GAAG;AAErB,QAAO;;AAGT,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;AAKH,KAAI,CAAC,aADS,EAAE,MAAM,GAAG,EAAE,CACH,IAAI,CAAC,UAAU,EAAE,CACvC,QAAO,IACL,oBACA,oCACD;AAIH,KAAI,UAAU,EAAE;MACV,SAAS,EAAE,GAAG,MAAM,EACtB,QAAO,IACL,oBACA,wCACD;YAIC,CAAC,aAAa,EAAE,CAClB,QAAO,IACL,oBACA,yBACD;AAIL,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,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE;;;AAIzE,MAAM,iBAAyB;CAC7B,MAAM,KAAK,aAAa,EAAE;CAC1B,MAAM,KAAK,aAAa,KAAK,IAAI;CAGjC,MAAM,UAFQ,KAAK,QAAQ,KAAK,MAAM,GAAG,GAC7B,aAAa,EAAE;CAE3B,MAAM,KAAK,aAAa,UAAU,IAAI;AACtC,QAAO,UAAU,QAAQ,KAAK,MAAM,GAAG;;;AAIzC,MAAM,QAAmB;CACvB,MAAM;CACN,WACE;CACF,cAAc;CACd,SAAS,CAAC,SAAS,eAAe;CAClC,kBAAkB;CAClB,SAAS;CACT,YAAY;CACZ,WAAW;CACX,UAAU,CAAC,iBAAiB;CAC5B;CACA;CACA;CACA;CACD"}
1
+ {"version":3,"file":"siret.js","names":[],"sources":["../../src/fr/siret.ts"],"sourcesContent":["/**\n * SIRET (Système d'Identification du Répertoire\n * des Établissements).\n *\n * French establishment identification number.\n * 14 digits: SIREN (9) + NIC (5). Validated\n * with Luhn, with a special case for La Poste.\n *\n * @see https://www.insee.fr/fr/information/2549588\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport {\n luhnValidate,\n luhnChecksum,\n} from \"#checksums/luhn\";\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst compact = (value: string): string =>\n clean(value, \" -.\");\n\n/**\n * La Poste SIRET uses digit sum % 5 instead of\n * Luhn, EXCEPT the head office (35600000000048)\n * which uses standard Luhn.\n */\nconst isLaPoste = (v: string): boolean =>\n v.startsWith(\"356000000\") && v !== \"35600000000048\";\n\nconst digitSum = (v: string): number => {\n let sum = 0;\n for (let i = 0; i < v.length; i++) {\n sum += Number(v[i]);\n }\n return sum;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 14) {\n return err(\n \"INVALID_LENGTH\",\n \"SIRET must be exactly 14 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"SIRET must contain only digits\",\n );\n }\n\n // Validate SIREN part (first 9 digits)\n const siren = v.slice(0, 9);\n if (!luhnValidate(siren) && !isLaPoste(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"SIRET SIREN part fails Luhn check\",\n );\n }\n\n // La Poste: digit sum mod 5\n if (isLaPoste(v)) {\n if (digitSum(v) % 5 !== 0) {\n return err(\n \"INVALID_CHECKSUM\",\n \"SIRET La Poste digit sum check failed\",\n );\n }\n } else {\n // Standard: full 14-digit Luhn\n if (!luhnValidate(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"SIRET fails Luhn check\",\n );\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, 3)} ${v.slice(3, 6)} ${v.slice(6, 9)} ${v.slice(9)}`;\n};\n\n/** Generate a random valid French SIRET. */\nconst generate = (): string => {\n const sp = randomDigits(8);\n const sc = luhnChecksum(sp + \"0\");\n const siren = sp + String((10 - sc) % 10);\n const nic = randomDigits(4);\n const payload = siren + nic;\n const cs = luhnChecksum(payload + \"0\");\n return payload + String((10 - cs) % 10);\n};\n\n/** French Establishment Identification Number. */\nconst siret: CountryValidator<\"FR\"> = {\n name: \"French Establishment ID\",\n localName:\n \"Système d'Identification du Répertoire des Établissements\",\n abbreviation: \"SIRET\",\n aliases: [\"SIRET\", \"numéro SIRET\"] as const,\n candidatePattern: \"\\\\d{3}\\\\s?\\\\d{3}\\\\s?\\\\d{3}\\\\s?\\\\d{5}\",\n scope: \"country\",\n country: \"FR\",\n entityType: \"company\",\n sourceUrl: \"https://www.insee.fr/fr/information/2549588\",\n examples: [\"73282932000074\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default siret;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;AAyBA,MAAM,WAAW,UACf,MAAM,OAAO,KAAK;;;;;;AAOpB,MAAM,aAAa,MACjB,EAAE,WAAW,WAAW,KAAK,MAAM;AAErC,MAAM,YAAY,MAAsB;CACtC,IAAI,MAAM;CACV,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,KAC5B,OAAO,OAAO,EAAE,EAAE;CAEpB,OAAO;AACT;AAEA,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,IACf,OAAO,IACL,kBACA,iCACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,gCACF;CAKF,IAAI,CAAC,aADS,EAAE,MAAM,GAAG,CACH,CAAC,KAAK,CAAC,UAAU,CAAC,GACtC,OAAO,IACL,oBACA,mCACF;CAIF,IAAI,UAAU,CAAC;MACT,SAAS,CAAC,IAAI,MAAM,GACtB,OAAO,IACL,oBACA,uCACF;CAAA,OAIF,IAAI,CAAC,aAAa,CAAC,GACjB,OAAO,IACL,oBACA,wBACF;CAIJ,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,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC;AACxE;;AAGA,MAAM,iBAAyB;CAC7B,MAAM,KAAK,aAAa,CAAC;CACzB,MAAM,KAAK,aAAa,KAAK,GAAG;CAGhC,MAAM,UAFQ,KAAK,QAAQ,KAAK,MAAM,EAAE,IAC5B,aAAa,CACC;CAC1B,MAAM,KAAK,aAAa,UAAU,GAAG;CACrC,OAAO,UAAU,QAAQ,KAAK,MAAM,EAAE;AACxC;;AAGA,MAAM,QAAgC;CACpC,MAAM;CACN,WACE;CACF,cAAc;CACd,SAAS,CAAC,SAAS,cAAc;CACjC,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,WAAW;CACX,UAAU,CAAC,gBAAgB;CAC3B;CACA;CACA;CACA;AACF"}
package/dist/fr/tva.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/fr/tva.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 French TVA. */
8
8
  declare const generate: () => string;
9
9
  /** French VAT Number. */
10
- declare const tva: Validator;
10
+ declare const tva: CountryValidator<"FR">;
11
11
  //#endregion
12
12
  export { compact, tva as default, format, generate, validate };
13
13
  //# sourceMappingURL=tva.d.ts.map
package/dist/fr/tva.js CHANGED
@@ -1,20 +1,9 @@
1
+ import { luhnChecksum, luhnValidate } from "../_checksums/luhn.js";
1
2
  import { clean } from "../_util/clean.js";
2
3
  import { randomDigits } 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/fr/tva.ts
7
- /**
8
- * n° TVA (Numéro de TVA intracommunautaire).
9
- *
10
- * French VAT number. 11 characters: 2-char
11
- * check prefix + 9-digit SIREN. The prefix
12
- * can be numeric (old style) or alphanumeric
13
- * (new style, letters from a restricted
14
- * alphabet excluding I and O).
15
- *
16
- * @see https://www.economie.gouv.fr/
17
- */
18
7
  const ALPHABET = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ";
19
8
  const compact = (value) => {
20
9
  let v = clean(value, " -.");
@@ -65,6 +54,7 @@ const tva = {
65
54
  "FR VAT"
66
55
  ],
67
56
  candidatePattern: "FR[A-Z0-9]{2}\\d{9}",
57
+ scope: "country",
68
58
  country: "FR",
69
59
  entityType: "company",
70
60
  sourceUrl: "https://www.economie.gouv.fr/",
@@ -1 +1 @@
1
- {"version":3,"file":"tva.js","names":[],"sources":["../../src/fr/tva.ts"],"sourcesContent":["/**\n * n° TVA (Numéro de TVA intracommunautaire).\n *\n * French VAT number. 11 characters: 2-char\n * check prefix + 9-digit SIREN. The prefix\n * can be numeric (old style) or alphanumeric\n * (new style, letters from a restricted\n * alphabet excluding I and O).\n *\n * @see https://www.economie.gouv.fr/\n */\n\nimport {\n luhnValidate,\n luhnChecksum,\n} from \"#checksums/luhn\";\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 ALPHABET = \"0123456789ABCDEFGHJKLMNPQRSTUVWXYZ\";\n\nconst compact = (value: string): string => {\n let v = clean(value, \" -.\");\n if (v.startsWith(\"FR\") || v.startsWith(\"fr\")) {\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 !== 11) {\n return err(\n \"INVALID_LENGTH\",\n \"French TVA must be 11 characters\",\n );\n }\n\n const prefix = v.slice(0, 2);\n const siren = v.slice(2);\n\n if (!isdigits(siren)) {\n return err(\n \"INVALID_FORMAT\",\n \"French TVA SIREN part must be digits\",\n );\n }\n\n // Validate prefix characters are in alphabet\n const p0 = prefix[0] ?? \"\";\n const p1 = prefix[1] ?? \"\";\n if (\n ALPHABET.indexOf(p0) < 0 ||\n ALPHABET.indexOf(p1) < 0\n ) {\n return err(\n \"INVALID_FORMAT\",\n \"French TVA prefix contains invalid chars\",\n );\n }\n\n // SIREN validation (skip Monaco: starts with 000)\n if (!siren.startsWith(\"000\") && !luhnValidate(siren)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"French TVA SIREN part fails Luhn check\",\n );\n }\n\n const c0 = ALPHABET.indexOf(p0);\n const c1 = ALPHABET.indexOf(p1);\n\n if (c0 < 10 && c1 < 10) {\n // Old-style: both digits numeric\n const check = Number(prefix);\n const expected = Number(siren + \"12\") % 97;\n if (check !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"French TVA check digits mismatch\",\n );\n }\n } else {\n // New-style: at least one letter\n let cvalue: number;\n if (c0 < 10) {\n cvalue = c0 * 24 + c1 - 10;\n } else {\n cvalue = c0 * 34 + c1 - 100;\n }\n const sirenNum = Number(siren);\n if (\n (sirenNum + 1 + Math.floor(cvalue / 11)) % 11 !==\n cvalue % 11\n ) {\n return err(\n \"INVALID_CHECKSUM\",\n \"French TVA check digits mismatch\",\n );\n }\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string =>\n `FR${compact(value)}`;\n\n/** Generate a random valid French TVA. */\nconst generate = (): string => {\n const sp = randomDigits(8);\n const cs = luhnChecksum(sp + \"0\");\n const siren = sp + String((10 - cs) % 10);\n const prefix = String(\n (12 + 3 * (Number(siren) % 97)) % 97,\n ).padStart(2, \"0\");\n return prefix + siren;\n};\n\n/** French VAT Number. */\nconst tva: Validator = {\n name: \"French VAT Number\",\n localName: \"Numéro de TVA intracommunautaire\",\n abbreviation: \"TVA\",\n aliases: [\n \"numéro de TVA\",\n \"TVA intracommunautaire\",\n \"FR VAT\",\n ] as const,\n candidatePattern: \"FR[A-Z0-9]{2}\\\\d{9}\",\n country: \"FR\",\n entityType: \"company\",\n sourceUrl: \"https://www.economie.gouv.fr/\",\n examples: [\"40303265045\", \"K7399859412\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default tva;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;;;;;;;;;;;;AAuBA,MAAM,WAAW;AAEjB,MAAM,WAAW,UAA0B;CACzC,IAAI,IAAI,MAAM,OAAO,MAAM;AAC3B,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,GACf,QAAO,IACL,kBACA,mCACD;CAGH,MAAM,SAAS,EAAE,MAAM,GAAG,EAAE;CAC5B,MAAM,QAAQ,EAAE,MAAM,EAAE;AAExB,KAAI,CAAC,SAAS,MAAM,CAClB,QAAO,IACL,kBACA,uCACD;CAIH,MAAM,KAAK,OAAO,MAAM;CACxB,MAAM,KAAK,OAAO,MAAM;AACxB,KACE,SAAS,QAAQ,GAAG,GAAG,KACvB,SAAS,QAAQ,GAAG,GAAG,EAEvB,QAAO,IACL,kBACA,2CACD;AAIH,KAAI,CAAC,MAAM,WAAW,MAAM,IAAI,CAAC,aAAa,MAAM,CAClD,QAAO,IACL,oBACA,yCACD;CAGH,MAAM,KAAK,SAAS,QAAQ,GAAG;CAC/B,MAAM,KAAK,SAAS,QAAQ,GAAG;AAE/B,KAAI,KAAK,MAAM,KAAK;MAEJ,OAAO,OAAO,KACX,OAAO,QAAQ,KAAK,GAAG,GAEtC,QAAO,IACL,oBACA,mCACD;QAEE;EAEL,IAAI;AACJ,MAAI,KAAK,GACP,UAAS,KAAK,KAAK,KAAK;MAExB,UAAS,KAAK,KAAK,KAAK;AAG1B,OADiB,OAAO,MAAM,GAEhB,IAAI,KAAK,MAAM,SAAS,GAAG,IAAI,OAC3C,SAAS,GAET,QAAO,IACL,oBACA,mCACD;;AAIL,QAAO;EAAE,OAAO;EAAM,SAAS;EAAG;;AAGpC,MAAM,UAAU,UACd,KAAK,QAAQ,MAAM;;AAGrB,MAAM,iBAAyB;CAC7B,MAAM,KAAK,aAAa,EAAE;CAC1B,MAAM,KAAK,aAAa,KAAK,IAAI;CACjC,MAAM,QAAQ,KAAK,QAAQ,KAAK,MAAM,GAAG;AAIzC,QAHe,QACZ,KAAK,KAAK,OAAO,MAAM,GAAG,OAAO,GACnC,CAAC,SAAS,GAAG,IAAI,GACF;;;AAIlB,MAAM,MAAiB;CACrB,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS;EACP;EACA;EACA;EACD;CACD,kBAAkB;CAClB,SAAS;CACT,YAAY;CACZ,WAAW;CACX,UAAU,CAAC,eAAe,cAAc;CACxC;CACA;CACA;CACA;CACD"}
1
+ {"version":3,"file":"tva.js","names":[],"sources":["../../src/fr/tva.ts"],"sourcesContent":["/**\n * n° TVA (Numéro de TVA intracommunautaire).\n *\n * French VAT number. 11 characters: 2-char\n * check prefix + 9-digit SIREN. The prefix\n * can be numeric (old style) or alphanumeric\n * (new style, letters from a restricted\n * alphabet excluding I and O).\n *\n * @see https://www.economie.gouv.fr/\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport {\n luhnValidate,\n luhnChecksum,\n} from \"#checksums/luhn\";\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst ALPHABET = \"0123456789ABCDEFGHJKLMNPQRSTUVWXYZ\";\n\nconst compact = (value: string): string => {\n let v = clean(value, \" -.\");\n if (v.startsWith(\"FR\") || v.startsWith(\"fr\")) {\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 !== 11) {\n return err(\n \"INVALID_LENGTH\",\n \"French TVA must be 11 characters\",\n );\n }\n\n const prefix = v.slice(0, 2);\n const siren = v.slice(2);\n\n if (!isdigits(siren)) {\n return err(\n \"INVALID_FORMAT\",\n \"French TVA SIREN part must be digits\",\n );\n }\n\n // Validate prefix characters are in alphabet\n const p0 = prefix[0] ?? \"\";\n const p1 = prefix[1] ?? \"\";\n if (\n ALPHABET.indexOf(p0) < 0 ||\n ALPHABET.indexOf(p1) < 0\n ) {\n return err(\n \"INVALID_FORMAT\",\n \"French TVA prefix contains invalid chars\",\n );\n }\n\n // SIREN validation (skip Monaco: starts with 000)\n if (!siren.startsWith(\"000\") && !luhnValidate(siren)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"French TVA SIREN part fails Luhn check\",\n );\n }\n\n const c0 = ALPHABET.indexOf(p0);\n const c1 = ALPHABET.indexOf(p1);\n\n if (c0 < 10 && c1 < 10) {\n // Old-style: both digits numeric\n const check = Number(prefix);\n const expected = Number(siren + \"12\") % 97;\n if (check !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"French TVA check digits mismatch\",\n );\n }\n } else {\n // New-style: at least one letter\n let cvalue: number;\n if (c0 < 10) {\n cvalue = c0 * 24 + c1 - 10;\n } else {\n cvalue = c0 * 34 + c1 - 100;\n }\n const sirenNum = Number(siren);\n if (\n (sirenNum + 1 + Math.floor(cvalue / 11)) % 11 !==\n cvalue % 11\n ) {\n return err(\n \"INVALID_CHECKSUM\",\n \"French TVA check digits mismatch\",\n );\n }\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string =>\n `FR${compact(value)}`;\n\n/** Generate a random valid French TVA. */\nconst generate = (): string => {\n const sp = randomDigits(8);\n const cs = luhnChecksum(sp + \"0\");\n const siren = sp + String((10 - cs) % 10);\n const prefix = String(\n (12 + 3 * (Number(siren) % 97)) % 97,\n ).padStart(2, \"0\");\n return prefix + siren;\n};\n\n/** French VAT Number. */\nconst tva: CountryValidator<\"FR\"> = {\n name: \"French VAT Number\",\n localName: \"Numéro de TVA intracommunautaire\",\n abbreviation: \"TVA\",\n aliases: [\n \"numéro de TVA\",\n \"TVA intracommunautaire\",\n \"FR VAT\",\n ] as const,\n candidatePattern: \"FR[A-Z0-9]{2}\\\\d{9}\",\n scope: \"country\",\n country: \"FR\",\n entityType: \"company\",\n sourceUrl: \"https://www.economie.gouv.fr/\",\n examples: [\"40303265045\", \"K7399859412\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default tva;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;AA0BA,MAAM,WAAW;AAEjB,MAAM,WAAW,UAA0B;CACzC,IAAI,IAAI,MAAM,OAAO,KAAK;CAC1B,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,IACf,OAAO,IACL,kBACA,kCACF;CAGF,MAAM,SAAS,EAAE,MAAM,GAAG,CAAC;CAC3B,MAAM,QAAQ,EAAE,MAAM,CAAC;CAEvB,IAAI,CAAC,SAAS,KAAK,GACjB,OAAO,IACL,kBACA,sCACF;CAIF,MAAM,KAAK,OAAO,MAAM;CACxB,MAAM,KAAK,OAAO,MAAM;CACxB,IACE,SAAS,QAAQ,EAAE,IAAI,KACvB,SAAS,QAAQ,EAAE,IAAI,GAEvB,OAAO,IACL,kBACA,0CACF;CAIF,IAAI,CAAC,MAAM,WAAW,KAAK,KAAK,CAAC,aAAa,KAAK,GACjD,OAAO,IACL,oBACA,wCACF;CAGF,MAAM,KAAK,SAAS,QAAQ,EAAE;CAC9B,MAAM,KAAK,SAAS,QAAQ,EAAE;CAE9B,IAAI,KAAK,MAAM,KAAK;MAEJ,OAAO,MAEb,MADS,OAAO,QAAQ,IAAI,IAAI,IAEtC,OAAO,IACL,oBACA,kCACF;CAAA,OAEG;EAEL,IAAI;EACJ,IAAI,KAAK,IACP,SAAS,KAAK,KAAK,KAAK;OAExB,SAAS,KAAK,KAAK,KAAK;EAG1B,KADiB,OAAO,KAEd,IAAI,IAAI,KAAK,MAAM,SAAS,EAAE,KAAK,OAC3C,SAAS,IAET,OAAO,IACL,oBACA,kCACF;CAEJ;CAEA,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UACd,KAAK,QAAQ,KAAK;;AAGpB,MAAM,iBAAyB;CAC7B,MAAM,KAAK,aAAa,CAAC;CACzB,MAAM,KAAK,aAAa,KAAK,GAAG;CAChC,MAAM,QAAQ,KAAK,QAAQ,KAAK,MAAM,EAAE;CAIxC,OAHe,QACZ,KAAK,KAAK,OAAO,KAAK,IAAI,OAAO,EACpC,EAAE,SAAS,GAAG,GACF,IAAI;AAClB;;AAGA,MAAM,MAA8B;CAClC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS;EACP;EACA;EACA;CACF;CACA,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,WAAW;CACX,UAAU,CAAC,eAAe,aAAa;CACvC;CACA;CACA;CACA;AACF"}