aboutsummaryrefslogtreecommitdiff
path: root/src/modules
diff options
context:
space:
mode:
authorLeyla Jähnig <[email protected]>2022-07-30 12:57:05 +0200
committerGitHub <[email protected]>2022-07-30 12:57:05 +0200
commitfc4815520b4c6aaf35a89fe41ff4a94b3346379c (patch)
tree44e170fa4c26eb6f81bcaa215640339435d9c5f5 /src/modules
parent09df73aa1ab97dfec4ed3a4dfdd8280f7b094a87 (diff)
downloadfaker-fc4815520b4c6aaf35a89fe41ff4a94b3346379c.tar.xz
faker-fc4815520b4c6aaf35a89fe41ff4a94b3346379c.zip
refactor(fake): move to `helpers` (#1161)
Co-authored-by: Eric Cheng <[email protected]>
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/address/index.ts6
-rw-r--r--src/modules/company/index.ts14
-rw-r--r--src/modules/fake/index.ts100
-rw-r--r--src/modules/helpers/index.ts131
4 files changed, 154 insertions, 97 deletions
diff --git a/src/modules/address/index.ts b/src/modules/address/index.ts
index 7c55bb51..4c2469e1 100644
--- a/src/modules/address/index.ts
+++ b/src/modules/address/index.ts
@@ -86,7 +86,7 @@ export class Address {
format = this.faker.datatype.number(formats.length - 1);
}
- return this.faker.fake(formats[format]);
+ return this.faker.helpers.fake(formats[format]);
}
/**
@@ -171,7 +171,7 @@ export class Address {
const format = this.faker.helpers.arrayElement(
this.faker.definitions.address.street
);
- return this.faker.fake(format);
+ return this.faker.helpers.fake(format);
}
/**
@@ -212,7 +212,7 @@ export class Address {
const formats = this.faker.definitions.address.street_address;
const format = formats[useFullAddress ? 'full' : 'normal'];
- return this.faker.fake(format);
+ return this.faker.helpers.fake(format);
}
/**
diff --git a/src/modules/company/index.ts b/src/modules/company/index.ts
index 968afbbf..1dce91fd 100644
--- a/src/modules/company/index.ts
+++ b/src/modules/company/index.ts
@@ -45,7 +45,7 @@ export class Company {
format = this.faker.datatype.number(formats.length - 1);
}
- return this.faker.fake(formats[format]);
+ return this.faker.helpers.fake(formats[format]);
}
/**
@@ -88,9 +88,11 @@ export class Company {
* faker.company.catchPhrase() // 'Upgradable systematic flexibility'
*/
catchPhrase(): string {
- return this.faker.fake(
- '{{company.catchPhraseAdjective}} {{company.catchPhraseDescriptor}} {{company.catchPhraseNoun}}'
- );
+ return [
+ this.catchPhraseAdjective(),
+ this.catchPhraseDescriptor(),
+ this.catchPhraseNoun(),
+ ].join(' ');
}
/**
@@ -100,9 +102,7 @@ export class Company {
* faker.company.bs() // 'cultivate synergistic e-markets'
*/
bs(): string {
- return this.faker.fake(
- '{{company.bsBuzz}} {{company.bsAdjective}} {{company.bsNoun}}'
- );
+ return [this.bsBuzz(), this.bsAdjective(), this.bsNoun()].join(' ');
}
/**
diff --git a/src/modules/fake/index.ts b/src/modules/fake/index.ts
index 9dff1c8e..a60acd5b 100644
--- a/src/modules/fake/index.ts
+++ b/src/modules/fake/index.ts
@@ -1,8 +1,10 @@
import type { Faker } from '../..';
-import { FakerError } from '../../errors/faker-error';
+import { deprecated } from '../../internal/deprecated';
/**
* Generator method for combining faker methods based on string input.
+ *
+ * @deprecated
*/
export class Fake {
constructor(private readonly faker: Faker) {
@@ -47,6 +49,7 @@ export class Fake {
* @param str The template string that will get interpolated. Must not be empty.
*
* @see faker.helpers.mustache() to use custom functions for resolution.
+ * @see faker.helpers.fake()
*
* @example
* faker.fake('{{name.lastName}}') // 'Barrows'
@@ -55,93 +58,16 @@ export class Fake {
* faker.fake('Good Morning {{name.firstName}}!') // 'Good Morning Estelle!'
* faker.fake('You can call me at {{phone.number(!## ### #####!)}}.') // 'You can call me at 202 555 973722.'
* faker.fake('I flipped the coin an got: {{helpers.arrayElement(["heads", "tails"])}}') // 'I flipped the coin an got: tails'
+ *
+ * @deprecated Use faker.helpers.fake() instead.
*/
fake(str: string): string {
- // if incoming str parameter is not provided, return error message
- if (typeof str !== 'string' || str.length === 0) {
- throw new FakerError('string parameter is required!');
- }
-
- // find first matching {{ and }}
- const start = str.search(/{{[a-z]/);
- const end = str.indexOf('}}', start);
-
- // if no {{ and }} is found, we are done
- if (start === -1 || end === -1) {
- return str;
- }
-
- // extract method name from between the {{ }} that we found
- // for example: {{name.firstName}}
- const token = str.substring(start + 2, end + 2);
- let method = token.replace('}}', '').replace('{{', '');
-
- // extract method parameters
- const regExp = /\(([^)]+)\)/;
- const matches = regExp.exec(method);
- let parameters = '';
- if (matches) {
- method = method.replace(regExp, '');
- parameters = matches[1];
- }
-
- // split the method into module and function
- const parts = method.split('.');
-
- let currentModuleOrMethod: unknown = this.faker;
- let currentDefinitions: unknown = this.faker.definitions;
-
- // Search for the requested method or definition
- for (const part of parts) {
- currentModuleOrMethod = currentModuleOrMethod?.[part];
- currentDefinitions = currentDefinitions?.[part];
- }
-
- // Make method executable
- let fn: (args?: unknown) => unknown;
- if (typeof currentModuleOrMethod === 'function') {
- fn = currentModuleOrMethod as (args?: unknown) => unknown;
- } else if (Array.isArray(currentDefinitions)) {
- fn = () =>
- this.faker.helpers.arrayElement(currentDefinitions as unknown[]);
- } else {
- throw new FakerError(`Invalid module method or definition: ${method}
-- faker.${method} is not a function
-- faker.definitions.${method} is not an array`);
- }
-
- // assign the function from the module.function namespace
- fn = fn.bind(this);
-
- // If parameters are populated here, they are always going to be of string type
- // since we might actually be dealing with an object or array,
- // we always attempt to the parse the incoming parameters into JSON
- let params: unknown;
- // Note: we experience a small performance hit here due to JSON.parse try / catch
- // If anyone actually needs to optimize this specific code path, please open a support issue on github
- try {
- params = JSON.parse(parameters);
- } catch (err) {
- // since JSON.parse threw an error, assume parameters was actually a string
- params = parameters;
- }
-
- let result: string;
- if (typeof params === 'string' && params.length === 0) {
- result = String(fn());
- } else {
- result = String(fn(params));
- }
-
- // Replace the found tag with the returned fake value
- // We cannot use string.replace here because the result might contain evaluated characters
- const res = str.substring(0, start) + result + str.substring(end + 2);
-
- if (res === '') {
- return '';
- }
-
- // return the response recursively until we are done finding all tags
- return this.fake(res);
+ deprecated({
+ deprecated: 'faker.fake()',
+ proposed: 'faker.helpers.fake()',
+ since: '7.4',
+ until: '8.0',
+ });
+ return this.faker.helpers.fake(str);
}
}
diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts
index a68b66ae..b4d73b2e 100644
--- a/src/modules/helpers/index.ts
+++ b/src/modules/helpers/index.ts
@@ -1,4 +1,5 @@
import type { Faker } from '../..';
+import { FakerError } from '../../errors/faker-error';
import { luhnCheckValue } from './luhn-check';
/**
@@ -454,4 +455,134 @@ export class Helpers {
return arrayCopy.slice(min);
}
+
+ /**
+ * Generator for combining faker methods based on a static string input.
+ *
+ * Note: We recommend using string template literals instead of `fake()`,
+ * which are faster and strongly typed (if you are using TypeScript),
+ * e.g. ``const address = `${faker.address.zipCode()} ${faker.address.city()}`;``
+ *
+ * This method is useful if you have to build a random string from a static, non-executable source
+ * (e.g. string coming from a user, stored in a database or a file).
+ *
+ * It checks the given string for placeholders and replaces them by calling faker methods:
+ *
+ * ```js
+ * const hello = faker.helpers.fake('Hi, my name is {{name.firstName}} {{name.lastName}}!')
+ * ```
+ *
+ * This would use the `faker.name.firstName()` and `faker.name.lastName()` method to resolve the placeholders respectively.
+ *
+ * It is also possible to provide parameters. At first, they will be parsed as json,
+ * and if that isn't possible, we will fall back to string:
+ *
+ * ```js
+ * const message = faker.helpers.fake(`You can call me at {{phone.number(+!# !## #### #####!)}}.')
+ * ```
+ *
+ * Currently it is not possible to set more than a single parameter.
+ *
+ * It is also NOT possible to use any non-faker methods or plain javascript in such templates.
+ *
+ * @param str The template string that will get interpolated. Must not be empty.
+ *
+ * @see faker.helpers.mustache() to use custom functions for resolution.
+ *
+ * @example
+ * faker.helpers.fake('{{name.lastName}}') // 'Barrows'
+ * faker.helpers.fake('{{name.lastName}}, {{name.firstName}} {{name.suffix}}') // 'Durgan, Noe MD'
+ * faker.helpers.fake('This is static test.') // 'This is static test.'
+ * faker.helpers.fake('Good Morning {{name.firstName}}!') // 'Good Morning Estelle!'
+ * faker.helpers.fake('You can call me at {{phone.number(!## ### #####!)}}.') // 'You can call me at 202 555 973722.'
+ * faker.helpers.fake('I flipped the coin an got: {{helpers.arrayElement(["heads", "tails"])}}') // 'I flipped the coin an got: tails'
+ */
+ fake(str: string): string {
+ // if incoming str parameter is not provided, return error message
+ if (typeof str !== 'string' || str.length === 0) {
+ throw new FakerError('string parameter is required!');
+ }
+
+ // find first matching {{ and }}
+ const start = str.search(/{{[a-z]/);
+ const end = str.indexOf('}}', start);
+
+ // if no {{ and }} is found, we are done
+ if (start === -1 || end === -1) {
+ return str;
+ }
+
+ // extract method name from between the {{ }} that we found
+ // for example: {{name.firstName}}
+ const token = str.substring(start + 2, end + 2);
+ let method = token.replace('}}', '').replace('{{', '');
+
+ // extract method parameters
+ const regExp = /\(([^)]+)\)/;
+ const matches = regExp.exec(method);
+ let parameters = '';
+ if (matches) {
+ method = method.replace(regExp, '');
+ parameters = matches[1];
+ }
+
+ // split the method into module and function
+ const parts = method.split('.');
+
+ let currentModuleOrMethod: unknown = this.faker;
+ let currentDefinitions: unknown = this.faker.definitions;
+
+ // Search for the requested method or definition
+ for (const part of parts) {
+ currentModuleOrMethod = currentModuleOrMethod?.[part];
+ currentDefinitions = currentDefinitions?.[part];
+ }
+
+ // Make method executable
+ let fn: (args?: unknown) => unknown;
+ if (typeof currentModuleOrMethod === 'function') {
+ fn = currentModuleOrMethod as (args?: unknown) => unknown;
+ } else if (Array.isArray(currentDefinitions)) {
+ fn = () =>
+ this.faker.helpers.arrayElement(currentDefinitions as unknown[]);
+ } else {
+ throw new FakerError(`Invalid module method or definition: ${method}
+- faker.${method} is not a function
+- faker.definitions.${method} is not an array`);
+ }
+
+ // assign the function from the module.function namespace
+ fn = fn.bind(this);
+
+ // If parameters are populated here, they are always going to be of string type
+ // since we might actually be dealing with an object or array,
+ // we always attempt to the parse the incoming parameters into JSON
+ let params: unknown;
+ // Note: we experience a small performance hit here due to JSON.parse try / catch
+ // If anyone actually needs to optimize this specific code path, please open a support issue on github
+ try {
+ params = JSON.parse(parameters);
+ } catch (err) {
+ // since JSON.parse threw an error, assume parameters was actually a string
+ params = parameters;
+ }
+
+ let result: string;
+ if (typeof params === 'string' && params.length === 0) {
+ result = String(fn());
+ } else {
+ result = String(fn(params));
+ }
+
+ // Replace the found tag with the returned fake value
+ // We cannot use string.replace here because the result might contain evaluated characters
+ const res = str.substring(0, start) + result + str.substring(end + 2);
+
+ if (res === '') {
+ return '';
+ }
+
+ // return the response recursively until we are done finding all tags
+ return this.fake(res);
+ }
}