@stll/stdnum 2.0.1 → 2.1.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.
- package/README.md +11 -9
- package/dist/_checksums/keccak.d.ts +5 -0
- package/dist/_checksums/keccak.js +118 -0
- package/dist/_checksums/keccak.js.map +1 -0
- package/dist/_checksums/mod112.js.map +1 -1
- package/dist/_checksums/sha256.d.ts +5 -0
- package/dist/_checksums/sha256.js +164 -0
- package/dist/_checksums/sha256.js.map +1 -0
- package/dist/_checksums/verhoeff.js.map +1 -1
- package/dist/_util/arabic.js.map +1 -1
- package/dist/_util/clean.d.ts +6 -1
- package/dist/_util/clean.js +7 -2
- package/dist/_util/clean.js.map +1 -1
- package/dist/_util/date.js.map +1 -1
- package/dist/ad/nrt.js.map +1 -1
- package/dist/ae/eid.js.map +1 -1
- package/dist/ai/tin.js.map +1 -1
- package/dist/al/nipt.js.map +1 -1
- package/dist/am/tin.js.map +1 -1
- package/dist/ar/cbu.js.map +1 -1
- package/dist/ar/cuit.js.map +1 -1
- package/dist/ar/dni.js.map +1 -1
- package/dist/at/businessid.js.map +1 -1
- package/dist/at/vnr.js.map +1 -1
- package/dist/au/abn.js.map +1 -1
- package/dist/au/tfn.js.map +1 -1
- package/dist/az/voen.js.map +1 -1
- package/dist/ba/jmbg.js.map +1 -1
- package/dist/be/bis.js.map +1 -1
- package/dist/be/nn.js.map +1 -1
- package/dist/be/vat.js.map +1 -1
- package/dist/bg/egn.js.map +1 -1
- package/dist/bg/vat.js.map +1 -1
- package/dist/bh/cpr.js.map +1 -1
- package/dist/bic.js.map +1 -1
- package/dist/br/cnpj.js.map +1 -1
- package/dist/br/cpf.js.map +1 -1
- package/dist/by/unp.js.map +1 -1
- package/dist/bz/tin.js.map +1 -1
- package/dist/ch/uid.js.map +1 -1
- package/dist/ch/vat.js.map +1 -1
- package/dist/cl/rut.js.map +1 -1
- package/dist/cn/ric.js.map +1 -1
- package/dist/cn/uscc.js.map +1 -1
- package/dist/cr/cpf.js.map +1 -1
- package/dist/crypto/btcbase58.d.ts +11 -0
- package/dist/crypto/btcbase58.js +76 -0
- package/dist/crypto/btcbase58.js.map +1 -0
- package/dist/crypto/btcbech32.d.ts +19 -0
- package/dist/crypto/btcbech32.js +145 -0
- package/dist/crypto/btcbech32.js.map +1 -0
- package/dist/crypto/eth.d.ts +11 -0
- package/dist/crypto/eth.js +63 -0
- package/dist/crypto/eth.js.map +1 -0
- package/dist/crypto/mod.d.ts +12 -0
- package/dist/crypto/mod.js +16 -0
- package/dist/crypto/mod.js.map +1 -0
- package/dist/crypto/wallet.d.ts +10 -0
- package/dist/crypto/wallet.js +55 -0
- package/dist/crypto/wallet.js.map +1 -0
- package/dist/cu/ni.js.map +1 -1
- package/dist/cz/rc.js.map +1 -1
- package/dist/de/handelsreg.js.map +1 -1
- package/dist/de/idnr.js.map +1 -1
- package/dist/de/stnr.js.map +1 -1
- package/dist/de/svnr.js.map +1 -1
- package/dist/dk/cpr.js.map +1 -1
- package/dist/dk/cvr.js.map +1 -1
- package/dist/dk/vat.js.map +1 -1
- package/dist/do/rnc.js.map +1 -1
- package/dist/ec/ruc.js.map +1 -1
- package/dist/ee/ik.js.map +1 -1
- package/dist/ee/vat.js.map +1 -1
- package/dist/eg/tn.js.map +1 -1
- package/dist/es/dni.js.map +1 -1
- package/dist/es/nie.js.map +1 -1
- package/dist/es/nss.js.map +1 -1
- package/dist/eu/vat.js.map +1 -1
- package/dist/fi/hetu.js.map +1 -1
- package/dist/fi/vat.js.map +1 -1
- package/dist/fi/ytunnus.js.map +1 -1
- package/dist/fr/nif.js.map +1 -1
- package/dist/fr/nir.js.map +1 -1
- package/dist/fr/tva.js.map +1 -1
- package/dist/gb/mod.d.ts +3 -2
- package/dist/gb/mod.js +3 -1
- package/dist/gb/mod.js.map +1 -1
- package/dist/gb/nhs.d.ts +11 -0
- package/dist/gb/nhs.js +51 -0
- package/dist/gb/nhs.js.map +1 -0
- package/dist/gb/nino.js.map +1 -1
- package/dist/gb/sedol.js.map +1 -1
- package/dist/gb/utr.js.map +1 -1
- package/dist/gb/vat.js.map +1 -1
- package/dist/ge/pin.js.map +1 -1
- package/dist/gh/tin.js.map +1 -1
- package/dist/gr/amka.js.map +1 -1
- package/dist/gt/nit.js.map +1 -1
- package/dist/hk/hkid.js.map +1 -1
- package/dist/hu/vat.js.map +1 -1
- package/dist/iban.js.map +1 -1
- package/dist/id/npwp.js.map +1 -1
- package/dist/ie/pps.js.map +1 -1
- package/dist/ie/vat.js.map +1 -1
- package/dist/il/idnr.js.map +1 -1
- package/dist/in/aadhaar.js.map +1 -1
- package/dist/in/gstin.js.map +1 -1
- package/dist/in/pan.js.map +1 -1
- package/dist/index.d.ts +76 -75
- package/dist/index.js +2 -1
- package/dist/ir/nid.js.map +1 -1
- package/dist/is/kennitala.js.map +1 -1
- package/dist/isin.js.map +1 -1
- package/dist/it/codicefiscale.js.map +1 -1
- package/dist/it/iva.js.map +1 -1
- package/dist/kr/rrn.js.map +1 -1
- package/dist/kw/civil.js.map +1 -1
- package/dist/kz/iin.js.map +1 -1
- package/dist/lei.js.map +1 -1
- package/dist/li/peid.js.map +1 -1
- package/dist/lk/nic.js.map +1 -1
- package/dist/lt/asmens.js.map +1 -1
- package/dist/lt/vat.js.map +1 -1
- package/dist/lu/vat.js.map +1 -1
- package/dist/lv/vat.js.map +1 -1
- package/dist/ma/ice.js.map +1 -1
- package/dist/mc/tva.js.map +1 -1
- package/dist/mt/vat.js.map +1 -1
- package/dist/mu/brn.js.map +1 -1
- package/dist/mx/clabe.js.map +1 -1
- package/dist/mx/curp.js.map +1 -1
- package/dist/mx/rfc.js.map +1 -1
- package/dist/my/nric.js.map +1 -1
- package/dist/ni/ruc.js.map +1 -1
- package/dist/nl/bsn.js.map +1 -1
- package/dist/nl/vat.js.map +1 -1
- package/dist/no/fodselsnummer.js.map +1 -1
- package/dist/no/mva.js.map +1 -1
- package/dist/no/orgnr.js.map +1 -1
- package/dist/nz/ird.js.map +1 -1
- package/dist/pa/ruc.js.map +1 -1
- package/dist/patterns.js.map +1 -1
- package/dist/pe/ruc.js.map +1 -1
- package/dist/pl/pesel.js.map +1 -1
- package/dist/pl/regon.js.map +1 -1
- package/dist/pt/cc.js.map +1 -1
- package/dist/ro/cnp.js.map +1 -1
- package/dist/ro/vat.js.map +1 -1
- package/dist/rs/pib.js.map +1 -1
- package/dist/ru/inn.js.map +1 -1
- package/dist/se/personnummer.js.map +1 -1
- package/dist/sg/uen.js.map +1 -1
- package/dist/si/emso.js.map +1 -1
- package/dist/si/vat.js.map +1 -1
- package/dist/sk/dic.js.map +1 -1
- package/dist/tw/ubn.js.map +1 -1
- package/dist/ua/edrpou.js.map +1 -1
- package/dist/us/itin.js.map +1 -1
- package/dist/us/rtn.js.map +1 -1
- package/dist/us/ssn.js.map +1 -1
- package/dist/uy/rut.js.map +1 -1
- package/dist/ve/rif.js.map +1 -1
- package/dist/vn/mst.js.map +1 -1
- package/dist/za/idnr.js.map +1 -1
- package/package.json +31 -6
- package/src/_checksums/keccak.ts +145 -0
- package/src/_checksums/sha256.ts +125 -0
- package/src/_util/clean.ts +7 -2
- package/src/crypto/btcbase58.ts +144 -0
- package/src/crypto/btcbech32.ts +210 -0
- package/src/crypto/eth.ts +114 -0
- package/src/crypto/mod.ts +4 -0
- package/src/crypto/wallet.ts +67 -0
- package/src/gb/mod.ts +1 -0
- package/src/gb/nhs.ts +92 -0
- package/src/index.ts +1 -0
package/dist/ro/cnp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cnp.js","names":[],"sources":["../../src/ro/cnp.ts"],"sourcesContent":["/**\n * CNP (Cod Numeric Personal).\n *\n * Romanian personal identification number. 13 digits\n * encoding gender/century, date of birth, county code,\n * serial number, and a check digit.\n *\n * @see https://ro.wikipedia.org/wiki/Cod_numeric_personal\n * @see https://www.cnp.ro/\n */\n\nimport type {\n ParsedPersonId,\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { weightedSum } from \"#checksums/weighted-sum\";\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 WEIGHTS = [\n 2, 7, 9, 1, 4, 6, 3, 5, 8, 2, 7, 9,\n] as const;\n\n// Counties 01-39 are the 39 modern judete; 40-46 are\n// Bucuresti sectors 1-6; 47-48 are the abolished\n// sectors 7-8; 51-52 are Calarasi/Giurgiu; 70 is \"Any\";\n// 80-83 are reserved. 49 and 50 are not allocated.\n// See https://github.com/vimishor/cnp-spec.\nconst VALID_COUNTIES = new Set([\n 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,\n 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,\n 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,\n 46, 47, 48, 51, 52, 70, 80, 81, 82, 83,\n]);\n\nconst centuryMap: Record<number, number> = {\n 1: 1900,\n 2: 1900,\n 3: 1800,\n 4: 1800,\n 5: 2000,\n 6: 2000,\n 7: 1900, // foreign residents\n 8: 1900, // foreign residents\n};\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 \"CNP must be exactly 13 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"CNP must contain only digits\",\n );\n }\n\n const g = Number(v[0]);\n if (g < 1 || g > 9) {\n return err(\n \"INVALID_COMPONENT\",\n \"CNP gender/century digit is invalid\",\n );\n }\n\n const century = centuryMap[g] ?? 1900;\n const yy = Number(v.slice(1, 3));\n const mm = Number(v.slice(3, 5));\n const dd = Number(v.slice(5, 7));\n const year = century + yy;\n\n if (!isValidDate(year, mm, dd)) {\n return err(\n \"INVALID_COMPONENT\",\n \"CNP contains an invalid date\",\n );\n }\n\n const county = Number(v.slice(7, 9));\n if (!VALID_COUNTIES.has(county)) {\n return err(\n \"INVALID_COMPONENT\",\n \"CNP county code is invalid\",\n );\n }\n\n const sum = weightedSum(v.slice(0, 12), WEIGHTS, 11);\n const check = sum === 10 ? 1 : sum;\n if (check !== Number(v[12])) {\n return err(\n \"INVALID_CHECKSUM\",\n \"CNP check digit 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 CNP.\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 g = Number(v[0]);\n const century = centuryMap[g] ?? 1900;\n const yy = Number(v.slice(1, 3));\n const mm = Number(v.slice(3, 5));\n const dd = Number(v.slice(5, 7));\n const year = century + yy;\n\n return {\n birthDate: new Date(year, mm - 1, dd),\n gender: g % 2 === 1 ? \"male\" : \"female\",\n };\n};\n\n/** Generate a random valid Romanian CNP. */\nconst generate = (): string => {\n for (;;) {\n const g = String(randomInt(1, 6));\n const yy = String(randomInt(0, 99)).padStart(2, \"0\");\n const mm = String(randomInt(1, 12)).padStart(2, \"0\");\n const dd = String(randomInt(1, 28)).padStart(2, \"0\");\n const county = String(randomInt(1, 52)).padStart(\n 2,\n \"0\",\n );\n const serial = String(randomInt(1, 999)).padStart(\n 3,\n \"0\",\n );\n const payload = g + yy + mm + dd + county + serial;\n const sum = weightedSum(payload, WEIGHTS, 11);\n const c = payload + String(sum === 10 ? 1 : sum);\n if (validate(c).valid) return c;\n }\n};\n\n/** Romanian Personal Identification Number. */\nconst cnp: CountryValidator<\"RO\", ParsedPersonId> = {\n name: \"Romanian Personal ID\",\n localName: \"Cod Numeric Personal\",\n abbreviation: \"CNP\",\n aliases: [\"CNP\", \"cod numeric personal\"] as const,\n candidatePattern:\n \"[1-8]\\\\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\\\\d|3[01])\\\\d{6}\",\n scope: \"country\",\n country: \"RO\",\n entityType: \"person\",\n sourceUrl: \"https://www.cnp.ro/\",\n lengths: [13] as const,\n examples: [\"1630615123457\"] as const,\n compact,\n format,\n parse,\n validate,\n generate,\n};\n\nexport default cnp;\nexport { compact, format, parse, validate, generate };\n"],"mappings":";;;;;;;AAwBA,MAAM,UAAU;CACd;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AACnC;AAOA,MAAM,iBAAiB,IAAI,IAAI;CAC7B;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CACvD;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CACpD;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CACpD;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;AACtC,CAAC;AAED,MAAM,aAAqC;CACzC,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;AACL;AAEA,MAAM,WAAW,UACf,MAAM,OAAO,IAAI;AAEnB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,IACf,OAAO,IACL,kBACA,+BACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,8BACF;CAGF,MAAM,IAAI,OAAO,EAAE,EAAE;CACrB,IAAI,IAAI,KAAK,IAAI,GACf,OAAO,IACL,qBACA,qCACF;CAGF,MAAM,UAAU,WAAW,MAAM;CACjC,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/B,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/B,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAG/B,IAAI,CAAC,YAFQ,UAAU,IAEA,IAAI,EAAE,GAC3B,OAAO,IACL,qBACA,8BACF;CAGF,MAAM,SAAS,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CACnC,IAAI,CAAC,eAAe,IAAI,MAAM,GAC5B,OAAO,IACL,qBACA,4BACF;CAGF,MAAM,MAAM,YAAY,EAAE,MAAM,GAAG,EAAE,GAAG,SAAS,EAAE;CAEnD,KADc,QAAQ,KAAK,IAAI,SACjB,OAAO,EAAE,GAAG,GACxB,OAAO,IACL,oBACA,gCACF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B,QAAQ,KAAK;;;;;AAMvD,MAAM,SAAS,UAAyC;CACtD,MAAM,SAAS,SAAS,KAAK;CAC7B,IAAI,CAAC,OAAO,OAAO,OAAO;CAE1B,MAAM,IAAI,OAAO;CACjB,MAAM,IAAI,OAAO,EAAE,EAAE;CACrB,MAAM,UAAU,WAAW,MAAM;CACjC,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/B,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/B,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/B,MAAM,OAAO,UAAU;CAEvB,OAAO;EACL,WAAW,IAAI,KAAK,MAAM,KAAK,GAAG,EAAE;EACpC,QAAQ,IAAI,MAAM,IAAI,SAAS;CACjC;AACF;;AAGA,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,IAAI,OAAO,UAAU,GAAG,CAAC,CAAC;EAChC,MAAM,KAAK,OAAO,UAAU,GAAG,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"cnp.js","names":[],"sources":["../../src/ro/cnp.ts"],"sourcesContent":["/**\n * CNP (Cod Numeric Personal).\n *\n * Romanian personal identification number. 13 digits\n * encoding gender/century, date of birth, county code,\n * serial number, and a check digit.\n *\n * @see https://ro.wikipedia.org/wiki/Cod_numeric_personal\n * @see https://www.cnp.ro/\n */\n\nimport type {\n ParsedPersonId,\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { weightedSum } from \"#checksums/weighted-sum\";\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 WEIGHTS = [\n 2, 7, 9, 1, 4, 6, 3, 5, 8, 2, 7, 9,\n] as const;\n\n// Counties 01-39 are the 39 modern judete; 40-46 are\n// Bucuresti sectors 1-6; 47-48 are the abolished\n// sectors 7-8; 51-52 are Calarasi/Giurgiu; 70 is \"Any\";\n// 80-83 are reserved. 49 and 50 are not allocated.\n// See https://github.com/vimishor/cnp-spec.\nconst VALID_COUNTIES = new Set([\n 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,\n 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,\n 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,\n 46, 47, 48, 51, 52, 70, 80, 81, 82, 83,\n]);\n\nconst centuryMap: Record<number, number> = {\n 1: 1900,\n 2: 1900,\n 3: 1800,\n 4: 1800,\n 5: 2000,\n 6: 2000,\n 7: 1900, // foreign residents\n 8: 1900, // foreign residents\n};\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 \"CNP must be exactly 13 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"CNP must contain only digits\",\n );\n }\n\n const g = Number(v[0]);\n if (g < 1 || g > 9) {\n return err(\n \"INVALID_COMPONENT\",\n \"CNP gender/century digit is invalid\",\n );\n }\n\n const century = centuryMap[g] ?? 1900;\n const yy = Number(v.slice(1, 3));\n const mm = Number(v.slice(3, 5));\n const dd = Number(v.slice(5, 7));\n const year = century + yy;\n\n if (!isValidDate(year, mm, dd)) {\n return err(\n \"INVALID_COMPONENT\",\n \"CNP contains an invalid date\",\n );\n }\n\n const county = Number(v.slice(7, 9));\n if (!VALID_COUNTIES.has(county)) {\n return err(\n \"INVALID_COMPONENT\",\n \"CNP county code is invalid\",\n );\n }\n\n const sum = weightedSum(v.slice(0, 12), WEIGHTS, 11);\n const check = sum === 10 ? 1 : sum;\n if (check !== Number(v[12])) {\n return err(\n \"INVALID_CHECKSUM\",\n \"CNP check digit 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 CNP.\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 g = Number(v[0]);\n const century = centuryMap[g] ?? 1900;\n const yy = Number(v.slice(1, 3));\n const mm = Number(v.slice(3, 5));\n const dd = Number(v.slice(5, 7));\n const year = century + yy;\n\n return {\n birthDate: new Date(year, mm - 1, dd),\n gender: g % 2 === 1 ? \"male\" : \"female\",\n };\n};\n\n/** Generate a random valid Romanian CNP. */\nconst generate = (): string => {\n for (;;) {\n const g = String(randomInt(1, 6));\n const yy = String(randomInt(0, 99)).padStart(2, \"0\");\n const mm = String(randomInt(1, 12)).padStart(2, \"0\");\n const dd = String(randomInt(1, 28)).padStart(2, \"0\");\n const county = String(randomInt(1, 52)).padStart(\n 2,\n \"0\",\n );\n const serial = String(randomInt(1, 999)).padStart(\n 3,\n \"0\",\n );\n const payload = g + yy + mm + dd + county + serial;\n const sum = weightedSum(payload, WEIGHTS, 11);\n const c = payload + String(sum === 10 ? 1 : sum);\n if (validate(c).valid) return c;\n }\n};\n\n/** Romanian Personal Identification Number. */\nconst cnp: CountryValidator<\"RO\", ParsedPersonId> = {\n name: \"Romanian Personal ID\",\n localName: \"Cod Numeric Personal\",\n abbreviation: \"CNP\",\n aliases: [\"CNP\", \"cod numeric personal\"] as const,\n candidatePattern:\n \"[1-8]\\\\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\\\\d|3[01])\\\\d{6}\",\n scope: \"country\",\n country: \"RO\",\n entityType: \"person\",\n sourceUrl: \"https://www.cnp.ro/\",\n lengths: [13] as const,\n examples: [\"1630615123457\"] as const,\n compact,\n format,\n parse,\n validate,\n generate,\n};\n\nexport default cnp;\nexport { compact, format, parse, validate, generate };\n"],"mappings":"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"}
|
package/dist/ro/vat.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vat.js","names":[],"sources":["../../src/ro/vat.ts"],"sourcesContent":["/**\n * CIF/CUI (Romanian VAT number).\n *\n * 2-10 digits. Pad to 10, weights\n * [7,5,3,2,1,7,5,3,2], check =\n * (10 * sum) % 11 % 10 === last digit.\n *\n * @see https://www.vatify.eu/romania-vat-number.html\n * @see https://www.anaf.ro/\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, randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst WEIGHTS = [7, 5, 3, 2, 1, 7, 5, 3, 2];\n\nconst compact = (value: string): string => {\n let v = clean(value, \" -/.\");\n if (v.startsWith(\"RO\") || v.startsWith(\"ro\")) {\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 < 2 || v.length > 10) {\n return err(\n \"INVALID_LENGTH\",\n \"Romanian VAT number must be 2 to 10 digits\",\n );\n }\n if (!isdigits(v) || v[0] === \"0\") {\n return err(\n \"INVALID_FORMAT\",\n \"Romanian VAT number must contain only digits \" +\n \"and must not start with 0\",\n );\n }\n // Pad to 10 digits\n const padded = v.padStart(10, \"0\");\n const sum = weightedSum(padded.slice(0, 9), WEIGHTS, 11);\n const check = ((sum * 10) % 11) % 10;\n if (check !== Number(padded[9])) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Romanian VAT number check digit mismatch\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string =>\n `RO${compact(value)}`;\n\n/** Generate a random valid Romanian VAT number. */\nconst generate = (): string => {\n for (;;) {\n const c =\n String(randomInt(1, 9)) +\n randomDigits(randomInt(1, 9));\n if (validate(c).valid) return c;\n }\n};\n\n/** Romanian VAT Number. */\nconst vat: CountryValidator<\"RO\"> = {\n name: \"Romanian VAT Number\",\n localName: \"Cod de Identificare Fiscală\",\n abbreviation: \"CIF\",\n aliases: [\n \"CUI\",\n \"CIF\",\n \"cod de identificare fiscală\",\n \"cod fiscal\",\n ] as const,\n candidatePattern: \"RO\\\\d{2,10}\",\n scope: \"country\",\n country: \"RO\",\n entityType: \"any\",\n sourceUrl: \"https://www.anaf.ro/\",\n lengths: [2, 3, 4, 5, 6, 7, 8, 9, 10] as const,\n examples: [\"18547290\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default vat;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;AAsBA,MAAM,UAAU;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AAE1C,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,SAAS,KAAK,EAAE,SAAS,IAC7B,OAAO,IACL,kBACA,4CACF;CAEF,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,KAC3B,OAAO,IACL,kBACA,wEAEF;CAGF,MAAM,SAAS,EAAE,SAAS,IAAI,GAAG;CAGjC,IAFY,YAAY,OAAO,MAAM,GAAG,CAAC,GAAG,SAAS,EACnC,IAAI,KAAM,KAAM,OACpB,OAAO,OAAO,EAAE,GAC5B,OAAO,IACL,oBACA,0CACF;CAEF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UACd,KAAK,QAAQ,KAAK;;AAGpB,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,IACJ,OAAO,UAAU,GAAG,CAAC,CAAC,IACtB,aAAa,UAAU,GAAG,CAAC,CAAC;EAC9B,IAAI,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"vat.js","names":[],"sources":["../../src/ro/vat.ts"],"sourcesContent":["/**\n * CIF/CUI (Romanian VAT number).\n *\n * 2-10 digits. Pad to 10, weights\n * [7,5,3,2,1,7,5,3,2], check =\n * (10 * sum) % 11 % 10 === last digit.\n *\n * @see https://www.vatify.eu/romania-vat-number.html\n * @see https://www.anaf.ro/\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, randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst WEIGHTS = [7, 5, 3, 2, 1, 7, 5, 3, 2];\n\nconst compact = (value: string): string => {\n let v = clean(value, \" -/.\");\n if (v.startsWith(\"RO\") || v.startsWith(\"ro\")) {\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 < 2 || v.length > 10) {\n return err(\n \"INVALID_LENGTH\",\n \"Romanian VAT number must be 2 to 10 digits\",\n );\n }\n if (!isdigits(v) || v[0] === \"0\") {\n return err(\n \"INVALID_FORMAT\",\n \"Romanian VAT number must contain only digits \" +\n \"and must not start with 0\",\n );\n }\n // Pad to 10 digits\n const padded = v.padStart(10, \"0\");\n const sum = weightedSum(padded.slice(0, 9), WEIGHTS, 11);\n const check = ((sum * 10) % 11) % 10;\n if (check !== Number(padded[9])) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Romanian VAT number check digit mismatch\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string =>\n `RO${compact(value)}`;\n\n/** Generate a random valid Romanian VAT number. */\nconst generate = (): string => {\n for (;;) {\n const c =\n String(randomInt(1, 9)) +\n randomDigits(randomInt(1, 9));\n if (validate(c).valid) return c;\n }\n};\n\n/** Romanian VAT Number. */\nconst vat: CountryValidator<\"RO\"> = {\n name: \"Romanian VAT Number\",\n localName: \"Cod de Identificare Fiscală\",\n abbreviation: \"CIF\",\n aliases: [\n \"CUI\",\n \"CIF\",\n \"cod de identificare fiscală\",\n \"cod fiscal\",\n ] as const,\n candidatePattern: \"RO\\\\d{2,10}\",\n scope: \"country\",\n country: \"RO\",\n entityType: \"any\",\n sourceUrl: \"https://www.anaf.ro/\",\n lengths: [2, 3, 4, 5, 6, 7, 8, 9, 10] as const,\n examples: [\"18547290\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default vat;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;AAsBA,MAAM,UAAU;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AAE1C,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,SAAS,KAAK,EAAE,SAAS,IAC7B,OAAO,IACL,kBACA,4CACF;CAEF,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,KAC3B,OAAO,IACL,kBACA,wEAEF;CAGF,MAAM,SAAS,EAAE,SAAS,IAAI,GAAG;CAGjC,IAFY,YAAY,OAAO,MAAM,GAAG,CAAC,GAAG,SAAS,EACnC,IAAI,KAAM,KAAM,OACpB,OAAO,OAAO,EAAE,GAC5B,OAAO,IACL,oBACA,0CACF;CAEF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UACd,KAAK,QAAQ,KAAK;;AAGpB,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,IACJ,OAAO,UAAU,GAAG,CAAC,CAAC,IACtB,aAAa,UAAU,GAAG,CAAC,CAAC;EAC9B,IAAI,SAAS,CAAC,CAAC,CAAC,OAAO,OAAO;CAChC;AACF;;AAGA,MAAM,MAA8B;CAClC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS;EACP;EACA;EACA;EACA;CACF;CACA,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,WAAW;CACX,SAAS;EAAC;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;CAAE;CACpC,UAAU,CAAC,UAAU;CACrB;CACA;CACA;CACA;AACF"}
|
package/dist/rs/pib.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pib.js","names":[],"sources":["../../src/rs/pib.ts"],"sourcesContent":["/**\n * PIB (Poreski identifikacioni broj).\n *\n * Serbian tax identification number. 9 digits with\n * a mod 11 checksum (ISO 7064 variant).\n *\n * @see https://en.wikipedia.org/wiki/Tax_identification_number_(Serbia)\n * @see https://www.purs.gov.rs/\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 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 \"PIB must be exactly 9 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"PIB must contain only digits\",\n );\n }\n\n // ISO 7064 Mod 11, 10 checksum\n let t = 10;\n for (let i = 0; i < 8; i++) {\n t = (t + Number(v[i])) % 10;\n if (t === 0) t = 10;\n t = (t * 2) % 11;\n }\n const check = (11 - t) % 10;\n if (check !== Number(v[8])) {\n return err(\n \"INVALID_CHECKSUM\",\n \"PIB check digit mismatch\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => compact(value);\n\n/** Generate a random valid Serbian PIB. */\nconst generate = (): string => {\n for (;;) {\n const c = randomDigits(9);\n if (validate(c).valid) return c;\n }\n};\n\n/** Serbian Tax Identification Number. */\nconst pib: CountryValidator<\"RS\"> = {\n name: \"Serbian Tax ID\",\n localName: \"Poreski identifikacioni broj\",\n abbreviation: \"PIB\",\n aliases: [\"PIB\", \"poreski identifikacioni broj\"] as const,\n candidatePattern: \"\\\\d{9}\",\n scope: \"country\",\n country: \"RS\",\n entityType: \"any\",\n lengths: [9] as const,\n sourceUrl: \"https://www.purs.gov.rs/\",\n examples: [\"101134702\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default pib;\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,GACf,OAAO,IACL,kBACA,8BACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,8BACF;CAIF,IAAI,IAAI;CACR,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;EAC1B,KAAK,IAAI,OAAO,EAAE,EAAE,KAAK;EACzB,IAAI,MAAM,GAAG,IAAI;EACjB,IAAK,IAAI,IAAK;CAChB;CAEA,KADe,KAAK,KAAK,OACX,OAAO,EAAE,EAAE,GACvB,OAAO,IACL,oBACA,0BACF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B,QAAQ,KAAK;;AAGvD,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,IAAI,aAAa,CAAC;EACxB,IAAI,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"pib.js","names":[],"sources":["../../src/rs/pib.ts"],"sourcesContent":["/**\n * PIB (Poreski identifikacioni broj).\n *\n * Serbian tax identification number. 9 digits with\n * a mod 11 checksum (ISO 7064 variant).\n *\n * @see https://en.wikipedia.org/wiki/Tax_identification_number_(Serbia)\n * @see https://www.purs.gov.rs/\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 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 \"PIB must be exactly 9 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"PIB must contain only digits\",\n );\n }\n\n // ISO 7064 Mod 11, 10 checksum\n let t = 10;\n for (let i = 0; i < 8; i++) {\n t = (t + Number(v[i])) % 10;\n if (t === 0) t = 10;\n t = (t * 2) % 11;\n }\n const check = (11 - t) % 10;\n if (check !== Number(v[8])) {\n return err(\n \"INVALID_CHECKSUM\",\n \"PIB check digit mismatch\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => compact(value);\n\n/** Generate a random valid Serbian PIB. */\nconst generate = (): string => {\n for (;;) {\n const c = randomDigits(9);\n if (validate(c).valid) return c;\n }\n};\n\n/** Serbian Tax Identification Number. */\nconst pib: CountryValidator<\"RS\"> = {\n name: \"Serbian Tax ID\",\n localName: \"Poreski identifikacioni broj\",\n abbreviation: \"PIB\",\n aliases: [\"PIB\", \"poreski identifikacioni broj\"] as const,\n candidatePattern: \"\\\\d{9}\",\n scope: \"country\",\n country: \"RS\",\n entityType: \"any\",\n lengths: [9] as const,\n sourceUrl: \"https://www.purs.gov.rs/\",\n examples: [\"101134702\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default pib;\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,GACf,OAAO,IACL,kBACA,8BACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,8BACF;CAIF,IAAI,IAAI;CACR,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;EAC1B,KAAK,IAAI,OAAO,EAAE,EAAE,KAAK;EACzB,IAAI,MAAM,GAAG,IAAI;EACjB,IAAK,IAAI,IAAK;CAChB;CAEA,KADe,KAAK,KAAK,OACX,OAAO,EAAE,EAAE,GACvB,OAAO,IACL,oBACA,0BACF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B,QAAQ,KAAK;;AAGvD,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,IAAI,aAAa,CAAC;EACxB,IAAI,SAAS,CAAC,CAAC,CAAC,OAAO,OAAO;CAChC;AACF;;AAGA,MAAM,MAA8B;CAClC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,OAAO,8BAA8B;CAC/C,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,SAAS,CAAC,CAAC;CACX,WAAW;CACX,UAAU,CAAC,WAAW;CACtB;CACA;CACA;CACA;AACF"}
|
package/dist/ru/inn.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inn.js","names":[],"sources":["../../src/ru/inn.ts"],"sourcesContent":["/**\n * INN (Идентификационный номер налогоплательщика).\n *\n * Russian taxpayer identification number. 10 digits\n * for companies (1 check digit), 12 digits for\n * individuals (2 check digits). Check digits are\n * computed as weighted sum mod 11 mod 10.\n *\n * @see https://en.wikipedia.org/wiki/Taxpayer_Identification_Number_(Russia)\n * @see https://www.nalog.gov.ru/\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst WEIGHTS_10 = [2, 4, 10, 3, 5, 9, 4, 6, 8] as const;\nconst WEIGHTS_11 = [7, 2, 4, 10, 3, 5, 9, 4, 6, 8] as const;\nconst WEIGHTS_12 = [\n 3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8,\n] as const;\n\nconst checkDigit = (\n value: string,\n weights: readonly number[],\n): number => {\n let sum = 0;\n for (const [i, weight] of weights.entries()) {\n sum += Number(value[i]) * weight;\n }\n return (sum % 11) % 10;\n};\n\nconst compact = (value: string): string =>\n clean(value, \" -\");\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 10 && v.length !== 12) {\n return err(\n \"INVALID_LENGTH\",\n \"INN must be 10 or 12 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"INN must contain only digits\",\n );\n }\n\n if (v.length === 10) {\n const check = checkDigit(v, WEIGHTS_10);\n if (check !== Number(v[9])) {\n return err(\n \"INVALID_CHECKSUM\",\n \"INN check digit mismatch\",\n );\n }\n } else {\n const check11 = checkDigit(v, WEIGHTS_11);\n const check12 = checkDigit(v, WEIGHTS_12);\n if (\n check11 !== Number(v[10]) ||\n check12 !== Number(v[11])\n ) {\n return err(\n \"INVALID_CHECKSUM\",\n \"INN check digit mismatch\",\n );\n }\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => compact(value);\n\n/** Generate a random valid 10-digit Russian INN. */\nconst generate = (): string => {\n for (;;) {\n const c = randomDigits(10);\n if (validate(c).valid) return c;\n }\n};\n\n/** Russian Taxpayer Identification Number. */\nconst inn: CountryValidator<\"RU\"> = {\n name: \"Russian Tax ID\",\n localName: \"Идентификационный номер налогоплательщика\",\n abbreviation: \"ИНН\",\n aliases: [\"ИНН\", \"INN\"] as const,\n candidatePattern: \"\\\\d{10,12}\",\n scope: \"country\",\n country: \"RU\",\n entityType: \"any\",\n lengths: [10, 12] as const,\n sourceUrl: \"https://www.nalog.gov.ru/\",\n examples: [\"7707083893\", \"526317984689\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default inn;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;AAsBA,MAAM,aAAa;CAAC;CAAG;CAAG;CAAI;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AAC9C,MAAM,aAAa;CAAC;CAAG;CAAG;CAAG;CAAI;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AACjD,MAAM,aAAa;CACjB;CAAG;CAAG;CAAG;CAAG;CAAI;CAAG;CAAG;CAAG;CAAG;CAAG;AACjC;AAEA,MAAM,cACJ,OACA,YACW;CACX,IAAI,MAAM;CACV,KAAK,MAAM,CAAC,GAAG,WAAW,QAAQ,QAAQ,GACxC,OAAO,OAAO,MAAM,EAAE,IAAI;CAE5B,OAAQ,MAAM,KAAM;AACtB;AAEA,MAAM,WAAW,UACf,MAAM,OAAO,IAAI;AAEnB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,MAAM,EAAE,WAAW,IAClC,OAAO,IACL,kBACA,6BACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,8BACF;CAGF,IAAI,EAAE,WAAW;MACD,WAAW,GAAG,UACpB,MAAM,OAAO,EAAE,EAAE,GACvB,OAAO,IACL,oBACA,0BACF;CAAA,OAEG;EACL,MAAM,UAAU,WAAW,GAAG,UAAU;EACxC,MAAM,UAAU,WAAW,GAAG,UAAU;EACxC,IACE,YAAY,OAAO,EAAE,GAAG,KACxB,YAAY,OAAO,EAAE,GAAG,GAExB,OAAO,IACL,oBACA,0BACF;CAEJ;CAEA,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B,QAAQ,KAAK;;AAGvD,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,IAAI,aAAa,EAAE;EACzB,IAAI,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"inn.js","names":[],"sources":["../../src/ru/inn.ts"],"sourcesContent":["/**\n * INN (Идентификационный номер налогоплательщика).\n *\n * Russian taxpayer identification number. 10 digits\n * for companies (1 check digit), 12 digits for\n * individuals (2 check digits). Check digits are\n * computed as weighted sum mod 11 mod 10.\n *\n * @see https://en.wikipedia.org/wiki/Taxpayer_Identification_Number_(Russia)\n * @see https://www.nalog.gov.ru/\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst WEIGHTS_10 = [2, 4, 10, 3, 5, 9, 4, 6, 8] as const;\nconst WEIGHTS_11 = [7, 2, 4, 10, 3, 5, 9, 4, 6, 8] as const;\nconst WEIGHTS_12 = [\n 3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8,\n] as const;\n\nconst checkDigit = (\n value: string,\n weights: readonly number[],\n): number => {\n let sum = 0;\n for (const [i, weight] of weights.entries()) {\n sum += Number(value[i]) * weight;\n }\n return (sum % 11) % 10;\n};\n\nconst compact = (value: string): string =>\n clean(value, \" -\");\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 10 && v.length !== 12) {\n return err(\n \"INVALID_LENGTH\",\n \"INN must be 10 or 12 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"INN must contain only digits\",\n );\n }\n\n if (v.length === 10) {\n const check = checkDigit(v, WEIGHTS_10);\n if (check !== Number(v[9])) {\n return err(\n \"INVALID_CHECKSUM\",\n \"INN check digit mismatch\",\n );\n }\n } else {\n const check11 = checkDigit(v, WEIGHTS_11);\n const check12 = checkDigit(v, WEIGHTS_12);\n if (\n check11 !== Number(v[10]) ||\n check12 !== Number(v[11])\n ) {\n return err(\n \"INVALID_CHECKSUM\",\n \"INN check digit mismatch\",\n );\n }\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => compact(value);\n\n/** Generate a random valid 10-digit Russian INN. */\nconst generate = (): string => {\n for (;;) {\n const c = randomDigits(10);\n if (validate(c).valid) return c;\n }\n};\n\n/** Russian Taxpayer Identification Number. */\nconst inn: CountryValidator<\"RU\"> = {\n name: \"Russian Tax ID\",\n localName: \"Идентификационный номер налогоплательщика\",\n abbreviation: \"ИНН\",\n aliases: [\"ИНН\", \"INN\"] as const,\n candidatePattern: \"\\\\d{10,12}\",\n scope: \"country\",\n country: \"RU\",\n entityType: \"any\",\n lengths: [10, 12] as const,\n sourceUrl: \"https://www.nalog.gov.ru/\",\n examples: [\"7707083893\", \"526317984689\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default inn;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;AAsBA,MAAM,aAAa;CAAC;CAAG;CAAG;CAAI;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AAC9C,MAAM,aAAa;CAAC;CAAG;CAAG;CAAG;CAAI;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AACjD,MAAM,aAAa;CACjB;CAAG;CAAG;CAAG;CAAG;CAAI;CAAG;CAAG;CAAG;CAAG;CAAG;AACjC;AAEA,MAAM,cACJ,OACA,YACW;CACX,IAAI,MAAM;CACV,KAAK,MAAM,CAAC,GAAG,WAAW,QAAQ,QAAQ,GACxC,OAAO,OAAO,MAAM,EAAE,IAAI;CAE5B,OAAQ,MAAM,KAAM;AACtB;AAEA,MAAM,WAAW,UACf,MAAM,OAAO,IAAI;AAEnB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,MAAM,EAAE,WAAW,IAClC,OAAO,IACL,kBACA,6BACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,8BACF;CAGF,IAAI,EAAE,WAAW;MACD,WAAW,GAAG,UACpB,MAAM,OAAO,EAAE,EAAE,GACvB,OAAO,IACL,oBACA,0BACF;CAAA,OAEG;EACL,MAAM,UAAU,WAAW,GAAG,UAAU;EACxC,MAAM,UAAU,WAAW,GAAG,UAAU;EACxC,IACE,YAAY,OAAO,EAAE,GAAG,KACxB,YAAY,OAAO,EAAE,GAAG,GAExB,OAAO,IACL,oBACA,0BACF;CAEJ;CAEA,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B,QAAQ,KAAK;;AAGvD,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,IAAI,aAAa,EAAE;EACzB,IAAI,SAAS,CAAC,CAAC,CAAC,OAAO,OAAO;CAChC;AACF;;AAGA,MAAM,MAA8B;CAClC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,OAAO,KAAK;CACtB,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,SAAS,CAAC,IAAI,EAAE;CAChB,WAAW;CACX,UAAU,CAAC,cAAc,cAAc;CACvC;CACA;CACA;CACA;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"personnummer.js","names":[],"sources":["../../src/se/personnummer.ts"],"sourcesContent":["/**\n * Personnummer (Personal Identity Number).\n *\n * Swedish personal identification number. 10 digits\n * in compact form (YYMMDDNNNC) with a Luhn checksum\n * on all 10 digits.\n *\n * @see https://www.skatteverket.se/privat/folkbokforing/personnummer.4.3810a01c150939e893f18c29.html\n */\n\nimport type {\n ParsedPersonId,\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport {\n luhnValidate,\n luhnChecksum,\n} from \"#checksums/luhn\";\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\n/**\n * Match python-stdnum's compact: preserve the '-' or '+'\n * separator at position -5, and strip any others.\n */\nconst compact = (value: string): string => {\n let v = clean(value, \" :\");\n if (\n (v.length === 10 || v.length === 12) &&\n v.at(-5) !== \"-\" &&\n v.at(-5) !== \"+\"\n ) {\n v = `${v.slice(0, -4)}-${v.slice(-4)}`;\n }\n const prefix = v\n .slice(0, -5)\n .replace(/-/g, \"\")\n .replace(/\\+/g, \"\");\n return `${prefix}${v.slice(-5)}`;\n};\n\n/**\n * Extract the birth date from the compacted number.\n * Matches python-stdnum's get_birth_date.\n */\nconst getBirthDate = (\n v: string,\n): { year: number; month: number; day: number } | null => {\n let year: number;\n let month: number;\n let day: number;\n\n if (v.length === 13) {\n year = Number(v.slice(0, 4));\n month = Number(v.slice(4, 6));\n day = Number(v.slice(6, 8));\n } else {\n const currentYear = new Date().getFullYear();\n let century = Math.floor(currentYear / 100);\n const yy = Number(v.slice(0, 2));\n if (yy > currentYear % 100) century -= 1;\n if (v.at(-5) === \"+\") century -= 1;\n year = century * 100 + yy;\n month = Number(v.slice(2, 4));\n day = Number(v.slice(4, 6));\n }\n\n if (!isValidDate(year, month, day)) return null;\n return { year, month, day };\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 11 && v.length !== 13) {\n return err(\n \"INVALID_LENGTH\",\n \"Personnummer must be 10 or 12 digits\",\n );\n }\n\n const digits = v.slice(0, -5) + v.slice(-4);\n const sep = v.at(-5);\n if ((sep !== \"-\" && sep !== \"+\") || !isdigits(digits)) {\n return err(\n \"INVALID_FORMAT\",\n \"Personnummer has invalid format\",\n );\n }\n\n if (getBirthDate(v) === null) {\n return err(\n \"INVALID_COMPONENT\",\n \"Personnummer contains an invalid date\",\n );\n }\n\n if (!luhnValidate(digits.slice(-10))) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Personnummer Luhn check 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 Personnummer.\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 birthDate = getBirthDate(v);\n if (birthDate === null) return null;\n\n const genderDigit = Number(v.at(-2));\n\n return {\n birthDate: new Date(\n birthDate.year,\n birthDate.month - 1,\n birthDate.day,\n ),\n gender: genderDigit % 2 === 0 ? \"female\" : \"male\",\n };\n};\n\n/** Generate a random valid Swedish personnummer. */\nconst generate = (): string => {\n for (;;) {\n const yy = String(randomInt(50, 99)).padStart(2, \"0\");\n const mm = String(randomInt(1, 12)).padStart(2, \"0\");\n const dd = String(randomInt(1, 28)).padStart(2, \"0\");\n const serial = String(randomInt(0, 999)).padStart(\n 3,\n \"0\",\n );\n const payload = yy + mm + dd + serial;\n const cs = luhnChecksum(payload + \"0\");\n const c = payload + String((10 - cs) % 10);\n const result = validate(c);\n if (result.valid) return result.compact;\n }\n};\n\n/** Swedish Personal Identity Number. */\nconst personnummer: CountryValidator<\"SE\", ParsedPersonId> =\n {\n name: \"Swedish Personal ID\",\n localName: \"Personnummer\",\n abbreviation: \"PN\",\n aliases: [\n \"personnummer\",\n \"personnr\",\n \"pers.nr\",\n \"personal identity number\",\n ] as const,\n candidatePattern: \"\\\\d{6,8}-\\\\d{4}\",\n scope: \"country\",\n country: \"SE\",\n entityType: \"person\",\n sourceUrl:\n \"https://www.skatteverket.se/privat/folkbokforing/personnummer.4.3810a01c150939e893f18c29.html\",\n examples: [\"880320-0016\"] as const,\n compact,\n format,\n parse,\n validate,\n generate,\n };\n\nexport default personnummer;\nexport { compact, format, parse, validate, generate };\n"],"mappings":";;;;;;;;;;;AA8BA,MAAM,WAAW,UAA0B;CACzC,IAAI,IAAI,MAAM,OAAO,IAAI;CACzB,KACG,EAAE,WAAW,MAAM,EAAE,WAAW,OACjC,EAAE,GAAG,EAAE,MAAM,OACb,EAAE,GAAG,EAAE,MAAM,KAEb,IAAI,GAAG,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE;CAMrC,OAAO,GAJQ,EACZ,MAAM,GAAG,EAAE,
|
|
1
|
+
{"version":3,"file":"personnummer.js","names":[],"sources":["../../src/se/personnummer.ts"],"sourcesContent":["/**\n * Personnummer (Personal Identity Number).\n *\n * Swedish personal identification number. 10 digits\n * in compact form (YYMMDDNNNC) with a Luhn checksum\n * on all 10 digits.\n *\n * @see https://www.skatteverket.se/privat/folkbokforing/personnummer.4.3810a01c150939e893f18c29.html\n */\n\nimport type {\n ParsedPersonId,\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport {\n luhnValidate,\n luhnChecksum,\n} from \"#checksums/luhn\";\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\n/**\n * Match python-stdnum's compact: preserve the '-' or '+'\n * separator at position -5, and strip any others.\n */\nconst compact = (value: string): string => {\n let v = clean(value, \" :\");\n if (\n (v.length === 10 || v.length === 12) &&\n v.at(-5) !== \"-\" &&\n v.at(-5) !== \"+\"\n ) {\n v = `${v.slice(0, -4)}-${v.slice(-4)}`;\n }\n const prefix = v\n .slice(0, -5)\n .replace(/-/g, \"\")\n .replace(/\\+/g, \"\");\n return `${prefix}${v.slice(-5)}`;\n};\n\n/**\n * Extract the birth date from the compacted number.\n * Matches python-stdnum's get_birth_date.\n */\nconst getBirthDate = (\n v: string,\n): { year: number; month: number; day: number } | null => {\n let year: number;\n let month: number;\n let day: number;\n\n if (v.length === 13) {\n year = Number(v.slice(0, 4));\n month = Number(v.slice(4, 6));\n day = Number(v.slice(6, 8));\n } else {\n const currentYear = new Date().getFullYear();\n let century = Math.floor(currentYear / 100);\n const yy = Number(v.slice(0, 2));\n if (yy > currentYear % 100) century -= 1;\n if (v.at(-5) === \"+\") century -= 1;\n year = century * 100 + yy;\n month = Number(v.slice(2, 4));\n day = Number(v.slice(4, 6));\n }\n\n if (!isValidDate(year, month, day)) return null;\n return { year, month, day };\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 11 && v.length !== 13) {\n return err(\n \"INVALID_LENGTH\",\n \"Personnummer must be 10 or 12 digits\",\n );\n }\n\n const digits = v.slice(0, -5) + v.slice(-4);\n const sep = v.at(-5);\n if ((sep !== \"-\" && sep !== \"+\") || !isdigits(digits)) {\n return err(\n \"INVALID_FORMAT\",\n \"Personnummer has invalid format\",\n );\n }\n\n if (getBirthDate(v) === null) {\n return err(\n \"INVALID_COMPONENT\",\n \"Personnummer contains an invalid date\",\n );\n }\n\n if (!luhnValidate(digits.slice(-10))) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Personnummer Luhn check 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 Personnummer.\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 birthDate = getBirthDate(v);\n if (birthDate === null) return null;\n\n const genderDigit = Number(v.at(-2));\n\n return {\n birthDate: new Date(\n birthDate.year,\n birthDate.month - 1,\n birthDate.day,\n ),\n gender: genderDigit % 2 === 0 ? \"female\" : \"male\",\n };\n};\n\n/** Generate a random valid Swedish personnummer. */\nconst generate = (): string => {\n for (;;) {\n const yy = String(randomInt(50, 99)).padStart(2, \"0\");\n const mm = String(randomInt(1, 12)).padStart(2, \"0\");\n const dd = String(randomInt(1, 28)).padStart(2, \"0\");\n const serial = String(randomInt(0, 999)).padStart(\n 3,\n \"0\",\n );\n const payload = yy + mm + dd + serial;\n const cs = luhnChecksum(payload + \"0\");\n const c = payload + String((10 - cs) % 10);\n const result = validate(c);\n if (result.valid) return result.compact;\n }\n};\n\n/** Swedish Personal Identity Number. */\nconst personnummer: CountryValidator<\"SE\", ParsedPersonId> =\n {\n name: \"Swedish Personal ID\",\n localName: \"Personnummer\",\n abbreviation: \"PN\",\n aliases: [\n \"personnummer\",\n \"personnr\",\n \"pers.nr\",\n \"personal identity number\",\n ] as const,\n candidatePattern: \"\\\\d{6,8}-\\\\d{4}\",\n scope: \"country\",\n country: \"SE\",\n entityType: \"person\",\n sourceUrl:\n \"https://www.skatteverket.se/privat/folkbokforing/personnummer.4.3810a01c150939e893f18c29.html\",\n examples: [\"880320-0016\"] as const,\n compact,\n format,\n parse,\n validate,\n generate,\n };\n\nexport default personnummer;\nexport { compact, format, parse, validate, generate };\n"],"mappings":"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"}
|
package/dist/sg/uen.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uen.js","names":[],"sources":["../../src/sg/uen.ts"],"sourcesContent":["/**\n * UEN (Singapore Unique Entity Number).\n *\n * 9 or 10 characters identifying businesses and\n * entities registered in Singapore. Three formats:\n *\n * - Business (ROB): 8 digits + 1 check letter\n * - Local company (ROC): 4-digit year + 5 digits\n * + 1 check letter\n * - Other entities: R/S/T + 2-digit year + 2-letter\n * entity type + 4 digits + 1 check letter\n *\n * @see https://www.uen.gov.sg/\n * @see https://www.oecd.org/tax/automatic-exchange/crs-implementation-and-assistance/tax-identification-numbers/Singapore-TIN.pdf\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\n/** Check letter alphabet for \"Other\" format. */\nconst OTHER_ALPHA = \"ABCDEFGHJKLMNPQRSTUVWX0123456789\";\n\nconst ENTITY_TYPES = new Set([\n \"CC\",\n \"CD\",\n \"CH\",\n \"CL\",\n \"CM\",\n \"CP\",\n \"CS\",\n \"CX\",\n \"DP\",\n \"FB\",\n \"FC\",\n \"FM\",\n \"FN\",\n \"GA\",\n \"GB\",\n \"GS\",\n \"HS\",\n \"LL\",\n \"LP\",\n \"MB\",\n \"MC\",\n \"MD\",\n \"MH\",\n \"MM\",\n \"MQ\",\n \"NB\",\n \"NR\",\n \"PA\",\n \"PB\",\n \"PF\",\n \"RF\",\n \"RP\",\n \"SM\",\n \"SS\",\n \"TC\",\n \"TU\",\n \"VH\",\n \"XL\",\n]);\n\nconst compact = (value: string): string =>\n clean(value, \" -\").toUpperCase();\n\n/**\n * Validate Business (ROB) UEN (9 chars):\n * 8 digits + 1 check letter.\n */\nconst BUSINESS_WEIGHTS = [10, 4, 9, 3, 8, 2, 7, 1] as const;\nconst BUSINESS_CHECK_ALPHA = \"XMKECAWLJDB\";\n\nconst validateBusiness = (v: string): ValidateResult => {\n if (!isdigits(v.slice(0, 8))) {\n return err(\n \"INVALID_FORMAT\",\n \"Business UEN must start with 8 digits\",\n );\n }\n // SAFETY: caller routes to this only when\n // v.length === 9.\n // eslint-disable-next-line no-non-null-assertion\n if (!/^[A-Z]$/.test(v[8]!)) {\n return err(\n \"INVALID_FORMAT\",\n \"Business UEN must end with a letter\",\n );\n }\n\n let sum = 0;\n for (const [i, weight] of BUSINESS_WEIGHTS.entries()) {\n sum += Number(v[i]) * weight;\n }\n const expected = BUSINESS_CHECK_ALPHA[sum % 11];\n if (v[8] !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"UEN check letter does not match\",\n );\n }\n return { valid: true, compact: v };\n};\n\n/**\n * Validate Local Company (ROC) UEN (10 chars):\n * 9 digits (year prefix) + 1 check letter.\n */\nconst LOCAL_WEIGHTS = [10, 8, 6, 4, 9, 7, 5, 3, 1] as const;\nconst LOCAL_CHECK_ALPHA = \"ZKCMDNERGWH\";\n\nconst validateLocalCompany = (\n v: string,\n): ValidateResult => {\n if (!isdigits(v.slice(0, 9))) {\n return err(\n \"INVALID_FORMAT\",\n \"Company UEN must have 9 digits\",\n );\n }\n // SAFETY: caller routes to this only when\n // v.length === 10.\n // eslint-disable-next-line no-non-null-assertion\n if (!/^[A-Z]$/.test(v[9]!)) {\n return err(\n \"INVALID_FORMAT\",\n \"Company UEN must end with a letter\",\n );\n }\n\n let sum = 0;\n for (const [i, weight] of LOCAL_WEIGHTS.entries()) {\n sum += Number(v[i]) * weight;\n }\n const expected = LOCAL_CHECK_ALPHA[sum % 11];\n if (v[9] !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"UEN check letter does not match\",\n );\n }\n return { valid: true, compact: v };\n};\n\n/**\n * Validate Other entity UEN (10 chars):\n * R/S/T + 2 digits + 2-letter type + 4 digits\n * + 1 check letter.\n */\nconst OTHER_WEIGHTS = [4, 3, 5, 3, 10, 2, 2, 5, 7] as const;\n\nconst validateOther = (v: string): ValidateResult => {\n // SAFETY: caller routes to this only when\n // v.length === 10.\n // eslint-disable-next-line no-non-null-assertion\n const prefix = v[0]!;\n if (prefix !== \"R\" && prefix !== \"S\" && prefix !== \"T\") {\n return err(\n \"INVALID_COMPONENT\",\n \"Other UEN must start with R, S, or T\",\n );\n }\n if (!isdigits(v.slice(1, 3))) {\n return err(\n \"INVALID_FORMAT\",\n \"Other UEN positions 2-3 must be digits\",\n );\n }\n const entityType = v.slice(3, 5);\n if (!ENTITY_TYPES.has(entityType)) {\n return err(\n \"INVALID_COMPONENT\",\n \"Unknown entity type: \" + entityType,\n );\n }\n if (!isdigits(v.slice(5, 9))) {\n return err(\n \"INVALID_FORMAT\",\n \"Other UEN positions 6-9 must be digits\",\n );\n }\n\n let sum = 0;\n for (const [i, weight] of OTHER_WEIGHTS.entries()) {\n const ch = v[i];\n if (ch === undefined) continue;\n const idx = OTHER_ALPHA.indexOf(ch);\n if (idx === -1) {\n return err(\n \"INVALID_FORMAT\",\n `Unexpected character at position ${i + 1}: ${ch}`,\n );\n }\n sum += idx * weight;\n }\n const expected =\n OTHER_ALPHA[(((sum - 5) % 11) + 11) % 11];\n if (v[9] !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"UEN check letter does not match\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 9 && v.length !== 10) {\n return err(\n \"INVALID_LENGTH\",\n \"UEN must be 9 or 10 characters\",\n );\n }\n\n if (!/^[A-Z0-9]+$/.test(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"UEN must contain only digits and letters\",\n );\n }\n\n // 9 chars: business (ROB)\n if (v.length === 9) {\n return validateBusiness(v);\n }\n\n // 10 chars: first char digit => local company,\n // otherwise \"other\" entity\n // SAFETY: v.length === 10 here.\n // eslint-disable-next-line no-non-null-assertion\n if (isdigits(v[0]!)) {\n return validateLocalCompany(v);\n }\n return validateOther(v);\n};\n\nconst format = (value: string): string => compact(value);\n\n/** Generate a random valid Singapore UEN (business format). */\nconst generate = (): string => {\n const body = randomDigits(8);\n let sum = 0;\n for (const [i, weight] of BUSINESS_WEIGHTS.entries()) {\n sum += Number(body[i]) * weight;\n }\n // SAFETY: sum % 11 is in 0..10 and BUSINESS_CHECK_ALPHA\n // has 11 characters.\n // eslint-disable-next-line no-non-null-assertion\n const check = BUSINESS_CHECK_ALPHA[sum % 11]!;\n return body + check;\n};\n\n/** Singapore Unique Entity Number. */\nconst uen: CountryValidator<\"SG\"> = {\n name: \"Singapore Unique Entity Number\",\n localName: \"Unique Entity Number\",\n abbreviation: \"UEN\",\n aliases: [\"UEN\", \"Unique Entity Number\"] as const,\n candidatePattern: \"[\\\\dSTR]\\\\d{7}[A-Z]\",\n scope: \"country\",\n country: \"SG\",\n entityType: \"company\",\n description:\n \"9 or 10-character business identifier issued by ACRA\",\n sourceUrl: \"https://www.uen.gov.sg/\",\n lengths: [9, 10] as const,\n examples: [\n \"00192200M\",\n \"197401143C\",\n \"S16FC0121D\",\n ] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default uen;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;AA2BA,MAAM,cAAc;AAEpB,MAAM,eAAe,IAAI,IAAI;CAC3B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,WAAW,UACf,MAAM,OAAO,IAAI,
|
|
1
|
+
{"version":3,"file":"uen.js","names":[],"sources":["../../src/sg/uen.ts"],"sourcesContent":["/**\n * UEN (Singapore Unique Entity Number).\n *\n * 9 or 10 characters identifying businesses and\n * entities registered in Singapore. Three formats:\n *\n * - Business (ROB): 8 digits + 1 check letter\n * - Local company (ROC): 4-digit year + 5 digits\n * + 1 check letter\n * - Other entities: R/S/T + 2-digit year + 2-letter\n * entity type + 4 digits + 1 check letter\n *\n * @see https://www.uen.gov.sg/\n * @see https://www.oecd.org/tax/automatic-exchange/crs-implementation-and-assistance/tax-identification-numbers/Singapore-TIN.pdf\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\n/** Check letter alphabet for \"Other\" format. */\nconst OTHER_ALPHA = \"ABCDEFGHJKLMNPQRSTUVWX0123456789\";\n\nconst ENTITY_TYPES = new Set([\n \"CC\",\n \"CD\",\n \"CH\",\n \"CL\",\n \"CM\",\n \"CP\",\n \"CS\",\n \"CX\",\n \"DP\",\n \"FB\",\n \"FC\",\n \"FM\",\n \"FN\",\n \"GA\",\n \"GB\",\n \"GS\",\n \"HS\",\n \"LL\",\n \"LP\",\n \"MB\",\n \"MC\",\n \"MD\",\n \"MH\",\n \"MM\",\n \"MQ\",\n \"NB\",\n \"NR\",\n \"PA\",\n \"PB\",\n \"PF\",\n \"RF\",\n \"RP\",\n \"SM\",\n \"SS\",\n \"TC\",\n \"TU\",\n \"VH\",\n \"XL\",\n]);\n\nconst compact = (value: string): string =>\n clean(value, \" -\").toUpperCase();\n\n/**\n * Validate Business (ROB) UEN (9 chars):\n * 8 digits + 1 check letter.\n */\nconst BUSINESS_WEIGHTS = [10, 4, 9, 3, 8, 2, 7, 1] as const;\nconst BUSINESS_CHECK_ALPHA = \"XMKECAWLJDB\";\n\nconst validateBusiness = (v: string): ValidateResult => {\n if (!isdigits(v.slice(0, 8))) {\n return err(\n \"INVALID_FORMAT\",\n \"Business UEN must start with 8 digits\",\n );\n }\n // SAFETY: caller routes to this only when\n // v.length === 9.\n // eslint-disable-next-line no-non-null-assertion\n if (!/^[A-Z]$/.test(v[8]!)) {\n return err(\n \"INVALID_FORMAT\",\n \"Business UEN must end with a letter\",\n );\n }\n\n let sum = 0;\n for (const [i, weight] of BUSINESS_WEIGHTS.entries()) {\n sum += Number(v[i]) * weight;\n }\n const expected = BUSINESS_CHECK_ALPHA[sum % 11];\n if (v[8] !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"UEN check letter does not match\",\n );\n }\n return { valid: true, compact: v };\n};\n\n/**\n * Validate Local Company (ROC) UEN (10 chars):\n * 9 digits (year prefix) + 1 check letter.\n */\nconst LOCAL_WEIGHTS = [10, 8, 6, 4, 9, 7, 5, 3, 1] as const;\nconst LOCAL_CHECK_ALPHA = \"ZKCMDNERGWH\";\n\nconst validateLocalCompany = (\n v: string,\n): ValidateResult => {\n if (!isdigits(v.slice(0, 9))) {\n return err(\n \"INVALID_FORMAT\",\n \"Company UEN must have 9 digits\",\n );\n }\n // SAFETY: caller routes to this only when\n // v.length === 10.\n // eslint-disable-next-line no-non-null-assertion\n if (!/^[A-Z]$/.test(v[9]!)) {\n return err(\n \"INVALID_FORMAT\",\n \"Company UEN must end with a letter\",\n );\n }\n\n let sum = 0;\n for (const [i, weight] of LOCAL_WEIGHTS.entries()) {\n sum += Number(v[i]) * weight;\n }\n const expected = LOCAL_CHECK_ALPHA[sum % 11];\n if (v[9] !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"UEN check letter does not match\",\n );\n }\n return { valid: true, compact: v };\n};\n\n/**\n * Validate Other entity UEN (10 chars):\n * R/S/T + 2 digits + 2-letter type + 4 digits\n * + 1 check letter.\n */\nconst OTHER_WEIGHTS = [4, 3, 5, 3, 10, 2, 2, 5, 7] as const;\n\nconst validateOther = (v: string): ValidateResult => {\n // SAFETY: caller routes to this only when\n // v.length === 10.\n // eslint-disable-next-line no-non-null-assertion\n const prefix = v[0]!;\n if (prefix !== \"R\" && prefix !== \"S\" && prefix !== \"T\") {\n return err(\n \"INVALID_COMPONENT\",\n \"Other UEN must start with R, S, or T\",\n );\n }\n if (!isdigits(v.slice(1, 3))) {\n return err(\n \"INVALID_FORMAT\",\n \"Other UEN positions 2-3 must be digits\",\n );\n }\n const entityType = v.slice(3, 5);\n if (!ENTITY_TYPES.has(entityType)) {\n return err(\n \"INVALID_COMPONENT\",\n \"Unknown entity type: \" + entityType,\n );\n }\n if (!isdigits(v.slice(5, 9))) {\n return err(\n \"INVALID_FORMAT\",\n \"Other UEN positions 6-9 must be digits\",\n );\n }\n\n let sum = 0;\n for (const [i, weight] of OTHER_WEIGHTS.entries()) {\n const ch = v[i];\n if (ch === undefined) continue;\n const idx = OTHER_ALPHA.indexOf(ch);\n if (idx === -1) {\n return err(\n \"INVALID_FORMAT\",\n `Unexpected character at position ${i + 1}: ${ch}`,\n );\n }\n sum += idx * weight;\n }\n const expected =\n OTHER_ALPHA[(((sum - 5) % 11) + 11) % 11];\n if (v[9] !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"UEN check letter does not match\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 9 && v.length !== 10) {\n return err(\n \"INVALID_LENGTH\",\n \"UEN must be 9 or 10 characters\",\n );\n }\n\n if (!/^[A-Z0-9]+$/.test(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"UEN must contain only digits and letters\",\n );\n }\n\n // 9 chars: business (ROB)\n if (v.length === 9) {\n return validateBusiness(v);\n }\n\n // 10 chars: first char digit => local company,\n // otherwise \"other\" entity\n // SAFETY: v.length === 10 here.\n // eslint-disable-next-line no-non-null-assertion\n if (isdigits(v[0]!)) {\n return validateLocalCompany(v);\n }\n return validateOther(v);\n};\n\nconst format = (value: string): string => compact(value);\n\n/** Generate a random valid Singapore UEN (business format). */\nconst generate = (): string => {\n const body = randomDigits(8);\n let sum = 0;\n for (const [i, weight] of BUSINESS_WEIGHTS.entries()) {\n sum += Number(body[i]) * weight;\n }\n // SAFETY: sum % 11 is in 0..10 and BUSINESS_CHECK_ALPHA\n // has 11 characters.\n // eslint-disable-next-line no-non-null-assertion\n const check = BUSINESS_CHECK_ALPHA[sum % 11]!;\n return body + check;\n};\n\n/** Singapore Unique Entity Number. */\nconst uen: CountryValidator<\"SG\"> = {\n name: \"Singapore Unique Entity Number\",\n localName: \"Unique Entity Number\",\n abbreviation: \"UEN\",\n aliases: [\"UEN\", \"Unique Entity Number\"] as const,\n candidatePattern: \"[\\\\dSTR]\\\\d{7}[A-Z]\",\n scope: \"country\",\n country: \"SG\",\n entityType: \"company\",\n description:\n \"9 or 10-character business identifier issued by ACRA\",\n sourceUrl: \"https://www.uen.gov.sg/\",\n lengths: [9, 10] as const,\n examples: [\n \"00192200M\",\n \"197401143C\",\n \"S16FC0121D\",\n ] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default uen;\nexport { compact, format, validate, generate };\n"],"mappings":"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"}
|
package/dist/si/emso.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emso.js","names":[],"sources":["../../src/si/emso.ts"],"sourcesContent":["/**\n * EMŠO (Enotna matična številka občana).\n *\n * Slovenian unique master citizen number. 13 digits\n * encoding DDMMYYY (7-digit birth year), region code,\n * serial number, and a check digit.\n *\n * Canonical source:\n * - Slovenia government registry overview\n *\n * This is the source behind the stricter register\n * code check (50-59) and the decision to reject\n * future birth dates in the embedded date field.\n *\n * @see https://www.gov.si/teme/registri-in-evidence-prebivalstva/\n */\n\nimport type {\n ParsedPersonId,\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { weightedSum } from \"#checksums/weighted-sum\";\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 WEIGHTS = [\n 7, 6, 5, 4, 3, 2, 7, 6, 5, 4, 3, 2,\n] as const;\n\nconst compact = (value: string): string =>\n clean(value, \" -\");\n\n/**\n * Compute the check digit matching python-stdnum:\n * `str(-total % 11 % 10)`.\n */\nconst calcCheckDigit = (v: string): number => {\n const total = weightedSum(v.slice(0, 12), WEIGHTS, 11);\n // Python's (-total % 11 % 10) — always 0..9\n // weightedSum already returns (sum % 11 + 11) % 11,\n // so total is 0..10. Negate within mod 11:\n return ((11 - total) % 11) % 10;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 13) {\n return err(\n \"INVALID_LENGTH\",\n \"EMŠO must be exactly 13 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"EMŠO must contain only digits\",\n );\n }\n\n // Validate embedded birth date (DDMMYYY)\n const dd = Number(v.slice(0, 2));\n const mm = Number(v.slice(2, 4));\n let yyyy = Number(v.slice(4, 7));\n // JMBG standard: 900-999 → 1900s, 000-899 → 2000s\n // Note: python-stdnum uses 800 as threshold, but\n // the official JMBG spec uses 900. No practical\n // difference (800-899 range has no living citizens).\n if (yyyy < 900) {\n yyyy += 2000;\n } else {\n yyyy += 1000;\n }\n if (!isValidDate(yyyy, mm, dd)) {\n return err(\n \"INVALID_COMPONENT\",\n \"EMŠO contains an invalid date\",\n );\n }\n const birthDate = new Date(yyyy, mm - 1, dd);\n const today = new Date();\n today.setHours(0, 0, 0, 0);\n if (birthDate > today) {\n return err(\n \"INVALID_COMPONENT\",\n \"EMŠO cannot contain a future birth date\",\n );\n }\n\n const register = Number(v.slice(7, 9));\n if (register < 50 || register > 59) {\n return err(\n \"INVALID_COMPONENT\",\n \"EMSO register code must be between 50 and 59\",\n );\n }\n\n if (calcCheckDigit(v) !== Number(v[12])) {\n return err(\n \"INVALID_CHECKSUM\",\n \"EMŠO check digit does not match\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => compact(value);\n\n/**\n * Extract birth date and gender from an EMSO.\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 let yyyy = Number(v.slice(4, 7));\n if (yyyy < 900) {\n yyyy += 2000;\n } else {\n yyyy += 1000;\n }\n\n const serial = Number(v.slice(9, 12));\n\n return {\n birthDate: new Date(yyyy, mm - 1, dd),\n gender: serial < 500 ? \"male\" : \"female\",\n };\n};\n\n/** Generate a random valid Slovenian EMSO. */\nconst generate = (): string => {\n for (;;) {\n const dd = String(randomInt(1, 28)).padStart(2, \"0\");\n const mm = String(randomInt(1, 12)).padStart(2, \"0\");\n const yyy = String(randomInt(900, 999));\n const rr = String(randomInt(50, 59));\n const sss = String(randomInt(0, 999)).padStart(3, \"0\");\n const partial = dd + mm + yyy + rr + sss;\n const c = partial + String(calcCheckDigit(partial));\n if (validate(c).valid) return c;\n }\n};\n\n/** Slovenian Unique Master Citizen Number. */\nconst emso: CountryValidator<\"SI\", ParsedPersonId> = {\n name: \"Slovenian Personal ID\",\n localName: \"Enotna matična številka občana\",\n abbreviation: \"EMŠO\",\n aliases: [\n \"EMŠO\",\n \"enotna matična številka občana\",\n ] as const,\n candidatePattern: \"\\\\d{13}\",\n scope: \"country\",\n country: \"SI\",\n entityType: \"person\",\n sourceUrl:\n \"https://www.gov.si/teme/registri-in-evidence-prebivalstva/\",\n examples: [\"0101006500006\"] as const,\n compact,\n format,\n parse,\n validate,\n generate,\n};\n\nexport default emso;\nexport { compact, format, parse, validate, generate };\n"],"mappings":";;;;;;;AA8BA,MAAM,UAAU;CACd;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AACnC;AAEA,MAAM,WAAW,UACf,MAAM,OAAO,IAAI;;;;;AAMnB,MAAM,kBAAkB,MAAsB;CAK5C,QAAS,KAJK,YAAY,EAAE,MAAM,GAAG,EAAE,GAAG,SAAS,EAIjC,KAAK,KAAM;AAC/B;AAEA,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,IACf,OAAO,IACL,kBACA,gCACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,+BACF;CAIF,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/B,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/B,IAAI,OAAO,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAK/B,IAAI,OAAO,KACT,QAAQ;MAER,QAAQ;CAEV,IAAI,CAAC,YAAY,MAAM,IAAI,EAAE,GAC3B,OAAO,IACL,qBACA,+BACF;CAEF,MAAM,YAAY,IAAI,KAAK,MAAM,KAAK,GAAG,EAAE;CAC3C,MAAM,wBAAQ,IAAI,KAAK;CACvB,MAAM,SAAS,GAAG,GAAG,GAAG,CAAC;CACzB,IAAI,YAAY,OACd,OAAO,IACL,qBACA,yCACF;CAGF,MAAM,WAAW,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CACrC,IAAI,WAAW,MAAM,WAAW,IAC9B,OAAO,IACL,qBACA,8CACF;CAGF,IAAI,eAAe,CAAC,MAAM,OAAO,EAAE,GAAG,GACpC,OAAO,IACL,oBACA,iCACF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B,QAAQ,KAAK;;;;;AAMvD,MAAM,SAAS,UAAyC;CACtD,MAAM,SAAS,SAAS,KAAK;CAC7B,IAAI,CAAC,OAAO,OAAO,OAAO;CAE1B,MAAM,IAAI,OAAO;CACjB,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/B,MAAM,KAAK,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/B,IAAI,OAAO,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/B,IAAI,OAAO,KACT,QAAQ;MAER,QAAQ;CAGV,MAAM,SAAS,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;CAEpC,OAAO;EACL,WAAW,IAAI,KAAK,MAAM,KAAK,GAAG,EAAE;EACpC,QAAQ,SAAS,MAAM,SAAS;CAClC;AACF;;AAGA,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,KAAK,OAAO,UAAU,GAAG,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"emso.js","names":[],"sources":["../../src/si/emso.ts"],"sourcesContent":["/**\n * EMŠO (Enotna matična številka občana).\n *\n * Slovenian unique master citizen number. 13 digits\n * encoding DDMMYYY (7-digit birth year), region code,\n * serial number, and a check digit.\n *\n * Canonical source:\n * - Slovenia government registry overview\n *\n * This is the source behind the stricter register\n * code check (50-59) and the decision to reject\n * future birth dates in the embedded date field.\n *\n * @see https://www.gov.si/teme/registri-in-evidence-prebivalstva/\n */\n\nimport type {\n ParsedPersonId,\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { weightedSum } from \"#checksums/weighted-sum\";\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 WEIGHTS = [\n 7, 6, 5, 4, 3, 2, 7, 6, 5, 4, 3, 2,\n] as const;\n\nconst compact = (value: string): string =>\n clean(value, \" -\");\n\n/**\n * Compute the check digit matching python-stdnum:\n * `str(-total % 11 % 10)`.\n */\nconst calcCheckDigit = (v: string): number => {\n const total = weightedSum(v.slice(0, 12), WEIGHTS, 11);\n // Python's (-total % 11 % 10) — always 0..9\n // weightedSum already returns (sum % 11 + 11) % 11,\n // so total is 0..10. Negate within mod 11:\n return ((11 - total) % 11) % 10;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 13) {\n return err(\n \"INVALID_LENGTH\",\n \"EMŠO must be exactly 13 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"EMŠO must contain only digits\",\n );\n }\n\n // Validate embedded birth date (DDMMYYY)\n const dd = Number(v.slice(0, 2));\n const mm = Number(v.slice(2, 4));\n let yyyy = Number(v.slice(4, 7));\n // JMBG standard: 900-999 → 1900s, 000-899 → 2000s\n // Note: python-stdnum uses 800 as threshold, but\n // the official JMBG spec uses 900. No practical\n // difference (800-899 range has no living citizens).\n if (yyyy < 900) {\n yyyy += 2000;\n } else {\n yyyy += 1000;\n }\n if (!isValidDate(yyyy, mm, dd)) {\n return err(\n \"INVALID_COMPONENT\",\n \"EMŠO contains an invalid date\",\n );\n }\n const birthDate = new Date(yyyy, mm - 1, dd);\n const today = new Date();\n today.setHours(0, 0, 0, 0);\n if (birthDate > today) {\n return err(\n \"INVALID_COMPONENT\",\n \"EMŠO cannot contain a future birth date\",\n );\n }\n\n const register = Number(v.slice(7, 9));\n if (register < 50 || register > 59) {\n return err(\n \"INVALID_COMPONENT\",\n \"EMSO register code must be between 50 and 59\",\n );\n }\n\n if (calcCheckDigit(v) !== Number(v[12])) {\n return err(\n \"INVALID_CHECKSUM\",\n \"EMŠO check digit does not match\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => compact(value);\n\n/**\n * Extract birth date and gender from an EMSO.\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 let yyyy = Number(v.slice(4, 7));\n if (yyyy < 900) {\n yyyy += 2000;\n } else {\n yyyy += 1000;\n }\n\n const serial = Number(v.slice(9, 12));\n\n return {\n birthDate: new Date(yyyy, mm - 1, dd),\n gender: serial < 500 ? \"male\" : \"female\",\n };\n};\n\n/** Generate a random valid Slovenian EMSO. */\nconst generate = (): string => {\n for (;;) {\n const dd = String(randomInt(1, 28)).padStart(2, \"0\");\n const mm = String(randomInt(1, 12)).padStart(2, \"0\");\n const yyy = String(randomInt(900, 999));\n const rr = String(randomInt(50, 59));\n const sss = String(randomInt(0, 999)).padStart(3, \"0\");\n const partial = dd + mm + yyy + rr + sss;\n const c = partial + String(calcCheckDigit(partial));\n if (validate(c).valid) return c;\n }\n};\n\n/** Slovenian Unique Master Citizen Number. */\nconst emso: CountryValidator<\"SI\", ParsedPersonId> = {\n name: \"Slovenian Personal ID\",\n localName: \"Enotna matična številka občana\",\n abbreviation: \"EMŠO\",\n aliases: [\n \"EMŠO\",\n \"enotna matična številka občana\",\n ] as const,\n candidatePattern: \"\\\\d{13}\",\n scope: \"country\",\n country: \"SI\",\n entityType: \"person\",\n sourceUrl:\n \"https://www.gov.si/teme/registri-in-evidence-prebivalstva/\",\n examples: [\"0101006500006\"] as const,\n compact,\n format,\n parse,\n validate,\n generate,\n};\n\nexport default emso;\nexport { compact, format, parse, validate, generate };\n"],"mappings":"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"}
|
package/dist/si/vat.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vat.js","names":[],"sources":["../../src/si/vat.ts"],"sourcesContent":["/**\n * DDV (Slovenian VAT number).\n *\n * 8 digits, no leading 0.\n * Weights [8,7,6,5,4,3,2], check = 11 - sum % 11.\n * If check === 10 invalid; if 11 the number is\n * invalid (spec says no valid number yields 11).\n *\n * @see https://www.vatify.eu/slovenia-vat-number.html\n * @see https://spot.gov.si/en/info/taxes/value-added-tax-vat\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, randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst WEIGHTS = [8, 7, 6, 5, 4, 3, 2];\n\nconst compact = (value: string): string => {\n let v = clean(value, \" -/.\");\n if (v.startsWith(\"SI\") || v.startsWith(\"si\")) {\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 \"Slovenian VAT number must be 8 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"Slovenian VAT number must contain only digits\",\n );\n }\n if (v[0] === \"0\") {\n return err(\n \"INVALID_COMPONENT\",\n \"Slovenian VAT number cannot start with 0\",\n );\n }\n const remainder = weightedSum(v.slice(0, 7), WEIGHTS, 11);\n const check = 11 - remainder;\n if (check === 11) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Slovenian VAT number check digit invalid\",\n );\n }\n if (check === 10) {\n // check digit 10 means 0\n if (Number(v[7]) !== 0) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Slovenian VAT number check digit mismatch\",\n );\n }\n } else if (check !== Number(v[7])) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Slovenian VAT number check digit mismatch\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string =>\n `SI${compact(value)}`;\n\n/** Generate a random valid Slovenian VAT number. */\nconst generate = (): string => {\n for (;;) {\n const c = String(randomInt(1, 9)) + randomDigits(7);\n if (validate(c).valid) return c;\n }\n};\n\n/** Slovenian VAT Number. */\nconst vat: CountryValidator<\"SI\"> = {\n name: \"Slovenian VAT Number\",\n localName: \"Davčna številka\",\n abbreviation: \"DDV\",\n aliases: [\n \"DDV\",\n \"identifikacijska številka za DDV\",\n ] as const,\n candidatePattern: \"SI\\\\d{8}\",\n scope: \"country\",\n country: \"SI\",\n entityType: \"company\",\n sourceUrl: \"https://www.fu.gov.si/\",\n lengths: [8] as const,\n examples: [\"15012557\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default vat;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;AAuBA,MAAM,UAAU;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AAEpC,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,uCACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,+CACF;CAEF,IAAI,EAAE,OAAO,KACX,OAAO,IACL,qBACA,0CACF;CAGF,MAAM,QAAQ,KADI,YAAY,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,EAC3B;CAC3B,IAAI,UAAU,IACZ,OAAO,IACL,oBACA,0CACF;CAEF,IAAI,UAAU;MAER,OAAO,EAAE,EAAE,MAAM,GACnB,OAAO,IACL,oBACA,2CACF;CAAA,OAEG,IAAI,UAAU,OAAO,EAAE,EAAE,GAC9B,OAAO,IACL,oBACA,2CACF;CAEF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UACd,KAAK,QAAQ,KAAK;;AAGpB,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,IAAI,OAAO,UAAU,GAAG,CAAC,CAAC,IAAI,aAAa,CAAC;EAClD,IAAI,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"vat.js","names":[],"sources":["../../src/si/vat.ts"],"sourcesContent":["/**\n * DDV (Slovenian VAT number).\n *\n * 8 digits, no leading 0.\n * Weights [8,7,6,5,4,3,2], check = 11 - sum % 11.\n * If check === 10 invalid; if 11 the number is\n * invalid (spec says no valid number yields 11).\n *\n * @see https://www.vatify.eu/slovenia-vat-number.html\n * @see https://spot.gov.si/en/info/taxes/value-added-tax-vat\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, randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst WEIGHTS = [8, 7, 6, 5, 4, 3, 2];\n\nconst compact = (value: string): string => {\n let v = clean(value, \" -/.\");\n if (v.startsWith(\"SI\") || v.startsWith(\"si\")) {\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 \"Slovenian VAT number must be 8 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"Slovenian VAT number must contain only digits\",\n );\n }\n if (v[0] === \"0\") {\n return err(\n \"INVALID_COMPONENT\",\n \"Slovenian VAT number cannot start with 0\",\n );\n }\n const remainder = weightedSum(v.slice(0, 7), WEIGHTS, 11);\n const check = 11 - remainder;\n if (check === 11) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Slovenian VAT number check digit invalid\",\n );\n }\n if (check === 10) {\n // check digit 10 means 0\n if (Number(v[7]) !== 0) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Slovenian VAT number check digit mismatch\",\n );\n }\n } else if (check !== Number(v[7])) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Slovenian VAT number check digit mismatch\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string =>\n `SI${compact(value)}`;\n\n/** Generate a random valid Slovenian VAT number. */\nconst generate = (): string => {\n for (;;) {\n const c = String(randomInt(1, 9)) + randomDigits(7);\n if (validate(c).valid) return c;\n }\n};\n\n/** Slovenian VAT Number. */\nconst vat: CountryValidator<\"SI\"> = {\n name: \"Slovenian VAT Number\",\n localName: \"Davčna številka\",\n abbreviation: \"DDV\",\n aliases: [\n \"DDV\",\n \"identifikacijska številka za DDV\",\n ] as const,\n candidatePattern: \"SI\\\\d{8}\",\n scope: \"country\",\n country: \"SI\",\n entityType: \"company\",\n sourceUrl: \"https://www.fu.gov.si/\",\n lengths: [8] as const,\n examples: [\"15012557\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default vat;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;AAuBA,MAAM,UAAU;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AAEpC,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,uCACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,+CACF;CAEF,IAAI,EAAE,OAAO,KACX,OAAO,IACL,qBACA,0CACF;CAGF,MAAM,QAAQ,KADI,YAAY,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,EAC3B;CAC3B,IAAI,UAAU,IACZ,OAAO,IACL,oBACA,0CACF;CAEF,IAAI,UAAU;MAER,OAAO,EAAE,EAAE,MAAM,GACnB,OAAO,IACL,oBACA,2CACF;CAAA,OAEG,IAAI,UAAU,OAAO,EAAE,EAAE,GAC9B,OAAO,IACL,oBACA,2CACF;CAEF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UACd,KAAK,QAAQ,KAAK;;AAGpB,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,IAAI,OAAO,UAAU,GAAG,CAAC,CAAC,IAAI,aAAa,CAAC;EAClD,IAAI,SAAS,CAAC,CAAC,CAAC,OAAO,OAAO;CAChC;AACF;;AAGA,MAAM,MAA8B;CAClC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CACP,OACA,kCACF;CACA,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,WAAW;CACX,SAAS,CAAC,CAAC;CACX,UAAU,CAAC,UAAU;CACrB;CACA;CACA;CACA;AACF"}
|
package/dist/sk/dic.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dic.js","names":["validateRc"],"sources":["../../src/sk/dic.ts"],"sourcesContent":["/**\n * IČ DPH (Identifikačné číslo pre daň z\n * pridanej hodnoty).\n *\n * Slovak VAT number. Format: \"SK\" + 10 digits.\n * The 10-digit number must be divisible by 11.\n * First digit is 1-9.\n *\n * @see https://www.financnasprava.sk/\n */\n\nimport { validate as validateRc } from \"../cz/rc\";\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 compact = (value: string): string => {\n const v = clean(value, \" -\");\n if (v.startsWith(\"SK\") || v.startsWith(\"sk\")) {\n return v.slice(2);\n }\n return v;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 10) {\n return err(\n \"INVALID_LENGTH\",\n \"Slovak VAT number must be 10 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"Slovak VAT number must contain only digits\",\n );\n }\n // A valid birth number is also accepted as DPH\n if (validateRc(v).valid) {\n return { valid: true, compact: v };\n }\n if (v[0] === \"0\") {\n return err(\n \"INVALID_COMPONENT\",\n \"Slovak VAT number cannot start with 0\",\n );\n }\n // Third digit must be 2, 3, 4, 7, 8, or 9\n const d3 = Number(v[2]);\n if (\n d3 !== 2 &&\n d3 !== 3 &&\n d3 !== 4 &&\n d3 !== 7 &&\n d3 !== 8 &&\n d3 !== 9\n ) {\n return err(\n \"INVALID_FORMAT\",\n \"Slovak VAT number has invalid third digit\",\n );\n }\n if (Number(v) % 11 !== 0) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Slovak VAT number is not divisible by 11\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string =>\n `SK${compact(value)}`;\n\n/** Generate a random valid Slovak DIČ. */\nconst generate = (): string => {\n for (;;) {\n const c = randomDigits(10);\n if (validate(c).valid) return c;\n }\n};\n\n/** Slovak VAT Number. */\nconst dic: CountryValidator<\"SK\"> = {\n name: \"Slovak VAT Number\",\n localName:\n \"Identifikačné číslo pre daň z pridanej hodnoty\",\n abbreviation: \"IČ DPH\",\n aliases: [\"DIČ\", \"daňové identifikačné číslo\"] as const,\n candidatePattern: \"SK\\\\d{10}\",\n scope: \"country\",\n country: \"SK\",\n entityType: \"company\",\n sourceUrl: \"https://www.financnasprava.sk/\",\n examples: [\"2021853504\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default dic;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;;;;;;;;;;;AAsBA,MAAM,WAAW,UAA0B;CACzC,MAAM,IAAI,MAAM,OAAO,IAAI;CAC3B,IAAI,EAAE,WAAW,IAAI,KAAK,EAAE,WAAW,IAAI,GACzC,OAAO,EAAE,MAAM,CAAC;CAElB,OAAO;AACT;AAEA,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,IACf,OAAO,IACL,kBACA,qCACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,4CACF;CAGF,IAAIA,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"dic.js","names":["validateRc"],"sources":["../../src/sk/dic.ts"],"sourcesContent":["/**\n * IČ DPH (Identifikačné číslo pre daň z\n * pridanej hodnoty).\n *\n * Slovak VAT number. Format: \"SK\" + 10 digits.\n * The 10-digit number must be divisible by 11.\n * First digit is 1-9.\n *\n * @see https://www.financnasprava.sk/\n */\n\nimport { validate as validateRc } from \"../cz/rc\";\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 compact = (value: string): string => {\n const v = clean(value, \" -\");\n if (v.startsWith(\"SK\") || v.startsWith(\"sk\")) {\n return v.slice(2);\n }\n return v;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 10) {\n return err(\n \"INVALID_LENGTH\",\n \"Slovak VAT number must be 10 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"Slovak VAT number must contain only digits\",\n );\n }\n // A valid birth number is also accepted as DPH\n if (validateRc(v).valid) {\n return { valid: true, compact: v };\n }\n if (v[0] === \"0\") {\n return err(\n \"INVALID_COMPONENT\",\n \"Slovak VAT number cannot start with 0\",\n );\n }\n // Third digit must be 2, 3, 4, 7, 8, or 9\n const d3 = Number(v[2]);\n if (\n d3 !== 2 &&\n d3 !== 3 &&\n d3 !== 4 &&\n d3 !== 7 &&\n d3 !== 8 &&\n d3 !== 9\n ) {\n return err(\n \"INVALID_FORMAT\",\n \"Slovak VAT number has invalid third digit\",\n );\n }\n if (Number(v) % 11 !== 0) {\n return err(\n \"INVALID_CHECKSUM\",\n \"Slovak VAT number is not divisible by 11\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string =>\n `SK${compact(value)}`;\n\n/** Generate a random valid Slovak DIČ. */\nconst generate = (): string => {\n for (;;) {\n const c = randomDigits(10);\n if (validate(c).valid) return c;\n }\n};\n\n/** Slovak VAT Number. */\nconst dic: CountryValidator<\"SK\"> = {\n name: \"Slovak VAT Number\",\n localName:\n \"Identifikačné číslo pre daň z pridanej hodnoty\",\n abbreviation: \"IČ DPH\",\n aliases: [\"DIČ\", \"daňové identifikačné číslo\"] as const,\n candidatePattern: \"SK\\\\d{10}\",\n scope: \"country\",\n country: \"SK\",\n entityType: \"company\",\n sourceUrl: \"https://www.financnasprava.sk/\",\n examples: [\"2021853504\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default dic;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;;;;;;;;;;;AAsBA,MAAM,WAAW,UAA0B;CACzC,MAAM,IAAI,MAAM,OAAO,IAAI;CAC3B,IAAI,EAAE,WAAW,IAAI,KAAK,EAAE,WAAW,IAAI,GACzC,OAAO,EAAE,MAAM,CAAC;CAElB,OAAO;AACT;AAEA,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,IACf,OAAO,IACL,kBACA,qCACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,4CACF;CAGF,IAAIA,WAAW,CAAC,CAAC,CAAC,OAChB,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;CAEnC,IAAI,EAAE,OAAO,KACX,OAAO,IACL,qBACA,uCACF;CAGF,MAAM,KAAK,OAAO,EAAE,EAAE;CACtB,IACE,OAAO,KACP,OAAO,KACP,OAAO,KACP,OAAO,KACP,OAAO,KACP,OAAO,GAEP,OAAO,IACL,kBACA,2CACF;CAEF,IAAI,OAAO,CAAC,IAAI,OAAO,GACrB,OAAO,IACL,oBACA,0CACF;CAEF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UACd,KAAK,QAAQ,KAAK;;AAGpB,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,IAAI,aAAa,EAAE;EACzB,IAAI,SAAS,CAAC,CAAC,CAAC,OAAO,OAAO;CAChC;AACF;;AAGA,MAAM,MAA8B;CAClC,MAAM;CACN,WACE;CACF,cAAc;CACd,SAAS,CAAC,OAAO,4BAA4B;CAC7C,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,WAAW;CACX,UAAU,CAAC,YAAY;CACvB;CACA;CACA;CACA;AACF"}
|
package/dist/tw/ubn.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ubn.js","names":[],"sources":["../../src/tw/ubn.ts"],"sourcesContent":["/**\n * UBN (Unified Business Number, 統一編號).\n *\n * Taiwanese company identifier. 8 digits with a\n * weighted checksum. Weights [1,2,1,2,1,2,4,1];\n * sum the individual digits of each product, total\n * mod 10 must be 0. Special case: when the 7th digit\n * is 7, checksum 9 is also accepted.\n *\n * @see https://zh.wikipedia.org/wiki/統一編號\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst WEIGHTS = [1, 2, 1, 2, 1, 2, 4, 1] as const;\n\n/** Sum the individual digits of a number. */\nconst digitSum = (n: number): number => {\n let sum = 0;\n while (n > 0) {\n sum += n % 10;\n n = Math.floor(n / 10);\n }\n return sum;\n};\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 \"UBN must be exactly 8 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"UBN must contain only digits\",\n );\n }\n\n let sum = 0;\n for (const [i, weight] of WEIGHTS.entries()) {\n sum += digitSum(Number(v[i]) * weight);\n }\n\n const checksum = sum % 10;\n if (checksum === 0) {\n return { valid: true, compact: v };\n }\n\n // Special case: when the 7th digit is 7 (product\n // 4*7=28), the checksum may be 9 instead of 0.\n if (checksum === 9 && v[6] === \"7\") {\n return { valid: true, compact: v };\n }\n\n return err(\n \"INVALID_CHECKSUM\",\n \"UBN checksum does not match\",\n );\n};\n\nconst format = (value: string): string => compact(value);\n\n/** Generate a random valid UBN. */\nconst generate = (): string => {\n for (;;) {\n const prefix = randomDigits(7);\n for (let d = 0; d < 10; d++) {\n const candidate = `${prefix}${d}`;\n const r = validate(candidate);\n if (r.valid) return candidate;\n }\n }\n};\n\n/** Taiwanese Unified Business Number. */\nconst ubn: CountryValidator<\"TW\"> = {\n name: \"Unified Business Number\",\n localName: \"統一編號\",\n abbreviation: \"UBN\",\n aliases: [\"統一編號\", \"UBN\"] as const,\n candidatePattern: \"\\\\d{8}\",\n scope: \"country\",\n country: \"TW\",\n entityType: \"company\",\n description:\n \"8-digit company identifier issued by the Ministry of Economic Affairs\",\n sourceUrl:\n \"https://zh.wikipedia.org/wiki/%E7%B5%B1%E4%B8%80%E7%B7%A8%E8%99%9F\",\n lengths: [8] as const,\n examples: [\"00501503\", \"04595257\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default ubn;\nexport { compact, format, generate, validate };\n"],"mappings":";;;;;AAsBA,MAAM,UAAU;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;;AAGvC,MAAM,YAAY,MAAsB;CACtC,IAAI,MAAM;CACV,OAAO,IAAI,GAAG;EACZ,OAAO,IAAI;EACX,IAAI,KAAK,MAAM,IAAI,EAAE;CACvB;CACA,OAAO;AACT;AAEA,MAAM,WAAW,UACf,MAAM,OAAO,IAAI;AAEnB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,GACf,OAAO,IACL,kBACA,8BACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,8BACF;CAGF,IAAI,MAAM;CACV,KAAK,MAAM,CAAC,GAAG,WAAW,QAAQ,QAAQ,GACxC,OAAO,SAAS,OAAO,EAAE,EAAE,IAAI,MAAM;CAGvC,MAAM,WAAW,MAAM;CACvB,IAAI,aAAa,GACf,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;CAKnC,IAAI,aAAa,KAAK,EAAE,OAAO,KAC7B,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;CAGnC,OAAO,IACL,oBACA,6BACF;AACF;AAEA,MAAM,UAAU,UAA0B,QAAQ,KAAK;;AAGvD,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,SAAS,aAAa,CAAC;EAC7B,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;GAC3B,MAAM,YAAY,GAAG,SAAS;GAE9B,IADU,SAAS,SACf,
|
|
1
|
+
{"version":3,"file":"ubn.js","names":[],"sources":["../../src/tw/ubn.ts"],"sourcesContent":["/**\n * UBN (Unified Business Number, 統一編號).\n *\n * Taiwanese company identifier. 8 digits with a\n * weighted checksum. Weights [1,2,1,2,1,2,4,1];\n * sum the individual digits of each product, total\n * mod 10 must be 0. Special case: when the 7th digit\n * is 7, checksum 9 is also accepted.\n *\n * @see https://zh.wikipedia.org/wiki/統一編號\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst WEIGHTS = [1, 2, 1, 2, 1, 2, 4, 1] as const;\n\n/** Sum the individual digits of a number. */\nconst digitSum = (n: number): number => {\n let sum = 0;\n while (n > 0) {\n sum += n % 10;\n n = Math.floor(n / 10);\n }\n return sum;\n};\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 \"UBN must be exactly 8 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"UBN must contain only digits\",\n );\n }\n\n let sum = 0;\n for (const [i, weight] of WEIGHTS.entries()) {\n sum += digitSum(Number(v[i]) * weight);\n }\n\n const checksum = sum % 10;\n if (checksum === 0) {\n return { valid: true, compact: v };\n }\n\n // Special case: when the 7th digit is 7 (product\n // 4*7=28), the checksum may be 9 instead of 0.\n if (checksum === 9 && v[6] === \"7\") {\n return { valid: true, compact: v };\n }\n\n return err(\n \"INVALID_CHECKSUM\",\n \"UBN checksum does not match\",\n );\n};\n\nconst format = (value: string): string => compact(value);\n\n/** Generate a random valid UBN. */\nconst generate = (): string => {\n for (;;) {\n const prefix = randomDigits(7);\n for (let d = 0; d < 10; d++) {\n const candidate = `${prefix}${d}`;\n const r = validate(candidate);\n if (r.valid) return candidate;\n }\n }\n};\n\n/** Taiwanese Unified Business Number. */\nconst ubn: CountryValidator<\"TW\"> = {\n name: \"Unified Business Number\",\n localName: \"統一編號\",\n abbreviation: \"UBN\",\n aliases: [\"統一編號\", \"UBN\"] as const,\n candidatePattern: \"\\\\d{8}\",\n scope: \"country\",\n country: \"TW\",\n entityType: \"company\",\n description:\n \"8-digit company identifier issued by the Ministry of Economic Affairs\",\n sourceUrl:\n \"https://zh.wikipedia.org/wiki/%E7%B5%B1%E4%B8%80%E7%B7%A8%E8%99%9F\",\n lengths: [8] as const,\n examples: [\"00501503\", \"04595257\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default ubn;\nexport { compact, format, generate, validate };\n"],"mappings":";;;;;AAsBA,MAAM,UAAU;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;;AAGvC,MAAM,YAAY,MAAsB;CACtC,IAAI,MAAM;CACV,OAAO,IAAI,GAAG;EACZ,OAAO,IAAI;EACX,IAAI,KAAK,MAAM,IAAI,EAAE;CACvB;CACA,OAAO;AACT;AAEA,MAAM,WAAW,UACf,MAAM,OAAO,IAAI;AAEnB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,GACf,OAAO,IACL,kBACA,8BACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,8BACF;CAGF,IAAI,MAAM;CACV,KAAK,MAAM,CAAC,GAAG,WAAW,QAAQ,QAAQ,GACxC,OAAO,SAAS,OAAO,EAAE,EAAE,IAAI,MAAM;CAGvC,MAAM,WAAW,MAAM;CACvB,IAAI,aAAa,GACf,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;CAKnC,IAAI,aAAa,KAAK,EAAE,OAAO,KAC7B,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;CAGnC,OAAO,IACL,oBACA,6BACF;AACF;AAEA,MAAM,UAAU,UAA0B,QAAQ,KAAK;;AAGvD,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,SAAS,aAAa,CAAC;EAC7B,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;GAC3B,MAAM,YAAY,GAAG,SAAS;GAE9B,IADU,SAAS,SACf,CAAC,CAAC,OAAO,OAAO;EACtB;CACF;AACF;;AAGA,MAAM,MAA8B;CAClC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,QAAQ,KAAK;CACvB,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,aACE;CACF,WACE;CACF,SAAS,CAAC,CAAC;CACX,UAAU,CAAC,YAAY,UAAU;CACjC;CACA;CACA;CACA;AACF"}
|
package/dist/ua/edrpou.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"edrpou.js","names":[],"sources":["../../src/ua/edrpou.ts"],"sourcesContent":["/**\n * EDRPOU (ЄДРПОУ, Unified State Register of\n * Enterprises and Organizations of Ukraine).\n *\n * 8-digit company identification number with a\n * weighted checksum. Two sets of weights are used\n * depending on whether the first digit is 0-2/6-9 or 3-5.\n *\n * @see https://en.wikipedia.org/wiki/EDRPOU\n * @see https://usr.minjust.gov.ua/\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst WEIGHTS_A = [1, 2, 3, 4, 5, 6, 7] as const;\nconst WEIGHTS_B = [7, 1, 2, 3, 4, 5, 6] as const;\nconst WEIGHTS_A2 = [3, 4, 5, 6, 7, 8, 9] as const;\nconst WEIGHTS_B2 = [9, 3, 4, 5, 6, 7, 8] as const;\n\nconst calcCheck = (\n value: string,\n weights: readonly number[],\n): number => {\n let sum = 0;\n for (const [i, weight] of weights.entries()) {\n if (i >= 7) break;\n sum += Number(value[i]) * weight;\n }\n return sum % 11;\n};\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 \"EDRPOU must be exactly 8 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"EDRPOU must contain only digits\",\n );\n }\n\n const firstDigit = Number(v[0]);\n const useA = firstDigit < 3 || firstDigit >= 6;\n const weightsFirst = useA ? WEIGHTS_A : WEIGHTS_B;\n const weightsSecond = useA ? WEIGHTS_A2 : WEIGHTS_B2;\n\n let check = calcCheck(v, weightsFirst);\n if (check >= 10) {\n check = calcCheck(v, weightsSecond) % 10;\n }\n\n if (check !== Number(v[7])) {\n return err(\n \"INVALID_CHECKSUM\",\n \"EDRPOU check digit mismatch\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => compact(value);\n\n/** Generate a random valid Ukrainian EDRPOU. */\nconst generate = (): string => {\n for (;;) {\n const c = randomDigits(8);\n if (validate(c).valid) return c;\n }\n};\n\n/** Ukrainian Company Register Number. */\nconst edrpou: CountryValidator<\"UA\"> = {\n name: \"Ukrainian Company Register Number\",\n localName: \"ЄДРПОУ\",\n abbreviation: \"ЄДРПОУ\",\n aliases: [\"ЄДРПОУ\", \"EDRPOU\"] as const,\n candidatePattern: \"\\\\d{8}\",\n scope: \"country\",\n country: \"UA\",\n entityType: \"company\",\n lengths: [8] as const,\n sourceUrl: \"https://usr.minjust.gov.ua/\",\n examples: [\"14360570\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default edrpou;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;AAsBA,MAAM,YAAY;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AACtC,MAAM,YAAY;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AACtC,MAAM,aAAa;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AACvC,MAAM,aAAa;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AAEvC,MAAM,aACJ,OACA,YACW;CACX,IAAI,MAAM;CACV,KAAK,MAAM,CAAC,GAAG,WAAW,QAAQ,QAAQ,GAAG;EAC3C,IAAI,KAAK,GAAG;EACZ,OAAO,OAAO,MAAM,EAAE,IAAI;CAC5B;CACA,OAAO,MAAM;AACf;AAEA,MAAM,WAAW,UACf,MAAM,OAAO,IAAI;AAEnB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,GACf,OAAO,IACL,kBACA,iCACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,iCACF;CAGF,MAAM,aAAa,OAAO,EAAE,EAAE;CAC9B,MAAM,OAAO,aAAa,KAAK,cAAc;CAC7C,MAAM,eAAe,OAAO,YAAY;CACxC,MAAM,gBAAgB,OAAO,aAAa;CAE1C,IAAI,QAAQ,UAAU,GAAG,YAAY;CACrC,IAAI,SAAS,IACX,QAAQ,UAAU,GAAG,aAAa,IAAI;CAGxC,IAAI,UAAU,OAAO,EAAE,EAAE,GACvB,OAAO,IACL,oBACA,6BACF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B,QAAQ,KAAK;;AAGvD,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,IAAI,aAAa,CAAC;EACxB,IAAI,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"edrpou.js","names":[],"sources":["../../src/ua/edrpou.ts"],"sourcesContent":["/**\n * EDRPOU (ЄДРПОУ, Unified State Register of\n * Enterprises and Organizations of Ukraine).\n *\n * 8-digit company identification number with a\n * weighted checksum. Two sets of weights are used\n * depending on whether the first digit is 0-2/6-9 or 3-5.\n *\n * @see https://en.wikipedia.org/wiki/EDRPOU\n * @see https://usr.minjust.gov.ua/\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst WEIGHTS_A = [1, 2, 3, 4, 5, 6, 7] as const;\nconst WEIGHTS_B = [7, 1, 2, 3, 4, 5, 6] as const;\nconst WEIGHTS_A2 = [3, 4, 5, 6, 7, 8, 9] as const;\nconst WEIGHTS_B2 = [9, 3, 4, 5, 6, 7, 8] as const;\n\nconst calcCheck = (\n value: string,\n weights: readonly number[],\n): number => {\n let sum = 0;\n for (const [i, weight] of weights.entries()) {\n if (i >= 7) break;\n sum += Number(value[i]) * weight;\n }\n return sum % 11;\n};\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 \"EDRPOU must be exactly 8 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"EDRPOU must contain only digits\",\n );\n }\n\n const firstDigit = Number(v[0]);\n const useA = firstDigit < 3 || firstDigit >= 6;\n const weightsFirst = useA ? WEIGHTS_A : WEIGHTS_B;\n const weightsSecond = useA ? WEIGHTS_A2 : WEIGHTS_B2;\n\n let check = calcCheck(v, weightsFirst);\n if (check >= 10) {\n check = calcCheck(v, weightsSecond) % 10;\n }\n\n if (check !== Number(v[7])) {\n return err(\n \"INVALID_CHECKSUM\",\n \"EDRPOU check digit mismatch\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => compact(value);\n\n/** Generate a random valid Ukrainian EDRPOU. */\nconst generate = (): string => {\n for (;;) {\n const c = randomDigits(8);\n if (validate(c).valid) return c;\n }\n};\n\n/** Ukrainian Company Register Number. */\nconst edrpou: CountryValidator<\"UA\"> = {\n name: \"Ukrainian Company Register Number\",\n localName: \"ЄДРПОУ\",\n abbreviation: \"ЄДРПОУ\",\n aliases: [\"ЄДРПОУ\", \"EDRPOU\"] as const,\n candidatePattern: \"\\\\d{8}\",\n scope: \"country\",\n country: \"UA\",\n entityType: \"company\",\n lengths: [8] as const,\n sourceUrl: \"https://usr.minjust.gov.ua/\",\n examples: [\"14360570\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default edrpou;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;AAsBA,MAAM,YAAY;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AACtC,MAAM,YAAY;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AACtC,MAAM,aAAa;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AACvC,MAAM,aAAa;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AAEvC,MAAM,aACJ,OACA,YACW;CACX,IAAI,MAAM;CACV,KAAK,MAAM,CAAC,GAAG,WAAW,QAAQ,QAAQ,GAAG;EAC3C,IAAI,KAAK,GAAG;EACZ,OAAO,OAAO,MAAM,EAAE,IAAI;CAC5B;CACA,OAAO,MAAM;AACf;AAEA,MAAM,WAAW,UACf,MAAM,OAAO,IAAI;AAEnB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,GACf,OAAO,IACL,kBACA,iCACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,iCACF;CAGF,MAAM,aAAa,OAAO,EAAE,EAAE;CAC9B,MAAM,OAAO,aAAa,KAAK,cAAc;CAC7C,MAAM,eAAe,OAAO,YAAY;CACxC,MAAM,gBAAgB,OAAO,aAAa;CAE1C,IAAI,QAAQ,UAAU,GAAG,YAAY;CACrC,IAAI,SAAS,IACX,QAAQ,UAAU,GAAG,aAAa,IAAI;CAGxC,IAAI,UAAU,OAAO,EAAE,EAAE,GACvB,OAAO,IACL,oBACA,6BACF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B,QAAQ,KAAK;;AAGvD,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,IAAI,aAAa,CAAC;EACxB,IAAI,SAAS,CAAC,CAAC,CAAC,OAAO,OAAO;CAChC;AACF;;AAGA,MAAM,SAAiC;CACrC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,UAAU,QAAQ;CAC5B,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,SAAS,CAAC,CAAC;CACX,WAAW;CACX,UAAU,CAAC,UAAU;CACrB;CACA;CACA;CACA;AACF"}
|
package/dist/us/itin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"itin.js","names":[],"sources":["../../src/us/itin.ts"],"sourcesContent":["const ITIN_ALLOWED_GROUPS = Array.from(\n { length: 30 },\n (_, i) => i + 70,\n).filter((g) => g !== 89 && g !== 93);\n\n/** Generate a random valid U.S. ITIN. */\nconst generate = (): string => {\n const area = \"9\" + randomDigits(2);\n const group = String(randomPick(ITIN_ALLOWED_GROUPS));\n const serial = randomDigits(4);\n return `${area}${group}${serial}`;\n};\n\n/**\n * ITIN (U.S. Individual Taxpayer Identification\n * Number).\n *\n * 9-digit number issued by the IRS to individuals\n * who need a taxpayer ID but are not eligible for\n * an SSN. Starts with 9; digits 4-5 (the \"group\")\n * must be in the range 70-99 excluding 89 and 93.\n *\n * @see https://www.irs.gov/individuals/individual-taxpayer-identification-number\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits, randomPick } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst ITIN_RE = /^(?<area>\\d{3})-?(?<group>\\d{2})-?\\d{4}$/;\n\n/** Groups 70-99 excluding 89 and 93. */\nconst ALLOWED_GROUPS = new Set(\n Array.from({ length: 30 }, (_, i) => i + 70)\n .filter((g) => g !== 89 && g !== 93)\n .map(String),\n);\n\nconst compact = (value: string): string =>\n clean(value, \" -\");\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"ITIN must contain only digits\",\n );\n }\n if (v.length !== 9) {\n return err(\"INVALID_LENGTH\", \"ITIN must be 9 digits\");\n }\n\n const match = ITIN_RE.exec(v);\n if (!match?.groups) {\n return err(\n \"INVALID_FORMAT\",\n \"ITIN must be 9 digits, optionally \" +\n \"formatted as NNN-NN-NNNN\",\n );\n }\n\n const { area, group } = match.groups;\n if (!area || !group) {\n return err(\"INVALID_FORMAT\", \"ITIN must be 9 digits\");\n }\n\n if (area[0] !== \"9\") {\n return err(\n \"INVALID_COMPONENT\",\n \"ITIN area must start with 9\",\n );\n }\n\n if (!ALLOWED_GROUPS.has(group)) {\n return err(\n \"INVALID_COMPONENT\",\n \"ITIN group digits are not in the \" +\n \"allowed range (70-99 excl. 89, 93)\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n if (v.length === 9) {\n return (\n `${v.slice(0, 3)}-${v.slice(3, 5)}` + `-${v.slice(5)}`\n );\n }\n return v;\n};\n\n/**\n * U.S. Individual Taxpayer Identification Number.\n */\nconst itin: CountryValidator<\"US\"> = {\n name: \"Individual Taxpayer Identification Number\",\n localName: \"Individual Taxpayer Identification Number\",\n abbreviation: \"ITIN\",\n aliases: [\n \"ITIN\",\n \"Individual Taxpayer Identification Number\",\n ] as const,\n candidatePattern: \"9\\\\d{2}[\\\\s-]?\\\\d{2}[\\\\s-]?\\\\d{4}\",\n scope: \"country\",\n country: \"US\",\n entityType: \"person\",\n sourceUrl:\n \"https://www.irs.gov/individuals/\" +\n \"individual-taxpayer-identification-number\",\n lengths: [9] as const,\n examples: [\"912-90-3456\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default itin;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;AAAA,MAAM,sBAAsB,MAAM,KAChC,EAAE,QAAQ,GAAG,IACZ,GAAG,MAAM,IAAI,EAChB,
|
|
1
|
+
{"version":3,"file":"itin.js","names":[],"sources":["../../src/us/itin.ts"],"sourcesContent":["const ITIN_ALLOWED_GROUPS = Array.from(\n { length: 30 },\n (_, i) => i + 70,\n).filter((g) => g !== 89 && g !== 93);\n\n/** Generate a random valid U.S. ITIN. */\nconst generate = (): string => {\n const area = \"9\" + randomDigits(2);\n const group = String(randomPick(ITIN_ALLOWED_GROUPS));\n const serial = randomDigits(4);\n return `${area}${group}${serial}`;\n};\n\n/**\n * ITIN (U.S. Individual Taxpayer Identification\n * Number).\n *\n * 9-digit number issued by the IRS to individuals\n * who need a taxpayer ID but are not eligible for\n * an SSN. Starts with 9; digits 4-5 (the \"group\")\n * must be in the range 70-99 excluding 89 and 93.\n *\n * @see https://www.irs.gov/individuals/individual-taxpayer-identification-number\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits, randomPick } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst ITIN_RE = /^(?<area>\\d{3})-?(?<group>\\d{2})-?\\d{4}$/;\n\n/** Groups 70-99 excluding 89 and 93. */\nconst ALLOWED_GROUPS = new Set(\n Array.from({ length: 30 }, (_, i) => i + 70)\n .filter((g) => g !== 89 && g !== 93)\n .map(String),\n);\n\nconst compact = (value: string): string =>\n clean(value, \" -\");\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"ITIN must contain only digits\",\n );\n }\n if (v.length !== 9) {\n return err(\"INVALID_LENGTH\", \"ITIN must be 9 digits\");\n }\n\n const match = ITIN_RE.exec(v);\n if (!match?.groups) {\n return err(\n \"INVALID_FORMAT\",\n \"ITIN must be 9 digits, optionally \" +\n \"formatted as NNN-NN-NNNN\",\n );\n }\n\n const { area, group } = match.groups;\n if (!area || !group) {\n return err(\"INVALID_FORMAT\", \"ITIN must be 9 digits\");\n }\n\n if (area[0] !== \"9\") {\n return err(\n \"INVALID_COMPONENT\",\n \"ITIN area must start with 9\",\n );\n }\n\n if (!ALLOWED_GROUPS.has(group)) {\n return err(\n \"INVALID_COMPONENT\",\n \"ITIN group digits are not in the \" +\n \"allowed range (70-99 excl. 89, 93)\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n if (v.length === 9) {\n return (\n `${v.slice(0, 3)}-${v.slice(3, 5)}` + `-${v.slice(5)}`\n );\n }\n return v;\n};\n\n/**\n * U.S. Individual Taxpayer Identification Number.\n */\nconst itin: CountryValidator<\"US\"> = {\n name: \"Individual Taxpayer Identification Number\",\n localName: \"Individual Taxpayer Identification Number\",\n abbreviation: \"ITIN\",\n aliases: [\n \"ITIN\",\n \"Individual Taxpayer Identification Number\",\n ] as const,\n candidatePattern: \"9\\\\d{2}[\\\\s-]?\\\\d{2}[\\\\s-]?\\\\d{4}\",\n scope: \"country\",\n country: \"US\",\n entityType: \"person\",\n sourceUrl:\n \"https://www.irs.gov/individuals/\" +\n \"individual-taxpayer-identification-number\",\n lengths: [9] as const,\n examples: [\"912-90-3456\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default itin;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;AAAA,MAAM,sBAAsB,MAAM,KAChC,EAAE,QAAQ,GAAG,IACZ,GAAG,MAAM,IAAI,EAChB,CAAC,CAAC,QAAQ,MAAM,MAAM,MAAM,MAAM,EAAE;;AAGpC,MAAM,iBAAyB;CAI7B,OAAO,GAHM,MAAM,aAAa,CAAC,IACnB,OAAO,WAAW,mBAAmB,CAE9B,IADN,aAAa,CACE;AAChC;AAwBA,MAAM,UAAU;;AAGhB,MAAM,iBAAiB,IAAI,IACzB,MAAM,KAAK,EAAE,QAAQ,GAAG,IAAI,GAAG,MAAM,IAAI,EAAE,CAAC,CACzC,QAAQ,MAAM,MAAM,MAAM,MAAM,EAAE,CAAC,CACnC,IAAI,MAAM,CACf;AAEA,MAAM,WAAW,UACf,MAAM,OAAO,IAAI;AAEnB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,+BACF;CAEF,IAAI,EAAE,WAAW,GACf,OAAO,IAAI,kBAAkB,uBAAuB;CAGtD,MAAM,QAAQ,QAAQ,KAAK,CAAC;CAC5B,IAAI,CAAC,OAAO,QACV,OAAO,IACL,kBACA,4DAEF;CAGF,MAAM,EAAE,MAAM,UAAU,MAAM;CAC9B,IAAI,CAAC,QAAQ,CAAC,OACZ,OAAO,IAAI,kBAAkB,uBAAuB;CAGtD,IAAI,KAAK,OAAO,KACd,OAAO,IACL,qBACA,6BACF;CAGF,IAAI,CAAC,eAAe,IAAI,KAAK,GAC3B,OAAO,IACL,qBACA,qEAEF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,GACf,OACE,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,EAAA,GAAU,EAAE,MAAM,CAAC;CAGvD,OAAO;AACT;;;;AAKA,MAAM,OAA+B;CACnC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CACP,QACA,2CACF;CACA,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,WACE;CAEF,SAAS,CAAC,CAAC;CACX,UAAU,CAAC,aAAa;CACxB;CACA;CACA;CACA;AACF"}
|
package/dist/us/rtn.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rtn.js","names":[],"sources":["../../src/us/rtn.ts"],"sourcesContent":["/**\n * RTN (Routing Transit Number / ABA Number).\n *\n * 9-digit number used by U.S. financial institutions\n * for routing wire transfers, ACH, and check\n * processing. Uses a weighted checksum with weights\n * [3, 7, 1] repeated three times.\n *\n * The first two digits identify the Federal Reserve\n * district (01-12) or special ranges (00 for U.S.\n * Government, 21-32 for thrifts, 61-72 for electronic,\n * 80 for traveler's cheques).\n *\n * @see https://en.wikipedia.org/wiki/ABA_routing_transit_number\n * @see https://www.frbservices.org/\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport {\n randomDigits,\n randomInt,\n randomPick,\n} from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst WEIGHTS = [3, 7, 1, 3, 7, 1, 3, 7, 1] as const;\n\nconst compact = (value: string): string =>\n clean(value, \" -\").trim();\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 9) {\n return err(\"INVALID_LENGTH\", \"RTN must be 9 digits\");\n }\n\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"RTN must contain only digits\",\n );\n }\n\n // Validate Federal Reserve prefix (first 2 digits)\n const prefix = Number(v.slice(0, 2));\n const validPrefixRanges =\n // 00 is reserved for U.S. Government and federal\n // agencies per the ABA Routing Number Policy;\n // 01-12 are the 12 Federal Reserve districts.\n // @see https://en.wikipedia.org/wiki/ABA_routing_transit_number\n (prefix >= 0 && prefix <= 12) ||\n (prefix >= 21 && prefix <= 32) ||\n (prefix >= 61 && prefix <= 72) ||\n prefix === 80;\n if (!validPrefixRanges) {\n return err(\n \"INVALID_COMPONENT\",\n \"RTN has an invalid Federal Reserve district\",\n );\n }\n\n // Weighted checksum must be divisible by 10\n let sum = 0;\n for (const [i, weight] of WEIGHTS.entries()) {\n sum += Number(v[i]) * weight;\n }\n if (sum % 10 !== 0) {\n return err(\n \"INVALID_CHECKSUM\",\n \"RTN checksum is invalid\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => compact(value);\n\n/** All valid Federal Reserve prefix ranges. */\nconst PREFIX_RANGES: readonly [number, number][] = [\n [0, 12],\n [21, 32],\n [61, 72],\n [80, 80],\n];\n\n/** Generate a random valid U.S. RTN. */\nconst generate = (): string => {\n const [low, high] = randomPick(PREFIX_RANGES);\n const prefix = String(randomInt(low, high)).padStart(\n 2,\n \"0\",\n );\n const mid = randomDigits(6);\n const body = prefix + mid;\n let sum = 0;\n for (const [i, weight] of WEIGHTS.entries()) {\n if (i >= 8) break;\n sum += Number(body[i]) * weight;\n }\n const check = (10 - (sum % 10)) % 10;\n return body + String(check);\n};\n\n/** U.S. Routing Transit Number. */\nconst rtn: CountryValidator<\"US\"> = {\n name: \"Routing Transit Number\",\n localName: \"Routing Transit Number\",\n abbreviation: \"RTN\",\n aliases: [\n \"RTN\",\n \"ABA\",\n \"Routing Number\",\n \"ABA Routing Number\",\n \"Routing Transit Number\",\n ] as const,\n candidatePattern: \"\\\\d{9}\",\n scope: \"country\",\n country: \"US\",\n entityType: \"company\",\n sourceUrl:\n \"https://en.wikipedia.org/wiki/ABA_routing_transit_number\",\n lengths: [9] as const,\n examples: [\"111000025\", \"021000021\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default rtn;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;AA+BA,MAAM,UAAU;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AAE1C,MAAM,WAAW,UACf,MAAM,OAAO,IAAI,
|
|
1
|
+
{"version":3,"file":"rtn.js","names":[],"sources":["../../src/us/rtn.ts"],"sourcesContent":["/**\n * RTN (Routing Transit Number / ABA Number).\n *\n * 9-digit number used by U.S. financial institutions\n * for routing wire transfers, ACH, and check\n * processing. Uses a weighted checksum with weights\n * [3, 7, 1] repeated three times.\n *\n * The first two digits identify the Federal Reserve\n * district (01-12) or special ranges (00 for U.S.\n * Government, 21-32 for thrifts, 61-72 for electronic,\n * 80 for traveler's cheques).\n *\n * @see https://en.wikipedia.org/wiki/ABA_routing_transit_number\n * @see https://www.frbservices.org/\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport {\n randomDigits,\n randomInt,\n randomPick,\n} from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst WEIGHTS = [3, 7, 1, 3, 7, 1, 3, 7, 1] as const;\n\nconst compact = (value: string): string =>\n clean(value, \" -\").trim();\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 9) {\n return err(\"INVALID_LENGTH\", \"RTN must be 9 digits\");\n }\n\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"RTN must contain only digits\",\n );\n }\n\n // Validate Federal Reserve prefix (first 2 digits)\n const prefix = Number(v.slice(0, 2));\n const validPrefixRanges =\n // 00 is reserved for U.S. Government and federal\n // agencies per the ABA Routing Number Policy;\n // 01-12 are the 12 Federal Reserve districts.\n // @see https://en.wikipedia.org/wiki/ABA_routing_transit_number\n (prefix >= 0 && prefix <= 12) ||\n (prefix >= 21 && prefix <= 32) ||\n (prefix >= 61 && prefix <= 72) ||\n prefix === 80;\n if (!validPrefixRanges) {\n return err(\n \"INVALID_COMPONENT\",\n \"RTN has an invalid Federal Reserve district\",\n );\n }\n\n // Weighted checksum must be divisible by 10\n let sum = 0;\n for (const [i, weight] of WEIGHTS.entries()) {\n sum += Number(v[i]) * weight;\n }\n if (sum % 10 !== 0) {\n return err(\n \"INVALID_CHECKSUM\",\n \"RTN checksum is invalid\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => compact(value);\n\n/** All valid Federal Reserve prefix ranges. */\nconst PREFIX_RANGES: readonly [number, number][] = [\n [0, 12],\n [21, 32],\n [61, 72],\n [80, 80],\n];\n\n/** Generate a random valid U.S. RTN. */\nconst generate = (): string => {\n const [low, high] = randomPick(PREFIX_RANGES);\n const prefix = String(randomInt(low, high)).padStart(\n 2,\n \"0\",\n );\n const mid = randomDigits(6);\n const body = prefix + mid;\n let sum = 0;\n for (const [i, weight] of WEIGHTS.entries()) {\n if (i >= 8) break;\n sum += Number(body[i]) * weight;\n }\n const check = (10 - (sum % 10)) % 10;\n return body + String(check);\n};\n\n/** U.S. Routing Transit Number. */\nconst rtn: CountryValidator<\"US\"> = {\n name: \"Routing Transit Number\",\n localName: \"Routing Transit Number\",\n abbreviation: \"RTN\",\n aliases: [\n \"RTN\",\n \"ABA\",\n \"Routing Number\",\n \"ABA Routing Number\",\n \"Routing Transit Number\",\n ] as const,\n candidatePattern: \"\\\\d{9}\",\n scope: \"country\",\n country: \"US\",\n entityType: \"company\",\n sourceUrl:\n \"https://en.wikipedia.org/wiki/ABA_routing_transit_number\",\n lengths: [9] as const,\n examples: [\"111000025\", \"021000021\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default rtn;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;AA+BA,MAAM,UAAU;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AAE1C,MAAM,WAAW,UACf,MAAM,OAAO,IAAI,CAAC,CAAC,KAAK;AAE1B,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CAEvB,IAAI,EAAE,WAAW,GACf,OAAO,IAAI,kBAAkB,sBAAsB;CAGrD,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,8BACF;CAIF,MAAM,SAAS,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAUnC,IAAI,EAJD,UAAU,KAAK,UAAU,MACzB,UAAU,MAAM,UAAU,MAC1B,UAAU,MAAM,UAAU,MAC3B,WAAW,KAEX,OAAO,IACL,qBACA,6CACF;CAIF,IAAI,MAAM;CACV,KAAK,MAAM,CAAC,GAAG,WAAW,QAAQ,QAAQ,GACxC,OAAO,OAAO,EAAE,EAAE,IAAI;CAExB,IAAI,MAAM,OAAO,GACf,OAAO,IACL,oBACA,yBACF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B,QAAQ,KAAK;;AAGvD,MAAM,gBAA6C;CACjD,CAAC,GAAG,EAAE;CACN,CAAC,IAAI,EAAE;CACP,CAAC,IAAI,EAAE;CACP,CAAC,IAAI,EAAE;AACT;;AAGA,MAAM,iBAAyB;CAC7B,MAAM,CAAC,KAAK,QAAQ,WAAW,aAAa;CAM5C,MAAM,OALS,OAAO,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,SAC1C,GACA,GAGgB,IADN,aAAa,CACD;CACxB,IAAI,MAAM;CACV,KAAK,MAAM,CAAC,GAAG,WAAW,QAAQ,QAAQ,GAAG;EAC3C,IAAI,KAAK,GAAG;EACZ,OAAO,OAAO,KAAK,EAAE,IAAI;CAC3B;CACA,MAAM,SAAS,KAAM,MAAM,MAAO;CAClC,OAAO,OAAO,OAAO,KAAK;AAC5B;;AAGA,MAAM,MAA8B;CAClC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS;EACP;EACA;EACA;EACA;EACA;CACF;CACA,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,WACE;CACF,SAAS,CAAC,CAAC;CACX,UAAU,CAAC,aAAa,WAAW;CACnC;CACA;CACA;CACA;AACF"}
|
package/dist/us/ssn.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssn.js","names":[],"sources":["../../src/us/ssn.ts"],"sourcesContent":["/** Generate a random valid U.S. SSN. */\nconst generate = (): string => {\n for (;;) {\n let area: string;\n do {\n area = String(randomInt(1, 899)).padStart(3, \"0\");\n } while (area === \"666\");\n const group = String(randomInt(1, 99)).padStart(2, \"0\");\n const serial = String(randomInt(1, 9999)).padStart(\n 4,\n \"0\",\n );\n const ssn = `${area}${group}${serial}`;\n if (!BLACKLIST.has(ssn)) return ssn;\n }\n};\n\n/**\n * SSN (U.S. Social Security Number).\n *\n * 9-digit identifier: 3-digit area, 2-digit group,\n * 4-digit serial. No checksum. Area cannot be 000,\n * 666, or 900-999; group cannot be 00; serial\n * cannot be 0000.\n *\n * @see https://en.wikipedia.org/wiki/Social_Security_number\n * @see https://www.ssa.gov/employer/verifySSN.htm\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\";\nimport { isdigits } from \"#util/strings\";\n\n/** Known-invalid SSNs used in advertisements. */\nconst BLACKLIST = new Set([\n \"078051120\",\n \"457555462\",\n \"219099999\",\n]);\n\nconst compact = (value: string): string =>\n clean(value, \" -\");\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"SSN must contain only digits\",\n );\n }\n if (v.length !== 9) {\n return err(\"INVALID_LENGTH\", \"SSN must be 9 digits\");\n }\n\n const area = v.slice(0, 3);\n const group = v.slice(3, 5);\n const serial = v.slice(5, 9);\n\n if (area === \"000\" || area === \"666\" || area[0] === \"9\") {\n return err(\n \"INVALID_COMPONENT\",\n \"SSN area number is invalid\",\n );\n }\n if (group === \"00\") {\n return err(\n \"INVALID_COMPONENT\",\n \"SSN group number cannot be 00\",\n );\n }\n if (serial === \"0000\") {\n return err(\n \"INVALID_COMPONENT\",\n \"SSN serial number cannot be 0000\",\n );\n }\n if (BLACKLIST.has(v)) {\n return err(\n \"INVALID_COMPONENT\",\n \"SSN is on the blacklist\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n if (v.length === 9) {\n return `${v.slice(0, 3)}-${v.slice(3, 5)}-${v.slice(5)}`;\n }\n return v;\n};\n\n/** U.S. Social Security Number. */\nconst ssn: CountryValidator<\"US\"> = {\n name: \"Social Security Number\",\n localName: \"Social Security Number\",\n abbreviation: \"SSN\",\n aliases: [\"SSN\", \"Social Security Number\"] as const,\n candidatePattern: \"\\\\d{3}-?\\\\d{2}-?\\\\d{4}\",\n scope: \"country\",\n country: \"US\",\n entityType: \"person\",\n sourceUrl: \"https://www.ssa.gov/employer/verifySSN.htm\",\n examples: [\"536904399\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default ssn;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;AACA,MAAM,iBAAyB;CAC7B,SAAS;EACP,IAAI;EACJ;GACE,OAAO,OAAO,UAAU,GAAG,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"ssn.js","names":[],"sources":["../../src/us/ssn.ts"],"sourcesContent":["/** Generate a random valid U.S. SSN. */\nconst generate = (): string => {\n for (;;) {\n let area: string;\n do {\n area = String(randomInt(1, 899)).padStart(3, \"0\");\n } while (area === \"666\");\n const group = String(randomInt(1, 99)).padStart(2, \"0\");\n const serial = String(randomInt(1, 9999)).padStart(\n 4,\n \"0\",\n );\n const ssn = `${area}${group}${serial}`;\n if (!BLACKLIST.has(ssn)) return ssn;\n }\n};\n\n/**\n * SSN (U.S. Social Security Number).\n *\n * 9-digit identifier: 3-digit area, 2-digit group,\n * 4-digit serial. No checksum. Area cannot be 000,\n * 666, or 900-999; group cannot be 00; serial\n * cannot be 0000.\n *\n * @see https://en.wikipedia.org/wiki/Social_Security_number\n * @see https://www.ssa.gov/employer/verifySSN.htm\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\";\nimport { isdigits } from \"#util/strings\";\n\n/** Known-invalid SSNs used in advertisements. */\nconst BLACKLIST = new Set([\n \"078051120\",\n \"457555462\",\n \"219099999\",\n]);\n\nconst compact = (value: string): string =>\n clean(value, \" -\");\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"SSN must contain only digits\",\n );\n }\n if (v.length !== 9) {\n return err(\"INVALID_LENGTH\", \"SSN must be 9 digits\");\n }\n\n const area = v.slice(0, 3);\n const group = v.slice(3, 5);\n const serial = v.slice(5, 9);\n\n if (area === \"000\" || area === \"666\" || area[0] === \"9\") {\n return err(\n \"INVALID_COMPONENT\",\n \"SSN area number is invalid\",\n );\n }\n if (group === \"00\") {\n return err(\n \"INVALID_COMPONENT\",\n \"SSN group number cannot be 00\",\n );\n }\n if (serial === \"0000\") {\n return err(\n \"INVALID_COMPONENT\",\n \"SSN serial number cannot be 0000\",\n );\n }\n if (BLACKLIST.has(v)) {\n return err(\n \"INVALID_COMPONENT\",\n \"SSN is on the blacklist\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n if (v.length === 9) {\n return `${v.slice(0, 3)}-${v.slice(3, 5)}-${v.slice(5)}`;\n }\n return v;\n};\n\n/** U.S. Social Security Number. */\nconst ssn: CountryValidator<\"US\"> = {\n name: \"Social Security Number\",\n localName: \"Social Security Number\",\n abbreviation: \"SSN\",\n aliases: [\"SSN\", \"Social Security Number\"] as const,\n candidatePattern: \"\\\\d{3}-?\\\\d{2}-?\\\\d{4}\",\n scope: \"country\",\n country: \"US\",\n entityType: \"person\",\n sourceUrl: \"https://www.ssa.gov/employer/verifySSN.htm\",\n examples: [\"536904399\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default ssn;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;AACA,MAAM,iBAAyB;CAC7B,SAAS;EACP,IAAI;EACJ;GACE,OAAO,OAAO,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;SACzC,SAAS;EAClB,MAAM,QAAQ,OAAO,UAAU,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;EACtD,MAAM,SAAS,OAAO,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,SACxC,GACA,GACF;EACA,MAAM,MAAM,GAAG,OAAO,QAAQ;EAC9B,IAAI,CAAC,UAAU,IAAI,GAAG,GAAG,OAAO;CAClC;AACF;;AAyBA,MAAM,YAAY,IAAI,IAAI;CACxB;CACA;CACA;AACF,CAAC;AAED,MAAM,WAAW,UACf,MAAM,OAAO,IAAI;AAEnB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,8BACF;CAEF,IAAI,EAAE,WAAW,GACf,OAAO,IAAI,kBAAkB,sBAAsB;CAGrD,MAAM,OAAO,EAAE,MAAM,GAAG,CAAC;CACzB,MAAM,QAAQ,EAAE,MAAM,GAAG,CAAC;CAC1B,MAAM,SAAS,EAAE,MAAM,GAAG,CAAC;CAE3B,IAAI,SAAS,SAAS,SAAS,SAAS,KAAK,OAAO,KAClD,OAAO,IACL,qBACA,4BACF;CAEF,IAAI,UAAU,MACZ,OAAO,IACL,qBACA,+BACF;CAEF,IAAI,WAAW,QACb,OAAO,IACL,qBACA,kCACF;CAEF,IAAI,UAAU,IAAI,CAAC,GACjB,OAAO,IACL,qBACA,yBACF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,GACf,OAAO,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC;CAEvD,OAAO;AACT;;AAGA,MAAM,MAA8B;CAClC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,OAAO,wBAAwB;CACzC,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,WAAW;CACX,UAAU,CAAC,WAAW;CACtB;CACA;CACA;CACA;AACF"}
|
package/dist/uy/rut.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rut.js","names":[],"sources":["../../src/uy/rut.ts"],"sourcesContent":["/**\n * RUT (Registro Único Tributario).\n *\n * Uruguayan tax identification number issued by the\n * DGI (Dirección General Impositiva). The number is\n * 12 digits: 2-digit document type (01-22), 6-digit\n * sequence, fixed \"001\" suffix, and a check digit\n * computed via weighted sum mod 11 (Python-style\n * modulo of the negated sum).\n *\n * Format: ############ (12 digits compact)\n *\n * @see https://www.agesic.gub.uy/\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 WEIGHTS = [4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2] as const;\n\nconst compact = (value: string): string => {\n let v = clean(value, \" -\").trim();\n if (v.toUpperCase().startsWith(\"UY\")) {\n v = v.slice(2);\n }\n return v;\n};\n\n/**\n * Python-style modulo: always returns a non-negative\n * result for a positive divisor.\n */\nconst pymod = (a: number, b: number): number =>\n ((a % b) + b) % b;\n\nconst calcCheckDigit = (value: string): string | null => {\n let sum = 0;\n for (const [i, weight] of WEIGHTS.entries()) {\n sum += Number(value[i]) * weight;\n }\n const result = pymod(-sum, 11);\n // A result of 10 means no valid single-digit check\n // digit exists; the DGI does not issue such numbers.\n if (result === 10) return null;\n return String(result);\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 12) {\n return err(\"INVALID_LENGTH\", \"RUT must be 12 digits\");\n }\n\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"RUT must contain only digits\",\n );\n }\n\n // First 2 digits: document type (01-22)\n const docType = Number.parseInt(v.slice(0, 2), 10);\n if (docType < 1 || docType > 22) {\n return err(\n \"INVALID_COMPONENT\",\n \"RUT document type must be between 01 and 22\",\n );\n }\n\n // Digits 2-8: sequence (must not be all zeros)\n if (v.slice(2, 8) === \"000000\") {\n return err(\n \"INVALID_COMPONENT\",\n \"RUT sequence must not be all zeros\",\n );\n }\n\n // Digits 8-11: must be \"001\"\n if (v.slice(8, 11) !== \"001\") {\n return err(\n \"INVALID_COMPONENT\",\n \"RUT branch code must be 001\",\n );\n }\n\n const expected = calcCheckDigit(v);\n if (expected === null || v.at(-1) !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"RUT check digit does not match\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n return `${v.slice(0, 2)}-${v.slice(2, 8)}-${v.slice(8, 11)}-${v.slice(11)}`;\n};\n\n/** Generate a random valid Uruguayan RUT. */\nconst generate = (): string => {\n for (;;) {\n const docType = String(randomInt(1, 22)).padStart(\n 2,\n \"0\",\n );\n const seq = randomDigits(6);\n if (seq === \"000000\") continue;\n const partial = `${docType}${seq}001`;\n const check = calcCheckDigit(partial);\n if (check === null) continue;\n return `${partial}${check}`;\n }\n};\n\n/**\n * Uruguayan RUT (tax identification number).\n *\n * Examples sourced from python-stdnum test suite.\n */\nconst rut: CountryValidator<\"UY\"> = {\n name: \"Uruguayan Tax ID\",\n localName: \"Registro Único Tributario\",\n abbreviation: \"RUT\",\n aliases: [\"RUT\", \"Registro Único Tributario\"] as const,\n candidatePattern: \"\\\\d{12}\",\n scope: \"country\",\n country: \"UY\",\n entityType: \"any\",\n lengths: [12] as const,\n examples: [\"010100010013\", \"102000010017\"] as const,\n compact,\n format,\n validate,\n sourceUrl: \"https://www.agesic.gub.uy/\",\n generate,\n};\n\nexport default rut;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;AAyBA,MAAM,UAAU;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AAEhD,MAAM,WAAW,UAA0B;CACzC,IAAI,IAAI,MAAM,OAAO,IAAI,
|
|
1
|
+
{"version":3,"file":"rut.js","names":[],"sources":["../../src/uy/rut.ts"],"sourcesContent":["/**\n * RUT (Registro Único Tributario).\n *\n * Uruguayan tax identification number issued by the\n * DGI (Dirección General Impositiva). The number is\n * 12 digits: 2-digit document type (01-22), 6-digit\n * sequence, fixed \"001\" suffix, and a check digit\n * computed via weighted sum mod 11 (Python-style\n * modulo of the negated sum).\n *\n * Format: ############ (12 digits compact)\n *\n * @see https://www.agesic.gub.uy/\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 WEIGHTS = [4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2] as const;\n\nconst compact = (value: string): string => {\n let v = clean(value, \" -\").trim();\n if (v.toUpperCase().startsWith(\"UY\")) {\n v = v.slice(2);\n }\n return v;\n};\n\n/**\n * Python-style modulo: always returns a non-negative\n * result for a positive divisor.\n */\nconst pymod = (a: number, b: number): number =>\n ((a % b) + b) % b;\n\nconst calcCheckDigit = (value: string): string | null => {\n let sum = 0;\n for (const [i, weight] of WEIGHTS.entries()) {\n sum += Number(value[i]) * weight;\n }\n const result = pymod(-sum, 11);\n // A result of 10 means no valid single-digit check\n // digit exists; the DGI does not issue such numbers.\n if (result === 10) return null;\n return String(result);\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 12) {\n return err(\"INVALID_LENGTH\", \"RUT must be 12 digits\");\n }\n\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"RUT must contain only digits\",\n );\n }\n\n // First 2 digits: document type (01-22)\n const docType = Number.parseInt(v.slice(0, 2), 10);\n if (docType < 1 || docType > 22) {\n return err(\n \"INVALID_COMPONENT\",\n \"RUT document type must be between 01 and 22\",\n );\n }\n\n // Digits 2-8: sequence (must not be all zeros)\n if (v.slice(2, 8) === \"000000\") {\n return err(\n \"INVALID_COMPONENT\",\n \"RUT sequence must not be all zeros\",\n );\n }\n\n // Digits 8-11: must be \"001\"\n if (v.slice(8, 11) !== \"001\") {\n return err(\n \"INVALID_COMPONENT\",\n \"RUT branch code must be 001\",\n );\n }\n\n const expected = calcCheckDigit(v);\n if (expected === null || v.at(-1) !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"RUT check digit does not match\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n return `${v.slice(0, 2)}-${v.slice(2, 8)}-${v.slice(8, 11)}-${v.slice(11)}`;\n};\n\n/** Generate a random valid Uruguayan RUT. */\nconst generate = (): string => {\n for (;;) {\n const docType = String(randomInt(1, 22)).padStart(\n 2,\n \"0\",\n );\n const seq = randomDigits(6);\n if (seq === \"000000\") continue;\n const partial = `${docType}${seq}001`;\n const check = calcCheckDigit(partial);\n if (check === null) continue;\n return `${partial}${check}`;\n }\n};\n\n/**\n * Uruguayan RUT (tax identification number).\n *\n * Examples sourced from python-stdnum test suite.\n */\nconst rut: CountryValidator<\"UY\"> = {\n name: \"Uruguayan Tax ID\",\n localName: \"Registro Único Tributario\",\n abbreviation: \"RUT\",\n aliases: [\"RUT\", \"Registro Único Tributario\"] as const,\n candidatePattern: \"\\\\d{12}\",\n scope: \"country\",\n country: \"UY\",\n entityType: \"any\",\n lengths: [12] as const,\n examples: [\"010100010013\", \"102000010017\"] as const,\n compact,\n format,\n validate,\n sourceUrl: \"https://www.agesic.gub.uy/\",\n generate,\n};\n\nexport default rut;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;AAyBA,MAAM,UAAU;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AAEhD,MAAM,WAAW,UAA0B;CACzC,IAAI,IAAI,MAAM,OAAO,IAAI,CAAC,CAAC,KAAK;CAChC,IAAI,EAAE,YAAY,CAAC,CAAC,WAAW,IAAI,GACjC,IAAI,EAAE,MAAM,CAAC;CAEf,OAAO;AACT;;;;;AAMA,MAAM,SAAS,GAAW,OACtB,IAAI,IAAK,KAAK;AAElB,MAAM,kBAAkB,UAAiC;CACvD,IAAI,MAAM;CACV,KAAK,MAAM,CAAC,GAAG,WAAW,QAAQ,QAAQ,GACxC,OAAO,OAAO,MAAM,EAAE,IAAI;CAE5B,MAAM,SAAS,MAAM,CAAC,KAAK,EAAE;CAG7B,IAAI,WAAW,IAAI,OAAO;CAC1B,OAAO,OAAO,MAAM;AACtB;AAEA,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CAEvB,IAAI,EAAE,WAAW,IACf,OAAO,IAAI,kBAAkB,uBAAuB;CAGtD,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,8BACF;CAIF,MAAM,UAAU,OAAO,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE;CACjD,IAAI,UAAU,KAAK,UAAU,IAC3B,OAAO,IACL,qBACA,6CACF;CAIF,IAAI,EAAE,MAAM,GAAG,CAAC,MAAM,UACpB,OAAO,IACL,qBACA,oCACF;CAIF,IAAI,EAAE,MAAM,GAAG,EAAE,MAAM,OACrB,OAAO,IACL,qBACA,6BACF;CAGF,MAAM,WAAW,eAAe,CAAC;CACjC,IAAI,aAAa,QAAQ,EAAE,GAAG,EAAE,MAAM,UACpC,OAAO,IACL,oBACA,gCACF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,KAAK;CACvB,OAAO,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE;AAC1E;;AAGA,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,UAAU,OAAO,UAAU,GAAG,EAAE,CAAC,CAAC,CAAC,SACvC,GACA,GACF;EACA,MAAM,MAAM,aAAa,CAAC;EAC1B,IAAI,QAAQ,UAAU;EACtB,MAAM,UAAU,GAAG,UAAU,IAAI;EACjC,MAAM,QAAQ,eAAe,OAAO;EACpC,IAAI,UAAU,MAAM;EACpB,OAAO,GAAG,UAAU;CACtB;AACF;;;;;;AAOA,MAAM,MAA8B;CAClC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,OAAO,2BAA2B;CAC5C,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,SAAS,CAAC,EAAE;CACZ,UAAU,CAAC,gBAAgB,cAAc;CACzC;CACA;CACA;CACA,WAAW;CACX;AACF"}
|
package/dist/ve/rif.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rif.js","names":[],"sources":["../../src/ve/rif.ts"],"sourcesContent":["/**\n * RIF (Registro de Información Fiscal).\n *\n * Venezuelan tax identification number issued by the\n * SENIAT. The number consists of 1 letter indicating\n * the entity type (J=juridical, G=government,\n * V=natural/Venezuelan, E=foreign, P=passport)\n * followed by 8 digits and a check digit computed\n * via weighted sum mod 11.\n *\n * Format: X-########-# or X######### (10 chars compact)\n *\n * @see https://en.wikipedia.org/wiki/Tax_Identification_Number#Venezuela\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits, randomPick } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\n/**\n * Map prefix letter to its numeric offset used\n * in the check digit computation.\n */\nconst PREFIX_VALUES: Record<string, number> = {\n V: 4,\n E: 8,\n J: 12,\n P: 16,\n G: 20,\n};\n\n/** Weights applied to the 8-digit body. */\nconst WEIGHTS = [3, 2, 7, 6, 5, 4, 3, 2] as const;\n\n/**\n * Lookup table for converting the mod 11 result\n * to the check character.\n */\nconst CHECK_LOOKUP = \"00987654321\";\n\nconst compact = (value: string): string =>\n clean(value, \" -.\").trim().toUpperCase();\n\nconst calcCheckDigit = (\n prefix: string,\n body: string,\n): string => {\n const pv = PREFIX_VALUES[prefix] ?? 0;\n let sum = 0;\n for (const [i, weight] of WEIGHTS.entries()) {\n sum += Number(body[i]) * weight;\n }\n const digit = (pv + (sum % 11)) % 11;\n // SAFETY: digit ∈ [0, 10] and CHECK_LOOKUP has 11 chars.\n // eslint-disable-next-line no-non-null-assertion\n return CHECK_LOOKUP[digit]!;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 10) {\n return err(\n \"INVALID_LENGTH\",\n \"RIF must be 10 characters\",\n );\n }\n\n // SAFETY: length check above guarantees v[0] exists.\n // eslint-disable-next-line no-non-null-assertion\n const prefix = v[0]!;\n if (!(prefix in PREFIX_VALUES)) {\n return err(\n \"INVALID_COMPONENT\",\n \"RIF must start with V, E, J, P, or G\",\n );\n }\n\n const body = v.slice(1, 9);\n const check = v.slice(9);\n if (!isdigits(v.slice(1))) {\n return err(\n \"INVALID_FORMAT\",\n \"RIF body must contain only digits\",\n );\n }\n\n const expected = calcCheckDigit(prefix, body);\n if (check !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"RIF check digit does not match\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n return `${v[0]}-${v.slice(1, 9)}-${v.slice(9)}`;\n};\n\nconst GENERATE_TYPES = [\"V\", \"E\", \"J\", \"P\", \"G\"] as const;\n\n/** Generate a random valid Venezuelan RIF. */\nconst generate = (): string => {\n const prefix = randomPick(GENERATE_TYPES);\n const body = randomDigits(8);\n return prefix + body + calcCheckDigit(prefix, body);\n};\n\n/**\n * Venezuelan RIF (tax identification number).\n *\n * Examples sourced from python-stdnum test suite.\n */\nconst rif: CountryValidator<\"VE\"> = {\n name: \"Venezuelan Tax ID\",\n localName: \"Registro de Información Fiscal\",\n abbreviation: \"RIF\",\n aliases: [\n \"RIF\",\n \"Registro de Información Fiscal\",\n ] as const,\n candidatePattern: \"[VEJPG]-?\\\\d{8}-?\\\\d\",\n scope: \"country\",\n country: \"VE\",\n entityType: \"any\",\n lengths: [10] as const,\n examples: [\"V309876543\", \"J309876546\"] as const,\n compact,\n format,\n validate,\n sourceUrl:\n \"https://en.wikipedia.org/wiki/Tax_Identification_Number#Venezuela\",\n generate,\n};\n\nexport default rif;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;;;;AA6BA,MAAM,gBAAwC;CAC5C,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;AACL;;AAGA,MAAM,UAAU;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;;;;;AAMvC,MAAM,eAAe;AAErB,MAAM,WAAW,UACf,MAAM,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"rif.js","names":[],"sources":["../../src/ve/rif.ts"],"sourcesContent":["/**\n * RIF (Registro de Información Fiscal).\n *\n * Venezuelan tax identification number issued by the\n * SENIAT. The number consists of 1 letter indicating\n * the entity type (J=juridical, G=government,\n * V=natural/Venezuelan, E=foreign, P=passport)\n * followed by 8 digits and a check digit computed\n * via weighted sum mod 11.\n *\n * Format: X-########-# or X######### (10 chars compact)\n *\n * @see https://en.wikipedia.org/wiki/Tax_Identification_Number#Venezuela\n */\n\nimport type {\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport { clean } from \"#util/clean\";\nimport { randomDigits, randomPick } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\n/**\n * Map prefix letter to its numeric offset used\n * in the check digit computation.\n */\nconst PREFIX_VALUES: Record<string, number> = {\n V: 4,\n E: 8,\n J: 12,\n P: 16,\n G: 20,\n};\n\n/** Weights applied to the 8-digit body. */\nconst WEIGHTS = [3, 2, 7, 6, 5, 4, 3, 2] as const;\n\n/**\n * Lookup table for converting the mod 11 result\n * to the check character.\n */\nconst CHECK_LOOKUP = \"00987654321\";\n\nconst compact = (value: string): string =>\n clean(value, \" -.\").trim().toUpperCase();\n\nconst calcCheckDigit = (\n prefix: string,\n body: string,\n): string => {\n const pv = PREFIX_VALUES[prefix] ?? 0;\n let sum = 0;\n for (const [i, weight] of WEIGHTS.entries()) {\n sum += Number(body[i]) * weight;\n }\n const digit = (pv + (sum % 11)) % 11;\n // SAFETY: digit ∈ [0, 10] and CHECK_LOOKUP has 11 chars.\n // eslint-disable-next-line no-non-null-assertion\n return CHECK_LOOKUP[digit]!;\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 10) {\n return err(\n \"INVALID_LENGTH\",\n \"RIF must be 10 characters\",\n );\n }\n\n // SAFETY: length check above guarantees v[0] exists.\n // eslint-disable-next-line no-non-null-assertion\n const prefix = v[0]!;\n if (!(prefix in PREFIX_VALUES)) {\n return err(\n \"INVALID_COMPONENT\",\n \"RIF must start with V, E, J, P, or G\",\n );\n }\n\n const body = v.slice(1, 9);\n const check = v.slice(9);\n if (!isdigits(v.slice(1))) {\n return err(\n \"INVALID_FORMAT\",\n \"RIF body must contain only digits\",\n );\n }\n\n const expected = calcCheckDigit(prefix, body);\n if (check !== expected) {\n return err(\n \"INVALID_CHECKSUM\",\n \"RIF check digit does not match\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n return `${v[0]}-${v.slice(1, 9)}-${v.slice(9)}`;\n};\n\nconst GENERATE_TYPES = [\"V\", \"E\", \"J\", \"P\", \"G\"] as const;\n\n/** Generate a random valid Venezuelan RIF. */\nconst generate = (): string => {\n const prefix = randomPick(GENERATE_TYPES);\n const body = randomDigits(8);\n return prefix + body + calcCheckDigit(prefix, body);\n};\n\n/**\n * Venezuelan RIF (tax identification number).\n *\n * Examples sourced from python-stdnum test suite.\n */\nconst rif: CountryValidator<\"VE\"> = {\n name: \"Venezuelan Tax ID\",\n localName: \"Registro de Información Fiscal\",\n abbreviation: \"RIF\",\n aliases: [\n \"RIF\",\n \"Registro de Información Fiscal\",\n ] as const,\n candidatePattern: \"[VEJPG]-?\\\\d{8}-?\\\\d\",\n scope: \"country\",\n country: \"VE\",\n entityType: \"any\",\n lengths: [10] as const,\n examples: [\"V309876543\", \"J309876546\"] as const,\n compact,\n format,\n validate,\n sourceUrl:\n \"https://en.wikipedia.org/wiki/Tax_Identification_Number#Venezuela\",\n generate,\n};\n\nexport default rif;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;;;;;AA6BA,MAAM,gBAAwC;CAC5C,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;AACL;;AAGA,MAAM,UAAU;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;;;;;AAMvC,MAAM,eAAe;AAErB,MAAM,WAAW,UACf,MAAM,OAAO,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY;AAEzC,MAAM,kBACJ,QACA,SACW;CACX,MAAM,KAAK,cAAc,WAAW;CACpC,IAAI,MAAM;CACV,KAAK,MAAM,CAAC,GAAG,WAAW,QAAQ,QAAQ,GACxC,OAAO,OAAO,KAAK,EAAE,IAAI;CAK3B,OAAO,cAHQ,KAAM,MAAM,MAAO;AAIpC;AAEA,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CAEvB,IAAI,EAAE,WAAW,IACf,OAAO,IACL,kBACA,2BACF;CAKF,MAAM,SAAS,EAAE;CACjB,IAAI,EAAE,UAAU,gBACd,OAAO,IACL,qBACA,sCACF;CAGF,MAAM,OAAO,EAAE,MAAM,GAAG,CAAC;CACzB,MAAM,QAAQ,EAAE,MAAM,CAAC;CACvB,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,GACtB,OAAO,IACL,kBACA,mCACF;CAIF,IAAI,UADa,eAAe,QAAQ,IACnB,GACnB,OAAO,IACL,oBACA,gCACF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,KAAK;CACvB,OAAO,GAAG,EAAE,GAAG,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC;AAC9C;AAEA,MAAM,iBAAiB;CAAC;CAAK;CAAK;CAAK;CAAK;AAAG;;AAG/C,MAAM,iBAAyB;CAC7B,MAAM,SAAS,WAAW,cAAc;CACxC,MAAM,OAAO,aAAa,CAAC;CAC3B,OAAO,SAAS,OAAO,eAAe,QAAQ,IAAI;AACpD;;;;;;AAOA,MAAM,MAA8B;CAClC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CACP,OACA,gCACF;CACA,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,SAAS,CAAC,EAAE;CACZ,UAAU,CAAC,cAAc,YAAY;CACrC;CACA;CACA;CACA,WACE;CACF;AACF"}
|
package/dist/vn/mst.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mst.js","names":[],"sources":["../../src/vn/mst.ts"],"sourcesContent":["/**\n * MST (Mã số thuế, Vietnam tax number).\n *\n * 10 or 13 digits. The first two digits encode the province\n * where the business was registered. Digits 3-9 are a\n * sequential number (0000001-9999999). Digit 10 is a\n * weighted mod-11 check digit. An optional 3-digit branch\n * suffix (001-999) may follow, separated by a dash.\n *\n * @see https://vi.wikipedia.org/wiki/Thuế_Việt_Nam#Mã_số_thuế_(MST)_của_doanh_nghiệp\n * @see https://easyinvoice.vn/ma-so-thue/\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 WEIGHTS = [31, 29, 23, 19, 17, 13, 7, 5, 3] as const;\n\nconst calcCheckDigit = (number: string): string => {\n let total = 0;\n for (let i = 0; i < 9; i++) {\n total += (WEIGHTS[i] ?? 0) * Number(number.charAt(i));\n }\n const remainder = 10 - (total % 11);\n // When remainder is 10, the sequential part is\n // never issued by GDT. Returning \"0\" keeps the\n // function correct as a digit calculator (mod 10\n // wrap) while still rejecting these numbers since\n // no real MST will have this combination.\n return String(\n remainder >= 10 ? remainder - 10 : remainder,\n );\n};\n\nconst compact = (value: string): string =>\n clean(value, \" -.\");\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 10 && v.length !== 13) {\n return err(\n \"INVALID_LENGTH\",\n \"MST must be 10 or 13 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"MST must contain only digits\",\n );\n }\n\n // Sequential part (digits 3-9) must not be all zeros\n if (v.slice(2, 9) === \"0000000\") {\n return err(\n \"INVALID_COMPONENT\",\n \"MST sequential part must not be 0000000\",\n );\n }\n\n // Branch suffix (last 3 digits) must not be 000\n if (v.length === 13 && v.slice(10) === \"000\") {\n return err(\n \"INVALID_COMPONENT\",\n \"MST branch suffix must not be 000\",\n );\n }\n\n // Check digit (position 10, index 9)\n if (v[9] !== calcCheckDigit(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"MST check digit does not match\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n if (v.length === 13) {\n return `${v.slice(0, 10)}-${v.slice(10)}`;\n }\n return v;\n};\n\n/** Generate a random valid Vietnamese MST. */\nconst generate = (): string => {\n for (;;) {\n const province = String(randomInt(1, 99)).padStart(\n 2,\n \"0\",\n );\n const payload = province + randomDigits(7);\n const c = payload + calcCheckDigit(payload);\n if (validate(c).valid) return c;\n }\n};\n\n/** Vietnamese Tax Number. */\nconst mst: CountryValidator<\"VN\"> = {\n name: \"Vietnamese Tax Number\",\n localName: \"Mã số thuế\",\n abbreviation: \"MST\",\n aliases: [\"MST\", \"mã số thuế\"] as const,\n candidatePattern: \"\\\\d{10}(-\\\\d{3})?\",\n scope: \"country\",\n country: \"VN\",\n entityType: \"company\",\n description:\n \"10- or 13-digit tax identifier for enterprises\",\n sourceUrl:\n \"https://vi.wikipedia.org/wiki/Thu%E1%BA%BF_Vi%E1%BB%87t_Nam#M%C3%A3_s%E1%BB%91_thu%E1%BA%BF_(MST)_c%E1%BB%A7a_doanh_nghi%E1%BB%87p\",\n lengths: [10, 13] as const,\n examples: [\"0100233488\", \"0314409058002\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default mst;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;AAuBA,MAAM,UAAU;CAAC;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAG;CAAG;AAAC;AAEhD,MAAM,kBAAkB,WAA2B;CACjD,IAAI,QAAQ;CACZ,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KACrB,UAAU,QAAQ,MAAM,KAAK,OAAO,OAAO,OAAO,CAAC,CAAC;CAEtD,MAAM,YAAY,KAAM,QAAQ;CAMhC,OAAO,OACL,aAAa,KAAK,YAAY,KAAK,SACrC;AACF;AAEA,MAAM,WAAW,UACf,MAAM,OAAO,KAAK;AAEpB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CAEvB,IAAI,EAAE,WAAW,MAAM,EAAE,WAAW,IAClC,OAAO,IACL,kBACA,6BACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,8BACF;CAIF,IAAI,EAAE,MAAM,GAAG,CAAC,MAAM,WACpB,OAAO,IACL,qBACA,yCACF;CAIF,IAAI,EAAE,WAAW,MAAM,EAAE,MAAM,EAAE,MAAM,OACrC,OAAO,IACL,qBACA,mCACF;CAIF,IAAI,EAAE,OAAO,eAAe,CAAC,GAC3B,OAAO,IACL,oBACA,gCACF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,IACf,OAAO,GAAG,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE;CAExC,OAAO;AACT;;AAGA,MAAM,iBAAyB;CAC7B,SAAS;EAKP,MAAM,UAJW,OAAO,UAAU,GAAG,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"mst.js","names":[],"sources":["../../src/vn/mst.ts"],"sourcesContent":["/**\n * MST (Mã số thuế, Vietnam tax number).\n *\n * 10 or 13 digits. The first two digits encode the province\n * where the business was registered. Digits 3-9 are a\n * sequential number (0000001-9999999). Digit 10 is a\n * weighted mod-11 check digit. An optional 3-digit branch\n * suffix (001-999) may follow, separated by a dash.\n *\n * @see https://vi.wikipedia.org/wiki/Thuế_Việt_Nam#Mã_số_thuế_(MST)_của_doanh_nghiệp\n * @see https://easyinvoice.vn/ma-so-thue/\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 WEIGHTS = [31, 29, 23, 19, 17, 13, 7, 5, 3] as const;\n\nconst calcCheckDigit = (number: string): string => {\n let total = 0;\n for (let i = 0; i < 9; i++) {\n total += (WEIGHTS[i] ?? 0) * Number(number.charAt(i));\n }\n const remainder = 10 - (total % 11);\n // When remainder is 10, the sequential part is\n // never issued by GDT. Returning \"0\" keeps the\n // function correct as a digit calculator (mod 10\n // wrap) while still rejecting these numbers since\n // no real MST will have this combination.\n return String(\n remainder >= 10 ? remainder - 10 : remainder,\n );\n};\n\nconst compact = (value: string): string =>\n clean(value, \" -.\");\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n\n if (v.length !== 10 && v.length !== 13) {\n return err(\n \"INVALID_LENGTH\",\n \"MST must be 10 or 13 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"MST must contain only digits\",\n );\n }\n\n // Sequential part (digits 3-9) must not be all zeros\n if (v.slice(2, 9) === \"0000000\") {\n return err(\n \"INVALID_COMPONENT\",\n \"MST sequential part must not be 0000000\",\n );\n }\n\n // Branch suffix (last 3 digits) must not be 000\n if (v.length === 13 && v.slice(10) === \"000\") {\n return err(\n \"INVALID_COMPONENT\",\n \"MST branch suffix must not be 000\",\n );\n }\n\n // Check digit (position 10, index 9)\n if (v[9] !== calcCheckDigit(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"MST check digit does not match\",\n );\n }\n\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n if (v.length === 13) {\n return `${v.slice(0, 10)}-${v.slice(10)}`;\n }\n return v;\n};\n\n/** Generate a random valid Vietnamese MST. */\nconst generate = (): string => {\n for (;;) {\n const province = String(randomInt(1, 99)).padStart(\n 2,\n \"0\",\n );\n const payload = province + randomDigits(7);\n const c = payload + calcCheckDigit(payload);\n if (validate(c).valid) return c;\n }\n};\n\n/** Vietnamese Tax Number. */\nconst mst: CountryValidator<\"VN\"> = {\n name: \"Vietnamese Tax Number\",\n localName: \"Mã số thuế\",\n abbreviation: \"MST\",\n aliases: [\"MST\", \"mã số thuế\"] as const,\n candidatePattern: \"\\\\d{10}(-\\\\d{3})?\",\n scope: \"country\",\n country: \"VN\",\n entityType: \"company\",\n description:\n \"10- or 13-digit tax identifier for enterprises\",\n sourceUrl:\n \"https://vi.wikipedia.org/wiki/Thu%E1%BA%BF_Vi%E1%BB%87t_Nam#M%C3%A3_s%E1%BB%91_thu%E1%BA%BF_(MST)_c%E1%BB%A7a_doanh_nghi%E1%BB%87p\",\n lengths: [10, 13] as const,\n examples: [\"0100233488\", \"0314409058002\"] as const,\n compact,\n format,\n validate,\n generate,\n};\n\nexport default mst;\nexport { compact, format, validate, generate };\n"],"mappings":";;;;;AAuBA,MAAM,UAAU;CAAC;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAG;CAAG;AAAC;AAEhD,MAAM,kBAAkB,WAA2B;CACjD,IAAI,QAAQ;CACZ,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KACrB,UAAU,QAAQ,MAAM,KAAK,OAAO,OAAO,OAAO,CAAC,CAAC;CAEtD,MAAM,YAAY,KAAM,QAAQ;CAMhC,OAAO,OACL,aAAa,KAAK,YAAY,KAAK,SACrC;AACF;AAEA,MAAM,WAAW,UACf,MAAM,OAAO,KAAK;AAEpB,MAAM,YAAY,UAAkC;CAClD,MAAM,IAAI,QAAQ,KAAK;CAEvB,IAAI,EAAE,WAAW,MAAM,EAAE,WAAW,IAClC,OAAO,IACL,kBACA,6BACF;CAEF,IAAI,CAAC,SAAS,CAAC,GACb,OAAO,IACL,kBACA,8BACF;CAIF,IAAI,EAAE,MAAM,GAAG,CAAC,MAAM,WACpB,OAAO,IACL,qBACA,yCACF;CAIF,IAAI,EAAE,WAAW,MAAM,EAAE,MAAM,EAAE,MAAM,OACrC,OAAO,IACL,qBACA,mCACF;CAIF,IAAI,EAAE,OAAO,eAAe,CAAC,GAC3B,OAAO,IACL,oBACA,gCACF;CAGF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,IACf,OAAO,GAAG,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE;CAExC,OAAO;AACT;;AAGA,MAAM,iBAAyB;CAC7B,SAAS;EAKP,MAAM,UAJW,OAAO,UAAU,GAAG,EAAE,CAAC,CAAC,CAAC,SACxC,GACA,GAEqB,IAAI,aAAa,CAAC;EACzC,MAAM,IAAI,UAAU,eAAe,OAAO;EAC1C,IAAI,SAAS,CAAC,CAAC,CAAC,OAAO,OAAO;CAChC;AACF;;AAGA,MAAM,MAA8B;CAClC,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,OAAO,YAAY;CAC7B,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ,aACE;CACF,WACE;CACF,SAAS,CAAC,IAAI,EAAE;CAChB,UAAU,CAAC,cAAc,eAAe;CACxC;CACA;CACA;CACA;AACF"}
|
package/dist/za/idnr.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idnr.js","names":[],"sources":["../../src/za/idnr.ts"],"sourcesContent":["/**\n * South African Identity Number.\n *\n * 13-digit number encoding date of birth, gender,\n * citizenship, and a Luhn check digit.\n * Format: YYMMDD SSSS C A Z\n * - YYMMDD: date of birth\n * - SSSS: sequence (0000-4999 female, 5000-9999 male)\n * - C: citizenship (0 = citizen, 1 = permanent resident)\n * - A: was used for race (now always 8 or 9)\n * - Z: Luhn check digit\n *\n * @see https://en.wikipedia.org/wiki/South_African_identity_document\n */\n\nimport type {\n ParsedPersonId,\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport {\n luhnValidate,\n luhnChecksum,\n} from \"#checksums/luhn\";\nimport { clean } from \"#util/clean\";\nimport { isValidDate } from \"#util/date\";\nimport { randomDigits, randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst compact = (value: string): string =>\n clean(value, \" \");\n\n/**\n * Resolve the birth date from the 2-digit year.\n * Years after the current year are assumed to be\n * in the previous century.\n */\nconst resolveBirthDate = (\n v: string,\n): { year: number; month: number; day: number } | null => {\n const today = new Date();\n const century = Math.floor(today.getFullYear() / 100);\n let year = century * 100 + Number(v.slice(0, 2));\n const month = Number(v.slice(2, 4));\n const day = Number(v.slice(4, 6));\n if (year > today.getFullYear()) {\n year -= 100;\n }\n if (!isValidDate(year, month, day)) return null;\n return { year, month, day };\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 13) {\n return err(\n \"INVALID_LENGTH\",\n \"SA ID must be exactly 13 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"SA ID must contain only digits\",\n );\n }\n if (resolveBirthDate(v) === null) {\n return err(\n \"INVALID_COMPONENT\",\n \"SA ID contains an invalid date of birth\",\n );\n }\n const citizenship = v[10];\n if (citizenship !== \"0\" && citizenship !== \"1\") {\n return err(\n \"INVALID_COMPONENT\",\n \"SA ID citizenship digit must be 0 or 1\",\n );\n }\n if (!luhnValidate(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"SA ID Luhn check digit mismatch\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n if (v.length === 13) {\n return `${v.slice(0, 6)} ${v.slice(6, 10)} ${v.slice(10, 12)} ${v.slice(12)}`;\n }\n return v;\n};\n\n/**\n * Extract birth date and gender from a South African\n * ID number. Returns null if the value is not valid.\n */\nconst parse = (value: string): ParsedPersonId | null => {\n const result = validate(value);\n if (!result.valid) return null;\n\n const v = result.compact;\n const bd = resolveBirthDate(v);\n if (bd === null) return null;\n\n const sequence = Number(v.slice(6, 10));\n\n return {\n birthDate: new Date(bd.year, bd.month - 1, bd.day),\n gender: sequence < 5000 ? \"female\" : \"male\",\n };\n};\n\n/** Generate a random valid South African ID. */\nconst generate = (): string => {\n for (;;) {\n const yy = String(randomInt(50, 99)).padStart(2, \"0\");\n const mm = String(randomInt(1, 12)).padStart(2, \"0\");\n const dd = String(randomInt(1, 28)).padStart(2, \"0\");\n const serial = randomDigits(4);\n const citizen = String(randomInt(0, 1));\n const payload = yy + mm + dd + serial + citizen + \"8\";\n const cs = luhnChecksum(payload + \"0\");\n const c = payload + String((10 - cs) % 10);\n if (validate(c).valid) return c;\n }\n};\n\n/** South African Identity Number. */\nconst idnr: CountryValidator<\"ZA\", ParsedPersonId> = {\n name: \"South African Identity Number\",\n localName: \"South African Identity Number\",\n abbreviation: \"SA ID\",\n aliases: [\"ID number\", \"RSA ID\"] as const,\n candidatePattern: \"\\\\d{13}\",\n scope: \"country\",\n country: \"ZA\",\n entityType: \"person\",\n compact,\n format,\n parse,\n validate,\n description:\n \"South African personal identification number\",\n sourceUrl:\n \"https://en.wikipedia.org/wiki/\" +\n \"South_African_identity_document\",\n lengths: [13] as const,\n examples: [\"7503305044089\", \"8001015009087\"] as const,\n generate,\n};\n\nexport default idnr;\nexport { compact, format, parse, validate, generate };\n"],"mappings":";;;;;;;AA+BA,MAAM,WAAW,UACf,MAAM,OAAO,GAAG;;;;;;AAOlB,MAAM,oBACJ,MACwD;CACxD,MAAM,wBAAQ,IAAI,KAAK;CAEvB,IAAI,OADY,KAAK,MAAM,MAAM,YAAY,IAAI,GAChC,IAAI,MAAM,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/C,MAAM,QAAQ,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAClC,MAAM,MAAM,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAChC,IAAI,OAAO,MAAM,YAAY,GAC3B,QAAQ;CAEV,IAAI,CAAC,YAAY,MAAM,OAAO,GAAG,GAAG,OAAO;CAC3C,OAAO;EAAE;EAAM;EAAO;CAAI;AAC5B;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;CAEF,IAAI,iBAAiB,CAAC,MAAM,MAC1B,OAAO,IACL,qBACA,yCACF;CAEF,MAAM,cAAc,EAAE;CACtB,IAAI,gBAAgB,OAAO,gBAAgB,KACzC,OAAO,IACL,qBACA,wCACF;CAEF,IAAI,CAAC,aAAa,CAAC,GACjB,OAAO,IACL,oBACA,iCACF;CAEF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,IACf,OAAO,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,EAAE,MAAM,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE;CAE5E,OAAO;AACT;;;;;AAMA,MAAM,SAAS,UAAyC;CACtD,MAAM,SAAS,SAAS,KAAK;CAC7B,IAAI,CAAC,OAAO,OAAO,OAAO;CAE1B,MAAM,IAAI,OAAO;CACjB,MAAM,KAAK,iBAAiB,CAAC;CAC7B,IAAI,OAAO,MAAM,OAAO;CAExB,MAAM,WAAW,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;CAEtC,OAAO;EACL,WAAW,IAAI,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,GAAG,GAAG;EACjD,QAAQ,WAAW,MAAO,WAAW;CACvC;AACF;;AAGA,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,KAAK,OAAO,UAAU,IAAI,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"idnr.js","names":[],"sources":["../../src/za/idnr.ts"],"sourcesContent":["/**\n * South African Identity Number.\n *\n * 13-digit number encoding date of birth, gender,\n * citizenship, and a Luhn check digit.\n * Format: YYMMDD SSSS C A Z\n * - YYMMDD: date of birth\n * - SSSS: sequence (0000-4999 female, 5000-9999 male)\n * - C: citizenship (0 = citizen, 1 = permanent resident)\n * - A: was used for race (now always 8 or 9)\n * - Z: Luhn check digit\n *\n * @see https://en.wikipedia.org/wiki/South_African_identity_document\n */\n\nimport type {\n ParsedPersonId,\n ValidateResult,\n CountryValidator,\n} from \"../types\";\n\nimport {\n luhnValidate,\n luhnChecksum,\n} from \"#checksums/luhn\";\nimport { clean } from \"#util/clean\";\nimport { isValidDate } from \"#util/date\";\nimport { randomDigits, randomInt } from \"#util/generate\";\nimport { err } from \"#util/result\";\nimport { isdigits } from \"#util/strings\";\n\nconst compact = (value: string): string =>\n clean(value, \" \");\n\n/**\n * Resolve the birth date from the 2-digit year.\n * Years after the current year are assumed to be\n * in the previous century.\n */\nconst resolveBirthDate = (\n v: string,\n): { year: number; month: number; day: number } | null => {\n const today = new Date();\n const century = Math.floor(today.getFullYear() / 100);\n let year = century * 100 + Number(v.slice(0, 2));\n const month = Number(v.slice(2, 4));\n const day = Number(v.slice(4, 6));\n if (year > today.getFullYear()) {\n year -= 100;\n }\n if (!isValidDate(year, month, day)) return null;\n return { year, month, day };\n};\n\nconst validate = (value: string): ValidateResult => {\n const v = compact(value);\n if (v.length !== 13) {\n return err(\n \"INVALID_LENGTH\",\n \"SA ID must be exactly 13 digits\",\n );\n }\n if (!isdigits(v)) {\n return err(\n \"INVALID_FORMAT\",\n \"SA ID must contain only digits\",\n );\n }\n if (resolveBirthDate(v) === null) {\n return err(\n \"INVALID_COMPONENT\",\n \"SA ID contains an invalid date of birth\",\n );\n }\n const citizenship = v[10];\n if (citizenship !== \"0\" && citizenship !== \"1\") {\n return err(\n \"INVALID_COMPONENT\",\n \"SA ID citizenship digit must be 0 or 1\",\n );\n }\n if (!luhnValidate(v)) {\n return err(\n \"INVALID_CHECKSUM\",\n \"SA ID Luhn check digit mismatch\",\n );\n }\n return { valid: true, compact: v };\n};\n\nconst format = (value: string): string => {\n const v = compact(value);\n if (v.length === 13) {\n return `${v.slice(0, 6)} ${v.slice(6, 10)} ${v.slice(10, 12)} ${v.slice(12)}`;\n }\n return v;\n};\n\n/**\n * Extract birth date and gender from a South African\n * ID number. Returns null if the value is not valid.\n */\nconst parse = (value: string): ParsedPersonId | null => {\n const result = validate(value);\n if (!result.valid) return null;\n\n const v = result.compact;\n const bd = resolveBirthDate(v);\n if (bd === null) return null;\n\n const sequence = Number(v.slice(6, 10));\n\n return {\n birthDate: new Date(bd.year, bd.month - 1, bd.day),\n gender: sequence < 5000 ? \"female\" : \"male\",\n };\n};\n\n/** Generate a random valid South African ID. */\nconst generate = (): string => {\n for (;;) {\n const yy = String(randomInt(50, 99)).padStart(2, \"0\");\n const mm = String(randomInt(1, 12)).padStart(2, \"0\");\n const dd = String(randomInt(1, 28)).padStart(2, \"0\");\n const serial = randomDigits(4);\n const citizen = String(randomInt(0, 1));\n const payload = yy + mm + dd + serial + citizen + \"8\";\n const cs = luhnChecksum(payload + \"0\");\n const c = payload + String((10 - cs) % 10);\n if (validate(c).valid) return c;\n }\n};\n\n/** South African Identity Number. */\nconst idnr: CountryValidator<\"ZA\", ParsedPersonId> = {\n name: \"South African Identity Number\",\n localName: \"South African Identity Number\",\n abbreviation: \"SA ID\",\n aliases: [\"ID number\", \"RSA ID\"] as const,\n candidatePattern: \"\\\\d{13}\",\n scope: \"country\",\n country: \"ZA\",\n entityType: \"person\",\n compact,\n format,\n parse,\n validate,\n description:\n \"South African personal identification number\",\n sourceUrl:\n \"https://en.wikipedia.org/wiki/\" +\n \"South_African_identity_document\",\n lengths: [13] as const,\n examples: [\"7503305044089\", \"8001015009087\"] as const,\n generate,\n};\n\nexport default idnr;\nexport { compact, format, parse, validate, generate };\n"],"mappings":";;;;;;;AA+BA,MAAM,WAAW,UACf,MAAM,OAAO,GAAG;;;;;;AAOlB,MAAM,oBACJ,MACwD;CACxD,MAAM,wBAAQ,IAAI,KAAK;CAEvB,IAAI,OADY,KAAK,MAAM,MAAM,YAAY,IAAI,GAChC,IAAI,MAAM,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAC/C,MAAM,QAAQ,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAClC,MAAM,MAAM,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;CAChC,IAAI,OAAO,MAAM,YAAY,GAC3B,QAAQ;CAEV,IAAI,CAAC,YAAY,MAAM,OAAO,GAAG,GAAG,OAAO;CAC3C,OAAO;EAAE;EAAM;EAAO;CAAI;AAC5B;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;CAEF,IAAI,iBAAiB,CAAC,MAAM,MAC1B,OAAO,IACL,qBACA,yCACF;CAEF,MAAM,cAAc,EAAE;CACtB,IAAI,gBAAgB,OAAO,gBAAgB,KACzC,OAAO,IACL,qBACA,wCACF;CAEF,IAAI,CAAC,aAAa,CAAC,GACjB,OAAO,IACL,oBACA,iCACF;CAEF,OAAO;EAAE,OAAO;EAAM,SAAS;CAAE;AACnC;AAEA,MAAM,UAAU,UAA0B;CACxC,MAAM,IAAI,QAAQ,KAAK;CACvB,IAAI,EAAE,WAAW,IACf,OAAO,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,EAAE,MAAM,IAAI,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE;CAE5E,OAAO;AACT;;;;;AAMA,MAAM,SAAS,UAAyC;CACtD,MAAM,SAAS,SAAS,KAAK;CAC7B,IAAI,CAAC,OAAO,OAAO,OAAO;CAE1B,MAAM,IAAI,OAAO;CACjB,MAAM,KAAK,iBAAiB,CAAC;CAC7B,IAAI,OAAO,MAAM,OAAO;CAExB,MAAM,WAAW,OAAO,EAAE,MAAM,GAAG,EAAE,CAAC;CAEtC,OAAO;EACL,WAAW,IAAI,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,GAAG,GAAG;EACjD,QAAQ,WAAW,MAAO,WAAW;CACvC;AACF;;AAGA,MAAM,iBAAyB;CAC7B,SAAS;EACP,MAAM,KAAK,OAAO,UAAU,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;EACpD,MAAM,KAAK,OAAO,UAAU,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;EACnD,MAAM,KAAK,OAAO,UAAU,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;EACnD,MAAM,SAAS,aAAa,CAAC;EAC7B,MAAM,UAAU,OAAO,UAAU,GAAG,CAAC,CAAC;EACtC,MAAM,UAAU,KAAK,KAAK,KAAK,SAAS,UAAU;EAClD,MAAM,KAAK,aAAa,UAAU,GAAG;EACrC,MAAM,IAAI,UAAU,QAAQ,KAAK,MAAM,EAAE;EACzC,IAAI,SAAS,CAAC,CAAC,CAAC,OAAO,OAAO;CAChC;AACF;;AAGA,MAAM,OAA+C;CACnD,MAAM;CACN,WAAW;CACX,cAAc;CACd,SAAS,CAAC,aAAa,QAAQ;CAC/B,kBAAkB;CAClB,OAAO;CACP,SAAS;CACT,YAAY;CACZ;CACA;CACA;CACA;CACA,aACE;CACF,WACE;CAEF,SAAS,CAAC,EAAE;CACZ,UAAU,CAAC,iBAAiB,eAAe;CAC3C;AACF"}
|