From 7d4d99f00bf1e29c14346bd6a9fab33c8e7d5743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leyla=20J=C3=A4hnig?= Date: Fri, 25 Nov 2022 16:59:10 +0100 Subject: feat(number): move methods to new module (#1122) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: ST-DDT Co-authored-by: Eric Cheng Co-authored-by: Leyla Jähnig Co-authored-by: Shinigami92 --- src/modules/color/index.ts | 34 ++---- src/modules/commerce/index.ts | 10 +- src/modules/datatype/index.ts | 111 ++++++----------- src/modules/date/index.ts | 12 +- src/modules/finance/index.ts | 20 ++- src/modules/git/index.ts | 2 +- src/modules/helpers/index.ts | 26 ++-- src/modules/image/index.ts | 2 +- src/modules/image/providers/lorempixel.ts | 2 +- src/modules/internet/index.ts | 18 +-- src/modules/internet/user-agent.ts | 66 +++++----- src/modules/location/index.ts | 20 +-- src/modules/number/index.ts | 197 ++++++++++++++++++++++++++++++ src/modules/random/index.ts | 2 +- src/modules/string/index.ts | 6 +- src/modules/system/index.ts | 47 +++---- src/modules/vehicle/index.ts | 12 +- 17 files changed, 346 insertions(+), 241 deletions(-) create mode 100644 src/modules/number/index.ts (limited to 'src/modules') diff --git a/src/modules/color/index.ts b/src/modules/color/index.ts index 4fd79a06..b232f649 100644 --- a/src/modules/color/index.ts +++ b/src/modules/color/index.ts @@ -320,13 +320,9 @@ export class ColorModule { color = formatHexColor(color, options); return color; } - color = Array.from({ length: 3 }).map(() => - this.faker.datatype.number({ min: 0, max: 255 }) - ); + color = Array.from({ length: 3 }).map(() => this.faker.number.int(255)); if (includeAlpha) { - color.push( - this.faker.datatype.float({ min: 0, max: 1, precision: 0.01 }) - ); + color.push(this.faker.number.float({ max: 1, precision: 0.01 })); cssFunction = 'rgba'; } return toColorFormat(color, format, cssFunction); @@ -385,7 +381,7 @@ export class ColorModule { cmyk(options?: { format?: ColorFormat }): string | number[]; cmyk(options?: { format?: ColorFormat }): string | number[] { const color: string | number[] = Array.from({ length: 4 }).map(() => - this.faker.datatype.float({ min: 0, max: 1, precision: 0.01 }) + this.faker.number.float({ max: 1, precision: 0.01 }) ); return toColorFormat(color, options?.format || 'decimal', 'cmyk'); } @@ -460,9 +456,9 @@ export class ColorModule { format?: ColorFormat; includeAlpha?: boolean; }): string | number[] { - const hsl: number[] = [this.faker.datatype.number({ min: 0, max: 360 })]; + const hsl: number[] = [this.faker.number.int(360)]; for (let i = 0; i < (options?.includeAlpha ? 3 : 2); i++) { - hsl.push(this.faker.datatype.float({ min: 0, max: 1, precision: 0.01 })); + hsl.push(this.faker.number.float({ max: 1, precision: 0.01 })); } return toColorFormat( hsl, @@ -537,9 +533,9 @@ export class ColorModule { * @since 7.0.0 */ hwb(options?: { format?: ColorFormat }): string | number[] { - const hsl: number[] = [this.faker.datatype.number({ min: 0, max: 360 })]; + const hsl: number[] = [this.faker.number.int(360)]; for (let i = 0; i < 2; i++) { - hsl.push(this.faker.datatype.float({ min: 0, max: 1, precision: 0.01 })); + hsl.push(this.faker.number.float({ max: 1, precision: 0.01 })); } return toColorFormat(hsl, options?.format || 'decimal', 'hwb'); } @@ -596,12 +592,10 @@ export class ColorModule { */ lab(options?: { format?: ColorFormat }): string | number[]; lab(options?: { format?: ColorFormat }): string | number[] { - const lab = [ - this.faker.datatype.float({ min: 0, max: 1, precision: 0.000001 }), - ]; + const lab = [this.faker.number.float({ max: 1, precision: 0.000001 })]; for (let i = 0; i < 2; i++) { lab.push( - this.faker.datatype.float({ min: -100, max: 100, precision: 0.0001 }) + this.faker.number.float({ min: -100, max: 100, precision: 0.0001 }) ); } return toColorFormat(lab, options?.format || 'decimal', 'lab'); @@ -671,13 +665,9 @@ export class ColorModule { */ lch(options?: { format?: ColorFormat }): string | number[]; lch(options?: { format?: ColorFormat }): string | number[] { - const lch = [ - this.faker.datatype.float({ min: 0, max: 1, precision: 0.000001 }), - ]; + const lch = [this.faker.number.float({ max: 1, precision: 0.000001 })]; for (let i = 0; i < 2; i++) { - lch.push( - this.faker.datatype.number({ min: 0, max: 230, precision: 0.1 }) - ); + lch.push(this.faker.number.float({ max: 230, precision: 0.1 })); } return toColorFormat(lch, options?.format || 'decimal', 'lch'); } @@ -753,7 +743,7 @@ export class ColorModule { options = { ...options, space: 'sRGB' }; } const color = Array.from({ length: 3 }).map(() => - this.faker.datatype.float({ min: 0, max: 1, precision: 0.0001 }) + this.faker.number.float({ max: 1, precision: 0.0001 }) ); return toColorFormat( color, diff --git a/src/modules/commerce/index.ts b/src/modules/commerce/index.ts index 088112c1..99515463 100644 --- a/src/modules/commerce/index.ts +++ b/src/modules/commerce/index.ts @@ -67,14 +67,10 @@ export class CommerceModule { return `${symbol}${0.0}`; } - const randValue = this.faker.datatype.number({ max: max, min: min }); + // TODO @Shinigami92 2022-11-24: https://github.com/faker-js/faker/issues/350 + const randValue = this.faker.number.int({ min, max }); - return ( - symbol + - (Math.round(randValue * Math.pow(10, dec)) / Math.pow(10, dec)).toFixed( - dec - ) - ); + return symbol + randValue.toFixed(dec); } /** diff --git a/src/modules/datatype/index.ts b/src/modules/datatype/index.ts index b40f2f43..22ee1bfe 100644 --- a/src/modules/datatype/index.ts +++ b/src/modules/datatype/index.ts @@ -1,7 +1,5 @@ import type { Faker } from '../..'; -import { FakerError } from '../../errors/faker-error'; import { deprecated } from '../../internal/deprecated'; -import type { Mersenne } from '../../internal/mersenne/mersenne'; /** * Module to generate various primitive values and data types. @@ -37,36 +35,26 @@ export class DatatypeModule { * faker.datatype.number({ min: 10, max: 100, precision: 0.01 }) // 36.94 * * @since 5.5.0 + * + * @deprecated Use `faker.number.int()` instead. */ number( options: number | { min?: number; max?: number; precision?: number } = 99999 ): number { + deprecated({ + deprecated: 'faker.datatype.number()', + proposed: 'faker.number.int()', + since: '8.0', + until: '9.0', + }); + 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 greater than min ${min}.`); - } + const { min = 0, max = min + 99999, precision = 1 } = options; - const mersenne: Mersenne = - // @ts-expect-error: access private member field - this.faker._mersenne; - - const randomNumber = mersenne.next({ - min: min / precision, - max: max / precision + 1, - }); - - // Workaround problem in float point arithmetics for e.g. 6681493 / 0.01 - return randomNumber / (1 / precision); + return this.faker.number.float({ min, max, precision }); } /** @@ -86,24 +74,19 @@ export class DatatypeModule { * faker.datatype.float({ min: 10, max: 100, precision: 0.001 }) // 57.315 * * @since 5.5.0 + * + * @deprecated Use `faker.number.float()` instead. */ 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); + deprecated({ + deprecated: 'faker.datatype.float()', + proposed: 'faker.number.float()', + since: '8.0', + until: '9.0', + }); + return this.faker.number.float(options); } /** @@ -139,7 +122,7 @@ export class DatatypeModule { max = Date.UTC(2100, 0); } - return new Date(this.number({ min, max })); + return new Date(this.faker.number.int({ min, max })); } /** @@ -177,7 +160,7 @@ export class DatatypeModule { * * @since 5.5.0 * - * @deprecated Use faker.string.uuid() instead. + * @deprecated Use `faker.string.uuid()` instead. */ uuid(): string { deprecated({ @@ -222,7 +205,7 @@ export class DatatypeModule { // This check is required to avoid returning false when float() returns 1 return true; } - return this.float({ min: 0, max: 1 }) < probability; + return this.faker.number.float({ max: 1 }) < probability; } /** @@ -247,7 +230,7 @@ export class DatatypeModule { * * @since 6.1.2 * - * @deprecated Use `faker.string.hexadecimal()` instead. + * @deprecated Use `faker.string.hexadecimal()` or `faker.number.hex()` instead. */ hexadecimal( options: { @@ -258,7 +241,7 @@ export class DatatypeModule { ): string { deprecated({ deprecated: 'faker.datatype.hexadecimal()', - proposed: 'faker.string.hexadecimal()', + proposed: 'faker.string.hexadecimal() or faker.number.hex()', since: '8.0', until: '9.0', }); @@ -280,7 +263,7 @@ export class DatatypeModule { properties.forEach((prop) => { returnObject[prop] = this.boolean() ? this.faker.string.sample() - : this.number(); + : this.faker.number.int(); }); return JSON.stringify(returnObject); @@ -299,7 +282,7 @@ export class DatatypeModule { */ array(length = 10): Array { return Array.from({ length }).map(() => - this.boolean() ? this.faker.string.sample() : this.number() + this.boolean() ? this.faker.string.sample() : this.faker.number.int() ); } @@ -320,6 +303,8 @@ export class DatatypeModule { * faker.datatype.bigInt({ min: 10n, max: 100n }) // 36n * * @since 6.0.0 + * + * @deprecated Use `faker.number.bigInt()` instead. */ bigInt( options?: @@ -332,36 +317,12 @@ export class DatatypeModule { max?: bigint | boolean | number | string; } ): bigint { - let min: bigint; - let max: bigint; - - if (typeof options === 'object') { - min = BigInt(options.min ?? 0); - max = BigInt(options.max ?? min + BigInt(999999999999999)); - } else { - min = BigInt(0); - max = BigInt(options ?? 999999999999999); - } - - if (max === min) { - return min; - } - - if (max < min) { - throw new FakerError(`Max ${max} should be larger then min ${min}.`); - } - - const delta = max - min; - - const offset = - BigInt( - this.faker.string.numeric({ - length: delta.toString(10).length, - allowLeadingZeros: true, - }) - ) % - (delta + BigInt(1)); - - return min + offset; + deprecated({ + deprecated: 'faker.datatype.bigInt()', + proposed: 'faker.number.bigInt()', + since: '8.0', + until: '9.0', + }); + return this.faker.number.bigInt(options); } } diff --git a/src/modules/date/index.ts b/src/modules/date/index.ts index d5470dab..673f0e33 100644 --- a/src/modules/date/index.ts +++ b/src/modules/date/index.ts @@ -58,7 +58,7 @@ export class DateModule { }; let past = date.getTime(); - past -= this.faker.datatype.number(range); // some time from now to N years ago, in milliseconds + past -= this.faker.number.int(range); // some time from now to N years ago, in milliseconds date.setTime(past); return date; @@ -91,7 +91,7 @@ export class DateModule { }; let future = date.getTime(); - future += this.faker.datatype.number(range); // some time from now to N years later, in milliseconds + future += this.faker.number.int(range); // some time from now to N years later, in milliseconds date.setTime(future); return date; @@ -111,7 +111,7 @@ export class DateModule { 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); + const dateOffset = this.faker.number.int(toMs - fromMs); return new Date(fromMs + dateOffset); } @@ -176,7 +176,7 @@ export class DateModule { }; let future = date.getTime(); - future -= this.faker.datatype.number(range); // some time from now to N days ago, in milliseconds + future -= this.faker.number.int(range); // some time from now to N days ago, in milliseconds date.setTime(future); return date; @@ -209,7 +209,7 @@ export class DateModule { }; let future = date.getTime(); - future += this.faker.datatype.number(range); // some time from now to N days later, in milliseconds + future += this.faker.number.int(range); // some time from now to N days later, in milliseconds date.setTime(future); return date; @@ -343,6 +343,6 @@ export class DateModule { throw new FakerError(`Max ${max} should be larger then min ${min}.`); } - return new Date(this.faker.datatype.number({ min, max })); + return new Date(this.faker.number.int({ min, max })); } } diff --git a/src/modules/finance/index.ts b/src/modules/finance/index.ts index e739d920..e6533e50 100644 --- a/src/modules/finance/index.ts +++ b/src/modules/finance/index.ts @@ -143,10 +143,10 @@ export class FinanceModule { symbol: string = '', autoFormat?: boolean ): string { - const randValue = this.faker.datatype.number({ + const randValue = this.faker.number.float({ max, min, - precision: Math.pow(10, -dec), + precision: 10 ** -dec, }); let formattedString: string; @@ -231,7 +231,7 @@ export class FinanceModule { * @since 3.1.0 */ bitcoinAddress(): string { - const addressLength = this.faker.datatype.number({ min: 25, max: 39 }); + const addressLength = this.faker.number.int({ min: 25, max: 39 }); let address = this.faker.helpers.arrayElement(['1', '3']); @@ -253,7 +253,7 @@ export class FinanceModule { * @since 5.0.0 */ litecoinAddress(): string { - const addressLength = this.faker.datatype.number({ min: 26, max: 33 }); + const addressLength = this.faker.number.int({ min: 26, max: 33 }); let address = this.faker.helpers.arrayElement(['L', 'M', '3']); @@ -305,11 +305,7 @@ export class FinanceModule { * @since 5.0.0 */ creditCardCVV(): string { - let cvv = ''; - for (let i = 0; i < 3; i++) { - cvv += this.faker.datatype.number({ max: 9 }).toString(); - } - return cvv; + return this.faker.string.numeric({ length: 3, allowLeadingZeros: true }); } /** @@ -342,7 +338,7 @@ export class FinanceModule { if (length < 1) { throw new FakerError('minimum length is 1'); } - return Array.from({ length }, () => this.faker.datatype.number(9)).join(''); + return this.faker.string.numeric({ length, allowLeadingZeros: true }); } /** @@ -394,7 +390,7 @@ export class FinanceModule { s += this.faker.helpers.arrayElement(iban.alpha); } else if (bban.type === 'c') { if (this.faker.datatype.boolean(0.8)) { - s += this.faker.datatype.number(9); + s += this.faker.number.int(9); } else { s += this.faker.helpers.arrayElement(iban.alpha); } @@ -408,7 +404,7 @@ export class FinanceModule { c--; } } else { - s += this.faker.datatype.number(9); + s += this.faker.number.int(9); } } c--; diff --git a/src/modules/git/index.ts b/src/modules/git/index.ts index 336da820..2ea65063 100644 --- a/src/modules/git/index.ts +++ b/src/modules/git/index.ts @@ -145,7 +145,7 @@ export class GitModule { // Timezone offset dateParts.push( GIT_TIMEZONE_FORMAT.format( - this.faker.datatype.number({ min: -11, max: 12 }) * 100 + this.faker.number.int({ min: -11, max: 12 }) * 100 ) ); diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts index 406f7f19..6caa8eff 100644 --- a/src/modules/helpers/index.ts +++ b/src/modules/helpers/index.ts @@ -56,9 +56,9 @@ export class HelpersModule { let str = ''; for (let i = 0; i < string.length; i++) { if (string.charAt(i) === symbol) { - str += this.faker.datatype.number(9); + str += this.faker.number.int(9); } else if (string.charAt(i) === '!') { - str += this.faker.datatype.number({ min: 2, max: 9 }); + str += this.faker.number.int({ min: 2, max: 9 }); } else { str += string.charAt(i); } @@ -117,13 +117,13 @@ export class HelpersModule { for (let i = 0; i < string.length; i++) { if (string.charAt(i) === '#') { - str += this.faker.datatype.number(9); + str += this.faker.number.int(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); + : this.faker.number.int(9); } else { str += string.charAt(i); } @@ -197,7 +197,7 @@ export class HelpersModule { max = min; min = tmp; } - repetitions = this.faker.datatype.number({ min: min, max: max }); + repetitions = this.faker.number.int({ min, max }); string = string.slice(0, token.index) + token[1].repeat(repetitions) + @@ -229,7 +229,7 @@ export class HelpersModule { } string = string.slice(0, token.index) + - this.faker.datatype.number({ min: min, max: max }).toString() + + this.faker.number.int({ min, max }).toString() + string.slice(token.index + token[0].length); token = string.match(RANGE_REG); } @@ -289,7 +289,7 @@ export class HelpersModule { } for (let i = list.length - 1; i > 0; --i) { - const j = this.faker.datatype.number(i); + const j = this.faker.number.int(i); [list[i], list[j]] = [list[j], list[i]]; } @@ -341,7 +341,7 @@ export class HelpersModule { * * @example * faker.helpers.mustache('I found {{count}} instances of "{{word}}".', { - * count: () => `${faker.datatype.number()}`, + * count: () => `${faker.number.int()}`, * word: "this word", * }) // 'I found 57591 instances of "this word".' * @@ -438,9 +438,7 @@ export class HelpersModule { array: ReadonlyArray = ['a', 'b', 'c'] as unknown as ReadonlyArray ): T { const index = - array.length > 1 - ? this.faker.datatype.number({ max: array.length - 1 }) - : 0; + array.length > 1 ? this.faker.number.int({ max: array.length - 1 }) : 0; return array[index]; } @@ -470,7 +468,7 @@ export class HelpersModule { count = array.length === 0 ? 0 - : this.faker.datatype.number({ min: 1, max: array.length }); + : this.faker.number.int({ min: 1, max: array.length }); } else if (count > array.length) { count = array.length; } else if (count < 0) { @@ -485,7 +483,7 @@ export class HelpersModule { while (i-- > min) { index = Math.floor( - (i + 1) * this.faker.datatype.float({ min: 0, max: 0.99 }) + (i + 1) * this.faker.number.float({ min: 0, max: 0.99 }) ); temp = arrayCopy[index]; arrayCopy[index] = arrayCopy[i]; @@ -644,7 +642,7 @@ export class HelpersModule { if (typeof numberOrRange === 'number') { return numberOrRange; } - return this.faker.datatype.number(numberOrRange); + return this.faker.number.int(numberOrRange); } /** diff --git a/src/modules/image/index.ts b/src/modules/image/index.ts index 8113c1f6..e0dd9d22 100644 --- a/src/modules/image/index.ts +++ b/src/modules/image/index.ts @@ -111,7 +111,7 @@ export class ImageModule { } if (randomize) { - url += `?lock=${this.faker.datatype.number()}`; + url += `?lock=${this.faker.number.int()}`; } return url; diff --git a/src/modules/image/providers/lorempixel.ts b/src/modules/image/providers/lorempixel.ts index a172517b..f8bb81e5 100644 --- a/src/modules/image/providers/lorempixel.ts +++ b/src/modules/image/providers/lorempixel.ts @@ -60,7 +60,7 @@ export class Lorempixel { } if (randomize) { - url += `?${this.faker.datatype.number()}`; + url += `?${this.faker.number.int()}`; } return url; diff --git a/src/modules/internet/index.ts b/src/modules/internet/index.ts index 60e3ac55..a32045d9 100644 --- a/src/modules/internet/index.ts +++ b/src/modules/internet/index.ts @@ -46,7 +46,7 @@ export class InternetModule { * @since 2.0.1 */ avatar(): string { - return `https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/${this.faker.datatype.number( + return `https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/${this.faker.number.int( 1249 )}.jpg`; } @@ -140,9 +140,9 @@ export class InternetModule { let result: string; firstName = firstName || this.faker.person.firstName(); lastName = lastName || this.faker.person.lastName(); - switch (this.faker.datatype.number(2)) { + switch (this.faker.number.int(2)) { case 0: - result = `${firstName}${this.faker.datatype.number(99)}`; + result = `${firstName}${this.faker.number.int(99)}`; break; case 1: result = @@ -152,7 +152,7 @@ export class InternetModule { result = `${firstName}${this.faker.helpers.arrayElement([ '.', '_', - ])}${lastName}${this.faker.datatype.number(99)}`; + ])}${lastName}${this.faker.number.int(99)}`; break; } result = result.toString().replace(/'/g, ''); @@ -319,7 +319,7 @@ export class InternetModule { */ ipv4(): string { const randNum = () => { - return this.faker.datatype.number(255).toFixed(0); + return this.faker.number.int(255).toFixed(0); }; const result: string[] = []; @@ -380,7 +380,7 @@ export class InternetModule { * @since 5.4.0 */ port(): number { - return this.faker.datatype.number({ min: 0, max: 65535 }); + return this.faker.number.int(65535); } /** @@ -418,7 +418,7 @@ export class InternetModule { blueBase: number = 0 ): string { const colorFromBase = (base: number): string => - Math.floor((this.faker.datatype.number(256) + base) / 2) + Math.floor((this.faker.number.int(256) + base) / 2) .toString(16) .padStart(2, '0'); @@ -451,7 +451,7 @@ export class InternetModule { } for (i = 0; i < 12; i++) { - mac += this.faker.datatype.number(15).toString(16); + mac += this.faker.number.hex(15); if (i % 2 === 1 && i !== 11) { mac += validSep; } @@ -506,7 +506,7 @@ export class InternetModule { pattern = consonant; } } - const n = this.faker.datatype.number(94) + 33; + const n = this.faker.number.int(94) + 33; let char = String.fromCharCode(n); if (memorable) { char = char.toLowerCase(); diff --git a/src/modules/internet/user-agent.ts b/src/modules/internet/user-agent.ts index 972b2574..005e31e6 100644 --- a/src/modules/internet/user-agent.ts +++ b/src/modules/internet/user-agent.ts @@ -58,7 +58,7 @@ export function generate(faker: Faker): string { obj: T ): keyof T => { //returns a random key from the passed object; keys are weighted by the decimal probability in their value - const rand = faker.datatype.number({ min: 0, max: 100 }) / 100; + const rand = faker.number.int(100) / 100; let min = 0; let max = 0; let return_val: string; @@ -217,7 +217,7 @@ export function generate(faker: Faker): string { //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 += `.${faker.datatype.number({ min: 0, max: 9 })}`; + return_val += `.${faker.string.numeric({ allowLeadingZeros: true })}`; } return return_val; }; @@ -225,53 +225,51 @@ export function generate(faker: Faker): string { const version_string = { net() { return [ - faker.datatype.number({ min: 1, max: 4 }), - faker.datatype.number({ min: 0, max: 9 }), - faker.datatype.number({ min: 10000, max: 99999 }), - faker.datatype.number({ min: 0, max: 9 }), + faker.number.int({ min: 1, max: 4 }), + faker.number.int(9), + faker.number.int({ min: 10000, max: 99999 }), + faker.number.int(9), ].join('.'); }, nt() { - return [ - faker.datatype.number({ min: 5, max: 6 }), - faker.datatype.number({ min: 0, max: 3 }), - ].join('.'); + return [faker.number.int({ min: 5, max: 6 }), faker.number.int(3)].join( + '.' + ); }, ie() { - return faker.datatype.number({ min: 7, max: 11 }); + return faker.number.int({ min: 7, max: 11 }); }, trident() { - return [ - faker.datatype.number({ min: 3, max: 7 }), - faker.datatype.number({ min: 0, max: 1 }), - ].join('.'); + return [faker.number.int({ min: 3, max: 7 }), faker.number.int(1)].join( + '.' + ); }, osx(delim?: string) { return [ 10, - faker.datatype.number({ min: 5, max: 10 }), - faker.datatype.number({ min: 0, max: 9 }), + faker.number.int({ min: 5, max: 10 }), + faker.number.int(9), ].join(delim || '.'); }, chrome() { return [ - faker.datatype.number({ min: 13, max: 39 }), + faker.number.int({ min: 13, max: 39 }), 0, - faker.datatype.number({ min: 800, max: 899 }), + faker.number.int({ min: 800, max: 899 }), 0, ].join('.'); }, presto() { - return `2.9.${faker.datatype.number({ min: 160, max: 190 })}`; + return `2.9.${faker.number.int({ min: 160, max: 190 })}`; }, presto2() { - return `${faker.datatype.number({ min: 10, max: 12 })}.00`; + return `${faker.number.int({ min: 10, max: 12 })}.00`; }, safari() { return [ - faker.datatype.number({ min: 531, max: 538 }), - faker.datatype.number({ min: 0, max: 2 }), - faker.datatype.number({ min: 0, max: 2 }), + faker.number.int({ min: 531, max: 538 }), + faker.number.int(2), + faker.number.int(2), ].join('.'); }, }; @@ -279,7 +277,7 @@ export function generate(faker: Faker): string { const browserMap = { firefox(arch: OS): string { //https://developer.mozilla.org/en-US/docs/Gecko_user_agent_string_reference - const firefox_ver = `${faker.datatype.number({ + const firefox_ver = `${faker.number.int({ min: 5, max: 15, })}${randomRevision(2)}`, @@ -303,7 +301,7 @@ export function generate(faker: Faker): string { if (ver >= 11) { //http://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx - return `Mozilla/5.0 (Windows NT 6.${faker.datatype.number({ + return `Mozilla/5.0 (Windows NT 6.${faker.number.int({ min: 1, max: 3, })}; Trident/7.0; ${ @@ -327,29 +325,23 @@ export function generate(faker: Faker): string { ? `(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/${faker.datatype.number({ + return `Opera/${faker.number.int({ min: 9, max: 14, - })}.${faker.datatype.number({ - min: 0, - max: 99, - })} ${os_ver}`; + })}.${faker.number.int(99)} ${os_ver}`; }, safari(arch: OS): string { const safari = version_string.safari(), - ver = `${faker.datatype.number({ + ver = `${faker.number.int({ min: 4, max: 7, - })}.${faker.datatype.number({ - min: 0, - max: 1, - })}.${faker.datatype.number({ min: 0, max: 10 })}`, + })}.${faker.number.int(1)}.${faker.number.int(10)}`, os_ver = arch === 'mac' ? `(Macintosh; ${randomProc('mac')} Mac OS X ${version_string.osx( '_' - )} rv:${faker.datatype.number({ + )} rv:${faker.number.int({ min: 2, max: 6, })}.0; ${randomLang()}) ` diff --git a/src/modules/location/index.ts b/src/modules/location/index.ts index fcb8aabd..a4e6ef9e 100644 --- a/src/modules/location/index.ts +++ b/src/modules/location/index.ts @@ -60,7 +60,7 @@ export class LocationModule { zipCodeByState(state: string): string { const zipRange = this.faker.definitions.location.postcode_by_state?.[state]; if (zipRange) { - return String(this.faker.datatype.number(zipRange)); + return String(this.faker.number.int(zipRange)); } return this.zipCode(); } @@ -269,11 +269,7 @@ export class LocationModule { */ // TODO @xDivisionByZerox 2022-06-12 this signature should probably be an object for easier maintainability latitude(max: number = 90, min: number = -90, precision: number = 4): number { - return this.faker.datatype.number({ - min, - max, - precision: parseFloat(`${(0.0).toPrecision(precision)}1`), - }); + return this.faker.number.float({ min, max, precision: 10 ** -precision }); } /** @@ -295,11 +291,7 @@ export class LocationModule { min: number = -180, precision: number = 4 ): number { - return this.faker.datatype.number({ - max: max, - min: min, - precision: parseFloat(`${(0.0).toPrecision(precision)}1`), - }); + return this.faker.number.float({ max, min, precision: 10 ** -precision }); } /** @@ -399,8 +391,7 @@ export class LocationModule { return [this.latitude(), this.longitude()]; } - const angleRadians = this.faker.datatype.float({ - min: 0, + const angleRadians = this.faker.number.float({ max: 2 * Math.PI, precision: 0.00001, }); // in ° radians @@ -408,8 +399,7 @@ export class LocationModule { const radiusMetric = isMetric ? radius : radius * 1.60934; // in km const errorCorrection = 0.995; // avoid float issues const distanceInKm = - this.faker.datatype.float({ - min: 0, + this.faker.number.float({ max: radiusMetric, precision: 0.001, }) * errorCorrection; // in km diff --git a/src/modules/number/index.ts b/src/modules/number/index.ts new file mode 100644 index 00000000..c30d5015 --- /dev/null +++ b/src/modules/number/index.ts @@ -0,0 +1,197 @@ +import type { Faker } from '../..'; +import { FakerError } from '../../errors/faker-error'; +import type { Mersenne } from '../../internal/mersenne/mersenne'; + +/** + * Module to generate numbers of any kind. + */ +export class NumberModule { + constructor(private readonly faker: Faker) { + // Bind `this` so namespaced is working correctly + for (const name of Object.getOwnPropertyNames(NumberModule.prototype)) { + if (name === 'constructor' || typeof this[name] !== 'function') { + continue; + } + this[name] = this[name].bind(this); + } + } + + /** + * Returns a single random integer between zero and the given max value or the given range. + * The bounds are inclusive. + * + * @param options Maximum value or options object. Defaults to `{}`. + * @param options.min Lower bound for generated number. Defaults to `0`. + * @param options.max Upper bound for generated number. Defaults to `min + 99999`. + * + * @throws When options define `max < min`. + * + * @example + * faker.number.int() // 55422 + * faker.number.int(100) // 52 + * faker.number.int({ min: 1000000 }) // 1031433 + * faker.number.int({ max: 100 }) // 42 + * faker.number.int({ min: 10, max: 100 }) // 57 + * + * @since 8.0.0 + */ + int(options: number | { min?: number; max?: number } = {}): number { + if (typeof options === 'number') { + options = { max: options }; + } + + const { min = 0, max = min + 99999 } = options; + + if (max === min) { + return min; + } + + if (max < min) { + throw new FakerError(`Max ${max} should be greater than min ${min}.`); + } + + const mersenne: Mersenne = + // @ts-expect-error: access private member field + this.faker._mersenne; + + return mersenne.next({ min, max: max + 1 }); + } + + /** + * Returns a single random floating-point number for a given precision or range and precision. + * + * @param options Precision or options object. Defaults to `{}`. + * @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.number.float() // 51696.36 + * faker.number.float(1) // 52023.2 + * faker.number.float({ min: 1000000 }) // 212859.76 + * faker.number.float({ max: 100 }) // 28.11 + * faker.number.float({ precision: 0.1 }) // 84055.3 + * faker.number.float({ min: 10, max: 100, precision: 0.001 }) // 57.315 + * + * @since 8.0.0 + */ + float( + options: number | { min?: number; max?: number; precision?: number } = {} + ): number { + if (typeof options === 'number') { + options = { + precision: options, + }; + } + + const { min = 0, max = min + 99999, precision = 0.01 } = options; + + if (max === min) { + return min; + } + + if (max < min) { + throw new FakerError(`Max ${max} should be greater than min ${min}.`); + } + + const factor = 1 / precision; + const int = this.int({ + min: min * factor, + max: max * factor, + }); + + return int / factor; + } + + /** + * Returns a lowercase [hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) number. + * + * @param options Maximum value or options object. Defaults to `{}`. + * @param options.min Lower bound for generated number. Defaults to `0`. + * @param options.max Upper bound for generated number. Defaults to `min + 16`. + * + * @example + * faker.number.hex() // 'b' + * faker.number.hex(16) // '9' + * faker.number.hex({ min: 0, max: 65536 }) // 'af17' + * + * @since 8.0.0 + */ + hex(options: number | { min?: number; max?: number } = {}): string { + if (typeof options === 'number') { + options = { max: options }; + } + + const { min = 0, max = min + 16 } = options; + + return this.int({ + max, + min, + }).toString(16); + } + + /** + * Returns a [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#bigint_type) number. + * + * @param options Maximum value or options object. Defaults to `{}`. + * @param options.min Lower bound for generated bigint. Defaults to `0n`. + * @param options.max Upper bound for generated bigint. Defaults to `min + 999999999999999n`. + * + * @throws When options define `max < min`. + * + * @example + * faker.number.bigInt() // 55422n + * faker.number.bigInt(100n) // 52n + * faker.number.bigInt({ min: 1000000n }) // 431433n + * faker.number.bigInt({ max: 100n }) // 42n + * faker.number.bigInt({ min: 10n, max: 100n }) // 36n + * + * @since 8.0.0 + */ + bigInt( + options: + | bigint + | number + | string + | boolean + | { + min?: bigint | number | string | boolean; + max?: bigint | number | string | boolean; + } = {} + ): bigint { + if ( + typeof options === 'bigint' || + typeof options === 'number' || + typeof options === 'string' || + typeof options === 'boolean' + ) { + options = { + max: options, + }; + } + + const min = BigInt(options.min ?? 0); + const max = BigInt(options.max ?? min + BigInt(999999999999999)); + + if (max === min) { + return min; + } + + if (max < min) { + throw new FakerError(`Max ${max} should be larger then min ${min}.`); + } + + const delta = max - min; + + const offset = + BigInt( + this.faker.string.numeric({ + length: delta.toString(10).length, + allowLeadingZeros: true, + }) + ) % + (delta + BigInt(1)); + + return min + offset; + } +} diff --git a/src/modules/random/index.ts b/src/modules/random/index.ts index cb81935b..21e46509 100644 --- a/src/modules/random/index.ts +++ b/src/modules/random/index.ts @@ -151,7 +151,7 @@ export class RandomModule { const words: string[] = []; if (count == null) { - count = this.faker.datatype.number({ min: 1, max: 3 }); + count = this.faker.number.int({ min: 1, max: 3 }); } for (let i = 0; i < count; i++) { diff --git a/src/modules/string/index.ts b/src/modules/string/index.ts index f1a13c1d..de1ec446 100644 --- a/src/modules/string/index.ts +++ b/src/modules/string/index.ts @@ -79,7 +79,7 @@ export type NumericChar = export type AlphaChar = LowerAlphaChar | UpperAlphaChar; export type AlphaNumericChar = AlphaChar | NumericChar; -const SAMPLE_MAX_LENGTH = Math.pow(2, 20); +const SAMPLE_MAX_LENGTH = 2 ** 20; /** * Module to generate string related entries. @@ -416,7 +416,7 @@ export class StringModule { while (returnString.length < length) { returnString += String.fromCharCode( - this.faker.datatype.number(charCodeOption) + this.faker.number.int(charCodeOption) ); } @@ -434,7 +434,7 @@ export class StringModule { uuid(): string { const RFC4122_TEMPLATE = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'; const replacePlaceholders = (placeholder: string) => { - const random = this.faker.datatype.number({ min: 0, max: 15 }); + const random = this.faker.number.int(15); const value = placeholder === 'x' ? random : (random & 0x3) | 0x8; return value.toString(16); }; diff --git a/src/modules/system/index.ts b/src/modules/system/index.ts index 12bb25ba..4bf28aff 100644 --- a/src/modules/system/index.ts +++ b/src/modules/system/index.ts @@ -228,9 +228,9 @@ export class SystemModule { */ semver(): string { return [ - this.faker.datatype.number(9), - this.faker.datatype.number(9), - this.faker.datatype.number(9), + this.faker.number.int(9), + this.faker.number.int(9), + this.faker.number.int(9), ].join('.'); } @@ -262,35 +262,24 @@ export class SystemModule { let suffix: string; let prefix = ''; + const digit = () => this.faker.string.numeric({ allowLeadingZeros: true }); switch (interfaceSchema) { case 'index': - suffix = this.faker.datatype.number(9).toString(); + suffix = digit(); break; case 'slot': - suffix = `${this.faker.datatype.number(9)}${ - this.faker.helpers.maybe(() => `f${this.faker.datatype.number(9)}`) ?? - '' - }${ - this.faker.helpers.maybe(() => `d${this.faker.datatype.number(9)}`) ?? - '' - }`; + suffix = `${digit()}${ + this.faker.helpers.maybe(() => `f${digit()}`) ?? '' + }${this.faker.helpers.maybe(() => `d${digit()}`) ?? ''}`; break; case 'mac': suffix = this.faker.internet.mac(''); break; case 'pci': - prefix = - this.faker.helpers.maybe(() => `P${this.faker.datatype.number(9)}`) ?? - ''; - suffix = `${this.faker.datatype.number(9)}s${this.faker.datatype.number( - 9 - )}${ - this.faker.helpers.maybe(() => `f${this.faker.datatype.number(9)}`) ?? - '' - }${ - this.faker.helpers.maybe(() => `d${this.faker.datatype.number(9)}`) ?? - '' - }`; + prefix = this.faker.helpers.maybe(() => `P${digit()}`) ?? ''; + suffix = `${digit()}s${digit()}${ + this.faker.helpers.maybe(() => `f${digit()}`) ?? '' + }${this.faker.helpers.maybe(() => `d${digit()}`) ?? ''}`; break; } @@ -322,17 +311,17 @@ export class SystemModule { const { includeYear = false, includeNonStandard = false } = options; // create the arrays to hold the available values for each component of the expression - const minutes = [this.faker.datatype.number({ min: 0, max: 59 }), '*']; - const hours = [this.faker.datatype.number({ min: 0, max: 23 }), '*']; - const days = [this.faker.datatype.number({ min: 1, max: 31 }), '*', '?']; - const months = [this.faker.datatype.number({ min: 1, max: 12 }), '*']; + const minutes = [this.faker.number.int(59), '*']; + const hours = [this.faker.number.int(23), '*']; + const days = [this.faker.number.int({ min: 1, max: 31 }), '*', '?']; + const months = [this.faker.number.int({ min: 1, max: 12 }), '*']; const daysOfWeek = [ - this.faker.datatype.number({ min: 0, max: 6 }), + this.faker.number.int(6), this.faker.helpers.arrayElement(CRON_DAY_OF_WEEK), '*', '?', ]; - const years = [this.faker.datatype.number({ min: 1970, max: 2099 }), '*']; + const years = [this.faker.number.int({ min: 1970, max: 2099 }), '*']; const minute = this.faker.helpers.arrayElement(minutes); const hour = this.faker.helpers.arrayElement(hours); diff --git a/src/modules/vehicle/index.ts b/src/modules/vehicle/index.ts index e6bdaeb3..dd08b75f 100644 --- a/src/modules/vehicle/index.ts +++ b/src/modules/vehicle/index.ts @@ -100,8 +100,7 @@ export class VehicleModule { length: 1, casing: 'upper', exclude, - })}${this.faker.datatype.number({ min: 10000, max: 99999 })}` // return five digit # - .toUpperCase(); + })}${this.faker.number.int({ min: 10000, max: 99999 })}`; // return five digit # } /** @@ -128,12 +127,9 @@ export class VehicleModule { return `${this.faker.string.alpha({ length: 2, casing: 'upper', - })}${this.faker.datatype.number({ - min: 0, - max: 9, - })}${this.faker.datatype.number({ - min: 0, - max: 9, + })}${this.faker.string.numeric({ + length: 2, + allowLeadingZeros: true, })}${this.faker.string.alpha({ length: 3, casing: 'upper', -- cgit v1.2.3