diff options
| author | Shinigami <[email protected]> | 2022-03-24 10:22:13 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-03-24 10:22:13 +0100 |
| commit | 7675abe5a62c8d44ecfd4a6f50bfb5fa50f40efa (patch) | |
| tree | ad679ab22251a4acc56b102458ccab8545bbd8b0 /src | |
| parent | d0a473f7ca6b525391ca8ab17e029335c66ed99e (diff) | |
| download | faker-7675abe5a62c8d44ecfd4a6f50bfb5fa50f40efa.tar.xz faker-7675abe5a62c8d44ecfd4a6f50bfb5fa50f40efa.zip | |
fix: name module gender (#644)
Diffstat (limited to 'src')
| -rw-r--r-- | src/index.ts | 2 | ||||
| -rw-r--r-- | src/name.ts | 294 |
2 files changed, 146 insertions, 150 deletions
diff --git a/src/index.ts b/src/index.ts index 0f4b71ba..d1c2cb1d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -27,6 +27,8 @@ export type { WordDefinitions, } from './definitions'; export type { FakerOptions, UsableLocale, UsedLocales } from './faker'; +export { Gender } from './name'; +export type { GenderType } from './name'; export { Faker }; // since we are requiring the top level of faker, load all locales by default diff --git a/src/name.ts b/src/name.ts index 6b727569..8fac27c4 100644 --- a/src/name.ts +++ b/src/name.ts @@ -1,5 +1,83 @@ import type { Faker } from '.'; +export enum Gender { + female = 'female', + male = 'male', +} + +// TODO @Shinigami92 21-03-2022: Remove 0 and 1 in v7 +export type GenderType = 'female' | 'male' | 0 | 1; + +/** + * Normalize gender. + * + * @param gender Gender. + * @returns Normalized gender. + */ +function normalizeGender( + gender?: GenderType +): Exclude<GenderType, number> | undefined { + if (gender == null || typeof gender === 'string') { + // TODO @Shinigami92 21-03-2022: Cast can be removed when we set `strict: true` + return gender as Exclude<GenderType, number>; + } + + const normalizedGender = gender === 0 ? 'male' : 'female'; + + console.warn( + `Deprecation Warning: Please use '${normalizedGender}' for gender instead of ${gender}` + ); + + return normalizedGender; +} + +/** + * Select a definition based on given gender. + * + * @param faker Faker instance. + * @param gender Gender. + * @param param2 Definitions. + * @param param2.generic Non-gender definitions. + * @param param2.female Female definitions. + * @param param2.male Male definitions. + * @returns Definition based on given gender. + */ +function selectDefinition( + faker: Faker, + gender: GenderType | undefined, + // TODO christopher 21-03-2022: Remove fallback empty object when `strict: true` + { + generic, + female, + male, + }: { generic?: string[]; female?: string[]; male?: string[] } = {} +) { + const normalizedGender = normalizeGender(gender); + + let values: string[] | undefined; + switch (normalizedGender) { + case 'female': + values = female; + break; + case 'male': + values = male; + break; + default: + values = generic; + break; + } + + if (values == null) { + if (female != null && male != null) { + values = faker.random.arrayElement([female, male]); + } else { + values = generic; + } + } + + return faker.random.arrayElement(values); +} + /** * Module to generate people's names and titles. */ @@ -18,131 +96,66 @@ export class Name { * Returns a random first name. * * @param gender The optional gender to use. - * Can be either `'male'` (or `0`) or `'female'` (or `1`). + * Can be either `'female'` or `'male'`. * * @example * faker.name.firstName() // 'Antwan' * faker.name.firstName("female") // 'Victoria' - * faker.name.firstName(1) // 'Ashley' * faker.name.firstName("male") // 'Tom' - * faker.name.firstName(0) // 'Ismael' */ - firstName(gender?: string | number): string { - if ( - typeof this.faker.definitions.name.male_first_name !== 'undefined' && - typeof this.faker.definitions.name.female_first_name !== 'undefined' - ) { - // some locale datasets ( like ru ) have first_name split by gender. since the name.first_name field does not exist in these datasets, - // we must randomly pick a name from either gender array so faker.name.firstName will return the correct locale data ( and not fallback ) - - if (typeof gender === 'string') { - if (gender.toLowerCase() === 'male') { - gender = 0; - } else if (gender.toLowerCase() === 'female') { - gender = 1; - } - } - - if (typeof gender !== 'number') { - if (typeof this.faker.definitions.name.first_name === 'undefined') { - gender = this.faker.datatype.number(1); - } else { - // Fall back to non-gendered names if they exist and gender wasn't specified - return this.faker.random.arrayElement( - this.faker.definitions.name.first_name - ); - } - } - if (gender === 0) { - return this.faker.random.arrayElement( - this.faker.definitions.name.male_first_name - ); - } else { - return this.faker.random.arrayElement( - this.faker.definitions.name.female_first_name - ); - } - } + firstName(gender?: GenderType): string { + const { first_name, female_first_name, male_first_name } = + this.faker.definitions.name; - return this.faker.random.arrayElement( - this.faker.definitions.name.first_name - ); + return selectDefinition(this.faker, gender, { + generic: first_name, + female: female_first_name, + male: male_first_name, + }); } /** * Returns a random last name. * * @param gender The optional gender to use. - * Can be either `'male'` (or `0`) or `'female'` (or `1`). + * Can be either `'female'` or `'male'`. * * @example * faker.name.lastName() // 'Hauck' * faker.name.lastName("female") // 'Grady' - * faker.name.lastName(1) // 'Kshlerin' * faker.name.lastName("male") // 'Barton' - * faker.name.lastName(0) // 'Lockman' */ - lastName(gender?: string | number): string { - if ( - typeof this.faker.definitions.name.male_last_name !== 'undefined' && - typeof this.faker.definitions.name.female_last_name !== 'undefined' - ) { - // some locale datasets ( like ru ) have last_name split by gender. i have no idea how last names can have genders, but also i do not speak russian - // see above comment of firstName method - if (typeof gender !== 'number') { - gender = this.faker.datatype.number(1); - } - if (gender === 0) { - return this.faker.random.arrayElement( - this.faker.locales[this.faker.locale].name.male_last_name - ); - } else { - return this.faker.random.arrayElement( - this.faker.locales[this.faker.locale].name.female_last_name - ); - } - } + lastName(gender?: GenderType): string { + const { last_name, female_last_name, male_last_name } = + this.faker.definitions.name; - return this.faker.random.arrayElement( - this.faker.definitions.name.last_name - ); + return selectDefinition(this.faker, gender, { + generic: last_name, + female: female_last_name, + male: male_last_name, + }); } /** * Returns a random middle name. * * @param gender The optional gender to use. - * Can be either `'male'` (or `0`) or `'female'` (or `1`). + * Can be either `'female'` or `'male'`. * * @example * faker.name.middleName() // 'Доброславівна' * faker.name.middleName("female") // 'Анастасівна' - * faker.name.middleName(1) // 'Анатоліївна' * faker.name.middleName("male") // 'Вікторович' - * faker.name.middleName(0) // 'Стефанович' */ - middleName(gender?: string | number): string { - if ( - typeof this.faker.definitions.name.male_middle_name !== 'undefined' && - typeof this.faker.definitions.name.female_middle_name !== 'undefined' - ) { - if (typeof gender !== 'number') { - gender = this.faker.datatype.number(1); - } - if (gender === 0) { - return this.faker.random.arrayElement( - this.faker.definitions.name.male_middle_name - ); - } else { - return this.faker.random.arrayElement( - this.faker.definitions.name.female_middle_name - ); - } - } + middleName(gender?: GenderType): string { + const { middle_name, female_middle_name, male_middle_name } = + this.faker.definitions.name; - return this.faker.random.arrayElement( - this.faker.definitions.name.middle_name - ); + return selectDefinition(this.faker, gender, { + generic: middle_name, + female: female_middle_name, + male: male_middle_name, + }); } /** @@ -151,35 +164,29 @@ export class Name { * @param firstName The optional first name to use. If not specified a random one will be chosen. * @param lastName The optional last name to use. If not specified a random one will be chosen. * @param gender The optional gender to use. - * Can be either `'male'` (or `0`) or `'female'` (or `1`). + * Can be either `'female'` or `'male'`. * * @example * faker.name.findName() // 'Allen Brown' * faker.name.findName('Joann') // 'Joann Osinski' - * faker.name.findName('Marcella', '', 1) // 'Mrs. Marcella Huels' + * faker.name.findName('Marcella', '', 'female') // 'Mrs. Marcella Huels' * faker.name.findName(undefined, 'Beer') // 'Mr. Alfonso Beer' - * faker.name.findName(undefined, undefined, 0) // 'Fernando Schaefer' + * faker.name.findName(undefined, undefined, 'male') // 'Fernando Schaefer' */ - findName( - firstName?: string, - lastName?: string, - gender?: string | number - ): string { - const r = this.faker.datatype.number(8); + findName(firstName?: string, lastName?: string, gender?: GenderType): string { + const variant = this.faker.datatype.number(8); let prefix = ''; let suffix = ''; - // in particular locales first and last names split by gender, - // thus we keep consistency by passing 0 as male and 1 as female - - if (typeof gender !== 'number') { - gender = this.faker.datatype.number(1); - } + const normalizedGender: Exclude<GenderType, number> = + normalizeGender(gender) ?? + this.faker.random.arrayElement(['female', 'male']); - firstName = firstName || this.faker.name.firstName(gender); - lastName = lastName || this.faker.name.lastName(gender); + firstName = firstName || this.faker.name.firstName(normalizedGender); + lastName = lastName || this.faker.name.lastName(normalizedGender); - switch (r) { + switch (variant) { + // TODO christopher 21-03-2022: Add possibility to have a prefix together with a suffix case 0: prefix = this.faker.name.prefix(gender); if (prefix) { @@ -198,22 +205,6 @@ export class Name { } /** - * Generates a random job title. - * - * @example - * faker.name.jobTitle() // 'Global Accounts Engineer' - */ - jobTitle(): string { - return ( - this.faker.name.jobDescriptor() + - ' ' + - this.faker.name.jobArea() + - ' ' + - this.faker.name.jobType() - ); - } - - /** * Return a random gender. * * @param binary Whether to return only binary gender names. Defaults to `false`. @@ -227,44 +218,30 @@ export class Name { return this.faker.random.arrayElement( this.faker.definitions.name.binary_gender ); - } else { - return this.faker.random.arrayElement(this.faker.definitions.name.gender); } + + return this.faker.random.arrayElement(this.faker.definitions.name.gender); } /** * Returns a random name prefix. * * @param gender The optional gender to use. - * Can be either `'male'` (or `0`) or `'female'` (or `1`). + * Can be either `'female'` or `'male'`. * * @example * faker.name.prefix() // 'Miss' * faker.name.prefix('female') // 'Ms.' - * faker.name.prefix(1) // 'Dr.' * faker.name.prefix('male') // 'Mr.' - * faker.name.prefix(0) // 'Mr.' */ - prefix(gender?: string | number): string { - if ( - typeof this.faker.definitions.name.male_prefix !== 'undefined' && - typeof this.faker.definitions.name.female_prefix !== 'undefined' - ) { - if (typeof gender !== 'number') { - gender = this.faker.datatype.number(1); - } - if (gender === 0) { - return this.faker.random.arrayElement( - this.faker.locales[this.faker.locale].name.male_prefix - ); - } else { - return this.faker.random.arrayElement( - this.faker.locales[this.faker.locale].name.female_prefix - ); - } - } + prefix(gender?: GenderType): string { + const { prefix, female_prefix, male_prefix } = this.faker.definitions.name; - return this.faker.random.arrayElement(this.faker.definitions.name.prefix); + return selectDefinition(this.faker, gender, { + generic: prefix, + female: female_prefix, + male: male_prefix, + }); } /** @@ -274,6 +251,7 @@ export class Name { * faker.name.suffix() // 'DDS' */ suffix(): string { + // TODO christopher 21-03-2022: Add female_suffix and male_suffix return this.faker.random.arrayElement(this.faker.definitions.name.suffix); } @@ -298,6 +276,22 @@ export class Name { } /** + * Generates a random job title. + * + * @example + * faker.name.jobTitle() // 'Global Accounts Engineer' + */ + jobTitle(): string { + return ( + this.faker.name.jobDescriptor() + + ' ' + + this.faker.name.jobArea() + + ' ' + + this.faker.name.jobType() + ); + } + + /** * Generates a random job descriptor. * * @example |
