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: migrate fake #79

Merged
merged 4 commits into from
Jan 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions src/fake.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import type { Faker } from '.';

/**
* Generator method for combining faker methods based on string input
*/
export class Fake {
constructor(private readonly faker: Faker) {
// Bind `this` so namespaced is working correctly
for (const name of Object.getOwnPropertyNames(Fake.prototype)) {
if (name === 'constructor' || typeof this[name] !== 'function') {
continue;
}
this[name] = this[name].bind(this);
}
}

/**
* Generator method for combining faker methods based on string input
*
* __Example:__
*
* ```
* console.log(faker.fake('{{name.lastName}}, {{name.firstName}} {{name.suffix}}'));
* // outputs: "Marks, Dean Sr."
* ```
*
* This will interpolate the format string with the value of methods
* [name.lastName]{@link faker.name.lastName}, [name.firstName]{@link faker.name.firstName},
* and [name.suffix]{@link faker.name.suffix}
*
* @method faker.fake
* @param str
*/
fake(str: string): string {
// setup default response as empty string
let res = '';

// if incoming str parameter is not provided, return error message
if (typeof str !== 'string' || str.length === 0) {
throw new Error('string parameter is required!');
}

// find first matching {{ and }}
const start = str.search('{{');
const end = str.search('}}');

// if no {{ and }} is found, we are done
if (start === -1 || end === -1) {
return str;
}

// console.log('attempting to parse', str);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be removed, this will not break anything


// extract method name from between the {{ }} that we found
// for example: {{name.firstName}}
const token = str.substr(start + 2, end - start - 2);
let method = token.replace('}}', '').replace('{{', '');

// console.log('method', method)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be removed, this will not break anything


// 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('.');

if (typeof this.faker[parts[0]] === 'undefined') {
throw new Error('Invalid module: ' + parts[0]);
}

if (typeof this.faker[parts[0]][parts[1]] === 'undefined') {
throw new Error('Invalid method: ' + parts[0] + '.' + parts[1]);
}

// assign the function from the module.function namespace
const fn = this.faker[parts[0]][parts[1]];

// 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: any;
// 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 = fn.call(this);
} else {
result = fn.call(this, params);
}

// replace the found tag with the returned fake value
res = str.replace('{{' + token + '}}', result);

// return the response recursively until we are done finding all tags
return this.fake(res);
}
}
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Datatype } from './datatype';
import { _Date } from './date';
import { Fake } from './fake';
import { Git } from './git';
import { Hacker } from './hacker';
import { Helpers } from './helpers';
Expand Down Expand Up @@ -155,7 +156,7 @@ export class Faker {

seedValue?: any[] | any;

readonly fake = new (require('./fake'))(this).fake;
readonly fake: Fake['fake'] = new Fake(this).fake;
readonly unique = new (require('./unique'))(this).unique;

readonly mersenne: Mersenne = new Mersenne();
Expand Down