diff options
| author | Shinigami92 <[email protected]> | 2022-01-10 21:34:27 +0100 |
|---|---|---|
| committer | Damien Retzinger <[email protected]> | 2022-01-14 18:37:49 -0500 |
| commit | e0d0b5cc45cfde3dd6a351650becf9ea83b99ae2 (patch) | |
| tree | 8014f68054db34065e1192ed61cd2e943ebe9bd5 | |
| parent | b20f80bf7886e89045e369add9c5598d3586a225 (diff) | |
| download | faker-e0d0b5cc45cfde3dd6a351650becf9ea83b99ae2.tar.xz faker-e0d0b5cc45cfde3dd6a351650becf9ea83b99ae2.zip | |
feat: rewrite datatype to ts
| -rw-r--r-- | src/datatype.ts | 253 | ||||
| -rw-r--r-- | src/index.ts | 36 | ||||
| -rw-r--r-- | src/mersenne.ts | 36 | ||||
| -rw-r--r-- | src/random.ts | 24 |
4 files changed, 349 insertions, 0 deletions
diff --git a/src/datatype.ts b/src/datatype.ts new file mode 100644 index 00000000..9aa2dea9 --- /dev/null +++ b/src/datatype.ts @@ -0,0 +1,253 @@ +import type { Faker } from '.'; + +export class Datatype { + constructor(private readonly faker: Faker, seed?: any[] | any) { + // Use a user provided seed if it is an array or number + if (Array.isArray(seed) && seed.length) { + this.faker.mersenne.seed_array(seed); + } else if (!isNaN(seed)) { + this.faker.mersenne.seed(seed); + } + } + + /** + * Returns a single random number based on a max number or range. + * + * @method faker.datatype.number + * @param options + */ + number( + options?: number | { min?: number; max?: number; precision?: number } + ): number { + if (typeof options === 'number') { + options = { max: options }; + } + + options = options ?? {}; + + if (typeof options.min === 'undefined') { + options.min = 0; + } + + if (typeof options.max === 'undefined') { + options.max = 99999; + } + + if (typeof options.precision === 'undefined') { + options.precision = 1; + } + + // Make the range inclusive of the max value + let max = options.max; + if (max >= 0) { + max += options.precision; + } + + let randomNumber = Math.floor( + this.faker.mersenne.rand( + max / options.precision, + options.min / options.precision + ) + ); + // Workaround problem in Float point arithmetics for e.g. 6681493 / 0.01 + randomNumber = randomNumber / (1 / options.precision); + + return randomNumber; + } + + /** + * Returns a single random floating-point number based on a max number or range. + * + * @method faker.datatype.float + * @param options + */ + 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 (typeof opts.precision === 'undefined') { + opts.precision = 0.01; + } + return this.faker.datatype.number(opts); + } + + /** + * Returns a Date object using a random number of milliseconds since 1. Jan 1970 UTC + * Caveat: seeding is not working + * + * @method faker.datatype.datetime + * @param options pass min OR max as number of milliseconds since 1. Jan 1970 UTC + */ + datetime(options): Date { + if (typeof options === 'number') { + options = { + max: options, + }; + } + + const minMax = 8640000000000000; + + options = options || {}; + + if (typeof options.min === 'undefined' || options.min < minMax * -1) { + options.min = new Date().setFullYear(1990, 1, 1); + } + + if (typeof options.max === 'undefined' || options.max > minMax) { + options.max = new Date().setFullYear(2100, 1, 1); + } + + const random = this.faker.datatype.number(options); + return new Date(random); + } + + /** + * Returns a string, containing UTF-16 chars between 33 and 125 ('!' to '}') + * + * + * @method faker.datatype.string + * @param length length of generated string, default = 10, max length = 2^20 + */ + string(length: number = 10): string { + const maxLength = Math.pow(2, 20); + if (length >= maxLength) { + length = maxLength; + } + + const charCodeOption = { + min: 33, + max: 125, + }; + + let returnString = ''; + + for (var i = 0; i < length; i++) { + returnString += String.fromCharCode( + this.faker.datatype.number(charCodeOption) + ); + } + + return returnString; + } + + /** + * uuid + * + * @method faker.datatype.uuid + */ + uuid(): string { + const RFC4122_TEMPLATE = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'; + const replacePlaceholders = (placeholder) => { + const random = this.faker.datatype.number({ min: 0, max: 15 }); + const value = placeholder == 'x' ? random : (random & 0x3) | 0x8; + return value.toString(16); + }; + return RFC4122_TEMPLATE.replace(/[xy]/g, replacePlaceholders); + } + + /** + * boolean + * + * @method faker.datatype.boolean + */ + boolean(): boolean { + return !!this.faker.datatype.number(1); + } + + /** + * hexaDecimal + * + * @method faker.datatype.hexaDecimal + * @param {number} count defaults to 1 + */ + hexaDecimal(count: number = 1): string { + let wholeString = ''; + for (let i = 0; i < count; i++) { + wholeString += this.faker.random.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 json object with 7 pre-defined properties + * + * @method faker.datatype.json + */ + json(): string { + const properties = ['foo', 'bar', 'bike', 'a', 'b', 'name', 'prop']; + + const returnObject: Record<string, string | number> = {}; + properties.forEach((prop) => { + returnObject[prop] = this.faker.datatype.boolean() + ? this.faker.datatype.string() + : this.faker.datatype.number(); + }); + + return JSON.stringify(returnObject); + } + + /** + * Returns an array with values generated by faker.datatype.number and faker.datatype.string + * + * @method faker.datatype.array + * @param length length of the returned array + */ + + array(length: number = 10): Array<string | number> { + const returnArray = new Array(length); + for (var i = 0; i < length; i++) { + returnArray[i] = this.faker.datatype.boolean() + ? this.faker.datatype.string() + : this.faker.datatype.number(); + } + return returnArray; + } + + /** + * Returns a Big Integer with values generated by faker.datatype.bigInt + * + * @method faker.datatype.bigInt + * @param value + */ + bigInt(value?: string | number | bigint | boolean): bigint { + if (value === undefined) { + value = + Math.floor(this.faker.datatype.number() * 99999999999) + 10000000000; + } + + return BigInt(value); + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 00000000..ea724d04 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,36 @@ +import { Datatype } from './datatype'; +import { Mersenne } from './mersenne'; +import { Random } from './random'; + +export interface FakerOptions { + locales?: string[]; + locale?: string; + localeFallback?: string; +} + +export class Faker { + locales: string[] | {}; + locale: string; + localeFallback: string; + + seedValue?: any[] | any; + + readonly mersenne: Mersenne = new Mersenne(); + random = new Random(this); + datatype: Datatype = new Datatype(this); + + constructor(opts: FakerOptions = {}) { + this.locales = this.locales || opts.locales || {}; + this.locale = this.locale || opts.locale || 'en'; + this.localeFallback = this.localeFallback || opts.localeFallback || 'en'; + } + + seed(value?: any[] | any) { + this.seedValue = value; + this.random = new Random(this, this.seedValue); + this.datatype = new Datatype(this, this.seedValue); + } +} + +export default Faker; +module.exports = Faker; diff --git a/src/mersenne.ts b/src/mersenne.ts new file mode 100644 index 00000000..e7ab78eb --- /dev/null +++ b/src/mersenne.ts @@ -0,0 +1,36 @@ +const Gen = require('../vendor/mersenne').MersenneTwister19937; + +export class Mersenne { + private gen = new Gen(); + + constructor() { + this.gen.init_genrand(new Date().getTime() % 1000000000); + } + + rand(max, min) { + if (max === undefined) { + min = 0; + max = 32768; + } + + return Math.floor(this.gen.genrand_real2() * (max - min) + min); + } + + seed(S) { + if (typeof S != 'number') { + throw new Error('seed(S) must take numeric argument; is ' + typeof S); + } + + this.gen.init_genrand(S); + } + + seed_array(A) { + if (typeof A != 'object') { + throw new Error( + 'seed_array(A) must take array of numbers; is ' + typeof A + ); + } + + this.gen.init_by_array(A, A.length); + } +} diff --git a/src/random.ts b/src/random.ts new file mode 100644 index 00000000..8b4feb29 --- /dev/null +++ b/src/random.ts @@ -0,0 +1,24 @@ +import type { Faker } from '.'; + +export class Random { + constructor(private readonly faker: Faker, seed?: any[] | any) { + // Use a user provided seed if it is an array or number + if (Array.isArray(seed) && seed.length) { + this.faker.mersenne.seed_array(seed); + } else if (!isNaN(seed)) { + this.faker.mersenne.seed(seed); + } + } + + /** + * Takes an array and returns a random element of the array. + * + * @method faker.random.arrayElement + * @param array + */ + arrayElement(array) { + array = array || ['a', 'b', 'c']; + var r = this.faker.datatype.number({ max: array.length - 1 }); + return array[r]; + } +} |
