Comparing version 1.5.0 to 1.6.2
{ | ||
"name": "ibankit", | ||
"version": "1.5.0", | ||
"version": "1.6.2", | ||
"description": "Validation, field extraction and creation of IBAN, BBAN, BIC numbers", | ||
"main": "lib/index.js", | ||
"types": "lib/index.d.ts", | ||
"main": "./lib/cjs/index.js", | ||
"module": "./lib/esm/index.js", | ||
"types": "./lib/cjs/index.d.ts", | ||
"keywords": [ | ||
@@ -19,7 +20,28 @@ "IBAN", | ||
], | ||
"release": { | ||
"branches": [ | ||
"main" | ||
], | ||
"plugins": [ | ||
"@semantic-release/commit-analyzer", | ||
"@semantic-release/npm", | ||
[ | ||
"@semantic-release/git", | ||
{ | ||
"assets": [ | ||
"package.json" | ||
], | ||
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" | ||
} | ||
] | ||
] | ||
}, | ||
"scripts": { | ||
"format": "prettier --write \"src/**/*.ts\"", | ||
"lint": "tslint -c tslint.json -p tsconfig.json", | ||
"lint": "eslint --ext .js,.jsx,.ts,.tsx src", | ||
"test": "jest", | ||
"build": "tsc" | ||
"build": "tsc", | ||
"prepublishOnly:esm": "tsc -p tsconfig.json", | ||
"prepublishOnly:cjs": "tsc -p tsconfig-cjs.json", | ||
"prepublishOnly": "npm run prepublishOnly:esm && npm run prepublishOnly:cjs" | ||
}, | ||
@@ -30,3 +52,3 @@ "repository": { | ||
}, | ||
"author": "", | ||
"author": "David Koblas", | ||
"license": "ISC", | ||
@@ -41,19 +63,27 @@ "homepage": "https://github.com/koblas/ibankit", | ||
"transform": { | ||
"\\.(ts|tsx)$": "ts-jest" | ||
"^.+\\.(ts|tsx)$": "ts-jest" | ||
}, | ||
"testRegex": "/test/.*\\.(ts|tsx|js)$" | ||
"testMatch": [ | ||
"/test/.*\\.(ts|tsx|js)$", | ||
"**/__tests__/**/*.+(ts|tsx|js)", | ||
"**/?(*.)+(spec|test).+(ts|tsx|js)" | ||
] | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^27.0.1", | ||
"handlebars": "^4.7.7", | ||
"jest": "^27.1.0", | ||
"prettier": "^2.3.2", | ||
"ts-jest": "^27.0.5", | ||
"tslint": "^6.1.3", | ||
"tslint-config-prettier": "^1.18.0", | ||
"tslint-eslint-rules": "^5.4.0", | ||
"tslint-microsoft-contrib": "^6.2.0", | ||
"typescript": "^4.4.2" | ||
}, | ||
"dependencies": {} | ||
"@semantic-release/changelog": "^6.0.3", | ||
"@semantic-release/git": "^10.0.1", | ||
"@types/jest": "^29.5.4", | ||
"@typescript-eslint/eslint-plugin": "^6.5.0", | ||
"@typescript-eslint/parser": "^6.5.0", | ||
"eslint": "^8.48.0", | ||
"eslint-config-airbnb-base": "^15.0.0", | ||
"eslint-config-airbnb-typescript": "^17.1.0", | ||
"eslint-config-prettier": "^9.0.0", | ||
"eslint-plugin-import": "^2.28.1", | ||
"eslint-plugin-prettier": "^5.0.0", | ||
"jest": "^29.6.4", | ||
"prettier": "^3.0.3", | ||
"ts-jest": "^29.1.1", | ||
"typescript": "^5.2.2" | ||
} | ||
} |
# ibankit | ||
[![CircleCI](https://circleci.com/gh/koblas/ibankit-js/tree/master.svg?style=svg)](https://circleci.com/gh/koblas/ibankit-js/tree/master) | ||
[![npm version](https://badge.fury.io/js/ibankit.svg)](https://badge.fury.io/js/ibankit) | ||
@@ -14,3 +13,3 @@ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/koblas/ibankit-js/blob/master/LICENSE.txt) | ||
- Drop-in replaceable with [iban-js](https://www.npmjs.com/package/iban) | ||
- Currently conformant with Version 88 of the IBAN registry | ||
- Currently conformant with Version 95 (July 2023) of the IBAN registry | ||
- Decodes bank, branch and account numbers from IBAN | ||
@@ -26,3 +25,3 @@ - Supports random BBAN / IBAN generation for testing | ||
This release should be compatible with the [SWIFT IBAN Registry | ||
Version 88](https://www.swift.com/swift-resource/9606/download). There may be a limited number | ||
Version 95](https://www.swift.com/swift-resource/9606/download). There may be a limited number | ||
of value differences, some countries in the Registry doesn't describe bank/branch information | ||
@@ -51,6 +50,3 @@ but may expose it as `3!n4!n` but leave the branch description as a blank. | ||
const iban = IBAN.random(); | ||
const iban = new IBANBuilder() | ||
.countryCode(CountryCode.AT) | ||
.bankCode("19043") | ||
.build(); | ||
const iban = new IBANBuilder().countryCode(CountryCode.AT).bankCode("19043").build(); | ||
@@ -95,5 +91,4 @@ // For simplicity in porting from iban-js applications | ||
Copyright 2018-2021 David Koblas | ||
Copyright 2018-2023 David Koblas | ||
Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 | ||
import { CharacterType, BbanStructurePart, PartType } from "./structurePart"; | ||
import { CountryCode } from "./country"; | ||
import { | ||
FormatException, | ||
FormatViolation, | ||
RequiredPartTypeMissing, | ||
} from "./exceptions"; | ||
import { objectEntries, objectValues } from "./poly"; | ||
import { FormatException, FormatViolation, RequiredPartTypeMissing } from "./exceptions"; | ||
@@ -15,12 +10,3 @@ /** | ||
return ( | ||
(11 - | ||
(value | ||
.split("") | ||
.reduce( | ||
(acc, s, idx) => | ||
acc + parseInt(s, 10) * weights[idx % weights.length], | ||
0, | ||
) % | ||
11)) % | ||
11 | ||
(11 - (value.split("").reduce((acc, s, idx) => acc + parseInt(s, 10) * weights[idx % weights.length], 0) % 11)) % 11 | ||
); | ||
@@ -31,5 +17,3 @@ } | ||
const weights = [1, 2, 4, 8, 5, 10, 9, 7, 3, 6]; | ||
const combined = [PartType.BANK_CODE, PartType.BRANCH_CODE] | ||
.map((p) => structure.extractValueMust(bban, p)) | ||
.join(""); | ||
const combined = [PartType.BANK_CODE, PartType.BRANCH_CODE].map((p) => structure.extractValueMust(bban, p)).join(""); | ||
@@ -46,5 +30,3 @@ function to11(v: number) { | ||
const d1 = to11(mod11(`00${combined}`, weights)); | ||
const d2 = to11( | ||
mod11(structure.extractValueMust(bban, PartType.ACCOUNT_NUMBER), weights), | ||
); | ||
const d2 = to11(mod11(structure.extractValueMust(bban, PartType.ACCOUNT_NUMBER), weights)); | ||
@@ -73,10 +55,6 @@ return `${d1}${d2}`; | ||
.join("") + "00"; | ||
objectEntries(replaceChars).map( | ||
([k, v]) => (combined = combined.replace(new RegExp(k, "g"), v)), | ||
); | ||
Object.entries(replaceChars).map(([k, v]) => (combined = combined.replace(new RegExp(k, "g"), v))); | ||
// Number is bigger than max integer, take the mod%97 by hand | ||
const expected = | ||
97 - | ||
combined.split("").reduce((acc, v) => (acc * 10 + parseInt(v)) % 97, 0); | ||
const expected = 97 - combined.split("").reduce((acc, v) => (acc * 10 + parseInt(v)) % 97, 0); | ||
@@ -87,58 +65,4 @@ return String(expected).padStart(2, "0"); | ||
function nationalIT(bban: string, structure: BbanStructure) { | ||
const even = [ | ||
0, | ||
1, | ||
2, | ||
3, | ||
4, | ||
5, | ||
6, | ||
7, | ||
8, | ||
9, | ||
10, | ||
11, | ||
12, | ||
13, | ||
14, | ||
15, | ||
16, | ||
17, | ||
18, | ||
19, | ||
20, | ||
21, | ||
22, | ||
23, | ||
24, | ||
25, | ||
]; | ||
const odd = [ | ||
1, | ||
0, | ||
5, | ||
7, | ||
9, | ||
13, | ||
15, | ||
17, | ||
19, | ||
21, | ||
2, | ||
4, | ||
18, | ||
20, | ||
11, | ||
3, | ||
6, | ||
8, | ||
12, | ||
14, | ||
16, | ||
10, | ||
22, | ||
25, | ||
24, | ||
23, | ||
]; | ||
const even = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]; | ||
const odd = [1, 0, 5, 7, 9, 13, 15, 17, 19, 21, 2, 4, 18, 20, 11, 3, 6, 8, 12, 14, 16, 10, 22, 25, 24, 23]; | ||
const V0 = "0".charCodeAt(0); | ||
@@ -154,4 +78,3 @@ const V9 = "9".charCodeAt(0); | ||
.map((v) => v - (V0 <= v && v <= V9 ? V0 : VA)) | ||
.reduce((acc, v, idx) => acc + (idx % 2 === 0 ? odd[v] : even[v]), 0) % | ||
26; | ||
.reduce((acc, v, idx) => acc + (idx % 2 === 0 ? odd[v] : even[v]), 0) % 26; | ||
@@ -162,5 +85,3 @@ return String.fromCharCode(VA + value); | ||
function nationalNO(bban: string, structure: BbanStructure) { | ||
const value = [PartType.BANK_CODE, PartType.ACCOUNT_NUMBER] | ||
.map((p) => structure.extractValueMust(bban, p)) | ||
.join(""); | ||
const value = [PartType.BANK_CODE, PartType.ACCOUNT_NUMBER].map((p) => structure.extractValueMust(bban, p)).join(""); | ||
@@ -173,28 +94,4 @@ return String(mod11(value, [5, 4, 3, 2, 7, 6, 5, 4, 3, 2]) % 10); | ||
const V0 = "0".charCodeAt(0); | ||
const weights = [ | ||
73, | ||
17, | ||
89, | ||
38, | ||
62, | ||
45, | ||
53, | ||
15, | ||
50, | ||
5, | ||
49, | ||
34, | ||
81, | ||
76, | ||
27, | ||
90, | ||
9, | ||
30, | ||
3, | ||
]; | ||
const remainder = [ | ||
PartType.BANK_CODE, | ||
PartType.BRANCH_CODE, | ||
PartType.ACCOUNT_NUMBER, | ||
] | ||
const weights = [73, 17, 89, 38, 62, 45, 53, 15, 50, 5, 49, 34, 81, 76, 27, 90, 9, 30, 3]; | ||
const remainder = [PartType.BANK_CODE, PartType.BRANCH_CODE, PartType.ACCOUNT_NUMBER] | ||
.map((p) => structure.extractValueMust(bban, p)) | ||
@@ -225,2 +122,3 @@ .join("") | ||
[CountryCode.AD]: new BbanStructure( | ||
// AD2!n4!n4!n12!c | ||
BbanStructurePart.bankCode(4, CharacterType.n), | ||
@@ -232,2 +130,3 @@ BbanStructurePart.branchCode(4, CharacterType.n), | ||
[CountryCode.AE]: new BbanStructure( | ||
// AE2!n3!n16!n | ||
BbanStructurePart.bankCode(3, CharacterType.n), | ||
@@ -245,5 +144,3 @@ BbanStructurePart.accountNumber(16, CharacterType.c), | ||
// Provisional | ||
[CountryCode.AO]: new BbanStructure( | ||
BbanStructurePart.accountNumber(21, CharacterType.n), | ||
), | ||
[CountryCode.AO]: new BbanStructure(BbanStructurePart.accountNumber(21, CharacterType.n)), | ||
@@ -270,37 +167,25 @@ [CountryCode.AT]: new BbanStructure( | ||
BbanStructurePart.accountNumber(7, CharacterType.n), | ||
BbanStructurePart.nationalCheckDigit( | ||
2, | ||
CharacterType.n, | ||
(bban: string, structure: BbanStructure) => { | ||
const accountNumber = structure.extractValue( | ||
bban, | ||
PartType.ACCOUNT_NUMBER, | ||
); | ||
const bankCode = structure.extractValue(bban, PartType.BANK_CODE); | ||
BbanStructurePart.nationalCheckDigit(2, CharacterType.n, (bban: string, structure: BbanStructure) => { | ||
const accountNumber = structure.extractValue(bban, PartType.ACCOUNT_NUMBER); | ||
const bankCode = structure.extractValue(bban, PartType.BANK_CODE); | ||
if (accountNumber === null || bankCode === null) { | ||
throw new FormatException( | ||
FormatViolation.NOT_EMPTY, | ||
"account number or bank code missing", | ||
); | ||
} | ||
if (accountNumber === null || bankCode === null) { | ||
throw new FormatException(FormatViolation.NOT_EMPTY, "account number or bank code missing"); | ||
} | ||
const value = parseInt(`${bankCode}${accountNumber}`, 10); | ||
const value = parseInt(`${bankCode}${accountNumber}`, 10); | ||
const remainder = Math.floor(value / 97); | ||
const remainder = Math.floor(value / 97); | ||
let expected = value - remainder * 97; | ||
if (expected === 0) { | ||
expected = 97; | ||
} | ||
let expected = value - remainder * 97; | ||
if (expected === 0) { | ||
expected = 97; | ||
} | ||
return String(expected).padStart(2, "0"); | ||
}, | ||
), | ||
return String(expected).padStart(2, "0"); | ||
}), | ||
), | ||
// Provisional | ||
[CountryCode.BF]: new BbanStructure( | ||
BbanStructurePart.accountNumber(23, CharacterType.n), | ||
), | ||
[CountryCode.BF]: new BbanStructure(BbanStructurePart.accountNumber(23, CharacterType.n)), | ||
@@ -321,3 +206,9 @@ [CountryCode.BG]: new BbanStructure( | ||
[CountryCode.BI]: new BbanStructure( | ||
BbanStructurePart.accountNumber(12, CharacterType.n), | ||
// BI2!n5!n5!n11!n2!n | ||
// Changed on October 21 (from 12!n) | ||
BbanStructurePart.bankCode(5, CharacterType.n), | ||
BbanStructurePart.branchCode(5, CharacterType.n), | ||
BbanStructurePart.accountNumber(11, CharacterType.n), | ||
BbanStructurePart.nationalCheckDigit(2, CharacterType.n), | ||
// BbanStructurePart.accountNumber(12, CharacterType.n), | ||
), | ||
@@ -379,5 +270,3 @@ | ||
// Provisional | ||
[CountryCode.CM]: new BbanStructure( | ||
BbanStructurePart.accountNumber(23, CharacterType.n), | ||
), | ||
[CountryCode.CM]: new BbanStructure(BbanStructurePart.accountNumber(23, CharacterType.n)), | ||
@@ -390,5 +279,3 @@ [CountryCode.CR]: new BbanStructure( | ||
// Provisional | ||
[CountryCode.CV]: new BbanStructure( | ||
BbanStructurePart.accountNumber(21, CharacterType.n), | ||
), | ||
[CountryCode.CV]: new BbanStructure(BbanStructurePart.accountNumber(21, CharacterType.n)), | ||
@@ -416,3 +303,10 @@ [CountryCode.CY]: new BbanStructure( | ||
// Provisional | ||
[CountryCode.DJ]: BbanStructure.bbanFR, | ||
[CountryCode.DJ]: new BbanStructure( | ||
// BI2!n5!n5!n11!n2!n | ||
// Changed on May 22 (from France's standard) | ||
BbanStructurePart.bankCode(5, CharacterType.n), | ||
BbanStructurePart.branchCode(5, CharacterType.n), | ||
BbanStructurePart.accountNumber(11, CharacterType.n), | ||
BbanStructurePart.nationalCheckDigit(2, CharacterType.n), | ||
), | ||
@@ -436,5 +330,3 @@ // Registry defines 4!n9!n1!n -- however no information on | ||
// Provisional | ||
[CountryCode.DZ]: new BbanStructure( | ||
BbanStructurePart.accountNumber(20, CharacterType.n), | ||
), | ||
[CountryCode.DZ]: new BbanStructure(BbanStructurePart.accountNumber(20, CharacterType.n)), | ||
@@ -469,2 +361,8 @@ [CountryCode.EE]: new BbanStructure( | ||
[CountryCode.FK]: new BbanStructure( | ||
// Added July 23 | ||
BbanStructurePart.bankCode(2, CharacterType.a), | ||
BbanStructurePart.accountNumber(12, CharacterType.n), | ||
), | ||
[CountryCode.FO]: new BbanStructure( | ||
@@ -492,2 +390,3 @@ BbanStructurePart.bankCode(4, CharacterType.n), | ||
[CountryCode.GE]: new BbanStructure( | ||
// Added Apr 23 | ||
BbanStructurePart.bankCode(2, CharacterType.a), | ||
@@ -591,5 +490,3 @@ BbanStructurePart.accountNumber(16, CharacterType.n), | ||
// Provisional | ||
[CountryCode.KM]: new BbanStructure( | ||
BbanStructurePart.accountNumber(23, CharacterType.n), | ||
), | ||
[CountryCode.KM]: new BbanStructure(BbanStructurePart.accountNumber(23, CharacterType.n)), | ||
@@ -643,5 +540,3 @@ [CountryCode.KW]: new BbanStructure( | ||
// Provisional | ||
[CountryCode.MA]: new BbanStructure( | ||
BbanStructurePart.accountNumber(24, CharacterType.n), | ||
), | ||
[CountryCode.MA]: new BbanStructure(BbanStructurePart.accountNumber(24, CharacterType.n)), | ||
@@ -687,2 +582,9 @@ [CountryCode.MC]: new BbanStructure( | ||
[CountryCode.MN]: new BbanStructure( | ||
// MN2!n4!n12!n | ||
// Added April 2023 | ||
BbanStructurePart.bankCode(4, CharacterType.n), | ||
BbanStructurePart.accountNumber(12, CharacterType.n), | ||
), | ||
[CountryCode.MR]: new BbanStructure( | ||
@@ -713,5 +615,3 @@ BbanStructurePart.bankCode(5, CharacterType.n), | ||
// Provisional | ||
[CountryCode.MZ]: new BbanStructure( | ||
BbanStructurePart.accountNumber(21, CharacterType.n), | ||
), | ||
[CountryCode.MZ]: new BbanStructure(BbanStructurePart.accountNumber(21, CharacterType.n)), | ||
@@ -724,6 +624,7 @@ // Provisional | ||
// Provisional | ||
[CountryCode.NI]: new BbanStructure( | ||
// NI2!n4!a20!n | ||
// Added April 2023 | ||
BbanStructurePart.bankCode(4, CharacterType.a), | ||
BbanStructurePart.accountNumber(24, CharacterType.n), | ||
BbanStructurePart.accountNumber(20, CharacterType.n), | ||
), | ||
@@ -744,3 +645,3 @@ | ||
BbanStructurePart.bankCode(4, CharacterType.c), | ||
BbanStructurePart.accountNumber(16, CharacterType.n), | ||
BbanStructurePart.accountNumber(16, CharacterType.c), | ||
), | ||
@@ -784,2 +685,10 @@ | ||
[CountryCode.RU]: new BbanStructure( | ||
// RU2!n9!n5!n15!c | ||
// Added May 2022 | ||
BbanStructurePart.bankCode(9, CharacterType.n), | ||
BbanStructurePart.branchCode(5, CharacterType.n), | ||
BbanStructurePart.accountNumber(15, CharacterType.c), | ||
), | ||
[CountryCode.SA]: new BbanStructure( | ||
@@ -798,2 +707,9 @@ BbanStructurePart.bankCode(2, CharacterType.n), | ||
[CountryCode.SD]: new BbanStructure( | ||
// SD2!n2!n12!n | ||
// Added October 2021 | ||
BbanStructurePart.bankCode(2, CharacterType.n), | ||
BbanStructurePart.accountNumber(12, CharacterType.n), | ||
), | ||
[CountryCode.SE]: new BbanStructure( | ||
@@ -831,2 +747,10 @@ BbanStructurePart.bankCode(3, CharacterType.n), | ||
[CountryCode.SO]: new BbanStructure( | ||
// SO2!n4!n3!n12!n | ||
// Added Feb 2023 | ||
BbanStructurePart.bankCode(4, CharacterType.n), | ||
BbanStructurePart.branchCode(3, CharacterType.n), | ||
BbanStructurePart.accountNumber(12, CharacterType.n), | ||
), | ||
[CountryCode.ST]: new BbanStructure( | ||
@@ -839,2 +763,4 @@ BbanStructurePart.bankCode(4, CharacterType.n), | ||
[CountryCode.SV]: new BbanStructure( | ||
// SV2!n4!a20!n | ||
// Added March 2021 | ||
BbanStructurePart.bankCode(4, CharacterType.a), | ||
@@ -898,2 +824,3 @@ BbanStructurePart.branchCode(4, CharacterType.n), | ||
}; | ||
private entries: BbanStructurePart[]; | ||
@@ -909,3 +836,3 @@ | ||
validate(bban: string) { | ||
validate(bban: string): void { | ||
this.validateBbanLength(bban); | ||
@@ -919,8 +846,5 @@ this.validateBbanEntries(bban); | ||
for (let part of this.getParts()) { | ||
for (const part of this.getParts()) { | ||
const partLength = part.getLength(); | ||
const partValue = bban.substring( | ||
bbanPartOffset, | ||
bbanPartOffset + partLength, | ||
); | ||
const partValue = bban.substring(bbanPartOffset, bbanPartOffset + partLength); | ||
@@ -943,5 +867,3 @@ bbanPartOffset = bbanPartOffset + partLength; | ||
if (value === null) { | ||
throw new RequiredPartTypeMissing( | ||
`Required part type [${partType}] missing`, | ||
); | ||
throw new RequiredPartTypeMissing(`Required part type [${partType}] missing`); | ||
} | ||
@@ -956,13 +878,11 @@ | ||
*/ | ||
static forCountry( | ||
countryCode: CountryCode | string | undefined, | ||
): BbanStructure | null { | ||
static forCountry(countryCode: CountryCode | string | undefined): BbanStructure | null { | ||
if (!countryCode) { | ||
return null; | ||
} | ||
return this.structures[countryCode] || null; | ||
return this.structures[countryCode as CountryCode] || null; | ||
} | ||
static getEntries(): BbanStructure[] { | ||
return objectValues(this.structures) as BbanStructure[]; | ||
return Object.values(this.structures) as BbanStructure[]; | ||
} | ||
@@ -1000,3 +920,3 @@ | ||
for (let part of this.getParts()) { | ||
for (const part of this.getParts()) { | ||
const partLength = part.getLength(); | ||
@@ -1012,7 +932,3 @@ const entryValue = bban.substring(offset, offset + partLength); | ||
private validateBbanEntryCharacterType( | ||
bban: string, | ||
part: BbanStructurePart, | ||
entryValue: string, | ||
) { | ||
private validateBbanEntryCharacterType(bban: string, part: BbanStructurePart, entryValue: string) { | ||
if (!part.validate(entryValue)) { | ||
@@ -1041,6 +957,3 @@ switch (part.getCharacterType()) { | ||
if ( | ||
part.getPartType() === PartType.NATIONAL_CHECK_DIGIT && | ||
part.hasGenerator | ||
) { | ||
if (part.getPartType() === PartType.NATIONAL_CHECK_DIGIT && part.hasGenerator) { | ||
const expected = part.generate(bban, this); | ||
@@ -1047,0 +960,0 @@ |
@@ -1,6 +0,2 @@ | ||
import { | ||
UnsupportedCountryException, | ||
FormatException, | ||
FormatViolation, | ||
} from "./exceptions"; | ||
import { UnsupportedCountryException, FormatException, FormatViolation } from "./exceptions"; | ||
import { countryByCode } from "./country"; | ||
@@ -23,35 +19,29 @@ | ||
/** | ||
* Validates bic. | ||
* | ||
* @param bic to be validated. | ||
* @throws FormatException if bic is invalid. | ||
* UnsupportedCountryException if bic's country is not supported. | ||
*/ | ||
export function validate(bic: string) { | ||
validateEmpty(bic); | ||
validateLength(bic); | ||
validateCase(bic); | ||
validateBankCode(bic); | ||
validateCountryCode(bic); | ||
validateLocationCode(bic); | ||
export function getBankCode(bic: string): string { | ||
return bic.substring(BANK_CODE_INDEX, BANK_CODE_INDEX + BANK_CODE_LENGTH); | ||
} | ||
if (hasBranchCode(bic)) { | ||
validateBranchCode(bic); | ||
} | ||
export function getCountryCode(bic: string): string { | ||
return bic.substring(COUNTRY_CODE_INDEX, COUNTRY_CODE_INDEX + COUNTRY_CODE_LENGTH); | ||
} | ||
export function getLocationCode(bic: string): string { | ||
return bic.substring(LOCATION_CODE_INDEX, LOCATION_CODE_INDEX + LOCATION_CODE_LENGTH); | ||
} | ||
export function getBranchCode(bic: string): string { | ||
return bic.substring(BRANCH_CODE_INDEX, BRANCH_CODE_INDEX + BRANCH_CODE_LENGTH); | ||
} | ||
export function hasBranchCode(bic: string): boolean { | ||
return bic.length === BIC11_LENGTH; | ||
} | ||
function validateEmpty(bic: string) { | ||
if (bic == null) { | ||
throw new FormatException( | ||
FormatViolation.NOT_NULL, | ||
"Null can't be a valid Bic.", | ||
); | ||
throw new FormatException(FormatViolation.NOT_NULL, "Null can't be a valid Bic."); | ||
} | ||
if (bic.length === 0) { | ||
throw new FormatException( | ||
FormatViolation.NOT_EMPTY, | ||
"Empty string can't be a valid Bic.", | ||
); | ||
throw new FormatException(FormatViolation.NOT_EMPTY, "Empty string can't be a valid Bic."); | ||
} | ||
@@ -71,6 +61,3 @@ } | ||
if (bic !== bic.toUpperCase()) { | ||
throw new FormatException( | ||
FormatViolation.BIC_ONLY_UPPER_CASE_LETTERS, | ||
"Bic must contain only upper case letters.", | ||
); | ||
throw new FormatException(FormatViolation.BIC_ONLY_UPPER_CASE_LETTERS, "Bic must contain only upper case letters."); | ||
} | ||
@@ -83,7 +70,3 @@ } | ||
if (!ucRegex.test(bankCode)) { | ||
throw new FormatException( | ||
FormatViolation.BANK_CODE_ONLY_LETTERS, | ||
"Bank code must contain only letters.", | ||
bankCode, | ||
); | ||
throw new FormatException(FormatViolation.BANK_CODE_ONLY_LETTERS, "Bank code must contain only letters.", bankCode); | ||
} | ||
@@ -108,6 +91,3 @@ } | ||
if (countryByCode(countryCode) == null) { | ||
throw new UnsupportedCountryException( | ||
"Country code is not supported.", | ||
countryCode, | ||
); | ||
throw new UnsupportedCountryException("Country code is not supported.", countryCode); | ||
} | ||
@@ -140,29 +120,20 @@ } | ||
export function getBankCode(bic: string) { | ||
return bic.substring(BANK_CODE_INDEX, BANK_CODE_INDEX + BANK_CODE_LENGTH); | ||
} | ||
/** | ||
* Validates bic. | ||
* | ||
* @param bic to be validated. | ||
* @throws FormatException if bic is invalid. | ||
* UnsupportedCountryException if bic's country is not supported. | ||
*/ | ||
export function validate(bic: string): void { | ||
validateEmpty(bic); | ||
validateLength(bic); | ||
validateCase(bic); | ||
validateBankCode(bic); | ||
validateCountryCode(bic); | ||
validateLocationCode(bic); | ||
export function getCountryCode(bic: string) { | ||
return bic.substring( | ||
COUNTRY_CODE_INDEX, | ||
COUNTRY_CODE_INDEX + COUNTRY_CODE_LENGTH, | ||
); | ||
if (hasBranchCode(bic)) { | ||
validateBranchCode(bic); | ||
} | ||
} | ||
export function getLocationCode(bic: string) { | ||
return bic.substring( | ||
LOCATION_CODE_INDEX, | ||
LOCATION_CODE_INDEX + LOCATION_CODE_LENGTH, | ||
); | ||
} | ||
export function getBranchCode(bic: string) { | ||
return bic.substring( | ||
BRANCH_CODE_INDEX, | ||
BRANCH_CODE_INDEX + BRANCH_CODE_LENGTH, | ||
); | ||
} | ||
export function hasBranchCode(bic: string) { | ||
return bic.length === BIC11_LENGTH; | ||
} |
@@ -1,3 +0,1 @@ | ||
import { objectEntries } from "./poly"; | ||
/** | ||
@@ -262,3 +260,3 @@ * Country Code Enum | ||
const countryData: Record<CountryCode, string[]> = { | ||
const countryData: Record<CountryCode, [string, string]> = { | ||
[CountryCode.AD]: ["Andorra", "AND"], | ||
@@ -516,11 +514,17 @@ [CountryCode.AE]: ["United Arab Emirates", "ARE"], | ||
const by2code = objectEntries(countryData).reduce((acc, [k, v]) => { | ||
acc[k] = [k, v]; | ||
return acc; | ||
}, {}); | ||
const by2code = Object.entries(countryData).reduce( | ||
(acc, [k, v]) => { | ||
acc[k] = [k as CountryCode, v]; | ||
return acc; | ||
}, | ||
{} as Record<string, [CountryCode, [string, string]]>, | ||
); | ||
const by3code = objectEntries(countryData).reduce((acc, [k, v]) => { | ||
acc[v[1]] = [k, v]; | ||
return acc; | ||
}, {}); | ||
const by3code = Object.entries(countryData).reduce( | ||
(acc, [k, v]) => { | ||
acc[v[1]] = [k as CountryCode, v]; | ||
return acc; | ||
}, | ||
{} as Record<string, [CountryCode, [string, string]]>, | ||
); | ||
@@ -527,0 +531,0 @@ export function countryByCode(code: string): CountryCode | null { |
@@ -37,11 +37,8 @@ export enum FormatViolation { | ||
formatViolation: FormatViolation; | ||
actual?: string; | ||
expected?: string; | ||
constructor( | ||
formatViolation: FormatViolation, | ||
msg: string, | ||
expected?: string, | ||
actual?: string, | ||
) { | ||
constructor(formatViolation: FormatViolation, msg: string, expected?: string, actual?: string) { | ||
super(msg); | ||
@@ -72,2 +69,3 @@ | ||
actual?: string; | ||
expected?: string; | ||
@@ -74,0 +72,0 @@ |
@@ -6,3 +6,3 @@ import * as ibanUtil from "./ibanUtil"; | ||
// Some useful RegEx-s | ||
const NON_ALPHANUM = /[^a-zA-Z0-9]/g; | ||
const NON_ALPHANUM = /[^a-z0-9]/ig; | ||
@@ -257,3 +257,3 @@ const samples: Record<string, string> = { | ||
*/ | ||
toString() { | ||
toString(): string { | ||
return this.value; | ||
@@ -370,4 +370,4 @@ } | ||
return s !== undefined ? s : samples["DE"]; | ||
return s !== undefined ? s : samples[CountryCode.DE]; | ||
} | ||
} |
@@ -6,7 +6,3 @@ import * as ibanUtil from "./ibanUtil"; | ||
import { randInt } from "./randInt"; | ||
import { | ||
UnsupportedCountryException, | ||
FormatViolation, | ||
FormatException, | ||
} from "./exceptions"; | ||
import { UnsupportedCountryException, FormatViolation, FormatException } from "./exceptions"; | ||
import { IBAN } from "./iban"; | ||
@@ -19,9 +15,17 @@ | ||
private countryCodeValue?: CountryCode; | ||
private bankCodeValue?: string; | ||
private branchCodeValue?: string; | ||
private nationalCheckDigitValue?: string; | ||
private accountTypeValue?: string; | ||
private accountNumberValue?: string; | ||
private ownerAccountTypeValue?: string; | ||
private identificationNumberValue?: string; | ||
private branchCheckDigitValue?: string; | ||
@@ -32,3 +36,3 @@ | ||
*/ | ||
public constructor() {} | ||
// public constructor() {} | ||
@@ -180,6 +184,3 @@ /** | ||
if (structure === null) { | ||
throw new UnsupportedCountryException( | ||
"Country code is not supported.", | ||
this.countryCodeValue, | ||
); | ||
throw new UnsupportedCountryException("Country code is not supported.", this.countryCodeValue); | ||
} | ||
@@ -190,24 +191,40 @@ | ||
case PartType.BANK_CODE: | ||
parts.push(this.bankCodeValue!); | ||
if (typeof this.bankCodeValue === "string") { | ||
parts.push(this.bankCodeValue); | ||
} | ||
break; | ||
case PartType.BRANCH_CODE: | ||
parts.push(this.branchCodeValue!); | ||
if (typeof this.branchCodeValue === "string") { | ||
parts.push(this.branchCodeValue); | ||
} | ||
break; | ||
case PartType.BRANCH_CHECK_DIGIT: | ||
parts.push(this.branchCheckDigitValue!); | ||
if (typeof this.branchCheckDigitValue === "string") { | ||
parts.push(this.branchCheckDigitValue); | ||
} | ||
break; | ||
case PartType.ACCOUNT_NUMBER: | ||
parts.push(this.accountNumberValue!); | ||
if (typeof this.accountNumberValue === "string") { | ||
parts.push(this.accountNumberValue); | ||
} | ||
break; | ||
case PartType.NATIONAL_CHECK_DIGIT: | ||
parts.push(this.nationalCheckDigitValue!); | ||
if (typeof this.nationalCheckDigitValue === "string") { | ||
parts.push(this.nationalCheckDigitValue); | ||
} | ||
break; | ||
case PartType.ACCOUNT_TYPE: | ||
parts.push(this.accountTypeValue!); | ||
if (typeof this.accountTypeValue === "string") { | ||
parts.push(this.accountTypeValue); | ||
} | ||
break; | ||
case PartType.OWNER_ACCOUNT_NUMBER: | ||
parts.push(this.ownerAccountTypeValue!); | ||
if (typeof this.ownerAccountTypeValue === "string") { | ||
parts.push(this.ownerAccountTypeValue); | ||
} | ||
break; | ||
case PartType.IDENTIFICATION_NUMBER: | ||
parts.push(this.identificationNumberValue!); | ||
if (typeof this.identificationNumberValue === "string") { | ||
parts.push(this.identificationNumberValue); | ||
} | ||
break; | ||
@@ -224,5 +241,3 @@ } | ||
private formatIban(): string { | ||
return `${this.countryCodeValue}${ | ||
ibanUtil.DEFAULT_CHECK_DIGIT | ||
}${this.formatBban()}`; | ||
return `${this.countryCodeValue}${ibanUtil.DEFAULT_CHECK_DIGIT}${this.formatBban()}`; | ||
} | ||
@@ -234,6 +249,3 @@ | ||
if (structure == null) { | ||
throw new UnsupportedCountryException( | ||
"Country code is not supported.", | ||
this.countryCodeValue, | ||
); | ||
throw new UnsupportedCountryException("Country code is not supported.", this.countryCodeValue); | ||
} | ||
@@ -249,6 +261,3 @@ | ||
} else if (!fillRandom) { | ||
throw new FormatException( | ||
FormatViolation.NOT_NULL, | ||
"bankCode is required; it cannot be null", | ||
); | ||
throw new FormatException(FormatViolation.NOT_NULL, "bankCode is required; it cannot be null"); | ||
} | ||
@@ -260,6 +269,3 @@ break; | ||
} else if (!fillRandom) { | ||
throw new FormatException( | ||
FormatViolation.NOT_NULL, | ||
"branchCode is required; it cannot be null", | ||
); | ||
throw new FormatException(FormatViolation.NOT_NULL, "branchCode is required; it cannot be null"); | ||
} | ||
@@ -271,6 +277,3 @@ break; | ||
} else if (!fillRandom) { | ||
throw new FormatException( | ||
FormatViolation.NOT_NULL, | ||
"branchCheckDigit is required; it cannot be null", | ||
); | ||
throw new FormatException(FormatViolation.NOT_NULL, "branchCheckDigit is required; it cannot be null"); | ||
} | ||
@@ -282,6 +285,3 @@ break; | ||
} else if (!fillRandom) { | ||
throw new FormatException( | ||
FormatViolation.NOT_NULL, | ||
"accountNumber is required; it cannot be null", | ||
); | ||
throw new FormatException(FormatViolation.NOT_NULL, "accountNumber is required; it cannot be null"); | ||
} | ||
@@ -299,6 +299,3 @@ break; | ||
} else if (!fillRandom) { | ||
throw new FormatException( | ||
FormatViolation.NOT_NULL, | ||
"accountType is required; it cannot be null", | ||
); | ||
throw new FormatException(FormatViolation.NOT_NULL, "accountType is required; it cannot be null"); | ||
} | ||
@@ -310,6 +307,3 @@ break; | ||
} else if (!fillRandom) { | ||
throw new FormatException( | ||
FormatViolation.NOT_NULL, | ||
"ownerAccountType is required; it cannot be null", | ||
); | ||
throw new FormatException(FormatViolation.NOT_NULL, "ownerAccountType is required; it cannot be null"); | ||
} | ||
@@ -321,6 +315,3 @@ break; | ||
} else if (!fillRandom) { | ||
throw new FormatException( | ||
FormatViolation.NOT_NULL, | ||
"indentificationNumber is required; it cannot be null", | ||
); | ||
throw new FormatException(FormatViolation.NOT_NULL, "indentificationNumber is required; it cannot be null"); | ||
} | ||
@@ -327,0 +318,0 @@ break; |
@@ -0,1 +1,2 @@ | ||
/* eslint-disable @typescript-eslint/no-use-before-define */ | ||
import { CountryCode, countryByCode } from "./country"; | ||
@@ -52,3 +53,3 @@ import { BbanStructure } from "./bbanStructure"; | ||
*/ | ||
export function validate(iban: string) { | ||
export function validate(iban: string): void { | ||
validateNotEmpty(iban); | ||
@@ -68,3 +69,3 @@ validateCountryCode(iban, true); | ||
*/ | ||
export function validateCheckDigit(iban: string) { | ||
export function validateCheckDigit(iban: string): void { | ||
validateNotEmpty(iban); | ||
@@ -85,3 +86,3 @@ validateCheckDigitPresence(iban); | ||
*/ | ||
export function validateBban(countryCode: string, bban: string) { | ||
export function validateBban(countryCode: string, bban: string): void { | ||
validateCountryCode(countryCode, true); | ||
@@ -134,6 +135,3 @@ | ||
export function getCheckDigit(iban: string): string { | ||
return iban.substring( | ||
CHECK_DIGIT_INDEX, | ||
CHECK_DIGIT_INDEX + CHECK_DIGIT_LENGTH, | ||
); | ||
return iban.substring(CHECK_DIGIT_INDEX, CHECK_DIGIT_INDEX + CHECK_DIGIT_LENGTH); | ||
} | ||
@@ -148,6 +146,3 @@ | ||
export function getCountryCode(iban: string): string { | ||
return iban.substring( | ||
COUNTRY_CODE_INDEX, | ||
COUNTRY_CODE_INDEX + COUNTRY_CODE_LENGTH, | ||
); | ||
return iban.substring(COUNTRY_CODE_INDEX, COUNTRY_CODE_INDEX + COUNTRY_CODE_LENGTH); | ||
} | ||
@@ -162,6 +157,3 @@ | ||
export function getCountryCodeAndCheckDigit(iban: string): string { | ||
return iban.substring( | ||
COUNTRY_CODE_INDEX, | ||
COUNTRY_CODE_INDEX + COUNTRY_CODE_LENGTH + CHECK_DIGIT_LENGTH, | ||
); | ||
return iban.substring(COUNTRY_CODE_INDEX, COUNTRY_CODE_INDEX + COUNTRY_CODE_LENGTH + CHECK_DIGIT_LENGTH); | ||
} | ||
@@ -290,6 +282,3 @@ | ||
*/ | ||
export function toFormattedString( | ||
iban: string, | ||
separator: string = " ", | ||
): string { | ||
export function toFormattedString(iban: string, separator: string = " "): string { | ||
return iban.replace(/(.{4})/g, `$1${separator}`).trim(); | ||
@@ -302,6 +291,3 @@ } | ||
*/ | ||
export function toFormattedStringBBAN( | ||
iban: string, | ||
separator: string = " ", | ||
): string { | ||
export function toFormattedStringBBAN(iban: string, separator: string = " "): string { | ||
const structure = getBbanStructure(iban); | ||
@@ -324,3 +310,3 @@ | ||
export function validateCheckDigitChecksum(iban: string) { | ||
export function validateCheckDigitChecksum(iban: string): void { | ||
if (calculateMod(iban) != 1) { | ||
@@ -340,13 +326,7 @@ const checkDigit = getCheckDigit(iban); | ||
if (iban == null) { | ||
throw new FormatException( | ||
FormatViolation.NOT_NULL, | ||
"Null can't be a valid Iban.", | ||
); | ||
throw new FormatException(FormatViolation.NOT_NULL, "Null can't be a valid Iban."); | ||
} | ||
if (iban.length === 0) { | ||
throw new FormatException( | ||
FormatViolation.NOT_EMPTY, | ||
"Empty string can't be a valid Iban.", | ||
); | ||
throw new FormatException(FormatViolation.NOT_EMPTY, "Empty string can't be a valid Iban."); | ||
} | ||
@@ -358,7 +338,3 @@ } | ||
if (iban.length < COUNTRY_CODE_LENGTH) { | ||
throw new FormatException( | ||
FormatViolation.COUNTRY_CODE_TWO_LETTERS, | ||
"Iban must contain 2 char country code.", | ||
iban, | ||
); | ||
throw new FormatException(FormatViolation.COUNTRY_CODE_TWO_LETTERS, "Iban must contain 2 char country code.", iban); | ||
} | ||
@@ -390,6 +366,3 @@ | ||
if (structure == null) { | ||
throw new UnsupportedCountryException( | ||
"Country code is not supported.", | ||
countryCode, | ||
); | ||
throw new UnsupportedCountryException("Country code is not supported.", countryCode); | ||
} | ||
@@ -445,15 +418,11 @@ } | ||
.split("") | ||
.reduce((total, ch) => { | ||
.reduce((totalValue, ch) => { | ||
const code = ch.charCodeAt(0); | ||
if (VA <= code && code <= VZ) { | ||
return addSum(total, code - VA + 10); | ||
return addSum(totalValue, code - VA + 10); | ||
} else if (V0 <= code && code <= V9) { | ||
return addSum(total, code - V0); | ||
return addSum(totalValue, code - V0); | ||
} else { | ||
throw new FormatException( | ||
FormatViolation.IBAN_VALID_CHARACTERS, | ||
`Invalid Character[${ch}] = '${code}'`, | ||
ch, | ||
); | ||
throw new FormatException(FormatViolation.IBAN_VALID_CHARACTERS, `Invalid Character[${ch}] = '${code}'`, ch); | ||
} | ||
@@ -475,5 +444,3 @@ }, 0); | ||
function getBbanStructureByCountry( | ||
countryCode: CountryCode, | ||
): BbanStructure | null { | ||
function getBbanStructureByCountry(countryCode: CountryCode): BbanStructure | null { | ||
return BbanStructure.forCountry(countryCode); | ||
@@ -480,0 +447,0 @@ } |
@@ -1,3 +0,3 @@ | ||
export function randInt(maxVal: number, minVal: number = 0) { | ||
export function randInt(maxVal: number, minVal: number = 0): number { | ||
return Math.floor(Math.random() * maxVal) + minVal; | ||
} |
@@ -58,6 +58,11 @@ import { randInt } from "./randInt"; | ||
private entryType: PartType; | ||
private characterType: CharacterType; | ||
private length: number; | ||
trailingSeparator: boolean; | ||
generate: GenerateValue; | ||
hasGenerator: boolean; | ||
@@ -80,13 +85,4 @@ | ||
static bankCode( | ||
length: number, | ||
characterType: CharacterType, | ||
trailingSeparator: boolean = true, | ||
): BbanStructurePart { | ||
return new BbanStructurePart( | ||
PartType.BANK_CODE, | ||
characterType, | ||
length, | ||
trailingSeparator, | ||
); | ||
static bankCode(length: number, characterType: CharacterType, trailingSeparator: boolean = true): BbanStructurePart { | ||
return new BbanStructurePart(PartType.BANK_CODE, characterType, length, trailingSeparator); | ||
} | ||
@@ -99,8 +95,3 @@ | ||
): BbanStructurePart { | ||
return new BbanStructurePart( | ||
PartType.BRANCH_CODE, | ||
characterType, | ||
length, | ||
trailingSeparator, | ||
); | ||
return new BbanStructurePart(PartType.BRANCH_CODE, characterType, length, trailingSeparator); | ||
} | ||
@@ -113,8 +104,3 @@ | ||
): BbanStructurePart { | ||
return new BbanStructurePart( | ||
PartType.ACCOUNT_NUMBER, | ||
characterType, | ||
length, | ||
trailingSeparator, | ||
); | ||
return new BbanStructurePart(PartType.ACCOUNT_NUMBER, characterType, length, trailingSeparator); | ||
} | ||
@@ -128,9 +114,3 @@ | ||
): BbanStructurePart { | ||
return new BbanStructurePart( | ||
PartType.NATIONAL_CHECK_DIGIT, | ||
characterType, | ||
length, | ||
trailingSeparator, | ||
generate, | ||
); | ||
return new BbanStructurePart(PartType.NATIONAL_CHECK_DIGIT, characterType, length, trailingSeparator, generate); | ||
} | ||
@@ -144,9 +124,3 @@ | ||
): BbanStructurePart { | ||
return new BbanStructurePart( | ||
PartType.BRANCH_CHECK_DIGIT, | ||
characterType, | ||
length, | ||
trailingSeparator, | ||
generate, | ||
); | ||
return new BbanStructurePart(PartType.BRANCH_CHECK_DIGIT, characterType, length, trailingSeparator, generate); | ||
} | ||
@@ -159,8 +133,3 @@ | ||
): BbanStructurePart { | ||
return new BbanStructurePart( | ||
PartType.ACCOUNT_TYPE, | ||
characterType, | ||
length, | ||
trailingSeparator, | ||
); | ||
return new BbanStructurePart(PartType.ACCOUNT_TYPE, characterType, length, trailingSeparator); | ||
} | ||
@@ -173,8 +142,3 @@ | ||
): BbanStructurePart { | ||
return new BbanStructurePart( | ||
PartType.CURRENCY_TYPE, | ||
characterType, | ||
length, | ||
trailingSeparator, | ||
); | ||
return new BbanStructurePart(PartType.CURRENCY_TYPE, characterType, length, trailingSeparator); | ||
} | ||
@@ -187,8 +151,3 @@ | ||
): BbanStructurePart { | ||
return new BbanStructurePart( | ||
PartType.OWNER_ACCOUNT_NUMBER, | ||
characterType, | ||
length, | ||
trailingSeparator, | ||
); | ||
return new BbanStructurePart(PartType.OWNER_ACCOUNT_NUMBER, characterType, length, trailingSeparator); | ||
} | ||
@@ -201,8 +160,3 @@ | ||
): BbanStructurePart { | ||
return new BbanStructurePart( | ||
PartType.IDENTIFICATION_NUMBER, | ||
characterType, | ||
length, | ||
trailingSeparator, | ||
); | ||
return new BbanStructurePart(PartType.IDENTIFICATION_NUMBER, characterType, length, trailingSeparator); | ||
} | ||
@@ -232,6 +186,7 @@ | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
private defaultGenerator(bban: string, structure: BbanStructure): string { | ||
const charChoices = charByCharacterType[this.characterType]; | ||
let s: string[] = []; | ||
const s: string[] = []; | ||
for (let i = 0; i < this.getLength(); i += 1) { | ||
@@ -238,0 +193,0 @@ s.push(charChoices[randInt(charChoices.length)]); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
Found 1 instance in 1 package
520224
58
7218
1
15
91
1