diff options
| author | Leyla Jähnig <[email protected]> | 2022-10-18 19:29:43 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-10-18 19:29:43 +0200 |
| commit | 79858fea203bce7ada9e9bcc7751f6ab25123977 (patch) | |
| tree | 440e365a55814763662392fca10c899acfa2c468 /src/modules/string | |
| parent | c977dbc79da0589557205ad2a95befa1cd6a9dea (diff) | |
| download | faker-79858fea203bce7ada9e9bcc7751f6ab25123977.tar.xz faker-79858fea203bce7ada9e9bcc7751f6ab25123977.zip | |
feat(string): move methods to new module (#1155)
Co-authored-by: Eric Cheng <[email protected]>
Co-authored-by: ST-DDT <[email protected]>
Co-authored-by: Shinigami92 <[email protected]>
Diffstat (limited to 'src/modules/string')
| -rw-r--r-- | src/modules/string/index.ts | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/src/modules/string/index.ts b/src/modules/string/index.ts new file mode 100644 index 00000000..a02fea0f --- /dev/null +++ b/src/modules/string/index.ts @@ -0,0 +1,425 @@ +import type { Faker } from '../..'; +import { FakerError } from '../../errors/faker-error'; +import type { LiteralUnion } from '../../utils/types'; + +export type Casing = 'upper' | 'lower' | 'mixed'; + +const UPPER_CHARS: readonly string[] = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''); +const LOWER_CHARS: readonly string[] = 'abcdefghijklmnopqrstuvwxyz'.split(''); +const DIGIT_CHARS: readonly string[] = '0123456789'.split(''); + +export type LowerAlphaChar = + | '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'; + +export type UpperAlphaChar = + | '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'; + +export type NumericChar = + | '0' + | '1' + | '2' + | '3' + | '4' + | '5' + | '6' + | '7' + | '8' + | '9'; + +export type AlphaChar = LowerAlphaChar | UpperAlphaChar; +export type AlphaNumericChar = AlphaChar | NumericChar; + +const SAMPLE_MAX_LENGTH = Math.pow(2, 20); + +/** + * Module to generate string related entries. + */ +export class StringModule { + constructor(private readonly faker: Faker) { + // Bind `this` so namespaced is working correctly + for (const name of Object.getOwnPropertyNames(StringModule.prototype)) { + if (name === 'constructor' || typeof this[name] !== 'function') { + continue; + } + this[name] = this[name].bind(this); + } + } + + /** + * Generating a string consisting of letters in the English alphabet. + * + * @param options Either the number of characters or an options instance. Defaults to `{ length: 1, casing: 'lower', bannedChars: [] }`. + * @param options.length The number of characters to generate. Defaults to `1`. + * @param options.casing The casing of the characters. Defaults to `'lower'`. + * @param options.bannedChars An array with characters to exclude. Defaults to `[]`. + * + * @example + * faker.string.alpha() // 'b' + * faker.string.alpha(10) // 'qccrabobaf' + * faker.string.alpha({ length: 5, casing: 'upper', bannedChars: ['A'] }) // 'DTCIC' + * + * @since 8.0.0 + */ + alpha( + options: + | number + | { + length?: number; + casing?: Casing; + bannedChars?: readonly LiteralUnion<AlphaChar>[] | string; + } = {} + ): string { + if (typeof options === 'number') { + options = { + length: options, + }; + } + + const { length = 1, casing = 'mixed' } = options; + let { bannedChars = [] } = options; + + if (typeof bannedChars === 'string') { + bannedChars = bannedChars.split(''); + } + + if (length <= 0) { + return ''; + } + + let charsArray: string[]; + switch (casing) { + case 'upper': + charsArray = [...UPPER_CHARS]; + break; + case 'lower': + charsArray = [...LOWER_CHARS]; + break; + case 'mixed': + default: + charsArray = [...LOWER_CHARS, ...UPPER_CHARS]; + break; + } + + charsArray = charsArray.filter((elem) => !bannedChars.includes(elem)); + + if (charsArray.length === 0) { + throw new FakerError( + 'Unable to generate string, because all possible characters are banned.' + ); + } + + return Array.from({ length }, () => + this.faker.helpers.arrayElement(charsArray) + ).join(''); + } + + /** + * Generating a string consisting of alpha characters and digits. + * + * @param options Either the number of characters or an options instance. Defaults to `{ length: 1, casing: 'mixed', bannedChars: [] }`. + * @param options.length The number of characters and digits to generate. Defaults to `1`. + * @param options.casing The casing of the characters. Defaults to `'mixed'`. + * @param options.bannedChars An array of characters and digits which should be banned in the generated string. Defaults to `[]`. + * + * @example + * faker.string.alphanumeric() // '2' + * faker.string.alphanumeric(5) // '3e5v7' + * faker.string.alphanumeric({ length: 5, bannedChars: ["a"] }) // 'xszlm' + * + * @since 8.0.0 + */ + alphanumeric( + options: + | number + | { + length?: number; + casing?: Casing; + bannedChars?: readonly LiteralUnion<AlphaNumericChar>[] | string; + } = {} + ): string { + if (typeof options === 'number') { + options = { + length: options, + }; + } + + const { length = 1, casing = 'mixed' } = options; + + if (length <= 0) { + return ''; + } + + let { bannedChars = [] } = options; + + if (typeof bannedChars === 'string') { + bannedChars = bannedChars.split(''); + } + + let charsArray = [...DIGIT_CHARS]; + + switch (casing) { + case 'upper': + charsArray.push(...UPPER_CHARS); + break; + case 'lower': + charsArray.push(...LOWER_CHARS); + break; + case 'mixed': + default: + charsArray.push(...LOWER_CHARS, ...UPPER_CHARS); + break; + } + + charsArray = charsArray.filter((elem) => !bannedChars.includes(elem)); + + if (charsArray.length === 0) { + throw new FakerError( + 'Unable to generate string, because all possible characters are banned.' + ); + } + + return Array.from({ length }, () => + this.faker.helpers.arrayElement(charsArray) + ).join(''); + } + + /** + * Returns a [hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) string. + * + * @param options The optional options object. + * @param options.length Length of the generated number. Defaults to `1`. + * @param options.casing Casing of the generated number. Defaults to `'mixed'`. + * @param options.prefix Prefix for the generated number. Defaults to `'0x'`. + * + * @example + * faker.string.hexadecimal() // '0xB' + * faker.string.hexadecimal({ length: 10 }) // '0xaE13d044cB' + * faker.string.hexadecimal({ prefix: '0x' }) // '0xE' + * faker.string.hexadecimal({ casing: 'lower' }) // '0xf' + * faker.string.hexadecimal({ length: 10, prefix: '#' }) // '#f12a974eB1' + * faker.string.hexadecimal({ length: 10, casing: 'upper' }) // '0xE3F38014FB' + * faker.string.hexadecimal({ casing: 'lower', prefix: '' }) // 'd' + * faker.string.hexadecimal({ length: 10, casing: 'mixed', prefix: '0x' }) // '0xAdE330a4D1' + * + * @since 8.0.0 + */ + hexadecimal( + options: { + length?: number; + casing?: Casing; + prefix?: string; + } = {} + ): string { + const { length = 1, casing = 'mixed', prefix = '0x' } = options; + + 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', + ]); + } + + if (casing === 'upper') { + wholeString = wholeString.toUpperCase(); + } else if (casing === 'lower') { + wholeString = wholeString.toLowerCase(); + } + + return `${prefix}${wholeString}`; + } + + /** + * Generates a given length string of digits. + * + * @param options Either the number of characters or the options to use. Defaults to `{ length: 1, allowLeadingZeros = false, bannedDigits = [] }`. + * @param options.length The number of digits to generate. Defaults to `1`. + * @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.string.numeric() // '2' + * faker.string.numeric(5) // '31507' + * faker.string.numeric(42) // '56434563150765416546479875435481513188548' + * faker.string.numeric({ length: 42, allowLeadingZeros: true }) // '00564846278453876543517840713421451546115' + * faker.string.numeric({ length: 6, bannedDigits: ['0'] }) // '943228' + * + * @since 8.0.0 + */ + numeric( + options: + | number + | { + length?: number; + allowLeadingZeros?: boolean; + bannedDigits?: readonly LiteralUnion<NumericChar>[] | string; + } = {} + ): string { + if (typeof options === 'number') { + options = { + length: options, + }; + } + + const { length = 1, allowLeadingZeros = false } = options; + if (length <= 0) { + return ''; + } + + let { bannedDigits = [] } = options; + + if (typeof bannedDigits === 'string') { + bannedDigits = bannedDigits.split(''); + } + + const allowedDigits = DIGIT_CHARS.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 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.string.sample() // 'Zo!.:*e>wR' + * faker.string.sample(5) // '6Bye8' + * + * @since 8.0.0 + */ + sample(length = 10): string { + if (length >= SAMPLE_MAX_LENGTH) { + length = SAMPLE_MAX_LENGTH; + } + + const charCodeOption = { + min: 33, + max: 125, + }; + + let returnString = ''; + + while (returnString.length < length) { + returnString += String.fromCharCode( + this.faker.datatype.number(charCodeOption) + ); + } + + return returnString; + } + + /** + * Returns a UUID v4 ([Universally Unique Identifier](https://en.wikipedia.org/wiki/Universally_unique_identifier)). + * + * @example + * faker.string.uuid() // '4136cd0b-d90b-4af7-b485-5d1ded8db252' + * + * @since 8.0.0 + */ + 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 value = placeholder === 'x' ? random : (random & 0x3) | 0x8; + return value.toString(16); + }; + return RFC4122_TEMPLATE.replace(/[xy]/g, replacePlaceholders); + } +} |
