aboutsummaryrefslogtreecommitdiff
path: root/src/modules
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/address/index.ts488
-rw-r--r--src/modules/animal/index.ts164
-rw-r--r--src/modules/commerce/index.ts133
-rw-r--r--src/modules/company/index.ts153
-rw-r--r--src/modules/database/index.ts75
-rw-r--r--src/modules/datatype/index.ts305
-rw-r--r--src/modules/date/index.ts256
-rw-r--r--src/modules/fake/index.ts134
-rw-r--r--src/modules/finance/iban.ts1414
-rw-r--r--src/modules/finance/index.ts436
-rw-r--r--src/modules/git/index.ts134
-rw-r--r--src/modules/hacker/index.ts94
-rw-r--r--src/modules/helpers/index.ts810
-rw-r--r--src/modules/image/index.ts345
-rw-r--r--src/modules/image/providers/lorempicsum.ts126
-rw-r--r--src/modules/image/providers/lorempixel.ts288
-rw-r--r--src/modules/image/providers/unsplash.ts157
-rw-r--r--src/modules/internet/index.ts458
-rw-r--r--src/modules/internet/user-agent.ts345
-rw-r--r--src/modules/lorem/index.ts205
-rw-r--r--src/modules/mersenne/index.ts73
-rw-r--r--src/modules/mersenne/twister.ts320
-rw-r--r--src/modules/music/index.ts26
-rw-r--r--src/modules/name/index.ts350
-rw-r--r--src/modules/phone/index.ts76
-rw-r--r--src/modules/random/index.ts648
-rw-r--r--src/modules/system/index.ts194
-rw-r--r--src/modules/time/index.ts57
-rw-r--r--src/modules/unique/index.ts139
-rw-r--r--src/modules/unique/unique.ts158
-rw-r--r--src/modules/vehicle/index.ts131
-rw-r--r--src/modules/word/index.ts174
32 files changed, 8866 insertions, 0 deletions
diff --git a/src/modules/address/index.ts b/src/modules/address/index.ts
new file mode 100644
index 00000000..db82e01e
--- /dev/null
+++ b/src/modules/address/index.ts
@@ -0,0 +1,488 @@
+import type { Faker } from '../..';
+
+/**
+ * Module to generate addresses and locations.
+ */
+export class Address {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Address.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Generates random zip code from specified format. If format is not specified,
+ * the locale's zip format is used.
+ *
+ * @param format The optional format used to generate the the zip code.
+ * By default, a random format is used from the locale zip formats.
+ *
+ * @see faker.helpers.replaceSymbols()
+ *
+ * @example
+ * faker.address.zipCode() // '17839'
+ * faker.address.zipCode('####') // '6925'
+ *
+ */
+ zipCode(format?: string): string {
+ // if zip format is not specified, use the zip format defined for the locale
+ if (format == null) {
+ const localeFormat = this.faker.definitions.address.postcode;
+ if (typeof localeFormat === 'string') {
+ format = localeFormat;
+ } else {
+ format = this.faker.helpers.arrayElement(localeFormat);
+ }
+ }
+ return this.faker.helpers.replaceSymbols(format);
+ }
+
+ /**
+ * Generates random zip code from state abbreviation. If state abbreviation is
+ * not specified, a random zip code is generated according to the locale's zip format.
+ * Only works for locales with postcode_by_state definition. If a locale does not
+ * have a postcode_by_state definition, a random zip code is generated according
+ * to the locale's zip format.
+ *
+ * @param state The abbreviation of the state to generate the zip code for.
+ *
+ * @example
+ * fakerUS.address.zipCodeByState("AK") // '99595'
+ * fakerUS.address.zipCodeByState("??") // '47683-9880'
+ */
+ zipCodeByState(state: string): string {
+ const zipRange = this.faker.definitions.address.postcode_by_state?.[state];
+ if (zipRange) {
+ return String(this.faker.datatype.number(zipRange));
+ }
+ return this.zipCode();
+ }
+
+ /**
+ * Generates a random localized city name.
+ *
+ * @param format The format to use. Can be either the index of the format to use or
+ * any method provided by faker wrapped in `{{}}`, e.g. `{{name.firstName}}` in
+ * order to build the city name.
+ *
+ * If no format string is provided one of the following is randomly used:
+ *
+ * - `{{address.cityPrefix}} {{name.firstName}}{{address.citySuffix}}`
+ * - `{{address.cityPrefix}} {{name.firstName}}`
+ * - `{{name.firstName}}{{address.citySuffix}}`
+ * - `{{name.lastName}}{{address.citySuffix}}`
+ * - `{{address.cityName}}` when city name is available
+ *
+ * @example
+ * faker.address.city() // 'Gleasonbury'
+ * faker.address.city(2) // 'Jadenshire'
+ */
+ // TODO ST-DDT 2022-02-10: The string parameter doesn't work as expected.
+ city(format?: string | number): string {
+ const formats = [
+ '{{address.cityPrefix}} {{name.firstName}}{{address.citySuffix}}',
+ '{{address.cityPrefix}} {{name.firstName}}',
+ '{{name.firstName}}{{address.citySuffix}}',
+ '{{name.lastName}}{{address.citySuffix}}',
+ ];
+
+ if (!format && this.faker.definitions.address.city_name) {
+ formats.push('{{address.cityName}}');
+ }
+
+ if (typeof format !== 'number') {
+ format = this.faker.datatype.number(formats.length - 1);
+ }
+
+ return this.faker.fake(formats[format]);
+ }
+
+ /**
+ * Returns a random localized city prefix.
+ *
+ * @example
+ * faker.address.cityPrefix() // 'East'
+ */
+ cityPrefix(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.address.city_prefix
+ );
+ }
+
+ /**
+ * Returns a random localized city suffix.
+ *
+ * @example
+ * faker.address.citySuffix() // 'mouth'
+ */
+ citySuffix(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.address.city_suffix
+ );
+ }
+
+ /**
+ * Returns a random localized city name.
+ *
+ * @example
+ * faker.address.cityName() // 'San Rafael'
+ */
+ cityName(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.address.city_name
+ );
+ }
+
+ /**
+ * Generates a random building number.
+ *
+ * @example
+ * faker.address.buildingNumber() // '379'
+ */
+ buildingNumber(): string {
+ const format = this.faker.helpers.arrayElement(
+ this.faker.definitions.address.building_number
+ );
+
+ return this.faker.helpers.replaceSymbolWithNumber(format);
+ }
+
+ /**
+ * Generates a random localized street name.
+ *
+ * @example
+ * faker.address.streetName() // 'Kulas Roads'
+ */
+ streetName(): string {
+ let result: string;
+ let suffix = this.streetSuffix();
+ if (suffix !== '') {
+ suffix = ` ${suffix}`;
+ }
+
+ switch (this.faker.datatype.number(1)) {
+ case 0:
+ result = this.faker.name.lastName() + suffix;
+ break;
+ case 1:
+ result = this.faker.name.firstName() + suffix;
+ break;
+ }
+ return result;
+ }
+
+ /**
+ * Generates a random localized street address.
+ *
+ * @param useFullAddress When true this will generate a full address.
+ * Otherwise it will just generate a street address.
+ *
+ * @example
+ * faker.address.streetName() // '0917 O'Conner Estates'
+ * faker.address.streetAddress(true) // '3393 Ronny Way Apt. 742'
+ * faker.address.streetAddress(false) // '34830 Erdman Hollow'
+ */
+ streetAddress(useFullAddress: boolean = false): string {
+ const formats = this.faker.definitions.address.street_address;
+ const format = formats[useFullAddress ? 'full' : 'normal'];
+
+ return this.faker.fake(format);
+ }
+
+ /**
+ * Returns a random localized street suffix.
+ *
+ * @example
+ * faker.address.streetSuffix() // 'Streets'
+ */
+ streetSuffix(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.address.street_suffix
+ );
+ }
+
+ /**
+ * Returns a random localized street prefix.
+ *
+ * @example
+ * fakerGH.address.streetPrefix() // 'Boame'
+ */
+ streetPrefix(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.address.street_prefix
+ );
+ }
+
+ /**
+ * Generates a random localized secondary address. This refers to a specific location at a given address
+ * such as an apartment or room number.
+ *
+ * @example
+ * faker.address.secondaryAddress() // 'Apt. 861'
+ */
+ secondaryAddress(): string {
+ return this.faker.helpers.replaceSymbolWithNumber(
+ this.faker.helpers.arrayElement(
+ this.faker.definitions.address.secondary_address
+ )
+ );
+ }
+
+ /**
+ * Returns a random localized county.
+ *
+ * @example
+ * faker.address.county() // 'Cambridgeshire'
+ */
+ county(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.address.county
+ );
+ }
+
+ /**
+ * Returns a random country name.
+ *
+ * @example
+ * faker.address.country() // 'Greece'
+ */
+ country(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.address.country
+ );
+ }
+
+ /**
+ * Returns a random country code.
+ *
+ * @param alphaCode The code to return. Can be either `'alpha-2'` (2 letter code)
+ * or `'alpha-3'` (three letter code). Defaults to `'alpha-2'`.
+ *
+ * @example
+ * faker.address.countryCode() // 'SJ'
+ * faker.address.countryCode('alpha-2') // 'GA'
+ * faker.address.countryCode('alpha-3') // 'TJK'
+ */
+ countryCode(alphaCode: 'alpha-2' | 'alpha-3' = 'alpha-2'): string {
+ const key: keyof typeof this.faker.definitions.address =
+ alphaCode === 'alpha-3' ? 'country_code_alpha_3' : 'country_code';
+
+ return this.faker.helpers.arrayElement(this.faker.definitions.address[key]);
+ }
+
+ /**
+ * Returns a random localized state from this country.
+ *
+ * @example
+ * faker.address.state() // 'Georgia'
+ */
+ state(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.address.state
+ );
+ }
+
+ /**
+ * Returns a random localized state's abbreviated name from this country.
+ *
+ * @example
+ * faker.address.stateAbbr() // 'ND'
+ */
+ stateAbbr(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.address.state_abbr
+ );
+ }
+
+ /**
+ * Generates a random latitude.
+ *
+ * @param max The upper bound for the latitude to generate. Defaults to `90`.
+ * @param min The lower bound for the latitude to generate. Defaults to `-90`.
+ * @param precision The number of decimal points of precision for the latitude. Defaults to `4`.
+ *
+ * @example
+ * faker.address.latitude() // '-30.9501'
+ * faker.address.latitude(10, -10, 5) // '2.68452'
+ */
+ latitude(max: number = 90, min: number = -90, precision: number = 4): string {
+ return this.faker.datatype
+ .number({
+ min,
+ max,
+ precision: parseFloat(`${(0.0).toPrecision(precision)}1`),
+ })
+ .toFixed(precision);
+ }
+
+ /**
+ * Generates a random longitude.
+ *
+ * @param max The upper bound for the longitude to generate. Defaults to `180`.
+ * @param min The lower bound for the longitude to generate. Defaults to `-180`.
+ * @param precision The number of decimal points of precision for the longitude. Defaults to `4`.
+ *
+ * @example
+ * faker.address.longitude() // '-154.0226'
+ * faker.address.longitude(10, -10, 5) // '-4.03620'
+ */
+ longitude(
+ max: number = 180,
+ min: number = -180,
+ precision: number = 4
+ ): string {
+ return this.faker.datatype
+ .number({
+ max: max,
+ min: min,
+ precision: parseFloat(`${(0.0).toPrecision(precision)}1`),
+ })
+ .toFixed(precision);
+ }
+
+ /**
+ * Returns a random direction (cardinal and ordinal; northwest, east, etc).
+ *
+ * @param useAbbr If true this will return abbreviated directions (NW, E, etc).
+ * Otherwise this will return the long name. Defaults to `false`.
+ *
+ * @example
+ * faker.address.direction() // 'Northeast'
+ * faker.address.direction(false) // 'South'
+ * faker.address.direction(true) // 'NE'
+ */
+ direction(useAbbr: boolean = false): string {
+ if (!useAbbr) {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.address.direction
+ );
+ }
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.address.direction_abbr
+ );
+ }
+
+ /**
+ * Returns a random cardinal direction (north, east, south, west).
+ *
+ * @param useAbbr If true this will return abbreviated directions (N, E, etc).
+ * Otherwise this will return the long name. Defaults to `false`.
+ *
+ * @example
+ * faker.address.cardinalDirection() // 'North'
+ * faker.address.cardinalDirection(false) // 'South'
+ * faker.address.cardinalDirection(true) // 'N'
+ */
+ cardinalDirection(useAbbr: boolean = false): string {
+ if (!useAbbr) {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.address.direction.slice(0, 4)
+ );
+ }
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.address.direction_abbr.slice(0, 4)
+ );
+ }
+
+ /**
+ * Returns a random ordinal direction (northwest, southeast, etc).
+ *
+ * @param useAbbr If true this will return abbreviated directions (NW, SE, etc).
+ * Otherwise this will return the long name. Defaults to `false`.
+ *
+ * @example
+ * faker.address.ordinalDirection() // 'Northeast'
+ * faker.address.ordinalDirection(false) // 'Northwest'
+ * faker.address.ordinalDirection(true) // 'NE'
+ */
+ ordinalDirection(useAbbr: boolean = false): string {
+ if (!useAbbr) {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.address.direction.slice(4, 8)
+ );
+ }
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.address.direction_abbr.slice(4, 8)
+ );
+ }
+
+ /**
+ * Generates a random GPS coordinate within the specified radius from the given coordinate.
+ *
+ * @param coordinate The original coordinate to get a new coordinate close to.
+ * If no coordinate is given, a random one will be chosen.
+ * @param radius The maximum distance from the given coordinate to the new coordinate. Defaults to `10`.
+ * @param isMetric If `true` assume the radius to be in kilometers. If `false` for miles. Defaults to `false`.
+ *
+ * @example
+ * faker.address.nearbyGPSCoordinate() // [ '33.8475', '-170.5953' ]
+ * faker.address.nearbyGPSCoordinate([33, -170]) // [ '33.0165', '-170.0636' ]
+ * faker.address.nearbyGPSCoordinate([33, -170], 1000, true) // [ '37.9163', '-179.2408' ]
+ */
+ // TODO ST-DDT 2022-02-10: Allow coordinate parameter to be [string, string].
+ nearbyGPSCoordinate(
+ coordinate?: [latitude: number, longitude: number],
+ radius: number = 10,
+ isMetric: boolean = false
+ ): [latitude: string, longitude: string] {
+ // If there is no coordinate, the best we can do is return a random GPS coordinate.
+ if (coordinate === undefined) {
+ return [this.latitude(), this.longitude()];
+ }
+
+ const angleRadians = this.faker.datatype.float({
+ min: 0,
+ max: 2 * Math.PI,
+ precision: 0.00001,
+ }); // in ° radians
+
+ const radiusMetric = isMetric ? radius : radius * 1.60934; // in km
+ const errorCorrection = 0.995; // avoid float issues
+ const distanceInKm =
+ this.faker.datatype.float({
+ min: 0,
+ max: radiusMetric,
+ precision: 0.001,
+ }) * errorCorrection; // in km
+
+ /**
+ * The distance in km per degree for earth.
+ */
+ // TODO @Shinigami92 2022-04-26: Provide an option property to provide custom circumferences.
+ const kmPerDegree = 40_000 / 360; // in km/°
+
+ const distanceInDegree = distanceInKm / kmPerDegree; // in °
+
+ const newCoordinate: [latitude: number, longitude: number] = [
+ coordinate[0] + Math.sin(angleRadians) * distanceInDegree,
+ coordinate[1] + Math.cos(angleRadians) * distanceInDegree,
+ ];
+
+ // Box latitude [-90°, 90°]
+ newCoordinate[0] = newCoordinate[0] % 180;
+ if (newCoordinate[0] < -90 || newCoordinate[0] > 90) {
+ newCoordinate[0] = Math.sign(newCoordinate[0]) * 180 - newCoordinate[0];
+ newCoordinate[1] += 180;
+ }
+ // Box longitude [-180°, 180°]
+ newCoordinate[1] = (((newCoordinate[1] % 360) + 540) % 360) - 180;
+
+ return [newCoordinate[0].toFixed(4), newCoordinate[1].toFixed(4)];
+ }
+
+ /**
+ * Returns a random time zone.
+ *
+ * @example
+ * faker.address.timeZone() // 'Pacific/Guam'
+ */
+ timeZone(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.address.time_zone
+ );
+ }
+}
diff --git a/src/modules/animal/index.ts b/src/modules/animal/index.ts
new file mode 100644
index 00000000..416fe533
--- /dev/null
+++ b/src/modules/animal/index.ts
@@ -0,0 +1,164 @@
+import type { Faker } from '../..';
+
+/**
+ * Module to generate animal related entries.
+ */
+export class Animal {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Animal.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Returns a random dog breed.
+ *
+ * @example
+ * faker.animal.dog() // 'Irish Water Spaniel'
+ */
+ dog(): string {
+ return this.faker.helpers.arrayElement(this.faker.definitions.animal.dog);
+ }
+
+ /**
+ * Returns a random cat breed.
+ *
+ * @example
+ * faker.animal.cat() // 'Singapura'
+ */
+ cat(): string {
+ return this.faker.helpers.arrayElement(this.faker.definitions.animal.cat);
+ }
+
+ /**
+ * Returns a random snake species.
+ *
+ * @example
+ * faker.animal.snake() // 'Eyelash viper'
+ */
+ snake(): string {
+ return this.faker.helpers.arrayElement(this.faker.definitions.animal.snake);
+ }
+
+ /**
+ * Returns a random bear species.
+ *
+ * @example
+ * faker.animal.bear() // 'Asian black bear'
+ */
+ bear(): string {
+ return this.faker.helpers.arrayElement(this.faker.definitions.animal.bear);
+ }
+
+ /**
+ * Returns a random lion species.
+ *
+ * @example
+ * faker.animal.lion() // 'Northeast Congo Lion'
+ */
+ lion(): string {
+ return this.faker.helpers.arrayElement(this.faker.definitions.animal.lion);
+ }
+
+ /**
+ * Returns a random cetacean species.
+ *
+ * @example
+ * faker.animal.cetacean() // 'Spinner Dolphin'
+ */
+ cetacean(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.animal.cetacean
+ );
+ }
+
+ /**
+ * Returns a random horse breed.
+ *
+ * @example
+ * faker.animal.horse() // 'Swedish Warmblood'
+ */
+ horse(): string {
+ return this.faker.helpers.arrayElement(this.faker.definitions.animal.horse);
+ }
+
+ /**
+ * Returns a random bird species.
+ *
+ * @example
+ * faker.animal.bird() // 'Buller's Shearwater'
+ */
+ bird(): string {
+ return this.faker.helpers.arrayElement(this.faker.definitions.animal.bird);
+ }
+
+ /**
+ * Returns a random cow species.
+ *
+ * @example
+ * faker.animal.cow() // 'Brava'
+ */
+ cow(): string {
+ return this.faker.helpers.arrayElement(this.faker.definitions.animal.cow);
+ }
+
+ /**
+ * Returns a random fish species.
+ *
+ * @example
+ * faker.animal.fish() // 'Mandarin fish'
+ */
+ fish(): string {
+ return this.faker.helpers.arrayElement(this.faker.definitions.animal.fish);
+ }
+
+ /**
+ * Returns a random crocodilian species.
+ *
+ * @example
+ * faker.animal.crocodilia() // 'Philippine Crocodile'
+ */
+ crocodilia(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.animal.crocodilia
+ );
+ }
+
+ /**
+ * Returns a random insect species.
+ *
+ * @example
+ * faker.animal.insect() // 'Pyramid ant'
+ */
+ insect(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.animal.insect
+ );
+ }
+
+ /**
+ * Returns a random rabbit species.
+ *
+ * @example
+ * faker.animal.rabbit() // 'Florida White'
+ */
+ rabbit(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.animal.rabbit
+ );
+ }
+
+ /**
+ * Returns a random animal type.
+ *
+ * @example
+ * faker.animal.type() // 'crocodilia'
+ */
+ type(): string {
+ return this.faker.helpers.arrayElement(this.faker.definitions.animal.type);
+ }
+}
diff --git a/src/modules/commerce/index.ts b/src/modules/commerce/index.ts
new file mode 100644
index 00000000..71ce96d6
--- /dev/null
+++ b/src/modules/commerce/index.ts
@@ -0,0 +1,133 @@
+import type { Faker } from '../..';
+
+/**
+ * Module to generate commerce and product related entries.
+ */
+export class Commerce {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Commerce.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Returns a human readable color name.
+ *
+ * @example
+ * faker.commerce.color() // 'red'
+ */
+ color(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.commerce.color
+ );
+ }
+
+ /**
+ * Returns a department inside a shop.
+ *
+ * @example
+ * faker.commerce.department() // 'Garden'
+ */
+ department(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.commerce.department
+ );
+ }
+
+ /**
+ * Generates a random descriptive product name.
+ *
+ * @example
+ * faker.commerce.productName() // 'Incredible Soft Gloves'
+ */
+ productName(): string {
+ return `${this.productAdjective()} ${this.productMaterial()} ${this.product()}`;
+ }
+
+ /**
+ * Generates a price between min and max (inclusive).
+ *
+ * @param min The minimum price. Defaults to `1`.
+ * @param max The maximum price. Defaults to `1000`.
+ * @param dec The number of decimal places. Defaults to `2`.
+ * @param symbol The currency value to use. Defaults to `''`.
+ *
+ * @example
+ * faker.commerce.price() // 828.00
+ * faker.commerce.price(100) // 904.00
+ * faker.commerce.price(100, 200) // 154.00
+ * faker.commerce.price(100, 200, 0) // 133
+ * faker.commerce.price(100, 200, 0, '$') // $114
+ */
+ price(
+ min: number = 1,
+ max: number = 1000,
+ dec: number = 2,
+ symbol: string = ''
+ ): string {
+ if (min < 0 || max < 0) {
+ return `${symbol}${0.0}`;
+ }
+
+ const randValue = this.faker.datatype.number({ max: max, min: min });
+
+ return (
+ symbol +
+ (Math.round(randValue * Math.pow(10, dec)) / Math.pow(10, dec)).toFixed(
+ dec
+ )
+ );
+ }
+
+ /**
+ * Returns an adjective describing a product.
+ *
+ * @example
+ * faker.commerce.productAdjective() // 'Handcrafted'
+ */
+ productAdjective(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.commerce.product_name.adjective
+ );
+ }
+
+ /**
+ * Returns a material of a product.
+ *
+ * @example
+ * faker.commerce.productMaterial() // 'Rubber'
+ */
+ productMaterial(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.commerce.product_name.material
+ );
+ }
+
+ /**
+ * Returns a short product name.
+ *
+ * @example
+ * faker.commerce.product() // 'Computer'
+ */
+ product(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.commerce.product_name.product
+ );
+ }
+
+ /**
+ * Returns a product description.
+ *
+ * @example
+ * faker.commerce.productDescription() // 'Andy shoes are designed to keeping...'
+ */
+ productDescription(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.commerce.product_description
+ );
+ }
+}
diff --git a/src/modules/company/index.ts b/src/modules/company/index.ts
new file mode 100644
index 00000000..fb5f2e66
--- /dev/null
+++ b/src/modules/company/index.ts
@@ -0,0 +1,153 @@
+import type { Faker } from '../..';
+
+/**
+ * Module to generate company related entries.
+ */
+export class Company {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Company.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Returns an array with possible company name suffixes.
+ *
+ * @example
+ * faker.company.suffixes() // [ 'Inc', 'and Sons', 'LLC', 'Group' ]
+ */
+ suffixes(): string[] {
+ // Don't want the source array exposed to modification, so return a copy
+ return this.faker.definitions.company.suffix.slice(0);
+ }
+
+ /**
+ * Generates a random company name.
+ *
+ * @param format The optional format index used to select a format.
+ *
+ * @example
+ * faker.company.companyName() // 'Zieme, Hauck and McClure'
+ */
+ companyName(format?: number): string {
+ const formats = [
+ '{{name.lastName}} {{company.companySuffix}}',
+ '{{name.lastName}} - {{name.lastName}}',
+ '{{name.lastName}}, {{name.lastName}} and {{name.lastName}}',
+ ];
+
+ if (typeof format !== 'number') {
+ format = this.faker.datatype.number(formats.length - 1);
+ }
+
+ return this.faker.fake(formats[format]);
+ }
+
+ /**
+ * Returns a random company suffix.
+ *
+ * @example
+ * faker.company.companySuffix() // 'and Sons'
+ */
+ companySuffix(): string {
+ return this.faker.helpers.arrayElement(this.suffixes());
+ }
+
+ /**
+ * Generates a random business catch phrase.
+ *
+ * @example
+ * faker.company.catchPhrase() // 'Upgradable systematic flexibility'
+ */
+ catchPhrase(): string {
+ return this.faker.fake(
+ '{{company.catchPhraseAdjective}} {{company.catchPhraseDescriptor}} {{company.catchPhraseNoun}}'
+ );
+ }
+
+ /**
+ * Generates a random company bs phrase.
+ *
+ * @example
+ * faker.company.bs() // 'cultivate synergistic e-markets'
+ */
+ bs(): string {
+ return this.faker.fake(
+ '{{company.bsBuzz}} {{company.bsAdjective}} {{company.bsNoun}}'
+ );
+ }
+
+ /**
+ * Returns a random catch phrase adjective.
+ *
+ * @example
+ * faker.company.catchPhraseAdjective() // 'Multi-tiered'
+ */
+ catchPhraseAdjective(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.company.adjective
+ );
+ }
+
+ /**
+ * Returns a random catch phrase descriptor.
+ *
+ * @example
+ * faker.company.catchPhraseDescriptor() // 'composite'
+ */
+ catchPhraseDescriptor(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.company.descriptor
+ );
+ }
+
+ /**
+ * Returns a random catch phrase noun.
+ *
+ * @example
+ * faker.company.catchPhraseNoun() // 'leverage'
+ */
+ catchPhraseNoun(): string {
+ return this.faker.helpers.arrayElement(this.faker.definitions.company.noun);
+ }
+
+ /**
+ * Returns a random company bs adjective.
+ *
+ * @example
+ * faker.company.bsAdjective() // 'one-to-one'
+ */
+ bsAdjective(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.company.bs_adjective
+ );
+ }
+
+ /**
+ * Returns a random company bs buzz word.
+ *
+ * @example
+ * faker.company.bsBuzz() // 'empower'
+ */
+ bsBuzz(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.company.bs_verb
+ );
+ }
+
+ /**
+ * Returns a random company bs noun.
+ *
+ * @example
+ * faker.company.bsNoun() // 'paradigms'
+ */
+ bsNoun(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.company.bs_noun
+ );
+ }
+}
diff --git a/src/modules/database/index.ts b/src/modules/database/index.ts
new file mode 100644
index 00000000..073d3f8a
--- /dev/null
+++ b/src/modules/database/index.ts
@@ -0,0 +1,75 @@
+import type { Faker } from '../..';
+
+/**
+ * Module to generate database related entries.
+ */
+export class Database {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Database.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Returns a random database column name.
+ *
+ * @example
+ * faker.database.column() // 'createdAt'
+ */
+ column(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.database.column
+ );
+ }
+
+ /**
+ * Returns a random database column type.
+ *
+ * @example
+ * faker.database.type() // 'timestamp'
+ */
+ type(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.database.type
+ );
+ }
+
+ /**
+ * Returns a random database collation.
+ *
+ * @example
+ * faker.database.collation() // 'utf8_unicode_ci'
+ */
+ collation(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.database.collation
+ );
+ }
+
+ /**
+ * Returns a random database engine.
+ *
+ * @example
+ * faker.database.engine() // 'ARCHIVE'
+ */
+ engine(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.database.engine
+ );
+ }
+
+ /**
+ * Returns a MongoDB [ObjectId](https://docs.mongodb.com/manual/reference/method/ObjectId/) string.
+ *
+ * @example
+ * faker.database.mongodbObjectId() // 'e175cac316a79afdd0ad3afb'
+ */
+ mongodbObjectId(): string {
+ // strip the "0x" from the hexadecimal output
+ return this.faker.datatype.hexadecimal(24).replace('0x', '').toLowerCase();
+ }
+}
diff --git a/src/modules/datatype/index.ts b/src/modules/datatype/index.ts
new file mode 100644
index 00000000..653d4d3f
--- /dev/null
+++ b/src/modules/datatype/index.ts
@@ -0,0 +1,305 @@
+import type { Faker } from '../..';
+import { FakerError } from '../../errors/faker-error';
+import { deprecated } from '../../internal/deprecated';
+
+/**
+ * Module to generate various primitive values and data types.
+ */
+export class Datatype {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Datatype.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Returns a single random number between zero and the given max value or the given range with the specified precision.
+ * The bounds are inclusive.
+ *
+ * @param options Maximum value or options object.
+ * @param options.min Lower bound for generated number. Defaults to `0`.
+ * @param options.max Upper bound for generated number. Defaults to `min + 99999`.
+ * @param options.precision Precision of the generated number. Defaults to `1`.
+ *
+ * @throws When options define `max < min`.
+ *
+ * @example
+ * faker.datatype.number() // 55422
+ * faker.datatype.number(100) // 52
+ * faker.datatype.number({ min: 1000000 }) // 431433
+ * faker.datatype.number({ max: 100 }) // 42
+ * faker.datatype.number({ precision: 0.01 }) // 64246.18
+ * faker.datatype.number({ min: 10, max: 100, precision: 0.01 }) // 36.94
+ */
+ number(
+ options: number | { min?: number; max?: number; precision?: number } = 99999
+ ): number {
+ if (typeof options === 'number') {
+ options = { max: options };
+ }
+
+ const { min = 0, precision = 1 } = options;
+ const max = options.max ?? min + 99999;
+
+ if (max === min) {
+ return min;
+ }
+
+ if (max < min) {
+ throw new FakerError(`Max ${max} should be larger then min ${min}.`);
+ }
+
+ const randomNumber = Math.floor(
+ this.faker.mersenne.rand(max / precision + 1, min / precision)
+ );
+
+ // Workaround problem in float point arithmetics for e.g. 6681493 / 0.01
+ return randomNumber / (1 / precision);
+ }
+
+ /**
+ * Returns a single random floating-point number for the given precision or range and precision.
+ *
+ * @param options Precision or options object.
+ * @param options.min Lower bound for generated number. Defaults to `0`.
+ * @param options.max Upper bound for generated number. Defaults to `99999`.
+ * @param options.precision Precision of the generated number. Defaults to `0.01`.
+ *
+ * @example
+ * faker.datatype.float() // 51696.36
+ * faker.datatype.float(0.1) // 52023.2
+ * faker.datatype.float({ min: 1000000 }) // 212859.76
+ * faker.datatype.float({ max: 100 }) // 28.11
+ * faker.datatype.float({ precision: 0.1 }) // 84055.3
+ * faker.datatype.float({ min: 10, max: 100, precision: 0.001 }) // 57.315
+ */
+ float(
+ options?: number | { min?: number; max?: number; precision?: number }
+ ): number {
+ if (typeof options === 'number') {
+ options = {
+ precision: options,
+ };
+ }
+ options = options || {};
+ const opts: { precision?: number } = {};
+ for (const p in options) {
+ opts[p] = options[p];
+ }
+ if (opts.precision == null) {
+ opts.precision = 0.01;
+ }
+ return this.number(opts);
+ }
+
+ /**
+ * Returns a Date object using a random number of milliseconds since
+ * the [Unix Epoch](https://en.wikipedia.org/wiki/Unix_time) (1 January 1970 UTC).
+ *
+ * @param options Max number of milliseconds since unix epoch or options object.
+ * @param options.min Lower bound for milliseconds since base date.
+ * When not provided or smaller than `-8640000000000000`, `1990-01-01` is considered
+ * as minimum generated date. Defaults to `631152000000`.
+ * @param options.max Upper bound for milliseconds since base date.
+ * When not provided or larger than `8640000000000000`, `2100-01-01` is considered
+ * as maximum generated date. Defaults to `4102444800000`.
+ *
+ * @example
+ * faker.datatype.datetime() // '2089-04-17T18:03:24.956Z'
+ * faker.datatype.datetime(1893456000000) // '2022-03-28T07:00:56.876Z'
+ * faker.datatype.datetime({ min: 1577836800000, max: 1893456000000 }) // '2021-09-12T07:13:00.255Z'
+ */
+ datetime(options: number | { min?: number; max?: number } = {}): Date {
+ const minMax = 8640000000000000;
+
+ let min = typeof options === 'number' ? undefined : options.min;
+ let max = typeof options === 'number' ? options : options.max;
+
+ if (min == null || min < minMax * -1) {
+ min = Date.UTC(1990, 0);
+ }
+
+ if (max == null || max > minMax) {
+ max = Date.UTC(2100, 0);
+ }
+
+ return new Date(this.number({ min, max }));
+ }
+
+ /**
+ * Returns a string containing UTF-16 chars between 33 and 125 (`!` to `}`).
+ *
+ * @param length Length of the generated string. Max length is `2^20`. Defaults to `10`.
+ *
+ * @example
+ * faker.datatype.string() // 'Zo!.:*e>wR'
+ * faker.datatype.string(5) // '6Bye8'
+ */
+ string(length = 10): string {
+ const maxLength = Math.pow(2, 20);
+ if (length >= maxLength) {
+ length = maxLength;
+ }
+
+ const charCodeOption = {
+ min: 33,
+ max: 125,
+ };
+
+ let returnString = '';
+
+ for (let i = 0; i < length; i++) {
+ returnString += String.fromCharCode(this.number(charCodeOption));
+ }
+
+ return returnString;
+ }
+
+ /**
+ * Returns a UUID v4 ([Universally Unique Identifier](https://en.wikipedia.org/wiki/Universally_unique_identifier)).
+ *
+ * @example
+ * faker.datatype.uuid() // '4136cd0b-d90b-4af7-b485-5d1ded8db252'
+ */
+ uuid(): string {
+ const RFC4122_TEMPLATE = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
+ const replacePlaceholders = (placeholder) => {
+ const random = this.number({ min: 0, max: 15 });
+ const value = placeholder === 'x' ? random : (random & 0x3) | 0x8;
+ return value.toString(16);
+ };
+ return RFC4122_TEMPLATE.replace(/[xy]/g, replacePlaceholders);
+ }
+
+ /**
+ * Returns the boolean value true or false.
+ *
+ * @example
+ * faker.datatype.boolean() // false
+ */
+ boolean(): boolean {
+ return !!this.number(1);
+ }
+
+ /**
+ * Returns a [hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) number.
+ *
+ * @param length Length of the generated number. Defaults to `1`.
+ *
+ * @see faker.datatype.hexadecimal()
+ *
+ * @example
+ * faker.datatype.hexaDecimal() // '0xb'
+ * faker.datatype.hexaDecimal(10) // '0xaE13F044fb'
+ *
+ * @deprecated
+ */
+ hexaDecimal(length = 1): string {
+ deprecated({
+ deprecated: 'faker.datatype.hexaDecimal()',
+ proposed: 'faker.datatype.hexadecimal()',
+ since: 'v6.1.2',
+ until: 'v7.0.0',
+ });
+
+ return this.hexadecimal(length);
+ }
+
+ /**
+ * Returns a [hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) number.
+ *
+ * @param length Length of the generated number. Defaults to `1`.
+ *
+ * @example
+ * faker.datatype.hexadecimal() // '0xb'
+ * faker.datatype.hexadecimal(10) // '0xaE13F044fb'
+ */
+ hexadecimal(length = 1): string {
+ let wholeString = '';
+
+ for (let i = 0; i < length; i++) {
+ wholeString += this.faker.helpers.arrayElement([
+ '0',
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ 'a',
+ 'b',
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ 'A',
+ 'B',
+ 'C',
+ 'D',
+ 'E',
+ 'F',
+ ]);
+ }
+
+ return `0x${wholeString}`;
+ }
+
+ /**
+ * Returns a string representing JSON object with 7 pre-defined properties.
+ *
+ * @example
+ * faker.datatype.json() // `{"foo":"mxz.v8ISij","bar":29154,"bike":8658,"a":"GxTlw$nuC:","b":40693,"name":"%'<FTou{7X","prop":"X(bd4iT>77"}`
+ */
+ json(): string {
+ const properties = ['foo', 'bar', 'bike', 'a', 'b', 'name', 'prop'];
+ const returnObject: Record<string, string | number> = {};
+
+ properties.forEach((prop) => {
+ returnObject[prop] = this.boolean() ? this.string() : this.number();
+ });
+
+ return JSON.stringify(returnObject);
+ }
+
+ /**
+ * Returns an array with random strings and numbers.
+ *
+ * @param length Size of the returned array. Defaults to `10`.
+ *
+ * @example
+ * faker.datatype.array() // [ 94099, 85352, 'Hz%T.C\\l;8', '|#gmtw3otS', '2>:rJ|3$&d', 56864, 'Ss2-p0RXSI', 51084, 2039, 'mNEU[.r0Vf' ]
+ * faker.datatype.array(3) // [ 61845, 'SK7H$W3:d*', 'm[%7N8*GVK' ]
+ */
+ array(length = 10): Array<string | number> {
+ return Array.from<string | number>({ length }).map(() =>
+ this.boolean() ? this.string() : this.number()
+ );
+ }
+
+ /**
+ * Returns a [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#bigint_type) number.
+ *
+ * @param value When provided, this method simply converts it to `BigInt` type.
+ *
+ * @example
+ * faker.datatype.bigInt() // 8507209999914928n
+ * faker.datatype.bigInt('156') // 156n
+ * faker.datatype.bigInt(30) // 30n
+ * faker.datatype.bigInt(3000n) // 3000n
+ * faker.datatype.bigInt(true) // 1n
+ */
+ bigInt(value?: string | number | bigint | boolean): bigint {
+ if (value === undefined) {
+ value = Math.floor(this.number() * 99999999999) + 10000000000;
+ }
+
+ return BigInt(value);
+ }
+}
diff --git a/src/modules/date/index.ts b/src/modules/date/index.ts
new file mode 100644
index 00000000..09f608f0
--- /dev/null
+++ b/src/modules/date/index.ts
@@ -0,0 +1,256 @@
+import type { Faker } from '../..';
+import type { DateEntryDefinition } from '../../definitions';
+
+/**
+ * Converts date passed as a string, number or Date to a Date object.
+ * If nothing or a non parseable value is passed, takes current date.
+ *
+ * @param date Date
+ */
+function toDate(date?: string | Date | number): Date {
+ date = new Date(date);
+ if (isNaN(date.valueOf())) {
+ date = new Date();
+ }
+
+ return date;
+}
+
+/**
+ * Module to generate dates.
+ */
+export class _Date {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(_Date.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Generates a random date in the past.
+ *
+ * @param years The range of years the date may be in the past. Defaults to `1`.
+ * @param refDate The date to use as reference point for the newly generated date. Defaults to now.
+ *
+ * @see faker.date.recent()
+ *
+ * @example
+ * faker.date.past() // '2021-12-03T05:40:44.408Z'
+ * faker.date.past(10) // '2017-10-25T21:34:19.488Z'
+ * faker.date.past(10, '2020-01-01T00:00:00.000Z') // '2017-08-18T02:59:12.350Z'
+ */
+ past(years?: number, refDate?: string | Date | number): Date {
+ const date = toDate(refDate);
+ const range = {
+ min: 1000,
+ max: (years || 1) * 365 * 24 * 3600 * 1000,
+ };
+
+ let past = date.getTime();
+ past -= this.faker.datatype.number(range); // some time from now to N years ago, in milliseconds
+ date.setTime(past);
+
+ return date;
+ }
+
+ /**
+ * Generates a random date in the future.
+ *
+ * @param years The range of years the date may be in the future. Defaults to `1`.
+ * @param refDate The date to use as reference point for the newly generated date. Defaults to now.
+ *
+ * @see faker.date.soon()
+ *
+ * @example
+ * faker.date.future() // '2022-11-19T05:52:49.100Z'
+ * faker.date.future(10) // '2030-11-23T09:38:28.710Z'
+ * faker.date.future(10, '2020-01-01T00:00:00.000Z') // '2020-12-13T22:45:10.252Z'
+ */
+ future(years?: number, refDate?: string | Date | number): Date {
+ const date = toDate(refDate);
+ const range = {
+ min: 1000,
+ max: (years || 1) * 365 * 24 * 3600 * 1000,
+ };
+
+ let future = date.getTime();
+ future += this.faker.datatype.number(range); // some time from now to N years later, in milliseconds
+ date.setTime(future);
+
+ return date;
+ }
+
+ /**
+ * Generates a random date between the given boundaries.
+ *
+ * @param from The early date boundary.
+ * @param to The late date boundary.
+ *
+ * @example
+ * faker.date.between('2020-01-01T00:00:00.000Z', '2030-01-01T00:00:00.000Z') // '2026-05-16T02:22:53.002Z'
+ */
+ between(from: string | Date | number, to: string | Date | number): Date {
+ const fromMs = toDate(from).getTime();
+ const toMs = toDate(to).getTime();
+ const dateOffset = this.faker.datatype.number(toMs - fromMs);
+
+ return new Date(fromMs + dateOffset);
+ }
+
+ /**
+ * Generates n random dates between the given boundaries.
+ *
+ * @param from The early date boundary.
+ * @param to The late date boundary.
+ * @param num The number of dates to generate. Defaults to `3`.
+ *
+ * @example
+ * faker.date.betweens('2020-01-01T00:00:00.000Z', '2030-01-01T00:00:00.000Z')
+ * // [
+ * // 2022-07-02T06:00:00.000Z,
+ * // 2024-12-31T12:00:00.000Z,
+ * // 2027-07-02T18:00:00.000Z
+ * // ]
+ * faker.date.betweens('2020-01-01T00:00:00.000Z', '2030-01-01T00:00:00.000Z', 2)
+ * // [ 2023-05-02T16:00:00.000Z, 2026-09-01T08:00:00.000Z ]
+ */
+ betweens(
+ from: string | Date | number,
+ to: string | Date | number,
+ num: number = 3
+ ): Date[] {
+ const dates: Date[] = [];
+
+ while (dates.length < num) {
+ dates.push(this.between(from, to));
+ }
+
+ return dates.sort((a, b) => a.getTime() - b.getTime());
+ }
+
+ /**
+ * Generates a random date in the recent past.
+ *
+ * @param days The range of days the date may be in the past. Defaults to `1`.
+ * @param refDate The date to use as reference point for the newly generated date. Defaults to now.
+ *
+ * @see faker.date.past()
+ *
+ * @example
+ * faker.date.recent() // '2022-02-04T02:09:35.077Z'
+ * faker.date.recent(10) // '2022-01-29T06:12:12.829Z'
+ * faker.date.recent(10, '2020-01-01T00:00:00.000Z') // '2019-12-27T18:11:19.117Z'
+ */
+ recent(days?: number, refDate?: string | Date | number): Date {
+ const date = toDate(refDate);
+ const range = {
+ min: 1000,
+ max: (days || 1) * 24 * 3600 * 1000,
+ };
+
+ let future = date.getTime();
+ future -= this.faker.datatype.number(range); // some time from now to N days ago, in milliseconds
+ date.setTime(future);
+
+ return date;
+ }
+
+ /**
+ * Generates a random date in the near future.
+ *
+ * @param days The range of days the date may be in the future. Defaults to `1`.
+ * @param refDate The date to use as reference point for the newly generated date. Defaults to now.
+ *
+ * @see faker.date.future()
+ *
+ * @example
+ * faker.date.soon() // '2022-02-05T09:55:39.216Z'
+ * faker.date.soon(10) // '2022-02-11T05:14:39.138Z'
+ * faker.date.soon(10, '2020-01-01T00:00:00.000Z') // '2020-01-01T02:40:44.990Z'
+ */
+ soon(days?: number, refDate?: string | Date | number): Date {
+ const date = toDate(refDate);
+ const range = {
+ min: 1000,
+ max: (days || 1) * 24 * 3600 * 1000,
+ };
+
+ let future = date.getTime();
+ future += this.faker.datatype.number(range); // some time from now to N days later, in milliseconds
+ date.setTime(future);
+
+ return date;
+ }
+
+ /**
+ * Returns a random name of a month.
+ *
+ * @param options The optional options to use.
+ * @param options.abbr Whether to return an abbreviation. Defaults to `false`.
+ * @param options.context Whether to return the name of a month in a context. Defaults to `false`.
+ *
+ * @example
+ * faker.date.month() // 'October'
+ * faker.date.month({ abbr: true }) // 'Feb'
+ * faker.date.month({ context: true }) // 'June'
+ * faker.date.month({ abbr: true, context: true }) // 'Sep'
+ */
+ month(options?: { abbr?: boolean; context?: boolean }): string {
+ const abbr = options?.abbr ?? false;
+ const context = options?.context ?? false;
+
+ const source = this.faker.definitions.date.month;
+ let type: keyof DateEntryDefinition;
+ if (abbr) {
+ if (context && source['abbr_context'] != null) {
+ type = 'abbr_context';
+ } else {
+ type = 'abbr';
+ }
+ } else if (context && source['wide_context'] != null) {
+ type = 'wide_context';
+ } else {
+ type = 'wide';
+ }
+
+ return this.faker.helpers.arrayElement(source[type]);
+ }
+
+ /**
+ * Returns a random day of the week.
+ *
+ * @param options The optional options to use.
+ * @param options.abbr Whether to return an abbreviation. Defaults to `false`.
+ * @param options.context Whether to return the day of the week in a context. Defaults to `false`.
+ *
+ * @example
+ * faker.date.weekday() // 'Monday'
+ * faker.date.weekday({ abbr: true }) // 'Thu'
+ * faker.date.weekday({ context: true }) // 'Thursday'
+ * faker.date.weekday({ abbr: true, context: true }) // 'Fri'
+ */
+ weekday(options?: { abbr?: boolean; context?: boolean }): string {
+ const abbr = options?.abbr ?? false;
+ const context = options?.context ?? false;
+
+ const source = this.faker.definitions.date.weekday;
+ let type: keyof DateEntryDefinition;
+ if (abbr) {
+ if (context && source['abbr_context'] != null) {
+ type = 'abbr_context';
+ } else {
+ type = 'abbr';
+ }
+ } else if (context && source['wide_context'] != null) {
+ type = 'wide_context';
+ } else {
+ type = 'wide';
+ }
+
+ return this.faker.helpers.arrayElement(source[type]);
+ }
+}
diff --git a/src/modules/fake/index.ts b/src/modules/fake/index.ts
new file mode 100644
index 00000000..a9f2a22a
--- /dev/null
+++ b/src/modules/fake/index.ts
@@ -0,0 +1,134 @@
+import type { Faker } from '../..';
+import { FakerError } from '../../errors/faker-error';
+
+/**
+ * Generator method for combining faker methods based on string input.
+ */
+export class Fake {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Fake.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Generator for combining faker methods based on a static string input.
+ *
+ * Note: We recommend using string template literals instead of `fake()`,
+ * which are faster and strongly typed (if you are using TypeScript),
+ * e.g. ``const address = `${faker.address.zipCode()} ${faker.address.city()}`;``
+ *
+ * This method is useful if you have to build a random string from a static, non-executable source
+ * (e.g. string coming from a user, stored in a database or a file).
+ *
+ * It checks the given string for placeholders and replaces them by calling faker methods:
+ *
+ * ```js
+ * const hello = faker.fake('Hi, my name is {{name.firstName}} {{name.lastName}}!')
+ * ```
+ *
+ * This would use the `faker.name.firstName()` and `faker.name.lastName()` method to resolve the placeholders respectively.
+ *
+ * It is also possible to provide parameters. At first, they will be parsed as json,
+ * and if that isn't possible, we will fall back to string:
+ *
+ * ```js
+ * const message = faker.fake(`You can call me at {{phone.phoneNumber(+!# !## #### #####!)}}.')
+ * ```
+ *
+ * Currently it is not possible to set more than a single parameter.
+ *
+ * It is also NOT possible to use any non-faker methods or plain javascript in such templates.
+ *
+ * @param str The template string that will get interpolated. Must not be empty.
+ *
+ * @see faker.helpers.mustache() to use custom functions for resolution.
+ *
+ * @example
+ * faker.fake('{{name.lastName}}') // 'Barrows'
+ * faker.fake('{{name.lastName}}, {{name.firstName}} {{name.suffix}}') // 'Durgan, Noe MD'
+ * faker.fake('This is static test.') // 'This is static test.'
+ * faker.fake('Good Morning {{name.firstName}}!') // 'Good Morning Estelle!'
+ * faker.fake('You can call me at {{phone.phoneNumber(!## ### #####!)}}.') // 'You can call me at 202 555 973722.'
+ * faker.fake('I flipped the coin an got: {{helpers.arrayElement(["heads", "tails"])}}') // 'I flipped the coin an got: tails'
+ */
+ fake(str: string): string {
+ // if incoming str parameter is not provided, return error message
+ if (typeof str !== 'string' || str.length === 0) {
+ throw new FakerError('string parameter is required!');
+ }
+
+ // find first matching {{ and }}
+ const start = str.search(/{{[a-z]/);
+ const end = str.indexOf('}}', start);
+
+ // if no {{ and }} is found, we are done
+ if (start === -1 || end === -1) {
+ return str;
+ }
+
+ // extract method name from between the {{ }} that we found
+ // for example: {{name.firstName}}
+ const token = str.substring(start + 2, end + 2);
+ let method = token.replace('}}', '').replace('{{', '');
+
+ // extract method parameters
+ const regExp = /\(([^)]+)\)/;
+ const matches = regExp.exec(method);
+ let parameters = '';
+ if (matches) {
+ method = method.replace(regExp, '');
+ parameters = matches[1];
+ }
+
+ // split the method into module and function
+ const parts = method.split('.');
+
+ if (this.faker[parts[0]] == null) {
+ throw new FakerError(`Invalid module: ${parts[0]}`);
+ }
+
+ if (this.faker[parts[0]][parts[1]] == null) {
+ throw new FakerError(`Invalid method: ${parts[0]}.${parts[1]}`);
+ }
+
+ // assign the function from the module.function namespace
+ let fn: (args?: unknown) => string = this.faker[parts[0]][parts[1]];
+ fn = fn.bind(this);
+
+ // If parameters are populated here, they are always going to be of string type
+ // since we might actually be dealing with an object or array,
+ // we always attempt to the parse the incoming parameters into JSON
+ let params: unknown;
+ // Note: we experience a small performance hit here due to JSON.parse try / catch
+ // If anyone actually needs to optimize this specific code path, please open a support issue on github
+ try {
+ params = JSON.parse(parameters);
+ } catch (err) {
+ // since JSON.parse threw an error, assume parameters was actually a string
+ params = parameters;
+ }
+
+ let result: string;
+ if (typeof params === 'string' && params.length === 0) {
+ result = String(fn());
+ } else {
+ result = String(fn(params));
+ }
+
+ // Replace the found tag with the returned fake value
+ // We cannot use string.replace here because the result might contain evaluated characters
+ const res = str.substring(0, start) + result + str.substring(end + 2);
+
+ if (res === '') {
+ return '';
+ }
+
+ // return the response recursively until we are done finding all tags
+ return this.fake(res);
+ }
+}
diff --git a/src/modules/finance/iban.ts b/src/modules/finance/iban.ts
new file mode 100644
index 00000000..9b4780c5
--- /dev/null
+++ b/src/modules/finance/iban.ts
@@ -0,0 +1,1414 @@
+interface Iban {
+ alpha: string[];
+ formats: Array<{
+ bban: Array<{ type: string; count: number }>;
+ country: string;
+ format?: string;
+ total?: number;
+ }>;
+ iso3166: string[];
+ mod97: (digitStr: string) => number;
+ pattern10: string[];
+ pattern100: string[];
+ toDigitString: (str: string) => string;
+}
+
+const iban: Iban = {
+ alpha: [
+ 'A',
+ 'B',
+ 'C',
+ 'D',
+ 'E',
+ 'F',
+ 'G',
+ 'H',
+ 'I',
+ 'J',
+ 'K',
+ 'L',
+ 'M',
+ 'N',
+ 'O',
+ 'P',
+ 'Q',
+ 'R',
+ 'S',
+ 'T',
+ 'U',
+ 'V',
+ 'W',
+ 'X',
+ 'Y',
+ 'Z',
+ ],
+ formats: [
+ {
+ country: 'AL',
+ total: 28,
+ bban: [
+ {
+ type: 'n',
+ count: 8,
+ },
+ {
+ type: 'c',
+ count: 16,
+ },
+ ],
+ format: 'ALkk bbbs sssx cccc cccc cccc cccc',
+ },
+ {
+ country: 'AD',
+ total: 24,
+ bban: [
+ {
+ type: 'n',
+ count: 8,
+ },
+ {
+ type: 'c',
+ count: 12,
+ },
+ ],
+ format: 'ADkk bbbb ssss cccc cccc cccc',
+ },
+ {
+ country: 'AT',
+ total: 20,
+ bban: [
+ {
+ type: 'n',
+ count: 5,
+ },
+ {
+ type: 'n',
+ count: 11,
+ },
+ ],
+ format: 'ATkk bbbb bccc cccc cccc',
+ },
+ {
+ // Azerbaijan
+ // https://transferwise.com/fr/iban/azerbaijan
+ // Length 28
+ // BBAN 2c,16n
+ // GEkk bbbb cccc cccc cccc cccc cccc
+ // b = National bank code (alpha)
+ // c = Account number
+ // example IBAN AZ21 NABZ 0000 0000 1370 1000 1944
+ country: 'AZ',
+ total: 28,
+ bban: [
+ {
+ type: 'a',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 20,
+ },
+ ],
+ format: 'AZkk bbbb cccc cccc cccc cccc cccc',
+ },
+ {
+ country: 'BH',
+ total: 22,
+ bban: [
+ {
+ type: 'a',
+ count: 4,
+ },
+ {
+ type: 'c',
+ count: 14,
+ },
+ ],
+ format: 'BHkk bbbb cccc cccc cccc cc',
+ },
+ {
+ country: 'BE',
+ total: 16,
+ bban: [
+ {
+ type: 'n',
+ count: 3,
+ },
+ {
+ type: 'n',
+ count: 9,
+ },
+ ],
+ format: 'BEkk bbbc cccc ccxx',
+ },
+ {
+ country: 'BA',
+ total: 20,
+ bban: [
+ {
+ type: 'n',
+ count: 6,
+ },
+ {
+ type: 'n',
+ count: 10,
+ },
+ ],
+ format: 'BAkk bbbs sscc cccc ccxx',
+ },
+ {
+ country: 'BR',
+ total: 29,
+ bban: [
+ {
+ type: 'n',
+ count: 13,
+ },
+ {
+ type: 'n',
+ count: 10,
+ },
+ {
+ type: 'a',
+ count: 1,
+ },
+ {
+ type: 'c',
+ count: 1,
+ },
+ ],
+ format: 'BRkk bbbb bbbb ssss sccc cccc ccct n',
+ },
+ {
+ country: 'BG',
+ total: 22,
+ bban: [
+ {
+ type: 'a',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 6,
+ },
+ {
+ type: 'c',
+ count: 8,
+ },
+ ],
+ format: 'BGkk bbbb ssss ddcc cccc cc',
+ },
+ {
+ country: 'CR',
+ total: 22,
+ bban: [
+ {
+ type: 'n',
+ count: 1,
+ },
+ {
+ type: 'n',
+ count: 3,
+ },
+ {
+ type: 'n',
+ count: 14,
+ },
+ ],
+ format: 'CRkk xbbb cccc cccc cccc cc',
+ },
+ {
+ country: 'HR',
+ total: 21,
+ bban: [
+ {
+ type: 'n',
+ count: 7,
+ },
+ {
+ type: 'n',
+ count: 10,
+ },
+ ],
+ format: 'HRkk bbbb bbbc cccc cccc c',
+ },
+ {
+ country: 'CY',
+ total: 28,
+ bban: [
+ {
+ type: 'n',
+ count: 8,
+ },
+ {
+ type: 'c',
+ count: 16,
+ },
+ ],
+ format: 'CYkk bbbs ssss cccc cccc cccc cccc',
+ },
+ {
+ country: 'CZ',
+ total: 24,
+ bban: [
+ {
+ type: 'n',
+ count: 10,
+ },
+ {
+ type: 'n',
+ count: 10,
+ },
+ ],
+ format: 'CZkk bbbb ssss sscc cccc cccc',
+ },
+ {
+ country: 'DK',
+ total: 18,
+ bban: [
+ {
+ type: 'n',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 10,
+ },
+ ],
+ format: 'DKkk bbbb cccc cccc cc',
+ },
+ {
+ country: 'DO',
+ total: 28,
+ bban: [
+ {
+ type: 'a',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 20,
+ },
+ ],
+ format: 'DOkk bbbb cccc cccc cccc cccc cccc',
+ },
+ {
+ country: 'TL',
+ total: 23,
+ bban: [
+ {
+ type: 'n',
+ count: 3,
+ },
+ {
+ type: 'n',
+ count: 16,
+ },
+ ],
+ format: 'TLkk bbbc cccc cccc cccc cxx',
+ },
+ {
+ country: 'EE',
+ total: 20,
+ bban: [
+ {
+ type: 'n',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 12,
+ },
+ ],
+ format: 'EEkk bbss cccc cccc cccx',
+ },
+ {
+ country: 'FO',
+ total: 18,
+ bban: [
+ {
+ type: 'n',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 10,
+ },
+ ],
+ format: 'FOkk bbbb cccc cccc cx',
+ },
+ {
+ country: 'FI',
+ total: 18,
+ bban: [
+ {
+ type: 'n',
+ count: 6,
+ },
+ {
+ type: 'n',
+ count: 8,
+ },
+ ],
+ format: 'FIkk bbbb bbcc cccc cx',
+ },
+ {
+ country: 'FR',
+ total: 27,
+ bban: [
+ {
+ type: 'n',
+ count: 10,
+ },
+ {
+ type: 'c',
+ count: 11,
+ },
+ {
+ type: 'n',
+ count: 2,
+ },
+ ],
+ format: 'FRkk bbbb bggg ggcc cccc cccc cxx',
+ },
+ {
+ country: 'GE',
+ total: 22,
+ bban: [
+ {
+ type: 'a',
+ count: 2,
+ },
+ {
+ type: 'n',
+ count: 16,
+ },
+ ],
+ format: 'GEkk bbcc cccc cccc cccc cc',
+ },
+ {
+ country: 'DE',
+ total: 22,
+ bban: [
+ {
+ type: 'n',
+ count: 8,
+ },
+ {
+ type: 'n',
+ count: 10,
+ },
+ ],
+ format: 'DEkk bbbb bbbb cccc cccc cc',
+ },
+ {
+ country: 'GI',
+ total: 23,
+ bban: [
+ {
+ type: 'a',
+ count: 4,
+ },
+ {
+ type: 'c',
+ count: 15,
+ },
+ ],
+ format: 'GIkk bbbb cccc cccc cccc ccc',
+ },
+ {
+ country: 'GR',
+ total: 27,
+ bban: [
+ {
+ type: 'n',
+ count: 7,
+ },
+ {
+ type: 'c',
+ count: 16,
+ },
+ ],
+ format: 'GRkk bbbs sssc cccc cccc cccc ccc',
+ },
+ {
+ country: 'GL',
+ total: 18,
+ bban: [
+ {
+ type: 'n',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 10,
+ },
+ ],
+ format: 'GLkk bbbb cccc cccc cc',
+ },
+ {
+ country: 'GT',
+ total: 28,
+ bban: [
+ {
+ type: 'c',
+ count: 4,
+ },
+ {
+ type: 'c',
+ count: 4,
+ },
+ {
+ type: 'c',
+ count: 16,
+ },
+ ],
+ format: 'GTkk bbbb mmtt cccc cccc cccc cccc',
+ },
+ {
+ country: 'HU',
+ total: 28,
+ bban: [
+ {
+ type: 'n',
+ count: 8,
+ },
+ {
+ type: 'n',
+ count: 16,
+ },
+ ],
+ format: 'HUkk bbbs sssk cccc cccc cccc cccx',
+ },
+ {
+ country: 'IS',
+ total: 26,
+ bban: [
+ {
+ type: 'n',
+ count: 6,
+ },
+ {
+ type: 'n',
+ count: 16,
+ },
+ ],
+ format: 'ISkk bbbb sscc cccc iiii iiii ii',
+ },
+ {
+ country: 'IE',
+ total: 22,
+ bban: [
+ {
+ type: 'c',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 6,
+ },
+ {
+ type: 'n',
+ count: 8,
+ },
+ ],
+ format: 'IEkk aaaa bbbb bbcc cccc cc',
+ },
+ {
+ country: 'IL',
+ total: 23,
+ bban: [
+ {
+ type: 'n',
+ count: 6,
+ },
+ {
+ type: 'n',
+ count: 13,
+ },
+ ],
+ format: 'ILkk bbbn nncc cccc cccc ccc',
+ },
+ {
+ country: 'IT',
+ total: 27,
+ bban: [
+ {
+ type: 'a',
+ count: 1,
+ },
+ {
+ type: 'n',
+ count: 10,
+ },
+ {
+ type: 'c',
+ count: 12,
+ },
+ ],
+ format: 'ITkk xaaa aabb bbbc cccc cccc ccc',
+ },
+ {
+ country: 'JO',
+ total: 30,
+ bban: [
+ {
+ type: 'a',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 18,
+ },
+ ],
+ format: 'JOkk bbbb nnnn cccc cccc cccc cccc cc',
+ },
+ {
+ country: 'KZ',
+ total: 20,
+ bban: [
+ {
+ type: 'n',
+ count: 3,
+ },
+ {
+ type: 'c',
+ count: 13,
+ },
+ ],
+ format: 'KZkk bbbc cccc cccc cccc',
+ },
+ {
+ country: 'XK',
+ total: 20,
+ bban: [
+ {
+ type: 'n',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 12,
+ },
+ ],
+ format: 'XKkk bbbb cccc cccc cccc',
+ },
+ {
+ country: 'KW',
+ total: 30,
+ bban: [
+ {
+ type: 'a',
+ count: 4,
+ },
+ {
+ type: 'c',
+ count: 22,
+ },
+ ],
+ format: 'KWkk bbbb cccc cccc cccc cccc cccc cc',
+ },
+ {
+ country: 'LV',
+ total: 21,
+ bban: [
+ {
+ type: 'a',
+ count: 4,
+ },
+ {
+ type: 'c',
+ count: 13,
+ },
+ ],
+ format: 'LVkk bbbb cccc cccc cccc c',
+ },
+ {
+ country: 'LB',
+ total: 28,
+ bban: [
+ {
+ type: 'n',
+ count: 4,
+ },
+ {
+ type: 'c',
+ count: 20,
+ },
+ ],
+ format: 'LBkk bbbb cccc cccc cccc cccc cccc',
+ },
+ {
+ country: 'LI',
+ total: 21,
+ bban: [
+ {
+ type: 'n',
+ count: 5,
+ },
+ {
+ type: 'c',
+ count: 12,
+ },
+ ],
+ format: 'LIkk bbbb bccc cccc cccc c',
+ },
+ {
+ country: 'LT',
+ total: 20,
+ bban: [
+ {
+ type: 'n',
+ count: 5,
+ },
+ {
+ type: 'n',
+ count: 11,
+ },
+ ],
+ format: 'LTkk bbbb bccc cccc cccc',
+ },
+ {
+ country: 'LU',
+ total: 20,
+ bban: [
+ {
+ type: 'n',
+ count: 3,
+ },
+ {
+ type: 'c',
+ count: 13,
+ },
+ ],
+ format: 'LUkk bbbc cccc cccc cccc',
+ },
+ {
+ country: 'MK',
+ total: 19,
+ bban: [
+ {
+ type: 'n',
+ count: 3,
+ },
+ {
+ type: 'c',
+ count: 10,
+ },
+ {
+ type: 'n',
+ count: 2,
+ },
+ ],
+ format: 'MKkk bbbc cccc cccc cxx',
+ },
+ {
+ country: 'MT',
+ total: 31,
+ bban: [
+ {
+ type: 'a',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 5,
+ },
+ {
+ type: 'c',
+ count: 18,
+ },
+ ],
+ format: 'MTkk bbbb ssss sccc cccc cccc cccc ccc',
+ },
+ {
+ country: 'MR',
+ total: 27,
+ bban: [
+ {
+ type: 'n',
+ count: 10,
+ },
+ {
+ type: 'n',
+ count: 13,
+ },
+ ],
+ format: 'MRkk bbbb bsss sscc cccc cccc cxx',
+ },
+ {
+ country: 'MU',
+ total: 30,
+ bban: [
+ {
+ type: 'a',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 15,
+ },
+ {
+ type: 'a',
+ count: 3,
+ },
+ ],
+ format: 'MUkk bbbb bbss cccc cccc cccc 000d dd',
+ },
+ {
+ country: 'MC',
+ total: 27,
+ bban: [
+ {
+ type: 'n',
+ count: 10,
+ },
+ {
+ type: 'c',
+ count: 11,
+ },
+ {
+ type: 'n',
+ count: 2,
+ },
+ ],
+ format: 'MCkk bbbb bsss sscc cccc cccc cxx',
+ },
+ {
+ country: 'MD',
+ total: 24,
+ bban: [
+ {
+ type: 'c',
+ count: 2,
+ },
+ {
+ type: 'c',
+ count: 18,
+ },
+ ],
+ format: 'MDkk bbcc cccc cccc cccc cccc',
+ },
+ {
+ country: 'ME',
+ total: 22,
+ bban: [
+ {
+ type: 'n',
+ count: 3,
+ },
+ {
+ type: 'n',
+ count: 15,
+ },
+ ],
+ format: 'MEkk bbbc cccc cccc cccc xx',
+ },
+ {
+ country: 'NL',
+ total: 18,
+ bban: [
+ {
+ type: 'a',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 10,
+ },
+ ],
+ format: 'NLkk bbbb cccc cccc cc',
+ },
+ {
+ country: 'NO',
+ total: 15,
+ bban: [
+ {
+ type: 'n',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 7,
+ },
+ ],
+ format: 'NOkk bbbb cccc ccx',
+ },
+ {
+ country: 'PK',
+ total: 24,
+ bban: [
+ {
+ type: 'a',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 16,
+ },
+ ],
+ format: 'PKkk bbbb cccc cccc cccc cccc',
+ },
+ {
+ country: 'PS',
+ total: 29,
+ bban: [
+ {
+ type: 'c',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 9,
+ },
+ {
+ type: 'n',
+ count: 12,
+ },
+ ],
+ format: 'PSkk bbbb xxxx xxxx xccc cccc cccc c',
+ },
+ {
+ country: 'PL',
+ total: 28,
+ bban: [
+ {
+ type: 'n',
+ count: 8,
+ },
+ {
+ type: 'n',
+ count: 16,
+ },
+ ],
+ format: 'PLkk bbbs sssx cccc cccc cccc cccc',
+ },
+ {
+ country: 'PT',
+ total: 25,
+ bban: [
+ {
+ type: 'n',
+ count: 8,
+ },
+ {
+ type: 'n',
+ count: 13,
+ },
+ ],
+ format: 'PTkk bbbb ssss cccc cccc cccx x',
+ },
+ {
+ country: 'QA',
+ total: 29,
+ bban: [
+ {
+ type: 'a',
+ count: 4,
+ },
+ {
+ type: 'c',
+ count: 21,
+ },
+ ],
+ format: 'QAkk bbbb cccc cccc cccc cccc cccc c',
+ },
+ {
+ country: 'RO',
+ total: 24,
+ bban: [
+ {
+ type: 'a',
+ count: 4,
+ },
+ {
+ type: 'c',
+ count: 16,
+ },
+ ],
+ format: 'ROkk bbbb cccc cccc cccc cccc',
+ },
+ {
+ country: 'SM',
+ total: 27,
+ bban: [
+ {
+ type: 'a',
+ count: 1,
+ },
+ {
+ type: 'n',
+ count: 10,
+ },
+ {
+ type: 'c',
+ count: 12,
+ },
+ ],
+ format: 'SMkk xaaa aabb bbbc cccc cccc ccc',
+ },
+ {
+ country: 'SA',
+ total: 24,
+ bban: [
+ {
+ type: 'n',
+ count: 2,
+ },
+ {
+ type: 'c',
+ count: 18,
+ },
+ ],
+ format: 'SAkk bbcc cccc cccc cccc cccc',
+ },
+ {
+ country: 'RS',
+ total: 22,
+ bban: [
+ {
+ type: 'n',
+ count: 3,
+ },
+ {
+ type: 'n',
+ count: 15,
+ },
+ ],
+ format: 'RSkk bbbc cccc cccc cccc xx',
+ },
+ {
+ country: 'SK',
+ total: 24,
+ bban: [
+ {
+ type: 'n',
+ count: 10,
+ },
+ {
+ type: 'n',
+ count: 10,
+ },
+ ],
+ format: 'SKkk bbbb ssss sscc cccc cccc',
+ },
+ {
+ country: 'SI',
+ total: 19,
+ bban: [
+ {
+ type: 'n',
+ count: 5,
+ },
+ {
+ type: 'n',
+ count: 10,
+ },
+ ],
+ format: 'SIkk bbss sccc cccc cxx',
+ },
+ {
+ country: 'ES',
+ total: 24,
+ bban: [
+ {
+ type: 'n',
+ count: 10,
+ },
+ {
+ type: 'n',
+ count: 10,
+ },
+ ],
+ format: 'ESkk bbbb gggg xxcc cccc cccc',
+ },
+ {
+ country: 'SE',
+ total: 24,
+ bban: [
+ {
+ type: 'n',
+ count: 3,
+ },
+ {
+ type: 'n',
+ count: 17,
+ },
+ ],
+ format: 'SEkk bbbc cccc cccc cccc cccc',
+ },
+ {
+ country: 'CH',
+ total: 21,
+ bban: [
+ {
+ type: 'n',
+ count: 5,
+ },
+ {
+ type: 'c',
+ count: 12,
+ },
+ ],
+ format: 'CHkk bbbb bccc cccc cccc c',
+ },
+ {
+ country: 'TN',
+ total: 24,
+ bban: [
+ {
+ type: 'n',
+ count: 5,
+ },
+ {
+ type: 'n',
+ count: 15,
+ },
+ ],
+ format: 'TNkk bbss sccc cccc cccc cccc',
+ },
+ {
+ country: 'TR',
+ total: 26,
+ bban: [
+ {
+ type: 'n',
+ count: 5,
+ },
+ {
+ type: 'n',
+ count: 1,
+ },
+ {
+ type: 'n',
+ count: 16,
+ },
+ ],
+ format: 'TRkk bbbb bxcc cccc cccc cccc cc',
+ },
+ {
+ country: 'AE',
+ total: 23,
+ bban: [
+ {
+ type: 'n',
+ count: 3,
+ },
+ {
+ type: 'n',
+ count: 16,
+ },
+ ],
+ format: 'AEkk bbbc cccc cccc cccc ccc',
+ },
+ {
+ country: 'GB',
+ total: 22,
+ bban: [
+ {
+ type: 'a',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 6,
+ },
+ {
+ type: 'n',
+ count: 8,
+ },
+ ],
+ format: 'GBkk bbbb ssss sscc cccc cc',
+ },
+ {
+ country: 'VG',
+ total: 24,
+ bban: [
+ {
+ type: 'c',
+ count: 4,
+ },
+ {
+ type: 'n',
+ count: 16,
+ },
+ ],
+ format: 'VGkk bbbb cccc cccc cccc cccc',
+ },
+ ],
+ iso3166: [
+ 'AD',
+ 'AE',
+ 'AF',
+ 'AG',
+ 'AI',
+ 'AL',
+ 'AM',
+ 'AO',
+ 'AQ',
+ 'AR',
+ 'AS',
+ 'AT',
+ 'AU',
+ 'AW',
+ 'AX',
+ 'AZ',
+ 'BA',
+ 'BB',
+ 'BD',
+ 'BE',
+ 'BF',
+ 'BG',
+ 'BH',
+ 'BI',
+ 'BJ',
+ 'BL',
+ 'BM',
+ 'BN',
+ 'BO',
+ 'BQ',
+ 'BR',
+ 'BS',
+ 'BT',
+ 'BV',
+ 'BW',
+ 'BY',
+ 'BZ',
+ 'CA',
+ 'CC',
+ 'CD',
+ 'CF',
+ 'CG',
+ 'CH',
+ 'CI',
+ 'CK',
+ 'CL',
+ 'CM',
+ 'CN',
+ 'CO',
+ 'CR',
+ 'CU',
+ 'CV',
+ 'CW',
+ 'CX',
+ 'CY',
+ 'CZ',
+ 'DE',
+ 'DJ',
+ 'DK',
+ 'DM',
+ 'DO',
+ 'DZ',
+ 'EC',
+ 'EE',
+ 'EG',
+ 'EH',
+ 'ER',
+ 'ES',
+ 'ET',
+ 'FI',
+ 'FJ',
+ 'FK',
+ 'FM',
+ 'FO',
+ 'FR',
+ 'GA',
+ 'GB',
+ 'GD',
+ 'GE',
+ 'GF',
+ 'GG',
+ 'GH',
+ 'GI',
+ 'GL',
+ 'GM',
+ 'GN',
+ 'GP',
+ 'GQ',
+ 'GR',
+ 'GS',
+ 'GT',
+ 'GU',
+ 'GW',
+ 'GY',
+ 'HK',
+ 'HM',
+ 'HN',
+ 'HR',
+ 'HT',
+ 'HU',
+ 'ID',
+ 'IE',
+ 'IL',
+ 'IM',
+ 'IN',
+ 'IO',
+ 'IQ',
+ 'IR',
+ 'IS',
+ 'IT',
+ 'JE',
+ 'JM',
+ 'JO',
+ 'JP',
+ 'KE',
+ 'KG',
+ 'KH',
+ 'KI',
+ 'KM',
+ 'KN',
+ 'KP',
+ 'KR',
+ 'KW',
+ 'KY',
+ 'KZ',
+ 'LA',
+ 'LB',
+ 'LC',
+ 'LI',
+ 'LK',
+ 'LR',
+ 'LS',
+ 'LT',
+ 'LU',
+ 'LV',
+ 'LY',
+ 'MA',
+ 'MC',
+ 'MD',
+ 'ME',
+ 'MF',
+ 'MG',
+ 'MH',
+ 'MK',
+ 'ML',
+ 'MM',
+ 'MN',
+ 'MO',
+ 'MP',
+ 'MQ',
+ 'MR',
+ 'MS',
+ 'MT',
+ 'MU',
+ 'MV',
+ 'MW',
+ 'MX',
+ 'MY',
+ 'MZ',
+ 'NA',
+ 'NC',
+ 'NE',
+ 'NF',
+ 'NG',
+ 'NI',
+ 'NL',
+ 'NO',
+ 'NP',
+ 'NR',
+ 'NU',
+ 'NZ',
+ 'OM',
+ 'PA',
+ 'PE',
+ 'PF',
+ 'PG',
+ 'PH',
+ 'PK',
+ 'PL',
+ 'PM',
+ 'PN',
+ 'PR',
+ 'PS',
+ 'PT',
+ 'PW',
+ 'PY',
+ 'QA',
+ 'RE',
+ 'RO',
+ 'RS',
+ 'RU',
+ 'RW',
+ 'SA',
+ 'SB',
+ 'SC',
+ 'SD',
+ 'SE',
+ 'SG',
+ 'SH',
+ 'SI',
+ 'SJ',
+ 'SK',
+ 'SL',
+ 'SM',
+ 'SN',
+ 'SO',
+ 'SR',
+ 'SS',
+ 'ST',
+ 'SV',
+ 'SX',
+ 'SY',
+ 'SZ',
+ 'TC',
+ 'TD',
+ 'TF',
+ 'TG',
+ 'TH',
+ 'TJ',
+ 'TK',
+ 'TL',
+ 'TM',
+ 'TN',
+ 'TO',
+ 'TR',
+ 'TT',
+ 'TV',
+ 'TW',
+ 'TZ',
+ 'UA',
+ 'UG',
+ 'UM',
+ 'US',
+ 'UY',
+ 'UZ',
+ 'VA',
+ 'VC',
+ 'VE',
+ 'VG',
+ 'VI',
+ 'VN',
+ 'VU',
+ 'WF',
+ 'WS',
+ 'XK',
+ 'YE',
+ 'YT',
+ 'ZA',
+ 'ZM',
+ 'ZW',
+ ],
+ mod97: (digitStr) => {
+ let m = 0;
+ for (let i = 0; i < digitStr.length; i++) {
+ m = (m * 10 + +digitStr[i]) % 97;
+ }
+ return m;
+ },
+ pattern10: ['01', '02', '03', '04', '05', '06', '07', '08', '09'],
+ pattern100: ['001', '002', '003', '004', '005', '006', '007', '008', '009'],
+ toDigitString: (str) =>
+ str.replace(/[A-Z]/gi, (match) =>
+ String(match.toUpperCase().charCodeAt(0) - 55)
+ ),
+};
+
+export default iban;
diff --git a/src/modules/finance/index.ts b/src/modules/finance/index.ts
new file mode 100644
index 00000000..a74dceba
--- /dev/null
+++ b/src/modules/finance/index.ts
@@ -0,0 +1,436 @@
+import type { Faker } from '../..';
+import { FakerError } from '../../errors/faker-error';
+import iban from './iban';
+
+/**
+ * Module to generate finance related entries.
+ */
+export class Finance {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Finance.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Generates a random account number.
+ *
+ * @param length The length of the account number. Defaults to `8`.
+ *
+ * @example
+ * faker.finance.account() // 92842238
+ * faker.finance.account(5) // 32564
+ */
+ account(length?: number): string {
+ length = length || 8;
+ let template = '';
+
+ for (let i = 0; i < length; i++) {
+ template += '#';
+ }
+ length = null;
+ return this.faker.helpers.replaceSymbolWithNumber(template);
+ }
+
+ /**
+ * Generates a random account name.
+ *
+ * @example
+ * faker.finance.accountName() // 'Personal Loan Account'
+ */
+ accountName(): string {
+ return [
+ this.faker.helpers.arrayElement(
+ this.faker.definitions.finance.account_type
+ ),
+ 'Account',
+ ].join(' ');
+ }
+
+ /**
+ * Generates a random routing number.
+ *
+ * @example
+ * faker.finance.routingNumber() // '522814402'
+ */
+ routingNumber(): string {
+ const routingNumber =
+ this.faker.helpers.replaceSymbolWithNumber('########');
+
+ // Modules 10 straight summation.
+ let sum = 0;
+
+ for (let i = 0; i < routingNumber.length; i += 3) {
+ sum += Number(routingNumber[i]) * 3;
+ sum += Number(routingNumber[i + 1]) * 7;
+ sum += Number(routingNumber[i + 2]) || 0;
+ }
+
+ return `${routingNumber}${Math.ceil(sum / 10) * 10 - sum}`;
+ }
+
+ /**
+ * Generates a random masked number.
+ *
+ * @param length The length of the unmasked number. Defaults to `4`.
+ * @param parens Whether to use surrounding parenthesis. Defaults to `true`.
+ * @param ellipsis Whether to prefix the numbers with an ellipsis. Defaults to `true`.
+ *
+ * @example
+ * faker.finance.mask() // '(...9711)'
+ * faker.finance.mask(3) // '(...342)'
+ * faker.finance.mask(3, false) // '...236'
+ * faker.finance.mask(3, false, false) // '298'
+ */
+ mask(length?: number, parens?: boolean, ellipsis?: boolean): string {
+ // set defaults
+ length = length || 4;
+ parens = parens == null ? true : parens;
+ ellipsis = ellipsis == null ? true : ellipsis;
+
+ // create a template for length
+ let template = '';
+
+ for (let i = 0; i < length; i++) {
+ template = `${template}#`;
+ }
+
+ //prefix with ellipsis
+ template = ellipsis ? ['...', template].join('') : template;
+
+ template = parens ? ['(', template, ')'].join('') : template;
+
+ //generate random numbers
+ template = this.faker.helpers.replaceSymbolWithNumber(template);
+
+ return template;
+ }
+
+ /**
+ * Generates a random amount between the given bounds (inclusive).
+ *
+ * @param min The lower bound for the amount. Defaults to `0`.
+ * @param max The upper bound for the amount. Defaults to `1000`.
+ * @param dec The number of decimal places for the amount. Defaults to `2`.
+ * @param symbol The symbol used to prefix the amount. Defaults to `''`.
+ * @param autoFormat If true this method will use `Number.toLocaleString()`. Otherwise it will use `Number.toFixed()`.
+ *
+ * @example
+ * faker.finance.amount() // '617.87'
+ * faker.finance.amount(5, 10) // '5.53'
+ * faker.finance.amount(5, 10, 0) // '8'
+ * faker.finance.amount(5, 10, 2, '$') // '$5.85'
+ * faker.finance.amount(5, 10, 5, '', true) // '9,75067'
+ */
+ amount(
+ min: number = 0,
+ max: number = 1000,
+ dec: number = 2,
+ symbol: string = '',
+ autoFormat?: boolean
+ ): string {
+ const randValue = this.faker.datatype.number({
+ max,
+ min,
+ precision: Math.pow(10, -dec),
+ });
+
+ let formattedString: string;
+ if (autoFormat) {
+ formattedString = randValue.toLocaleString(undefined, {
+ minimumFractionDigits: dec,
+ });
+ } else {
+ formattedString = randValue.toFixed(dec);
+ }
+
+ return symbol + formattedString;
+ }
+
+ /**
+ * Returns a random transaction type.
+ *
+ * @example
+ * faker.finance.transactionType() // 'payment'
+ */
+ transactionType(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.finance.transaction_type
+ );
+ }
+
+ /**
+ * Returns a random currency code.
+ * (The short text/abbreviation for the currency (e.g. `US Dollar` -> `USD`))
+ *
+ * @example
+ * faker.finance.currencyCode() // 'USD'
+ */
+ currencyCode(): string {
+ return this.faker.helpers.objectValue(
+ this.faker.definitions.finance.currency
+ )['code'];
+ }
+
+ /**
+ * Returns a random currency name.
+ *
+ * @example
+ * faker.finance.currencyName() // 'US Dollar'
+ */
+ currencyName(): string {
+ return this.faker.helpers.objectKey(
+ this.faker.definitions.finance.currency
+ ) as string;
+ }
+
+ /**
+ * Returns a random currency symbol.
+ *
+ * @example
+ * faker.finance.currencySymbol() // '$'
+ */
+ currencySymbol(): string {
+ let symbol: string;
+ while (!symbol) {
+ symbol = this.faker.helpers.objectValue(
+ this.faker.definitions.finance.currency
+ )['symbol'];
+ }
+ return symbol;
+ }
+
+ /**
+ * Generates a random bitcoin address.
+ *
+ * @example
+ * faker.finance.bitcoinAddress() // '3ySdvCkTLVy7gKD4j6JfSaf5d'
+ */
+ bitcoinAddress(): string {
+ const addressLength = this.faker.datatype.number({ min: 25, max: 34 });
+
+ let address = this.faker.helpers.arrayElement(['1', '3']);
+
+ for (let i = 0; i < addressLength - 1; i++)
+ address += this.faker.helpers.arrayElement(
+ '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'.split('')
+ );
+
+ return address;
+ }
+
+ /**
+ * Generates a random litecoin address.
+ *
+ * @example
+ * faker.finance.litecoinAddress() // 'MoQaSTGWBRXkWfyxKbNKuPrAWGELzcW'
+ */
+ litecoinAddress(): string {
+ const addressLength = this.faker.datatype.number({ min: 26, max: 33 });
+
+ let address = this.faker.helpers.arrayElement(['L', 'M', '3']);
+
+ for (let i = 0; i < addressLength - 1; i++)
+ address += this.faker.helpers.arrayElement(
+ '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'.split('')
+ );
+
+ return address;
+ }
+
+ /**
+ * Generates a random credit card number.
+ *
+ * @param issuer The name of the issuer (case insensitive) or the format used to generate one.
+ *
+ * @example
+ * faker.finance.creditCardNumber() // '4427163488668'
+ * faker.finance.creditCardNumber('visa') // '4882664999003'
+ * faker.finance.creditCardNumber('63[7-9]#-####-####-###L') // '6375-3265-4676-6644'
+ */
+ creditCardNumber(issuer = ''): string {
+ let format: string;
+ const localeFormat = this.faker.definitions.finance.credit_card;
+ const normalizedIssuer = issuer.toLowerCase();
+ if (normalizedIssuer in localeFormat) {
+ format = this.faker.helpers.arrayElement(localeFormat[normalizedIssuer]);
+ } else if (issuer.match(/#/)) {
+ // The user chose an optional scheme
+ format = issuer;
+ } else {
+ // Choose a random issuer
+ // Credit cards are in an object structure
+ const formats = this.faker.helpers.objectValue(localeFormat); // There could be multiple formats
+ format = this.faker.helpers.arrayElement(formats);
+ }
+ format = format.replace(/\//g, '');
+ return this.faker.helpers.replaceCreditCardSymbols(format);
+ }
+
+ /**
+ * Generates a random credit card CVV.
+ *
+ * @example
+ * faker.finance.creditCardCVV() // '506'
+ */
+ creditCardCVV(): string {
+ let cvv = '';
+ for (let i = 0; i < 3; i++) {
+ cvv += this.faker.datatype.number({ max: 9 }).toString();
+ }
+ return cvv;
+ }
+
+ /**
+ * Returns a random credit card issuer.
+ *
+ * @example
+ * faker.finance.creditCardIssuer() // 'discover'
+ */
+ creditCardIssuer(): string {
+ return this.faker.helpers.objectKey(
+ this.faker.definitions.finance.credit_card
+ ) as string;
+ }
+
+ /**
+ * Generates a random PIN number.
+ *
+ * @param length The length of the PIN to generate. Defaults to `4`.
+ * @throws Will throw an error if length is less than 1.
+ *
+ * @example
+ * faker.finance.pin() // '5067'
+ * faker.finance.pin(6) // '213789'
+ */
+ pin(length: number = 4): string {
+ if (length < 1) {
+ throw new FakerError('minimum length is 1');
+ }
+ return Array.from({ length }, () => this.faker.datatype.number(9)).join('');
+ }
+
+ /**
+ * Generates a random ethereum Address.
+ *
+ * @example
+ * faker.finance.ethereumAddress() // '0xf03dfeecbafc5147241cc4c4ca20b3c9dfd04c4a'
+ */
+ ethereumAddress(): string {
+ const address = this.faker.datatype.hexadecimal(40).toLowerCase();
+ return address;
+ }
+
+ /**
+ * Generates a random iban.
+ *
+ * @param formatted Return a formatted version of the generated IBAN. Defaults to `false`.
+ * @param countryCode The country code from which you want to generate an IBAN, if none is provided a random country will be used.
+ * @throws Will throw an error if the passed country code is not supported.
+ *
+ * @example
+ * faker.finance.iban() // 'TR736918640040966092800056'
+ * faker.finance.iban(true) // 'FR20 8008 2330 8984 74S3 Z620 224'
+ * faker.finance.iban(true, 'DE') // 'DE84 1022 7075 0900 1170 01'
+ */
+ iban(formatted: boolean = false, countryCode?: string): string {
+ const ibanFormat = countryCode
+ ? iban.formats.find((f) => f.country === countryCode)
+ : this.faker.helpers.arrayElement(iban.formats);
+
+ if (!ibanFormat) {
+ throw new FakerError(`Country code ${countryCode} not supported.`);
+ }
+
+ let s = '';
+ let count = 0;
+ for (const bban of ibanFormat.bban) {
+ let c = bban.count;
+ count += bban.count;
+ while (c > 0) {
+ if (bban.type === 'a') {
+ s += this.faker.helpers.arrayElement(iban.alpha);
+ } else if (bban.type === 'c') {
+ if (this.faker.datatype.number(100) < 80) {
+ s += this.faker.datatype.number(9);
+ } else {
+ s += this.faker.helpers.arrayElement(iban.alpha);
+ }
+ } else {
+ if (c >= 3 && this.faker.datatype.number(100) < 30) {
+ if (this.faker.datatype.boolean()) {
+ s += this.faker.helpers.arrayElement(iban.pattern100);
+ c -= 2;
+ } else {
+ s += this.faker.helpers.arrayElement(iban.pattern10);
+ c--;
+ }
+ } else {
+ s += this.faker.datatype.number(9);
+ }
+ }
+ c--;
+ }
+ s = s.substring(0, count);
+ }
+ let checksum: string | number =
+ 98 - iban.mod97(iban.toDigitString(`${s}${ibanFormat.country}00`));
+
+ if (checksum < 10) {
+ checksum = `0${checksum}`;
+ }
+
+ const result = `${ibanFormat.country}${checksum}${s}`;
+
+ return formatted ? result.match(/.{1,4}/g).join(' ') : result;
+ }
+
+ /**
+ * Generates a random bic.
+ *
+ * @example
+ * faker.finance.bic() // 'WYAUPGX1432'
+ */
+ bic(): string {
+ const vowels = ['A', 'E', 'I', 'O', 'U'];
+ const prob = this.faker.datatype.number(100);
+
+ return [
+ this.faker.helpers.replaceSymbols('???'),
+ this.faker.helpers.arrayElement(vowels),
+ this.faker.helpers.arrayElement(iban.iso3166),
+ this.faker.helpers.replaceSymbols('?'),
+ '1',
+ prob < 10
+ ? this.faker.helpers.replaceSymbols(
+ `?${this.faker.helpers.arrayElement(vowels)}?`
+ )
+ : prob < 40
+ ? this.faker.helpers.replaceSymbols('###')
+ : '',
+ ].join('');
+ }
+
+ /**
+ * Generates a random transaction description.
+ *
+ * @example
+ * faker.finance.transactionDescription()
+ * // 'invoice transaction at Kilback - Durgan using card ending with ***(...4316) for UAH 783.82 in account ***16168663'
+ */
+ transactionDescription(): string {
+ const transaction = this.faker.helpers.createTransaction();
+ const account = transaction.account;
+ const amount = transaction.amount;
+ const transactionType = transaction.type;
+ const company = transaction.business;
+ const card = this.mask();
+ const currency = this.currencyCode();
+
+ return `${transactionType} transaction at ${company} using card ending with ***${card} for ${currency} ${amount} in account ***${account}`;
+ }
+}
diff --git a/src/modules/git/index.ts b/src/modules/git/index.ts
new file mode 100644
index 00000000..e86f6648
--- /dev/null
+++ b/src/modules/git/index.ts
@@ -0,0 +1,134 @@
+import type { Faker } from '../..';
+
+/**
+ * Module to generate git related entries.
+ */
+export class Git {
+ private hexChars = [
+ '0',
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ 'a',
+ 'b',
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ ];
+
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Git.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Generates a random branch name.
+ *
+ * @example
+ * faker.git.branch() // 'feed-parse'
+ */
+ branch(): string {
+ const noun = this.faker.hacker.noun().replace(' ', '-');
+ const verb = this.faker.hacker.verb().replace(' ', '-');
+ return `${noun}-${verb}`;
+ }
+
+ /**
+ * Generates a random commit entry.
+ *
+ * @param options Options for the commit entry.
+ * @param options.merge Set to `true` to generate a merge message line.
+ * @param options.eol Choose the end of line character to use. Defaults to 'CRLF'.
+ * 'LF' = '\n',
+ * 'CRLF' = '\r\n'
+ *
+ * @example
+ * faker.git.commitEntry()
+ * // commit fe8c38a965d13d9794eb36918cb24cebe49a45c2
+ * // Author: Mable Harvey <[email protected]>
+ * // Date: Sat Feb 05 2022 15:09:18 GMT+0100 (Mitteleuropäische Normalzeit)
+ * //
+ * // copy primary system
+ */
+ commitEntry(
+ options: {
+ merge?: boolean;
+ eol?: 'LF' | 'CRLF';
+ } = {}
+ ): string {
+ const lines = [`commit ${this.faker.git.commitSha()}`];
+
+ if (options.merge || this.faker.datatype.number({ min: 0, max: 4 }) === 0) {
+ lines.push(`Merge: ${this.shortSha()} ${this.shortSha()}`);
+ }
+
+ lines.push(
+ `Author: ${this.faker.name.firstName()} ${this.faker.name.lastName()} <${this.faker.internet.email()}>`,
+ `Date: ${this.faker.date.recent().toString()}`,
+ '',
+ `\xa0\xa0\xa0\xa0${this.commitMessage()}`,
+ // to end with a eol char
+ ''
+ );
+
+ const eolOption = options.eol ?? 'CRLF';
+ const eolChar = eolOption === 'CRLF' ? '\r\n' : '\n';
+ const entry = lines.join(eolChar);
+
+ return entry;
+ }
+
+ /**
+ * Generates a random commit message.
+ *
+ * @example
+ * faker.git.commitMessage() // 'reboot cross-platform driver'
+ */
+ commitMessage(): string {
+ return `${this.faker.hacker.verb()} ${this.faker.hacker.adjective()} ${this.faker.hacker.noun()}`;
+ }
+
+ /**
+ * Generates a random commit sha (full).
+ *
+ * @example
+ * faker.git.commitSha() // '2c6e3880fd94ddb7ef72d34e683cdc0c47bec6e6'
+ */
+ commitSha(): string {
+ let commit = '';
+
+ for (let i = 0; i < 40; i++) {
+ commit += this.faker.helpers.arrayElement(this.hexChars);
+ }
+
+ return commit;
+ }
+
+ /**
+ * Generates a random commit sha (short).
+ *
+ * @example
+ * faker.git.shortSha() // '6155732'
+ */
+ shortSha(): string {
+ let shortSha = '';
+
+ for (let i = 0; i < 7; i++) {
+ shortSha += this.faker.helpers.arrayElement(this.hexChars);
+ }
+
+ return shortSha;
+ }
+}
diff --git a/src/modules/hacker/index.ts b/src/modules/hacker/index.ts
new file mode 100644
index 00000000..ee1bbc5c
--- /dev/null
+++ b/src/modules/hacker/index.ts
@@ -0,0 +1,94 @@
+import type { Faker } from '../..';
+
+/**
+ * Module to generate hacker/IT words and phrases.
+ */
+export class Hacker {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Hacker.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Returns a random hacker/IT abbreviation.
+ *
+ * @example
+ * faker.hacker.abbreviation() // 'THX'
+ */
+ abbreviation(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.hacker.abbreviation
+ );
+ }
+
+ /**
+ * Returns a random hacker/IT adjective.
+ *
+ * @example
+ * faker.hacker.adjective() // 'cross-platform'
+ */
+ adjective(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.hacker.adjective
+ );
+ }
+
+ /**
+ * Returns a random hacker/IT noun.
+ *
+ * @example
+ * faker.hacker.noun() // 'system'
+ */
+ noun(): string {
+ return this.faker.helpers.arrayElement(this.faker.definitions.hacker.noun);
+ }
+
+ /**
+ * Returns a random hacker/IT verb.
+ *
+ * @example
+ * faker.hacker.verb() // 'copy'
+ */
+ verb(): string {
+ return this.faker.helpers.arrayElement(this.faker.definitions.hacker.verb);
+ }
+
+ /**
+ * Returns a random hacker/IT verb for continuous actions (en: ing suffix; e.g. hacking).
+ *
+ * @example
+ * faker.hacker.ingverb() // 'navigating'
+ */
+ ingverb(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.hacker.ingverb
+ );
+ }
+
+ /**
+ * Generates a random hacker/IT phrase.
+ *
+ * @example
+ * faker.hacker.phrase()
+ * // 'If we override the card, we can get to the HDD feed through the back-end HDD sensor!'
+ */
+ phrase(): string {
+ const data = {
+ abbreviation: this.abbreviation,
+ adjective: this.adjective,
+ ingverb: this.ingverb,
+ noun: this.noun,
+ verb: this.verb,
+ };
+
+ const phrase = this.faker.helpers.arrayElement(
+ this.faker.definitions.hacker.phrase
+ );
+ return this.faker.helpers.mustache(phrase, data);
+ }
+}
diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts
new file mode 100644
index 00000000..1b28ddfa
--- /dev/null
+++ b/src/modules/helpers/index.ts
@@ -0,0 +1,810 @@
+import type { Faker } from '../..';
+import { deprecated } from '../../internal/deprecated';
+
+/**
+ * A full card with various details.
+ */
+export interface Card {
+ name: string;
+ username: string;
+ email: string;
+ address: {
+ streetA: string;
+ streetB: string;
+ streetC: string;
+ streetD: string;
+ city: string;
+ state: string;
+ country: string;
+ zipcode: string;
+ geo: {
+ lat: string;
+ lng: string;
+ };
+ };
+ phone: string;
+ website: string;
+ company: {
+ name: string;
+ catchPhrase: string;
+ bs: string;
+ };
+ posts: Array<{
+ words: string;
+ sentence: string;
+ sentences: string;
+ paragraph: string;
+ }>;
+ accountHistory: Array<{
+ amount: string;
+ date: Date;
+ business: string;
+ name: string;
+ type: string;
+ account: string;
+ }>;
+}
+
+/**
+ * A persons card with various details attempting to use a consistent context.
+ */
+export interface ContextualCard {
+ name: string;
+ username: string;
+ avatar: string;
+ email: string;
+ dob: Date;
+ phone: string;
+ address: {
+ street: string;
+ suite: string;
+ city: string;
+ zipcode: string;
+ geo: {
+ lat: string;
+ lng: string;
+ };
+ };
+ website: string;
+ company: {
+ name: string;
+ catchPhrase: string;
+ bs: string;
+ };
+}
+
+/**
+ * A user card with various details.
+ */
+export interface UserCard {
+ name: string;
+ username: string;
+ email: string;
+ address: {
+ street: string;
+ suite: string;
+ city: string;
+ zipcode: string;
+ geo: {
+ lat: string;
+ lng: string;
+ };
+ };
+ phone: string;
+ website: string;
+ company: {
+ name: string;
+ catchPhrase: string;
+ bs: string;
+ };
+}
+
+/**
+ * A transaction info.
+ */
+export interface Transaction {
+ amount: string;
+ date: Date;
+ business: string;
+ name: string;
+ type: string;
+ account: string;
+}
+
+/**
+ * Module with various helper methods that transform the method input rather than returning values from locales.
+ * The transformation process may call methods that use the locale data.
+ */
+export class Helpers {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Helpers.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Backward-compatibility. Use `faker.helpers.arrayElement()` instead.
+ *
+ * Takes an array and returns a random element of the array.
+ *
+ * @template T The type of the entries to pick from.
+ * @param array The array to select an element from.
+ *
+ * @see faker.helpers.arrayElement()
+ *
+ * @example
+ * faker.helpers.randomize() // 'c'
+ * faker.helpers.randomize([1, 2, 3]) // '2'
+ *
+ * @deprecated
+ */
+ randomize<T = string>(
+ array: ReadonlyArray<T> = ['a', 'b', 'c'] as unknown as ReadonlyArray<T>
+ ): T {
+ deprecated({
+ deprecated: 'faker.helpers.randomize()',
+ proposed: 'faker.helpers.arrayElement()',
+ // since: 'v5.0.0', (?)
+ until: 'v7.0.0',
+ });
+ return this.arrayElement(array);
+ }
+
+ /**
+ * Slugifies the given string.
+ * For that all spaces (` `) are replaced by hyphens (`-`)
+ * and most non word characters except for dots and hyphens will be removed.
+ *
+ * @param string The input to slugify.
+ *
+ * @example
+ * faker.helpers.slugify() // ''
+ * faker.helpers.slugify("Hello world!") // 'Hello-world'
+ */
+ slugify(string: string = ''): string {
+ return string
+ .replace(/ /g, '-')
+ .replace(/[^\一-龠\ぁ-ゔ\ァ-ヴー\w\.\-]+/g, '');
+ }
+
+ /**
+ * Parses the given string symbol by symbol and replaces the placeholders with digits (`0` - `9`).
+ * `!` will be replaced by digits >=2 (`2` - `9`).
+ *
+ * @param string The template string to parse.
+ * @param symbol The symbol to replace with digits. Defaults to `'#'`.
+ *
+ * @example
+ * faker.helpers.replaceSymbolWithNumber() // ''
+ * faker.helpers.replaceSymbolWithNumber('#####') // '04812'
+ * faker.helpers.replaceSymbolWithNumber('!####') // '27378'
+ * faker.helpers.replaceSymbolWithNumber('Your pin is: !####') // '29841'
+ */
+ replaceSymbolWithNumber(string: string = '', symbol: string = '#'): string {
+ let str = '';
+ for (let i = 0; i < string.length; i++) {
+ if (string.charAt(i) === symbol) {
+ str += this.faker.datatype.number(9);
+ } else if (string.charAt(i) === '!') {
+ str += this.faker.datatype.number({ min: 2, max: 9 });
+ } else {
+ str += string.charAt(i);
+ }
+ }
+ return str;
+ }
+
+ /**
+ * Parses the given string symbol by symbols and replaces the placeholder appropriately.
+ *
+ * - `#` will be replaced with a digit (`0` - `9`).
+ * - `?` will be replaced with an upper letter ('A' - 'Z')
+ * - and `*` will be replaced with either a digit or letter.
+ *
+ * @param string The template string to parse.
+ *
+ * @example
+ * faker.helpers.replaceSymbols() // ''
+ * faker.helpers.replaceSymbols('#####') // '98441'
+ * faker.helpers.replaceSymbols('?????') // 'ZYRQQ'
+ * faker.helpers.replaceSymbols('*****') // '4Z3P7'
+ * faker.helpers.replaceSymbols('Your pin is: #?*#?*') // '0T85L1'
+ */
+ replaceSymbols(string: string = ''): string {
+ const alpha = [
+ 'A',
+ 'B',
+ 'C',
+ 'D',
+ 'E',
+ 'F',
+ 'G',
+ 'H',
+ 'I',
+ 'J',
+ 'K',
+ 'L',
+ 'M',
+ 'N',
+ 'O',
+ 'P',
+ 'Q',
+ 'R',
+ 'S',
+ 'T',
+ 'U',
+ 'V',
+ 'W',
+ 'X',
+ 'Y',
+ 'Z',
+ ];
+ let str = '';
+
+ for (let i = 0; i < string.length; i++) {
+ if (string.charAt(i) === '#') {
+ str += this.faker.datatype.number(9);
+ } else if (string.charAt(i) === '?') {
+ str += this.arrayElement(alpha);
+ } else if (string.charAt(i) === '*') {
+ str += this.faker.datatype.boolean()
+ ? this.arrayElement(alpha)
+ : this.faker.datatype.number(9);
+ } else {
+ str += string.charAt(i);
+ }
+ }
+ return str;
+ }
+
+ /**
+ * Replaces the symbols and patterns in a credit card schema including Luhn checksum.
+ *
+ * This method supports both range patterns `[4-9]` as well as the patterns used by `replaceSymbolWithNumber()`.
+ * `L` will be replaced with the appropriate Luhn checksum.
+ *
+ * @param string The credit card format pattern. Defaults to `6453-####-####-####-###L`.
+ * @param symbol The symbol to replace with a digit.
+ *
+ * @example
+ * faker.helpers.replaceCreditCardSymbols() // '6453-4876-8626-8995-3779'
+ * faker.helpers.replaceCreditCardSymbols('1234-[4-9]-##!!-L') // '1234-9-5298-2'
+ */
+ replaceCreditCardSymbols(
+ string: string = '6453-####-####-####-###L',
+ symbol: string = '#'
+ ): string {
+ // default values required for calling method without arguments
+
+ // Function calculating the Luhn checksum of a number string
+ const getCheckBit = (number: number[]) => {
+ number.reverse();
+ number = number.map((num, index) => {
+ if (index % 2 === 0) {
+ num *= 2;
+ if (num > 9) {
+ num -= 9;
+ }
+ }
+ return num;
+ });
+ const sum = number.reduce((prev, curr) => prev + curr);
+ return sum % 10;
+ };
+
+ string = this.regexpStyleStringParse(string); // replace [4-9] with a random number in range etc...
+ string = this.replaceSymbolWithNumber(string, symbol); // replace ### with random numbers
+
+ const numberList = string
+ .replace(/\D/g, '')
+ .split('')
+ .map((num) => parseInt(num));
+ const checkNum = getCheckBit(numberList);
+ return string.replace('L', String(checkNum));
+ }
+
+ /**
+ * Repeats the given string the given number of times.
+ *
+ * @param string The string to repeat. Defaults to `''`.
+ * @param num The number of times to repeat it. Defaults to `0`.
+ *
+ * @example
+ * faker.helpers.repeatString('Hello world! ') // ''
+ * faker.helpers.repeatString('Hello world! ', 1) // 'Hello world! '
+ * faker.helpers.repeatString('Hello world! ', 2) // 'Hello world! Hello world! '
+ */
+ repeatString(string = '', num = 0): string {
+ let text = '';
+ for (let i = 0; i < num; i++) {
+ text += string.toString();
+ }
+ return text;
+ }
+
+ /**
+ * Replaces the regex like expressions in the given string with matching values.
+ *
+ * Supported patterns:
+ * - `.{times}` => Repeat the character exactly `times` times.
+ * - `.{min,max}` => Repeat the character `min` to `max` times.
+ * - `[min-max]` => Generate a number between min and max (inclusive).
+ *
+ * @param string The template string to to parse.
+ *
+ * @example
+ * faker.helpers.regexpStyleStringParse() // ''
+ * faker.helpers.regexpStyleStringParse('#{5}') // '#####'
+ * faker.helpers.regexpStyleStringParse('#{2,9}') // '#######'
+ * faker.helpers.regexpStyleStringParse('[500-15000]') // '8375'
+ * faker.helpers.regexpStyleStringParse('#{3}test[1-5]') // '###test3'
+ */
+ regexpStyleStringParse(string: string = ''): string {
+ // Deal with range repeat `{min,max}`
+ const RANGE_REP_REG = /(.)\{(\d+)\,(\d+)\}/;
+ const REP_REG = /(.)\{(\d+)\}/;
+ const RANGE_REG = /\[(\d+)\-(\d+)\]/;
+ let min: number;
+ let max: number;
+ let tmp: number;
+ let repetitions: number;
+ let token = string.match(RANGE_REP_REG);
+ while (token != null) {
+ min = parseInt(token[2]);
+ max = parseInt(token[3]);
+ // switch min and max
+ if (min > max) {
+ tmp = max;
+ max = min;
+ min = tmp;
+ }
+ repetitions = this.faker.datatype.number({ min: min, max: max });
+ string =
+ string.slice(0, token.index) +
+ this.repeatString(token[1], repetitions) +
+ string.slice(token.index + token[0].length);
+ token = string.match(RANGE_REP_REG);
+ }
+ // Deal with repeat `{num}`
+ token = string.match(REP_REG);
+ while (token != null) {
+ repetitions = parseInt(token[2]);
+ string =
+ string.slice(0, token.index) +
+ this.repeatString(token[1], repetitions) +
+ string.slice(token.index + token[0].length);
+ token = string.match(REP_REG);
+ }
+ // Deal with range `[min-max]` (only works with numbers for now)
+ //TODO: implement for letters e.g. [0-9a-zA-Z] etc.
+
+ token = string.match(RANGE_REG);
+ while (token != null) {
+ min = parseInt(token[1]); // This time we are not capturing the char before `[]`
+ max = parseInt(token[2]);
+ // switch min and max
+ if (min > max) {
+ tmp = max;
+ max = min;
+ min = tmp;
+ }
+ string =
+ string.slice(0, token.index) +
+ this.faker.datatype.number({ min: min, max: max }).toString() +
+ string.slice(token.index + token[0].length);
+ token = string.match(RANGE_REG);
+ }
+ return string;
+ }
+
+ /**
+ * Takes an array and randomizes it in place then returns it.
+ *
+ * Uses the modern version of the Fisher–Yates algorithm.
+ *
+ * @template T The type of the entries to shuffle.
+ * @param o The array to shuffle. Defaults to `[]`.
+ *
+ * @example
+ * faker.helpers.shuffle() // []
+ * faker.helpers.shuffle(['a', 'b', 'c']) // [ 'b', 'c', 'a' ]
+ */
+ shuffle<T>(o?: T[]): T[] {
+ if (o == null || o.length === 0) {
+ return o || [];
+ }
+
+ for (let i = o.length - 1; i > 0; --i) {
+ const j = this.faker.datatype.number(i);
+ const x = o[i];
+ o[i] = o[j];
+ o[j] = x;
+ }
+ return o;
+ }
+
+ /**
+ * Takes an array of strings or function that returns a string
+ * and outputs a unique array of strings based on that source.
+ * This method does not store the unique state between invocations.
+ *
+ * @template T The type of the entries.
+ * @param source The strings to choose from or a function that generates a string.
+ * @param length The number of elements to generate.
+ *
+ * @example
+ * faker.helpers.uniqueArray(faker.random.word, 50)
+ * faker.helpers.uniqueArray(faker.definitions.name.first_name, 6)
+ * faker.helpers.uniqueArray(["Hello", "World", "Goodbye"], 2)
+ */
+ uniqueArray<T>(source: readonly T[] | (() => T), length: number): T[] {
+ if (Array.isArray(source)) {
+ const set = new Set<T>(source);
+ const array = Array.from(set);
+ return this.shuffle(array).splice(0, length);
+ }
+ const set = new Set<T>();
+ try {
+ if (typeof source === 'function') {
+ while (set.size < length) {
+ set.add(source());
+ }
+ }
+ } catch {
+ // Ignore
+ }
+ return Array.from(set);
+ }
+
+ /**
+ * Replaces the `{{placeholder}}` patterns in the given string mustache style.
+ *
+ * @param str The template string to parse.
+ * @param data The data used to populate the placeholders.
+ * This is a record where the key is the template placeholder,
+ * whereas the value is either a string or a function suitable for `String.replace()`.
+ *
+ * @example
+ * faker.helpers.mustache('I found {{count}} instances of "{{word}}".', {
+ * count: () => `${faker.datatype.number()}`,
+ * word: "this word",
+ * }) // 'I found 57591 instances of "this word".'
+ */
+ mustache(
+ str: string | undefined,
+ data: Record<string, string | Parameters<string['replace']>[1]>
+ ): string {
+ if (str == null) {
+ return '';
+ }
+ for (const p in data) {
+ const re = new RegExp(`{{${p}}}`, 'g');
+ const value = data[p];
+ if (typeof value === 'string') {
+ str = str.replace(re, value);
+ } else {
+ str = str.replace(re, value);
+ }
+ }
+ return str;
+ }
+
+ /**
+ * Generates a full card with various random details.
+ *
+ * @example
+ * faker.helpers.createCard()
+ * // {
+ * // name: 'Maxine Abbott',
+ * // username: 'Idell_Kautzer60',
+ * // email: '[email protected]',
+ * // address: {
+ * // streetA: 'Drake Avenue',
+ * // ...
+ * @deprecated If you need some specific object you should create your own method.
+ */
+ createCard(): Card {
+ deprecated({
+ deprecated: 'helpers.createCard()',
+ proposed: 'a self-build function',
+ since: 'v6.1.0',
+ until: 'v7.0.0',
+ });
+ return {
+ name: this.faker.name.findName(),
+ username: this.faker.internet.userName(),
+ email: this.faker.internet.email(),
+ address: {
+ streetA: this.faker.address.streetName(),
+ streetB: this.faker.address.streetAddress(),
+ streetC: this.faker.address.streetAddress(true),
+ streetD: this.faker.address.secondaryAddress(),
+ city: this.faker.address.city(),
+ state: this.faker.address.state(),
+ country: this.faker.address.country(),
+ zipcode: this.faker.address.zipCode(),
+ geo: {
+ lat: this.faker.address.latitude(),
+ lng: this.faker.address.longitude(),
+ },
+ },
+ phone: this.faker.phone.phoneNumber(),
+ website: this.faker.internet.domainName(),
+ company: {
+ name: this.faker.company.companyName(),
+ catchPhrase: this.faker.company.catchPhrase(),
+ bs: this.faker.company.bs(),
+ },
+ posts: [
+ {
+ words: this.faker.lorem.words(),
+ sentence: this.faker.lorem.sentence(),
+ sentences: this.faker.lorem.sentences(),
+ paragraph: this.faker.lorem.paragraph(),
+ },
+ {
+ words: this.faker.lorem.words(),
+ sentence: this.faker.lorem.sentence(),
+ sentences: this.faker.lorem.sentences(),
+ paragraph: this.faker.lorem.paragraph(),
+ },
+ {
+ words: this.faker.lorem.words(),
+ sentence: this.faker.lorem.sentence(),
+ sentences: this.faker.lorem.sentences(),
+ paragraph: this.faker.lorem.paragraph(),
+ },
+ ],
+ accountHistory: [
+ this.createTransaction(),
+ this.createTransaction(),
+ this.createTransaction(),
+ ],
+ };
+ }
+
+ /**
+ * Generates a persons card with various details attempting to use a consistent context.
+ *
+ * @example
+ * faker.helpers.contextualCard()
+ * // {
+ * // name: 'Eveline',
+ * // username: 'Eveline.Brekke56',
+ * // avatar: 'https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/122.jpg',
+ * // email: '[email protected]',
+ * // dob: 1964-05-06T05:14:37.874Z,
+ * // ...
+ * @deprecated If you need some specific object you should create your own method.
+ */
+ contextualCard(): ContextualCard {
+ deprecated({
+ deprecated: 'helpers.contextualCard()',
+ proposed: 'a self-build function',
+ since: 'v6.1.0',
+ until: 'v7.0.0',
+ });
+ const name = this.faker.name.firstName();
+ const userName = this.faker.internet.userName(name);
+ return {
+ name: name,
+ username: userName,
+ avatar: this.faker.internet.avatar(),
+ email: this.faker.internet.email(userName),
+ dob: this.faker.date.past(
+ 50,
+ new Date('Sat Sep 20 1992 21:35:02 GMT+0200 (CEST)')
+ ),
+ phone: this.faker.phone.phoneNumber(),
+ address: {
+ street: this.faker.address.streetName(),
+ suite: this.faker.address.secondaryAddress(),
+ city: this.faker.address.city(),
+ zipcode: this.faker.address.zipCode(),
+ geo: {
+ lat: this.faker.address.latitude(),
+ lng: this.faker.address.longitude(),
+ },
+ },
+ website: this.faker.internet.domainName(),
+ company: {
+ name: this.faker.company.companyName(),
+ catchPhrase: this.faker.company.catchPhrase(),
+ bs: this.faker.company.bs(),
+ },
+ };
+ }
+
+ /**
+ * Generates a user card with various details.
+ *
+ * @example
+ * faker.helpers.userCard()
+ * // {
+ * // name: 'Jodi Ferry',
+ * // username: 'Maybell.Kris',
+ * // email: '[email protected]',
+ * // address: {
+ * // street: 'McKenzie Estates',
+ * // ....
+ * @deprecated If you need some specific object you should create your own method.
+ */
+ userCard(): UserCard {
+ deprecated({
+ deprecated: 'helpers.userCard()',
+ proposed: 'a self-build function',
+ since: 'v6.1.0',
+ until: 'v7.0.0',
+ });
+ return {
+ name: this.faker.name.findName(),
+ username: this.faker.internet.userName(),
+ email: this.faker.internet.email(),
+ address: {
+ street: this.faker.address.streetName(),
+ suite: this.faker.address.secondaryAddress(),
+ city: this.faker.address.city(),
+ zipcode: this.faker.address.zipCode(),
+ geo: {
+ lat: this.faker.address.latitude(),
+ lng: this.faker.address.longitude(),
+ },
+ },
+ phone: this.faker.phone.phoneNumber(),
+ website: this.faker.internet.domainName(),
+ company: {
+ name: this.faker.company.companyName(),
+ catchPhrase: this.faker.company.catchPhrase(),
+ bs: this.faker.company.bs(),
+ },
+ };
+ }
+
+ /**
+ * Generates an example transaction.
+ *
+ * @example
+ * faker.helpers.createTransaction()
+ * // {
+ * // amount: '551.32',
+ * // date: 2012-02-01T23:00:00.000Z,
+ * // business: 'Will, Fisher and Marks',
+ * // name: 'Investment Account (...8755)',
+ * // type: 'invoice',
+ * // account: '41796240'
+ * // }
+ */
+ createTransaction(): Transaction {
+ return {
+ amount: this.faker.finance.amount(),
+ date: new Date(2012, 1, 2), // TODO: add a ranged date method
+ business: this.faker.company.companyName(),
+ name: [this.faker.finance.accountName(), this.faker.finance.mask()].join(
+ ' '
+ ),
+ type: this.arrayElement(this.faker.definitions.finance.transaction_type),
+ account: this.faker.finance.account(),
+ };
+ }
+
+ /**
+ * Returns the result of the callback if the probability check was successful, otherwise `undefined`.
+ *
+ * @template T The type of result of the given callback.
+ * @param callback The callback to that will be invoked if the probability check was successful.
+ * @param options The options to use. Defaults to `{}`.
+ * @param options.probability The probability (`[0.00, 1.00]`) of the callback being invoked. Defaults to `0.5`.
+ *
+ * @example
+ * faker.helpers.maybe(() => 'Hello World!') // 'Hello World!'
+ * faker.helpers.maybe(() => 'Hello World!', { probability: 0.1 }) // undefined
+ * faker.helpers.maybe(() => 'Hello World!', { probability: 0.9 }) // 'Hello World!'
+ */
+ maybe<T>(
+ callback: () => T,
+ options: { probability?: number } = {}
+ ): T | undefined {
+ const { probability = 0.5 } = options;
+ if (this.faker.datatype.float({ min: 0, max: 1 }) < probability) {
+ return callback();
+ }
+ return undefined;
+ }
+
+ /**
+ * Returns a random key from given object or `undefined` if no key could be found.
+ *
+ * @param object The object to be used.
+ *
+ * @example
+ * faker.helpers.objectKey({ myProperty: 'myValue' }) // 'myProperty'
+ */
+ objectKey<T extends Record<string, unknown>>(object: T): keyof T {
+ const array: Array<keyof T> = Object.keys(object);
+ return this.arrayElement(array);
+ }
+
+ /**
+ * Returns a random value from given object or `undefined` if no key could be found.
+ *
+ * @param object The object to be used.
+ *
+ * @example
+ * faker.helpers.objectValue({ myProperty: 'myValue' }) // 'myValue'
+ */
+ objectValue<T extends Record<string, unknown>>(object: T): T[keyof T] {
+ const key = this.faker.helpers.objectKey(object);
+ return object[key];
+ }
+
+ /**
+ * Returns random element from the given array.
+ *
+ * @template T The type of the entries to pick from.
+ * @param array Array to pick the value from.
+ *
+ * @example
+ * faker.helpers.arrayElement(['cat', 'dog', 'mouse']) // 'dog'
+ */
+ arrayElement<T = string>(
+ // TODO @Shinigami92 2022-04-30: We want to remove this default value, but currently it's not possible because some definitions could be empty
+ // See https://github.com/faker-js/faker/issues/893
+ array: ReadonlyArray<T> = ['a', 'b', 'c'] as unknown as ReadonlyArray<T>
+ ): T {
+ const index =
+ array.length > 1
+ ? this.faker.datatype.number({ max: array.length - 1 })
+ : 0;
+
+ return array[index];
+ }
+
+ /**
+ * Returns a subset with random elements of the given array in random order.
+ *
+ * @template T The type of the entries to pick from.
+ * @param array Array to pick the value from.
+ * @param count Number of elements to pick.
+ * When not provided, random number of elements will be picked.
+ * When value exceeds array boundaries, it will be limited to stay inside.
+ *
+ * @example
+ * faker.helpers.arrayElements(['cat', 'dog', 'mouse']) // ['mouse', 'cat']
+ * faker.helpers.arrayElements([1, 2, 3, 4, 5], 2) // [4, 2]
+ */
+ arrayElements<T>(
+ // TODO @Shinigami92 2022-04-30: We want to remove this default value, but currently it's not possible because some definitions could be empty
+ // See https://github.com/faker-js/faker/issues/893
+ array: ReadonlyArray<T> = ['a', 'b', 'c'] as unknown as ReadonlyArray<T>,
+ count?: number
+ ): T[] {
+ if (typeof count !== 'number') {
+ count = this.faker.datatype.number({ min: 1, max: array.length });
+ } else if (count > array.length) {
+ count = array.length;
+ } else if (count < 0) {
+ count = 0;
+ }
+
+ const arrayCopy = array.slice(0);
+ let i = array.length;
+ const min = i - count;
+ let temp: T;
+ let index: number;
+
+ while (i-- > min) {
+ index = Math.floor(
+ (i + 1) * this.faker.datatype.float({ min: 0, max: 0.99 })
+ );
+ temp = arrayCopy[index];
+ arrayCopy[index] = arrayCopy[i];
+ arrayCopy[i] = temp;
+ }
+
+ return arrayCopy.slice(min);
+ }
+}
diff --git a/src/modules/image/index.ts b/src/modules/image/index.ts
new file mode 100644
index 00000000..9e8e1879
--- /dev/null
+++ b/src/modules/image/index.ts
@@ -0,0 +1,345 @@
+import type { Faker } from '../..';
+import type { MethodsOf } from '../../utils/types';
+import { LoremPicsum } from './providers/lorempicsum';
+import { Lorempixel } from './providers/lorempixel';
+import { Unsplash } from './providers/unsplash';
+
+/**
+ * Module to generate placeholder images.
+ *
+ * Default provider is unsplash image provider.
+ */
+export class Image {
+ readonly lorempixel: Lorempixel;
+ readonly unsplash: Unsplash;
+ readonly lorempicsum: LoremPicsum;
+
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Image.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+
+ this.lorempixel = new Lorempixel(this.faker);
+ this.unsplash = new Unsplash(this.faker);
+ this.lorempicsum = new LoremPicsum(this.faker);
+ }
+
+ /**
+ * Generates a random image url from one of the supported categories.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to randomize the image or not. Defaults to `false`.
+ *
+ * @example
+ * faker.image.image() // 'http://loremflickr.com/640/480/city'
+ * faker.image.image(1234, 2345) // 'http://loremflickr.com/1234/2345/sports'
+ * faker.image.image(1234, 2345, true) // 'http://loremflickr.com/1234/2345/nature?56789'
+ */
+ image(width?: number, height?: number, randomize?: boolean): string {
+ const categories: MethodsOf<Image, Image['image']> = [
+ 'abstract',
+ 'animals',
+ 'business',
+ 'cats',
+ 'city',
+ 'food',
+ 'nightlife',
+ 'fashion',
+ 'people',
+ 'nature',
+ 'sports',
+ 'technics',
+ 'transport',
+ ];
+ return this[this.faker.helpers.arrayElement(categories)](
+ width,
+ height,
+ randomize
+ );
+ }
+
+ /**
+ * Generates a random avatar image url.
+ *
+ * @example
+ * faker.image.avatar()
+ * // 'https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/170.jpg'
+ */
+ avatar(): string {
+ return this.faker.internet.avatar();
+ }
+
+ /**
+ * Generates a random image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param category The category of the image. By default, a random one will be selected.
+ * @param randomize Whether to randomize the image or not. Defaults to `false`.
+ * @param https When true, return a `https` url. Otherwise, return a `http` url.
+ *
+ * @example
+ * faker.image.imageUrl() // 'http://loremflickr.com/640/480'
+ * faker.image.imageUrl(1234, 2345) // 'http://loremflickr.com/1234/2345'
+ * faker.image.imageUrl(1234, 2345, 'cat') // 'http://loremflickr.com/1234/2345/cat'
+ * faker.image.imageUrl(1234, 2345, 'cat', true) // 'http://loremflickr.com/1234/2345/cat?6849'
+ * faker.image.imageUrl(1234, 2345, 'cat', true, true) // 'https://loremflickr.com/1234/2345/cat?56789'
+ */
+ imageUrl(
+ width?: number,
+ height?: number,
+ category?: string,
+ randomize?: boolean,
+ https?: boolean
+ ): string {
+ width = width || 640;
+ height = height || 480;
+ let protocol = 'http://';
+ if (https === true) {
+ protocol = 'https://';
+ }
+ let url = `${protocol}loremflickr.com/${width}/${height}`;
+ if (category != null) {
+ url += `/${category}`;
+ }
+
+ if (randomize) {
+ url += `?${this.faker.datatype.number()}`;
+ }
+
+ return url;
+ }
+
+ /**
+ * Generates a random abstract image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to randomize the image or not. Defaults to `false`.
+ *
+ * @example
+ * faker.image.abstract() // 'http://loremflickr.com/640/480/abstract'
+ * faker.image.abstract(1234, 2345) // 'http://loremflickr.com/1234/2345/abstract'
+ * faker.image.abstract(1234, 2345, true) // 'http://loremflickr.com/1234/2345/abstract?56789'
+ */
+ abstract(width?: number, height?: number, randomize?: boolean): string {
+ return this.imageUrl(width, height, 'abstract', randomize);
+ }
+
+ /**
+ * Generates a random animal image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to randomize the image or not. Defaults to `false`.
+ *
+ * @example
+ * faker.image.animals() // 'http://loremflickr.com/640/480/animals'
+ * faker.image.animals(1234, 2345) // 'http://loremflickr.com/1234/2345/animals'
+ * faker.image.animals(1234, 2345, true) // 'http://loremflickr.com/1234/2345/animals?56789'
+ */
+ animals(width?: number, height?: number, randomize?: boolean): string {
+ return this.imageUrl(width, height, 'animals', randomize);
+ }
+
+ /**
+ * Generates a random business image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to randomize the image or not. Defaults to `false`.
+ *
+ * @example
+ * faker.image.business() // 'http://loremflickr.com/640/480/business'
+ * faker.image.business(1234, 2345) // 'http://loremflickr.com/1234/2345/business'
+ * faker.image.business(1234, 2345, true) // 'http://loremflickr.com/1234/2345/business?56789'
+ */
+ business(width?: number, height?: number, randomize?: boolean): string {
+ return this.imageUrl(width, height, 'business', randomize);
+ }
+
+ /**
+ * Generates a random cat image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to randomize the image or not. Defaults to `false`.
+ *
+ * @example
+ * faker.image.cats() // 'http://loremflickr.com/640/480/cats'
+ * faker.image.cats(1234, 2345) // 'http://loremflickr.com/1234/2345/cats'
+ * faker.image.cats(1234, 2345, true) // 'http://loremflickr.com/1234/2345/cats?56789'
+ */
+ cats(width?: number, height?: number, randomize?: boolean): string {
+ return this.imageUrl(width, height, 'cats', randomize);
+ }
+
+ /**
+ * Generates a random city image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to randomize the image or not. Defaults to `false`.
+ *
+ * @example
+ * faker.image.city() // 'http://loremflickr.com/640/480/city'
+ * faker.image.city(1234, 2345) // 'http://loremflickr.com/1234/2345/city'
+ * faker.image.city(1234, 2345, true) // 'http://loremflickr.com/1234/2345/city?56789'
+ */
+ city(width?: number, height?: number, randomize?: boolean): string {
+ return this.imageUrl(width, height, 'city', randomize);
+ }
+
+ /**
+ * Generates a random food image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to randomize the image or not. Defaults to `false`.
+ *
+ * @example
+ * faker.image.food() // 'http://loremflickr.com/640/480/food'
+ * faker.image.food(1234, 2345) // 'http://loremflickr.com/1234/2345/food'
+ * faker.image.food(1234, 2345, true) // 'http://loremflickr.com/1234/2345/food?56789'
+ */
+ food(width?: number, height?: number, randomize?: boolean): string {
+ return this.imageUrl(width, height, 'food', randomize);
+ }
+
+ /**
+ * Generates a random nightlife image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to randomize the image or not. Defaults to `false`.
+ *
+ * @example
+ * faker.image.nightlife() // 'http://loremflickr.com/640/480/nightlife'
+ * faker.image.nightlife(1234, 2345) // 'http://loremflickr.com/1234/2345/nightlife'
+ * faker.image.nightlife(1234, 2345, true) // 'http://loremflickr.com/1234/2345/nightlife?56789'
+ */
+ nightlife(width?: number, height?: number, randomize?: boolean): string {
+ return this.imageUrl(width, height, 'nightlife', randomize);
+ }
+
+ /**
+ * Generates a random fashion image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to randomize the image or not. Defaults to `false`.
+ *
+ * @example
+ * faker.image.fashion() // 'http://loremflickr.com/640/480/fashion'
+ * faker.image.fashion(1234, 2345) // 'http://loremflickr.com/1234/2345/fashion'
+ * faker.image.fashion(1234, 2345, true) // 'http://loremflickr.com/1234/2345/fashion?56789'
+ */
+ fashion(width?: number, height?: number, randomize?: boolean): string {
+ return this.imageUrl(width, height, 'fashion', randomize);
+ }
+
+ /**
+ * Generates a random people image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to randomize the image or not. Defaults to `false`.
+ *
+ * @example
+ * faker.image.people() // 'http://loremflickr.com/640/480/people'
+ * faker.image.people(1234, 2345) // 'http://loremflickr.com/1234/2345/people'
+ * faker.image.people(1234, 2345, true) // 'http://loremflickr.com/1234/2345/people?56789'
+ */
+ people(width?: number, height?: number, randomize?: boolean): string {
+ return this.imageUrl(width, height, 'people', randomize);
+ }
+
+ /**
+ * Generates a random nature image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to randomize the image or not. Defaults to `false`.
+ *
+ * @example
+ * faker.image.nature() // 'http://loremflickr.com/640/480/nature'
+ * faker.image.nature(1234, 2345) // 'http://loremflickr.com/1234/2345/nature'
+ * faker.image.nature(1234, 2345, true) // 'http://loremflickr.com/1234/2345/nature?56789'
+ */
+ nature(width?: number, height?: number, randomize?: boolean): string {
+ return this.imageUrl(width, height, 'nature', randomize);
+ }
+
+ /**
+ * Generates a random sports image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to randomize the image or not. Defaults to `false`.
+ *
+ * @example
+ * faker.image.sports() // 'http://loremflickr.com/640/480/sports'
+ * faker.image.sports(1234, 2345) // 'http://loremflickr.com/1234/2345/sports'
+ * faker.image.sports(1234, 2345, true) // 'http://loremflickr.com/1234/2345/sports?56789'
+ */
+ sports(width?: number, height?: number, randomize?: boolean): string {
+ return this.imageUrl(width, height, 'sports', randomize);
+ }
+
+ /**
+ * Generates a random technics image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to randomize the image or not. Defaults to `false`.
+ *
+ * @example
+ * faker.image.technics() // 'http://loremflickr.com/640/480/technics'
+ * faker.image.technics(1234, 2345) // 'http://loremflickr.com/1234/2345/technics'
+ * faker.image.technics(1234, 2345, true) // 'http://loremflickr.com/1234/2345/technics?56789'
+ */
+ technics(width?: number, height?: number, randomize?: boolean): string {
+ return this.imageUrl(width, height, 'technics', randomize);
+ }
+
+ /**
+ * Generates a random transport image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to randomize the image or not. Defaults to `false`.
+ *
+ * @example
+ * faker.image.transport() // 'http://loremflickr.com/640/480/transport'
+ * faker.image.transport(1234, 2345) // 'http://loremflickr.com/1234/2345/transport'
+ * faker.image.transport(1234, 2345, true) // 'http://loremflickr.com/1234/2345/transport?56789'
+ */
+ transport(width?: number, height?: number, randomize?: boolean): string {
+ return this.imageUrl(width, height, 'transport', randomize);
+ }
+
+ /**
+ * Generates a random data uri containing an svg image.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param color The color to use. Defaults to `grey`.
+ *
+ * @example
+ * faker.image.dataUri() // 'data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http...'
+ */
+ dataUri(width?: number, height?: number, color: string = 'grey'): string {
+ const svgString = `<svg xmlns="http://www.w3.org/2000/svg" version="1.1" baseProfile="full" width="${width}" height="${height}"><rect width="100%" height="100%" fill="${color}"/><text x="${
+ width / 2
+ }" y="${
+ height / 2
+ }" font-size="20" alignment-baseline="middle" text-anchor="middle" fill="white">${width}x${height}</text></svg>`;
+ const rawPrefix = 'data:image/svg+xml;charset=UTF-8,';
+ return rawPrefix + encodeURIComponent(svgString);
+ }
+}
diff --git a/src/modules/image/providers/lorempicsum.ts b/src/modules/image/providers/lorempicsum.ts
new file mode 100644
index 00000000..25869205
--- /dev/null
+++ b/src/modules/image/providers/lorempicsum.ts
@@ -0,0 +1,126 @@
+import type { Faker } from '../../..';
+
+/**
+ * Module to generate links to random images on `https://picsum.photos/`.
+ */
+// TODO ST-DDT 2022-03-11: Rename to picsum?
+export class LoremPicsum {
+ constructor(private readonly faker: Faker) {}
+
+ /**
+ * Generates a new picsum image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param grayscale Whether to return a grayscale image. Default to `false`.
+ * @param blur The optional level of blur to apply. Supports `1` - `10`.
+ */
+ image(
+ width?: number,
+ height?: number,
+ grayscale?: boolean,
+ blur?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
+ ): string {
+ return this.imageUrl(width, height, grayscale, blur);
+ }
+
+ /**
+ * Generates a new picsum image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param grayscale Whether to return a grayscale image. Default to `false`.
+ */
+ imageGrayscale(width?: number, height?: number, grayscale?: boolean): string {
+ return this.imageUrl(width, height, grayscale);
+ }
+
+ /**
+ * Generates a new picsum image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param blur The optional level of blur to apply. Supports `1` - `10`.
+ */
+ imageBlurred(
+ width?: number,
+ height?: number,
+ blur?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
+ ): string {
+ return this.imageUrl(width, height, undefined, blur);
+ }
+
+ /**
+ * Generates a new picsum image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param grayscale Whether to return a grayscale image. Default to `false`.
+ * @param blur The optional level of blur to apply. Supports `1` - `10`.
+ * @param seed The optional seed to use.
+ */
+ imageRandomSeeded(
+ width?: number,
+ height?: number,
+ grayscale?: boolean,
+ blur?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10,
+ seed?: string
+ ): string {
+ // TODO ST-DDT 2022-03-11: This method does the same as image url, maybe generate a seed, if it is missig?
+ return this.imageUrl(width, height, grayscale, blur, seed);
+ }
+
+ /**
+ * Returns a random avatar url.
+ *
+ * @example
+ * faker.internet.avatar()
+ * // 'https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/315.jpg'
+ */
+ // TODO ST-DDT 2022-03-11: Deprecate this method as it is duplicate and has nothing to do with lorempicsum.
+ avatar(): string {
+ return this.faker.internet.avatar();
+ }
+
+ /**
+ * Generates a new picsum image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param grayscale Whether to return a grayscale image. Default to `false`.
+ * @param blur The optional level of blur to apply. Supports `1` - `10`.
+ * @param seed The optional seed to use.
+ */
+ imageUrl(
+ width?: number,
+ height?: number,
+ grayscale?: boolean,
+ blur?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10,
+ seed?: string
+ ): string {
+ width = width || 640;
+ height = height || 480;
+
+ let url = 'https://picsum.photos';
+
+ if (seed) {
+ url += `/seed/${seed}`;
+ }
+
+ url += `/${width}/${height}`;
+
+ if (grayscale && blur) {
+ return `${url}?grayscale&blur=${blur}`;
+ }
+
+ if (grayscale) {
+ return `${url}?grayscale`;
+ }
+
+ if (blur) {
+ return `${url}?blur=${blur}`;
+ }
+
+ return url;
+ }
+}
diff --git a/src/modules/image/providers/lorempixel.ts b/src/modules/image/providers/lorempixel.ts
new file mode 100644
index 00000000..f1ab384b
--- /dev/null
+++ b/src/modules/image/providers/lorempixel.ts
@@ -0,0 +1,288 @@
+import type { Faker } from '../../..';
+import type { MethodsOf } from '../../../utils/types';
+
+/**
+ * Module to generate links to random images on `https://lorempixel.com/`.
+ */
+export class Lorempixel {
+ constructor(private readonly faker: Faker) {}
+
+ /**
+ * Generates a new lorempixel image url for a random supported category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to append a seed to the url. Defaults to `false`.
+ */
+ image(width?: number, height?: number, randomize?: boolean): string {
+ const categories: MethodsOf<Lorempixel, Lorempixel['image']> = [
+ 'abstract',
+ 'animals',
+ 'business',
+ 'cats',
+ 'city',
+ 'food',
+ 'nightlife',
+ 'fashion',
+ 'people',
+ 'nature',
+ 'sports',
+ 'technics',
+ 'transport',
+ ];
+ return this[this.faker.helpers.arrayElement(categories)](
+ width,
+ height,
+ randomize
+ );
+ }
+
+ /**
+ * Returns a random avatar url.
+ *
+ * @example
+ * faker.internet.avatar()
+ * // 'https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/315.jpg'
+ */
+ // TODO ST-DDT 2022-03-11: Deprecate this method as it is duplicate and has nothing to do with lorempixel.
+ avatar(): string {
+ return this.faker.internet.avatar();
+ }
+
+ /**
+ * Generates a new lorempixel image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param category The category of the image to generate.
+ * @param randomize Whether to append a seed to the url. Defaults to `false`.
+ */
+ imageUrl(
+ width?: number,
+ height?: number,
+ category?: string,
+ randomize?: boolean
+ ): string {
+ width = width || 640;
+ height = height || 480;
+
+ let url = `https://lorempixel.com/${width}/${height}`;
+ if (category != null) {
+ url += `/${category}`;
+ }
+
+ if (randomize) {
+ url += `?${this.faker.datatype.number()}`;
+ }
+
+ return url;
+ }
+
+ /**
+ * Generates a new lorempixel image url using the "abstract" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to append a seed to the url. Defaults to `false`.
+ */
+ abstract(width?: number, height?: number, randomize?: boolean): string {
+ return this.faker.image.lorempixel.imageUrl(
+ width,
+ height,
+ 'abstract',
+ randomize
+ );
+ }
+
+ /**
+ * Generates a new lorempixel image url using the "animals" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to append a seed to the url. Defaults to `false`.
+ */
+ animals(width?: number, height?: number, randomize?: boolean): string {
+ return this.faker.image.lorempixel.imageUrl(
+ width,
+ height,
+ 'animals',
+ randomize
+ );
+ }
+
+ /**
+ * Generates a new lorempixel image url using the "business" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to append a seed to the url. Defaults to `false`.
+ */
+ business(width?: number, height?: number, randomize?: boolean): string {
+ return this.faker.image.lorempixel.imageUrl(
+ width,
+ height,
+ 'business',
+ randomize
+ );
+ }
+
+ /**
+ * Generates a new lorempixel image url using the "cats" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to append a seed to the url. Defaults to `false`.
+ */
+ cats(width?: number, height?: number, randomize?: boolean): string {
+ return this.faker.image.lorempixel.imageUrl(
+ width,
+ height,
+ 'cats',
+ randomize
+ );
+ }
+
+ /**
+ * Generates a new lorempixel image url using the "city" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to append a seed to the url. Defaults to `false`.
+ */
+ city(width?: number, height?: number, randomize?: boolean): string {
+ return this.faker.image.lorempixel.imageUrl(
+ width,
+ height,
+ 'city',
+ randomize
+ );
+ }
+
+ /**
+ * Generates a new lorempixel image url using the "food" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to append a seed to the url. Defaults to `false`.
+ */
+ food(width?: number, height?: number, randomize?: boolean): string {
+ return this.faker.image.lorempixel.imageUrl(
+ width,
+ height,
+ 'food',
+ randomize
+ );
+ }
+
+ /**
+ * Generates a new lorempixel image url using the "nightlife" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to append a seed to the url. Defaults to `false`.
+ */
+ nightlife(width?: number, height?: number, randomize?: boolean): string {
+ return this.faker.image.lorempixel.imageUrl(
+ width,
+ height,
+ 'nightlife',
+ randomize
+ );
+ }
+
+ /**
+ * Generates a new lorempixel image url using the "fashion" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to append a seed to the url. Defaults to `false`.
+ */
+ fashion(width?: number, height?: number, randomize?: boolean): string {
+ return this.faker.image.lorempixel.imageUrl(
+ width,
+ height,
+ 'fashion',
+ randomize
+ );
+ }
+
+ /**
+ * Generates a new lorempixel image url using the "people" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to append a seed to the url. Defaults to `false`.
+ */
+ people(width?: number, height?: number, randomize?: boolean): string {
+ return this.faker.image.lorempixel.imageUrl(
+ width,
+ height,
+ 'people',
+ randomize
+ );
+ }
+
+ /**
+ * Generates a new lorempixel image url using the "nature" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to append a seed to the url. Defaults to `false`.
+ */
+ nature(width?: number, height?: number, randomize?: boolean): string {
+ return this.faker.image.lorempixel.imageUrl(
+ width,
+ height,
+ 'nature',
+ randomize
+ );
+ }
+
+ /**
+ * Generates a new lorempixel image url using the "sports" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to append a seed to the url. Defaults to `false`.
+ */
+ sports(width?: number, height?: number, randomize?: boolean): string {
+ return this.faker.image.lorempixel.imageUrl(
+ width,
+ height,
+ 'sports',
+ randomize
+ );
+ }
+
+ /**
+ * Generates a new lorempixel image url using the "technics" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to append a seed to the url. Defaults to `false`.
+ */
+ technics(width?: number, height?: number, randomize?: boolean): string {
+ return this.faker.image.lorempixel.imageUrl(
+ width,
+ height,
+ 'technics',
+ randomize
+ );
+ }
+
+ /**
+ * Generates a new lorempixel image url using the "transport" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param randomize Whether to append a seed to the url. Defaults to `false`.
+ */
+ transport(width?: number, height?: number, randomize?: boolean): string {
+ return this.faker.image.lorempixel.imageUrl(
+ width,
+ height,
+ 'transport',
+ randomize
+ );
+ }
+}
diff --git a/src/modules/image/providers/unsplash.ts b/src/modules/image/providers/unsplash.ts
new file mode 100644
index 00000000..45bd815c
--- /dev/null
+++ b/src/modules/image/providers/unsplash.ts
@@ -0,0 +1,157 @@
+import type { Faker } from '../../..';
+
+/**
+ * Module to generate links to random images on `https://source.unsplash.com/`.
+ */
+export class Unsplash {
+ // TODO ST-DDT 2022-03-11: Remove unused(?) constant
+ categories = [
+ 'food',
+ 'nature',
+ 'people',
+ 'technology',
+ 'objects',
+ 'buildings',
+ ];
+
+ constructor(private readonly faker: Faker) {}
+
+ /**
+ * Generates a new unsplash image url for a random supported category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param keyword The image keywords to use.
+ */
+ image(width?: number, height?: number, keyword?: string): string {
+ return this.imageUrl(width, height, undefined, keyword);
+ }
+
+ /**
+ * Returns a random avatar url.
+ *
+ * @example
+ * faker.internet.avatar()
+ * // 'https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/315.jpg'
+ */
+ // TODO ST-DDT 2022-03-11: Deprecate this method as it is duplicate and has nothing to do with unsplash.
+ avatar(): string {
+ return this.faker.internet.avatar();
+ }
+
+ /**
+ * Generates a new unsplash image url.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param category The category of the image to generate.
+ * @param keyword The image keywords to use.
+ */
+ imageUrl(
+ width?: number,
+ height?: number,
+ category?: string,
+ keyword?: string
+ ): string {
+ width = width || 640;
+ height = height || 480;
+
+ let url = 'https://source.unsplash.com';
+
+ if (category != null) {
+ url += `/category/${category}`;
+ }
+
+ url += `/${width}x${height}`;
+
+ if (keyword != null) {
+ const keywordFormat = /^([A-Za-z0-9].+,[A-Za-z0-9]+)$|^([A-Za-z0-9]+)$/;
+ if (keywordFormat.test(keyword)) {
+ url += `?${keyword}`;
+ }
+ }
+
+ return url;
+ }
+
+ /**
+ * Generates a new unsplash image url using the "food" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param keyword The image keywords to use.
+ */
+ food(width?: number, height?: number, keyword?: string): string {
+ return this.faker.image.unsplash.imageUrl(width, height, 'food', keyword);
+ }
+
+ /**
+ * Generates a new unsplash image url using the "people" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param keyword The image keywords to use.
+ */
+ people(width?: number, height?: number, keyword?: string): string {
+ return this.faker.image.unsplash.imageUrl(width, height, 'people', keyword);
+ }
+
+ /**
+ * Generates a new unsplash image url using the "nature" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param keyword The image keywords to use.
+ */
+ nature(width?: number, height?: number, keyword?: string): string {
+ return this.faker.image.unsplash.imageUrl(width, height, 'nature', keyword);
+ }
+
+ /**
+ * Generates a new unsplash image url using the "technology" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param keyword The image keywords to use.
+ */
+ technology(width?: number, height?: number, keyword?: string): string {
+ return this.faker.image.unsplash.imageUrl(
+ width,
+ height,
+ 'technology',
+ keyword
+ );
+ }
+
+ /**
+ * Generates a new unsplash image url using the "objects" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param keyword The image keywords to use.
+ */
+ objects(width?: number, height?: number, keyword?: string): string {
+ return this.faker.image.unsplash.imageUrl(
+ width,
+ height,
+ 'objects',
+ keyword
+ );
+ }
+
+ /**
+ * Generates a new unsplash image url using the "buildings" category.
+ *
+ * @param width The width of the image. Defaults to `640`.
+ * @param height The height of the image. Defaults to `480`.
+ * @param keyword The image keywords to use.
+ */
+ buildings(width?: number, height?: number, keyword?: string): string {
+ return this.faker.image.unsplash.imageUrl(
+ width,
+ height,
+ 'buildings',
+ keyword
+ );
+ }
+}
diff --git a/src/modules/internet/index.ts b/src/modules/internet/index.ts
new file mode 100644
index 00000000..bcc5daf3
--- /dev/null
+++ b/src/modules/internet/index.ts
@@ -0,0 +1,458 @@
+import type { Faker } from '../..';
+import * as random_ua from './user-agent';
+
+export type EmojiType =
+ | 'smiley'
+ | 'body'
+ | 'person'
+ | 'nature'
+ | 'food'
+ | 'travel'
+ | 'activity'
+ | 'object'
+ | 'symbol'
+ | 'flag';
+
+/**
+ * Module to generate internet related entries.
+ */
+export class Internet {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Internet.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Returns a random avatar url.
+ *
+ * @example
+ * faker.internet.avatar()
+ * // 'https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/315.jpg'
+ */
+ avatar(): string {
+ return `https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/${this.faker.datatype.number(
+ 1249
+ )}.jpg`;
+ }
+
+ /**
+ * Generates an email address using the given person's name as base.
+ *
+ * @param firstName The optional first name to use. If not specified, a random one will be chosen.
+ * @param lastName The optional last name to use. If not specified, a random one will be chosen.
+ * @param provider The mail provider domain to use. If not specified, a random free mail provider will be chosen.
+ * @param options The options to use. Defaults to `{ allowSpecialCharacters: false }`.
+ * @param options.allowSpecialCharacters Whether special characters such as ``.!#$%&'*+-/=?^_`{|}~`` should be included
+ * in the email address. Defaults to `false`.
+ *
+ * @example
+ * faker.internet.email() // '[email protected]'
+ * faker.internet.email('Jeanne', 'Doe') // '[email protected]'
+ * faker.internet.email('Jeanne', 'Doe', 'example.fakerjs.dev') // '[email protected]'
+ * faker.internet.email('Jeanne', 'Doe', 'example.fakerjs.dev', { allowSpecialCharacters: true }) // 'Jeanne%[email protected]'
+ */
+ email(
+ firstName?: string,
+ lastName?: string,
+ provider?: string,
+ options?: { allowSpecialCharacters?: boolean }
+ ): string {
+ provider =
+ provider ||
+ this.faker.helpers.arrayElement(
+ this.faker.definitions.internet.free_email
+ );
+
+ let localPart: string = this.faker.helpers.slugify(
+ this.userName(firstName, lastName)
+ );
+
+ if (options?.allowSpecialCharacters) {
+ const usernameChars: string[] = '._-'.split('');
+ const specialChars: string[] = ".!#$%&'*+-/=?^_`{|}~".split('');
+ localPart = localPart.replace(
+ this.faker.helpers.arrayElement(usernameChars),
+ this.faker.helpers.arrayElement(specialChars)
+ );
+ }
+
+ return `${localPart}@${provider}`;
+ }
+
+ /**
+ * Generates an email address using an example mail provider using the given person's name as base.
+ *
+ * @param firstName The optional first name to use. If not specified, a random one will be chosen.
+ * @param lastName The optional last name to use. If not specified, a random one will be chosen.
+ * @param options The options to use. Defaults to `{ allowSpecialCharacters: false }`.
+ * @param options.allowSpecialCharacters Whether special characters such as ``.!#$%&'*+-/=?^_`{|}~`` should be included
+ * in the email address. Defaults to `false`.
+ *
+ * @example
+ * faker.internet.exampleEmail() // '[email protected]'
+ * faker.internet.exampleEmail('Jeanne', 'Doe') // '[email protected]'
+ * faker.internet.exampleEmail('Jeanne', 'Doe', { allowSpecialCharacters: true }) // 'Jeanne%[email protected]'
+ */
+ exampleEmail(
+ firstName?: string,
+ lastName?: string,
+ options?: { allowSpecialCharacters?: boolean }
+ ): string {
+ const provider = this.faker.helpers.arrayElement(
+ this.faker.definitions.internet.example_email
+ );
+ return this.email(firstName, lastName, provider, options);
+ }
+
+ /**
+ * Generates a username using the given person's name as base.
+ *
+ * @param firstName The optional first name to use. If not specified, a random one will be chosen.
+ * @param lastName The optional last name to use. If not specified, a random one will be chosen.
+ *
+ * @example
+ * faker.internet.userName() // 'Nettie_Zboncak40'
+ * faker.internet.userName('Jeanne', 'Doe') // 'Jeanne98'
+ */
+ userName(firstName?: string, lastName?: string): string {
+ let result: string;
+ firstName = firstName || this.faker.name.firstName();
+ lastName = lastName || this.faker.name.lastName();
+ switch (this.faker.datatype.number(2)) {
+ case 0:
+ result = `${firstName}${this.faker.datatype.number(99)}`;
+ break;
+ case 1:
+ result =
+ firstName + this.faker.helpers.arrayElement(['.', '_']) + lastName;
+ break;
+ case 2:
+ result = `${firstName}${this.faker.helpers.arrayElement([
+ '.',
+ '_',
+ ])}${lastName}${this.faker.datatype.number(99)}`;
+ break;
+ }
+ result = result.toString().replace(/'/g, '');
+ result = result.replace(/ /g, '');
+ return result;
+ }
+
+ /**
+ * Returns a random web protocol. Either `http` or `https`.
+ *
+ * @example
+ * faker.internet.protocol() // 'http'
+ * faker.internet.protocol() // 'https'
+ */
+ protocol(): 'http' | 'https' {
+ const protocols: ['http', 'https'] = ['http', 'https'];
+ return this.faker.helpers.arrayElement(protocols);
+ }
+
+ /**
+ * Returns a random http method.
+ *
+ * Can be either of the following:
+ *
+ * - `GET`
+ * - `POST`
+ * - `PUT`
+ * - `DELETE`
+ * - `PATCH`
+ *
+ * @example
+ * faker.internet.httpMethod() // 'PATCH'
+ */
+ httpMethod(): 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' {
+ const httpMethods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'] = [
+ 'GET',
+ 'POST',
+ 'PUT',
+ 'DELETE',
+ 'PATCH',
+ ];
+ return this.faker.helpers.arrayElement(httpMethods);
+ }
+
+ /**
+ * Generates a random url.
+ *
+ * @example
+ * faker.internet.url() // 'https://remarkable-hackwork.info'
+ */
+ url(): string {
+ return `${this.protocol()}://${this.domainName()}`;
+ }
+
+ /**
+ * Generates a random domain name.
+ *
+ * @example
+ * faker.internet.domainName() // 'slow-timer.info'
+ */
+ domainName(): string {
+ return `${this.domainWord()}.${this.domainSuffix()}`;
+ }
+
+ /**
+ * Returns a random domain suffix.
+ *
+ * @example
+ * faker.internet.domainSuffix() // 'com'
+ * faker.internet.domainSuffix() // 'name'
+ */
+ domainSuffix(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.internet.domain_suffix
+ );
+ }
+
+ /**
+ * Generates a random domain word.
+ *
+ * @example
+ * faker.internet.domainWord() // 'close-reality'
+ * faker.internet.domainWord() // 'weird-cytoplasm'
+ */
+ domainWord(): string {
+ return `${this.faker.word.adjective()}-${this.faker.word.noun()}`
+ .replace(/([\\~#&*{}/:<>?|\"'])/gi, '')
+ .replace(/\s/g, '-')
+ .replace(/-{2,}/g, '-')
+ .toLowerCase();
+ }
+
+ /**
+ * Generates a random IPv4 address.
+ *
+ * @example
+ * faker.internet.ip() // '245.108.222.0'
+ */
+ ip(): string {
+ // TODO @Shinigami92 2022-03-21: We may want to return a IPv4 or IPv6 address here in a later major release
+ return this.ipv4();
+ }
+
+ /**
+ * Generates a random IPv4 address.
+ *
+ * @example
+ * faker.internet.ipv4() // '245.108.222.0'
+ */
+ ipv4(): string {
+ const randNum = () => {
+ return this.faker.datatype.number(255).toFixed(0);
+ };
+
+ const result: string[] = [];
+ for (let i = 0; i < 4; i++) {
+ result[i] = randNum();
+ }
+
+ return result.join('.');
+ }
+
+ /**
+ * Generates a random IPv6 address.
+ *
+ * @example
+ * faker.internet.ipv6() // '269f:1230:73e3:318d:842b:daab:326d:897b'
+ */
+ ipv6(): string {
+ const randHash = () => {
+ let result = '';
+ for (let i = 0; i < 4; i++) {
+ result += this.faker.helpers.arrayElement([
+ '0',
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ 'a',
+ 'b',
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ ]);
+ }
+ return result;
+ };
+
+ const result: string[] = [];
+ for (let i = 0; i < 8; i++) {
+ result[i] = randHash();
+ }
+ return result.join(':');
+ }
+
+ /**
+ * Generates a random port number.
+ *
+ * @example
+ * faker.internet.port() // '9414'
+ */
+ port(): number {
+ return this.faker.datatype.number({ min: 0, max: 65535 });
+ }
+
+ /**
+ * Generates a random user agent string.
+ *
+ * @example
+ * faker.internet.userAgent()
+ * // 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_8_8) AppleWebKit/536.0.2 (KHTML, like Gecko) Chrome/27.0.849.0 Safari/536.0.2'
+ */
+ userAgent(): string {
+ return random_ua.generate(this.faker);
+ }
+
+ /**
+ * Generates a random css hex color code in aesthetically pleasing color palette.
+ *
+ * Based on
+ * http://stackoverflow.com/questions/43044/algorithm-to-randomly-generate-an-aesthetically-pleasing-color-palette
+ *
+ * @param redBase The optional base red in range between `0` and `255`. Defaults to `0`.
+ * @param greenBase The optional base green in range between `0` and `255`. Defaults to `0`.
+ * @param blueBase The optional base blue in range between `0` and `255`. Defaults to `0`.
+ *
+ * @example
+ * faker.internet.color() // '#30686e'
+ * faker.internet.color(100, 100, 100) // '#4e5f8b'
+ */
+ color(
+ redBase: number = 0,
+ greenBase: number = 0,
+ blueBase: number = 0
+ ): string {
+ const colorFromBase = (base: number): string =>
+ Math.floor((this.faker.datatype.number(256) + base) / 2)
+ .toString(16)
+ .padStart(2, '0');
+
+ const red = colorFromBase(redBase);
+ const green = colorFromBase(greenBase);
+ const blue = colorFromBase(blueBase);
+
+ return `#${red}${green}${blue}`;
+ }
+
+ /**
+ * Generates a random mac address.
+ *
+ * @param sep The optional separator to use. Can be either `':'`, `'-'` or `''`. Defaults to `':'`.
+ *
+ * @example
+ * faker.internet.mac() // '32:8e:2e:09:c6:05'
+ */
+ mac(sep?: string): string {
+ let i: number;
+ let mac = '';
+ let validSep = ':';
+
+ // if the client passed in a different separator than `:`,
+ // we will use it if it is in the list of acceptable separators (dash or no separator)
+ if (['-', ''].indexOf(sep) !== -1) {
+ validSep = sep;
+ }
+
+ for (i = 0; i < 12; i++) {
+ mac += this.faker.datatype.number(15).toString(16);
+ if (i % 2 === 1 && i !== 11) {
+ mac += validSep;
+ }
+ }
+ return mac;
+ }
+
+ /**
+ * Generates a random password.
+ *
+ * @param len The length of the password to generate. Defaults to `15`.
+ * @param memorable Whether the generated password should be memorable. Defaults to `false`.
+ * @param pattern The pattern that all chars should match should match.
+ * This option will be ignored, if `memorable` is `true`. Defaults to `/\w/`.
+ * @param prefix The prefix to use. Defaults to `''`.
+ *
+ * @example
+ * faker.internet.password() // '89G1wJuBLbGziIs'
+ * faker.internet.password(20) // 'aF55c_8O9kZaPOrysFB_'
+ * faker.internet.password(20, true) // 'lawetimufozujosodedi'
+ * faker.internet.password(20, true, /[A-Z]/) // 'HMAQDFFYLDDUTBKVNFVS'
+ * faker.internet.password(20, true, /[A-Z]/, 'Hello ') // 'Hello IREOXTDWPERQSB'
+ */
+ password(
+ len: number = 15,
+ memorable: boolean = false,
+ pattern: RegExp = /\w/,
+ prefix: string = ''
+ ): string {
+ /*
+ * password-generator ( function )
+ * Copyright(c) 2011-2013 Bermi Ferrer <[email protected]>
+ * MIT Licensed
+ */
+ const vowel = /[aeiouAEIOU]$/;
+ const consonant = /[bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ]$/;
+ const _password = (
+ length: number,
+ memorable: boolean,
+ pattern: RegExp,
+ prefix: string
+ ): string => {
+ if (prefix.length >= length) {
+ return prefix;
+ }
+ if (memorable) {
+ if (prefix.match(consonant)) {
+ pattern = vowel;
+ } else {
+ pattern = consonant;
+ }
+ }
+ const n = this.faker.datatype.number(94) + 33;
+ let char = String.fromCharCode(n);
+ if (memorable) {
+ char = char.toLowerCase();
+ }
+ if (!char.match(pattern)) {
+ return _password(length, memorable, pattern, prefix);
+ }
+ return _password(length, memorable, pattern, prefix + char);
+ };
+ return _password(len, memorable, pattern, prefix);
+ }
+
+ /**
+ * Generates a random emoji.
+ *
+ * @param options Options object.
+ * @param options.types A list of the emoji types that should be used.
+ * @example
+ * faker.internet.emoji() // '🥰'
+ * faker.internet.emoji({ types: ['food', 'nature'] }) // '🥐'
+ */
+ emoji(options: { types?: ReadonlyArray<EmojiType> } = {}): string {
+ const {
+ types = Object.keys(
+ this.faker.definitions.internet.emoji
+ ) as Array<EmojiType>,
+ } = options;
+ const emojiType = this.faker.helpers.arrayElement(types);
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.internet.emoji[emojiType]
+ );
+ }
+}
diff --git a/src/modules/internet/user-agent.ts b/src/modules/internet/user-agent.ts
new file mode 100644
index 00000000..046758d4
--- /dev/null
+++ b/src/modules/internet/user-agent.ts
@@ -0,0 +1,345 @@
+/**
+ * Copyright (c) 2022 Faker
+ *
+ * This is a version of the original code migrated to TypeScript and modified
+ * by the Faker team.
+ *
+ * Check LICENSE for more details about the copyright.
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (c) 2012-2014 Jeffrey Mealo
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Based loosely on Luka Pusic's PHP Script:
+ * http://360percents.com/posts/php-random-user-agent-generator/
+ *
+ * The license for that script is as follows:
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ *
+ * <[email protected]> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Luka Pusic
+ */
+
+import type { Faker } from '../..';
+
+export type Arch = 'lin' | 'mac' | 'win';
+
+export function generate(faker: Faker): string {
+ function rnd(
+ a?: string[] | number | Record<string, number>,
+ b?: number
+ ): string | number {
+ //calling rnd() with no arguments is identical to rnd(0, 100)
+ a = a || 0;
+ b = b || 100;
+
+ if (typeof b === 'number' && typeof a === 'number') {
+ // 9/2018 - Added faker random to ensure mersenne and seed
+ return faker.datatype.number({ min: a, max: b });
+ }
+
+ if (Array.isArray(a)) {
+ //returns a random element from array (a), even weighting
+ return faker.helpers.arrayElement(a);
+ }
+
+ if (a && typeof a === 'object') {
+ //returns a random key from the passed object; keys are weighted by the decimal probability in their value
+ return ((obj) => {
+ const rand = (rnd(0, 100) as number) / 100;
+ let min = 0;
+ let max = 0;
+ let return_val: string;
+
+ for (const key in obj) {
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
+ max = obj[key] + min;
+ return_val = key;
+ if (rand >= min && rand <= max) {
+ break;
+ }
+ min = min + obj[key];
+ }
+ }
+
+ return return_val;
+ })(a);
+ }
+
+ throw new TypeError(
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
+ `Invalid arguments passed to rnd. (${b ? `${a}, ${b}` : a})`
+ );
+ }
+
+ function randomLang(): string | number {
+ return rnd([
+ 'AB',
+ 'AF',
+ 'AN',
+ 'AR',
+ 'AS',
+ 'AZ',
+ 'BE',
+ 'BG',
+ 'BN',
+ 'BO',
+ 'BR',
+ 'BS',
+ 'CA',
+ 'CE',
+ 'CO',
+ 'CS',
+ 'CU',
+ 'CY',
+ 'DA',
+ 'DE',
+ 'EL',
+ 'EN',
+ 'EO',
+ 'ES',
+ 'ET',
+ 'EU',
+ 'FA',
+ 'FI',
+ 'FJ',
+ 'FO',
+ 'FR',
+ 'FY',
+ 'GA',
+ 'GD',
+ 'GL',
+ 'GV',
+ 'HE',
+ 'HI',
+ 'HR',
+ 'HT',
+ 'HU',
+ 'HY',
+ 'ID',
+ 'IS',
+ 'IT',
+ 'JA',
+ 'JV',
+ 'KA',
+ 'KG',
+ 'KO',
+ 'KU',
+ 'KW',
+ 'KY',
+ 'LA',
+ 'LB',
+ 'LI',
+ 'LN',
+ 'LT',
+ 'LV',
+ 'MG',
+ 'MK',
+ 'MN',
+ 'MO',
+ 'MS',
+ 'MT',
+ 'MY',
+ 'NB',
+ 'NE',
+ 'NL',
+ 'NN',
+ 'NO',
+ 'OC',
+ 'PL',
+ 'PT',
+ 'RM',
+ 'RO',
+ 'RU',
+ 'SC',
+ 'SE',
+ 'SK',
+ 'SL',
+ 'SO',
+ 'SQ',
+ 'SR',
+ 'SV',
+ 'SW',
+ 'TK',
+ 'TR',
+ 'TY',
+ 'UK',
+ 'UR',
+ 'UZ',
+ 'VI',
+ 'VO',
+ 'YI',
+ 'ZH',
+ ]);
+ }
+
+ function randomBrowserAndOS(): Array<string | number> {
+ const browser = rnd({
+ chrome: 0.45132810566,
+ iexplorer: 0.27477061836,
+ firefox: 0.19384170608,
+ safari: 0.06186781118,
+ opera: 0.01574236955,
+ });
+ const os = {
+ chrome: { win: 0.89, mac: 0.09, lin: 0.02 },
+ firefox: { win: 0.83, mac: 0.16, lin: 0.01 },
+ opera: { win: 0.91, mac: 0.03, lin: 0.06 },
+ safari: { win: 0.04, mac: 0.96 },
+ iexplorer: ['win'],
+ };
+
+ return [browser, rnd(os[browser])];
+ }
+
+ function randomProc(arch: Arch): string | number {
+ const procs = {
+ lin: ['i686', 'x86_64'],
+ mac: { Intel: 0.48, PPC: 0.01, 'U; Intel': 0.48, 'U; PPC': 0.01 },
+ win: ['', 'WOW64', 'Win64; x64'],
+ };
+ return rnd(procs[arch]);
+ }
+
+ function randomRevision(dots: number): string {
+ let return_val = '';
+ //generate a random revision
+ //dots = 2 returns .x.y where x & y are between 0 and 9
+ for (let x = 0; x < dots; x++) {
+ return_val += `.${rnd(0, 9)}`;
+ }
+ return return_val;
+ }
+
+ const version_string = {
+ net() {
+ return [rnd(1, 4), rnd(0, 9), rnd(10000, 99999), rnd(0, 9)].join('.');
+ },
+ nt() {
+ return `${rnd(5, 6)}.${rnd(0, 3)}`;
+ },
+ ie() {
+ return rnd(7, 11);
+ },
+ trident() {
+ return `${rnd(3, 7)}.${rnd(0, 1)}`;
+ },
+ osx(delim?: string) {
+ return [10, rnd(5, 10), rnd(0, 9)].join(delim || '.');
+ },
+ chrome() {
+ return [rnd(13, 39), 0, rnd(800, 899), 0].join('.');
+ },
+ presto() {
+ return `2.9.${rnd(160, 190)}`;
+ },
+ presto2() {
+ return `${rnd(10, 12)}.00`;
+ },
+ safari() {
+ return `${rnd(531, 538)}.${rnd(0, 2)}.${rnd(0, 2)}`;
+ },
+ };
+
+ const browser = {
+ firefox(arch: Arch): string {
+ //https://developer.mozilla.org/en-US/docs/Gecko_user_agent_string_reference
+ const firefox_ver = `${rnd(5, 15)}${randomRevision(2)}`,
+ gecko_ver = `Gecko/20100101 Firefox/${firefox_ver}`,
+ proc = randomProc(arch),
+ os_ver =
+ arch === 'win'
+ ? `(Windows NT ${version_string.nt()}${proc ? `; ${proc}` : ''}`
+ : arch === 'mac'
+ ? `(Macintosh; ${proc} Mac OS X ${version_string.osx()}`
+ : `(X11; Linux ${proc}`;
+
+ return `Mozilla/5.0 ${os_ver}; rv:${firefox_ver.slice(
+ 0,
+ -2
+ )}) ${gecko_ver}`;
+ },
+
+ iexplorer(): string {
+ const ver = version_string.ie();
+
+ if (ver >= 11) {
+ //http://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx
+ return `Mozilla/5.0 (Windows NT 6.${rnd(1, 3)}; Trident/7.0; ${rnd([
+ 'Touch; ',
+ '',
+ ])}rv:11.0) like Gecko`;
+ }
+
+ //http://msdn.microsoft.com/en-us/library/ie/ms537503(v=vs.85).aspx
+ return `Mozilla/5.0 (compatible; MSIE ${ver}.0; Windows NT ${version_string.nt()}; Trident/${version_string.trident()}${
+ rnd(0, 1) === 1 ? `; .NET CLR ${version_string.net()}` : ''
+ })`;
+ },
+
+ opera(arch: Arch): string {
+ //http://www.opera.com/docs/history/
+ const presto_ver = ` Presto/${version_string.presto()} Version/${version_string.presto2()})`,
+ os_ver =
+ arch === 'win'
+ ? `(Windows NT ${version_string.nt()}; U; ${randomLang()}${presto_ver}`
+ : arch === 'lin'
+ ? `(X11; Linux ${randomProc(arch)}; U; ${randomLang()}${presto_ver}`
+ : `(Macintosh; Intel Mac OS X ${version_string.osx()} U; ${randomLang()} Presto/${version_string.presto()} Version/${version_string.presto2()})`;
+
+ return `Opera/${rnd(9, 14)}.${rnd(0, 99)} ${os_ver}`;
+ },
+
+ safari(arch: Arch): string {
+ const safari = version_string.safari(),
+ ver = `${rnd(4, 7)}.${rnd(0, 1)}.${rnd(0, 10)}`,
+ os_ver =
+ arch === 'mac'
+ ? `(Macintosh; ${randomProc('mac')} Mac OS X ${version_string.osx(
+ '_'
+ )} rv:${rnd(2, 6)}.0; ${randomLang()}) `
+ : `(Windows; U; Windows NT ${version_string.nt()})`;
+
+ return `Mozilla/5.0 ${os_ver}AppleWebKit/${safari} (KHTML, like Gecko) Version/${ver} Safari/${safari}`;
+ },
+
+ chrome(arch: Arch): string {
+ const safari = version_string.safari(),
+ os_ver =
+ arch === 'mac'
+ ? `(Macintosh; ${randomProc('mac')} Mac OS X ${version_string.osx(
+ '_'
+ )}) `
+ : arch === 'win'
+ ? `(Windows; U; Windows NT ${version_string.nt()})`
+ : `(X11; Linux ${randomProc(arch)}`;
+
+ return `Mozilla/5.0 ${os_ver} AppleWebKit/${safari} (KHTML, like Gecko) Chrome/${version_string.chrome()} Safari/${safari}`;
+ },
+ };
+
+ const random = randomBrowserAndOS();
+ return browser[random[0]](random[1]);
+}
diff --git a/src/modules/lorem/index.ts b/src/modules/lorem/index.ts
new file mode 100644
index 00000000..5df39146
--- /dev/null
+++ b/src/modules/lorem/index.ts
@@ -0,0 +1,205 @@
+import type { Faker } from '../..';
+
+/**
+ * Module to generate random texts and words.
+ */
+export class Lorem {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Lorem.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Generates a word of a specified length.
+ *
+ * @param length length of the word that should be returned. Defaults to a random length.
+ *
+ * @example
+ * faker.lorem.word() // 'temporibus'
+ * faker.lorem.word(5) // 'velit'
+ */
+ word(length?: number): string {
+ const hasRightLength = (word: string) => word.length === length;
+ let properLengthWords: readonly string[];
+ if (length == null) {
+ properLengthWords = this.faker.definitions.lorem.words;
+ } else {
+ properLengthWords =
+ this.faker.definitions.lorem.words.filter(hasRightLength);
+ }
+ return this.faker.helpers.arrayElement(properLengthWords);
+ }
+
+ /**
+ * Generates a space separated list of words.
+ *
+ * @param num The number of words to generate. Defaults to `3`.
+ *
+ * @example
+ * faker.lorem.words() // 'qui praesentium pariatur'
+ * faker.lorem.words(10) // 'debitis consectetur voluptatem non doloremque ipsum autem totam eum ratione'
+ */
+ words(num: number = 3): string {
+ const words: string[] = [];
+ for (let i = 0; i < num; i++) {
+ words.push(this.word());
+ }
+ return words.join(' ');
+ }
+
+ /**
+ * Generates a space separated list of words beginning a capital letter and ending with a dot.
+ *
+ * @param wordCount The number of words, that should be in the sentence. Defaults to a random number between `3` and `10`.
+ *
+ * @example
+ * faker.lorem.sentence() // 'Voluptatum cupiditate suscipit autem eveniet aut dolorem aut officiis distinctio.'
+ * faker.lorem.sentence(5) // 'Laborum voluptatem officiis est et.'
+ */
+ sentence(wordCount?: number): string {
+ if (wordCount == null) {
+ wordCount = this.faker.datatype.number({ min: 3, max: 10 });
+ }
+
+ const sentence = this.words(wordCount);
+ return `${sentence.charAt(0).toUpperCase() + sentence.slice(1)}.`;
+ }
+
+ /**
+ * Generates a slugified text consisting of the given number of hyphen separated words.
+ *
+ * @param wordCount The number of words to generate. Defaults to `3`.
+ *
+ * @example
+ * faker.lorem.slug() // 'dolores-illo-est'
+ */
+ slug(wordCount?: number): string {
+ const words = this.words(wordCount);
+
+ return this.faker.helpers.slugify(words);
+ }
+
+ /**
+ * Generates the given number of sentences.
+ *
+ * @param sentenceCount The number of sentences to generate. Defaults to a random number between `2` and `6`.
+ * @param separator The separator to add between sentences. Defaults to `' '`.
+ *
+ * @example
+ * faker.lorem.sentences() // 'Iste molestiae incidunt aliquam possimus reprehenderit eum corrupti. Deleniti modi voluptatem nostrum ut esse.'
+ * faker.lorem.sentences(2) // 'Maxime vel numquam quibusdam. Dignissimos ex molestias quos aut molestiae quam nihil occaecati maiores.'
+ * faker.lorem.sentences(2, '\n')
+ * // 'Et rerum a unde tempora magnam sit nisi.
+ * // Et perspiciatis ipsam omnis.'
+ */
+ sentences(sentenceCount?: number, separator: string = ' '): string {
+ if (sentenceCount == null) {
+ sentenceCount = this.faker.datatype.number({ min: 2, max: 6 });
+ }
+ const sentences: string[] = [];
+ for (sentenceCount; sentenceCount > 0; sentenceCount--) {
+ sentences.push(this.sentence());
+ }
+ return sentences.join(separator);
+ }
+
+ /**
+ * Generates a paragraph with at least the given number of sentences.
+ *
+ * @param sentenceCount The minim number of sentences to generate. Defaults to `3`.
+ *
+ * @example
+ * faker.lorem.paragraph() // 'Non architecto nam unde sint. Ex tenetur dolor facere optio aut consequatur. Ea laudantium reiciendis repellendus.'
+ * faker.lorem.paragraph() // 'Animi possimus nemo consequuntur ut ea et tempore unde qui. Quis corporis esse occaecati.'
+ */
+ paragraph(sentenceCount: number = 3): string {
+ return this.sentences(sentenceCount + this.faker.datatype.number(3));
+ }
+
+ /**
+ * Generates the given number of paragraphs.
+ *
+ * @param paragraphCount The number of paragraphs to generate. Defaults to `3`.
+ * @param separator The separator to use. Defaults to `'\n'`.
+ *
+ * @example
+ * faker.lorem.paragraphs()
+ * // 'Beatae voluptatem dicta et assumenda fugit eaque quidem consequatur. Fuga unde provident. Id reprehenderit soluta facilis est laborum laborum. Illum aut non ut. Est nulla rem ipsa.
+ * // Voluptatibus quo pariatur est. Temporibus deleniti occaecati pariatur nemo est molestias voluptas. Doloribus commodi et et exercitationem vel et. Omnis inventore cum aut amet.
+ * // Sapiente deleniti et. Ducimus maiores eum. Rem dolorem itaque aliquam.'
+ *
+ * faker.lorem.paragraphs(5)
+ * // 'Quia hic sunt ducimus expedita quo impedit soluta. Quam impedit et ipsum optio. Unde dolores nulla nobis vero et aspernatur officiis.
+ * // Aliquam dolorem temporibus dolores voluptatem voluptatem qui nostrum quia. Sit hic facilis rerum eius. Beatae doloribus nesciunt iste ipsum.
+ * // Natus nam eum nulla voluptas molestiae fuga libero nihil voluptatibus. Sed quam numquam eum ipsam temporibus eaque ut et. Enim quas debitis quasi quis. Vitae et vitae.
+ * // Repellat voluptatem est laborum illo harum sed reprehenderit aut. Quo sit et. Exercitationem blanditiis totam velit ad dicta placeat.
+ * // Rerum non eum incidunt amet quo. Eaque laborum ut. Recusandae illo ab distinctio veritatis. Cum quis architecto ad maxime a.'
+ *
+ * faker.lorem.paragraphs(2, '<br/>\n')
+ * // 'Eos magnam aut qui accusamus. Sapiente quas culpa totam excepturi. Blanditiis totam distinctio occaecati dignissimos cumque atque qui officiis.<br/>
+ * // Nihil quis vel consequatur. Blanditiis commodi deserunt sunt animi dolorum. A optio porro hic dolorum fugit aut et sint voluptas. Minima ad sed ipsa est non dolores.'
+ */
+ paragraphs(paragraphCount: number = 3, separator: string = '\n'): string {
+ const paragraphs: string[] = [];
+ for (paragraphCount; paragraphCount > 0; paragraphCount--) {
+ paragraphs.push(this.paragraph());
+ }
+ return paragraphs.join(separator);
+ }
+
+ /**
+ * Generates a random text based on a random lorem method.
+ *
+ * @example
+ * faker.lorem.text() // 'Doloribus autem non quis vero quia.'
+ * faker.lorem.text()
+ * // 'Rerum eum reiciendis id ipsa hic dolore aut laborum provident.
+ * // Quis beatae quis corporis veritatis corrupti ratione delectus sapiente ut.
+ * // Quis ut dolor dolores facilis possimus tempore voluptates.
+ * // Iure nam officia optio cumque.
+ * // Dolor tempora iusto.'
+ */
+ text(): string {
+ const methods: Array<keyof Lorem> = [
+ 'word',
+ 'words',
+ 'sentence',
+ 'sentences',
+ 'paragraph',
+ 'paragraphs',
+ 'lines',
+ ];
+
+ const method = this.faker.helpers.arrayElement(methods);
+
+ return `${this[method]()}`;
+ }
+
+ /**
+ * Generates the given number lines of lorem separated by `'\n'`.
+ *
+ * @param lineCount The number of lines to generate. Defaults to a random number between `1` and `5`.
+ *
+ * @example
+ * faker.lorem.lines()
+ * // 'Rerum quia aliquam pariatur explicabo sint minima eos.
+ * // Voluptatem repellat consequatur deleniti qui quibusdam harum cumque.
+ * // Enim eveniet a qui.
+ * // Consectetur velit eligendi animi nostrum veritatis.'
+ *
+ * faker.lorem.lines()
+ * // 'Soluta deserunt eos quam reiciendis libero autem enim nam ut.
+ * // Voluptate aut aut.'
+ */
+ lines(lineCount?: number): string {
+ if (lineCount == null) {
+ lineCount = this.faker.datatype.number({ min: 1, max: 5 });
+ }
+ return this.sentences(lineCount, '\n');
+ }
+}
diff --git a/src/modules/mersenne/index.ts b/src/modules/mersenne/index.ts
new file mode 100644
index 00000000..33e610f8
--- /dev/null
+++ b/src/modules/mersenne/index.ts
@@ -0,0 +1,73 @@
+import { FakerError } from '../../errors/faker-error';
+import Gen from './twister';
+
+/**
+ * Module to generate seed based random numbers.
+ */
+export class Mersenne {
+ private gen = new Gen();
+
+ constructor() {
+ this.gen.initGenrand(new Date().getTime() % 1000000000);
+
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Mersenne.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Generates a random number between `[min, max)`.
+ *
+ * @param max The maximum number. Defaults to `0`.
+ * @param min The minimum number. Defaults to `32768`.
+ *
+ * @example
+ * faker.mersenne.rand() // 15515
+ * faker.mersenne.rand(500, 1000) // 578
+ */
+ rand(max = 32768, min = 0): number {
+ if (min > max) {
+ const temp = min;
+ min = max;
+ max = temp;
+ }
+
+ return Math.floor(this.gen.genrandReal2() * (max - min) + min);
+ }
+
+ /**
+ * Sets the seed to use.
+ *
+ * @param S The seed to use.
+ * @throws If the seed is not a `number`.
+ */
+ seed(S: number): void {
+ if (typeof S !== 'number') {
+ throw new FakerError(
+ `seed(S) must take numeric argument; is ${typeof S}`
+ );
+ }
+
+ this.gen.initGenrand(S);
+ }
+
+ /**
+ * Sets the seed to use.
+ *
+ * @param A The seed to use.
+ * @throws If the seed is not a `number[]`.
+ */
+ seed_array(A: number[]): void {
+ if (typeof A !== 'object') {
+ throw new FakerError(
+ `seed_array(A) must take array of numbers; is ${typeof A}`
+ );
+ }
+
+ this.gen.initByArray(A, A.length);
+ }
+}
diff --git a/src/modules/mersenne/twister.ts b/src/modules/mersenne/twister.ts
new file mode 100644
index 00000000..5859f3ae
--- /dev/null
+++ b/src/modules/mersenne/twister.ts
@@ -0,0 +1,320 @@
+/**
+ * Copyright (c) 2022 Faker
+ *
+ * This is a version of the original source code migrated to TypeScript and
+ * modified by the Faker team.
+ *
+ * Check LICENSE for more details on copyright.
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (c) 2006 Y. Okada
+ *
+ * This program is a JavaScript version of Mersenne Twister, with concealment
+ * and encapsulation in class, an almost straight conversion from the original
+ * program, mt19937ar.c, translated by Y. Okada on July 17, 2006, and modified
+ * a little at July 20, 2006, but there are not any substantial differences.
+ *
+ * In this program, procedure descriptions and comments of original source code
+ * were not removed.
+ *
+ * Lines commented with //c// were originally descriptions of c procedure.
+ * And a few following lines are appropriate JavaScript descriptions.
+ *
+ * Lines commented with /* and *\/ are original comments.
+ * Lines commented with // are additional comments in this JavaScript version.
+ *
+ * Before using this version, create at least one instance of
+ * MersenneTwister19937 class, and initialize the each state, given below
+ * in C comments, of all the instances.
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * A C-program for MT19937, with initialization improved 2002/1/26.
+ * Coded by Takuji Nishimura and Makoto Matsumoto.
+ *
+ * Before using, initialize the state by using init_genrand(seed)
+ * or init_by_array(init_key, key_length).
+ *
+ * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The names of its contributors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Any feedback is very welcome.
+ * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+ * email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+ */
+
+export default class MersenneTwister19937 {
+ private readonly N = 624;
+ private readonly M = 397;
+ private readonly MATRIX_A = 0x9908b0df; // constant vector a
+ private readonly UPPER_MASK = 0x80000000; // most significant w-r bits
+ private readonly LOWER_MASK = 0x7fffffff; // least significant r bits
+ private mt: number[] = new Array(this.N); // the array for the state vector
+ private mti = this.N + 1; // mti==N+1 means mt[N] is not initialized
+
+ /**
+ * Returns a 32-bits unsigned integer from an operand to which applied a bit
+ * operator.
+ *
+ * @param n1 number to unsign
+ */
+ private unsigned32(n1: number): number {
+ return n1 < 0 ? (n1 ^ this.UPPER_MASK) + this.UPPER_MASK : n1;
+ }
+
+ /**
+ * Emulates lowerflow of a c 32-bits unsigned integer variable, instead of
+ * the operator -. These both arguments must be non-negative integers
+ * expressible using unsigned 32 bits.
+ *
+ * @param n1 dividend
+ * @param n2 divisor
+ */
+ private subtraction32(n1: number, n2: number): number {
+ return n1 < n2
+ ? this.unsigned32((0x100000000 - (n2 - n1)) & 0xffffffff)
+ : n1 - n2;
+ }
+
+ /**
+ * Emulates overflow of a c 32-bits unsigned integer variable, instead of the operator +.
+ * these both arguments must be non-negative integers expressible using unsigned 32 bits.
+ *
+ * @param n1 number one for addition
+ * @param n2 number two for addition
+ */
+ private addition32(n1: number, n2: number): number {
+ return this.unsigned32((n1 + n2) & 0xffffffff);
+ }
+
+ /**
+ * Emulates overflow of a c 32-bits unsigned integer variable, instead of the operator *.
+ * These both arguments must be non-negative integers expressible using unsigned 32 bits.
+ *
+ * @param n1 number one for multiplication
+ * @param n2 number two for multiplication
+ */
+ private multiplication32(n1: number, n2: number): number {
+ let sum = 0;
+ for (let i = 0; i < 32; ++i) {
+ if ((n1 >>> i) & 0x1) {
+ sum = this.addition32(sum, this.unsigned32(n2 << i));
+ }
+ }
+ return sum;
+ }
+
+ /**
+ * Initializes mt[N] with a seed.
+ *
+ * @param seed the seed to use
+ */
+ initGenrand(seed: number): void {
+ this.mt[0] = this.unsigned32(seed & 0xffffffff);
+ for (this.mti = 1; this.mti < this.N; this.mti++) {
+ this.mt[this.mti] =
+ //(1812433253 * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
+ this.addition32(
+ this.multiplication32(
+ 1812433253,
+ this.unsigned32(
+ this.mt[this.mti - 1] ^ (this.mt[this.mti - 1] >>> 30)
+ )
+ ),
+ this.mti
+ );
+
+ /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
+ /* In the previous versions, MSBs of the seed affect */
+ /* only MSBs of the array mt[]. */
+ /* 2002/01/09 modified by Makoto Matsumoto */
+ this.mt[this.mti] = this.unsigned32(this.mt[this.mti] & 0xffffffff);
+ }
+ }
+
+ /**
+ * Initialize by an array with array-length.
+ *
+ * @param initKey is the array for initializing keys
+ * @param keyLength is its length
+ */
+ initByArray(initKey: number[], keyLength: number): void {
+ this.initGenrand(19650218);
+ let i = 1;
+ let j = 0;
+ let k = this.N > keyLength ? this.N : keyLength;
+ for (; k; k--) {
+ // mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525)) + init_key[j] + j;
+ this.mt[i] = this.addition32(
+ this.addition32(
+ this.unsigned32(
+ this.mt[i] ^
+ this.multiplication32(
+ this.unsigned32(this.mt[i - 1] ^ (this.mt[i - 1] >>> 30)),
+ 1664525
+ )
+ ),
+ initKey[j]
+ ),
+ j
+ );
+ // mt[i] &= 0xffffffff; for WORDSIZE > 32 machines
+ this.mt[i] = this.unsigned32(this.mt[i] & 0xffffffff);
+ i++;
+ j++;
+ if (i >= this.N) {
+ this.mt[0] = this.mt[this.N - 1];
+ i = 1;
+ }
+ if (j >= keyLength) {
+ j = 0;
+ }
+ }
+ for (k = this.N - 1; k; k--) {
+ // mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941)) - i
+ this.mt[i] = this.subtraction32(
+ this.unsigned32(
+ this.mt[i] ^
+ this.multiplication32(
+ this.unsigned32(this.mt[i - 1] ^ (this.mt[i - 1] >>> 30)),
+ 1566083941
+ )
+ ),
+ i
+ );
+ // mt[i] &= 0xffffffff; for WORDSIZE > 32 machines
+ this.mt[i] = this.unsigned32(this.mt[i] & 0xffffffff);
+ i++;
+ if (i >= this.N) {
+ this.mt[0] = this.mt[this.N - 1];
+ i = 1;
+ }
+ }
+ this.mt[0] = 0x80000000; // MSB is 1; assuring non-zero initial array
+ }
+
+ // moved outside of genrandInt32() by jwatte 2010-11-17; generate less garbage
+ private mag01 = [0x0, this.MATRIX_A];
+
+ /**
+ * Generates a random number on [0,2^32]-interval
+ */
+ genrandInt32(): number {
+ let y: number;
+
+ if (this.mti >= this.N) {
+ // generate N words at one time
+ let kk: number;
+
+ // if initGenrand() has not been called a default initial seed is used
+ if (this.mti === this.N + 1) {
+ this.initGenrand(5489);
+ }
+
+ for (kk = 0; kk < this.N - this.M; kk++) {
+ y = this.unsigned32(
+ (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK)
+ );
+
+ this.mt[kk] = this.unsigned32(
+ this.mt[kk + this.M] ^ (y >>> 1) ^ this.mag01[y & 0x1]
+ );
+ }
+
+ for (; kk < this.N - 1; kk++) {
+ y = this.unsigned32(
+ (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK)
+ );
+
+ this.mt[kk] = this.unsigned32(
+ this.mt[kk + (this.M - this.N)] ^ (y >>> 1) ^ this.mag01[y & 0x1]
+ );
+ }
+
+ y = this.unsigned32(
+ (this.mt[this.N - 1] & this.UPPER_MASK) | (this.mt[0] & this.LOWER_MASK)
+ );
+
+ this.mt[this.N - 1] = this.unsigned32(
+ this.mt[this.M - 1] ^ (y >>> 1) ^ this.mag01[y & 0x1]
+ );
+
+ this.mti = 0;
+ }
+
+ y = this.mt[this.mti++];
+
+ // Tempering
+ y = this.unsigned32(y ^ (y >>> 11));
+ y = this.unsigned32(y ^ ((y << 7) & 0x9d2c5680));
+ y = this.unsigned32(y ^ ((y << 15) & 0xefc60000));
+ y = this.unsigned32(y ^ (y >>> 18));
+
+ return y;
+ }
+
+ /**
+ * Generates a random number on [0,2^32]-interval
+ */
+ genrandInt31(): number {
+ return this.genrandInt32() >>> 1;
+ }
+
+ /**
+ * Generates a random number on [0,1]-real-interval
+ */
+ genrandReal1(): number {
+ return this.genrandInt32() * (1.0 / 4294967295.0); // divided by 2^32-1
+ }
+
+ /**
+ * Generates a random number on [0,1)-real-interval
+ */
+ genrandReal2(): number {
+ return this.genrandInt32() * (1.0 / 4294967296.0); // divided by 2^32
+ }
+
+ /**
+ * Generates a random number on (0,1)-real-interval
+ */
+ genrandReal3(): number {
+ return (this.genrandInt32() + 0.5) * (1.0 / 4294967296.0); // divided by 2^32
+ }
+
+ /**
+ * Generates a random number on [0,1) with 53-bit resolution
+ */
+ genrandRes53(): number {
+ const a = this.genrandInt32() >>> 5,
+ b = this.genrandInt32() >>> 6;
+ return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0);
+ }
+ // These real versions are due to Isaku Wada, 2002/01/09
+}
diff --git a/src/modules/music/index.ts b/src/modules/music/index.ts
new file mode 100644
index 00000000..a34a4bb8
--- /dev/null
+++ b/src/modules/music/index.ts
@@ -0,0 +1,26 @@
+import type { Faker } from '../..';
+
+/**
+ * Module to generate music related entries.
+ */
+export class Music {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Music.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Returns a random music genre.
+ *
+ * @example
+ * faker.music.genre() // 'Reggae'
+ */
+ genre(): string {
+ return this.faker.helpers.arrayElement(this.faker.definitions.music.genre);
+ }
+}
diff --git a/src/modules/name/index.ts b/src/modules/name/index.ts
new file mode 100644
index 00000000..c1ac22a7
--- /dev/null
+++ b/src/modules/name/index.ts
@@ -0,0 +1,350 @@
+import type { Faker } from '../..';
+import { deprecated } from '../../internal/deprecated';
+
+export enum Gender {
+ female = 'female',
+ male = 'male',
+}
+
+// TODO @Shinigami92 2022-03-21: Remove 0 and 1 in v7
+export type GenderType = 'female' | 'male' | 0 | 1;
+
+/**
+ * Normalize gender.
+ *
+ * @param gender Gender.
+ * @param functionName Temporary parameter for deprecation message.
+ * @returns Normalized gender.
+ */
+function normalizeGender(
+ gender?: GenderType,
+ functionName?: string
+): Exclude<GenderType, number> | undefined {
+ if (gender == null || typeof gender === 'string') {
+ // TODO @Shinigami92 2022-03-21: Cast can be removed when we set `strict: true`
+ return gender as Exclude<GenderType, number>;
+ }
+
+ const normalizedGender = gender === 0 ? 'male' : 'female';
+
+ deprecated({
+ deprecated: `name.${functionName}(number)`,
+ proposed: "'female' or 'male'",
+ since: 'v6.1.0',
+ until: 'v7.0.0',
+ });
+
+ return normalizedGender;
+}
+
+/**
+ * Select a definition based on given gender.
+ *
+ * @param faker Faker instance.
+ * @param gender Gender.
+ * @param param2 Definitions.
+ * @param param2.generic Non-gender definitions.
+ * @param param2.female Female definitions.
+ * @param param2.male Male definitions.
+ * @param functionName Temporary parameter for deprecation message.
+ * @returns Definition based on given gender.
+ */
+function selectDefinition(
+ faker: Faker,
+ gender: GenderType | undefined,
+ // TODO @Shinigami92 2022-03-21: Remove fallback empty object when `strict: true`
+ {
+ generic,
+ female,
+ male,
+ }: { generic?: string[]; female?: string[]; male?: string[] } = {},
+ functionName?: string
+) {
+ const normalizedGender = normalizeGender(gender, functionName);
+
+ let values: string[] | undefined;
+ switch (normalizedGender) {
+ case 'female':
+ values = female;
+ break;
+ case 'male':
+ values = male;
+ break;
+ default:
+ values = generic;
+ break;
+ }
+
+ if (values == null) {
+ if (female != null && male != null) {
+ values = faker.helpers.arrayElement([female, male]);
+ } else {
+ values = generic;
+ }
+ }
+
+ return faker.helpers.arrayElement(values);
+}
+
+/**
+ * Module to generate people's names and titles.
+ */
+export class Name {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Name.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Returns a random first name.
+ *
+ * @param gender The optional gender to use.
+ * Can be either `'female'` or `'male'`.
+ *
+ * @example
+ * faker.name.firstName() // 'Antwan'
+ * faker.name.firstName("female") // 'Victoria'
+ * faker.name.firstName("male") // 'Tom'
+ */
+ firstName(gender?: GenderType): string {
+ const { first_name, female_first_name, male_first_name } =
+ this.faker.definitions.name;
+
+ return selectDefinition(
+ this.faker,
+ gender,
+ {
+ generic: first_name,
+ female: female_first_name,
+ male: male_first_name,
+ },
+ 'firstName'
+ );
+ }
+
+ /**
+ * Returns a random last name.
+ *
+ * @param gender The optional gender to use.
+ * Can be either `'female'` or `'male'`.
+ *
+ * @example
+ * faker.name.lastName() // 'Hauck'
+ * faker.name.lastName("female") // 'Grady'
+ * faker.name.lastName("male") // 'Barton'
+ */
+ lastName(gender?: GenderType): string {
+ const { last_name, female_last_name, male_last_name } =
+ this.faker.definitions.name;
+
+ return selectDefinition(
+ this.faker,
+ gender,
+ {
+ generic: last_name,
+ female: female_last_name,
+ male: male_last_name,
+ },
+ 'lastName'
+ );
+ }
+
+ /**
+ * Returns a random middle name.
+ *
+ * @param gender The optional gender to use.
+ * Can be either `'female'` or `'male'`.
+ *
+ * @example
+ * faker.name.middleName() // 'Доброславівна'
+ * faker.name.middleName("female") // 'Анастасівна'
+ * faker.name.middleName("male") // 'Вікторович'
+ */
+ middleName(gender?: GenderType): string {
+ const { middle_name, female_middle_name, male_middle_name } =
+ this.faker.definitions.name;
+
+ return selectDefinition(
+ this.faker,
+ gender,
+ {
+ generic: middle_name,
+ female: female_middle_name,
+ male: male_middle_name,
+ },
+ 'middleName'
+ );
+ }
+
+ /**
+ * Generates a random full name.
+ *
+ * @param firstName The optional first name to use. If not specified a random one will be chosen.
+ * @param lastName The optional last name to use. If not specified a random one will be chosen.
+ * @param gender The optional gender to use.
+ * Can be either `'female'` or `'male'`.
+ *
+ * @example
+ * faker.name.findName() // 'Allen Brown'
+ * faker.name.findName('Joann') // 'Joann Osinski'
+ * faker.name.findName('Marcella', '', 'female') // 'Mrs. Marcella Huels'
+ * faker.name.findName(undefined, 'Beer') // 'Mr. Alfonso Beer'
+ * faker.name.findName(undefined, undefined, 'male') // 'Fernando Schaefer'
+ */
+ findName(firstName?: string, lastName?: string, gender?: GenderType): string {
+ const variant = this.faker.datatype.number(8);
+ let prefix = '';
+ let suffix = '';
+
+ const normalizedGender: Exclude<GenderType, number> =
+ normalizeGender(gender, 'findName') ??
+ this.faker.helpers.arrayElement(['female', 'male']);
+
+ firstName = firstName || this.firstName(normalizedGender);
+ lastName = lastName || this.lastName(normalizedGender);
+
+ switch (variant) {
+ // TODO @Shinigami92 2022-03-21: Add possibility to have a prefix together with a suffix
+ case 0:
+ prefix = this.prefix(gender);
+ if (prefix) {
+ return `${prefix} ${firstName} ${lastName}`;
+ }
+ // TODO @Shinigami92 2022-01-21: Not sure if this fallthrough is wanted
+ // eslint-disable-next-line no-fallthrough
+ case 1:
+ suffix = this.suffix();
+ if (suffix) {
+ return `${firstName} ${lastName} ${suffix}`;
+ }
+ }
+
+ return `${firstName} ${lastName}`;
+ }
+
+ /**
+ * Return a random gender.
+ *
+ * @param binary Whether to return only binary gender names. Defaults to `false`.
+ *
+ * @example
+ * faker.name.gender() // 'Trans*Man'
+ * faker.name.gender(true) // 'Female'
+ */
+ gender(binary?: boolean): string {
+ if (binary) {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.name.binary_gender
+ );
+ }
+
+ return this.faker.helpers.arrayElement(this.faker.definitions.name.gender);
+ }
+
+ /**
+ * Returns a random name prefix.
+ *
+ * @param gender The optional gender to use.
+ * Can be either `'female'` or `'male'`.
+ *
+ * @example
+ * faker.name.prefix() // 'Miss'
+ * faker.name.prefix('female') // 'Ms.'
+ * faker.name.prefix('male') // 'Mr.'
+ */
+ prefix(gender?: GenderType): string {
+ const { prefix, female_prefix, male_prefix } = this.faker.definitions.name;
+
+ return selectDefinition(
+ this.faker,
+ gender,
+ {
+ generic: prefix,
+ female: female_prefix,
+ male: male_prefix,
+ },
+ 'prefix'
+ );
+ }
+
+ /**
+ * Returns a random name suffix.
+ *
+ * @example
+ * faker.name.suffix() // 'DDS'
+ */
+ suffix(): string {
+ // TODO @Shinigami92 2022-03-21: Add female_suffix and male_suffix
+ return this.faker.helpers.arrayElement(this.faker.definitions.name.suffix);
+ }
+
+ /**
+ * Generates a random job title.
+ *
+ * @example
+ * faker.name.title() // 'International Integration Manager'
+ *
+ * @deprecated
+ */
+ title(): string {
+ deprecated({
+ deprecated: 'faker.name.title()',
+ proposed: 'faker.name.jobTitle()',
+ since: 'v6.1.2',
+ until: 'v7.0.0',
+ });
+
+ return this.jobTitle();
+ }
+
+ /**
+ * Generates a random job title.
+ *
+ * @example
+ * faker.name.jobTitle() // 'Global Accounts Engineer'
+ */
+ jobTitle(): string {
+ return `${this.jobDescriptor()} ${this.jobArea()} ${this.jobType()}`;
+ }
+
+ /**
+ * Generates a random job descriptor.
+ *
+ * @example
+ * faker.name.jobDescriptor() // 'Customer'
+ */
+ jobDescriptor(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.name.title.descriptor
+ );
+ }
+
+ /**
+ * Generates a random job area.
+ *
+ * @example
+ * faker.name.jobArea() // 'Brand'
+ */
+ jobArea(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.name.title.level
+ );
+ }
+
+ /**
+ * Generates a random job type.
+ *
+ * @example
+ * faker.name.jobType() // 'Assistant'
+ */
+ jobType(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.name.title.job
+ );
+ }
+}
diff --git a/src/modules/phone/index.ts b/src/modules/phone/index.ts
new file mode 100644
index 00000000..7e85915c
--- /dev/null
+++ b/src/modules/phone/index.ts
@@ -0,0 +1,76 @@
+import type { Faker } from '../..';
+
+/**
+ * Module to generate phone-related data.
+ */
+export class Phone {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Phone.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Generates a random phone number.
+ *
+ * @param format Format of the phone number. Defaults to `faker.phone.phoneFormats()`.
+ *
+ * @example
+ * faker.phone.phoneNumber() // '961-770-7727'
+ * faker.phone.phoneNumber('501-###-###') // '501-039-841'
+ * faker.phone.phoneNumber('+48 91 ### ## ##') // '+48 91 463 61 70'
+ */
+ // TODO @pkuczynski 2022-02-01: simplify name to `number()`
+ phoneNumber(format?: string): string {
+ return this.faker.helpers.replaceSymbolWithNumber(
+ format || this.phoneFormats()
+ );
+ }
+
+ /**
+ * Returns phone number in a format of the given index from `faker.definitions.phone_number.formats`.
+ *
+ * @param phoneFormatsArrayIndex Index in the `faker.definitions.phone_number.formats` array. Defaults to `0`.
+ *
+ * @example
+ * faker.phone.phoneNumberFormat() // '943-627-0355'
+ * faker.phone.phoneNumberFormat(3) // '282.652.3201'
+ */
+ // FIXME @Shinigami 2022-01-14: this is strange passing in an array index
+ // TODO @pkuczynski 2022-02-01: discuss removing this method as it tightly couples with localisation
+ phoneNumberFormat(phoneFormatsArrayIndex = 0): string {
+ return this.faker.helpers.replaceSymbolWithNumber(
+ this.faker.definitions.phone_number.formats[phoneFormatsArrayIndex]
+ );
+ }
+
+ /**
+ * Returns a random phone number format.
+ *
+ * @example
+ * faker.phone.phoneFormats() // '!##.!##.####'
+ */
+ // TODO @pkuczynski 2022-02-01: simplify name to `format()`
+ phoneFormats(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.phone_number.formats
+ );
+ }
+
+ /**
+ * Generates IMEI number.
+ *
+ * @example
+ * faker.phone.imei() // '13-850175-913761-7'
+ */
+ imei(): string {
+ return this.faker.helpers.replaceCreditCardSymbols(
+ '##-######-######-L',
+ '#'
+ );
+ }
+}
diff --git a/src/modules/random/index.ts b/src/modules/random/index.ts
new file mode 100644
index 00000000..7939b298
--- /dev/null
+++ b/src/modules/random/index.ts
@@ -0,0 +1,648 @@
+import type { Faker } from '../..';
+import { FakerError } from '../../errors/faker-error';
+import { deprecated } from '../../internal/deprecated';
+
+/**
+ * Method to reduce array of characters.
+ *
+ * @param arr existing array of characters
+ * @param values array of characters which should be removed
+ * @returns new array without banned characters
+ */
+function arrayRemove<T>(arr: T[], values: readonly T[]): T[] {
+ values.forEach((value) => {
+ arr = arr.filter((ele) => ele !== value);
+ });
+ return arr;
+}
+
+/**
+ * Generates random values of different kinds. Some methods are deprecated and have been moved to dedicated modules.
+ */
+export class Random {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Random.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Returns a single random number between zero and the given max value or the given range with the specified precision.
+ * The bounds are inclusive.
+ *
+ * @param options Maximum value or options object.
+ * @param options.min Lower bound for generated number. Defaults to `0`.
+ * @param options.max Upper bound for generated number. Defaults to `99999`.
+ * @param options.precision Precision of the generated number. Defaults to `1`.
+ *
+ * @see faker.datatype.number()
+ *
+ * @example
+ * faker.random.number() // 55422
+ * faker.random.number(100) // 52
+ * faker.random.number({ min: 1000000 }) // 431433
+ * faker.random.number({ max: 100 }) // 42
+ * faker.random.number({ precision: 0.01 }) // 64246.18
+ * faker.random.number({ min: 10, max: 100, precision: 0.01 }) // 36.94
+ *
+ * @deprecated
+ */
+ number(
+ options?: number | { min?: number; max?: number; precision?: number }
+ ): number {
+ deprecated({
+ deprecated: 'faker.random.number()',
+ proposed: 'faker.datatype.number()',
+ // since: 'v5.0.0', (?)
+ until: 'v7.0.0',
+ });
+ return this.faker.datatype.number(options);
+ }
+
+ /**
+ * Returns a single random floating-point number for the given precision or range and precision.
+ *
+ * @param options Precision or options object.
+ * @param options.min Lower bound for generated number. Defaults to `0`.
+ * @param options.max Upper bound for generated number. Defaults to `99999`.
+ * @param options.precision Precision of the generated number. Defaults to `0.01`.
+ *
+ * @see faker.datatype.float()
+ *
+ * @example
+ * faker.random.float() // 51696.36
+ * faker.random.float(0.1) // 52023.2
+ * faker.random.float({ min: 1000000 }) // 212859.76
+ * faker.random.float({ max: 100 }) // 28.11
+ * faker.random.float({ precision: 0.1 }) // 84055.3
+ * faker.random.float({ min: 10, max: 100, precision: 0.001 }) // 57.315
+ *
+ * @deprecated
+ */
+ float(
+ options?: number | { min?: number; max?: number; precision?: number }
+ ): number {
+ deprecated({
+ deprecated: 'faker.random.float()',
+ proposed: 'faker.datatype.float()',
+ // since: 'v5.0.0', (?)
+ until: 'v7.0.0',
+ });
+ return this.faker.datatype.float(options);
+ }
+
+ /**
+ * Returns random element from the given array.
+ *
+ * @template T The type of the entries to pick from.
+ * @param array Array to pick the value from. Defaults to `['a', 'b', 'c']`.
+ *
+ * @example
+ * faker.random.arrayElement() // 'b'
+ * faker.random.arrayElement(['cat', 'dog', 'mouse']) // 'dog'
+ *
+ * @deprecated
+ */
+ arrayElement<T = string>(
+ array: ReadonlyArray<T> = ['a', 'b', 'c'] as unknown as ReadonlyArray<T>
+ ): T {
+ deprecated({
+ deprecated: 'faker.random.arrayElement()',
+ proposed: 'faker.helpers.arrayElement()',
+ since: 'v6.3.0',
+ until: 'v7.0.0',
+ });
+ return this.faker.helpers.arrayElement(array);
+ }
+
+ /**
+ * Returns a subset with random elements of the given array in random order.
+ *
+ * @template T The type of the entries to pick from.
+ * @param array Array to pick the value from. Defaults to `['a', 'b', 'c']`.
+ * @param count Number of elements to pick.
+ * When not provided, random number of elements will be picked.
+ * When value exceeds array boundaries, it will be limited to stay inside.
+ *
+ * @example
+ * faker.random.arrayElements() // ['b', 'c']
+ * faker.random.arrayElements(['cat', 'dog', 'mouse']) // ['mouse', 'cat']
+ * faker.random.arrayElements([1, 2, 3, 4, 5], 2) // [4, 2]
+ *
+ * @deprecated
+ */
+ arrayElements<T>(
+ array: ReadonlyArray<T> = ['a', 'b', 'c'] as unknown as ReadonlyArray<T>,
+ count?: number
+ ): T[] {
+ deprecated({
+ deprecated: 'faker.random.arrayElements()',
+ proposed: 'faker.helpers.arrayElements()',
+ since: 'v6.3.0',
+ until: 'v7.0.0',
+ });
+ return this.faker.helpers.arrayElements(array, count);
+ }
+
+ /**
+ * Returns a random key from given object.
+ *
+ * @template T The type of `Record` to pick from.
+ * @template K The keys of `T`.
+ * @param object The object to get the keys from.
+ * @param field If this is set to `'key'`, this method will a return a random key of the given instance.
+ *
+ * @see faker.helpers.objectKey()
+ *
+ * @example
+ * const object = { keyA: 'valueA', keyB: 42 };
+ * faker.random.objectElement(object, 'key') // 'keyB'
+ *
+ * @deprecated
+ */
+ objectElement<T extends Record<string, unknown>, K extends keyof T>(
+ object: T,
+ field: 'key'
+ ): K;
+ /**
+ * Returns a random value from given object.
+ *
+ * @template T The type of `Record` to pick from.
+ * @template K The keys of `T`.
+ * @param object The object to get the values from.
+ * @param field If this is set to `'value'`, this method will a return a random value of the given instance.
+ *
+ * @see faker.helpers.objectValue()
+ *
+ * @example
+ * const object = { keyA: 'valueA', keyB: 42 };
+ * faker.random.objectElement(object) // 42
+ * faker.random.objectElement(object, 'value') // 'valueA'
+ *
+ * @deprecated
+ */
+ objectElement<T extends Record<string, unknown>, K extends keyof T>(
+ object: T,
+ field?: unknown
+ ): T[K];
+ /**
+ * Returns a random key or value from given object.
+ *
+ * @template T The type of `Record` to pick from.
+ * @template K The keys of `T`.
+ * @param object The object to get the keys or values from.
+ * @param field If this is set to `'key'`, this method will a return a random key of the given instance.
+ * If this is set to `'value'`, this method will a return a random value of the given instance.
+ * Defaults to `'value'`.
+ *
+ * @see faker.helpers.objectKey()
+ * @see faker.helpers.objectValue()
+ *
+ * @example
+ * const object = { keyA: 'valueA', keyB: 42 };
+ * faker.random.objectElement(object) // 42
+ * faker.random.objectElement(object, 'key') // 'keyB'
+ * faker.random.objectElement(object, 'value') // 'valueA'
+ *
+ * @deprecated
+ */
+ objectElement<T extends Record<string, unknown>, K extends keyof T>(
+ object?: T,
+ field?: 'key' | 'value'
+ ): K | T[K];
+ /**
+ * Returns a random key or value from given object.
+ *
+ * @template T The type of `Record` to pick from.
+ * @template K The keys of `T`.
+ * @param object The object to get the keys or values from.
+ * @param field If this is set to `'key'`, this method will a return a random key of the given instance.
+ * If this is set to `'value'`, this method will a return a random value of the given instance.
+ * Defaults to `'value'`.
+ *
+ * @see faker.helpers.objectKey()
+ * @see faker.helpers.objectValue()
+ *
+ * @example
+ * const object = { keyA: 'valueA', keyB: 42 };
+ * faker.random.objectElement(object) // 42
+ * faker.random.objectElement(object, 'key') // 'keyB'
+ * faker.random.objectElement(object, 'value') // 'valueA'
+ *
+ * @deprecated
+ */
+ objectElement<T extends Record<string, unknown>, K extends keyof T>(
+ object: T = { foo: 'bar', too: 'car' } as unknown as T,
+ field: 'key' | 'value' = 'value'
+ ): K | T[K] {
+ const useKey = field === 'key';
+ deprecated({
+ deprecated: `faker.random.objectElement(${useKey ? "obj, 'key'" : ''})`,
+ proposed: `faker.helpers.object${useKey ? 'Key' : 'Value'}()`,
+ since: 'v6.3.0',
+ until: 'v7.0.0',
+ });
+ return field === 'key'
+ ? (this.faker.helpers.objectKey(object) as K)
+ : (this.faker.helpers.objectValue(object) as T[K]);
+ }
+
+ /**
+ * Returns a UUID v4 ([Universally Unique Identifier](https://en.wikipedia.org/wiki/Universally_unique_identifier)).
+ *
+ * @see faker.datatype.uuid()
+ *
+ * @example
+ * faker.random.uuid() // '4136cd0b-d90b-4af7-b485-5d1ded8db252'
+ *
+ * @deprecated
+ */
+ uuid(): string {
+ deprecated({
+ deprecated: 'faker.random.uuid()',
+ proposed: 'faker.datatype.uuid()',
+ // since: 'v5.0.0', (?)
+ until: 'v7.0.0',
+ });
+ return this.faker.datatype.uuid();
+ }
+
+ /**
+ * Returns the boolean value `true` or `false`.
+ *
+ * @see faker.datatype.boolean()
+ *
+ * @example
+ * faker.random.boolean() // false
+ *
+ * @deprecated
+ */
+ boolean(): boolean {
+ deprecated({
+ deprecated: 'faker.random.boolean()',
+ proposed: 'faker.datatype.boolean()',
+ // since: 'v5.0.0', (?)
+ until: 'v7.0.0',
+ });
+ return this.faker.datatype.boolean();
+ }
+
+ /**
+ * Returns random word.
+ *
+ * @example
+ * faker.random.word() // 'Seamless'
+ */
+ word(): string {
+ const wordMethods = [
+ this.faker.commerce.department,
+ this.faker.commerce.productName,
+ this.faker.commerce.productAdjective,
+ this.faker.commerce.productMaterial,
+ this.faker.commerce.product,
+ this.faker.commerce.color,
+
+ this.faker.company.catchPhraseAdjective,
+ this.faker.company.catchPhraseDescriptor,
+ this.faker.company.catchPhraseNoun,
+ this.faker.company.bsAdjective,
+ this.faker.company.bsBuzz,
+ this.faker.company.bsNoun,
+ this.faker.address.streetSuffix,
+ this.faker.address.county,
+ this.faker.address.country,
+ this.faker.address.state,
+
+ this.faker.finance.accountName,
+ this.faker.finance.transactionType,
+ this.faker.finance.currencyName,
+
+ this.faker.hacker.noun,
+ this.faker.hacker.verb,
+ this.faker.hacker.adjective,
+ this.faker.hacker.ingverb,
+ this.faker.hacker.abbreviation,
+
+ this.faker.name.jobDescriptor,
+ this.faker.name.jobArea,
+ this.faker.name.jobType,
+ ];
+
+ const bannedChars = [
+ '!',
+ '#',
+ '%',
+ '&',
+ '*',
+ ')',
+ '(',
+ '+',
+ '=',
+ '.',
+ '<',
+ '>',
+ '{',
+ '}',
+ '[',
+ ']',
+ ':',
+ ';',
+ "'",
+ '"',
+ '_',
+ '-',
+ ];
+ let result: string;
+
+ do {
+ // randomly pick from the many faker methods that can generate words
+ const randomWordMethod = this.faker.helpers.arrayElement(wordMethods);
+
+ result = randomWordMethod();
+ } while (!result || bannedChars.some((char) => result.includes(char)));
+
+ return this.faker.helpers.arrayElement(result.split(' '));
+ }
+
+ /**
+ * Returns string with set of random words.
+ *
+ * @param count Number of words. Defaults to a random value between `1` and `3`.
+ *
+ * @example
+ * faker.random.words() // 'neural'
+ * faker.random.words(5) // 'copy Handcrafted bus client-server Point'
+ */
+ words(count?: number): string {
+ const words: string[] = [];
+
+ if (count == null) {
+ count = this.faker.datatype.number({ min: 1, max: 3 });
+ }
+
+ for (let i = 0; i < count; i++) {
+ words.push(this.word());
+ }
+
+ return words.join(' ');
+ }
+
+ /**
+ * Returns a random image url.
+ *
+ * @see faker.random.image()
+ *
+ * @example
+ * faker.random.image() // 'http://placeimg.com/640/480/animals'
+ *
+ * @deprecated
+ */
+ image(): string {
+ deprecated({
+ deprecated: 'faker.random.image()',
+ proposed: 'faker.image.image()',
+ // since: 'v5.0.0', (?)
+ until: 'v7.0.0',
+ });
+ return this.faker.image.image();
+ }
+
+ /**
+ * Returns a random locale, that is available in this faker instance.
+ * You can use the returned locale with `faker.setLocale(result)`.
+ *
+ * @example
+ * faker.random.locale() // 'el'
+ */
+ locale(): string {
+ return this.faker.helpers.arrayElement(Object.keys(this.faker.locales));
+ }
+
+ /**
+ * Generating a string consisting of lower/upper alpha characters based on count and upcase options.
+ *
+ * @param options Either the number of characters or an options instance. Defaults to `{ count: 1, upcase: false, bannedChars: [] }`.
+ * @param options.count The number of characters to generate. Defaults to `1`.
+ * @param options.upcase If true, the result will be uppercase. If false, it will be lowercase. Defaults to `false`.
+ * @param options.bannedChars An array with characters to exclude. Defaults to `[]`.
+ *
+ * @example
+ * faker.random.alpha() // 'b'
+ * faker.random.alpha(10) // 'qccrabobaf'
+ * faker.random.alpha({ count: 5, upcase: true, bannedChars: ['a'] }) // 'DTCIC'
+ */
+ // TODO @Shinigami92 2022-02-14: Tests covered `(count, options)`, but they were never typed like that
+ alpha(
+ options:
+ | number
+ | {
+ count?: number;
+ upcase?: boolean;
+ bannedChars?: readonly string[];
+ } = {}
+ ): string {
+ if (typeof options === 'number') {
+ options = {
+ count: options,
+ };
+ }
+ const { count = 1, upcase = false, bannedChars = [] } = options;
+
+ let charsArray = [
+ 'a',
+ 'b',
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ 'g',
+ 'h',
+ 'i',
+ 'j',
+ 'k',
+ 'l',
+ 'm',
+ 'n',
+ 'o',
+ 'p',
+ 'q',
+ 'r',
+ 's',
+ 't',
+ 'u',
+ 'v',
+ 'w',
+ 'x',
+ 'y',
+ 'z',
+ ];
+
+ charsArray = arrayRemove(charsArray, bannedChars);
+
+ let wholeString = '';
+ for (let i = 0; i < count; i++) {
+ wholeString += this.faker.helpers.arrayElement(charsArray);
+ }
+
+ return upcase ? wholeString.toUpperCase() : wholeString;
+ }
+
+ /**
+ * Generating a string consisting of lower/upper alpha characters and digits based on count and upcase options.
+ *
+ * @param count The number of characters and digits to generate. Defaults to `1`.
+ * @param options The options to use. Defaults to `{ bannedChars: [] }`.
+ * @param options.bannedChars An array of characters and digits which should be banned in the generated string. Defaults to `[]`.
+ *
+ * @example
+ * faker.random.alphaNumeric() // '2'
+ * faker.random.alphaNumeric(5) // '3e5v7'
+ * faker.random.alphaNumeric(5, { bannedChars: ["a"] }) // 'xszlm'
+ */
+ alphaNumeric(
+ count: number = 1,
+ options: { bannedChars?: readonly string[] } = {}
+ ): string {
+ const { bannedChars = [] } = options;
+
+ let charsArray = [
+ '0',
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ 'a',
+ 'b',
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ 'g',
+ 'h',
+ 'i',
+ 'j',
+ 'k',
+ 'l',
+ 'm',
+ 'n',
+ 'o',
+ 'p',
+ 'q',
+ 'r',
+ 's',
+ 't',
+ 'u',
+ 'v',
+ 'w',
+ 'x',
+ 'y',
+ 'z',
+ ];
+
+ charsArray = arrayRemove(charsArray, bannedChars);
+
+ if (charsArray.length === 0) {
+ throw new FakerError(
+ 'Unable to generate string, because all possible characters are banned.'
+ );
+ }
+
+ let wholeString = '';
+ for (let i = 0; i < count; i++) {
+ wholeString += this.faker.helpers.arrayElement(charsArray);
+ }
+
+ return wholeString;
+ }
+
+ /**
+ * Generates a given length string of digits.
+ *
+ * @param length The number of digits to generate. Defaults to `1`.
+ * @param options The options to use. Defaults to `{}`.
+ * @param options.allowLeadingZeros If true, leading zeros will be allowed. Defaults to `false`.
+ * @param options.bannedDigits An array of digits which should be banned in the generated string. Defaults to `[]`.
+ *
+ * @example
+ * faker.random.numeric() // '2'
+ * faker.random.numeric(5) // '31507'
+ * faker.random.numeric(42) // '56434563150765416546479875435481513188548'
+ * faker.random.numeric(42, { allowLeadingZeros: true }) // '00564846278453876543517840713421451546115'
+ * faker.random.numeric(6, { bannedDigits: ['0'] }) // '943228'
+ */
+ numeric(
+ length: number = 1,
+ options: {
+ allowLeadingZeros?: boolean;
+ bannedDigits?: readonly string[];
+ } = {}
+ ): string {
+ if (length <= 0) {
+ return '';
+ }
+
+ const { allowLeadingZeros = false, bannedDigits = [] } = options;
+
+ const allowedDigits = '0123456789'
+ .split('')
+ .filter((digit) => !bannedDigits.includes(digit));
+
+ if (
+ allowedDigits.length === 0 ||
+ (allowedDigits.length === 1 &&
+ !allowLeadingZeros &&
+ allowedDigits[0] === '0')
+ ) {
+ throw new FakerError(
+ 'Unable to generate numeric string, because all possible digits are banned.'
+ );
+ }
+
+ let result = '';
+
+ if (!allowLeadingZeros && !bannedDigits.includes('0')) {
+ result += this.faker.helpers.arrayElement(
+ allowedDigits.filter((digit) => digit !== '0')
+ );
+ }
+
+ while (result.length < length) {
+ result += this.faker.helpers.arrayElement(allowedDigits);
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns a hexadecimal number.
+ *
+ * @param count Length of the generated number. Defaults to `1`.
+ *
+ * @see faker.datatype.hexadecimal()
+ *
+ * @example
+ * faker.random.hexaDecimal() // '0xb'
+ * faker.random.hexaDecimal(10) // '0xaE13F044fb'
+ *
+ * @deprecated
+ */
+ hexaDecimal(count?: number): string {
+ deprecated({
+ deprecated: 'faker.random.hexaDecimal()',
+ proposed: 'faker.datatype.hexadecimal()',
+ // since: 'v5.0.0', (?)
+ until: 'v7.0.0',
+ });
+
+ return this.faker.datatype.hexadecimal(count);
+ }
+}
diff --git a/src/modules/system/index.ts b/src/modules/system/index.ts
new file mode 100644
index 00000000..250f1fb8
--- /dev/null
+++ b/src/modules/system/index.ts
@@ -0,0 +1,194 @@
+import type { Faker } from '../..';
+
+const commonFileTypes = ['video', 'audio', 'image', 'text', 'application'];
+
+const commonMimeTypes = [
+ 'application/pdf',
+ 'audio/mpeg',
+ 'audio/wav',
+ 'image/png',
+ 'image/jpeg',
+ 'image/gif',
+ 'video/mp4',
+ 'video/mpeg',
+ 'text/html',
+];
+
+/**
+ * Converts the given set to an array.
+ *
+ * @param set The set to convert.
+ */
+// TODO ST-DDT 2022-03-11: Replace with Array.from(Set)
+function setToArray<T>(set: Set<T>): T[] {
+ // shortcut if Array.from is available
+ if (Array.from) {
+ return Array.from(set);
+ }
+
+ const array: T[] = [];
+ set.forEach((item) => {
+ array.push(item);
+ });
+ return array;
+}
+
+/**
+ * Generates fake data for many computer systems properties.
+ */
+export class System {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(System.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Returns a random file name with extension.
+ *
+ * @example
+ * faker.system.fileName() // 'self_enabling_accountability_toys.kpt'
+ */
+ fileName(): string {
+ const str = this.faker.random.words().toLowerCase().replace(/\W/g, '_');
+
+ return `${str}.${this.fileExt()}`;
+ }
+
+ /**
+ * Returns a random file name with a given extension or a commonly used extension.
+ *
+ * @param ext Extension. Empty string is considered to be not set.
+ * @example
+ * faker.system.commonFileName() // 'dollar.jpg'
+ * faker.system.commonFileName('txt') // 'global_borders_wyoming.txt'
+ */
+ commonFileName(ext?: string): string {
+ const str = this.faker.random.words().toLowerCase().replace(/\W/g, '_');
+
+ return `${str}.${ext || this.commonFileExt()}`;
+ }
+
+ /**
+ * Returns a mime-type.
+ *
+ * @example
+ * faker.system.mimeType() // 'video/vnd.vivo'
+ */
+ mimeType(): string {
+ const mimeTypeKeys = Object.keys(this.faker.definitions.system.mimeTypes);
+
+ return this.faker.helpers.arrayElement(mimeTypeKeys);
+ }
+
+ /**
+ * Returns a commonly used file type.
+ *
+ * @example
+ * faker.system.commonFileType() // 'audio'
+ */
+ commonFileType(): string {
+ return this.faker.helpers.arrayElement(commonFileTypes);
+ }
+
+ /**
+ * Returns a commonly used file extension.
+ *
+ * @example
+ * faker.system.commonFileExt() // 'gif'
+ */
+ commonFileExt(): string {
+ return this.fileExt(this.faker.helpers.arrayElement(commonMimeTypes));
+ }
+
+ /**
+ * Returns a file type.
+ *
+ * @example
+ * faker.system.fileType() // 'message'
+ */
+ fileType(): string {
+ const typeSet = new Set<string>();
+ const mimeTypes = this.faker.definitions.system.mimeTypes;
+
+ Object.keys(mimeTypes).forEach((m) => {
+ const type = m.split('/')[0];
+
+ typeSet.add(type);
+ });
+
+ const types = setToArray(typeSet);
+ return this.faker.helpers.arrayElement(types);
+ }
+
+ /**
+ * Returns a file extension.
+ *
+ * @param mimeType Valid [mime-type](https://github.com/jshttp/mime-db/blob/master/db.json)
+ *
+ * @example
+ * faker.system.fileExt() // 'emf'
+ * faker.system.fileExt('application/json') // 'json'
+ */
+ fileExt(mimeType?: string): string {
+ if (typeof mimeType === 'string') {
+ const mimes = this.faker.definitions.system.mimeTypes;
+ return this.faker.helpers.arrayElement(mimes[mimeType].extensions);
+ }
+
+ const mimeTypes = this.faker.definitions.system.mimeTypes;
+ const extensionSet = new Set<string>();
+
+ Object.keys(mimeTypes).forEach((m) => {
+ if (mimeTypes[m].extensions instanceof Array) {
+ mimeTypes[m].extensions.forEach((ext) => {
+ extensionSet.add(ext);
+ });
+ }
+ });
+
+ const extensions = setToArray(extensionSet);
+
+ return this.faker.helpers.arrayElement(extensions);
+ }
+
+ /**
+ * Returns a directory path.
+ *
+ * @example
+ * faker.system.directoryPath() // '/etc/mail'
+ */
+ directoryPath(): string {
+ const paths = this.faker.definitions.system.directoryPaths;
+ return this.faker.helpers.arrayElement(paths);
+ }
+
+ /**
+ * Returns a file path.
+ *
+ * @example
+ * faker.system.filePath() // '/usr/local/src/money.dotx'
+ */
+ // TODO @prisis 2022-01-25: add a parameter to have the possibility to have one or two ext on file.
+ filePath(): string {
+ return `${this.directoryPath()}/${this.fileName()}`;
+ }
+
+ /**
+ * Returns a [semantic version](https://semver.org).
+ *
+ * @example
+ * faker.system.semver() // '1.1.2'
+ */
+ semver(): string {
+ return [
+ this.faker.datatype.number(9),
+ this.faker.datatype.number(9),
+ this.faker.datatype.number(9),
+ ].join('.');
+ }
+}
diff --git a/src/modules/time/index.ts b/src/modules/time/index.ts
new file mode 100644
index 00000000..021d75c8
--- /dev/null
+++ b/src/modules/time/index.ts
@@ -0,0 +1,57 @@
+import { deprecated } from '../../internal/deprecated';
+import type { LiteralUnion } from '../../utils/types';
+
+/**
+ * Module to generate time of dates in various formats.
+ *
+ * @deprecated You should stop using this module, as it will be removed in the future.
+ */
+export class Time {
+ /**
+ * Returns recent time.
+ *
+ * @param format The format to use.
+ *
+ * - `'abbr'` Return a string with only the time. `Date.toLocaleTimeString`.
+ * - `'date'` Return a date instance.
+ * - `'wide'` Return a string with a long time. `Date.toTimeString()`.
+ * - `'unix'` Returns a unix timestamp.
+ *
+ * Defaults to `'unix'`.
+ *
+ * @example
+ * faker.time.recent() // 1643067231856
+ * faker.time.recent('abbr') // '12:34:07 AM'
+ * faker.time.recent('date') // 2022-03-01T20:35:47.402Z
+ * faker.time.recent('wide') // '00:34:11 GMT+0100 (Central European Standard Time)'
+ * faker.time.recent('unix') // 1643067231856
+ *
+ * @deprecated You should stop using this function, as it will be removed in the future. Use the native `new Date()` with one of the wanted functions directly.
+ */
+ recent(
+ format: LiteralUnion<'abbr' | 'date' | 'wide' | 'unix'> = 'unix'
+ ): string | number | Date {
+ deprecated({
+ deprecated: 'faker.time.recent()',
+ proposed: 'native `new Date()` and call the function you want on it',
+ since: 'v6.1.0',
+ until: 'v7.0.0',
+ });
+
+ let date: string | number | Date = new Date();
+
+ switch (format) {
+ case 'abbr':
+ date = date.toLocaleTimeString();
+ break;
+ case 'wide':
+ date = date.toTimeString();
+ break;
+ case 'unix':
+ date = date.getTime();
+ break;
+ }
+
+ return date;
+ }
+}
diff --git a/src/modules/unique/index.ts b/src/modules/unique/index.ts
new file mode 100644
index 00000000..798fc29e
--- /dev/null
+++ b/src/modules/unique/index.ts
@@ -0,0 +1,139 @@
+import { deprecated } from '../../internal/deprecated';
+import type { RecordKey } from './unique';
+import * as uniqueExec from './unique';
+
+/**
+ * Module to generate unique entries.
+ */
+export class Unique {
+ /**
+ * Maximum time `unique.exec` will attempt to run before aborting.
+ *
+ * @deprecated Use options instead.
+ */
+ private _maxTime = 10;
+
+ /**
+ * Maximum time `unique.exec` will attempt to run before aborting.
+ *
+ * @deprecated Use options instead.
+ */
+ get maxTime(): number {
+ deprecated({
+ deprecated: 'faker.unique.maxTime',
+ proposed: 'Options',
+ since: 'v6.2.0',
+ until: 'v7.0.0',
+ });
+ return this._maxTime;
+ }
+
+ /**
+ * Maximum time `unique.exec` will attempt to run before aborting.
+ *
+ * @deprecated Use options instead.
+ */
+ set maxTime(value: number) {
+ deprecated({
+ deprecated: 'faker.unique.maxTime',
+ proposed: 'Options',
+ since: 'v6.2.0',
+ until: 'v7.0.0',
+ });
+ this._maxTime = value;
+ }
+
+ /**
+ * Maximum retries `unique.exec` will recurse before aborting (max loop depth).
+ *
+ * @deprecated Use options instead.
+ */
+ private _maxRetries = 10;
+
+ /**
+ * Maximum retries `unique.exec` will recurse before aborting (max loop depth).
+ *
+ * @deprecated Use options instead.
+ */
+ get maxRetries(): number {
+ deprecated({
+ deprecated: 'faker.unique.maxRetries',
+ proposed: 'Options',
+ since: 'v6.2.0',
+ until: 'v7.0.0',
+ });
+ return this._maxRetries;
+ }
+
+ /**
+ * Maximum retries `unique.exec` will recurse before aborting (max loop depth).
+ *
+ * @deprecated Use options instead.
+ */
+ set maxRetries(value: number) {
+ deprecated({
+ deprecated: 'faker.unique.maxRetries',
+ proposed: 'Options',
+ since: 'v6.2.0',
+ until: 'v7.0.0',
+ });
+ this._maxRetries = value;
+ }
+
+ constructor() {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Unique.prototype)) {
+ if (
+ name === 'constructor' ||
+ name === 'maxTime' ||
+ name === 'maxRetries' ||
+ typeof this[name] !== 'function'
+ ) {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Generates a unique result using the results of the given method.
+ * Used unique entries will be stored internally and filtered from subsequent calls.
+ *
+ * @template Method The type of the method to execute.
+ * @param method The method used to generate the values.
+ * @param args The arguments used to call the method.
+ * @param options The optional options used to configure this method.
+ * @param options.startTime This parameter does nothing.
+ * @param options.maxTime The time in milliseconds this method may take before throwing an error. Defaults to `50`.
+ * @param options.maxRetries The total number of attempts to try before throwing an error. Defaults to `50`.
+ * @param options.currentIterations This parameter does nothing.
+ * @param options.exclude The value or values that should be excluded/skipped. Defaults to `[]`.
+ * @param options.compare The function used to determine whether a value was already returned. Defaults to check the existence of the key.
+ * @param options.store The store of unique entries. Defaults to a global store.
+ *
+ * @example
+ * faker.unique(faker.name.firstName) // 'Corbin'
+ */
+ unique<Method extends (...parameters) => RecordKey>(
+ method: Method,
+ args?: Parameters<Method>,
+ options: {
+ startTime?: number;
+ maxTime?: number;
+ maxRetries?: number;
+ currentIterations?: number;
+ exclude?: RecordKey | RecordKey[];
+ compare?: (obj: Record<RecordKey, RecordKey>, key: RecordKey) => 0 | -1;
+ store?: Record<RecordKey, RecordKey>;
+ } = {}
+ ): ReturnType<Method> {
+ const { maxTime = this._maxTime, maxRetries = this._maxRetries } = options;
+ return uniqueExec.exec(method, args, {
+ ...options,
+ startTime: new Date().getTime(),
+ maxTime,
+ maxRetries,
+ currentIterations: 0,
+ });
+ }
+}
diff --git a/src/modules/unique/unique.ts b/src/modules/unique/unique.ts
new file mode 100644
index 00000000..70408faf
--- /dev/null
+++ b/src/modules/unique/unique.ts
@@ -0,0 +1,158 @@
+import { FakerError } from '../../errors/faker-error';
+
+export type RecordKey = string | number | symbol;
+
+/**
+ * Global store of unique values.
+ * This means that faker should *never* return duplicate values across all API methods when using `Faker.unique` without passing `options.store`.
+ */
+const GLOBAL_UNIQUE_STORE: Record<RecordKey, RecordKey> = {};
+
+/**
+ * Global exclude list of results.
+ * Defaults to nothing excluded.
+ */
+const GLOBAL_UNIQUE_EXCLUDE: RecordKey[] = [];
+
+/**
+ * Uniqueness compare function.
+ * Default behavior is to check value as key against object hash.
+ *
+ * @param obj The object to check.
+ * @param key The key to check.
+ */
+function defaultCompare(
+ obj: Record<RecordKey, RecordKey>,
+ key: RecordKey
+): 0 | -1 {
+ if (obj[key] === undefined) {
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Logs the given code as an error and throws it.
+ * Also logs a message for helping the user.
+ *
+ * @param startTime The time the execution started.
+ * @param now The current time.
+ * @param code The error code.
+ * @param store The store of unique entries.
+ * @param currentIterations Current iteration or retries of `unique.exec` (current loop depth).
+ *
+ * @throws The given error code with additional text.
+ */
+function errorMessage(
+ startTime: number,
+ now: number,
+ code: string,
+ store: Record<RecordKey, RecordKey>,
+ currentIterations: number
+): never {
+ console.error('Error', code);
+ console.log(
+ `Found ${Object.keys(store).length} unique entries before throwing error.
+retried: ${currentIterations}
+total time: ${now - startTime}ms`
+ );
+ throw new FakerError(
+ `${code} for uniqueness check.
+
+May not be able to generate any more unique values with current settings.
+Try adjusting maxTime or maxRetries parameters for faker.unique().`
+ );
+}
+
+/**
+ * Generates a unique result using the results of the given method.
+ * Used unique entries will be stored internally and filtered from subsequent calls.
+ *
+ * @template Method The type of the method to execute.
+ * @param method The method used to generate the values.
+ * @param args The arguments used to call the method.
+ * @param options The optional options used to configure this method.
+ * @param options.startTime The time this execution stared. Defaults to `new Date().getTime()`.
+ * @param options.maxTime The time in milliseconds this method may take before throwing an error. Defaults to `50`.
+ * @param options.maxRetries The total number of attempts to try before throwing an error. Defaults to `50`.
+ * @param options.currentIterations The current attempt. Defaults to `0`.
+ * @param options.exclude The value or values that should be excluded/skipped. Defaults to `[]`.
+ * @param options.compare The function used to determine whether a value was already returned. Defaults to check the existence of the key.
+ * @param options.store The store of unique entries. Defaults to `GLOBAL_UNIQUE_STORE`.
+ */
+export function exec<Method extends (...parameters) => RecordKey>(
+ method: Method,
+ args: Parameters<Method>,
+ options: {
+ startTime?: number;
+ maxTime?: number;
+ maxRetries?: number;
+ currentIterations?: number;
+ exclude?: RecordKey | RecordKey[];
+ compare?: (obj: Record<RecordKey, RecordKey>, key: RecordKey) => 0 | -1;
+ store?: Record<RecordKey, RecordKey>;
+ } = {}
+): ReturnType<Method> {
+ const now = new Date().getTime();
+
+ const {
+ startTime = new Date().getTime(),
+ maxTime = 50,
+ maxRetries = 50,
+ compare = defaultCompare,
+ store = GLOBAL_UNIQUE_STORE,
+ } = options;
+ let { exclude = GLOBAL_UNIQUE_EXCLUDE } = options;
+ options.currentIterations = options.currentIterations ?? 0;
+
+ // Support single exclude argument as string
+ if (!Array.isArray(exclude)) {
+ exclude = [exclude];
+ }
+
+ // if (options.currentIterations > 0) {
+ // console.log('iterating', options.currentIterations)
+ // }
+
+ // console.log(now - startTime)
+ if (now - startTime >= maxTime) {
+ return errorMessage(
+ startTime,
+ now,
+ `Exceeded maxTime: ${maxTime}`,
+ store,
+ options.currentIterations
+ );
+ }
+
+ if (options.currentIterations >= maxRetries) {
+ return errorMessage(
+ startTime,
+ now,
+ `Exceeded maxRetries: ${maxRetries}`,
+ store,
+ options.currentIterations
+ );
+ }
+
+ // Execute the provided method to find a potential satisfied value.
+ const result: ReturnType<Method> = method.apply(this, args);
+
+ // If the result has not been previously found, add it to the found array and return the value as it's unique.
+ if (compare(store, result) === -1 && exclude.indexOf(result) === -1) {
+ store[result] = result;
+ options.currentIterations = 0;
+ return result;
+ } else {
+ // console.log('conflict', result);
+ options.currentIterations++;
+ return exec(method, args, {
+ ...options,
+ startTime,
+ maxTime,
+ maxRetries,
+ compare,
+ exclude,
+ });
+ }
+}
diff --git a/src/modules/vehicle/index.ts b/src/modules/vehicle/index.ts
new file mode 100644
index 00000000..ec010af9
--- /dev/null
+++ b/src/modules/vehicle/index.ts
@@ -0,0 +1,131 @@
+import type { Faker } from '../..';
+
+/**
+ * Module to generate vehicle related entries.
+ */
+export class Vehicle {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Vehicle.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Returns a random vehicle.
+ *
+ * @example
+ * faker.vehicle.vehicle() // 'BMW Explorer'
+ */
+ vehicle(): string {
+ return `${this.manufacturer()} ${this.model()}`;
+ }
+
+ /**
+ * Returns a manufacturer name.
+ *
+ * @example
+ * faker.vehicle.manufacturer() // 'Ford'
+ */
+ manufacturer(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.vehicle.manufacturer
+ );
+ }
+
+ /**
+ * Returns a vehicle model.
+ *
+ * @example
+ * faker.vehicle.model() // 'Explorer'
+ */
+ model(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.vehicle.model
+ );
+ }
+
+ /**
+ * Returns a vehicle type.
+ *
+ * @example
+ * faker.vehicle.type() // 'Coupe'
+ */
+ type(): string {
+ return this.faker.helpers.arrayElement(this.faker.definitions.vehicle.type);
+ }
+
+ /**
+ * Returns a fuel type.
+ *
+ * @example
+ * faker.vehicle.fuel() // 'Electric'
+ */
+ fuel(): string {
+ return this.faker.helpers.arrayElement(this.faker.definitions.vehicle.fuel);
+ }
+
+ /**
+ * Returns a vehicle identification number (VIN).
+ *
+ * @example
+ * faker.vehicle.vin() // 'YV1MH682762184654'
+ */
+ vin(): string {
+ const bannedChars = ['o', 'i', 'q'];
+ return `${this.faker.random.alphaNumeric(10, {
+ bannedChars,
+ })}${this.faker.random.alpha({
+ count: 1,
+ upcase: true,
+ bannedChars,
+ })}${this.faker.random.alphaNumeric(1, {
+ bannedChars,
+ })}${this.faker.datatype.number({ min: 10000, max: 99999 })}` // return five digit #
+ .toUpperCase();
+ }
+
+ /**
+ * Returns a vehicle color.
+ *
+ * @example
+ * faker.vehicle.color() // 'red'
+ */
+ color(): string {
+ return this.faker.commerce.color();
+ }
+
+ /**
+ * Returns a vehicle registration number (Vehicle Registration Mark - VRM)
+ *
+ * @example
+ * faker.vehicle.vrm() // 'MF56UPA'
+ */
+ vrm(): string {
+ return `${this.faker.random.alpha({
+ count: 2,
+ upcase: true,
+ })}${this.faker.datatype.number({
+ min: 0,
+ max: 9,
+ })}${this.faker.datatype.number({
+ min: 0,
+ max: 9,
+ })}${this.faker.random.alpha({ count: 3, upcase: true })}`.toUpperCase();
+ }
+
+ /**
+ * Returns a type of bicycle.
+ *
+ * @example
+ * faker.vehicle.bicycle() // 'Adventure Road Bicycle'
+ */
+ bicycle(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.vehicle.bicycle_type
+ );
+ }
+}
diff --git a/src/modules/word/index.ts b/src/modules/word/index.ts
new file mode 100644
index 00000000..5968d225
--- /dev/null
+++ b/src/modules/word/index.ts
@@ -0,0 +1,174 @@
+import type { Faker } from '../..';
+
+/**
+ * Filters a string array for values with a specific length.
+ * If length is not provided or no values with this length there found a copy of the original array is returned.
+ *
+ * @param options The options to provide
+ * @param options.wordList A list of word to filter
+ * @param options.length The exact length words should have
+ */
+function filterWordListByLength(options: {
+ wordList: string[];
+ length?: number;
+}): string[] {
+ if (!options.length) {
+ return options.wordList;
+ }
+
+ const wordListWithLengthFilter = options.wordList.filter(
+ (word) => word.length === options.length
+ );
+
+ return wordListWithLengthFilter.length > 0
+ ? wordListWithLengthFilter
+ : [...options.wordList];
+}
+
+/**
+ * Module to return various types of words.
+ */
+export class Word {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Word.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Returns an adjective of random or optionally specified length.
+ *
+ * @param length Expected adjective length. If specified length is unresolvable, returns adjective of a random length.
+ *
+ * @example
+ * faker.word.adjective() // 'pungent'
+ * faker.word.adjective(5) // 'slimy'
+ * faker.word.adjective(100) // 'complete'
+ */
+ adjective(length?: number): string {
+ return this.faker.helpers.arrayElement(
+ filterWordListByLength({
+ wordList: this.faker.definitions.word.adjective,
+ length,
+ })
+ );
+ }
+
+ /**
+ * Returns an adverb of random or optionally specified length.
+ *
+ * @param length Expected adverb length. If specified length is unresolvable, returns adverb of a random length.
+ *
+ * @example
+ * faker.word.adverb() // 'quarrelsomely'
+ * faker.word.adverb(5) // 'madly'
+ * faker.word.adverb(100) // 'sadly'
+ */
+ adverb(length?: number): string {
+ return this.faker.helpers.arrayElement(
+ filterWordListByLength({
+ wordList: this.faker.definitions.word.adverb,
+ length,
+ })
+ );
+ }
+
+ /**
+ * Returns a conjunction of random or optionally specified length.
+ *
+ * @param length Expected conjunction length. If specified length is unresolvable, returns conjunction of a random length.
+ *
+ * @example
+ * faker.word.conjunction() // 'in order that'
+ * faker.word.conjunction(5) // 'since'
+ * faker.word.conjunction(100) // 'as long as'
+ */
+ conjunction(length?: number): string {
+ return this.faker.helpers.arrayElement(
+ filterWordListByLength({
+ wordList: this.faker.definitions.word.conjunction,
+ length,
+ })
+ );
+ }
+
+ /**
+ * Returns an interjection of random or optionally specified length.
+ *
+ * @param length Expected interjection length. If specified length is unresolvable, returns interjection of a random length.
+ *
+ * @example
+ * faker.word.interjection() // 'gah'
+ * faker.word.interjection(5) // 'fooey'
+ * faker.word.interjection(100) // 'yowza'
+ */
+ interjection(length?: number): string {
+ return this.faker.helpers.arrayElement(
+ filterWordListByLength({
+ wordList: this.faker.definitions.word.interjection,
+ length,
+ })
+ );
+ }
+
+ /**
+ * Returns a noun of random or optionally specified length.
+ *
+ * @param length Expected noun length. If specified length is unresolvable, returns noun of a random length.
+ *
+ * @example
+ * faker.word.noun() // 'external'
+ * faker.word.noun(5) // 'front'
+ * faker.word.noun(100) // 'care'
+ */
+ noun(length?: number): string {
+ return this.faker.helpers.arrayElement(
+ filterWordListByLength({
+ wordList: this.faker.definitions.word.noun,
+ length,
+ })
+ );
+ }
+
+ /**
+ * Returns a preposition of random or optionally specified length.
+ *
+ * @param length Expected preposition length. If specified length is unresolvable, returns preposition of a random length.
+ *
+ * @example
+ * faker.word.preposition() // 'without'
+ * faker.word.preposition(5) // 'abaft'
+ * faker.word.preposition(100) // 'an'
+ */
+ preposition(length?: number): string {
+ return this.faker.helpers.arrayElement(
+ filterWordListByLength({
+ wordList: this.faker.definitions.word.preposition,
+ length,
+ })
+ );
+ }
+
+ /**
+ * Returns a verb of random or optionally specified length.
+ *
+ * @param length Expected verb length. If specified length is unresolvable, returns verb of a random length.
+ *
+ * @example
+ * faker.word.verb() // 'act'
+ * faker.word.verb(5) // 'tinge'
+ * faker.word.verb(100) // 'mess'
+ */
+ verb(length?: number): string {
+ return this.faker.helpers.arrayElement(
+ filterWordListByLength({
+ wordList: this.faker.definitions.word.verb,
+ length,
+ })
+ );
+ }
+}