From 405b12917b00a9386274af5f303ae25215a13034 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Sun, 13 Nov 2022 17:09:07 +0700 Subject: [PATCH 01/20] fix(internet): use a ascii-only fallback for email addresses in some locales, revert slugify to ascii only --- src/modules/helpers/index.ts | 4 +--- src/modules/internet/index.ts | 10 ++++++++++ test/internet.spec.ts | 13 ------------- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts index 7da4fbc8889..2d9400c30ae 100644 --- a/src/modules/helpers/index.ts +++ b/src/modules/helpers/index.ts @@ -32,9 +32,7 @@ export class HelpersModule { * @since 2.0.1 */ slugify(string: string = ''): string { - return string - .replace(/ /g, '-') - .replace(/[^\一-龠\ぁ-ゔ\ァ-ヴー\w\.\-]+/g, ''); + return string.replace(/ /g, '-').replace(/[^\w\.\-]+/g, ''); } /** diff --git a/src/modules/internet/index.ts b/src/modules/internet/index.ts index 60e3ac55a46..db6d342078a 100644 --- a/src/modules/internet/index.ts +++ b/src/modules/internet/index.ts @@ -85,6 +85,16 @@ export class InternetModule { this.userName(firstName, lastName) ); + //In some locales e.g. ja or el, userName contains mostly non-Unicode characters + //https://github.com/faker-js/faker/issues/1105 + //After slugify it becomes a string with only 0-9, _ and . + //In that case we generate a purely random local part instead + const invalidLocalPart: boolean = /^[0-9\._]*$/.test(localPart); + if (invalidLocalPart) { + localPart = + this.faker.string.alpha({ length: 2, casing: 'lower' }) + + this.faker.datatype.number({ min: 10000, max: 9999999 }).toString(); + } if (options?.allowSpecialCharacters) { const usernameChars: string[] = '._-'.split(''); const specialChars: string[] = ".!#$%&'*+-/=?^_`{|}~".split(''); diff --git a/test/internet.spec.ts b/test/internet.spec.ts index 02f0edaa760..d632f59862e 100644 --- a/test/internet.spec.ts +++ b/test/internet.spec.ts @@ -130,19 +130,6 @@ describe('internet', () => { expect(faker.definitions.internet.free_email).toContain(suffix); }); - it('should return an email with japanese characters', () => { - const email = faker.internet.email('思源_唐3'); - - expect(email).toBeTruthy(); - expect(email).toBeTypeOf('string'); - expect(email).toSatisfy(validator.isEmail); - - const [prefix, suffix] = email.split('@'); - - expect(prefix).toMatch(/^思源_唐3/); - expect(faker.definitions.internet.free_email).toContain(suffix); - }); - it('should return an email with special characters', () => { const email = faker.internet.email('Mike', 'Smith', null, { allowSpecialCharacters: true, From 4b137b40e917130c6496acfd9fbcdfcff302f434 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Sun, 13 Nov 2022 17:33:39 +0700 Subject: [PATCH 02/20] fix(internet): use a ascii-only fallback for email addresses in some locales, revert slugify to ascii only --- test/internet.spec.ts | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/test/internet.spec.ts b/test/internet.spec.ts index d632f59862e..abe29e25d8f 100644 --- a/test/internet.spec.ts +++ b/test/internet.spec.ts @@ -190,20 +190,6 @@ describe('internet', () => { expect(prefix).toMatch(/^Aiden([._]Harann)?\d*/); }); - it('should return an email with the example suffix and japanese characters', () => { - const email = faker.internet.exampleEmail('思源_唐3'); - - expect(email).toBeTruthy(); - expect(email).toBeTypeOf('string'); - expect(email).toSatisfy(validator.isEmail); - - const [prefix, suffix] = email.split('@'); - - expect(suffix).toMatch(/^example\.(com|net|org)$/); - expect(faker.definitions.internet.example_email).toContain(suffix); - expect(prefix).toMatch(/^思源_唐3/); - }); - it('should return an email with special characters', () => { const email = faker.internet.exampleEmail('Mike', 'Smith', { allowSpecialCharacters: true, From bf18f4ae4b8c3eef49e353d07aade988405e31aa Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Sun, 13 Nov 2022 23:47:48 +0700 Subject: [PATCH 03/20] fix(internet): use a ascii-only fallback for email addresses in some locales, revert slugify to ascii only - add test --- test/internet.spec.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/internet.spec.ts b/test/internet.spec.ts index abe29e25d8f..e3103c177d7 100644 --- a/test/internet.spec.ts +++ b/test/internet.spec.ts @@ -98,6 +98,20 @@ describe('internet', () => { expect(faker.definitions.internet.free_email).toContain(suffix); }); + it('should return a valid email in every locale', () => { + for (const locale of Object.keys(faker.locales)) { + faker.setLocale(locale); + const email = faker.internet.email(); + + expect(email).toBeTruthy(); + expect(email).toBeTypeOf('string'); + expect(email).toSatisfy( + validator.isEmail, + `locale: ${locale} has invalid email: ${email}` + ); + } + }); + it('should return an email with given firstName', () => { const email = faker.internet.email('Aiden.Harann55'); From ddbb19a693a0ae84efa7ee3a4ff935a8e65592e7 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Sun, 13 Nov 2022 23:51:01 +0700 Subject: [PATCH 04/20] fix(internet): use a ascii-only fallback for email addresses in some locales, revert slugify to ascii only - fix test --- test/internet.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/internet.spec.ts b/test/internet.spec.ts index e3103c177d7..1bcb09f61cc 100644 --- a/test/internet.spec.ts +++ b/test/internet.spec.ts @@ -109,7 +109,7 @@ describe('internet', () => { validator.isEmail, `locale: ${locale} has invalid email: ${email}` ); - } + } }); it('should return an email with given firstName', () => { From 219173d3593633d47a0cfcc061bf07c6d9a7f073 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Thu, 17 Nov 2022 16:05:03 +0700 Subject: [PATCH 05/20] Update src/modules/internet/index.ts Co-authored-by: Shinigami --- src/modules/internet/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/internet/index.ts b/src/modules/internet/index.ts index db6d342078a..2019ad033a4 100644 --- a/src/modules/internet/index.ts +++ b/src/modules/internet/index.ts @@ -85,10 +85,10 @@ export class InternetModule { this.userName(firstName, lastName) ); - //In some locales e.g. ja or el, userName contains mostly non-Unicode characters - //https://github.com/faker-js/faker/issues/1105 - //After slugify it becomes a string with only 0-9, _ and . - //In that case we generate a purely random local part instead + // In some locales e.g. ja or el, userName contains mostly non-Unicode characters + // https://github.com/faker-js/faker/issues/1105 + // After slugify it becomes a string with only 0-9, _ and . + // In that case we generate a purely random local part instead const invalidLocalPart: boolean = /^[0-9\._]*$/.test(localPart); if (invalidLocalPart) { localPart = From c37ffcddc38f72ea18fe97392e5571fd79351a41 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Sun, 20 Nov 2022 23:35:20 +0700 Subject: [PATCH 06/20] fix(internet): use a ascii-only fallback for email addresses in some locales, revert slugify to ascii only - allow stripping diacritics --- src/modules/helpers/index.ts | 6 +++++- test/helpers.spec.ts | 16 ++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts index 2d9400c30ae..9928f1b6f7e 100644 --- a/src/modules/helpers/index.ts +++ b/src/modules/helpers/index.ts @@ -32,7 +32,11 @@ export class HelpersModule { * @since 2.0.1 */ slugify(string: string = ''): string { - return string.replace(/ /g, '-').replace(/[^\w\.\-]+/g, ''); + return string + .normalize('NFKD') //for example è decomposes to as e + ̀ + .replace(/[\u0300-\u036f]/g, '') // removes combining marks + .replace(/ /g, '-') // replaces spaces with hyphens + .replace(/[^\w\.\-]+/g, ''); // removes all non-word characters except for dots and hyphens } /** diff --git a/test/helpers.spec.ts b/test/helpers.spec.ts index a8a89b3ad2d..6705ce09341 100644 --- a/test/helpers.spec.ts +++ b/test/helpers.spec.ts @@ -176,9 +176,21 @@ describe('helpers', () => { }); describe('slugify()', () => { - it('removes unwanted characters from URI string', () => { - expect(faker.helpers.slugify('Aiden.Harªann')).toBe('Aiden.Harann'); + it('removes non-word characters from strings except . and -', () => { + expect(faker.helpers.slugify('foo bar')).toBe('foo-bar'); + expect(faker.helpers.slugify('Faker is cool')).toBe('Faker-is-cool'); + expect(faker.helpers.slugify('super*star')).toBe('superstar'); expect(faker.helpers.slugify("d'angelo.net")).toBe('dangelo.net'); + expect(faker.helpers.slugify('hello你好')).toBe('hello'); + }); + }); + + describe('slugify()', () => { + it('strips simple diacritics from strings', () => { + expect(faker.helpers.slugify('Aiden.Harªann')).toBe('Aiden.Haraann'); + expect(faker.helpers.slugify('Adèle.Argüello')).toBe( + 'Adele.Arguello' + ); }); }); From d4b958be32ed9b35611e69d50d853b36e102386f Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Fri, 25 Nov 2022 13:14:04 +0700 Subject: [PATCH 07/20] fix(internet): make faker.internet.userName return ASCII only --- src/modules/internet/index.ts | 111 +++++++++++++++++++++++++++++----- 1 file changed, 96 insertions(+), 15 deletions(-) diff --git a/src/modules/internet/index.ts b/src/modules/internet/index.ts index 2019ad033a4..2b182b5e107 100644 --- a/src/modules/internet/index.ts +++ b/src/modules/internet/index.ts @@ -81,20 +81,7 @@ export class InternetModule { this.faker.definitions.internet.free_email ); - let localPart: string = this.faker.helpers.slugify( - this.userName(firstName, lastName) - ); - - // In some locales e.g. ja or el, userName contains mostly non-Unicode characters - // https://github.com/faker-js/faker/issues/1105 - // After slugify it becomes a string with only 0-9, _ and . - // In that case we generate a purely random local part instead - const invalidLocalPart: boolean = /^[0-9\._]*$/.test(localPart); - if (invalidLocalPart) { - localPart = - this.faker.string.alpha({ length: 2, casing: 'lower' }) + - this.faker.datatype.number({ min: 10000, max: 9999999 }).toString(); - } + let localPart: string = this.userName(firstName, lastName); if (options?.allowSpecialCharacters) { const usernameChars: string[] = '._-'.split(''); const specialChars: string[] = ".!#$%&'*+-/=?^_`{|}~".split(''); @@ -135,7 +122,7 @@ export class InternetModule { } /** - * Generates a username using the given person's name as base. + * Generates a username using the given person's name as base. This will always return a plain ASCII string. * * @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. @@ -165,8 +152,102 @@ export class InternetModule { ])}${lastName}${this.faker.datatype.number(99)}`; break; } + + //There may still be non-ascii characters in the result. + //First remove simple accents etc + result = result + .normalize('NFKD') //for example è decomposes to as e + ̀ + .replace(/[\u0300-\u036f]/g, ''); // removes combining marks + + //simple mapping for Cyrillic - FIXME we could also do this for some other simple alphabets like Greek and Thai + const mappings: { [key: string]: string } = { + Ё: 'YO', + Й: 'I', + Ц: 'TS', + У: 'U', + К: 'K', + Е: 'E', + Н: 'N', + Г: 'G', + Ш: 'SH', + Щ: 'SCH', + З: 'Z', + Х: 'H', + Ъ: "'", + ё: 'yo', + й: 'i', + ц: 'ts', + у: 'u', + к: 'k', + е: 'e', + н: 'n', + г: 'g', + ш: 'sh', + щ: 'sch', + з: 'z', + х: 'h', + ъ: "'", + Ф: 'F', + Ы: 'I', + В: 'V', + А: 'А', + П: 'P', + Р: 'R', + О: 'O', + Л: 'L', + Д: 'D', + Ж: 'ZH', + Э: 'E', + ф: 'f', + ы: 'i', + в: 'v', + а: 'a', + п: 'p', + р: 'r', + о: 'o', + л: 'l', + д: 'd', + ж: 'zh', + э: 'e', + Я: 'Ya', + Ч: 'CH', + С: 'S', + М: 'M', + И: 'I', + Т: 'T', + Ь: "'", + Б: 'B', + Ю: 'YU', + я: 'ya', + ч: 'ch', + с: 's', + м: 'm', + и: 'i', + т: 't', + ь: "'", + б: 'b', + ю: 'yu', + }; + result = result + .split('') + .map(function (char) { + //if we have a mapping for this character, use it + if (mappings[char]) { + return mappings[char]; + } + if (char.charCodeAt(0) < 0x80) { + //keep ascii characters + return char; + } + //return the hex value for Chinese, Japanese, Korean etc + return char.charCodeAt(0).toString(16); + }) + .join(''); + + //remove spaces and ' result = result.toString().replace(/'/g, ''); result = result.replace(/ /g, ''); + return result; } From 83cd5197a269a0cbeb054965fa918be7853fee83 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Fri, 25 Nov 2022 21:41:32 +0700 Subject: [PATCH 08/20] fix(internet): make faker.internet.userName return ASCII only - and use base36 as fallback --- src/modules/internet/char-mappings.ts | 68 +++++++++++++++++++++ src/modules/internet/index.ts | 88 ++++----------------------- 2 files changed, 80 insertions(+), 76 deletions(-) create mode 100644 src/modules/internet/char-mappings.ts diff --git a/src/modules/internet/char-mappings.ts b/src/modules/internet/char-mappings.ts new file mode 100644 index 00000000000..7bdc400ecc1 --- /dev/null +++ b/src/modules/internet/char-mappings.ts @@ -0,0 +1,68 @@ +export const charMapping: { [key: string]: string } = { + Ё: 'YO', + Й: 'I', + Ц: 'TS', + У: 'U', + К: 'K', + Е: 'E', + Н: 'N', + Г: 'G', + Ш: 'SH', + Щ: 'SCH', + З: 'Z', + Х: 'H', + Ъ: "'", + ё: 'yo', + й: 'i', + ц: 'ts', + у: 'u', + к: 'k', + е: 'e', + н: 'n', + г: 'g', + ш: 'sh', + щ: 'sch', + з: 'z', + х: 'h', + ъ: "'", + Ф: 'F', + Ы: 'I', + В: 'V', + А: 'А', + П: 'P', + Р: 'R', + О: 'O', + Л: 'L', + Д: 'D', + Ж: 'ZH', + Э: 'E', + ф: 'f', + ы: 'i', + в: 'v', + а: 'a', + п: 'p', + р: 'r', + о: 'o', + л: 'l', + д: 'd', + ж: 'zh', + э: 'e', + Я: 'Ya', + Ч: 'CH', + С: 'S', + М: 'M', + И: 'I', + Т: 'T', + Ь: "'", + Б: 'B', + Ю: 'YU', + я: 'ya', + ч: 'ch', + с: 's', + м: 'm', + и: 'i', + т: 't', + ь: "'", + б: 'b', + ю: 'yu', +}; diff --git a/src/modules/internet/index.ts b/src/modules/internet/index.ts index 2b182b5e107..44b5da5f327 100644 --- a/src/modules/internet/index.ts +++ b/src/modules/internet/index.ts @@ -1,5 +1,6 @@ import type { Faker } from '../..'; import * as random_ua from './user-agent'; +import { charMapping } from './char-mappings'; export type EmojiType = | 'smiley' @@ -122,14 +123,18 @@ export class InternetModule { } /** - * Generates a username using the given person's name as base. This will always return a plain ASCII string. + * Generates a username using the given person's name as base. This will always return a plain ASCII string. Some basic stripping of accents and transliteration of characters will be done. * * @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 lastName The optional last name to use - though the last name is not always used. If not specified, a random one will be chosen. * * @example * faker.internet.userName() // 'Nettie_Zboncak40' * faker.internet.userName('Jeanne', 'Doe') // 'Jeanne98' + * faker.internet.userName('John', 'Doe') // 'John.Doe' + * faker.internet.userName('Hélene', 'Müller') // 'Helene_Muller11' + * faker.internet.userName('Фёдор', 'Достоевский') // 'Fedor.Dostoevskii50' + * faker.internet.userName("大羽","陳") //hlzp8d.tpv45 * * @since 2.0.1 */ @@ -159,88 +164,19 @@ export class InternetModule { .normalize('NFKD') //for example è decomposes to as e + ̀ .replace(/[\u0300-\u036f]/g, ''); // removes combining marks - //simple mapping for Cyrillic - FIXME we could also do this for some other simple alphabets like Greek and Thai - const mappings: { [key: string]: string } = { - Ё: 'YO', - Й: 'I', - Ц: 'TS', - У: 'U', - К: 'K', - Е: 'E', - Н: 'N', - Г: 'G', - Ш: 'SH', - Щ: 'SCH', - З: 'Z', - Х: 'H', - Ъ: "'", - ё: 'yo', - й: 'i', - ц: 'ts', - у: 'u', - к: 'k', - е: 'e', - н: 'n', - г: 'g', - ш: 'sh', - щ: 'sch', - з: 'z', - х: 'h', - ъ: "'", - Ф: 'F', - Ы: 'I', - В: 'V', - А: 'А', - П: 'P', - Р: 'R', - О: 'O', - Л: 'L', - Д: 'D', - Ж: 'ZH', - Э: 'E', - ф: 'f', - ы: 'i', - в: 'v', - а: 'a', - п: 'p', - р: 'r', - о: 'o', - л: 'l', - д: 'd', - ж: 'zh', - э: 'e', - Я: 'Ya', - Ч: 'CH', - С: 'S', - М: 'M', - И: 'I', - Т: 'T', - Ь: "'", - Б: 'B', - Ю: 'YU', - я: 'ya', - ч: 'ch', - с: 's', - м: 'm', - и: 'i', - т: 't', - ь: "'", - б: 'b', - ю: 'yu', - }; result = result .split('') .map(function (char) { - //if we have a mapping for this character, use it - if (mappings[char]) { - return mappings[char]; + //if we have a mapping for this character, (for Cyrillic, Greek etc) use it + if (charMapping[char]) { + return charMapping[char]; } if (char.charCodeAt(0) < 0x80) { //keep ascii characters return char; } - //return the hex value for Chinese, Japanese, Korean etc - return char.charCodeAt(0).toString(16); + //final fallback return the Unicode char code value for Chinese, Japanese, Korean etc, base-36 encoded + return char.charCodeAt(0).toString(36); }) .join(''); From 225de8d6cff9fc548fc608ca73b5f9ef2aba2fd2 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Fri, 25 Nov 2022 21:44:42 +0700 Subject: [PATCH 09/20] fix(internet): add faker.internet.displayName --- src/modules/internet/index.ts | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/modules/internet/index.ts b/src/modules/internet/index.ts index 44b5da5f327..b77706e0fcc 100644 --- a/src/modules/internet/index.ts +++ b/src/modules/internet/index.ts @@ -187,6 +187,46 @@ export class InternetModule { return result; } + /** + * Generates a display name using the given person's name as base. If the input names include Unicode characters, the resulting display name will contain Unicode characters. It will not contain spaces. + * + * @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.displayName() // 'Nettie_Zboncak40' + * faker.internet.displayName('Jeanne', 'Doe') // 'Jeanne98' + * faker.internet.displayName('John', 'Doe') // 'John.Doe' + * faker.internet.displayName('Hélene', 'Müller') // 'Hélene_Müller11' + * faker.internet.displayName('Фёдор', 'Достоевский') // 'Фёдор.Достоевский50' + * faker.internet.displayName("大羽","陳") //大羽.陳 + * + * @since 8.0.0 + */ + displayName(firstName?: string, lastName?: string): string { + let result: string; + firstName = firstName || this.faker.person.firstName(); + lastName = lastName || this.faker.person.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`. * From 5280dd09934f1646f65729b52ee2d7efc6d7a342 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Fri, 25 Nov 2022 23:04:36 +0700 Subject: [PATCH 10/20] fix(internet): add displayName tests, add Greek --- src/modules/internet/char-mappings.ts | 80 +++++++++++++++++++++++- test/__snapshots__/internet.spec.ts.snap | 12 ++++ test/internet.spec.ts | 48 ++++++++++++++ 3 files changed, 138 insertions(+), 2 deletions(-) diff --git a/src/modules/internet/char-mappings.ts b/src/modules/internet/char-mappings.ts index 7bdc400ecc1..760991a497a 100644 --- a/src/modules/internet/char-mappings.ts +++ b/src/modules/internet/char-mappings.ts @@ -1,4 +1,4 @@ -export const charMapping: { [key: string]: string } = { +const cyrillicMapping: { [key: string]: string } = { Ё: 'YO', Й: 'I', Ц: 'TS', @@ -28,7 +28,7 @@ export const charMapping: { [key: string]: string } = { Ф: 'F', Ы: 'I', В: 'V', - А: 'А', + А: 'A', П: 'P', Р: 'R', О: 'O', @@ -66,3 +66,79 @@ export const charMapping: { [key: string]: string } = { б: 'b', ю: 'yu', }; +const greekMapping: { [key: string]: string } = { + α: 'a', + ά: 'a', + Ά: 'A', + β: 'b', + Β: 'B', + γ: 'g', + Γ: 'G', + δ: 'd', + Δ: 'D', + ε: 'e', + Ε: 'E', + έ: 'e', + Έ: 'E', + ζ: 'z', + Ζ: 'Z', + η: 'h', + Η: 'H', + ή: 'h', + Ή: 'H', + θ: 'th', + Θ: 'TH', + ι: 'i', + Ι: 'I', + ί: 'i', + Ί: 'I', + ϊ: 'i', + Ϊ: 'I', + ΐ: 'i', + κ: 'k', + Κ: 'K', + λ: 'l', + Λ: 'L', + μ: 'm', + Μ: 'M', + ν: 'n', + Ν: 'N', + ξ: 'ks', + Ξ: 'KS', + ο: 'o', + Ο: 'O', + ό: 'o', + Ό: 'O', + π: 'p', + Π: 'P', + ρ: 'r', + Ρ: 'R', + σ: 's', + Σ: 'S', + ς: 's', + τ: 't', + Τ: 'T', + υ: 'y', + Υ: 'Y', + ύ: 'y', + Ύ: 'Y', + ϋ: 'y', + Ϋ: 'Y', + ΰ: 'y', + φ: 'f', + Φ: 'F', + χ: 'x', + Χ: 'X', + ψ: 'ps', + Ψ: 'Ps', + ω: 'w', + Ω: 'w', + ώ: 'w', + Ώ: 'w', + Α: 'A', +}; + +export const charMapping: { [key: string]: string } = { + ...cyrillicMapping, + ...greekMapping, +}; diff --git a/test/__snapshots__/internet.spec.ts.snap b/test/__snapshots__/internet.spec.ts.snap index 4b87bff9c4d..bdf36cda026 100644 --- a/test/__snapshots__/internet.spec.ts.snap +++ b/test/__snapshots__/internet.spec.ts.snap @@ -6,6 +6,10 @@ exports[`internet > 42 > color > noArgs 1`] = `"#30667a"`; exports[`internet > 42 > color > with color base 1`] = `"#6298ac"`; +exports[`internet > 42 > displayName > noArgs 1`] = `"Garnet.Schinner73"`; + +exports[`internet > 42 > displayName > with names 1`] = `"Jane_Doe"`; + exports[`internet > 42 > domainName 1`] = `"hasty-shin.org"`; exports[`internet > 42 > domainSuffix 1`] = `"info"`; @@ -70,6 +74,10 @@ exports[`internet > 1211 > color > noArgs 1`] = `"#773a72"`; exports[`internet > 1211 > color > with color base 1`] = `"#a96ca4"`; +exports[`internet > 1211 > displayName > noArgs 1`] = `"Tito_Koelpin22"`; + +exports[`internet > 1211 > displayName > with names 1`] = `"Jane.Doe89"`; + exports[`internet > 1211 > domainName 1`] = `"vibrant-infix.org"`; exports[`internet > 1211 > domainSuffix 1`] = `"org"`; @@ -134,6 +142,10 @@ exports[`internet > 1337 > color > noArgs 1`] = `"#214814"`; exports[`internet > 1337 > color > with color base 1`] = `"#537a46"`; +exports[`internet > 1337 > displayName > noArgs 1`] = `"Devyn21"`; + +exports[`internet > 1337 > displayName > with names 1`] = `"Jane56"`; + exports[`internet > 1337 > domainName 1`] = `"fair-migration.com"`; exports[`internet > 1337 > domainSuffix 1`] = `"biz"`; diff --git a/test/internet.spec.ts b/test/internet.spec.ts index 1bcb09f61cc..5d9c2cc3d79 100644 --- a/test/internet.spec.ts +++ b/test/internet.spec.ts @@ -41,6 +41,10 @@ describe('internet', () => { t.it('noArgs').it('with names', 'Jane', 'Doe'); }); + t.describe('displayName', (t) => { + t.it('noArgs').it('with names', 'Jane', 'Doe'); + }); + t.describe('password', (t) => { t.it('noArgs').it('with length', 10); }); @@ -249,6 +253,50 @@ describe('internet', () => { /^Aiden((\d{1,2})|([._]Harann\d{1,2})|([._](Harann)))/ ); }); + + it('should strip accents', () => { + const username = faker.internet.userName('Adèle', 'Smith'); + expect(username).includes('Adele'); + }); + + it('should transliterate Cyrillic', () => { + const username = faker.internet.userName('Амос', 'Васильев'); + expect(username).includes('Amos'); + }); + + it('should provide a fallback for Chinese etc', () => { + const username = faker.internet.userName('大羽', '陳'); + expect(username).includes('hlzp8d'); + }); + }); + describe('displayName()', () => { + it('should return a random display name', () => { + const displayName = faker.internet.displayName(); + + expect(displayName).toBeTruthy(); + expect(displayName).toBeTypeOf('string'); + expect(displayName).toMatch(/\w/); + }); + + it('should return a random display name with given firstName', () => { + const displayName = faker.internet.displayName('Aiden'); + + expect(displayName).toBeTruthy(); + expect(displayName).toBeTypeOf('string'); + expect(displayName).toMatch(/\w/); + expect(displayName).includes('Aiden'); + }); + + it('should return a random display name with given firstName and lastName', () => { + const displayName = faker.internet.displayName('Aiden', 'Harann'); + + expect(displayName).toBeTruthy(); + expect(displayName).toBeTypeOf('string'); + expect(displayName).includes('Aiden'); + expect(displayName).toMatch( + /^Aiden((\d{1,2})|([._]Harann\d{1,2})|([._](Harann)))/ + ); + }); }); describe('protocol()', () => { From f16a53c160e4f9e5ffd2779fe8aaa626959fe410 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Fri, 25 Nov 2022 23:13:22 +0700 Subject: [PATCH 11/20] fix(internet): fix deprecations --- src/modules/internet/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/internet/index.ts b/src/modules/internet/index.ts index 4731a3e64b2..ea5c6e991d3 100644 --- a/src/modules/internet/index.ts +++ b/src/modules/internet/index.ts @@ -1,6 +1,6 @@ import type { Faker } from '../..'; -import * as random_ua from './user-agent'; import { charMapping } from './char-mappings'; +import * as random_ua from './user-agent'; export type EmojiType = | 'smiley' @@ -142,9 +142,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 = @@ -154,7 +154,7 @@ export class InternetModule { result = `${firstName}${this.faker.helpers.arrayElement([ '.', '_', - ])}${lastName}${this.faker.datatype.number(99)}`; + ])}${lastName}${this.faker.number.int(99)}`; break; } From 82cb25423803c65650c1e518942a21f634fc3338 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Fri, 25 Nov 2022 23:19:16 +0700 Subject: [PATCH 12/20] fix(internet): fix lint --- src/modules/internet/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/internet/index.ts b/src/modules/internet/index.ts index ea5c6e991d3..41b8d6de38e 100644 --- a/src/modules/internet/index.ts +++ b/src/modules/internet/index.ts @@ -203,7 +203,7 @@ export class InternetModule { * * @since 8.0.0 */ - displayName(firstName?: string, lastName?: string): string { + displayName(firstName?: string, lastName?: string): string { let result: string; firstName = firstName || this.faker.person.firstName(); lastName = lastName || this.faker.person.lastName(); From 9e662250f321538f823476e5b21e9511a7dec5b0 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Fri, 25 Nov 2022 23:38:13 +0700 Subject: [PATCH 13/20] fix(internet): new source and add arabic,farsi,armenian --- src/modules/internet/char-mappings.ts | 421 +++++++++++++++++--------- 1 file changed, 281 insertions(+), 140 deletions(-) diff --git a/src/modules/internet/char-mappings.ts b/src/modules/internet/char-mappings.ts index 760991a497a..942a805de00 100644 --- a/src/modules/internet/char-mappings.ts +++ b/src/modules/internet/char-mappings.ts @@ -1,144 +1,285 @@ -const cyrillicMapping: { [key: string]: string } = { - Ё: 'YO', - Й: 'I', - Ц: 'TS', - У: 'U', - К: 'K', - Е: 'E', - Н: 'N', - Г: 'G', - Ш: 'SH', - Щ: 'SCH', - З: 'Z', - Х: 'H', - Ъ: "'", - ё: 'yo', - й: 'i', - ц: 'ts', - у: 'u', - к: 'k', - е: 'e', - н: 'n', - г: 'g', - ш: 'sh', - щ: 'sch', - з: 'z', - х: 'h', - ъ: "'", - Ф: 'F', - Ы: 'I', - В: 'V', - А: 'A', - П: 'P', - Р: 'R', - О: 'O', - Л: 'L', - Д: 'D', - Ж: 'ZH', - Э: 'E', - ф: 'f', - ы: 'i', - в: 'v', - а: 'a', - п: 'p', - р: 'r', - о: 'o', - л: 'l', - д: 'd', - ж: 'zh', - э: 'e', - Я: 'Ya', - Ч: 'CH', - С: 'S', - М: 'M', - И: 'I', - Т: 'T', - Ь: "'", - Б: 'B', - Ю: 'YU', - я: 'ya', - ч: 'ch', - с: 's', - м: 'm', - и: 'i', - т: 't', - ь: "'", - б: 'b', - ю: 'yu', -}; -const greekMapping: { [key: string]: string } = { - α: 'a', - ά: 'a', - Ά: 'A', - β: 'b', - Β: 'B', - γ: 'g', - Γ: 'G', - δ: 'd', - Δ: 'D', - ε: 'e', - Ε: 'E', - έ: 'e', - Έ: 'E', - ζ: 'z', - Ζ: 'Z', - η: 'h', - Η: 'H', - ή: 'h', - Ή: 'H', - θ: 'th', - Θ: 'TH', - ι: 'i', - Ι: 'I', - ί: 'i', - Ί: 'I', - ϊ: 'i', - Ϊ: 'I', - ΐ: 'i', - κ: 'k', - Κ: 'K', - λ: 'l', - Λ: 'L', - μ: 'm', - Μ: 'M', - ν: 'n', - Ν: 'N', - ξ: 'ks', - Ξ: 'KS', - ο: 'o', - Ο: 'O', - ό: 'o', - Ό: 'O', - π: 'p', - Π: 'P', - ρ: 'r', - Ρ: 'R', - σ: 's', - Σ: 'S', - ς: 's', - τ: 't', - Τ: 'T', - υ: 'y', - Υ: 'Y', - ύ: 'y', - Ύ: 'Y', - ϋ: 'y', - Ϋ: 'Y', - ΰ: 'y', - φ: 'f', - Φ: 'F', - χ: 'x', - Χ: 'X', - ψ: 'ps', - Ψ: 'Ps', - ω: 'w', - Ω: 'w', - ώ: 'w', - Ώ: 'w', - Α: 'A', -}; - +//selectively sourced from https://github.com/sindresorhus/transliterate/blob/main/replacements.js (under MIT license) +const cyrillicMapping: { [key: string]: string } = Object.fromEntries([ + ['А', 'A'], + ['а', 'a'], + ['Б', 'B'], + ['б', 'b'], + ['В', 'V'], + ['в', 'v'], + ['Г', 'G'], + ['г', 'g'], + ['Д', 'D'], + ['д', 'd'], + ['ъе', 'ye'], + ['Ъе', 'Ye'], + ['ъЕ', 'yE'], + ['ЪЕ', 'YE'], + ['Е', 'E'], + ['е', 'e'], + ['Ё', 'Yo'], + ['ё', 'yo'], + ['Ж', 'Zh'], + ['ж', 'zh'], + ['З', 'Z'], + ['з', 'z'], + ['И', 'I'], + ['и', 'i'], + ['ый', 'iy'], + ['Ый', 'Iy'], + ['ЫЙ', 'IY'], + ['ыЙ', 'iY'], + ['Й', 'Y'], + ['й', 'y'], + ['К', 'K'], + ['к', 'k'], + ['Л', 'L'], + ['л', 'l'], + ['М', 'M'], + ['м', 'm'], + ['Н', 'N'], + ['н', 'n'], + ['О', 'O'], + ['о', 'o'], + ['П', 'P'], + ['п', 'p'], + ['Р', 'R'], + ['р', 'r'], + ['С', 'S'], + ['с', 's'], + ['Т', 'T'], + ['т', 't'], + ['У', 'U'], + ['у', 'u'], + ['Ф', 'F'], + ['ф', 'f'], + ['Х', 'Kh'], + ['х', 'kh'], + ['Ц', 'Ts'], + ['ц', 'ts'], + ['Ч', 'Ch'], + ['ч', 'ch'], + ['Ш', 'Sh'], + ['ш', 'sh'], + ['Щ', 'Sch'], + ['щ', 'sch'], + ['Ъ', ''], + ['ъ', ''], + ['Ы', 'Y'], + ['ы', 'y'], + ['Ь', ''], + ['ь', ''], + ['Э', 'E'], + ['э', 'e'], + ['Ю', 'Yu'], + ['ю', 'yu'], + ['Я', 'Ya'], + ['я', 'ya'], +]); +const greekMapping: { [key: string]: string } = Object.fromEntries([ + ['α', 'a'], + ['β', 'v'], + ['γ', 'g'], + ['δ', 'd'], + ['ε', 'e'], + ['ζ', 'z'], + ['η', 'i'], + ['θ', 'th'], + ['ι', 'i'], + ['κ', 'k'], + ['λ', 'l'], + ['μ', 'm'], + ['ν', 'n'], + ['ξ', 'ks'], + ['ο', 'o'], + ['π', 'p'], + ['ρ', 'r'], + ['σ', 's'], + ['τ', 't'], + ['υ', 'y'], + ['φ', 'f'], + ['χ', 'x'], + ['ψ', 'ps'], + ['ω', 'o'], + ['ά', 'a'], + ['έ', 'e'], + ['ί', 'i'], + ['ό', 'o'], + ['ύ', 'y'], + ['ή', 'i'], + ['ώ', 'o'], + ['ς', 's'], + ['ϊ', 'i'], + ['ΰ', 'y'], + ['ϋ', 'y'], + ['ΐ', 'i'], + ['Α', 'A'], + ['Β', 'B'], + ['Γ', 'G'], + ['Δ', 'D'], + ['Ε', 'E'], + ['Ζ', 'Z'], + ['Η', 'I'], + ['Θ', 'TH'], + ['Ι', 'I'], + ['Κ', 'K'], + ['Λ', 'L'], + ['Μ', 'M'], + ['Ν', 'N'], + ['Ξ', 'KS'], + ['Ο', 'O'], + ['Π', 'P'], + ['Ρ', 'R'], + ['Σ', 'S'], + ['Τ', 'T'], + ['Υ', 'Y'], + ['Φ', 'F'], + ['Χ', 'X'], + ['Ψ', 'PS'], + ['Ω', 'O'], + ['Ά', 'A'], + ['Έ', 'E'], + ['Ί', 'I'], + ['Ό', 'O'], + ['Ύ', 'Y'], + ['Ή', 'I'], + ['Ώ', 'O'], + ['Ϊ', 'I'], + ['Ϋ', 'Y'], +]); +const arabicMapping: { [key: string]: string } = Object.fromEntries([ + ['ء', 'e'], + ['آ', 'a'], + ['أ', 'a'], + ['ؤ', 'w'], + ['إ', 'i'], + ['ئ', 'y'], + ['ا', 'a'], + ['ب', 'b'], + ['ة', 't'], + ['ت', 't'], + ['ث', 'th'], + ['ج', 'j'], + ['ح', 'h'], + ['خ', 'kh'], + ['د', 'd'], + ['ذ', 'dh'], + ['ر', 'r'], + ['ز', 'z'], + ['س', 's'], + ['ش', 'sh'], + ['ص', 's'], + ['ض', 'd'], + ['ط', 't'], + ['ظ', 'z'], + ['ع', 'e'], + ['غ', 'gh'], + ['ـ', '_'], + ['ف', 'f'], + ['ق', 'q'], + ['ك', 'k'], + ['ل', 'l'], + ['م', 'm'], + ['ن', 'n'], + ['ه', 'h'], + ['و', 'w'], + ['ى', 'a'], + ['ي', 'y'], + ['َ‎', 'a'], + ['ُ', 'u'], + ['ِ‎', 'i'], +]); +const armenianMapping: { [key: string]: string } = Object.fromEntries([ + ['ա', 'a'], + ['Ա', 'A'], + ['բ', 'b'], + ['Բ', 'B'], + ['գ', 'g'], + ['Գ', 'G'], + ['դ', 'd'], + ['Դ', 'D'], + ['ե', 'ye'], + ['Ե', 'Ye'], + ['զ', 'z'], + ['Զ', 'Z'], + ['է', 'e'], + ['Է', 'E'], + ['ը', 'y'], + ['Ը', 'Y'], + ['թ', 't'], + ['Թ', 'T'], + ['ժ', 'zh'], + ['Ժ', 'Zh'], + ['ի', 'i'], + ['Ի', 'I'], + ['լ', 'l'], + ['Լ', 'L'], + ['խ', 'kh'], + ['Խ', 'Kh'], + ['ծ', 'ts'], + ['Ծ', 'Ts'], + ['կ', 'k'], + ['Կ', 'K'], + ['հ', 'h'], + ['Հ', 'H'], + ['ձ', 'dz'], + ['Ձ', 'Dz'], + ['ղ', 'gh'], + ['Ղ', 'Gh'], + ['ճ', 'tch'], + ['Ճ', 'Tch'], + ['մ', 'm'], + ['Մ', 'M'], + ['յ', 'y'], + ['Յ', 'Y'], + ['ն', 'n'], + ['Ն', 'N'], + ['շ', 'sh'], + ['Շ', 'Sh'], + ['ո', 'vo'], + ['Ո', 'Vo'], + ['չ', 'ch'], + ['Չ', 'Ch'], + ['պ', 'p'], + ['Պ', 'P'], + ['ջ', 'j'], + ['Ջ', 'J'], + ['ռ', 'r'], + ['Ռ', 'R'], + ['ս', 's'], + ['Ս', 'S'], + ['վ', 'v'], + ['Վ', 'V'], + ['տ', 't'], + ['Տ', 'T'], + ['ր', 'r'], + ['Ր', 'R'], + ['ց', 'c'], + ['Ց', 'C'], + ['ու', 'u'], + ['ՈՒ', 'U'], + ['Ու', 'U'], + ['փ', 'p'], + ['Փ', 'P'], + ['ք', 'q'], + ['Ք', 'Q'], + ['օ', 'o'], + ['Օ', 'O'], + ['ֆ', 'f'], + ['Ֆ', 'F'], + ['և', 'yev'], +]); +const farsiMapping: { [key: string]: string } = Object.fromEntries([ + ['چ', 'ch'], + ['ک', 'k'], + ['گ', 'g'], + ['پ', 'p'], + ['ژ', 'zh'], + ['ی', 'y'], +]); export const charMapping: { [key: string]: string } = { ...cyrillicMapping, ...greekMapping, + ...arabicMapping, + ...farsiMapping, + ...armenianMapping, }; From b717385fe68682ddce9bc98437942bee671b677d Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Sun, 27 Nov 2022 10:56:49 +0700 Subject: [PATCH 14/20] Update src/modules/internet/index.ts Co-authored-by: ST-DDT --- src/modules/internet/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/internet/index.ts b/src/modules/internet/index.ts index 41b8d6de38e..5c31fb33b1e 100644 --- a/src/modules/internet/index.ts +++ b/src/modules/internet/index.ts @@ -134,7 +134,7 @@ export class InternetModule { * faker.internet.userName('John', 'Doe') // 'John.Doe' * faker.internet.userName('Hélene', 'Müller') // 'Helene_Muller11' * faker.internet.userName('Фёдор', 'Достоевский') // 'Fedor.Dostoevskii50' - * faker.internet.userName("大羽","陳") //hlzp8d.tpv45 + * faker.internet.userName('大羽', '陳') // 'hlzp8d.tpv45' * * @since 2.0.1 */ From 4b0ee084e308c3642373687afa98e7afb5e45a2a Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Sun, 27 Nov 2022 10:56:58 +0700 Subject: [PATCH 15/20] Update src/modules/internet/index.ts Co-authored-by: ST-DDT --- src/modules/internet/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/internet/index.ts b/src/modules/internet/index.ts index 5c31fb33b1e..79cc00c6bb1 100644 --- a/src/modules/internet/index.ts +++ b/src/modules/internet/index.ts @@ -199,7 +199,7 @@ export class InternetModule { * faker.internet.displayName('John', 'Doe') // 'John.Doe' * faker.internet.displayName('Hélene', 'Müller') // 'Hélene_Müller11' * faker.internet.displayName('Фёдор', 'Достоевский') // 'Фёдор.Достоевский50' - * faker.internet.displayName("大羽","陳") //大羽.陳 + * faker.internet.displayName('大羽', '陳') // '大羽.陳' * * @since 8.0.0 */ From 2e1b5f614ed792b77df6760fc1889f23aba745fa Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Sun, 27 Nov 2022 11:05:21 +0700 Subject: [PATCH 16/20] Update test/internet.spec.ts Co-authored-by: ST-DDT --- test/internet.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/internet.spec.ts b/test/internet.spec.ts index 5d9c2cc3d79..c87a3608a2d 100644 --- a/test/internet.spec.ts +++ b/test/internet.spec.ts @@ -269,6 +269,7 @@ describe('internet', () => { expect(username).includes('hlzp8d'); }); }); + describe('displayName()', () => { it('should return a random display name', () => { const displayName = faker.internet.displayName(); From 5b2757aceb003507c79dee4930d30b4cc10d7db6 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Sun, 27 Nov 2022 11:07:31 +0700 Subject: [PATCH 17/20] fix(internet): improve tests and docs --- src/modules/internet/index.ts | 16 ++++++++++------ test/helpers.spec.ts | 2 -- test/internet.spec.ts | 10 ++++++++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/modules/internet/index.ts b/src/modules/internet/index.ts index 79cc00c6bb1..43801532cf2 100644 --- a/src/modules/internet/index.ts +++ b/src/modules/internet/index.ts @@ -123,18 +123,20 @@ export class InternetModule { } /** - * Generates a username using the given person's name as base. This will always return a plain ASCII string. Some basic stripping of accents and transliteration of characters will be done. + * Generates a username using the given person's name as base. The resuling username may use neither, one or both of the names provided. This will always return a plain ASCII string. Some basic stripping of accents and transliteration of characters will be done. * * @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 - though the last name is not always used. 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. + * + * @see faker.internet.displayName * * @example * faker.internet.userName() // 'Nettie_Zboncak40' - * faker.internet.userName('Jeanne', 'Doe') // 'Jeanne98' + * faker.internet.userName('Jeanne', 'Doe') // 'Jeanne98' - note surname is not used * faker.internet.userName('John', 'Doe') // 'John.Doe' * faker.internet.userName('Hélene', 'Müller') // 'Helene_Muller11' * faker.internet.userName('Фёдор', 'Достоевский') // 'Fedor.Dostoevskii50' - * faker.internet.userName('大羽', '陳') // 'hlzp8d.tpv45' + * faker.internet.userName('大羽', '陳') // 'hlzp8d.tpv45' - note neither name is used * * @since 2.0.1 */ @@ -188,14 +190,16 @@ export class InternetModule { } /** - * Generates a display name using the given person's name as base. If the input names include Unicode characters, the resulting display name will contain Unicode characters. It will not contain spaces. + * Generates a display name using the given person's name as base. The resulting display name may use one or both of the provided names. If the input names include Unicode characters, the resulting display name will contain Unicode characters. It will not contain spaces. * * @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. * + * @see faker.internet.userName + * * @example * faker.internet.displayName() // 'Nettie_Zboncak40' - * faker.internet.displayName('Jeanne', 'Doe') // 'Jeanne98' + * faker.internet.displayName('Jeanne', 'Doe') // 'Jeanne98' - note surname not used. * faker.internet.displayName('John', 'Doe') // 'John.Doe' * faker.internet.displayName('Hélene', 'Müller') // 'Hélene_Müller11' * faker.internet.displayName('Фёдор', 'Достоевский') // 'Фёдор.Достоевский50' diff --git a/test/helpers.spec.ts b/test/helpers.spec.ts index 5dcd38fac80..530c3b49a00 100644 --- a/test/helpers.spec.ts +++ b/test/helpers.spec.ts @@ -187,9 +187,7 @@ describe('helpers', () => { expect(faker.helpers.slugify("d'angelo.net")).toBe('dangelo.net'); expect(faker.helpers.slugify('hello你好')).toBe('hello'); }); - }); - describe('slugify()', () => { it('strips simple diacritics from strings', () => { expect(faker.helpers.slugify('Aiden.Harªann')).toBe('Aiden.Haraann'); expect(faker.helpers.slugify('Adèle.Argüello')).toBe( diff --git a/test/internet.spec.ts b/test/internet.spec.ts index c87a3608a2d..45ed19638bf 100644 --- a/test/internet.spec.ts +++ b/test/internet.spec.ts @@ -38,11 +38,17 @@ describe('internet', () => { }); t.describe('userName', (t) => { - t.it('noArgs').it('with names', 'Jane', 'Doe'); + t.it('noArgs').it('with Latin names', 'Jane', 'Doe'); + t.it('noArgs').it('with accented names', 'Hélene', 'Müller'); + t.it('noArgs').it('with Cyrillic names', 'Фёдор', 'Достоевский'); + t.it('noArgs').it('with Chinese names', '大羽', '陳'); }); t.describe('displayName', (t) => { - t.it('noArgs').it('with names', 'Jane', 'Doe'); + t.it('noArgs').it('with Latin names', 'Jane', 'Doe'); + t.it('noArgs').it('with accented names', 'Hélene', 'Müller'); + t.it('noArgs').it('with Cyrillic names', 'Фёдор', 'Достоевский'); + t.it('noArgs').it('with Chinese names', '大羽', '陳'); }); t.describe('password', (t) => { From 4884f270098800e72cd188d7af3f7f878839c807 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Sun, 27 Nov 2022 11:15:10 +0700 Subject: [PATCH 18/20] fix(internet): improve tests and docs --- src/modules/internet/index.ts | 4 +- test/__snapshots__/internet.spec.ts.snap | 84 ++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/modules/internet/index.ts b/src/modules/internet/index.ts index 43801532cf2..bdf0e6fdae1 100644 --- a/src/modules/internet/index.ts +++ b/src/modules/internet/index.ts @@ -128,7 +128,7 @@ export class InternetModule { * @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. * - * @see faker.internet.displayName + * @see faker.internet.displayName() * * @example * faker.internet.userName() // 'Nettie_Zboncak40' @@ -195,7 +195,7 @@ export class InternetModule { * @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. * - * @see faker.internet.userName + * @see faker.internet.userName() * * @example * faker.internet.displayName() // 'Nettie_Zboncak40' diff --git a/test/__snapshots__/internet.spec.ts.snap b/test/__snapshots__/internet.spec.ts.snap index bdf36cda026..5b33c9e23be 100644 --- a/test/__snapshots__/internet.spec.ts.snap +++ b/test/__snapshots__/internet.spec.ts.snap @@ -8,6 +8,20 @@ exports[`internet > 42 > color > with color base 1`] = `"#6298ac"`; exports[`internet > 42 > displayName > noArgs 1`] = `"Garnet.Schinner73"`; +exports[`internet > 42 > displayName > noArgs 2`] = `"Garnet.Schinner73"`; + +exports[`internet > 42 > displayName > noArgs 3`] = `"Garnet.Schinner73"`; + +exports[`internet > 42 > displayName > noArgs 4`] = `"Garnet.Schinner73"`; + +exports[`internet > 42 > displayName > with Chinese names 1`] = `"大羽_陳"`; + +exports[`internet > 42 > displayName > with Cyrillic names 1`] = `"Фёдор_Достоевский"`; + +exports[`internet > 42 > displayName > with Latin names 1`] = `"Jane_Doe"`; + +exports[`internet > 42 > displayName > with accented names 1`] = `"Hélene_Müller"`; + exports[`internet > 42 > displayName > with names 1`] = `"Jane_Doe"`; exports[`internet > 42 > domainName 1`] = `"hasty-shin.org"`; @@ -66,6 +80,20 @@ exports[`internet > 42 > userAgent 1`] = `"Mozilla/5.0 (Windows; U; Windows NT 6 exports[`internet > 42 > userName > noArgs 1`] = `"Garnet.Schinner73"`; +exports[`internet > 42 > userName > noArgs 2`] = `"Garnet.Schinner73"`; + +exports[`internet > 42 > userName > noArgs 3`] = `"Garnet.Schinner73"`; + +exports[`internet > 42 > userName > noArgs 4`] = `"Garnet.Schinner73"`; + +exports[`internet > 42 > userName > with Chinese names 1`] = `"hlzp8d_tpv"`; + +exports[`internet > 42 > userName > with Cyrillic names 1`] = `"Fedor_Dostoevskii"`; + +exports[`internet > 42 > userName > with Latin names 1`] = `"Jane_Doe"`; + +exports[`internet > 42 > userName > with accented names 1`] = `"Helene_Muller"`; + exports[`internet > 42 > userName > with names 1`] = `"Jane_Doe"`; exports[`internet > 1211 > avatar 1`] = `"https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/1160.jpg"`; @@ -76,6 +104,20 @@ exports[`internet > 1211 > color > with color base 1`] = `"#a96ca4"`; exports[`internet > 1211 > displayName > noArgs 1`] = `"Tito_Koelpin22"`; +exports[`internet > 1211 > displayName > noArgs 2`] = `"Tito_Koelpin22"`; + +exports[`internet > 1211 > displayName > noArgs 3`] = `"Tito_Koelpin22"`; + +exports[`internet > 1211 > displayName > noArgs 4`] = `"Tito_Koelpin22"`; + +exports[`internet > 1211 > displayName > with Chinese names 1`] = `"大羽.陳89"`; + +exports[`internet > 1211 > displayName > with Cyrillic names 1`] = `"Фёдор.Достоевский89"`; + +exports[`internet > 1211 > displayName > with Latin names 1`] = `"Jane.Doe89"`; + +exports[`internet > 1211 > displayName > with accented names 1`] = `"Hélene.Müller89"`; + exports[`internet > 1211 > displayName > with names 1`] = `"Jane.Doe89"`; exports[`internet > 1211 > domainName 1`] = `"vibrant-infix.org"`; @@ -134,6 +176,20 @@ exports[`internet > 1211 > userAgent 1`] = `"Mozilla/5.0 (Macintosh; U; Intel Ma exports[`internet > 1211 > userName > noArgs 1`] = `"Tito_Koelpin22"`; +exports[`internet > 1211 > userName > noArgs 2`] = `"Tito_Koelpin22"`; + +exports[`internet > 1211 > userName > noArgs 3`] = `"Tito_Koelpin22"`; + +exports[`internet > 1211 > userName > noArgs 4`] = `"Tito_Koelpin22"`; + +exports[`internet > 1211 > userName > with Chinese names 1`] = `"hlzp8d.tpv89"`; + +exports[`internet > 1211 > userName > with Cyrillic names 1`] = `"Fedor.Dostoevskii89"`; + +exports[`internet > 1211 > userName > with Latin names 1`] = `"Jane.Doe89"`; + +exports[`internet > 1211 > userName > with accented names 1`] = `"Helene.Muller89"`; + exports[`internet > 1211 > userName > with names 1`] = `"Jane.Doe89"`; exports[`internet > 1337 > avatar 1`] = `"https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/327.jpg"`; @@ -144,6 +200,20 @@ exports[`internet > 1337 > color > with color base 1`] = `"#537a46"`; exports[`internet > 1337 > displayName > noArgs 1`] = `"Devyn21"`; +exports[`internet > 1337 > displayName > noArgs 2`] = `"Devyn21"`; + +exports[`internet > 1337 > displayName > noArgs 3`] = `"Devyn21"`; + +exports[`internet > 1337 > displayName > noArgs 4`] = `"Devyn21"`; + +exports[`internet > 1337 > displayName > with Chinese names 1`] = `"大羽56"`; + +exports[`internet > 1337 > displayName > with Cyrillic names 1`] = `"Фёдор56"`; + +exports[`internet > 1337 > displayName > with Latin names 1`] = `"Jane56"`; + +exports[`internet > 1337 > displayName > with accented names 1`] = `"Hélene56"`; + exports[`internet > 1337 > displayName > with names 1`] = `"Jane56"`; exports[`internet > 1337 > domainName 1`] = `"fair-migration.com"`; @@ -202,4 +272,18 @@ exports[`internet > 1337 > userAgent 1`] = `"Mozilla/5.0 (Windows; U; Windows NT exports[`internet > 1337 > userName > noArgs 1`] = `"Devyn21"`; +exports[`internet > 1337 > userName > noArgs 2`] = `"Devyn21"`; + +exports[`internet > 1337 > userName > noArgs 3`] = `"Devyn21"`; + +exports[`internet > 1337 > userName > noArgs 4`] = `"Devyn21"`; + +exports[`internet > 1337 > userName > with Chinese names 1`] = `"hlzp8d56"`; + +exports[`internet > 1337 > userName > with Cyrillic names 1`] = `"Fedor56"`; + +exports[`internet > 1337 > userName > with Latin names 1`] = `"Jane56"`; + +exports[`internet > 1337 > userName > with accented names 1`] = `"Helene56"`; + exports[`internet > 1337 > userName > with names 1`] = `"Jane56"`; From 3505045ca0e493f484cbe8fee75c52f07360dd40 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Tue, 29 Nov 2022 09:51:14 +0700 Subject: [PATCH 19/20] Update src/modules/internet/char-mappings.ts Co-authored-by: Eric Cheng --- src/modules/internet/char-mappings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/internet/char-mappings.ts b/src/modules/internet/char-mappings.ts index 942a805de00..4d635e76eba 100644 --- a/src/modules/internet/char-mappings.ts +++ b/src/modules/internet/char-mappings.ts @@ -1,4 +1,4 @@ -//selectively sourced from https://github.com/sindresorhus/transliterate/blob/main/replacements.js (under MIT license) +// selectively sourced from https://github.com/sindresorhus/transliterate/blob/main/replacements.js (under MIT license) const cyrillicMapping: { [key: string]: string } = Object.fromEntries([ ['А', 'A'], ['а', 'a'], From c9caafc045a20763b29b7312ad9cef9643c8cfa3 Mon Sep 17 00:00:00 2001 From: Matt Mayer Date: Thu, 1 Dec 2022 16:41:20 +0700 Subject: [PATCH 20/20] fix: comment fixes --- src/modules/internet/char-mappings.ts | 2 +- src/modules/internet/index.ts | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/modules/internet/char-mappings.ts b/src/modules/internet/char-mappings.ts index 4d635e76eba..6b7843797ea 100644 --- a/src/modules/internet/char-mappings.ts +++ b/src/modules/internet/char-mappings.ts @@ -1,4 +1,4 @@ -// selectively sourced from https://github.com/sindresorhus/transliterate/blob/main/replacements.js (under MIT license) +// Selectively sourced from https://github.com/sindresorhus/transliterate/blob/08bbfd3a13ac393d945a430ed5ec62f044a08d70/replacements.js (under MIT license) const cyrillicMapping: { [key: string]: string } = Object.fromEntries([ ['А', 'A'], ['а', 'a'], diff --git a/src/modules/internet/index.ts b/src/modules/internet/index.ts index bdf0e6fdae1..dc3eaa624f7 100644 --- a/src/modules/internet/index.ts +++ b/src/modules/internet/index.ts @@ -160,29 +160,27 @@ export class InternetModule { break; } - //There may still be non-ascii characters in the result. - //First remove simple accents etc + // There may still be non-ascii characters in the result. + // First remove simple accents etc result = result .normalize('NFKD') //for example è decomposes to as e + ̀ .replace(/[\u0300-\u036f]/g, ''); // removes combining marks result = result .split('') - .map(function (char) { - //if we have a mapping for this character, (for Cyrillic, Greek etc) use it + .map((char) => { + // If we have a mapping for this character, (for Cyrillic, Greek etc) use it if (charMapping[char]) { return charMapping[char]; } if (char.charCodeAt(0) < 0x80) { - //keep ascii characters + // Keep ASCII characters return char; } - //final fallback return the Unicode char code value for Chinese, Japanese, Korean etc, base-36 encoded + // Final fallback return the Unicode char code value for Chinese, Japanese, Korean etc, base-36 encoded return char.charCodeAt(0).toString(36); }) .join(''); - - //remove spaces and ' result = result.toString().replace(/'/g, ''); result = result.replace(/ /g, '');