uk-modulus-check
Advanced tools
Comparing version 1.0.14 to 1.0.15
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.applyPostTotalExceptionRules = exports.applyOverwriteExceptionRules = exports.applyWeightValueExceptionRules = exports.applyAccountDetailExceptionRules = void 0; | ||
const fs_1 = require("fs"); | ||
const enums_1 = require("./enums"); | ||
const loadSubstitutionMap = () => (0, fs_1.readFileSync)(`${__dirname}/data/scsubtab.txt`, 'utf8') | ||
.split('\r\n') | ||
.map((line) => line.split(/\s+/)) | ||
.reduce((acc, [key, value]) => (Object.assign(Object.assign({}, acc), { [key]: value })), {}); | ||
const scsubtab_json_1 = __importDefault(require("./data/scsubtab.json")); | ||
const applyLengthAdjustments = (sortCode, accountNumber) => { | ||
@@ -27,7 +26,6 @@ let [adjustedSortCode, adjustedAccountNumber] = [sortCode, accountNumber]; | ||
}; | ||
const applyExceptionAdjustments = (sortCode, accountNumber, modulusWeightException) => { | ||
let [adjustedSortCode, adjustedAccountNumber] = [sortCode, accountNumber]; | ||
let substitutionMap = loadSubstitutionMap(); | ||
if (modulusWeightException === 5 && substitutionMap[sortCode]) { | ||
adjustedSortCode = substitutionMap[sortCode]; | ||
const applyExceptionAdjustments = (sortCode, modulusWeightException) => { | ||
let adjustedSortCode = sortCode; | ||
if (modulusWeightException === 5 && scsubtab_json_1.default[sortCode]) { | ||
adjustedSortCode = scsubtab_json_1.default[sortCode]; | ||
} | ||
@@ -40,8 +38,8 @@ else if (modulusWeightException === 8) { | ||
} | ||
return { sortCode: adjustedSortCode, accountNumber: adjustedAccountNumber }; | ||
return adjustedSortCode; | ||
}; | ||
const applyAccountDetailExceptionRules = (sortCode, accountNumber, modulusWeightException) => { | ||
const { sortCode: lengthAdjustedSortCode, accountNumber: lengthAdjustedAccountNumber, } = applyLengthAdjustments(sortCode, accountNumber); | ||
const { sortCode: exceptionAdjustedSortCode, accountNumber: exceptionAdjustedAccountNumber, } = applyExceptionAdjustments(lengthAdjustedSortCode, lengthAdjustedAccountNumber, modulusWeightException); | ||
return exceptionAdjustedSortCode + exceptionAdjustedAccountNumber; | ||
const exceptionAdjustedSortCode = applyExceptionAdjustments(lengthAdjustedSortCode, modulusWeightException); | ||
return exceptionAdjustedSortCode + lengthAdjustedAccountNumber; | ||
}; | ||
@@ -74,10 +72,5 @@ exports.applyAccountDetailExceptionRules = applyAccountDetailExceptionRules; | ||
const applyOverwriteExceptionRules = (modulusWeight, accountDetails) => { | ||
const a = accountDetails[enums_1.AccountDetailIndex.A]; | ||
const g = accountDetails[enums_1.AccountDetailIndex.G]; | ||
const h = accountDetails[enums_1.AccountDetailIndex.H]; | ||
// exception 3 is a special case where the first digit of the account number must be 1 or 9 | ||
if (modulusWeight.exception === 3 && ['1', '9'].includes(a)) { | ||
const { [enums_1.AccountDetailIndex.A]: a, [enums_1.AccountDetailIndex.G]: g, [enums_1.AccountDetailIndex.H]: h, } = accountDetails; | ||
if (modulusWeight.exception === 3 && ['1', '9'].includes(a)) | ||
return { modifiedAccountDetails: accountDetails, overwriteResult: true }; | ||
} | ||
// exception 6 is a special case where the first digit of the account number must be between 4 and 10 and the 7th and 8th digits must be the same | ||
if (modulusWeight.exception === 6 && | ||
@@ -108,5 +101,4 @@ parseInt(a, 10) >= 4 && | ||
if (exception == 4) { | ||
const remainder = total % 11; | ||
const checkDigit = parseInt(accountDetails.substring(accountDetails.length - 2), 10); | ||
if (remainder === checkDigit) { | ||
if (total % 11 === | ||
parseInt(accountDetails.substring(accountDetails.length - 2), 10)) { | ||
overwriteResult2 = true; | ||
@@ -113,0 +105,0 @@ } |
import { ModulusWeight } from './interfaces'; | ||
export default class ModulusChecker { | ||
private modulusWeighstArray; | ||
private unseenSortCodeBehaviour; | ||
constructor(unseenSortCodeBehaviour?: boolean); | ||
private loadModulusWeightsArray; | ||
modulusCheck: (modulusWeight: ModulusWeight, sortCode: string, accountNumber: string) => boolean; | ||
validate(sortCode: string, accountNumber: string): boolean; | ||
} |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const fs_1 = require("fs"); | ||
const enums_1 = require("./enums"); | ||
const ExceptionRules_1 = require("./ExceptionRules"); | ||
const valacdos_json_1 = __importDefault(require("./data/valacdos.json")); | ||
class ModulusChecker { | ||
constructor(unseenSortCodeBehaviour = true) { | ||
this.unseenSortCodeBehaviour = true; | ||
constructor() { | ||
this.modulusCheck = (modulusWeight, sortCode, accountNumber) => { | ||
@@ -17,5 +19,4 @@ // by default, the account details are the sort code followed by the account number | ||
const { modifiedAccountDetails, overwriteResult } = (0, ExceptionRules_1.applyOverwriteExceptionRules)(modulusWeight, accountDetails); | ||
if (overwriteResult !== null) { | ||
if (overwriteResult !== null) | ||
return overwriteResult; | ||
} | ||
// multiply each digit of the account details by the corresponding weight value | ||
@@ -39,56 +40,35 @@ const multiplicationResultArray = modifiedAccountDetails | ||
} | ||
// there are acceptions that are applied after the total has been calculated | ||
// there are exceptions that are applied after the total has been calculated | ||
// these can either adjust the total, or require a non-standard modulus check | ||
const { adjustedTotal, overwriteResult2 } = (0, ExceptionRules_1.applyPostTotalExceptionRules)(modulusWeight.exception, total, accountDetails); | ||
if (overwriteResult2 !== null) { | ||
if (overwriteResult2 !== null) | ||
return overwriteResult2; | ||
} | ||
if (modulusWeight.check_type === enums_1.CheckType.MOD11) { | ||
return adjustedTotal % 11 === 0; | ||
} | ||
else { | ||
return adjustedTotal % 10 === 0; | ||
} | ||
const checkTypeValue = modulusWeight.check_type === enums_1.CheckType.MOD11 ? 11 : 10; | ||
return adjustedTotal % checkTypeValue === 0; | ||
}; | ||
this.modulusWeighstArray = this.loadModulusWeightsArray(); | ||
this.unseenSortCodeBehaviour = unseenSortCodeBehaviour; | ||
} | ||
loadModulusWeightsArray() { | ||
return (0, fs_1.readFileSync)(`${__dirname}/data/valacdos-v7-90.txt`, 'utf8') | ||
.split('\r\n') | ||
.map((line) => { | ||
const data = line.split(/\s+/); | ||
return { | ||
start: parseInt(data[0], 10), | ||
end: parseInt(data[1], 10), | ||
check_type: data[2], | ||
exception: parseInt(data[17], 10) || null, | ||
weights: data.slice(3, 17).map((weight) => parseInt(weight, 10)), | ||
}; | ||
}); | ||
} | ||
validate(sortCode, accountNumber) { | ||
// sort code must be 6 digits and account number must be between 6 and 10 digits | ||
if (accountNumber.length < 6 || | ||
accountNumber.length > 10 || | ||
sortCode.length !== 6) { | ||
// sort code must be 6 digits, account number must be between 6 and 10 digits | ||
if (accountNumber.length <= 6 || | ||
accountNumber.length >= 10 || | ||
sortCode.length !== 6) | ||
return false; | ||
} | ||
// check if there are any non-numeric characters in the sort code or account number | ||
if (!/^\d+$/.test(sortCode + accountNumber)) { | ||
// sort code and account number must be numeric | ||
if (!/^\d+$/.test(sortCode + accountNumber)) | ||
return false; | ||
} | ||
const matchingModulusWeights = this.modulusWeighstArray.filter((weight) => parseInt(sortCode, 10) >= weight.start && | ||
// find the modulus weight that matches the sort code | ||
const matchingModulusWeights = valacdos_json_1.default.filter((weight) => weight.start && | ||
weight.end && | ||
parseInt(sortCode, 10) >= weight.start && | ||
parseInt(sortCode, 10) <= weight.end); | ||
// there must be at least one matching modulus weight, otherwise return the default behaviour | ||
if (!matchingModulusWeights.length) { | ||
return this.unseenSortCodeBehaviour; | ||
} | ||
// return true if any of the matching modulus weights pass the modulus | ||
// this includes the case where there are multiple matching modulus weights | ||
return matchingModulusWeights | ||
.map((weight) => this.modulusCheck(weight, sortCode, accountNumber)) | ||
.some((result) => result); | ||
// if there are no matching modulus weights, the sort code is not recognised | ||
// return true, since Vocalink data doesn't seem to have 100% coverage | ||
if (!matchingModulusWeights.length) | ||
return true; | ||
// if any of the matching modulus weights pass the modulus, the account number is valid | ||
// note, this is slightly conservative, and might return true for some invalid account numbers | ||
// find the actual spec. quite confusing on these cases | ||
return matchingModulusWeights.some((weight) => this.modulusCheck(weight, sortCode, accountNumber)); | ||
} | ||
} | ||
exports.default = ModulusChecker; |
import { CheckType } from './enums'; | ||
export interface ModulusWeight { | ||
start: number; | ||
end: number; | ||
check_type: CheckType; | ||
start: number | null; | ||
end: number | null; | ||
check_type?: CheckType; | ||
exception: number | null; | ||
@@ -7,0 +7,0 @@ weights: number[]; |
{ | ||
"name": "uk-modulus-check", | ||
"version": "1.0.14", | ||
"version": "1.0.15", | ||
"main": "dist/index.js", | ||
@@ -17,3 +17,4 @@ "types": "dist/index.d.ts", | ||
"test": "jest", | ||
"format": "prettier --write 'src/**/*.{ts,js,json,md}'" | ||
"format": "prettier --write 'src/**/*.{ts,js,json,md}'", | ||
"publish": "npm run build && npm publish" | ||
}, | ||
@@ -20,0 +21,0 @@ "keywords": [ |
@@ -61,2 +61,7 @@ import ModulusChecker from '../src'; | ||
test('should return true for a sort code not on the spec range', () => { | ||
const isValid = checker.validate('000000', '12345678'); | ||
expect(isValid).toBe(true); | ||
}); | ||
// Vocalink spec tests | ||
@@ -63,0 +68,0 @@ |
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
1334826
40
76377
2
0