From af3ff454e2b84660f8ea0ac3e428c52129e2a0a8 Mon Sep 17 00:00:00 2001 From: rrbharath Date: Mon, 8 Jun 2026 19:27:26 -0400 Subject: [PATCH] feat(isISMN): add validator for isISMN --- README.md | 2 ++ src/index.js | 2 ++ src/lib/isISMN.js | 27 +++++++++++++++++++++++++ test/validators/isISMN.test.js | 37 ++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+) create mode 100644 src/lib/isISMN.js create mode 100644 test/validators/isISMN.test.js diff --git a/README.md b/README.md index 8ef42fd79..2d99bd4bb 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ Validator | Description **isIPRange(str [, version])** | check if the string is an IP Range (version 4 or 6). **isISBN(str [, options])** | check if the string is an [ISBN][ISBN].

`options` is an object that has no default.
**Options:**
`version`: ISBN version to compare to. Accepted values are '10' and '13'. If none provided, both will be tested. **isISIN(str)** | check if the string is an [ISIN][ISIN] (stock/security identifier). +**isISMN(str)** | check if the string is an [ISMN][ISMN]. Supports the modern 13-digit format beginning with `979-0` and the legacy 10-character format beginning with `M`. **isISO6346(str)** | check if the string is a valid [ISO 6346](https://en.wikipedia.org/wiki/ISO_6346) shipping container identification. **isISO6391(str)** | check if the string is a valid [ISO 639-1][ISO 639-1] language code. **isISO8601(str [, options])** | check if the string is a valid [ISO 8601][ISO 8601] date.
`options` is an object which defaults to `{ strict: false, strictSeparator: false }`. If `strict` is true, date strings with invalid dates like `2009-02-29` will be invalid. If `strictSeparator` is true, date strings with date and time separated by anything other than a T will be invalid. @@ -251,6 +252,7 @@ This project is licensed under the [MIT](LICENSE). See the [LICENSE](LICENSE) fi [IMEI]: https://en.wikipedia.org/wiki/International_Mobile_Equipment_Identity [ISBN]: https://en.wikipedia.org/wiki/ISBN [ISIN]: https://en.wikipedia.org/wiki/International_Securities_Identification_Number +[ISMN]: https://ismn-international.org/ismn/the-ismn/ [ISO 639-1]: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601 [ISO 15924]: https://en.wikipedia.org/wiki/ISO_15924 diff --git a/src/index.js b/src/index.js index 3700cbd6c..92272bca8 100644 --- a/src/index.js +++ b/src/index.js @@ -79,6 +79,7 @@ import isIdentityCard from './lib/isIdentityCard'; import isEAN from './lib/isEAN'; import isISIN from './lib/isISIN'; import isISBN from './lib/isISBN'; +import isISMN from './lib/isISMN'; import isISSN from './lib/isISSN'; import isTaxID from './lib/isTaxID'; @@ -200,6 +201,7 @@ const validator = { isEAN, isISIN, isISBN, + isISMN, isISSN, isMobilePhone, isMobilePhoneLocales, diff --git a/src/lib/isISMN.js b/src/lib/isISMN.js new file mode 100644 index 000000000..9b0b9a0c1 --- /dev/null +++ b/src/lib/isISMN.js @@ -0,0 +1,27 @@ +import assertString from './util/assertString'; + +const possibleIsmn10 = /^M[0-9]{9}$/; +const possibleIsmn13 = /^9790[0-9]{9}$/; +const factor = [1, 3]; + +function hasValidCheckDigit(ismn) { + let checksum = 0; + + for (let i = 0; i < 12; i++) { + checksum += factor[i % 2] * Number(ismn.charAt(i)); + } + + return Number(ismn.charAt(12)) === ((10 - (checksum % 10)) % 10); +} + +export default function isISMN(ismn) { + assertString(ismn); + + const sanitizedIsmn = ismn.replace(/[\s-]+/g, '').toUpperCase(); + + if (possibleIsmn10.test(sanitizedIsmn)) { + return hasValidCheckDigit(`9790${sanitizedIsmn.slice(1)}`); + } + + return possibleIsmn13.test(sanitizedIsmn) && hasValidCheckDigit(sanitizedIsmn); +} diff --git a/test/validators/isISMN.test.js b/test/validators/isISMN.test.js new file mode 100644 index 000000000..f17099ee8 --- /dev/null +++ b/test/validators/isISMN.test.js @@ -0,0 +1,37 @@ +import test from '../testFunctions'; + +describe('isISMN', () => { + it('should validate ISMNs', () => { + test({ + validator: 'isISMN', + valid: [ + '9790345246805', + '979-0-345-24680-5', + '979 0 345 24680 5', + '9790215901001', + '979-0-2159-0100-1', + '979 0 2159 0100 1', + 'M345246805', + 'M-345-24680-5', + 'M 345 24680 5', + 'm-345-24680-5', + 'M230671187', + 'M-2306-7118-7', + ], + invalid: [ + '9790345246800', + '979-0-345-24680-0', + '979-1-345-24680-5', + '9780345246805', + 'M345246800', + 'M-345-24680-0', + 'M-345-24680-X', + 'M-345-2468A-5', + '979034524680', + '97903452468055', + 'foo', + '', + ], + }); + }); +});