From a2da7c496e9a3741d165ddfe6128b50837fec361 Mon Sep 17 00:00:00 2001 From: Shinigami Date: Tue, 3 May 2022 15:48:20 +0200 Subject: refactor!: reorganize src folder (#909) --- src/address.ts | 488 ---------- src/animal.ts | 164 ---- src/commerce.ts | 133 --- src/company.ts | 153 --- src/database.ts | 75 -- src/datatype.ts | 305 ------ src/date.ts | 256 ----- src/definitions/internet.ts | 2 +- src/fake.ts | 134 --- src/faker.ts | 56 +- src/finance.ts | 436 --------- src/git.ts | 134 --- src/hacker.ts | 94 -- src/helpers.ts | 810 ---------------- src/image.ts | 345 ------- src/image_providers/lorempicsum.ts | 126 --- src/image_providers/lorempixel.ts | 288 ------ src/image_providers/unsplash.ts | 157 --- src/index.ts | 4 +- src/internet.ts | 458 --------- src/lorem.ts | 205 ---- src/mersenne.ts | 73 -- src/modules/address/index.ts | 488 ++++++++++ src/modules/animal/index.ts | 164 ++++ src/modules/commerce/index.ts | 133 +++ src/modules/company/index.ts | 153 +++ src/modules/database/index.ts | 75 ++ src/modules/datatype/index.ts | 305 ++++++ src/modules/date/index.ts | 256 +++++ src/modules/fake/index.ts | 134 +++ src/modules/finance/iban.ts | 1414 ++++++++++++++++++++++++++++ src/modules/finance/index.ts | 436 +++++++++ src/modules/git/index.ts | 134 +++ src/modules/hacker/index.ts | 94 ++ src/modules/helpers/index.ts | 810 ++++++++++++++++ src/modules/image/index.ts | 345 +++++++ src/modules/image/providers/lorempicsum.ts | 126 +++ src/modules/image/providers/lorempixel.ts | 288 ++++++ src/modules/image/providers/unsplash.ts | 157 +++ src/modules/internet/index.ts | 458 +++++++++ src/modules/internet/user-agent.ts | 345 +++++++ src/modules/lorem/index.ts | 205 ++++ src/modules/mersenne/index.ts | 73 ++ src/modules/mersenne/twister.ts | 320 +++++++ src/modules/music/index.ts | 26 + src/modules/name/index.ts | 350 +++++++ src/modules/phone/index.ts | 76 ++ src/modules/random/index.ts | 648 +++++++++++++ src/modules/system/index.ts | 194 ++++ src/modules/time/index.ts | 57 ++ src/modules/unique/index.ts | 139 +++ src/modules/unique/unique.ts | 158 ++++ src/modules/vehicle/index.ts | 131 +++ src/modules/word/index.ts | 174 ++++ src/music.ts | 26 - src/name.ts | 350 ------- src/phone.ts | 76 -- src/random.ts | 648 ------------- src/system.ts | 194 ---- src/time.ts | 57 -- src/unique.ts | 139 --- src/utils/iban.ts | 1414 ---------------------------- src/utils/mersenne.ts | 320 ------- src/utils/types.ts | 9 + src/utils/unique.ts | 158 ---- src/utils/user-agent.ts | 345 ------- src/vehicle.ts | 131 --- src/word.ts | 174 ---- 68 files changed, 8904 insertions(+), 8899 deletions(-) delete mode 100644 src/address.ts delete mode 100644 src/animal.ts delete mode 100644 src/commerce.ts delete mode 100644 src/company.ts delete mode 100644 src/database.ts delete mode 100644 src/datatype.ts delete mode 100644 src/date.ts delete mode 100644 src/fake.ts delete mode 100644 src/finance.ts delete mode 100644 src/git.ts delete mode 100644 src/hacker.ts delete mode 100644 src/helpers.ts delete mode 100644 src/image.ts delete mode 100644 src/image_providers/lorempicsum.ts delete mode 100644 src/image_providers/lorempixel.ts delete mode 100644 src/image_providers/unsplash.ts delete mode 100644 src/internet.ts delete mode 100644 src/lorem.ts delete mode 100644 src/mersenne.ts create mode 100644 src/modules/address/index.ts create mode 100644 src/modules/animal/index.ts create mode 100644 src/modules/commerce/index.ts create mode 100644 src/modules/company/index.ts create mode 100644 src/modules/database/index.ts create mode 100644 src/modules/datatype/index.ts create mode 100644 src/modules/date/index.ts create mode 100644 src/modules/fake/index.ts create mode 100644 src/modules/finance/iban.ts create mode 100644 src/modules/finance/index.ts create mode 100644 src/modules/git/index.ts create mode 100644 src/modules/hacker/index.ts create mode 100644 src/modules/helpers/index.ts create mode 100644 src/modules/image/index.ts create mode 100644 src/modules/image/providers/lorempicsum.ts create mode 100644 src/modules/image/providers/lorempixel.ts create mode 100644 src/modules/image/providers/unsplash.ts create mode 100644 src/modules/internet/index.ts create mode 100644 src/modules/internet/user-agent.ts create mode 100644 src/modules/lorem/index.ts create mode 100644 src/modules/mersenne/index.ts create mode 100644 src/modules/mersenne/twister.ts create mode 100644 src/modules/music/index.ts create mode 100644 src/modules/name/index.ts create mode 100644 src/modules/phone/index.ts create mode 100644 src/modules/random/index.ts create mode 100644 src/modules/system/index.ts create mode 100644 src/modules/time/index.ts create mode 100644 src/modules/unique/index.ts create mode 100644 src/modules/unique/unique.ts create mode 100644 src/modules/vehicle/index.ts create mode 100644 src/modules/word/index.ts delete mode 100644 src/music.ts delete mode 100644 src/name.ts delete mode 100644 src/phone.ts delete mode 100644 src/random.ts delete mode 100644 src/system.ts delete mode 100644 src/time.ts delete mode 100644 src/unique.ts delete mode 100644 src/utils/iban.ts delete mode 100644 src/utils/mersenne.ts delete mode 100644 src/utils/unique.ts delete mode 100644 src/utils/user-agent.ts delete mode 100644 src/vehicle.ts delete mode 100644 src/word.ts (limited to 'src') diff --git a/src/address.ts b/src/address.ts deleted file mode 100644 index e077acaa..00000000 --- a/src/address.ts +++ /dev/null @@ -1,488 +0,0 @@ -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/animal.ts b/src/animal.ts deleted file mode 100644 index 6a1d10a2..00000000 --- a/src/animal.ts +++ /dev/null @@ -1,164 +0,0 @@ -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/commerce.ts b/src/commerce.ts deleted file mode 100644 index 754fe73a..00000000 --- a/src/commerce.ts +++ /dev/null @@ -1,133 +0,0 @@ -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/company.ts b/src/company.ts deleted file mode 100644 index c2d72260..00000000 --- a/src/company.ts +++ /dev/null @@ -1,153 +0,0 @@ -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/database.ts b/src/database.ts deleted file mode 100644 index 770b4b04..00000000 --- a/src/database.ts +++ /dev/null @@ -1,75 +0,0 @@ -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/datatype.ts b/src/datatype.ts deleted file mode 100644 index 0984779b..00000000 --- a/src/datatype.ts +++ /dev/null @@ -1,305 +0,0 @@ -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":"%'77"}` - */ - json(): string { - const properties = ['foo', 'bar', 'bike', 'a', 'b', 'name', 'prop']; - const returnObject: Record = {}; - - 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 { - return Array.from({ 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/date.ts b/src/date.ts deleted file mode 100644 index bb65ce4e..00000000 --- a/src/date.ts +++ /dev/null @@ -1,256 +0,0 @@ -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/definitions/internet.ts b/src/definitions/internet.ts index 3687229f..e81871f6 100644 --- a/src/definitions/internet.ts +++ b/src/definitions/internet.ts @@ -1,4 +1,4 @@ -import type { EmojiType } from '../internet'; +import type { EmojiType } from '../modules/internet'; /** * The possible definitions related to internet stuff. diff --git a/src/fake.ts b/src/fake.ts deleted file mode 100644 index 4b6bc788..00000000 --- a/src/fake.ts +++ /dev/null @@ -1,134 +0,0 @@ -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/faker.ts b/src/faker.ts index 58209d34..e9fa978e 100644 --- a/src/faker.ts +++ b/src/faker.ts @@ -1,37 +1,33 @@ -import { Address } from './address'; -import { Animal } from './animal'; -import { Commerce } from './commerce'; -import { Company } from './company'; -import { Database } from './database'; -import { Datatype } from './datatype'; -import { _Date } from './date'; import type { LocaleDefinition } from './definitions'; import { FakerError } from './errors/faker-error'; -import { Fake } from './fake'; -import { Finance } from './finance'; -import { Git } from './git'; -import { Hacker } from './hacker'; -import { Helpers } from './helpers'; -import { Image } from './image'; import { deprecated } from './internal/deprecated'; -import { Internet } from './internet'; import type { KnownLocale } from './locales'; -import { Lorem } from './lorem'; -import { Mersenne } from './mersenne'; -import { Music } from './music'; -import { Name } from './name'; -import { Phone } from './phone'; -import { Random } from './random'; -import { System } from './system'; -import { Time } from './time'; -import { Unique } from './unique'; -import { Vehicle } from './vehicle'; -import { Word } from './word'; - -// https://github.com/microsoft/TypeScript/issues/29729#issuecomment-471566609 -export type LiteralUnion = - | T - | (U & { zz_IGNORE_ME?: never }); +import { Address } from './modules/address'; +import { Animal } from './modules/animal'; +import { Commerce } from './modules/commerce'; +import { Company } from './modules/company'; +import { Database } from './modules/database'; +import { Datatype } from './modules/datatype'; +import { _Date } from './modules/date'; +import { Fake } from './modules/fake'; +import { Finance } from './modules/finance'; +import { Git } from './modules/git'; +import { Hacker } from './modules/hacker'; +import { Helpers } from './modules/helpers'; +import { Image } from './modules/image'; +import { Internet } from './modules/internet'; +import { Lorem } from './modules/lorem'; +import { Mersenne } from './modules/mersenne'; +import { Music } from './modules/music'; +import { Name } from './modules/name'; +import { Phone } from './modules/phone'; +import { Random } from './modules/random'; +import { System } from './modules/system'; +import { Time } from './modules/time'; +import { Unique } from './modules/unique'; +import { Vehicle } from './modules/vehicle'; +import { Word } from './modules/word'; +import type { LiteralUnion } from './utils/types'; export type UsableLocale = LiteralUnion; export type UsedLocales = Partial>; diff --git a/src/finance.ts b/src/finance.ts deleted file mode 100644 index 48ce550c..00000000 --- a/src/finance.ts +++ /dev/null @@ -1,436 +0,0 @@ -import type { Faker } from '.'; -import { FakerError } from './errors/faker-error'; -import iban from './utils/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/git.ts b/src/git.ts deleted file mode 100644 index c0c98062..00000000 --- a/src/git.ts +++ /dev/null @@ -1,134 +0,0 @@ -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 - * // 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/hacker.ts b/src/hacker.ts deleted file mode 100644 index 49c63602..00000000 --- a/src/hacker.ts +++ /dev/null @@ -1,94 +0,0 @@ -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/helpers.ts b/src/helpers.ts deleted file mode 100644 index 0d8ce5b0..00000000 --- a/src/helpers.ts +++ /dev/null @@ -1,810 +0,0 @@ -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( - array: ReadonlyArray = ['a', 'b', 'c'] as unknown as ReadonlyArray - ): 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(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(source: readonly T[] | (() => T), length: number): T[] { - if (Array.isArray(source)) { - const set = new Set(source); - const array = Array.from(set); - return this.shuffle(array).splice(0, length); - } - const set = new Set(); - 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[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: 'Nora_Bruen@hotmail.com', - * // 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: 'Eveline.Brekke56.Hoppe@yahoo.com', - * // 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: 'Zoey_Lubowitz@yahoo.com', - * // 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( - 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>(object: T): keyof T { - const array: Array = 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>(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( - // 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 = ['a', 'b', 'c'] as unknown as ReadonlyArray - ): 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( - // 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 = ['a', 'b', 'c'] as unknown as ReadonlyArray, - 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/image.ts b/src/image.ts deleted file mode 100644 index fc6a2a96..00000000 --- a/src/image.ts +++ /dev/null @@ -1,345 +0,0 @@ -import type { Faker } from '.'; -import { LoremPicsum } from './image_providers/lorempicsum'; -import { Lorempixel } from './image_providers/lorempixel'; -import { Unsplash } from './image_providers/unsplash'; -import type { MethodsOf } from './utils/types'; - -/** - * 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 = [ - '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 = `${width}x${height}`; - const rawPrefix = 'data:image/svg+xml;charset=UTF-8,'; - return rawPrefix + encodeURIComponent(svgString); - } -} diff --git a/src/image_providers/lorempicsum.ts b/src/image_providers/lorempicsum.ts deleted file mode 100644 index f28b1e8f..00000000 --- a/src/image_providers/lorempicsum.ts +++ /dev/null @@ -1,126 +0,0 @@ -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/image_providers/lorempixel.ts b/src/image_providers/lorempixel.ts deleted file mode 100644 index 17cbc2f5..00000000 --- a/src/image_providers/lorempixel.ts +++ /dev/null @@ -1,288 +0,0 @@ -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 = [ - '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/image_providers/unsplash.ts b/src/image_providers/unsplash.ts deleted file mode 100644 index 994b2a04..00000000 --- a/src/image_providers/unsplash.ts +++ /dev/null @@ -1,157 +0,0 @@ -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/index.ts b/src/index.ts index 984833f5..8a1d415e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -28,8 +28,8 @@ export type { } from './definitions'; export { FakerError } from './errors/faker-error'; export type { FakerOptions, UsableLocale, UsedLocales } from './faker'; -export { Gender } from './name'; -export type { GenderType } from './name'; +export { Gender } from './modules/name'; +export type { GenderType } from './modules/name'; export { Faker }; // since we are requiring the top level of faker, load all locales by default diff --git a/src/internet.ts b/src/internet.ts deleted file mode 100644 index 6d018dc3..00000000 --- a/src/internet.ts +++ /dev/null @@ -1,458 +0,0 @@ -import type { Faker } from '.'; -import * as random_ua from './utils/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() // 'Kassandra4@hotmail.com' - * faker.internet.email('Jeanne', 'Doe') // 'Jeanne63@yahoo.com' - * faker.internet.email('Jeanne', 'Doe', 'example.fakerjs.dev') // 'Jeanne_Doe88@example.fakerjs.dev' - * faker.internet.email('Jeanne', 'Doe', 'example.fakerjs.dev', { allowSpecialCharacters: true }) // 'Jeanne%Doe88@example.fakerjs.dev' - */ - 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() // 'Helmer.Graham23@example.com' - * faker.internet.exampleEmail('Jeanne', 'Doe') // 'Jeanne96@example.net' - * faker.internet.exampleEmail('Jeanne', 'Doe', { allowSpecialCharacters: true }) // 'Jeanne%Doe88@example.com' - */ - 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 - * 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 } = {}): string { - const { - types = Object.keys( - this.faker.definitions.internet.emoji - ) as Array, - } = options; - const emojiType = this.faker.helpers.arrayElement(types); - return this.faker.helpers.arrayElement( - this.faker.definitions.internet.emoji[emojiType] - ); - } -} diff --git a/src/lorem.ts b/src/lorem.ts deleted file mode 100644 index a7a1b4d3..00000000 --- a/src/lorem.ts +++ /dev/null @@ -1,205 +0,0 @@ -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, '
\n') - * // 'Eos magnam aut qui accusamus. Sapiente quas culpa totam excepturi. Blanditiis totam distinctio occaecati dignissimos cumque atque qui officiis.
- * // 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 = [ - '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/mersenne.ts b/src/mersenne.ts deleted file mode 100644 index c8f531f2..00000000 --- a/src/mersenne.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { FakerError } from './errors/faker-error'; -import Gen from './utils/mersenne'; - -/** - * 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/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":"%'77"}` + */ + json(): string { + const properties = ['foo', 'bar', 'bike', 'a', 'b', 'name', 'prop']; + const returnObject: Record = {}; + + 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 { + return Array.from({ 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 + * // 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( + array: ReadonlyArray = ['a', 'b', 'c'] as unknown as ReadonlyArray + ): 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(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(source: readonly T[] | (() => T), length: number): T[] { + if (Array.isArray(source)) { + const set = new Set(source); + const array = Array.from(set); + return this.shuffle(array).splice(0, length); + } + const set = new Set(); + 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[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: 'Nora_Bruen@hotmail.com', + * // 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: 'Eveline.Brekke56.Hoppe@yahoo.com', + * // 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: 'Zoey_Lubowitz@yahoo.com', + * // 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( + 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>(object: T): keyof T { + const array: Array = 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>(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( + // 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 = ['a', 'b', 'c'] as unknown as ReadonlyArray + ): 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( + // 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 = ['a', 'b', 'c'] as unknown as ReadonlyArray, + 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 = [ + '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 = `${width}x${height}`; + 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 = [ + '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() // 'Kassandra4@hotmail.com' + * faker.internet.email('Jeanne', 'Doe') // 'Jeanne63@yahoo.com' + * faker.internet.email('Jeanne', 'Doe', 'example.fakerjs.dev') // 'Jeanne_Doe88@example.fakerjs.dev' + * faker.internet.email('Jeanne', 'Doe', 'example.fakerjs.dev', { allowSpecialCharacters: true }) // 'Jeanne%Doe88@example.fakerjs.dev' + */ + 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() // 'Helmer.Graham23@example.com' + * faker.internet.exampleEmail('Jeanne', 'Doe') // 'Jeanne96@example.net' + * faker.internet.exampleEmail('Jeanne', 'Doe', { allowSpecialCharacters: true }) // 'Jeanne%Doe88@example.com' + */ + 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 + * 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 } = {}): string { + const { + types = Object.keys( + this.faker.definitions.internet.emoji + ) as Array, + } = 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): + * + * 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, + 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 { + 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, '
\n') + * // 'Eos magnam aut qui accusamus. Sapiente quas culpa totam excepturi. Blanditiis totam distinctio occaecati dignissimos cumque atque qui officiis.
+ * // 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 = [ + '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 | 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; + } + + 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 = + 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(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( + array: ReadonlyArray = ['a', 'b', 'c'] as unknown as ReadonlyArray + ): 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( + array: ReadonlyArray = ['a', 'b', 'c'] as unknown as ReadonlyArray, + 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, 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, 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, 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, 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(set: Set): 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(); + 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(); + + 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 RecordKey>( + method: Method, + args?: Parameters, + options: { + startTime?: number; + maxTime?: number; + maxRetries?: number; + currentIterations?: number; + exclude?: RecordKey | RecordKey[]; + compare?: (obj: Record, key: RecordKey) => 0 | -1; + store?: Record; + } = {} + ): ReturnType { + 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 = {}; + +/** + * 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, + 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, + 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 RecordKey>( + method: Method, + args: Parameters, + options: { + startTime?: number; + maxTime?: number; + maxRetries?: number; + currentIterations?: number; + exclude?: RecordKey | RecordKey[]; + compare?: (obj: Record, key: RecordKey) => 0 | -1; + store?: Record; + } = {} +): ReturnType { + 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.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, + }) + ); + } +} diff --git a/src/music.ts b/src/music.ts deleted file mode 100644 index d0e0a1a7..00000000 --- a/src/music.ts +++ /dev/null @@ -1,26 +0,0 @@ -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/name.ts b/src/name.ts deleted file mode 100644 index 280e4b09..00000000 --- a/src/name.ts +++ /dev/null @@ -1,350 +0,0 @@ -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 | 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; - } - - 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 = - 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/phone.ts b/src/phone.ts deleted file mode 100644 index c8a1902d..00000000 --- a/src/phone.ts +++ /dev/null @@ -1,76 +0,0 @@ -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/random.ts b/src/random.ts deleted file mode 100644 index 87976828..00000000 --- a/src/random.ts +++ /dev/null @@ -1,648 +0,0 @@ -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(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( - array: ReadonlyArray = ['a', 'b', 'c'] as unknown as ReadonlyArray - ): 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( - array: ReadonlyArray = ['a', 'b', 'c'] as unknown as ReadonlyArray, - 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, 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, 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, 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, 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/system.ts b/src/system.ts deleted file mode 100644 index 90e56d55..00000000 --- a/src/system.ts +++ /dev/null @@ -1,194 +0,0 @@ -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(set: Set): 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(); - 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(); - - 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/time.ts b/src/time.ts deleted file mode 100644 index c33638a7..00000000 --- a/src/time.ts +++ /dev/null @@ -1,57 +0,0 @@ -import type { LiteralUnion } from './faker'; -import { deprecated } from './internal/deprecated'; - -/** - * 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/unique.ts b/src/unique.ts deleted file mode 100644 index 188a2e63..00000000 --- a/src/unique.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { deprecated } from './internal/deprecated'; -import type { RecordKey } from './utils/unique'; -import * as uniqueExec from './utils/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 RecordKey>( - method: Method, - args?: Parameters, - options: { - startTime?: number; - maxTime?: number; - maxRetries?: number; - currentIterations?: number; - exclude?: RecordKey | RecordKey[]; - compare?: (obj: Record, key: RecordKey) => 0 | -1; - store?: Record; - } = {} - ): ReturnType { - 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/utils/iban.ts b/src/utils/iban.ts deleted file mode 100644 index 9b4780c5..00000000 --- a/src/utils/iban.ts +++ /dev/null @@ -1,1414 +0,0 @@ -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/utils/mersenne.ts b/src/utils/mersenne.ts deleted file mode 100644 index 5859f3ae..00000000 --- a/src/utils/mersenne.ts +++ /dev/null @@ -1,320 +0,0 @@ -/** - * 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/utils/types.ts b/src/utils/types.ts index 705d02d1..65c87ebf 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -1,3 +1,12 @@ +/** + * Type that provides auto-suggestions but also any string. + * + * @see https://github.com/microsoft/TypeScript/issues/29729#issuecomment-471566609 + */ +export type LiteralUnion = + | T + | (U & { zz_IGNORE_ME?: never }); + /** * Type that represents a single method/function name of the given type. */ diff --git a/src/utils/unique.ts b/src/utils/unique.ts deleted file mode 100644 index df1b827e..00000000 --- a/src/utils/unique.ts +++ /dev/null @@ -1,158 +0,0 @@ -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 = {}; - -/** - * 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, - 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, - 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 RecordKey>( - method: Method, - args: Parameters, - options: { - startTime?: number; - maxTime?: number; - maxRetries?: number; - currentIterations?: number; - exclude?: RecordKey | RecordKey[]; - compare?: (obj: Record, key: RecordKey) => 0 | -1; - store?: Record; - } = {} -): ReturnType { - 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.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/utils/user-agent.ts b/src/utils/user-agent.ts deleted file mode 100644 index b3438cbd..00000000 --- a/src/utils/user-agent.ts +++ /dev/null @@ -1,345 +0,0 @@ -/** - * 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): - * - * 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, - 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 { - 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/vehicle.ts b/src/vehicle.ts deleted file mode 100644 index ca0d11f2..00000000 --- a/src/vehicle.ts +++ /dev/null @@ -1,131 +0,0 @@ -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/word.ts b/src/word.ts deleted file mode 100644 index b586c0d0..00000000 --- a/src/word.ts +++ /dev/null @@ -1,174 +0,0 @@ -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, - }) - ); - } -} -- cgit v1.2.3