Skip to content

Commit

Permalink
feat(isISBN): allow usage of options object (#2157)
Browse files Browse the repository at this point in the history
  • Loading branch information
WikiRik authored Jan 30, 2023
1 parent 753c29d commit 6dba289
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 73 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ Validator | Description
**isInt(str [, options])** | check if the string is an integer.<br/><br/>`options` is an object which can contain the keys `min` and/or `max` to check the integer is within boundaries (e.g. `{ min: 10, max: 99 }`). `options` can also contain the key `allow_leading_zeroes`, which when set to false will disallow integer values with leading zeroes (e.g. `{ allow_leading_zeroes: false }`). Finally, `options` can contain the keys `gt` and/or `lt` which will enforce integers being greater than or less than, respectively, the value provided (e.g. `{gt: 1, lt: 4}` for a number between 1 and 4).
**isIP(str [, version])** | check if the string is an IP (version 4 or 6).
**isIPRange(str [, version])** | check if the string is an IP Range (version 4 or 6).
**isISBN(str [, version])** | check if the string is an [ISBN][ISBN] (version 10 or 13).
**isISBN(str [, options])** | check if the string is an [ISBN][ISBN].<br/><br/>`options` is an object that has no default.<br/>**Options:**<br/>`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).
**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. <br/>`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.
Expand Down
52 changes: 32 additions & 20 deletions src/lib/isISBN.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,55 @@
import assertString from './util/assertString';

const isbn10Maybe = /^(?:[0-9]{9}X|[0-9]{10})$/;
const isbn13Maybe = /^(?:[0-9]{13})$/;
const possibleIsbn10 = /^(?:[0-9]{9}X|[0-9]{10})$/;
const possibleIsbn13 = /^(?:[0-9]{13})$/;
const factor = [1, 3];

export default function isISBN(str, version = '') {
assertString(str);
version = String(version);
if (!version) {
return isISBN(str, 10) || isISBN(str, 13);
export default function isISBN(isbn, options) {
assertString(isbn);

// For backwards compatibility:
// isISBN(str [, version]), i.e. `options` could be used as argument for the legacy `version`
const version = String(options?.version || options);

if (!(options?.version || options)) {
return isISBN(isbn, { version: 10 }) || isISBN(isbn, { version: 13 });
}
const sanitized = str.replace(/[\s-]+/g, '');

const sanitizedIsbn = isbn.replace(/[\s-]+/g, '');

let checksum = 0;
let i;

if (version === '10') {
if (!isbn10Maybe.test(sanitized)) {
if (!possibleIsbn10.test(sanitizedIsbn)) {
return false;
}
for (i = 0; i < 9; i++) {
checksum += (i + 1) * sanitized.charAt(i);

for (let i = 0; i < version - 1; i++) {
checksum += (i + 1) * sanitizedIsbn.charAt(i);
}
if (sanitized.charAt(9) === 'X') {

if (sanitizedIsbn.charAt(9) === 'X') {
checksum += 10 * 10;
} else {
checksum += 10 * sanitized.charAt(9);
checksum += 10 * sanitizedIsbn.charAt(9);
}

if ((checksum % 11) === 0) {
return !!sanitized;
return true;
}
} else if (version === '13') {
if (!isbn13Maybe.test(sanitized)) {
if (!possibleIsbn13.test(sanitizedIsbn)) {
return false;
}
for (i = 0; i < 12; i++) {
checksum += factor[i % 2] * sanitized.charAt(i);

for (let i = 0; i < 12; i++) {
checksum += factor[i % 2] * sanitizedIsbn.charAt(i);
}
if (sanitized.charAt(12) - ((10 - (checksum % 10)) % 10) === 0) {
return !!sanitized;

if (sanitizedIsbn.charAt(12) - ((10 - (checksum % 10)) % 10) === 0) {
return true;
}
}

return false;
}
52 changes: 0 additions & 52 deletions test/validators.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5860,58 +5860,6 @@ describe('Validators', () => {
});
});

it('should validate ISBNs', () => {
test({
validator: 'isISBN',
args: [10],
valid: [
'3836221195', '3-8362-2119-5', '3 8362 2119 5',
'1617290858', '1-61729-085-8', '1 61729 085-8',
'0007269706', '0-00-726970-6', '0 00 726970 6',
'3423214120', '3-423-21412-0', '3 423 21412 0',
'340101319X', '3-401-01319-X', '3 401 01319 X',
],
invalid: [
'3423214121', '3-423-21412-1', '3 423 21412 1',
'978-3836221191', '9783836221191',
'123456789a', 'foo', '',
],
});
test({
validator: 'isISBN',
args: [13],
valid: [
'9783836221191', '978-3-8362-2119-1', '978 3 8362 2119 1',
'9783401013190', '978-3401013190', '978 3401013190',
'9784873113685', '978-4-87311-368-5', '978 4 87311 368 5',
],
invalid: [
'9783836221190', '978-3-8362-2119-0', '978 3 8362 2119 0',
'3836221195', '3-8362-2119-5', '3 8362 2119 5',
'01234567890ab', 'foo', '',
],
});
test({
validator: 'isISBN',
valid: [
'340101319X',
'9784873113685',
],
invalid: [
'3423214121',
'9783836221190',
],
});
test({
validator: 'isISBN',
args: ['foo'],
invalid: [
'340101319X',
'9784873113685',
],
});
});

it('should validate EANs', () => {
test({
validator: 'isEAN',
Expand Down
109 changes: 109 additions & 0 deletions test/validators/isISBN.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import test from '../testFunctions';

describe('isISBN', () => {
it('should validate ISBNs', () => {
test({
validator: 'isISBN',
args: [{ version: 10 }],
valid: [
'3836221195', '3-8362-2119-5', '3 8362 2119 5',
'1617290858', '1-61729-085-8', '1 61729 085-8',
'0007269706', '0-00-726970-6', '0 00 726970 6',
'3423214120', '3-423-21412-0', '3 423 21412 0',
'340101319X', '3-401-01319-X', '3 401 01319 X',
],
invalid: [
'3423214121', '3-423-21412-1', '3 423 21412 1',
'978-3836221191', '9783836221191',
'123456789a', 'foo', '',
],
});
test({
validator: 'isISBN',
args: [{ version: 13 }],
valid: [
'9783836221191', '978-3-8362-2119-1', '978 3 8362 2119 1',
'9783401013190', '978-3401013190', '978 3401013190',
'9784873113685', '978-4-87311-368-5', '978 4 87311 368 5',
],
invalid: [
'9783836221190', '978-3-8362-2119-0', '978 3 8362 2119 0',
'3836221195', '3-8362-2119-5', '3 8362 2119 5',
'01234567890ab', 'foo', '',
],
});
test({
validator: 'isISBN',
valid: [
'340101319X',
'9784873113685',
],
invalid: [
'3423214121',
'9783836221190',
],
});
test({
validator: 'isISBN',
args: [{ version: 'foo' }],
invalid: [
'340101319X',
'9784873113685',
],
});
});

describe('(legacy syntax)', () => {
it('should validate ISBNs', () => {
test({
validator: 'isISBN',
args: [10],
valid: [
'3836221195', '3-8362-2119-5', '3 8362 2119 5',
'1617290858', '1-61729-085-8', '1 61729 085-8',
'0007269706', '0-00-726970-6', '0 00 726970 6',
'3423214120', '3-423-21412-0', '3 423 21412 0',
'340101319X', '3-401-01319-X', '3 401 01319 X',
],
invalid: [
'3423214121', '3-423-21412-1', '3 423 21412 1',
'978-3836221191', '9783836221191',
'123456789a', 'foo', '',
],
});
test({
validator: 'isISBN',
args: [13],
valid: [
'9783836221191', '978-3-8362-2119-1', '978 3 8362 2119 1',
'9783401013190', '978-3401013190', '978 3401013190',
'9784873113685', '978-4-87311-368-5', '978 4 87311 368 5',
],
invalid: [
'9783836221190', '978-3-8362-2119-0', '978 3 8362 2119 0',
'3836221195', '3-8362-2119-5', '3 8362 2119 5',
'01234567890ab', 'foo', '',
],
});
test({
validator: 'isISBN',
valid: [
'340101319X',
'9784873113685',
],
invalid: [
'3423214121',
'9783836221190',
],
});
test({
validator: 'isISBN',
args: ['foo'],
invalid: [
'340101319X',
'9784873113685',
],
});
});
});
});

0 comments on commit 6dba289

Please sign in to comment.