aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin van der Vliet <[email protected]>2023-09-10 10:05:56 +0200
committerGitHub <[email protected]>2023-09-10 10:05:56 +0200
commitcb4ef2846ad8d09cdc4ca5366b6057f9f6e38783 (patch)
tree52eed7018da3cb7e3c54c232d88fd002bbd482b5
parent8a6ce4978fada63f6364237e968f427e0a198135 (diff)
downloadfaker-cb4ef2846ad8d09cdc4ca5366b6057f9f6e38783.tar.xz
faker-cb4ef2846ad8d09cdc4ca5366b6057f9f6e38783.zip
feat(commerce): add method for generating ISBN-10 and ISBN-13 (#2240)
-rw-r--r--src/modules/commerce/index.ts152
-rw-r--r--test/modules/__snapshots__/commerce.spec.ts.snap30
-rw-r--r--test/modules/commerce.spec.ts66
3 files changed, 248 insertions, 0 deletions
diff --git a/src/modules/commerce/index.ts b/src/modules/commerce/index.ts
index f0068415..2464af03 100644
--- a/src/modules/commerce/index.ts
+++ b/src/modules/commerce/index.ts
@@ -2,6 +2,79 @@ import type { Faker } from '../../faker';
import { bindThisToMemberFunctions } from '../../internal/bind-this-to-member-functions';
import { deprecated } from '../../internal/deprecated';
+// Source for official prefixes: https://www.isbn-international.org/range_file_generation
+const ISBN_LENGTH_RULES: Record<
+ string,
+ Array<[rangeMaximum: number, length: number]>
+> = {
+ '0': [
+ [1999999, 2],
+ [2279999, 3],
+ [2289999, 4],
+ [3689999, 3],
+ [3699999, 4],
+ [6389999, 3],
+ [6397999, 4],
+ [6399999, 7],
+ [6449999, 3],
+ [6459999, 7],
+ [6479999, 3],
+ [6489999, 7],
+ [6549999, 3],
+ [6559999, 4],
+ [6999999, 3],
+ [8499999, 4],
+ [8999999, 5],
+ [9499999, 6],
+ [9999999, 7],
+ ],
+ '1': [
+ [99999, 3],
+ [299999, 2],
+ [349999, 3],
+ [399999, 4],
+ [499999, 3],
+ [699999, 2],
+ [999999, 4],
+ [3979999, 3],
+ [5499999, 4],
+ [6499999, 5],
+ [6799999, 4],
+ [6859999, 5],
+ [7139999, 4],
+ [7169999, 3],
+ [7319999, 4],
+ [7399999, 7],
+ [7749999, 5],
+ [7753999, 7],
+ [7763999, 5],
+ [7764999, 7],
+ [7769999, 5],
+ [7782999, 7],
+ [7899999, 5],
+ [7999999, 4],
+ [8004999, 5],
+ [8049999, 5],
+ [8379999, 5],
+ [8384999, 7],
+ [8671999, 5],
+ [8675999, 4],
+ [8697999, 5],
+ [9159999, 6],
+ [9165059, 7],
+ [9168699, 6],
+ [9169079, 7],
+ [9195999, 6],
+ [9196549, 7],
+ [9729999, 6],
+ [9877999, 4],
+ [9911499, 6],
+ [9911999, 7],
+ [9989899, 6],
+ [9999999, 7],
+ ],
+};
+
/**
* Module to generate commerce and product related entries.
*
@@ -258,4 +331,83 @@ export class CommerceModule {
this.faker.definitions.commerce.product_description
);
}
+
+ /**
+ * Returns a random [ISBN](https://en.wikipedia.org/wiki/ISBN) identifier.
+ *
+ * @param options The variant to return or an options object. Defaults to `{}`.
+ * @param options.variant The variant to return. Can be either `10` (10-digit format)
+ * or `13` (13-digit format). Defaults to `13`.
+ * @param options.separator The separator to use in the format. Defaults to `'-'`.
+ *
+ * @example
+ * faker.commerce.isbn() // '978-0-692-82459-7'
+ * faker.commerce.isbn(10) // '1-155-36404-X'
+ * faker.commerce.isbn(13) // '978-1-60808-867-6'
+ * faker.commerce.isbn({ separator: ' ' }) // '978 0 452 81498 1'
+ * faker.commerce.isbn({ variant: 10, separator: ' ' }) // '0 940319 49 7'
+ * faker.commerce.isbn({ variant: 13, separator: ' ' }) // '978 1 6618 9122 0'
+ *
+ * @since 8.1.0
+ */
+ isbn(
+ options:
+ | 10
+ | 13
+ | {
+ /**
+ * The variant of the identifier to return.
+ * Can be either `10` (10-digit format)
+ * or `13` (13-digit format).
+ *
+ * @default 13
+ */
+ variant?: 10 | 13;
+
+ /**
+ * The separator to use in the format.
+ *
+ * @default '-'
+ */
+ separator?: string;
+ } = {}
+ ): string {
+ if (typeof options === 'number') {
+ options = { variant: options };
+ }
+
+ const { variant = 13, separator = '-' } = options;
+
+ const prefix = '978';
+ const [group, groupRules] =
+ this.faker.helpers.objectEntry(ISBN_LENGTH_RULES);
+ const element = this.faker.string.numeric(8);
+ const elementValue = parseInt(element.slice(0, -1));
+
+ const registrantLength = groupRules.find(
+ ([rangeMaximum]) => elementValue <= rangeMaximum
+ )[1];
+
+ const registrant = element.slice(0, registrantLength);
+ const publication = element.slice(registrantLength);
+
+ const data = [prefix, group, registrant, publication];
+ if (variant === 10) {
+ data.shift();
+ }
+
+ const isbn = data.join('');
+
+ let checksum = 0;
+ for (let i = 0; i < variant - 1; i++) {
+ const weight = variant === 10 ? i + 1 : i % 2 ? 3 : 1;
+ checksum += weight * parseInt(isbn[i]);
+ }
+
+ checksum = variant === 10 ? checksum % 11 : (10 - (checksum % 10)) % 10;
+
+ data.push(checksum === 10 ? 'X' : checksum.toString());
+
+ return data.join(separator);
+ }
}
diff --git a/test/modules/__snapshots__/commerce.spec.ts.snap b/test/modules/__snapshots__/commerce.spec.ts.snap
index 1dde6785..00b8f08e 100644
--- a/test/modules/__snapshots__/commerce.spec.ts.snap
+++ b/test/modules/__snapshots__/commerce.spec.ts.snap
@@ -2,6 +2,16 @@
exports[`commerce > 42 > department 1`] = `"Tools"`;
+exports[`commerce > 42 > isbn > noArgs 1`] = `"978-0-7917-7551-6"`;
+
+exports[`commerce > 42 > isbn > with space separators 1`] = `"978 0 7917 7551 6"`;
+
+exports[`commerce > 42 > isbn > with variant 10 1`] = `"0-7917-7551-8"`;
+
+exports[`commerce > 42 > isbn > with variant 10 and space separators 1`] = `"0 7917 7551 8"`;
+
+exports[`commerce > 42 > isbn > with variant 13 1`] = `"978-0-7917-7551-6"`;
+
exports[`commerce > 42 > price > noArgs 1`] = `"375.00"`;
exports[`commerce > 42 > price > with max 1`] = `"375.00"`;
@@ -36,6 +46,16 @@ exports[`commerce > 42 > productName 1`] = `"Fantastic Soft Sausages"`;
exports[`commerce > 1211 > department 1`] = `"Automotive"`;
+exports[`commerce > 1211 > isbn > noArgs 1`] = `"978-1-4872-1906-2"`;
+
+exports[`commerce > 1211 > isbn > with space separators 1`] = `"978 1 4872 1906 2"`;
+
+exports[`commerce > 1211 > isbn > with variant 10 1`] = `"1-4872-1906-7"`;
+
+exports[`commerce > 1211 > isbn > with variant 10 and space separators 1`] = `"1 4872 1906 7"`;
+
+exports[`commerce > 1211 > isbn > with variant 13 1`] = `"978-1-4872-1906-2"`;
+
exports[`commerce > 1211 > price > noArgs 1`] = `"929.00"`;
exports[`commerce > 1211 > price > with max 1`] = `"929.00"`;
@@ -70,6 +90,16 @@ exports[`commerce > 1211 > productName 1`] = `"Unbranded Cotton Salad"`;
exports[`commerce > 1337 > department 1`] = `"Computers"`;
+exports[`commerce > 1337 > isbn > noArgs 1`] = `"978-0-512-25403-0"`;
+
+exports[`commerce > 1337 > isbn > with space separators 1`] = `"978 0 512 25403 0"`;
+
+exports[`commerce > 1337 > isbn > with variant 10 1`] = `"0-512-25403-6"`;
+
+exports[`commerce > 1337 > isbn > with variant 10 and space separators 1`] = `"0 512 25403 6"`;
+
+exports[`commerce > 1337 > isbn > with variant 13 1`] = `"978-0-512-25403-0"`;
+
exports[`commerce > 1337 > price > noArgs 1`] = `"263.00"`;
exports[`commerce > 1337 > price > with max 1`] = `"263.00"`;
diff --git a/test/modules/commerce.spec.ts b/test/modules/commerce.spec.ts
index 15ad7aee..0588e228 100644
--- a/test/modules/commerce.spec.ts
+++ b/test/modules/commerce.spec.ts
@@ -1,3 +1,4 @@
+import validator from 'validator';
import { describe, expect, it } from 'vitest';
import { faker } from '../../src';
import { seededTests } from './../support/seededRuns';
@@ -38,6 +39,17 @@ describe('commerce', () => {
symbol: '$',
});
});
+
+ t.describe('isbn', (t) => {
+ t.it('noArgs')
+ .it('with variant 10', 10)
+ .it('with variant 13', 13)
+ .it('with variant 10 and space separators', {
+ variant: 10,
+ separator: ' ',
+ })
+ .it('with space separators', { separator: ' ' });
+ });
});
describe.each(times(NON_SEEDED_BASED_RUN).map(() => faker.seed()))(
@@ -158,6 +170,60 @@ describe('commerce', () => {
);
});
});
+
+ describe(`isbn()`, () => {
+ it('should return ISBN-13 with hyphen separators when not passing arguments', () => {
+ const isbn = faker.commerce.isbn();
+
+ expect(isbn).toBeTruthy();
+ expect(isbn).toBeTypeOf('string');
+ expect(
+ isbn,
+ 'The expected match should be ISBN-13 with hyphens'
+ ).toMatch(/^978-[01]-[\d-]{9}-\d$/);
+ expect(isbn).toSatisfy((isbn: string) => validator.isISBN(isbn, 13));
+ });
+
+ it('should return ISBN-10 with hyphen separators when passing variant 10 as argument', () => {
+ const isbn = faker.commerce.isbn(10);
+
+ expect(
+ isbn,
+ 'The expected match should be ISBN-10 with hyphens'
+ ).toMatch(/^[01]-[\d-]{9}-[\dX]$/);
+ expect(isbn).toSatisfy((isbn: string) => validator.isISBN(isbn, 10));
+ });
+
+ it('should return ISBN-13 with hyphen separators when passing variant 13 as argument', () => {
+ const isbn = faker.commerce.isbn(13);
+
+ expect(
+ isbn,
+ 'The expected match should be ISBN-13 with hyphens'
+ ).toMatch(/^978-[01]-[\d-]{9}-\d$/);
+ expect(isbn).toSatisfy((isbn: string) => validator.isISBN(isbn, 13));
+ });
+
+ it('should return ISBN-10 with space separators when passing variant 10 and space separators as argument', () => {
+ const isbn = faker.commerce.isbn({ variant: 10, separator: ' ' });
+
+ expect(
+ isbn,
+ 'The expected match should be ISBN-10 with space separators'
+ ).toMatch(/^[01] [\d ]{9} [\dX]$/);
+ expect(isbn).toSatisfy((isbn: string) => validator.isISBN(isbn, 10));
+ });
+
+ it('should return ISBN-13 with space separators when passing space separators as argument', () => {
+ const isbn = faker.commerce.isbn({ separator: ' ' });
+
+ expect(
+ isbn,
+ 'The expected match should be ISBN-13 with space separators'
+ ).toMatch(/^978 [01] [\d ]{9} \d$/);
+ expect(isbn).toSatisfy((isbn: string) => validator.isISBN(isbn, 13));
+ });
+ });
}
);
});