diff --git a/src/lib/isISIN.js b/src/lib/isISIN.js index 4576b684c..a6f6fa645 100644 --- a/src/lib/isISIN.js +++ b/src/lib/isISIN.js @@ -2,6 +2,12 @@ import assertString from './util/assertString'; const isin = /^[A-Z]{2}[0-9A-Z]{9}[0-9]$/; +// this link details how the check digit is calculated: +// https://www.isin.org/isin-format/. it is a little bit +// odd in that it works with digits, not numbers. in order +// to make only one pass through the ISIN characters, the +// each alpha character is handled as 2 characters within +// the loop. export default function isISIN(str) { assertString(str); @@ -9,27 +15,44 @@ export default function isISIN(str) { return false; } - const checksumStr = str.replace(/[A-Z]/g, character => (parseInt(character, 36))); - + let double = true; let sum = 0; - let digit; - let tmpNum; - let shouldDouble = true; - for (let i = checksumStr.length - 2; i >= 0; i--) { - digit = checksumStr.substring(i, (i + 1)); - tmpNum = parseInt(digit, 10); - if (shouldDouble) { - tmpNum *= 2; - if (tmpNum >= 10) { - sum += tmpNum + 1; - } else { - sum += tmpNum; + // convert values + for (let i = str.length - 2; i >= 0; i--) { + if (str[i] >= 'A' && str[i] <= 'Z') { + const value = str[i].charCodeAt(0) - 55; + const lo = value % 10; + const hi = Math.trunc(value / 10); + // letters have two digits, so handle the low order + // and high order digits separately. + for (const digit of [lo, hi]) { + if (double) { + if (digit >= 5) { + sum += 1 + ((digit - 5) * 2); + } else { + sum += digit * 2; + } + } else { + sum += digit; + } + double = !double; } } else { - sum += tmpNum; + const digit = str[i].charCodeAt(0) - '0'.charCodeAt(0); + if (double) { + if (digit >= 5) { + sum += 1 + ((digit - 5) * 2); + } else { + sum += digit * 2; + } + } else { + sum += digit; + } + double = !double; } - shouldDouble = !shouldDouble; } - return parseInt(str.substr(str.length - 1), 10) === (10000 - sum) % 10; + const check = (Math.trunc(((sum + 9) / 10)) * 10) - sum; + + return +str[str.length - 1] === check; } diff --git a/test/validators.js b/test/validators.js index 2befa37d0..1f92e1480 100644 --- a/test/validators.js +++ b/test/validators.js @@ -4845,6 +4845,7 @@ describe('Validators', () => { 'GB0001411924', 'DE000WCH8881', 'PLLWBGD00016', + 'US0378331005', ], invalid: [ 'DE000BAY0018',