Skip to content

Commit 8fa14c6

Browse files
Shinigami92HonzaMac
authored andcommitted
feat: migrate fake (#79)
Co-authored-by: Honza Machala <[email protected]>
1 parent 6122d3c commit 8fa14c6

File tree

2 files changed

+112
-1
lines changed

2 files changed

+112
-1
lines changed

src/fake.ts

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import type { Faker } from '.';
2+
3+
/**
4+
* Generator method for combining faker methods based on string input
5+
*/
6+
export class Fake {
7+
constructor(private readonly faker: Faker) {
8+
// Bind `this` so namespaced is working correctly
9+
for (const name of Object.getOwnPropertyNames(Fake.prototype)) {
10+
if (name === 'constructor' || typeof this[name] !== 'function') {
11+
continue;
12+
}
13+
this[name] = this[name].bind(this);
14+
}
15+
}
16+
17+
/**
18+
* Generator method for combining faker methods based on string input
19+
*
20+
* __Example:__
21+
*
22+
* ```
23+
* console.log(faker.fake('{{name.lastName}}, {{name.firstName}} {{name.suffix}}'));
24+
* // outputs: "Marks, Dean Sr."
25+
* ```
26+
*
27+
* This will interpolate the format string with the value of methods
28+
* [name.lastName]{@link faker.name.lastName}, [name.firstName]{@link faker.name.firstName},
29+
* and [name.suffix]{@link faker.name.suffix}
30+
*
31+
* @method faker.fake
32+
* @param str
33+
*/
34+
fake(str: string): string {
35+
// setup default response as empty string
36+
let res = '';
37+
38+
// if incoming str parameter is not provided, return error message
39+
if (typeof str !== 'string' || str.length === 0) {
40+
throw new Error('string parameter is required!');
41+
}
42+
43+
// find first matching {{ and }}
44+
const start = str.search('{{');
45+
const end = str.search('}}');
46+
47+
// if no {{ and }} is found, we are done
48+
if (start === -1 || end === -1) {
49+
return str;
50+
}
51+
52+
// console.log('attempting to parse', str);
53+
54+
// extract method name from between the {{ }} that we found
55+
// for example: {{name.firstName}}
56+
const token = str.substr(start + 2, end - start - 2);
57+
let method = token.replace('}}', '').replace('{{', '');
58+
59+
// console.log('method', method)
60+
61+
// extract method parameters
62+
const regExp = /\(([^)]+)\)/;
63+
const matches = regExp.exec(method);
64+
let parameters = '';
65+
if (matches) {
66+
method = method.replace(regExp, '');
67+
parameters = matches[1];
68+
}
69+
70+
// split the method into module and function
71+
const parts = method.split('.');
72+
73+
if (typeof this.faker[parts[0]] === 'undefined') {
74+
throw new Error('Invalid module: ' + parts[0]);
75+
}
76+
77+
if (typeof this.faker[parts[0]][parts[1]] === 'undefined') {
78+
throw new Error('Invalid method: ' + parts[0] + '.' + parts[1]);
79+
}
80+
81+
// assign the function from the module.function namespace
82+
const fn = this.faker[parts[0]][parts[1]];
83+
84+
// If parameters are populated here, they are always going to be of string type
85+
// since we might actually be dealing with an object or array,
86+
// we always attempt to the parse the incoming parameters into JSON
87+
let params: any;
88+
// Note: we experience a small performance hit here due to JSON.parse try / catch
89+
// If anyone actually needs to optimize this specific code path, please open a support issue on github
90+
try {
91+
params = JSON.parse(parameters);
92+
} catch (err) {
93+
// since JSON.parse threw an error, assume parameters was actually a string
94+
params = parameters;
95+
}
96+
97+
let result: string;
98+
if (typeof params === 'string' && params.length === 0) {
99+
result = fn.call(this);
100+
} else {
101+
result = fn.call(this, params);
102+
}
103+
104+
// replace the found tag with the returned fake value
105+
res = str.replace('{{' + token + '}}', result);
106+
107+
// return the response recursively until we are done finding all tags
108+
return this.fake(res);
109+
}
110+
}

src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Datatype } from './datatype';
22
import { _Date } from './date';
3+
import { Fake } from './fake';
34
import { Git } from './git';
45
import { Hacker } from './hacker';
56
import { Helpers } from './helpers';
@@ -155,7 +156,7 @@ export class Faker {
155156

156157
seedValue?: any[] | any;
157158

158-
readonly fake = new (require('./fake'))(this).fake;
159+
readonly fake: Fake['fake'] = new Fake(this).fake;
159160
readonly unique = new (require('./unique'))(this).unique;
160161

161162
readonly mersenne: Mersenne = new Mersenne();

0 commit comments

Comments
 (0)