@stll/stdnum 0.0.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -5
- package/README.md +28 -4
- package/dist/_checksums/luhn.js.map +1 -1
- package/dist/_checksums/mod1110.js +1 -1
- package/dist/_checksums/mod1110.js.map +1 -1
- package/dist/_checksums/mod112.js +5 -5
- package/dist/_checksums/mod112.js.map +1 -1
- package/dist/_checksums/mod97.js.map +1 -1
- package/dist/_checksums/verhoeff.js.map +1 -1
- package/dist/_checksums/weighted-sum.js.map +1 -1
- package/dist/_util/arabic.js.map +1 -1
- package/dist/_util/clean.js.map +1 -1
- package/dist/_util/date.js.map +1 -1
- package/dist/_util/generate.d.ts +13 -1
- package/dist/_util/generate.js +23 -1
- package/dist/_util/generate.js.map +1 -1
- package/dist/_util/result.js.map +1 -1
- package/dist/_util/strings.js.map +1 -1
- package/dist/ad/mod.d.ts +3 -2
- package/dist/ad/nrt.d.ts +16 -2
- package/dist/ad/nrt.js +4 -16
- package/dist/ad/nrt.js.map +1 -1
- package/dist/ae/eid.d.ts +2 -3
- package/dist/ae/eid.js +2 -12
- package/dist/ae/eid.js.map +1 -1
- package/dist/ae/mod.d.ts +3 -2
- package/dist/ai/mod.d.ts +3 -2
- package/dist/ai/tin.d.ts +20 -2
- package/dist/ai/tin.js +1 -18
- package/dist/ai/tin.js.map +1 -1
- package/dist/al/mod.d.ts +3 -2
- package/dist/al/nipt.d.ts +13 -2
- package/dist/al/nipt.js +1 -11
- package/dist/al/nipt.js.map +1 -1
- package/dist/am/mod.d.ts +3 -2
- package/dist/am/tin.d.ts +16 -2
- package/dist/am/tin.js +1 -14
- package/dist/am/tin.js.map +1 -1
- package/dist/ar/cbu.d.ts +2 -3
- package/dist/ar/cbu.js +2 -10
- package/dist/ar/cbu.js.map +1 -1
- package/dist/ar/cuit.d.ts +2 -3
- package/dist/ar/cuit.js +13 -29
- package/dist/ar/cuit.js.map +1 -1
- package/dist/ar/dni.d.ts +11 -2
- package/dist/ar/dni.js +1 -9
- package/dist/ar/dni.js.map +1 -1
- package/dist/ar/mod.d.ts +3 -2
- package/dist/at/businessid.d.ts +10 -2
- package/dist/at/businessid.js +1 -8
- package/dist/at/businessid.js.map +1 -1
- package/dist/at/mod.d.ts +3 -2
- package/dist/at/tin.d.ts +2 -3
- package/dist/at/tin.js +1 -11
- package/dist/at/tin.js.map +1 -1
- package/dist/at/uid.d.ts +2 -3
- package/dist/at/uid.js +2 -10
- package/dist/at/uid.js.map +1 -1
- package/dist/at/vnr.d.ts +5 -4
- package/dist/at/vnr.js +23 -16
- package/dist/at/vnr.js.map +1 -1
- package/dist/au/abn.d.ts +2 -3
- package/dist/au/abn.js +1 -10
- package/dist/au/abn.js.map +1 -1
- package/dist/au/acn.d.ts +2 -3
- package/dist/au/acn.js +1 -10
- package/dist/au/acn.js.map +1 -1
- package/dist/au/mod.d.ts +3 -2
- package/dist/au/tfn.d.ts +2 -3
- package/dist/au/tfn.js +1 -10
- package/dist/au/tfn.js.map +1 -1
- package/dist/az/mod.d.ts +3 -2
- package/dist/az/voen.d.ts +2 -3
- package/dist/az/voen.js +1 -14
- package/dist/az/voen.js.map +1 -1
- package/dist/ba/jmbg.d.ts +2 -3
- package/dist/ba/jmbg.js +4 -11
- package/dist/ba/jmbg.js.map +1 -1
- package/dist/ba/mod.d.ts +3 -2
- package/dist/bd/mod.d.ts +3 -2
- package/dist/bd/nid.d.ts +23 -2
- package/dist/bd/nid.js +11 -32
- package/dist/bd/nid.js.map +1 -1
- package/dist/be/bis.d.ts +2 -3
- package/dist/be/bis.js +1 -11
- package/dist/be/bis.js.map +1 -1
- package/dist/be/mod.d.ts +3 -2
- package/dist/be/nn.d.ts +2 -3
- package/dist/be/nn.js +1 -11
- package/dist/be/nn.js.map +1 -1
- package/dist/be/vat.d.ts +2 -3
- package/dist/be/vat.js +1 -9
- package/dist/be/vat.js.map +1 -1
- package/dist/bg/egn.d.ts +2 -3
- package/dist/bg/egn.js +5 -13
- package/dist/bg/egn.js.map +1 -1
- package/dist/bg/mod.d.ts +3 -2
- package/dist/bg/pnf.d.ts +2 -3
- package/dist/bg/pnf.js +1 -8
- package/dist/bg/pnf.js.map +1 -1
- package/dist/bg/vat.d.ts +2 -3
- package/dist/bg/vat.js +3 -9
- package/dist/bg/vat.js.map +1 -1
- package/dist/bh/cpr.d.ts +5 -4
- package/dist/bh/cpr.js +9 -19
- package/dist/bh/cpr.js.map +1 -1
- package/dist/bh/mod.d.ts +3 -2
- package/dist/bic.d.ts +13 -2
- package/dist/bic.js +14 -26
- package/dist/bic.js.map +1 -1
- package/dist/br/cnpj.d.ts +2 -3
- package/dist/br/cnpj.js +1 -20
- package/dist/br/cnpj.js.map +1 -1
- package/dist/br/cpf.d.ts +2 -3
- package/dist/br/cpf.js +1 -14
- package/dist/br/cpf.js.map +1 -1
- package/dist/br/mod.d.ts +3 -2
- package/dist/by/mod.d.ts +3 -2
- package/dist/by/unp.d.ts +2 -3
- package/dist/by/unp.js +9 -17
- package/dist/by/unp.js.map +1 -1
- package/dist/bz/mod.d.ts +3 -2
- package/dist/bz/tin.d.ts +5 -4
- package/dist/bz/tin.js +10 -27
- package/dist/bz/tin.js.map +1 -1
- package/dist/ca/bn.d.ts +2 -3
- package/dist/ca/bn.js +2 -10
- package/dist/ca/bn.js.map +1 -1
- package/dist/ca/mod.d.ts +3 -2
- package/dist/ca/sin.d.ts +2 -3
- package/dist/ca/sin.js +2 -10
- package/dist/ca/sin.js.map +1 -1
- package/dist/ch/mod.d.ts +3 -2
- package/dist/ch/ssn.d.ts +2 -3
- package/dist/ch/ssn.js +1 -9
- package/dist/ch/ssn.js.map +1 -1
- package/dist/ch/uid.d.ts +2 -3
- package/dist/ch/uid.js +1 -9
- package/dist/ch/uid.js.map +1 -1
- package/dist/ch/vat.d.ts +2 -3
- package/dist/ch/vat.js +1 -9
- package/dist/ch/vat.js.map +1 -1
- package/dist/cl/mod.d.ts +3 -2
- package/dist/cl/rut.d.ts +2 -3
- package/dist/cl/rut.js +2 -15
- package/dist/cl/rut.js.map +1 -1
- package/dist/cn/mod.d.ts +3 -2
- package/dist/cn/ric.d.ts +2 -3
- package/dist/cn/ric.js +4 -14
- package/dist/cn/ric.js.map +1 -1
- package/dist/cn/uscc.d.ts +2 -3
- package/dist/cn/uscc.js +8 -16
- package/dist/cn/uscc.js.map +1 -1
- package/dist/co/mod.d.ts +3 -2
- package/dist/co/nit.d.ts +2 -3
- package/dist/co/nit.js +6 -13
- package/dist/co/nit.js.map +1 -1
- package/dist/cr/cpf.d.ts +18 -2
- package/dist/cr/cpf.js +5 -19
- package/dist/cr/cpf.js.map +1 -1
- package/dist/cr/mod.d.ts +3 -2
- package/dist/creditcard.d.ts +2 -3
- package/dist/creditcard.js +5 -14
- package/dist/creditcard.js.map +1 -1
- package/dist/cu/mod.d.ts +3 -2
- package/dist/cu/ni.d.ts +5 -4
- package/dist/cu/ni.js +13 -18
- package/dist/cu/ni.js.map +1 -1
- package/dist/cy/mod.d.ts +3 -2
- package/dist/cy/vat.d.ts +2 -3
- package/dist/cy/vat.js +1 -8
- package/dist/cy/vat.js.map +1 -1
- package/dist/cz/dic.d.ts +2 -3
- package/dist/cz/dic.js +7 -13
- package/dist/cz/dic.js.map +1 -1
- package/dist/cz/ico.d.ts +2 -3
- package/dist/cz/ico.js +2 -10
- package/dist/cz/ico.js.map +1 -1
- package/dist/cz/mod.d.ts +3 -2
- package/dist/cz/rc.d.ts +2 -3
- package/dist/cz/rc.js +22 -21
- package/dist/cz/rc.js.map +1 -1
- package/dist/de/handelsreg.d.ts +19 -2
- package/dist/de/handelsreg.js +10 -26
- package/dist/de/handelsreg.js.map +1 -1
- package/dist/de/idnr.d.ts +2 -3
- package/dist/de/idnr.js +2 -12
- package/dist/de/idnr.js.map +1 -1
- package/dist/de/mod.d.ts +3 -2
- package/dist/de/stnr.d.ts +17 -3
- package/dist/de/stnr.js +1 -15
- package/dist/de/stnr.js.map +1 -1
- package/dist/de/svnr.d.ts +2 -3
- package/dist/de/svnr.js +4 -13
- package/dist/de/svnr.js.map +1 -1
- package/dist/de/vat.d.ts +2 -3
- package/dist/de/vat.js +2 -11
- package/dist/de/vat.js.map +1 -1
- package/dist/dk/cpr.d.ts +5 -4
- package/dist/dk/cpr.js +14 -12
- package/dist/dk/cpr.js.map +1 -1
- package/dist/dk/cvr.d.ts +2 -3
- package/dist/dk/cvr.js +2 -15
- package/dist/dk/cvr.js.map +1 -1
- package/dist/dk/mod.d.ts +3 -2
- package/dist/dk/vat.d.ts +2 -3
- package/dist/dk/vat.js +3 -13
- package/dist/dk/vat.js.map +1 -1
- package/dist/do/mod.d.ts +3 -2
- package/dist/do/rnc.d.ts +2 -3
- package/dist/do/rnc.js +3 -17
- package/dist/do/rnc.js.map +1 -1
- package/dist/ec/mod.d.ts +3 -2
- package/dist/ec/ruc.d.ts +2 -3
- package/dist/ec/ruc.js +2 -19
- package/dist/ec/ruc.js.map +1 -1
- package/dist/ee/ik.d.ts +2 -3
- package/dist/ee/ik.js +6 -15
- package/dist/ee/ik.js.map +1 -1
- package/dist/ee/mod.d.ts +3 -2
- package/dist/ee/registrikood.d.ts +2 -3
- package/dist/ee/registrikood.js +9 -15
- package/dist/ee/registrikood.js.map +1 -1
- package/dist/ee/vat.d.ts +2 -3
- package/dist/ee/vat.js +2 -10
- package/dist/ee/vat.js.map +1 -1
- package/dist/eg/mod.d.ts +3 -2
- package/dist/eg/tn.d.ts +11 -2
- package/dist/eg/tn.js +1 -9
- package/dist/eg/tn.js.map +1 -1
- package/dist/es/cif.d.ts +2 -3
- package/dist/es/cif.js +3 -12
- package/dist/es/cif.js.map +1 -1
- package/dist/es/dni.d.ts +2 -3
- package/dist/es/dni.js +1 -9
- package/dist/es/dni.js.map +1 -1
- package/dist/es/mod.d.ts +3 -2
- package/dist/es/nie.d.ts +2 -3
- package/dist/es/nie.js +14 -22
- package/dist/es/nie.js.map +1 -1
- package/dist/es/nss.d.ts +2 -3
- package/dist/es/nss.js +1 -16
- package/dist/es/nss.js.map +1 -1
- package/dist/es/vat.d.ts +2 -3
- package/dist/es/vat.js +5 -10
- package/dist/es/vat.js.map +1 -1
- package/dist/eu/mod.d.ts +3 -2
- package/dist/eu/vat.d.ts +5 -4
- package/dist/eu/vat.js +44 -2
- package/dist/eu/vat.js.map +1 -1
- package/dist/fi/hetu.d.ts +5 -4
- package/dist/fi/hetu.js +19 -12
- package/dist/fi/hetu.js.map +1 -1
- package/dist/fi/mod.d.ts +3 -2
- package/dist/fi/vat.d.ts +2 -3
- package/dist/fi/vat.js +3 -10
- package/dist/fi/vat.js.map +1 -1
- package/dist/fi/ytunnus.d.ts +2 -3
- package/dist/fi/ytunnus.js +2 -10
- package/dist/fi/ytunnus.js.map +1 -1
- package/dist/fr/mod.d.ts +3 -2
- package/dist/fr/nif.d.ts +2 -3
- package/dist/fr/nif.js +1 -9
- package/dist/fr/nif.js.map +1 -1
- package/dist/fr/nir.d.ts +2 -3
- package/dist/fr/nir.js +3 -14
- package/dist/fr/nir.js.map +1 -1
- package/dist/fr/siren.d.ts +2 -3
- package/dist/fr/siren.js +2 -10
- package/dist/fr/siren.js.map +1 -1
- package/dist/fr/siret.d.ts +2 -3
- package/dist/fr/siret.js +2 -11
- package/dist/fr/siret.js.map +1 -1
- package/dist/fr/tva.d.ts +2 -3
- package/dist/fr/tva.js +2 -12
- package/dist/fr/tva.js.map +1 -1
- package/dist/gb/mod.d.ts +3 -2
- package/dist/gb/nino.d.ts +12 -2
- package/dist/gb/nino.js +8 -17
- package/dist/gb/nino.js.map +1 -1
- package/dist/gb/sedol.d.ts +2 -3
- package/dist/gb/sedol.js +9 -18
- package/dist/gb/sedol.js.map +1 -1
- package/dist/gb/utr.d.ts +2 -3
- package/dist/gb/utr.js +2 -10
- package/dist/gb/utr.js.map +1 -1
- package/dist/gb/vat.d.ts +2 -3
- package/dist/gb/vat.js +2 -11
- package/dist/gb/vat.js.map +1 -1
- package/dist/ge/mod.d.ts +3 -2
- package/dist/ge/pin.d.ts +14 -2
- package/dist/ge/pin.js +1 -12
- package/dist/ge/pin.js.map +1 -1
- package/dist/gh/mod.d.ts +3 -2
- package/dist/gh/tin.d.ts +2 -3
- package/dist/gh/tin.js +10 -24
- package/dist/gh/tin.js.map +1 -1
- package/dist/gr/amka.d.ts +2 -3
- package/dist/gr/amka.js +3 -11
- package/dist/gr/amka.js.map +1 -1
- package/dist/gr/mod.d.ts +3 -2
- package/dist/gr/vat.d.ts +2 -3
- package/dist/gr/vat.js +1 -10
- package/dist/gr/vat.js.map +1 -1
- package/dist/gt/mod.d.ts +3 -2
- package/dist/gt/nit.d.ts +2 -3
- package/dist/gt/nit.js +6 -14
- package/dist/gt/nit.js.map +1 -1
- package/dist/hk/hkid.d.ts +2 -3
- package/dist/hk/hkid.js +2 -10
- package/dist/hk/hkid.js.map +1 -1
- package/dist/hk/mod.d.ts +3 -2
- package/dist/hr/mod.d.ts +3 -2
- package/dist/hr/vat.d.ts +2 -3
- package/dist/hr/vat.js +2 -9
- package/dist/hr/vat.js.map +1 -1
- package/dist/hu/mod.d.ts +3 -2
- package/dist/hu/vat.d.ts +2 -3
- package/dist/hu/vat.js +3 -10
- package/dist/hu/vat.js.map +1 -1
- package/dist/iban.d.ts +2 -3
- package/dist/iban.js +2 -8
- package/dist/iban.js.map +1 -1
- package/dist/id/mod.d.ts +3 -2
- package/dist/id/npwp.d.ts +2 -3
- package/dist/id/npwp.js +3 -13
- package/dist/id/npwp.js.map +1 -1
- package/dist/ie/mod.d.ts +3 -2
- package/dist/ie/pps.d.ts +2 -3
- package/dist/ie/pps.js +1 -10
- package/dist/ie/pps.js.map +1 -1
- package/dist/ie/vat.d.ts +2 -3
- package/dist/ie/vat.js +1 -9
- package/dist/ie/vat.js.map +1 -1
- package/dist/il/idnr.d.ts +2 -3
- package/dist/il/idnr.js +2 -9
- package/dist/il/idnr.js.map +1 -1
- package/dist/il/mod.d.ts +3 -2
- package/dist/in/aadhaar.d.ts +2 -3
- package/dist/in/aadhaar.js +2 -12
- package/dist/in/aadhaar.js.map +1 -1
- package/dist/in/gstin.d.ts +2 -3
- package/dist/in/gstin.js +4 -11
- package/dist/in/gstin.js.map +1 -1
- package/dist/in/mod.d.ts +3 -2
- package/dist/in/pan.d.ts +15 -2
- package/dist/in/pan.js +3 -15
- package/dist/in/pan.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6 -6
- package/dist/iq/mod.d.ts +3 -2
- package/dist/iq/nid.d.ts +16 -2
- package/dist/iq/nid.js +2 -15
- package/dist/iq/nid.js.map +1 -1
- package/dist/ir/mod.d.ts +3 -2
- package/dist/ir/nid.d.ts +2 -3
- package/dist/ir/nid.js +2 -24
- package/dist/ir/nid.js.map +1 -1
- package/dist/is/kennitala.d.ts +2 -3
- package/dist/is/kennitala.js +2 -13
- package/dist/is/kennitala.js.map +1 -1
- package/dist/is/mod.d.ts +3 -2
- package/dist/is/vsk.d.ts +9 -2
- package/dist/is/vsk.js +1 -7
- package/dist/is/vsk.js.map +1 -1
- package/dist/isin.d.ts +2 -3
- package/dist/isin.js +11 -21
- package/dist/isin.js.map +1 -1
- package/dist/it/codicefiscale.d.ts +5 -4
- package/dist/it/codicefiscale.js +27 -23
- package/dist/it/codicefiscale.js.map +1 -1
- package/dist/it/iva.d.ts +2 -3
- package/dist/it/iva.js +2 -9
- package/dist/it/iva.js.map +1 -1
- package/dist/it/mod.d.ts +3 -2
- package/dist/jp/cn.d.ts +2 -3
- package/dist/jp/cn.js +1 -9
- package/dist/jp/cn.js.map +1 -1
- package/dist/jp/mod.d.ts +3 -2
- package/dist/jp/mynumber.d.ts +2 -3
- package/dist/jp/mynumber.js +1 -10
- package/dist/jp/mynumber.js.map +1 -1
- package/dist/kr/brn.d.ts +11 -2
- package/dist/kr/brn.js +1 -9
- package/dist/kr/brn.js.map +1 -1
- package/dist/kr/mod.d.ts +3 -2
- package/dist/kr/rrn.d.ts +5 -4
- package/dist/kr/rrn.js +15 -13
- package/dist/kr/rrn.js.map +1 -1
- package/dist/kw/civil.d.ts +6 -5
- package/dist/kw/civil.js +20 -17
- package/dist/kw/civil.js.map +1 -1
- package/dist/kw/mod.d.ts +3 -2
- package/dist/kz/iin.d.ts +2 -3
- package/dist/kz/iin.js +4 -18
- package/dist/kz/iin.js.map +1 -1
- package/dist/kz/mod.d.ts +3 -2
- package/dist/lei.d.ts +2 -3
- package/dist/lei.js +2 -11
- package/dist/lei.js.map +1 -1
- package/dist/li/mod.d.ts +3 -2
- package/dist/li/peid.d.ts +11 -2
- package/dist/li/peid.js +1 -9
- package/dist/li/peid.js.map +1 -1
- package/dist/lk/mod.d.ts +3 -2
- package/dist/lk/nic.d.ts +5 -4
- package/dist/lk/nic.js +16 -16
- package/dist/lk/nic.js.map +1 -1
- package/dist/lt/asmens.d.ts +2 -3
- package/dist/lt/asmens.js +2 -1
- package/dist/lt/asmens.js.map +1 -1
- package/dist/lt/mod.d.ts +3 -2
- package/dist/lt/vat.d.ts +2 -3
- package/dist/lt/vat.js +2 -10
- package/dist/lt/vat.js.map +1 -1
- package/dist/lu/mod.d.ts +3 -2
- package/dist/lu/vat.d.ts +2 -3
- package/dist/lu/vat.js +2 -8
- package/dist/lu/vat.js.map +1 -1
- package/dist/luhn.d.ts +2 -3
- package/dist/luhn.js +9 -9
- package/dist/luhn.js.map +1 -1
- package/dist/lv/mod.d.ts +3 -2
- package/dist/lv/vat.d.ts +2 -3
- package/dist/lv/vat.js +19 -18
- package/dist/lv/vat.js.map +1 -1
- package/dist/ma/ice.d.ts +2 -3
- package/dist/ma/ice.js +2 -11
- package/dist/ma/ice.js.map +1 -1
- package/dist/ma/mod.d.ts +3 -2
- package/dist/mc/mod.d.ts +3 -2
- package/dist/mc/tva.d.ts +2 -3
- package/dist/mc/tva.js +1 -0
- package/dist/mc/tva.js.map +1 -1
- package/dist/md/idno.d.ts +2 -3
- package/dist/md/idno.js +1 -10
- package/dist/md/idno.js.map +1 -1
- package/dist/md/mod.d.ts +3 -2
- package/dist/me/mod.d.ts +3 -2
- package/dist/me/pib.d.ts +2 -3
- package/dist/me/pib.js +2 -10
- package/dist/me/pib.js.map +1 -1
- package/dist/mk/edb.d.ts +2 -3
- package/dist/mk/edb.js +2 -11
- package/dist/mk/edb.js.map +1 -1
- package/dist/mk/mod.d.ts +3 -2
- package/dist/mt/mod.d.ts +3 -2
- package/dist/mt/vat.d.ts +2 -3
- package/dist/mt/vat.js +3 -10
- package/dist/mt/vat.js.map +1 -1
- package/dist/mu/brn.d.ts +23 -2
- package/dist/mu/brn.js +1 -21
- package/dist/mu/brn.js.map +1 -1
- package/dist/mu/mod.d.ts +3 -2
- package/dist/mx/clabe.d.ts +2 -3
- package/dist/mx/clabe.js +1 -14
- package/dist/mx/clabe.js.map +1 -1
- package/dist/mx/curp.d.ts +5 -4
- package/dist/mx/curp.js +27 -19
- package/dist/mx/curp.js.map +1 -1
- package/dist/mx/mod.d.ts +3 -2
- package/dist/mx/rfc.d.ts +5 -4
- package/dist/mx/rfc.js +23 -20
- package/dist/mx/rfc.js.map +1 -1
- package/dist/my/mod.d.ts +3 -2
- package/dist/my/nric.d.ts +5 -4
- package/dist/my/nric.js +18 -16
- package/dist/my/nric.js.map +1 -1
- package/dist/ng/mod.d.ts +3 -2
- package/dist/ng/nin.d.ts +13 -2
- package/dist/ng/nin.js +1 -11
- package/dist/ng/nin.js.map +1 -1
- package/dist/ni/mod.d.ts +3 -2
- package/dist/ni/ruc.d.ts +2 -3
- package/dist/ni/ruc.js +1 -23
- package/dist/ni/ruc.js.map +1 -1
- package/dist/nl/bsn.d.ts +2 -3
- package/dist/nl/bsn.js +2 -10
- package/dist/nl/bsn.js.map +1 -1
- package/dist/nl/kvk.d.ts +9 -2
- package/dist/nl/kvk.js +1 -7
- package/dist/nl/kvk.js.map +1 -1
- package/dist/nl/mod.d.ts +3 -2
- package/dist/nl/vat.d.ts +2 -3
- package/dist/nl/vat.js +4 -50
- package/dist/nl/vat.js.map +1 -1
- package/dist/no/fodselsnummer.d.ts +2 -3
- package/dist/no/fodselsnummer.js +3 -10
- package/dist/no/fodselsnummer.js.map +1 -1
- package/dist/no/mod.d.ts +3 -2
- package/dist/no/mva.d.ts +2 -3
- package/dist/no/mva.js +1 -8
- package/dist/no/mva.js.map +1 -1
- package/dist/no/orgnr.d.ts +2 -3
- package/dist/no/orgnr.js +2 -8
- package/dist/no/orgnr.js.map +1 -1
- package/dist/nz/ird.d.ts +2 -3
- package/dist/nz/ird.js +4 -13
- package/dist/nz/ird.js.map +1 -1
- package/dist/nz/mod.d.ts +3 -2
- package/dist/pa/mod.d.ts +3 -2
- package/dist/pa/ruc.d.ts +2 -3
- package/dist/pa/ruc.js +4 -19
- package/dist/pa/ruc.js.map +1 -1
- package/dist/patterns.d.ts +8 -10
- package/dist/patterns.js +83 -28
- package/dist/patterns.js.map +1 -1
- package/dist/pe/mod.d.ts +3 -2
- package/dist/pe/ruc.d.ts +2 -3
- package/dist/pe/ruc.js +10 -24
- package/dist/pe/ruc.js.map +1 -1
- package/dist/ph/mod.d.ts +3 -2
- package/dist/ph/philid.d.ts +14 -2
- package/dist/ph/philid.js +1 -12
- package/dist/ph/philid.js.map +1 -1
- package/dist/pk/cnic.d.ts +14 -2
- package/dist/pk/cnic.js +1 -12
- package/dist/pk/cnic.js.map +1 -1
- package/dist/pk/mod.d.ts +3 -2
- package/dist/pl/mod.d.ts +3 -2
- package/dist/pl/nip.d.ts +2 -3
- package/dist/pl/nip.js +2 -10
- package/dist/pl/nip.js.map +1 -1
- package/dist/pl/pesel.d.ts +2 -3
- package/dist/pl/pesel.js +4 -13
- package/dist/pl/pesel.js.map +1 -1
- package/dist/pl/regon.d.ts +2 -3
- package/dist/pl/regon.js +2 -11
- package/dist/pl/regon.js.map +1 -1
- package/dist/pt/cc.d.ts +2 -3
- package/dist/pt/cc.js +7 -13
- package/dist/pt/cc.js.map +1 -1
- package/dist/pt/mod.d.ts +3 -2
- package/dist/pt/vat.d.ts +2 -3
- package/dist/pt/vat.js +3 -11
- package/dist/pt/vat.js.map +1 -1
- package/dist/ro/cnp.d.ts +2 -3
- package/dist/ro/cnp.js +5 -14
- package/dist/ro/cnp.js.map +1 -1
- package/dist/ro/mod.d.ts +3 -2
- package/dist/ro/vat.d.ts +2 -3
- package/dist/ro/vat.js +13 -11
- package/dist/ro/vat.js.map +1 -1
- package/dist/rs/mod.d.ts +3 -2
- package/dist/rs/pib.d.ts +2 -3
- package/dist/rs/pib.js +1 -9
- package/dist/rs/pib.js.map +1 -1
- package/dist/ru/inn.d.ts +2 -3
- package/dist/ru/inn.js +2 -12
- package/dist/ru/inn.js.map +1 -1
- package/dist/ru/mod.d.ts +3 -2
- package/dist/se/mod.d.ts +3 -2
- package/dist/se/orgnr.d.ts +2 -3
- package/dist/se/orgnr.js +2 -9
- package/dist/se/orgnr.js.map +1 -1
- package/dist/se/personnummer.d.ts +2 -3
- package/dist/se/personnummer.js +8 -15
- package/dist/se/personnummer.js.map +1 -1
- package/dist/se/vat.d.ts +2 -3
- package/dist/se/vat.js +3 -10
- package/dist/se/vat.js.map +1 -1
- package/dist/sg/mod.d.ts +3 -2
- package/dist/sg/uen.d.ts +2 -3
- package/dist/sg/uen.js +47 -70
- package/dist/sg/uen.js.map +1 -1
- package/dist/si/emso.d.ts +2 -3
- package/dist/si/emso.js +12 -14
- package/dist/si/emso.js.map +1 -1
- package/dist/si/mod.d.ts +3 -2
- package/dist/si/vat.d.ts +2 -3
- package/dist/si/vat.js +3 -12
- package/dist/si/vat.js.map +1 -1
- package/dist/sk/dic.d.ts +2 -3
- package/dist/sk/dic.js +1 -0
- package/dist/sk/dic.js.map +1 -1
- package/dist/sk/ico.d.ts +2 -3
- package/dist/sk/ico.js +1 -0
- package/dist/sk/ico.js.map +1 -1
- package/dist/sk/mod.d.ts +3 -2
- package/dist/sk/rc.d.ts +4 -5
- package/dist/sk/rc.js +6 -2
- package/dist/sk/rc.js.map +1 -1
- package/dist/th/mod.d.ts +3 -2
- package/dist/th/tin.d.ts +2 -3
- package/dist/th/tin.js +1 -11
- package/dist/th/tin.js.map +1 -1
- package/dist/tr/mod.d.ts +3 -2
- package/dist/tr/tckimlik.d.ts +2 -3
- package/dist/tr/tckimlik.js +1 -20
- package/dist/tr/tckimlik.js.map +1 -1
- package/dist/tr/vkn.d.ts +2 -3
- package/dist/tr/vkn.js +1 -20
- package/dist/tr/vkn.js.map +1 -1
- package/dist/tw/mod.d.ts +3 -2
- package/dist/tw/ubn.d.ts +2 -3
- package/dist/tw/ubn.js +2 -12
- package/dist/tw/ubn.js.map +1 -1
- package/dist/types.d.ts +56 -21
- package/dist/ua/edrpou.d.ts +2 -3
- package/dist/ua/edrpou.js +5 -12
- package/dist/ua/edrpou.js.map +1 -1
- package/dist/ua/mod.d.ts +3 -2
- package/dist/us/ein.d.ts +12 -2
- package/dist/us/ein.js +88 -97
- package/dist/us/ein.js.map +1 -1
- package/dist/us/itin.d.ts +13 -2
- package/dist/us/itin.js +4 -15
- package/dist/us/itin.js.map +1 -1
- package/dist/us/mod.d.ts +3 -2
- package/dist/us/rtn.d.ts +2 -3
- package/dist/us/rtn.js +11 -23
- package/dist/us/rtn.js.map +1 -1
- package/dist/us/ssn.d.ts +13 -2
- package/dist/us/ssn.js +1 -11
- package/dist/us/ssn.js.map +1 -1
- package/dist/uy/mod.d.ts +3 -2
- package/dist/uy/rut.d.ts +2 -3
- package/dist/uy/rut.js +2 -15
- package/dist/uy/rut.js.map +1 -1
- package/dist/ve/mod.d.ts +3 -2
- package/dist/ve/rif.d.ts +2 -3
- package/dist/ve/rif.js +13 -26
- package/dist/ve/rif.js.map +1 -1
- package/dist/vn/mod.d.ts +3 -2
- package/dist/vn/mst.d.ts +2 -3
- package/dist/vn/mst.js +1 -12
- package/dist/vn/mst.js.map +1 -1
- package/dist/za/idnr.d.ts +2 -3
- package/dist/za/idnr.js +4 -16
- package/dist/za/idnr.js.map +1 -1
- package/dist/za/mod.d.ts +3 -2
- package/package.json +34 -21
- package/src/_checksums/mod1110.ts +1 -1
- package/src/_checksums/mod112.ts +7 -6
- package/src/_util/generate.ts +38 -0
- package/src/ad/nrt.ts +19 -7
- package/src/ae/eid.ts +7 -3
- package/src/ai/tin.ts +7 -3
- package/src/al/nipt.ts +7 -3
- package/src/am/tin.ts +7 -3
- package/src/ar/cbu.ts +9 -5
- package/src/ar/cuit.ts +22 -10
- package/src/ar/dni.ts +7 -3
- package/src/at/businessid.ts +7 -3
- package/src/at/tin.ts +7 -3
- package/src/at/uid.ts +7 -3
- package/src/at/vnr.ts +62 -12
- package/src/au/abn.ts +7 -3
- package/src/au/acn.ts +7 -3
- package/src/au/tfn.ts +7 -3
- package/src/az/voen.ts +9 -3
- package/src/ba/jmbg.ts +9 -7
- package/src/bd/nid.ts +11 -7
- package/src/be/bis.ts +8 -4
- package/src/be/nn.ts +7 -3
- package/src/be/vat.ts +7 -3
- package/src/bg/egn.ts +19 -10
- package/src/bg/pnf.ts +7 -3
- package/src/bg/vat.ts +8 -3
- package/src/bh/cpr.ts +17 -4
- package/src/bic.ts +26 -20
- package/src/br/cnpj.ts +7 -3
- package/src/br/cpf.ts +7 -3
- package/src/by/unp.ts +19 -9
- package/src/bz/tin.ts +19 -4
- package/src/ca/bn.ts +7 -3
- package/src/ca/sin.ts +7 -3
- package/src/ch/ssn.ts +7 -3
- package/src/ch/uid.ts +7 -3
- package/src/ch/vat.ts +9 -5
- package/src/cl/rut.ts +11 -5
- package/src/cn/ric.ts +11 -7
- package/src/cn/uscc.ts +27 -11
- package/src/co/nit.ts +14 -6
- package/src/cr/cpf.ts +11 -6
- package/src/creditcard.ts +10 -6
- package/src/cu/ni.ts +28 -7
- package/src/cy/vat.ts +7 -3
- package/src/cz/dic.ts +9 -4
- package/src/cz/ico.ts +7 -3
- package/src/cz/rc.ts +61 -29
- package/src/de/handelsreg.ts +21 -6
- package/src/de/idnr.ts +10 -3
- package/src/de/stnr.ts +11 -3
- package/src/de/svnr.ts +14 -5
- package/src/de/vat.ts +7 -3
- package/src/dk/cpr.ts +23 -8
- package/src/dk/cvr.ts +7 -3
- package/src/dk/vat.ts +8 -3
- package/src/do/rnc.ts +9 -5
- package/src/ec/ruc.ts +9 -5
- package/src/ee/ik.ts +21 -10
- package/src/ee/registrikood.ts +12 -7
- package/src/ee/vat.ts +7 -3
- package/src/eg/tn.ts +7 -3
- package/src/es/cif.ts +10 -7
- package/src/es/dni.ts +7 -3
- package/src/es/nie.ts +18 -9
- package/src/es/nss.ts +7 -3
- package/src/es/vat.ts +13 -5
- package/src/eu/vat.ts +55 -6
- package/src/fi/hetu.ts +26 -8
- package/src/fi/vat.ts +8 -3
- package/src/fi/ytunnus.ts +7 -3
- package/src/fr/nif.ts +7 -3
- package/src/fr/nir.ts +9 -7
- package/src/fr/siren.ts +7 -3
- package/src/fr/siret.ts +7 -3
- package/src/fr/tva.ts +7 -3
- package/src/gb/nino.ts +18 -13
- package/src/gb/sedol.ts +21 -15
- package/src/gb/utr.ts +7 -3
- package/src/gb/vat.ts +7 -3
- package/src/ge/pin.ts +7 -3
- package/src/gh/tin.ts +11 -6
- package/src/gr/amka.ts +7 -3
- package/src/gr/vat.ts +7 -3
- package/src/gt/nit.ts +13 -6
- package/src/hk/hkid.ts +9 -4
- package/src/hr/vat.ts +7 -3
- package/src/hu/vat.ts +8 -3
- package/src/iban.ts +7 -3
- package/src/id/npwp.ts +7 -3
- package/src/ie/pps.ts +7 -3
- package/src/ie/vat.ts +7 -3
- package/src/il/idnr.ts +7 -3
- package/src/in/aadhaar.ts +7 -3
- package/src/in/gstin.ts +10 -4
- package/src/in/pan.ts +15 -6
- package/src/index.ts +6 -0
- package/src/iq/nid.ts +7 -3
- package/src/ir/nid.ts +7 -3
- package/src/is/kennitala.ts +7 -3
- package/src/is/vsk.ts +7 -3
- package/src/isin.ts +17 -7
- package/src/it/codicefiscale.ts +49 -7
- package/src/it/iva.ts +7 -3
- package/src/jp/cn.ts +7 -3
- package/src/jp/mynumber.ts +7 -3
- package/src/kr/brn.ts +7 -3
- package/src/kr/rrn.ts +27 -8
- package/src/kw/civil.ts +31 -14
- package/src/kz/iin.ts +9 -8
- package/src/lei.ts +7 -3
- package/src/li/peid.ts +7 -3
- package/src/lk/nic.ts +31 -8
- package/src/lt/asmens.ts +8 -4
- package/src/lt/vat.ts +8 -3
- package/src/lu/vat.ts +8 -3
- package/src/luhn.ts +10 -3
- package/src/lv/vat.ts +53 -23
- package/src/ma/ice.ts +7 -3
- package/src/mc/tva.ts +9 -5
- package/src/md/idno.ts +7 -3
- package/src/me/pib.ts +7 -3
- package/src/mk/edb.ts +7 -3
- package/src/mt/vat.ts +8 -3
- package/src/mu/brn.ts +7 -3
- package/src/mx/clabe.ts +7 -3
- package/src/mx/curp.ts +47 -10
- package/src/mx/rfc.ts +42 -7
- package/src/my/nric.ts +33 -8
- package/src/ng/nin.ts +7 -3
- package/src/ni/ruc.ts +7 -3
- package/src/nl/bsn.ts +7 -3
- package/src/nl/kvk.ts +7 -3
- package/src/nl/vat.ts +18 -69
- package/src/no/fodselsnummer.ts +12 -7
- package/src/no/mva.ts +9 -5
- package/src/no/orgnr.ts +7 -3
- package/src/nz/ird.ts +12 -8
- package/src/pa/ruc.ts +39 -11
- package/src/patterns.ts +184 -46
- package/src/pe/ruc.ts +13 -10
- package/src/ph/philid.ts +7 -3
- package/src/pk/cnic.ts +9 -3
- package/src/pl/nip.ts +7 -3
- package/src/pl/pesel.ts +9 -7
- package/src/pl/regon.ts +7 -3
- package/src/pt/cc.ts +13 -7
- package/src/pt/vat.ts +8 -3
- package/src/ro/cnp.ts +16 -8
- package/src/ro/vat.ts +8 -3
- package/src/rs/pib.ts +7 -3
- package/src/ru/inn.ts +9 -5
- package/src/se/orgnr.ts +7 -3
- package/src/se/personnummer.ts +35 -32
- package/src/se/vat.ts +8 -3
- package/src/sg/uen.ts +44 -23
- package/src/si/emso.ts +37 -11
- package/src/si/vat.ts +8 -3
- package/src/sk/dic.ts +8 -4
- package/src/sk/ico.ts +3 -2
- package/src/sk/rc.ts +17 -4
- package/src/th/tin.ts +7 -3
- package/src/tr/tckimlik.ts +7 -3
- package/src/tr/vkn.ts +7 -3
- package/src/tw/ubn.ts +9 -5
- package/src/types.ts +69 -7
- package/src/ua/edrpou.ts +10 -5
- package/src/us/ein.ts +95 -91
- package/src/us/itin.ts +14 -11
- package/src/us/rtn.ts +32 -19
- package/src/us/ssn.ts +7 -3
- package/src/uy/rut.ts +9 -5
- package/src/ve/rif.ts +19 -12
- package/src/vn/mst.ts +7 -3
- package/src/za/idnr.ts +9 -7
package/dist/nz/ird.js
CHANGED
|
@@ -3,16 +3,6 @@ import { randomDigits } from "../_util/generate.js";
|
|
|
3
3
|
import { err } from "../_util/result.js";
|
|
4
4
|
import { isdigits } from "../_util/strings.js";
|
|
5
5
|
//#region src/nz/ird.ts
|
|
6
|
-
/**
|
|
7
|
-
* IRD number (New Zealand Inland Revenue Department
|
|
8
|
-
* number, Te Tari Take).
|
|
9
|
-
*
|
|
10
|
-
* 8 or 9 digit number with a weighted checksum.
|
|
11
|
-
* Uses primary weights, falling back to secondary
|
|
12
|
-
* weights if the primary check yields 10.
|
|
13
|
-
*
|
|
14
|
-
* @see https://www.ird.govt.nz/
|
|
15
|
-
*/
|
|
16
6
|
const PRIMARY_WEIGHTS = [
|
|
17
7
|
3,
|
|
18
8
|
2,
|
|
@@ -41,11 +31,11 @@ const SECONDARY_WEIGHTS = [
|
|
|
41
31
|
const calcCheckDigit = (payload) => {
|
|
42
32
|
const padded = payload.padStart(8, "0");
|
|
43
33
|
let sum = 0;
|
|
44
|
-
for (
|
|
34
|
+
for (const [i, weight] of PRIMARY_WEIGHTS.entries()) sum += weight * Number(padded[i]);
|
|
45
35
|
let remainder = (-sum % 11 + 11) % 11;
|
|
46
36
|
if (remainder !== 10) return remainder;
|
|
47
37
|
sum = 0;
|
|
48
|
-
for (
|
|
38
|
+
for (const [i, weight] of SECONDARY_WEIGHTS.entries()) sum += weight * Number(padded[i]);
|
|
49
39
|
remainder = (-sum % 11 + 11) % 11;
|
|
50
40
|
if (remainder === 10) return null;
|
|
51
41
|
return remainder;
|
|
@@ -63,7 +53,7 @@ const validate = (value) => {
|
|
|
63
53
|
if (num < 1e7 || num >= 15e7) return err("INVALID_COMPONENT", "IRD number out of valid range");
|
|
64
54
|
const expected = calcCheckDigit(v.slice(0, -1));
|
|
65
55
|
if (expected === null) return err("INVALID_COMPONENT", "IRD number cannot have a valid check digit");
|
|
66
|
-
if (expected !== Number(v
|
|
56
|
+
if (expected !== Number(v.at(-1))) return err("INVALID_CHECKSUM", "IRD check digit does not match");
|
|
67
57
|
return {
|
|
68
58
|
valid: true,
|
|
69
59
|
compact: v
|
|
@@ -88,6 +78,7 @@ const ird = {
|
|
|
88
78
|
abbreviation: "IRD",
|
|
89
79
|
aliases: ["IRD number", "tax number NZ"],
|
|
90
80
|
candidatePattern: "\\d{8,9}",
|
|
81
|
+
scope: "country",
|
|
91
82
|
country: "NZ",
|
|
92
83
|
entityType: "any",
|
|
93
84
|
compact,
|
package/dist/nz/ird.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ird.js","names":[],"sources":["../../src/nz/ird.ts"],"sourcesContent":["/**\n * IRD number (New Zealand Inland Revenue Department\n * number, Te Tari Take).\n *\n * 8 or 9 digit number with a weighted checksum.\n * Uses primary weights, falling back to secondary\n * weights if the primary check yields 10.\n *\n * @see https://www.ird.govt.nz/\n */\n\nimport {
|
|
1
|
+
{"version":3,"file":"ird.js","names":[],"sources":["../../src/nz/ird.ts"],"sourcesContent":["/**\n * IRD number (New Zealand Inland Revenue Department\n * number, Te Tari Take).\n *\n * 8 or 9 digit number with a weighted checksum.\n * Uses primary weights, falling back to secondary\n * weights if the primary check yields 10.\n *\n * @see https://www.ird.govt.nz/\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst PRIMARY_WEIGHTS = [3, 2, 7, 6, 5, 4, 3, 2] as const;\n\nconst SECONDARY_WEIGHTS = [7, 4, 3, 2, 5, 2, 7, 6] as const;\n\n/**\n * Calculate the check digit for an IRD number.\n * The input should be the number without the check\n * digit, zero-padded to 8 digits.\n */\nconst calcCheckDigit = (payload: string): number | null => {\n const padded = payload.padStart(8, \"0\");\n let sum = 0;\n for (const [i, weight] of PRIMARY_WEIGHTS.entries()) {\n sum += weight * Number(padded[i]);\n }\n let remainder = ((-sum % 11) + 11) % 11;\n if (remainder !== 10) return remainder;\n\n sum = 0;\n for (const [i, weight] of SECONDARY_WEIGHTS.entries()) {\n sum += weight * Number(padded[i]);\n }\n remainder = ((-sum % 11) + 11) % 11;\n if (remainder === 10) return null;\n return remainder;\n};\n\nconst compact = (value: string): string => {\n let v = clean(value, \" -\").toUpperCase();\n if (v.startsWith(\"NZ\")) {\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 && v.length !== 9) {\n return err(\n \"INVALID_LENGTH\",\n \"IRD number must be 8 or 9 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"IRD number must contain only digits\",\n );\n }\n const num = Number(v);\n if (num < 10_000_000 || num >= 150_000_000) {\n return err(\n \"INVALID_COMPONENT\",\n \"IRD number out of valid range\",\n );\n }\n const payload = v.slice(0, -1);\n const expected = calcCheckDigit(payload);\n if (expected === null) {\n return err(\n \"INVALID_COMPONENT\",\n \"IRD number cannot have a valid check digit\",\n );\n }\n if (expected !== Number(v.at(-1))) {\n return err(\n \"INVALID_CHECKSUM\",\n \"IRD check digit does not match\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n const last6 = v.slice(-6);\n const prefix = v.slice(0, -6);\n return `${prefix}-${last6.slice(0, 3)}-${last6.slice(3)}`;\n};\n\n/** Generate a random valid NZ IRD number. */\nconst generate = (): string => {\n for (;;) {\n const c = randomDigits(9);\n if (validate(c).valid) return c;\n }\n};\n\n/** New Zealand IRD Number. */\nconst ird: CountryValidator<\"NZ\"> = {\n name: \"IRD Number\",\n localName: \"IRD Number\",\n abbreviation: \"IRD\",\n aliases: [\"IRD number\", \"tax number NZ\"] as const,\n candidatePattern: \"\\\\d{8,9}\",\n scope: \"country\",\n country: \"NZ\",\n entityType: \"any\",\n compact,\n format,\n validate,\n description:\n \"New Zealand Inland Revenue Department number\",\n sourceUrl: \"https://www.ird.govt.nz/\",\n lengths: [8, 9] as const,\n examples: [\"49091850\", \"136410132\"] as const,\n generate,\n};\n\nexport default ird;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;AAqBA,MAAM,kBAAkB;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AAE/C,MAAM,oBAAoB;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;;;;;;AAOjD,MAAM,kBAAkB,YAAmC;CACzD,MAAM,SAAS,QAAQ,SAAS,GAAG,GAAG;CACtC,IAAI,MAAM;CACV,KAAK,MAAM,CAAC,GAAG,WAAW,gBAAgB,QAAQ,GAChD,OAAO,SAAS,OAAO,OAAO,EAAE;CAElC,IAAI,aAAc,CAAC,MAAM,KAAM,MAAM;CACrC,IAAI,cAAc,IAAI,OAAO;CAE7B,MAAM;CACN,KAAK,MAAM,CAAC,GAAG,WAAW,kBAAkB,QAAQ,GAClD,OAAO,SAAS,OAAO,OAAO,EAAE;CAElC,aAAc,CAAC,MAAM,KAAM,MAAM;CACjC,IAAI,cAAc,IAAI,OAAO;CAC7B,OAAO;AACT;AAEA,MAAM,WAAW,UAA0B;CACzC,IAAI,IAAI,MAAM,OAAO,IAAI,EAAE,YAAY;CACvC,IAAI,EAAE,WAAW,IAAI,GACnB,IAAI,EAAE,MAAM,CAAC;CAEf,OAAO;AACT;AAEA,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,KAAK,EAAE,WAAW,GACjC,OAAO,IACL,kBACA,kCACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,qCACF;CAEF,MAAM,MAAM,OAAO,CAAC;CACpB,IAAI,MAAM,OAAc,OAAO,MAC7B,OAAO,IACL,qBACA,+BACF;CAGF,MAAM,WAAW,eADD,EAAE,MAAM,GAAG,EACW,CAAC;CACvC,IAAI,aAAa,MACf,OAAO,IACL,qBACA,4CACF;CAEF,IAAI,aAAa,OAAO,EAAE,GAAG,EAAE,CAAC,GAC9B,OAAO,IACL,oBACA,gCACF;CAEF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,KAAK;CACvB,MAAM,QAAQ,EAAE,MAAM,EAAE;CAExB,OAAO,GADQ,EAAE,MAAM,GAAG,EACX,EAAE,GAAG,MAAM,MAAM,GAAG,CAAC,EAAE,GAAG,MAAM,MAAM,CAAC;AACxD;;AAGA,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,eAAe;CACvC,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ;CACA;CACA;CACA,aACE;CACF,WAAW;CACX,SAAS,CAAC,GAAG,CAAC;CACd,UAAU,CAAC,YAAY,WAAW;CAClC;AACF"}
|
package/dist/nz/mod.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { __exportAll } from "../_virtual/_rolldown/runtime.js";
|
|
2
1
|
import ird from "./ird.js";
|
|
3
2
|
|
|
4
3
|
//#region src/nz/mod.d.ts
|
|
5
|
-
|
|
4
|
+
declare namespace mod_d_exports {
|
|
5
|
+
export { ird };
|
|
6
|
+
}
|
|
6
7
|
//#endregion
|
|
7
8
|
export { ird, mod_d_exports };
|
|
8
9
|
//# sourceMappingURL=mod.d.ts.map
|
package/dist/pa/mod.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { __exportAll } from "../_virtual/_rolldown/runtime.js";
|
|
2
1
|
import ruc from "./ruc.js";
|
|
3
2
|
|
|
4
3
|
//#region src/pa/mod.d.ts
|
|
5
|
-
|
|
4
|
+
declare namespace mod_d_exports {
|
|
5
|
+
export { ruc };
|
|
6
|
+
}
|
|
6
7
|
//#endregion
|
|
7
8
|
export { mod_d_exports, ruc };
|
|
8
9
|
//# sourceMappingURL=mod.d.ts.map
|
package/dist/pa/ruc.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CountryValidator, ValidateResult } from "../types.js";
|
|
2
2
|
|
|
3
3
|
//#region src/pa/ruc.d.ts
|
|
4
|
-
|
|
5
4
|
/**
|
|
6
5
|
* Compact: normalize Unicode, collapse whitespace,
|
|
7
6
|
* strip colons around DV, and uppercase. Keeps
|
|
@@ -17,7 +16,7 @@ declare const format: (value: string) => string;
|
|
|
17
16
|
/** Generate a random valid Panama RUC (natural person). */
|
|
18
17
|
declare const generate: () => string;
|
|
19
18
|
/** Panama tax identification number. */
|
|
20
|
-
declare const ruc:
|
|
19
|
+
declare const ruc: CountryValidator<"PA">;
|
|
21
20
|
//#endregion
|
|
22
21
|
export { compact, ruc as default, format, generate, validate };
|
|
23
22
|
//# sourceMappingURL=ruc.d.ts.map
|
package/dist/pa/ruc.js
CHANGED
|
@@ -3,24 +3,6 @@ import { randomInt } from "../_util/generate.js";
|
|
|
3
3
|
import { err } from "../_util/result.js";
|
|
4
4
|
//#region src/pa/ruc.ts
|
|
5
5
|
/**
|
|
6
|
-
* RUC (Registro Único de Contribuyente, Panama
|
|
7
|
-
* tax number).
|
|
8
|
-
*
|
|
9
|
-
* The RUC identifies taxpayers in Panama. It comes
|
|
10
|
-
* in several formats depending on entity type
|
|
11
|
-
* (natural person, legal entity, foreigner, etc.)
|
|
12
|
-
* and is always accompanied by a two-digit check
|
|
13
|
-
* code called the "dígito verificador" (DV).
|
|
14
|
-
*
|
|
15
|
-
* The DV is computed by encoding the hyphen-separated
|
|
16
|
-
* RUC into a 20-position numeric buffer, then applying
|
|
17
|
-
* a double weighted-sum mod 11 algorithm. The encoding
|
|
18
|
-
* and legacy-format handling follow the official ANIP/DGI
|
|
19
|
-
* specification.
|
|
20
|
-
*
|
|
21
|
-
* @see https://dgi.mef.gob.pa/
|
|
22
|
-
*/
|
|
23
|
-
/**
|
|
24
6
|
* Legacy cross-reference table: maps two-digit codes
|
|
25
7
|
* at positions 5–6 of old-format juridical RUCs.
|
|
26
8
|
*/
|
|
@@ -96,7 +78,8 @@ const digitDV = (buf, isOldFormat) => {
|
|
|
96
78
|
*/
|
|
97
79
|
const computeDV = (segments, raw) => {
|
|
98
80
|
const len = segments.length;
|
|
99
|
-
if (len < 3 || len > 4
|
|
81
|
+
if (len < 3 || len > 4) return null;
|
|
82
|
+
if (len === 4 !== (segments[1] === "NT")) return null;
|
|
100
83
|
let buf;
|
|
101
84
|
let isOld = false;
|
|
102
85
|
const s0 = segments[0];
|
|
@@ -175,6 +158,7 @@ const generate = () => {
|
|
|
175
158
|
String(randomInt(1, 99999))
|
|
176
159
|
];
|
|
177
160
|
const dv = computeDV(segments, segments.join("-"));
|
|
161
|
+
if (dv === null) throw new Error("Failed to compute Panama RUC DV");
|
|
178
162
|
return `${segments.join("-")} DV${dv}`;
|
|
179
163
|
};
|
|
180
164
|
/** Panama tax identification number. */
|
|
@@ -184,6 +168,7 @@ const ruc = {
|
|
|
184
168
|
abbreviation: "RUC",
|
|
185
169
|
aliases: ["RUC"],
|
|
186
170
|
candidatePattern: "\\d{1,2}-?\\d{1,4}-?\\d{1,6}",
|
|
171
|
+
scope: "country",
|
|
187
172
|
country: "PA",
|
|
188
173
|
entityType: "any",
|
|
189
174
|
description: "Tax identifier issued by Panama's DGI",
|
package/dist/pa/ruc.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ruc.js","names":[],"sources":["../../src/pa/ruc.ts"],"sourcesContent":["/**\n * RUC (Registro Único de Contribuyente, Panama\n * tax number).\n *\n * The RUC identifies taxpayers in Panama. It comes\n * in several formats depending on entity type\n * (natural person, legal entity, foreigner, etc.)\n * and is always accompanied by a two-digit check\n * code called the \"dígito verificador\" (DV).\n *\n * The DV is computed by encoding the hyphen-separated\n * RUC into a 20-position numeric buffer, then applying\n * a double weighted-sum mod 11 algorithm. The encoding\n * and legacy-format handling follow the official ANIP/DGI\n * specification.\n *\n * @see https://dgi.mef.gob.pa/\n */\n\nimport { clean } from \"#util/clean\";\nimport { randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\n\nimport type { ValidateResult, Validator } from \"../types\";\n\n/**\n * Legacy cross-reference table: maps two-digit codes\n * at positions 5–6 of old-format juridical RUCs.\n */\nconst LEGACY_MAP: Record<string, string> = {\n \"00\": \"00\",\n \"10\": \"01\",\n \"11\": \"02\",\n \"12\": \"03\",\n \"13\": \"04\",\n \"14\": \"05\",\n \"15\": \"06\",\n \"16\": \"07\",\n \"17\": \"08\",\n \"18\": \"09\",\n \"19\": \"01\",\n \"20\": \"02\",\n \"21\": \"03\",\n \"22\": \"04\",\n \"23\": \"07\",\n \"24\": \"08\",\n \"25\": \"09\",\n \"26\": \"02\",\n \"27\": \"03\",\n \"28\": \"04\",\n \"29\": \"05\",\n \"30\": \"06\",\n \"31\": \"07\",\n \"32\": \"08\",\n \"33\": \"09\",\n \"34\": \"01\",\n \"35\": \"02\",\n \"36\": \"03\",\n \"37\": \"04\",\n \"38\": \"05\",\n \"39\": \"06\",\n \"40\": \"07\",\n \"41\": \"08\",\n \"42\": \"09\",\n \"43\": \"01\",\n \"44\": \"02\",\n \"45\": \"03\",\n \"46\": \"04\",\n \"47\": \"05\",\n \"48\": \"06\",\n \"49\": \"07\",\n};\n\n/** Prepend n leading zeros. */\nconst z = (n: number): string => \"0\".repeat(Math.max(0, n));\n\n/**\n * Compute a single DV digit via weighted sum mod 11.\n * Weights start at 2 and increment, applied\n * right-to-left. For old-format juridical RUCs,\n * weight 12 is skipped (jumps from 11 to 13).\n */\nconst digitDV = (\n buf: string,\n isOldFormat: boolean,\n): number => {\n let weight = 2;\n let sum = 0;\n for (let i = buf.length - 1; i >= 0; i--) {\n if (isOldFormat && weight === 12) {\n weight += 1; // skip 12, continue from 13\n }\n sum += weight * (buf.charCodeAt(i) - 48);\n weight += 1;\n }\n const r = sum % 11;\n return r > 1 ? 11 - r : 0;\n};\n\n/**\n * Encode the RUC segments into a numeric buffer\n * according to entity type, then compute the two\n * DV digits.\n *\n * Returns the two-digit DV string, or null if the\n * format is unrecognized.\n */\nconst computeDV = (\n segments: readonly string[],\n raw: string,\n): string | null => {\n const len = segments.length;\n\n if (\n len < 3 ||\n len > 4 ||\n (len === 4 && segments[1] !== \"NT\")\n ) {\n return null;\n }\n\n let buf: string;\n let isOld = false;\n\n const s0 = segments[0]!;\n const s1 = segments[1]!;\n const s2 = segments[2]!;\n\n if (raw[0] === \"E\") {\n // Foreign person (E-xxx-xxx)\n buf =\n z(4 - s1.length) +\n \"0000005\" +\n \"00\" +\n \"50\" +\n z(3 - s1.length) +\n s1 +\n z(5 - s2.length) +\n s2;\n } else if (s1 === \"NT\") {\n // NT designation (xxNT-xxx-xxx)\n const s3 = segments[3]!;\n const prefix = s0.slice(0, -2);\n buf =\n z(4 - s1.length) +\n \"0000005\" +\n z(4 - prefix.length) +\n prefix +\n \"43\" +\n z(3 - s2.length) +\n s2 +\n z(5 - s3.length) +\n s3;\n } else if (s0.endsWith(\"AV\")) {\n // AV suffix\n const prefix = s0.slice(0, -2);\n buf =\n z(4 - s1.length) +\n \"0000005\" +\n z(4 - prefix.length) +\n prefix +\n \"15\" +\n z(3 - s1.length) +\n s1 +\n z(5 - s2.length) +\n s2;\n } else if (s0.endsWith(\"PI\")) {\n // PI suffix\n const prefix = s0.slice(0, -2);\n buf =\n z(4 - s1.length) +\n \"0000005\" +\n z(4 - prefix.length) +\n prefix +\n \"79\" +\n z(3 - s1.length) +\n s1 +\n z(5 - s2.length) +\n s2;\n } else if (s0 === \"PE\") {\n // PE prefix (foreign-born)\n buf =\n z(4 - s1.length) +\n \"0000005\" +\n \"00\" +\n \"75\" +\n z(3 - s1.length) +\n s1 +\n z(5 - s2.length) +\n s2;\n } else if (raw[0] === \"N\") {\n // N prefix (naturalized citizen)\n buf =\n z(4 - s1.length) +\n \"0000005\" +\n \"00\" +\n \"40\" +\n z(3 - s1.length) +\n s1 +\n z(5 - s2.length) +\n s2;\n } else if (s0.length >= 1 && s0.length <= 2) {\n // Natural person (province 1–2 digits)\n buf =\n z(4 - s1.length) +\n \"0000005\" +\n z(2 - s0.length) +\n s0 +\n \"00\" +\n z(3 - s1.length) +\n s1 +\n z(5 - s2.length) +\n s2;\n } else {\n // Juridical (company)\n buf =\n z(10 - s0.length) +\n s0 +\n z(4 - s1.length) +\n s1 +\n z(6 - s2.length) +\n s2;\n isOld =\n buf[3] === \"0\" && buf[4] === \"0\" && buf[5]! < \"5\";\n }\n\n // Apply legacy cross-reference for old format\n if (isOld) {\n const key = buf.slice(5, 7);\n const mapped = LEGACY_MAP[key] ?? key;\n buf = buf.slice(0, 5) + mapped + buf.slice(7);\n }\n\n const dv1 = digitDV(buf, isOld);\n const dv2 = digitDV(\n buf + String.fromCharCode(48 + dv1),\n isOld,\n );\n\n return `${dv1}${dv2}`;\n};\n\n/**\n * Compact: normalize Unicode, collapse whitespace,\n * strip colons around DV, and uppercase. Keeps\n * hyphens (structural separators) and a single\n * space before \"DV\".\n */\nconst compact = (value: string): string => {\n let v = clean(value, \"\").trim().toUpperCase();\n // Normalize DV portion: \" DV: 49\" -> \" DV49\"\n v = v.replace(/\\s*DV[:\\s]*(\\d{2})$/, \" DV$1\");\n // Collapse any remaining internal whitespace\n v = v.replace(/\\s+/g, \" \");\n return v;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n // Extract the DV portion: \"...DV49\", \"...DV:49\",\n // or \"... DV 49\"\n const dvMatch = v.match(/^(.+?)-?\\s*DV[:\\s]*(\\d{2})$/);\n\n if (!dvMatch) {\n return err(\n \"INVALID_FORMAT\",\n \"Panama RUC must include DV \" +\n \"(dígito verificador)\",\n );\n }\n\n const rucPart = dvMatch[1]!;\n const dvPart = dvMatch[2]!;\n\n // The RUC part should be hyphen-separated segments\n const segments = rucPart.replace(/-+$/, \"\").split(\"-\");\n\n if (segments.length < 3 || segments.length > 4) {\n return err(\n \"INVALID_FORMAT\",\n \"Panama RUC must have 3–4 \" +\n \"hyphen-separated segments\",\n );\n }\n\n if (segments.some((s) => s.length === 0)) {\n return err(\n \"INVALID_FORMAT\",\n \"Panama RUC segments must not be empty\",\n );\n }\n\n const computed = computeDV(segments, rucPart);\n if (computed === null) {\n return err(\n \"INVALID_FORMAT\",\n \"Unrecognized Panama RUC format\",\n );\n }\n\n if (computed !== dvPart) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Panama RUC dígito verificador \" + \"does not match\",\n );\n }\n\n const compactForm = segments.join(\"-\") + \" DV\" + dvPart;\n return { valid: true, compact: compactForm };\n};\n\n/**\n * Format: display as segments with \" DV XX\".\n */\nconst format = (value: string): string => {\n const v = compact(value);\n const dvMatch = v.match(/^(.+?)-?\\s*DV[:\\s]*(\\d{2})$/);\n if (!dvMatch) return v;\n\n const rucPart = dvMatch[1]!.replace(/-+$/, \"\");\n const dvPart = dvMatch[2]!;\n const segments = rucPart.split(\"-\");\n return `${segments.join(\"-\")} DV ${dvPart}`;\n};\n\n/** Generate a random valid Panama RUC (natural person). */\nconst generate = (): string => {\n const province = String(randomInt(1, 13));\n const volume = String(randomInt(1, 9999));\n const folio = String(randomInt(1, 99999));\n const segments = [province, volume, folio];\n const dv = computeDV(segments, segments.join(\"-\"))!;\n return `${segments.join(\"-\")} DV${dv}`;\n};\n\n/** Panama tax identification number. */\nconst ruc: Validator = {\n name: \"Tax Identification Number\",\n localName: \"Registro Único de Contribuyente\",\n abbreviation: \"RUC\",\n aliases: [\"RUC\"] as const,\n candidatePattern: \"\\\\d{1,2}-?\\\\d{1,4}-?\\\\d{1,6}\",\n country: \"PA\",\n entityType: \"any\",\n description: \"Tax identifier issued by Panama's DGI\",\n sourceUrl: \"https://dgi.mef.gob.pa/\",\n examples: [\n \"1-184-921 DV49\",\n \"2588017-1-831938 DV20\",\n ] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default ruc;\nexport { compact, format, validate, generate };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ruc.js","names":[],"sources":["../../src/pa/ruc.ts"],"sourcesContent":["/**\n * RUC (Registro Único de Contribuyente, Panama\n * tax number).\n *\n * The RUC identifies taxpayers in Panama. It comes\n * in several formats depending on entity type\n * (natural person, legal entity, foreigner, etc.)\n * and is always accompanied by a two-digit check\n * code called the \"dígito verificador\" (DV).\n *\n * The DV is computed by encoding the hyphen-separated\n * RUC into a 20-position numeric buffer, then applying\n * a double weighted-sum mod 11 algorithm. The encoding\n * and legacy-format handling follow the official ANIP/DGI\n * specification.\n *\n * @see https://dgi.mef.gob.pa/\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\n\n/**\n * Legacy cross-reference table: maps two-digit codes\n * at positions 5–6 of old-format juridical RUCs.\n */\nconst LEGACY_MAP: Record<string, string> = {\n \"00\": \"00\",\n \"10\": \"01\",\n \"11\": \"02\",\n \"12\": \"03\",\n \"13\": \"04\",\n \"14\": \"05\",\n \"15\": \"06\",\n \"16\": \"07\",\n \"17\": \"08\",\n \"18\": \"09\",\n \"19\": \"01\",\n \"20\": \"02\",\n \"21\": \"03\",\n \"22\": \"04\",\n \"23\": \"07\",\n \"24\": \"08\",\n \"25\": \"09\",\n \"26\": \"02\",\n \"27\": \"03\",\n \"28\": \"04\",\n \"29\": \"05\",\n \"30\": \"06\",\n \"31\": \"07\",\n \"32\": \"08\",\n \"33\": \"09\",\n \"34\": \"01\",\n \"35\": \"02\",\n \"36\": \"03\",\n \"37\": \"04\",\n \"38\": \"05\",\n \"39\": \"06\",\n \"40\": \"07\",\n \"41\": \"08\",\n \"42\": \"09\",\n \"43\": \"01\",\n \"44\": \"02\",\n \"45\": \"03\",\n \"46\": \"04\",\n \"47\": \"05\",\n \"48\": \"06\",\n \"49\": \"07\",\n};\n\n/** Prepend n leading zeros. */\nconst z = (n: number): string => \"0\".repeat(Math.max(0, n));\n\n/**\n * Compute a single DV digit via weighted sum mod 11.\n * Weights start at 2 and increment, applied\n * right-to-left. For old-format juridical RUCs,\n * weight 12 is skipped (jumps from 11 to 13).\n */\nconst digitDV = (\n buf: string,\n isOldFormat: boolean,\n): number => {\n let weight = 2;\n let sum = 0;\n for (let i = buf.length - 1; i >= 0; i--) {\n if (isOldFormat && weight === 12) {\n weight += 1; // skip 12, continue from 13\n }\n sum += weight * (buf.charCodeAt(i) - 48);\n weight += 1;\n }\n const r = sum % 11;\n return r > 1 ? 11 - r : 0;\n};\n\n/**\n * Encode the RUC segments into a numeric buffer\n * according to entity type, then compute the two\n * DV digits.\n *\n * Returns the two-digit DV string, or null if the\n * format is unrecognized.\n */\nconst computeDV = (\n segments: readonly string[],\n raw: string,\n): string | null => {\n const len = segments.length;\n\n if (len < 3 || len > 4) {\n return null;\n }\n // The NT designation requires exactly 4 segments\n // (xxNT-NT-xxx-xxx); any other 4-segment shape is\n // unrecognized, and a 3-segment \"NT\" in position 1\n // is malformed.\n if ((len === 4) !== (segments[1] === \"NT\")) {\n return null;\n }\n\n let buf: string;\n let isOld = false;\n\n // SAFETY: length check above ensures 3..4 segments.\n // eslint-disable-next-line no-non-null-assertion\n const s0 = segments[0]!;\n // eslint-disable-next-line no-non-null-assertion\n const s1 = segments[1]!;\n // eslint-disable-next-line no-non-null-assertion\n const s2 = segments[2]!;\n\n if (raw[0] === \"E\") {\n // Foreign person (E-xxx-xxx)\n buf =\n z(4 - s1.length) +\n \"0000005\" +\n \"00\" +\n \"50\" +\n z(3 - s1.length) +\n s1 +\n z(5 - s2.length) +\n s2;\n } else if (s1 === \"NT\") {\n // NT designation (xxNT-NT-xxx-xxx)\n // SAFETY: NT branch implies len === 4 (checked above).\n // eslint-disable-next-line no-non-null-assertion\n const s3 = segments[3]!;\n const prefix = s0.slice(0, -2);\n buf =\n z(4 - s1.length) +\n \"0000005\" +\n z(4 - prefix.length) +\n prefix +\n \"43\" +\n z(3 - s2.length) +\n s2 +\n z(5 - s3.length) +\n s3;\n } else if (s0.endsWith(\"AV\")) {\n // AV suffix\n const prefix = s0.slice(0, -2);\n buf =\n z(4 - s1.length) +\n \"0000005\" +\n z(4 - prefix.length) +\n prefix +\n \"15\" +\n z(3 - s1.length) +\n s1 +\n z(5 - s2.length) +\n s2;\n } else if (s0.endsWith(\"PI\")) {\n // PI suffix\n const prefix = s0.slice(0, -2);\n buf =\n z(4 - s1.length) +\n \"0000005\" +\n z(4 - prefix.length) +\n prefix +\n \"79\" +\n z(3 - s1.length) +\n s1 +\n z(5 - s2.length) +\n s2;\n } else if (s0 === \"PE\") {\n // PE prefix (foreign-born)\n buf =\n z(4 - s1.length) +\n \"0000005\" +\n \"00\" +\n \"75\" +\n z(3 - s1.length) +\n s1 +\n z(5 - s2.length) +\n s2;\n } else if (raw[0] === \"N\") {\n // N prefix (naturalized citizen)\n buf =\n z(4 - s1.length) +\n \"0000005\" +\n \"00\" +\n \"40\" +\n z(3 - s1.length) +\n s1 +\n z(5 - s2.length) +\n s2;\n } else if (s0.length >= 1 && s0.length <= 2) {\n // Natural person (province 1–2 digits)\n buf =\n z(4 - s1.length) +\n \"0000005\" +\n z(2 - s0.length) +\n s0 +\n \"00\" +\n z(3 - s1.length) +\n s1 +\n z(5 - s2.length) +\n s2;\n } else {\n // Juridical (company)\n buf =\n z(10 - s0.length) +\n s0 +\n z(4 - s1.length) +\n s1 +\n z(6 - s2.length) +\n s2;\n // SAFETY: juridical branch zero-pads s0 to at least\n // 10 chars (z(10 - s0.length)), so buf[3..6] are\n // always defined.\n isOld =\n buf[3] === \"0\" &&\n buf[4] === \"0\" &&\n // eslint-disable-next-line no-non-null-assertion\n buf[5]! < \"5\";\n }\n\n // Apply legacy cross-reference for old format\n if (isOld) {\n const key = buf.slice(5, 7);\n const mapped = LEGACY_MAP[key] ?? key;\n buf = buf.slice(0, 5) + mapped + buf.slice(7);\n }\n\n const dv1 = digitDV(buf, isOld);\n const dv2 = digitDV(\n buf + String.fromCharCode(48 + dv1),\n isOld,\n );\n\n return `${dv1}${dv2}`;\n};\n\n/**\n * Compact: normalize Unicode, collapse whitespace,\n * strip colons around DV, and uppercase. Keeps\n * hyphens (structural separators) and a single\n * space before \"DV\".\n */\nconst compact = (value: string): string => {\n let v = clean(value, \"\").trim().toUpperCase();\n // Normalize DV portion: \" DV: 49\" -> \" DV49\"\n v = v.replace(/\\s*DV[:\\s]*(\\d{2})$/, \" DV$1\");\n // Collapse any remaining internal whitespace\n v = v.replace(/\\s+/g, \" \");\n return v;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n // Extract the DV portion: \"...DV49\", \"...DV:49\",\n // or \"... DV 49\"\n const dvMatch = v.match(/^(.+?)-?\\s*DV[:\\s]*(\\d{2})$/);\n\n if (!dvMatch) {\n return err(\n \"INVALID_FORMAT\",\n \"Panama RUC must include DV \" +\n \"(dígito verificador)\",\n );\n }\n\n // SAFETY: both DV regex capture groups are required.\n // eslint-disable-next-line no-non-null-assertion\n const rucPart = dvMatch[1]!;\n // eslint-disable-next-line no-non-null-assertion\n const dvPart = dvMatch[2]!;\n\n // The RUC part should be hyphen-separated segments\n const segments = rucPart.replace(/-+$/, \"\").split(\"-\");\n\n if (segments.length < 3 || segments.length > 4) {\n return err(\n \"INVALID_FORMAT\",\n \"Panama RUC must have 3–4 \" +\n \"hyphen-separated segments\",\n );\n }\n\n if (segments.some((s) => s.length === 0)) {\n return err(\n \"INVALID_FORMAT\",\n \"Panama RUC segments must not be empty\",\n );\n }\n\n const computed = computeDV(segments, rucPart);\n if (computed === null) {\n return err(\n \"INVALID_FORMAT\",\n \"Unrecognized Panama RUC format\",\n );\n }\n\n if (computed !== dvPart) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Panama RUC dígito verificador \" + \"does not match\",\n );\n }\n\n const compactForm = segments.join(\"-\") + \" DV\" + dvPart;\n return { valid: true, compact: compactForm };\n};\n\n/**\n * Format: display as segments with \" DV XX\".\n */\nconst format = (value: string): string => {\n const v = compact(value);\n const dvMatch = v.match(/^(.+?)-?\\s*DV[:\\s]*(\\d{2})$/);\n if (!dvMatch) return v;\n\n // SAFETY: both DV regex capture groups are required.\n // eslint-disable-next-line no-non-null-assertion\n const rucPart = dvMatch[1]!.replace(/-+$/, \"\");\n // eslint-disable-next-line no-non-null-assertion\n const dvPart = dvMatch[2]!;\n const segments = rucPart.split(\"-\");\n return `${segments.join(\"-\")} DV ${dvPart}`;\n};\n\n/** Generate a random valid Panama RUC (natural person). */\nconst generate = (): string => {\n const province = String(randomInt(1, 13));\n const volume = String(randomInt(1, 9999));\n const folio = String(randomInt(1, 99999));\n const segments = [province, volume, folio];\n const dv = computeDV(segments, segments.join(\"-\"));\n if (dv === null) {\n throw new Error(\"Failed to compute Panama RUC DV\");\n }\n return `${segments.join(\"-\")} DV${dv}`;\n};\n\n/** Panama tax identification number. */\nconst ruc: CountryValidator<\"PA\"> = {\n name: \"Tax Identification Number\",\n localName: \"Registro Único de Contribuyente\",\n abbreviation: \"RUC\",\n aliases: [\"RUC\"] as const,\n candidatePattern: \"\\\\d{1,2}-?\\\\d{1,4}-?\\\\d{1,6}\",\n scope: \"country\",\n country: \"PA\",\n entityType: \"any\",\n description: \"Tax identifier issued by Panama's DGI\",\n sourceUrl: \"https://dgi.mef.gob.pa/\",\n examples: [\n \"1-184-921 DV49\",\n \"2588017-1-831938 DV20\",\n ] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default ruc;\nexport { compact, format, validate, generate };\n"],"mappings":"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"}
|
package/dist/patterns.d.ts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
import { CountryCode, Validator } from "./types.js";
|
|
1
|
+
import { CountryCode, CountryValidator, Validator } from "./types.js";
|
|
2
2
|
|
|
3
3
|
//#region src/patterns.d.ts
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
/** The validator this pattern was derived from. */
|
|
7
|
-
validator: Validator;
|
|
8
|
-
/** Loose regex matching candidates in text. */
|
|
4
|
+
type ValidatorPattern<TValidator extends Validator = Validator> = {
|
|
5
|
+
/** The validator this pattern was derived from. */validator: TValidator; /** Loose regex matching candidates in text. */
|
|
9
6
|
regex: RegExp;
|
|
10
7
|
};
|
|
11
8
|
/**
|
|
@@ -25,21 +22,22 @@ declare const toRegex: (v: Validator) => RegExp;
|
|
|
25
22
|
/**
|
|
26
23
|
* Build patterns for a list of validators.
|
|
27
24
|
*/
|
|
28
|
-
declare const toPatterns: (validators: readonly
|
|
25
|
+
declare const toPatterns: <TValidator extends Validator>(validators: readonly TValidator[]) => ValidatorPattern<TValidator>[];
|
|
29
26
|
/**
|
|
30
27
|
* Filter validators by country code and build
|
|
31
28
|
* patterns.
|
|
32
29
|
*/
|
|
33
|
-
|
|
30
|
+
type CountryScopedValidator<TValidator extends Validator, TCountry extends CountryCode> = TValidator extends CountryValidator<infer TValidatorCountry, infer TParsed> ? TCountry extends TValidatorCountry ? TValidator & CountryValidator<TCountry, TParsed> : TValidatorCountry extends TCountry ? TValidator : never : never;
|
|
31
|
+
declare const byCountry: <TCountry extends CountryCode, TValidator extends Validator>(country: TCountry, validators: readonly TValidator[]) => ValidatorPattern<CountryScopedValidator<TValidator, TCountry>>[];
|
|
34
32
|
/**
|
|
35
33
|
* Filter validators by entity type and build
|
|
36
34
|
* patterns.
|
|
37
35
|
*/
|
|
38
|
-
declare const byEntityType: (entityType: "person" | "company" | "any", validators: readonly
|
|
36
|
+
declare const byEntityType: <TValidator extends Validator>(entityType: "person" | "company" | "any", validators: readonly TValidator[]) => ValidatorPattern<TValidator>[];
|
|
39
37
|
/**
|
|
40
38
|
* Build patterns for ALL provided validators.
|
|
41
39
|
*/
|
|
42
|
-
declare const allPatterns: (validators: readonly
|
|
40
|
+
declare const allPatterns: <TValidator extends Validator>(validators: readonly TValidator[]) => ValidatorPattern<TValidator>[];
|
|
43
41
|
//#endregion
|
|
44
42
|
export { ValidatorPattern, allPatterns, byCountry, byEntityType, toPatterns, toRegex };
|
|
45
43
|
//# sourceMappingURL=patterns.d.ts.map
|
package/dist/patterns.js
CHANGED
|
@@ -19,8 +19,9 @@ const inferLengths = (v) => {
|
|
|
19
19
|
* "25 123 891" → [2, 3, 3].
|
|
20
20
|
*/
|
|
21
21
|
const inferGroups = (v) => {
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const first = v.examples?.[0];
|
|
23
|
+
if (first === void 0) return null;
|
|
24
|
+
const compact = v.compact(first);
|
|
24
25
|
const formatted = v.format(compact);
|
|
25
26
|
if (formatted === compact) return null;
|
|
26
27
|
const parts = formatted.split(/[^a-zA-Z0-9]+/);
|
|
@@ -34,43 +35,97 @@ const inferGroups = (v) => {
|
|
|
34
35
|
* (e.g., "CZ" for DIČ, "CHE" for Swiss UID).
|
|
35
36
|
*/
|
|
36
37
|
const inferPrefix = (v) => {
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
const examples = v.examples;
|
|
39
|
+
const first = examples?.[0];
|
|
40
|
+
if (!examples || first === void 0) return null;
|
|
41
|
+
const compact = v.compact(first);
|
|
42
|
+
const compactPrefix = compact.match(/^([A-Z]+)\d/)?.[1];
|
|
43
|
+
if (compactPrefix !== void 0 && examples.length > 1) {
|
|
44
|
+
if (examples.every((ex) => v.compact(ex).startsWith(compactPrefix))) return compactPrefix;
|
|
45
|
+
} else if (compactPrefix !== void 0 && examples.length === 1) return compactPrefix;
|
|
46
|
+
const fmtPrefix = v.format(compact).match(/^([A-Z]+)[\s\-./]?\d/)?.[1];
|
|
47
|
+
if (fmtPrefix !== void 0 && !compact.startsWith(fmtPrefix)) return fmtPrefix;
|
|
46
48
|
return null;
|
|
47
49
|
};
|
|
48
50
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* if
|
|
51
|
+
* Character class for a string fragment:
|
|
52
|
+
* `\d` if all digits, `[A-Z]` if all letters,
|
|
53
|
+
* `[A-Z0-9]` if mixed.
|
|
52
54
|
*/
|
|
53
|
-
const
|
|
54
|
-
if (!v.examples || v.examples.length === 0) return "\\d";
|
|
55
|
+
const charClassFor = (s) => {
|
|
55
56
|
let hasLetter = false;
|
|
56
57
|
let hasDigit = false;
|
|
57
|
-
for (const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (/[a-zA-Z]/.test(ch)) hasLetter = true;
|
|
61
|
-
if (/\d/.test(ch)) hasDigit = true;
|
|
62
|
-
}
|
|
58
|
+
for (const ch of s) {
|
|
59
|
+
if (/[a-zA-Z]/.test(ch)) hasLetter = true;
|
|
60
|
+
if (/\d/.test(ch)) hasDigit = true;
|
|
63
61
|
}
|
|
64
62
|
if (hasLetter && hasDigit) return "[A-Z0-9]";
|
|
65
63
|
if (hasLetter) return "[A-Z]";
|
|
66
64
|
return "\\d";
|
|
67
65
|
};
|
|
68
66
|
/**
|
|
67
|
+
* Determine the character class needed for the
|
|
68
|
+
* compact form: `\d` if all digits, `[A-Z0-9]`
|
|
69
|
+
* if alphanumeric, etc.
|
|
70
|
+
*/
|
|
71
|
+
const inferCharClass = (v) => {
|
|
72
|
+
if (!v.examples || v.examples.length === 0) return "\\d";
|
|
73
|
+
return charClassFor(v.examples.map((ex) => v.compact(ex)).join(""));
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Infer per-group sizes AND character classes from
|
|
77
|
+
* format(). Returns groups with per-position char
|
|
78
|
+
* classes, e.g., "12 010188 M 01 1" →
|
|
79
|
+
* sizes: [2, 6, 1, 2, 1]
|
|
80
|
+
* classes: ["\d", "\d", "[A-Z]", "\d", "\d"]
|
|
81
|
+
*
|
|
82
|
+
* Only returns non-null when per-group classes
|
|
83
|
+
* differ (some groups are letters, some digits).
|
|
84
|
+
* Letter-only groups before the first digit group
|
|
85
|
+
* are treated as prefixes and excluded (handled
|
|
86
|
+
* by inferPrefix separately).
|
|
87
|
+
*/
|
|
88
|
+
const inferPerGroup = (v) => {
|
|
89
|
+
const first = v.examples?.[0];
|
|
90
|
+
if (first === void 0) return null;
|
|
91
|
+
const compact = v.compact(first);
|
|
92
|
+
const formatted = v.format(compact);
|
|
93
|
+
if (formatted === compact) return null;
|
|
94
|
+
if (!(/[a-zA-Z]/.test(compact) && /\d/.test(compact))) return null;
|
|
95
|
+
const parts = formatted.split(/[^a-zA-Z0-9]+/);
|
|
96
|
+
if (parts.some((p) => /[a-zA-Z]/.test(p) && /\d/.test(p))) return null;
|
|
97
|
+
const filtered = [];
|
|
98
|
+
let seenDigitGroup = false;
|
|
99
|
+
for (const p of parts) {
|
|
100
|
+
if (p.length === 0) continue;
|
|
101
|
+
if (/\d/.test(p)) {
|
|
102
|
+
seenDigitGroup = true;
|
|
103
|
+
filtered.push({
|
|
104
|
+
size: p.length,
|
|
105
|
+
charClass: charClassFor(p)
|
|
106
|
+
});
|
|
107
|
+
} else if (seenDigitGroup) filtered.push({
|
|
108
|
+
size: p.length,
|
|
109
|
+
charClass: charClassFor(p)
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (filtered.length <= 1) return null;
|
|
113
|
+
const firstClass = filtered[0]?.charClass;
|
|
114
|
+
if (filtered.every((g) => g.charClass === firstClass)) return null;
|
|
115
|
+
return filtered;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
69
118
|
* Build a group regex from group sizes + char class.
|
|
70
119
|
* [2, 3, 3] with \d → /\d{2}[\s\-.]?\d{3}[\s\-.]?\d{3}/
|
|
71
120
|
*/
|
|
72
121
|
const groupsToPattern = (groups, cc) => groups.map((g) => `${cc}{${g}}`).join(SEP);
|
|
73
122
|
/**
|
|
123
|
+
* Build a group regex with per-group char classes.
|
|
124
|
+
* Produces tighter patterns when groups have different
|
|
125
|
+
* character types (e.g., digits vs letters).
|
|
126
|
+
*/
|
|
127
|
+
const groupsToPatternPerClass = (groups) => groups.map(({ size, charClass }) => `${charClass}{${size}}`).join(SEP);
|
|
128
|
+
/**
|
|
74
129
|
* Derive a loose candidate-matching regex from
|
|
75
130
|
* a validator. The regex finds potential matches;
|
|
76
131
|
* use `validate()` to confirm.
|
|
@@ -84,7 +139,9 @@ const toRegex = (v) => {
|
|
|
84
139
|
const lengths = inferLengths(v);
|
|
85
140
|
const cc = inferCharClass(v);
|
|
86
141
|
let pattern;
|
|
87
|
-
|
|
142
|
+
const perGroup = inferPerGroup(v);
|
|
143
|
+
if (perGroup && lengths.length <= 1) pattern = groupsToPatternPerClass(perGroup);
|
|
144
|
+
else if (groups && lengths.length <= 1) pattern = groupsToPattern(groups, cc);
|
|
88
145
|
else if (lengths.length === 1) pattern = `${cc}{${lengths[0]}}`;
|
|
89
146
|
else if (lengths.length > 1) pattern = `${cc}{${Math.min(...lengths)},${Math.max(...lengths)}}`;
|
|
90
147
|
else pattern = `${cc}{6,20}`;
|
|
@@ -103,11 +160,9 @@ const toPatterns = (validators) => validators.map((v) => ({
|
|
|
103
160
|
validator: v,
|
|
104
161
|
regex: toRegex(v)
|
|
105
162
|
}));
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
*/
|
|
110
|
-
const byCountry = (country, validators) => toPatterns(validators.filter((v) => v.country === country));
|
|
163
|
+
const byCountry = (country, validators) => {
|
|
164
|
+
return toPatterns(validators.filter((v) => v.scope === "country" && v.country === country));
|
|
165
|
+
};
|
|
111
166
|
/**
|
|
112
167
|
* Filter validators by entity type and build
|
|
113
168
|
* patterns.
|
package/dist/patterns.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patterns.js","names":[],"sources":["../src/patterns.ts"],"sourcesContent":["/**\n * Derive candidate-matching regex patterns from\n * validators. These patterns find CANDIDATES in\n * text — use `validate()` to confirm each match.\n *\n * Designed for integration with regex-set or\n * similar multi-pattern scanning engines.\n *\n * @example\n * ```ts\n * import {\n * toRegex, byCountry, byEntityType,\n * } from \"@stll/stdnum/patterns\";\n * import { cz } from \"@stll/stdnum\";\n *\n * // Single validator\n * toRegex(cz.ico);\n * // → /(?<!\\w)\\d{8}(?!\\w)/g\n *\n * // All Czech validators\n * byCountry(\"CZ\");\n * // → [{ validator: cz.ico, regex }, ...]\n *\n * // All company identifiers\n * byEntityType(\"company\");\n * // → [{ validator, regex }, ...]\n * ```\n */\n\nimport type { CountryCode, Validator } from \"./types\";\n\n// ─── Pattern type ─────────────────────────────\n\nexport type ValidatorPattern = {\n /** The validator this pattern was derived from. */\n validator: Validator;\n /** Loose regex matching candidates in text. */\n regex: RegExp;\n};\n\n// ─── Regex derivation ─────────────────────────\n\n/** Separator chars that compact() strips. */\nconst SEP = \"[\\\\s\\\\-./]?\";\n\n/**\n * Infer compact lengths from metadata or examples.\n */\nconst inferLengths = (v: Validator): number[] => {\n if (v.lengths && v.lengths.length > 0) {\n return [...v.lengths];\n }\n if (v.examples && v.examples.length > 0) {\n const lens = new Set<number>();\n for (const ex of v.examples) {\n lens.add(v.compact(ex).length);\n }\n return [...lens];\n }\n return [];\n};\n\n/**\n * Derive the display grouping from format().\n * Returns an array of group sizes, e.g.,\n * \"25 123 891\" → [2, 3, 3].\n */\nconst inferGroups = (v: Validator): number[] | null => {\n if (!v.examples || v.examples.length === 0) {\n return null;\n }\n const compact = v.compact(v.examples[0]!);\n const formatted = v.format(compact);\n if (formatted === compact) return null;\n\n // Split on non-alphanumeric separators\n const parts = formatted.split(/[^a-zA-Z0-9]+/);\n if (parts.length <= 1) return null;\n\n // For digit-only validators, skip letter-only\n // tokens (prefix like \"CHE\"). For alphanumeric\n // validators (IBAN, ISIN), keep all groups.\n const isAlphanumeric = parts.some(\n (p) => /[a-zA-Z]/.test(p) && /\\d/.test(p),\n );\n const groups = parts\n .filter(\n (p) =>\n p.length > 0 && (isAlphanumeric || /\\d/.test(p)),\n )\n .map((p) => p.length);\n\n return groups.length > 1 ? groups : null;\n};\n\n/**\n * Detect if this validator uses a known prefix\n * (e.g., \"CZ\" for DIČ, \"CHE\" for Swiss UID).\n */\nconst inferPrefix = (v: Validator): string | null => {\n if (!v.examples || v.examples.length === 0) {\n return null;\n }\n const compact = v.compact(v.examples[0]!);\n // Prefix already present in compact form.\n // But only if ALL examples share the same prefix\n // (e.g., \"CHE\" for Swiss UID). If examples have\n // different prefixes (IBAN: GB/DE/FR), there's\n // no fixed prefix — it's part of the value.\n const compactMatch = compact.match(/^([A-Z]+)\\d/);\n if (compactMatch && v.examples!.length > 1) {\n const pfx = compactMatch[1]!;\n const allSame = v.examples!.every((ex) =>\n v.compact(ex).startsWith(pfx),\n );\n if (allSame) return pfx;\n } else if (compactMatch && v.examples!.length === 1) {\n return compactMatch[1]!;\n }\n // Prefix added only by format()\n // (e.g., \"DE\" for de.vat, \"CZ\" for cz.dic)\n const formatted = v.format(compact);\n const fmtMatch = formatted.match(/^([A-Z]+)[\\s\\-./]?\\d/);\n if (fmtMatch && !compact.startsWith(fmtMatch[1]!)) {\n return fmtMatch[1]!;\n }\n return null;\n};\n\n/**\n * Determine the character class needed for the\n * compact form: `\\d` if all digits, `[A-Z0-9]`\n * if alphanumeric, etc.\n */\nconst inferCharClass = (v: Validator): string => {\n if (!v.examples || v.examples.length === 0) {\n return \"\\\\d\";\n }\n let hasLetter = false;\n let hasDigit = false;\n for (const ex of v.examples) {\n const c = v.compact(ex);\n for (const ch of c) {\n if (/[a-zA-Z]/.test(ch)) hasLetter = true;\n if (/\\d/.test(ch)) hasDigit = true;\n }\n }\n if (hasLetter && hasDigit) return \"[A-Z0-9]\";\n if (hasLetter) return \"[A-Z]\";\n return \"\\\\d\";\n};\n\n/**\n * Build a group regex from group sizes + char class.\n * [2, 3, 3] with \\d → /\\d{2}[\\s\\-.]?\\d{3}[\\s\\-.]?\\d{3}/\n */\nconst groupsToPattern = (\n groups: number[],\n cc: string,\n): string => groups.map((g) => `${cc}{${g}}`).join(SEP);\n\n/**\n * Derive a loose candidate-matching regex from\n * a validator. The regex finds potential matches;\n * use `validate()` to confirm.\n *\n * Handles both digit-only (IČO, NIP) and\n * alphanumeric (IBAN, BIC, ISIN, LEI) validators.\n */\nexport const toRegex = (v: Validator): RegExp => {\n const prefix = inferPrefix(v);\n const groups = inferGroups(v);\n const lengths = inferLengths(v);\n const cc = inferCharClass(v);\n\n let pattern: string;\n\n if (groups && lengths.length <= 1) {\n pattern = groupsToPattern(groups, cc);\n } else if (lengths.length === 1) {\n pattern = `${cc}{${lengths[0]}}`;\n } else if (lengths.length > 1) {\n const min = Math.min(...lengths);\n const max = Math.max(...lengths);\n pattern = `${cc}{${min},${max}}`;\n } else {\n pattern = `${cc}{6,20}`;\n }\n\n if (prefix) {\n pattern = `${prefix}${SEP}${pattern}`;\n }\n\n // Word boundary to avoid matching inside\n // larger numbers\n return new RegExp(`(?<!\\\\w)${pattern}(?!\\\\w)`, \"g\");\n};\n\n// ─── Grouped collections ──────────────────────\n\n/**\n * All discovered validators, lazily populated.\n * Import * from \"../src\" would pull everything;\n * instead, callers pass validators explicitly.\n */\n\n/**\n * Build patterns for a list of validators.\n */\nexport const toPatterns = (\n validators: readonly Validator[],\n): ValidatorPattern[] =>\n validators.map((v) => ({\n validator: v,\n regex: toRegex(v),\n }));\n\n/**\n * Filter validators by country code and build\n * patterns.\n */\nexport const byCountry = (\n country: CountryCode,\n validators: readonly Validator[],\n): ValidatorPattern[] =>\n toPatterns(\n validators.filter((v) => v.country === country),\n );\n\n/**\n * Filter validators by entity type and build\n * patterns.\n */\nexport const byEntityType = (\n entityType: \"person\" | \"company\" | \"any\",\n validators: readonly Validator[],\n): ValidatorPattern[] =>\n toPatterns(\n validators.filter(\n (v) =>\n entityType === \"any\" ||\n v.entityType === entityType ||\n v.entityType === \"any\",\n ),\n );\n\n/**\n * Build patterns for ALL provided validators.\n */\nexport const allPatterns = (\n validators: readonly Validator[],\n): ValidatorPattern[] => toPatterns(validators);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"patterns.js","names":[],"sources":["../src/patterns.ts"],"sourcesContent":["/**\n * Derive candidate-matching regex patterns from\n * validators. These patterns find CANDIDATES in\n * text — use `validate()` to confirm each match.\n *\n * Designed for integration with regex-set or\n * similar multi-pattern scanning engines.\n *\n * @example\n * ```ts\n * import {\n * toRegex, byCountry, byEntityType,\n * } from \"@stll/stdnum/patterns\";\n * import { cz } from \"@stll/stdnum\";\n *\n * // Single validator\n * toRegex(cz.ico);\n * // → /(?<!\\w)\\d{8}(?!\\w)/g\n *\n * // All Czech validators\n * byCountry(\"CZ\");\n * // → [{ validator: cz.ico, regex }, ...]\n *\n * // All company identifiers\n * byEntityType(\"company\");\n * // → [{ validator, regex }, ...]\n * ```\n */\n\nimport type {\n CountryCode,\n CountryValidator,\n Validator,\n} from \"./types\";\n\n// ─── Pattern type ─────────────────────────────\n\nexport type ValidatorPattern<\n TValidator extends Validator = Validator,\n> = {\n /** The validator this pattern was derived from. */\n validator: TValidator;\n /** Loose regex matching candidates in text. */\n regex: RegExp;\n};\n\n// ─── Regex derivation ─────────────────────────\n\n/** Separator chars that compact() strips. */\nconst SEP = \"[\\\\s\\\\-./]?\";\n\n/**\n * Infer compact lengths from metadata or examples.\n */\nconst inferLengths = (v: Validator): number[] => {\n if (v.lengths && v.lengths.length > 0) {\n return [...v.lengths];\n }\n if (v.examples && v.examples.length > 0) {\n const lens = new Set<number>();\n for (const ex of v.examples) {\n lens.add(v.compact(ex).length);\n }\n return [...lens];\n }\n return [];\n};\n\n/**\n * Derive the display grouping from format().\n * Returns an array of group sizes, e.g.,\n * \"25 123 891\" → [2, 3, 3].\n */\nconst inferGroups = (v: Validator): number[] | null => {\n const first = v.examples?.[0];\n if (first === undefined) return null;\n const compact = v.compact(first);\n const formatted = v.format(compact);\n if (formatted === compact) return null;\n\n // Split on non-alphanumeric separators\n const parts = formatted.split(/[^a-zA-Z0-9]+/);\n if (parts.length <= 1) return null;\n\n // For digit-only validators, skip letter-only\n // tokens (prefix like \"CHE\"). For alphanumeric\n // validators (IBAN, ISIN), keep all groups.\n const isAlphanumeric = parts.some(\n (p) => /[a-zA-Z]/.test(p) && /\\d/.test(p),\n );\n const groups = parts\n .filter(\n (p) =>\n p.length > 0 && (isAlphanumeric || /\\d/.test(p)),\n )\n .map((p) => p.length);\n\n return groups.length > 1 ? groups : null;\n};\n\n/**\n * Detect if this validator uses a known prefix\n * (e.g., \"CZ\" for DIČ, \"CHE\" for Swiss UID).\n */\nconst inferPrefix = (v: Validator): string | null => {\n const examples = v.examples;\n const first = examples?.[0];\n if (!examples || first === undefined) return null;\n const compact = v.compact(first);\n // Prefix already present in compact form.\n // But only if ALL examples share the same prefix\n // (e.g., \"CHE\" for Swiss UID). If examples have\n // different prefixes (IBAN: GB/DE/FR), there's\n // no fixed prefix — it's part of the value.\n const compactMatch = compact.match(/^([A-Z]+)\\d/);\n const compactPrefix = compactMatch?.[1];\n if (compactPrefix !== undefined && examples.length > 1) {\n const allSame = examples.every((ex) =>\n v.compact(ex).startsWith(compactPrefix),\n );\n if (allSame) return compactPrefix;\n } else if (\n compactPrefix !== undefined &&\n examples.length === 1\n ) {\n return compactPrefix;\n }\n // Prefix added only by format()\n // (e.g., \"DE\" for de.vat, \"CZ\" for cz.dic)\n const formatted = v.format(compact);\n const fmtMatch = formatted.match(/^([A-Z]+)[\\s\\-./]?\\d/);\n const fmtPrefix = fmtMatch?.[1];\n if (\n fmtPrefix !== undefined &&\n !compact.startsWith(fmtPrefix)\n ) {\n return fmtPrefix;\n }\n return null;\n};\n\n/**\n * Character class for a string fragment:\n * `\\d` if all digits, `[A-Z]` if all letters,\n * `[A-Z0-9]` if mixed.\n */\nconst charClassFor = (s: string): string => {\n let hasLetter = false;\n let hasDigit = false;\n for (const ch of s) {\n if (/[a-zA-Z]/.test(ch)) hasLetter = true;\n if (/\\d/.test(ch)) hasDigit = true;\n }\n if (hasLetter && hasDigit) return \"[A-Z0-9]\";\n if (hasLetter) return \"[A-Z]\";\n return \"\\\\d\";\n};\n\n/**\n * Determine the character class needed for the\n * compact form: `\\d` if all digits, `[A-Z0-9]`\n * if alphanumeric, etc.\n */\nconst inferCharClass = (v: Validator): string => {\n if (!v.examples || v.examples.length === 0) {\n return \"\\\\d\";\n }\n const combined = v.examples\n .map((ex) => v.compact(ex))\n .join(\"\");\n return charClassFor(combined);\n};\n\ntype PerGroup = { size: number; charClass: string };\n\n/**\n * Infer per-group sizes AND character classes from\n * format(). Returns groups with per-position char\n * classes, e.g., \"12 010188 M 01 1\" →\n * sizes: [2, 6, 1, 2, 1]\n * classes: [\"\\d\", \"\\d\", \"[A-Z]\", \"\\d\", \"\\d\"]\n *\n * Only returns non-null when per-group classes\n * differ (some groups are letters, some digits).\n * Letter-only groups before the first digit group\n * are treated as prefixes and excluded (handled\n * by inferPrefix separately).\n */\nconst inferPerGroup = (v: Validator): PerGroup[] | null => {\n const first = v.examples?.[0];\n if (first === undefined) return null;\n const compact = v.compact(first);\n const formatted = v.format(compact);\n if (formatted === compact) return null;\n\n // Only applies to mixed validators (compact has\n // both letters and digits in separate positions,\n // like German SVNR \"12010188M011\").\n const compactMixed =\n /[a-zA-Z]/.test(compact) && /\\d/.test(compact);\n if (!compactMixed) return null;\n\n // Also skip if any single part mixes letters and\n // digits (IBAN, ISIN) — inferGroups already\n // handles those correctly with the global class.\n const parts = formatted.split(/[^a-zA-Z0-9]+/);\n const isAlphanumeric = parts.some(\n (p) => /[a-zA-Z]/.test(p) && /\\d/.test(p),\n );\n if (isAlphanumeric) return null;\n\n // Keep digit groups and letter-only groups that\n // appear AFTER the first digit group (embedded\n // letters). Skip letter-only groups before the\n // first digit group (prefix like \"CHE\").\n const filtered: PerGroup[] = [];\n let seenDigitGroup = false;\n for (const p of parts) {\n if (p.length === 0) continue;\n if (/\\d/.test(p)) {\n seenDigitGroup = true;\n filtered.push({\n size: p.length,\n charClass: charClassFor(p),\n });\n } else if (seenDigitGroup) {\n filtered.push({\n size: p.length,\n charClass: charClassFor(p),\n });\n }\n }\n\n if (filtered.length <= 1) return null;\n\n const firstClass = filtered[0]?.charClass;\n const allSame = filtered.every(\n (g) => g.charClass === firstClass,\n );\n if (allSame) return null;\n\n return filtered;\n};\n\n/**\n * Build a group regex from group sizes + char class.\n * [2, 3, 3] with \\d → /\\d{2}[\\s\\-.]?\\d{3}[\\s\\-.]?\\d{3}/\n */\nconst groupsToPattern = (\n groups: number[],\n cc: string,\n): string => groups.map((g) => `${cc}{${g}}`).join(SEP);\n\n/**\n * Build a group regex with per-group char classes.\n * Produces tighter patterns when groups have different\n * character types (e.g., digits vs letters).\n */\nconst groupsToPatternPerClass = (\n groups: readonly { size: number; charClass: string }[],\n): string =>\n groups\n .map(({ size, charClass }) => `${charClass}{${size}}`)\n .join(SEP);\n\n/**\n * Derive a loose candidate-matching regex from\n * a validator. The regex finds potential matches;\n * use `validate()` to confirm.\n *\n * Handles both digit-only (IČO, NIP) and\n * alphanumeric (IBAN, BIC, ISIN, LEI) validators.\n */\nexport const toRegex = (v: Validator): RegExp => {\n const prefix = inferPrefix(v);\n const groups = inferGroups(v);\n const lengths = inferLengths(v);\n const cc = inferCharClass(v);\n\n let pattern: string;\n\n // Use per-group char classes when groups mix\n // digits and letters (e.g., German SVNR:\n // \"12 010188 M 01 1\" → [\\d, \\d, [A-Z], \\d, \\d]).\n // This prevents overly broad [A-Z0-9] from\n // matching all-caps prose as identifiers.\n const perGroup = inferPerGroup(v);\n\n if (perGroup && lengths.length <= 1) {\n pattern = groupsToPatternPerClass(perGroup);\n } else if (groups && lengths.length <= 1) {\n pattern = groupsToPattern(groups, cc);\n } else if (lengths.length === 1) {\n pattern = `${cc}{${lengths[0]}}`;\n } else if (lengths.length > 1) {\n const min = Math.min(...lengths);\n const max = Math.max(...lengths);\n pattern = `${cc}{${min},${max}}`;\n } else {\n pattern = `${cc}{6,20}`;\n }\n\n if (prefix) {\n pattern = `${prefix}${SEP}${pattern}`;\n }\n\n // Word boundary to avoid matching inside\n // larger numbers\n return new RegExp(`(?<!\\\\w)${pattern}(?!\\\\w)`, \"g\");\n};\n\n// ─── Grouped collections ──────────────────────\n\n/**\n * All discovered validators, lazily populated.\n * Import * from \"../src\" would pull everything;\n * instead, callers pass validators explicitly.\n */\n\n/**\n * Build patterns for a list of validators.\n */\nexport const toPatterns = <TValidator extends Validator>(\n validators: readonly TValidator[],\n): ValidatorPattern<TValidator>[] =>\n validators.map((v) => ({\n validator: v,\n regex: toRegex(v),\n }));\n\n/**\n * Filter validators by country code and build\n * patterns.\n */\ntype CountryScopedValidator<\n TValidator extends Validator,\n TCountry extends CountryCode,\n> =\n TValidator extends CountryValidator<\n infer TValidatorCountry,\n infer TParsed\n >\n ? TCountry extends TValidatorCountry\n ? TValidator & CountryValidator<TCountry, TParsed>\n : TValidatorCountry extends TCountry\n ? TValidator\n : never\n : never;\n\nexport const byCountry = <\n TCountry extends CountryCode,\n TValidator extends Validator,\n>(\n country: TCountry,\n validators: readonly TValidator[],\n): ValidatorPattern<\n CountryScopedValidator<TValidator, TCountry>\n>[] => {\n const countryValidators = validators.filter(\n (\n v,\n ): v is CountryScopedValidator<TValidator, TCountry> =>\n v.scope === \"country\" && v.country === country,\n );\n return toPatterns(countryValidators);\n};\n\n/**\n * Filter validators by entity type and build\n * patterns.\n */\nexport const byEntityType = <TValidator extends Validator>(\n entityType: \"person\" | \"company\" | \"any\",\n validators: readonly TValidator[],\n): ValidatorPattern<TValidator>[] =>\n toPatterns(\n validators.filter(\n (v) =>\n entityType === \"any\" ||\n v.entityType === entityType ||\n v.entityType === \"any\",\n ),\n );\n\n/**\n * Build patterns for ALL provided validators.\n */\nexport const allPatterns = <TValidator extends Validator>(\n validators: readonly TValidator[],\n): ValidatorPattern<TValidator>[] => toPatterns(validators);\n"],"mappings":"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"}
|
package/dist/pe/mod.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { __exportAll } from "../_virtual/_rolldown/runtime.js";
|
|
2
1
|
import ruc from "./ruc.js";
|
|
3
2
|
|
|
4
3
|
//#region src/pe/mod.d.ts
|
|
5
|
-
|
|
4
|
+
declare namespace mod_d_exports {
|
|
5
|
+
export { ruc };
|
|
6
|
+
}
|
|
6
7
|
//#endregion
|
|
7
8
|
export { mod_d_exports, ruc };
|
|
8
9
|
//# sourceMappingURL=mod.d.ts.map
|
package/dist/pe/ruc.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CountryValidator, ValidateResult } from "../types.js";
|
|
2
2
|
|
|
3
3
|
//#region src/pe/ruc.d.ts
|
|
4
|
-
|
|
5
4
|
declare const compact: (value: string) => string;
|
|
6
5
|
declare const validate: (value: string) => ValidateResult;
|
|
7
6
|
declare const format: (value: string) => string;
|
|
@@ -13,7 +12,7 @@ declare const generate: () => string;
|
|
|
13
12
|
* Examples sourced from python-stdnum test suite
|
|
14
13
|
* (pe.ruc module).
|
|
15
14
|
*/
|
|
16
|
-
declare const ruc:
|
|
15
|
+
declare const ruc: CountryValidator<"PE">;
|
|
17
16
|
//#endregion
|
|
18
17
|
export { compact, ruc as default, format, generate, validate };
|
|
19
18
|
//# sourceMappingURL=ruc.d.ts.map
|
package/dist/pe/ruc.js
CHANGED
|
@@ -1,24 +1,9 @@
|
|
|
1
1
|
import { clean } from "../_util/clean.js";
|
|
2
|
-
import { randomDigits } from "../_util/generate.js";
|
|
2
|
+
import { randomDigits, randomPick } from "../_util/generate.js";
|
|
3
3
|
import { err } from "../_util/result.js";
|
|
4
4
|
import { isdigits } from "../_util/strings.js";
|
|
5
5
|
//#region src/pe/ruc.ts
|
|
6
6
|
/**
|
|
7
|
-
* RUC (Registro Único de Contribuyentes).
|
|
8
|
-
*
|
|
9
|
-
* Peruvian tax identification number assigned by SUNAT
|
|
10
|
-
* (Superintendencia Nacional de Aduanas y de
|
|
11
|
-
* Administración Tributaria). The number consists of
|
|
12
|
-
* 11 digits: a type prefix (10 = person, 20 = company,
|
|
13
|
-
* among others), 8 identification digits, and a check
|
|
14
|
-
* digit computed using a weighted modulo 11 algorithm.
|
|
15
|
-
*
|
|
16
|
-
* Format: XXXXXXXXXXX (11 digits, no separators).
|
|
17
|
-
*
|
|
18
|
-
* @see https://www.sunat.gob.pe/
|
|
19
|
-
* @see https://en.wikipedia.org/wiki/Tax_identification_number#Peru
|
|
20
|
-
*/
|
|
21
|
-
/**
|
|
22
7
|
* Valid type prefixes for RUC numbers.
|
|
23
8
|
* 10 = natural person, 15 = non-domiciled without RUC,
|
|
24
9
|
* 17 = non-domiciled, 20 = legal entity,
|
|
@@ -42,6 +27,12 @@ const WEIGHTS = [
|
|
|
42
27
|
3,
|
|
43
28
|
2
|
|
44
29
|
];
|
|
30
|
+
const GENERATE_PREFIXES = [
|
|
31
|
+
"10",
|
|
32
|
+
"15",
|
|
33
|
+
"17",
|
|
34
|
+
"20"
|
|
35
|
+
];
|
|
45
36
|
const compact = (value) => clean(value, " -.").trim();
|
|
46
37
|
/**
|
|
47
38
|
* Compute the RUC check digit using weighted sum
|
|
@@ -51,7 +42,7 @@ const compact = (value) => clean(value, " -.").trim();
|
|
|
51
42
|
*/
|
|
52
43
|
const calcCheckDigit = (body) => {
|
|
53
44
|
let sum = 0;
|
|
54
|
-
for (
|
|
45
|
+
for (const [i, weight] of WEIGHTS.entries()) sum += Number(body[i]) * weight;
|
|
55
46
|
const remainder = 11 - sum % 11;
|
|
56
47
|
if (remainder >= 10) return remainder - 10;
|
|
57
48
|
return remainder;
|
|
@@ -72,13 +63,7 @@ const validate = (value) => {
|
|
|
72
63
|
const format = (value) => compact(value);
|
|
73
64
|
/** Generate a random valid Peruvian RUC. */
|
|
74
65
|
const generate = () => {
|
|
75
|
-
const
|
|
76
|
-
"10",
|
|
77
|
-
"15",
|
|
78
|
-
"17",
|
|
79
|
-
"20"
|
|
80
|
-
];
|
|
81
|
-
const body = prefixes[Math.floor(Math.random() * prefixes.length)] + randomDigits(8);
|
|
66
|
+
const body = randomPick(GENERATE_PREFIXES) + randomDigits(8);
|
|
82
67
|
return body + String(calcCheckDigit(body));
|
|
83
68
|
};
|
|
84
69
|
/**
|
|
@@ -93,6 +78,7 @@ const ruc = {
|
|
|
93
78
|
abbreviation: "RUC",
|
|
94
79
|
aliases: ["RUC"],
|
|
95
80
|
candidatePattern: "\\d{11}",
|
|
81
|
+
scope: "country",
|
|
96
82
|
country: "PE",
|
|
97
83
|
entityType: "any",
|
|
98
84
|
compact,
|