Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: separate methods for object key value #503

Merged
merged 9 commits into from
Apr 30, 2022
13 changes: 6 additions & 7 deletions src/finance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ export class Finance {
* faker.finance.currencyCode() // 'USD'
*/
currencyCode(): string {
return this.faker.random.objectElement(
return this.faker.helpers.objectValue(
this.faker.definitions.finance.currency
)['code'];
}
Expand All @@ -183,10 +183,9 @@ export class Finance {
* faker.finance.currencyName() // 'US Dollar'
*/
currencyName(): string {
return this.faker.random.objectElement(
this.faker.definitions.finance.currency,
'key'
);
return this.faker.helpers.objectKey(
this.faker.definitions.finance.currency
) as string;
}

/**
Expand All @@ -198,7 +197,7 @@ export class Finance {
currencySymbol(): string {
let symbol: string;
while (!symbol) {
symbol = this.faker.random.objectElement(
symbol = this.faker.helpers.objectValue(
this.faker.definitions.finance.currency
)['symbol'];
}
Expand Down Expand Up @@ -265,7 +264,7 @@ export class Finance {
} else {
// Choose a random provider
// Credit cards are in an object structure
const formats = this.faker.random.objectElement(localeFormat, 'value'); // There could be multiple formats
const formats = this.faker.helpers.objectValue(localeFormat); // There could be multiple formats
format = this.faker.random.arrayElement(formats);
}
format = format.replace(/\//g, '');
Expand Down
35 changes: 31 additions & 4 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ export interface Transaction {
}

/**
* Module with various helper methods that don't fit in a particular category.
* Module with various helper methods that transform the method input rather than returning values from locales.
* The transformation process may call methods that use the locale data.
*/
export class Helpers {
constructor(private readonly faker: Faker) {
Expand Down Expand Up @@ -701,9 +702,9 @@ export class Helpers {
* @param options.probability The probability (`[0.00, 1.00]`) of the callback being invoked. Defaults to `0.5`.
*
* @example
* faker.random.maybe(() => 'Hello World!') // 'Hello World!'
* faker.random.maybe(() => 'Hello World!', { probability: 0.1 }) // undefined
* faker.random.maybe(() => 'Hello World!', { probability: 0.9 }) // 'Hello World!'
* faker.helpers.maybe(() => 'Hello World!') // 'Hello World!'
* faker.helpers.maybe(() => 'Hello World!', { probability: 0.1 }) // undefined
* faker.helpers.maybe(() => 'Hello World!', { probability: 0.9 }) // 'Hello World!'
*/
maybe<T>(
callback: () => T,
Expand All @@ -715,4 +716,30 @@ export class Helpers {
}
return undefined;
}

/**
* Returns a random key from given object.
*
* @param object The object to be used.
*
* @example
* faker.helpers.objectKey({ myProperty: 'myValue' }) // 'myProperty'
*/
objectKey<T extends Record<string, unknown>>(object: T): keyof T {
const array: Array<keyof T> = Object.keys(object);
return this.faker.random.arrayElement(array);
}

/**
* Returns a random value from given object.
*
* @param object The object to be used.
*
* @example
* faker.helpers.objectValue({ myProperty: 'myValue' }) // 'myValue'
*/
objectValue<T extends Record<string, unknown>>(object: T): T[keyof T] {
const key = this.faker.helpers.objectKey(object);
return object[key];
}
}
75 changes: 62 additions & 13 deletions src/random.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,25 +161,42 @@ export class Random {
}

/**
* Returns a random key or value from given object.
* Returns a random key from given object.
*
* @template T The type of `Record` to pick from.
* @template K The keys of `T`.
* @param object The object to get the keys or values from.
* @param object The object to get the keys from.
* @param field If this is set to `'key'`, this method will a return a random key of the given instance.
* If this is set to `'value'`, this method will a return a random value of the given instance.
* Defaults to `'value'`.
*
* @see faker.helpers.objectKey()
*
* @example
* const object = { keyA: 'valueA', keyB: 42 };
* faker.random.objectElement(object) // 42
* faker.random.objectElement(object, 'key') // 'keyB'
* faker.random.objectElement(object, 'value') // 'valueA'
*
* @deprecated
*/
objectElement<T extends Record<string, unknown>, K extends keyof T>(
object: T,
field: 'key'
): K;
/**
* Returns a random value from given object.
*
* @template T The type of `Record` to pick from.
* @template K The keys of `T`.
* @param object The object to get the values from.
* @param field If this is set to `'value'`, this method will a return a random value of the given instance.
*
* @see faker.helpers.objectValue()
*
* @example
* const object = { keyA: 'valueA', keyB: 42 };
* faker.random.objectElement(object) // 42
* faker.random.objectElement(object, 'value') // 'valueA'
*
* @deprecated
*/
objectElement<T extends Record<string, unknown>, K extends keyof T>(
object: T,
field?: unknown
Expand All @@ -194,24 +211,56 @@ export class Random {
* If this is set to `'value'`, this method will a return a random value of the given instance.
* Defaults to `'value'`.
*
* @see faker.helpers.objectKey()
* @see faker.helpers.objectValue()
*
* @example
* const object = { keyA: 'valueA', keyB: 42 };
* faker.random.objectElement(object) // 42
* faker.random.objectElement(object, 'key') // 'keyB'
* faker.random.objectElement(object, 'value') // 'valueA'
*
* @deprecated
*/
objectElement<T extends Record<string, unknown>, K extends keyof T>(
object: T,
object?: T,
field?: 'key' | 'value'
): K | T[K];
/**
* Returns a random key or value from given object.
*
* @template T The type of `Record` to pick from.
* @template K The keys of `T`.
* @param object The object to get the keys or values from.
* @param field If this is set to `'key'`, this method will a return a random key of the given instance.
* If this is set to `'value'`, this method will a return a random value of the given instance.
* Defaults to `'value'`.
*
* @see faker.helpers.objectKey()
* @see faker.helpers.objectValue()
*
* @example
* const object = { keyA: 'valueA', keyB: 42 };
* faker.random.objectElement(object) // 42
* faker.random.objectElement(object, 'key') // 'keyB'
* faker.random.objectElement(object, 'value') // 'valueA'
*
* @deprecated
*/
objectElement<T extends Record<string, unknown>, K extends keyof T>(
object = { foo: 'bar', too: 'car' } as unknown as T,
field = 'value'
object: T = { foo: 'bar', too: 'car' } as unknown as T,
field: 'key' | 'value' = 'value'
): K | T[K] {
const array: Array<keyof T> = Object.keys(object);
const key = this.arrayElement(array);

return field === 'key' ? (key as K) : (object[key] as T[K]);
const useKey = field === 'key';
deprecated({
deprecated: `faker.random.objectElement(${useKey ? "obj, 'key'" : ''})`,
proposed: `faker.helpers.object${useKey ? 'Key' : 'Value'}()`,
since: 'v6.3.0',
until: 'v7.0.0',
});
return field === 'key'
? (this.faker.helpers.objectKey(object) as K)
: (this.faker.helpers.objectValue(object) as T[K]);
}

/**
Expand Down
26 changes: 26 additions & 0 deletions test/helpers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,32 @@ describe('helpers', () => {
});
});

describe('objectKey', () => {
it('should return a random key', () => {
const testObject = {
hello: 'to',
you: 'my',
friend: '!',
};
const actual = faker.helpers.objectKey(testObject);

expect(Object.keys(testObject)).toContain(actual);
});
});

describe('objectValue', () => {
it('should return a random value', () => {
const testObject = {
hello: 'to',
you: 'my',
friend: '!',
};
const actual = faker.helpers.objectValue(testObject);

expect(Object.values(testObject)).toContain(actual);
});
});

describe('deprecation warnings', () => {
it.each([['randomize', 'random.arrayElement']])(
'should warn user that function helpers.%s is deprecated',
Expand Down
14 changes: 14 additions & 0 deletions test/random.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ describe('random', () => {

describe('objectElement', () => {
it('should return a random value', () => {
const spy = vi.spyOn(console, 'warn');

const testObject = {
hello: 'to',
you: 'my',
Expand All @@ -167,9 +169,16 @@ describe('random', () => {
const actual = faker.random.objectElement(testObject);

expect(Object.values(testObject)).toContain(actual);
expect(spy).toHaveBeenCalledWith(
`[@faker-js/faker]: faker.random.objectElement() is deprecated since v6.3.0 and will be removed in v7.0.0. Please use faker.helpers.objectValue() instead.`
);

spy.mockRestore();
});

it('should return a random key', () => {
const spy = vi.spyOn(console, 'warn');

const testObject = {
hello: 'to',
you: 'my',
Expand All @@ -178,6 +187,11 @@ describe('random', () => {
const actual = faker.random.objectElement(testObject, 'key');

expect(Object.keys(testObject)).toContain(actual);
expect(spy).toHaveBeenCalledWith(
`[@faker-js/faker]: faker.random.objectElement(obj, 'key') is deprecated since v6.3.0 and will be removed in v7.0.0. Please use faker.helpers.objectKey() instead.`
);

spy.mockRestore();
});
});

Expand Down