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: split SimpleFaker class from Faker #2369

Merged
merged 26 commits into from Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d3529e4
Split BaseFaker class from Faker
Shinigami92 Sep 1, 2023
d864e16
add base modules
Shinigami92 Sep 1, 2023
09eabda
Export a baseFaker
Shinigami92 Sep 1, 2023
673202d
Move base faker to own file
Shinigami92 Sep 7, 2023
fdabd9c
Export BaseModules
Shinigami92 Sep 7, 2023
4846a2e
Add test
Shinigami92 Sep 7, 2023
678be1f
generate base faker docs
Shinigami92 Sep 7, 2023
871a95b
Add JSDoc
Shinigami92 Sep 7, 2023
c0b777b
Just use processFakerClass
Shinigami92 Sep 10, 2023
9bd3115
comment
Shinigami92 Sep 10, 2023
fc2a48d
Add warning in localization guide
Shinigami92 Sep 10, 2023
f8d6158
Merge branch 'next' into 1351-split-faker-class-into-smaller-unit
Shinigami92 Sep 11, 2023
1eccef7
Apply review suggestions
Shinigami92 Sep 12, 2023
88fa166
Merge branch 'next' into 1351-split-faker-class-into-smaller-unit
Shinigami92 Sep 12, 2023
c04ee63
Rename to simple
Shinigami92 Sep 13, 2023
9584543
Merge branch 'next' into 1351-split-faker-class-into-smaller-unit
Shinigami92 Sep 13, 2023
2455a46
Update JSDoc
Shinigami92 Sep 13, 2023
845f329
Add simple faker usage docs
Shinigami92 Sep 13, 2023
1db38c2
chore: remove generics (#2393)
Shinigami92 Sep 15, 2023
7aea4a2
Merge branch 'next' into 1351-split-faker-class-into-smaller-unit
Shinigami92 Sep 15, 2023
81268eb
Update docs/guide/usage.md
Shinigami92 Sep 15, 2023
0d3b73f
use list
Shinigami92 Sep 15, 2023
9ae1ff7
add link
Shinigami92 Sep 15, 2023
c2cd495
Merge branch 'next' into 1351-split-faker-class-into-smaller-unit
Shinigami92 Sep 15, 2023
6919e75
Merge branch 'next' into 1351-split-faker-class-into-smaller-unit
Shinigami92 Sep 17, 2023
0ace8eb
Merge branch 'next' into 1351-split-faker-class-into-smaller-unit
ST-DDT Sep 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/.vitepress/api-pages.ts
Expand Up @@ -3,6 +3,7 @@
export const apiPages = [
{ text: 'Overview', link: '/api/' },
{ text: 'Faker', link: '/api/faker.html' },
{ text: 'SimpleFaker', link: '/api/simpleFaker.html' },
{ text: 'Airline', link: '/api/airline.html' },
{ text: 'Animal', link: '/api/animal.html' },
{ text: 'Color', link: '/api/color.html' },
Expand Down
15 changes: 15 additions & 0 deletions docs/guide/usage.md
Expand Up @@ -127,6 +127,21 @@ or alternatively you can set a default reference date for all these methods:
faker.setDefaultRefDate('2023-01-01T00:00:00.000Z');
```

## Simple data generation

Faker provides a `simpleFaker` that can be used to generate data that are not based on any locales like numbers and strings.
Also **helpers** like `arrayElement` or `multiple` are available.

This is useful if you just want to generate e.g. `uuid`s for your test environment, but don't want/need to initiate/load a full Faker instance, which would include at least 500KB of locale data.

```ts
import { simpleFaker } from '@faker-js/faker';

const uuid = simpleFaker.string.uuid();
```

Shinigami92 marked this conversation as resolved.
Show resolved Hide resolved
See more about `SimpleFaker` in the [API docs](/api/simpleFaker).

## Create complex objects

Faker mostly generates values for primitives.
Expand Down
40 changes: 28 additions & 12 deletions scripts/apidoc/fakerClass.ts
Expand Up @@ -4,36 +4,48 @@ import type { Method } from '../../docs/.vitepress/components/api-docs/method';
import { writeApiDocsModule } from './apiDocsWriter';
import { analyzeModule, processModuleMethods } from './moduleMethods';
import { analyzeSignature } from './signature';
import { selectApiSignature } from './typedoc';
import { extractModuleFieldName, selectApiSignature } from './typedoc';
import type { ModuleSummary } from './utils';

export async function processFakerClass(
export async function processFakerClasses(
project: ProjectReflection
): Promise<ModuleSummary> {
const fakerClass = project
): Promise<ModuleSummary[]> {
const fakerClasses = project
.getChildrenByKind(ReflectionKind.Class)
.filter((clazz) => clazz.name === 'Faker')[0];
.filter((clazz) => clazz.name === 'Faker' || clazz.name === 'SimpleFaker');

if (!fakerClass) {
throw new Error('Faker class not found');
if (fakerClasses.length !== 2) {
throw new Error('Faker classes not found');
}

return processClass(fakerClass);
return Promise.all(fakerClasses.map(processClass));
}

async function processClass(
fakerClass: DeclarationReflection
): Promise<ModuleSummary> {
console.log(`Processing Faker class`);
const { name } = fakerClass;
const moduleFieldName = extractModuleFieldName(fakerClass);

console.log(`Processing ${name} class`);

const { comment, deprecated } = analyzeModule(fakerClass);
const methods: Method[] = [];

console.debug(`- constructor`);
methods.push(await processConstructor(fakerClass));

methods.push(...(await processModuleMethods(fakerClass, 'faker.')));
methods.push(
...(await processModuleMethods(fakerClass, `${moduleFieldName}.`))
);

return writeApiDocsModule('Faker', 'faker', comment, deprecated, methods);
return writeApiDocsModule(
name,
moduleFieldName,
comment,
deprecated,
methods
);
}

async function processConstructor(
Expand All @@ -45,7 +57,11 @@ async function processConstructor(

const signature = selectApiSignature(constructor);

const method = await analyzeSignature(signature, '', 'new Faker');
const method = await analyzeSignature(
signature,
'',
`new ${fakerClass.name}`
);

return {
...method,
Expand Down
4 changes: 2 additions & 2 deletions scripts/apidoc/generate.ts
Expand Up @@ -5,7 +5,7 @@ import {
writeApiSearchIndex,
writeSourceBaseUrl,
} from './apiDocsWriter';
import { processFakerClass } from './fakerClass';
import { processFakerClasses } from './fakerClass';
import { processFakerUtilities } from './fakerUtilities';
import { processModules } from './moduleMethods';
import { loadProject } from './typedoc';
Expand All @@ -23,7 +23,7 @@ export async function generate(): Promise<void> {
await app.generateJson(project, pathOutputJson);

const pages = await Promise.all([
processFakerClass(project),
...(await processFakerClasses(project)),
...(await processModules(project)).sort((a, b) =>
a.text.localeCompare(b.text)
),
Expand Down
192 changes: 6 additions & 186 deletions src/faker.ts
@@ -1,8 +1,6 @@
import type { LocaleDefinition, MetadataDefinition } from './definitions';
import { FakerError } from './errors/faker-error';
import { deprecated } from './internal/deprecated';
import type { Mersenne } from './internal/mersenne/mersenne';
import mersenne from './internal/mersenne/mersenne';
import type { LocaleProxy } from './locale-proxy';
import { createLocaleProxy } from './locale-proxy';
import { AirlineModule } from './modules/airline';
Expand All @@ -11,7 +9,6 @@ import { ColorModule } from './modules/color';
import { CommerceModule } from './modules/commerce';
import { CompanyModule } from './modules/company';
import { DatabaseModule } from './modules/database';
import { DatatypeModule } from './modules/datatype';
import { DateModule } from './modules/date';
import { FinanceModule } from './modules/finance';
import { GitModule } from './modules/git';
Expand All @@ -23,16 +20,15 @@ import type { LocationModule as AddressModule } from './modules/location';
import { LocationModule } from './modules/location';
import { LoremModule } from './modules/lorem';
import { MusicModule } from './modules/music';
import { NumberModule } from './modules/number';
import type { PersonModule as NameModule } from './modules/person';
import { PersonModule } from './modules/person';
import { PhoneModule } from './modules/phone';
import { RandomModule } from './modules/random';
import { ScienceModule } from './modules/science';
import { StringModule } from './modules/string';
import { SystemModule } from './modules/system';
import { VehicleModule } from './modules/vehicle';
import { WordModule } from './modules/word';
import { SimpleFaker } from './simple-faker';
import { mergeLocales } from './utils/merge-locales';

/**
Expand Down Expand Up @@ -60,72 +56,16 @@ import { mergeLocales } from './utils/merge-locales';
*
* customFaker.music.genre(); // throws Error as this data is not available in `es`
*/
export class Faker {
export class Faker extends SimpleFaker {
readonly rawDefinitions: LocaleDefinition;
readonly definitions: LocaleProxy;
private _defaultRefDate: () => Date = () => new Date();

/**
* Gets a new reference date used to generate relative dates.
*/
get defaultRefDate(): () => Date {
return this._defaultRefDate;
}

/**
* Sets the `refDate` source to use if no `refDate` date is passed to the date methods.
*
* @param dateOrSource The function or the static value used to generate the `refDate` date instance.
* The function must return a new valid `Date` instance for every call.
* Defaults to `() => new Date()`.
*
* @see [Reproducible Results](https://fakerjs.dev/guide/usage.html#reproducible-results)
* @see faker.seed() for reproducible results.
*
* @example
* faker.seed(1234);
*
* // Default behavior
* // faker.setDefaultRefDate();
* faker.date.past(); // Changes based on the current date/time
*
* // Use a static ref date
* faker.setDefaultRefDate(new Date('2020-01-01'));
* faker.date.past(); // Reproducible '2019-07-03T08:27:58.118Z'
*
* // Use a ref date that changes every time it is used
* let clock = new Date("2020-01-01").getTime();
* faker.setDefaultRefDate(() => {
* clock += 1000; // +1s
* return new Date(clock);
* });
*
* faker.defaultRefDate() // 2020-01-01T00:00:01Z
* faker.defaultRefDate() // 2020-01-01T00:00:02Z
*/
setDefaultRefDate(
dateOrSource: string | Date | number | (() => Date) = () => new Date()
): void {
if (typeof dateOrSource === 'function') {
this._defaultRefDate = dateOrSource;
} else {
this._defaultRefDate = () => new Date(dateOrSource);
}
}

/** @internal */
private readonly _mersenne: Mersenne = mersenne();

/**
* @deprecated Use the modules specific to the type of data you want to generate instead.
*/
// eslint-disable-next-line deprecation/deprecation
readonly random: RandomModule = new RandomModule(this);

readonly helpers: HelpersModule = new HelpersModule(this);

readonly datatype: DatatypeModule = new DatatypeModule(this);

readonly airline: AirlineModule = new AirlineModule(this);
readonly animal: AnimalModule = new AnimalModule(this);
readonly color: ColorModule = new ColorModule(this);
Expand All @@ -136,16 +76,15 @@ export class Faker {
readonly finance = new FinanceModule(this);
readonly git: GitModule = new GitModule(this);
readonly hacker: HackerModule = new HackerModule(this);
readonly helpers: HelpersModule = new HelpersModule(this);
readonly image: ImageModule = new ImageModule(this);
readonly internet: InternetModule = new InternetModule(this);
readonly location: LocationModule = new LocationModule(this);
readonly lorem: LoremModule = new LoremModule(this);
readonly music: MusicModule = new MusicModule(this);
readonly person: PersonModule = new PersonModule(this);
readonly number: NumberModule = new NumberModule(this);
readonly phone: PhoneModule = new PhoneModule(this);
readonly science: ScienceModule = new ScienceModule(this);
readonly string: StringModule = new StringModule(this);
readonly system: SystemModule = new SystemModule(this);
readonly vehicle: VehicleModule = new VehicleModule(this);
readonly word: WordModule = new WordModule(this);
Expand Down Expand Up @@ -299,9 +238,12 @@ export class Faker {
localeFallback?: string;
}
) {
super();

const { locales } = options as {
locales: Record<string, LocaleDefinition>;
};

if (locales != null) {
deprecated({
deprecated:
Expand Down Expand Up @@ -336,128 +278,6 @@ export class Faker {
this.definitions = createLocaleProxy(this.rawDefinitions);
}

/**
* Sets the seed or generates a new one.
*
* Please note that generated values are dependent on both the seed and the
* number of calls that have been made since it was set.
*
* This method is intended to allow for consistent values in tests, so you
* might want to use hardcoded values as the seed.
*
* In addition to that it can be used for creating truly random tests
* (by passing no arguments), that still can be reproduced if needed,
* by logging the result and explicitly setting it if needed.
*
* @param seed The seed to use. Defaults to a random number.
*
* @returns The seed that was set.
*
* @see [Reproducible Results](https://fakerjs.dev/guide/usage.html#reproducible-results)
* @see faker.setDefaultRefDate() when generating relative dates.
*
* @example
* // Consistent values for tests:
* faker.seed(42)
* faker.number.int(10); // 4
* faker.number.int(10); // 8
*
* faker.seed(42)
* faker.number.int(10); // 4
* faker.number.int(10); // 8
*
* // Random but reproducible tests:
* // Simply log the seed, and if you need to reproduce it, insert the seed here
* console.log('Running test with seed:', faker.seed());
*/
seed(seed?: number): number;
/**
* Sets the seed array.
*
* Please note that generated values are dependent on both the seed and the
* number of calls that have been made since it was set.
*
* This method is intended to allow for consistent values in a tests, so you
* might want to use hardcoded values as the seed.
*
* In addition to that it can be used for creating truly random tests
* (by passing no arguments), that still can be reproduced if needed,
* by logging the result and explicitly setting it if needed.
*
* @param seedArray The seed array to use.
*
* @returns The seed array that was set.
*
* @see [Reproducible Results](https://fakerjs.dev/guide/usage.html#reproducible-results)
* @see faker.setDefaultRefDate() when generating relative dates.
*
* @example
* // Consistent values for tests:
* faker.seed([42, 13, 17])
* faker.number.int(10); // 4
* faker.number.int(10); // 8
*
* faker.seed([42, 13, 17])
* faker.number.int(10); // 4
* faker.number.int(10); // 8
*
* // Random but reproducible tests:
* // Simply log the seed, and if you need to reproduce it, insert the seed here
* console.log('Running test with seed:', faker.seed());
*/
seed(seedArray: number[]): number[];
/**
* Sets the seed or generates a new one.
*
* Please note that generated values are dependent on both the seed and the
* number of calls that have been made since it was set.
*
* This method is intended to allow for consistent values in a tests, so you
* might want to use hardcoded values as the seed.
*
* In addition to that it can be used for creating truly random tests
* (by passing no arguments), that still can be reproduced if needed,
* by logging the result and explicitly setting it if needed.
*
* @param seed The seed or seed array to use.
*
* @returns The seed that was set.
*
* @see [Reproducible Results](https://fakerjs.dev/guide/usage.html#reproducible-results)
* @see faker.setDefaultRefDate() when generating relative dates.
*
* @example
* // Consistent values for tests (using a number):
* faker.seed(42)
* faker.number.int(10); // 4
* faker.number.int(10); // 8
*
* faker.seed(42)
* faker.number.int(10); // 4
* faker.number.int(10); // 8
*
* // Consistent values for tests (using an array):
* faker.seed([42, 13, 17])
* faker.number.int(10); // 4
* faker.number.int(10); // 8
*
* faker.seed([42, 13, 17])
* faker.number.int(10); // 4
* faker.number.int(10); // 8
*
* // Random but reproducible tests:
* // Simply log the seed, and if you need to reproduce it, insert the seed here
* console.log('Running test with seed:', faker.seed());
*/
seed(seed?: number | number[]): number | number[];
seed(
seed: number | number[] = Math.ceil(Math.random() * Number.MAX_SAFE_INTEGER)
): number | number[] {
this._mersenne.seed(seed);

return seed;
}

/**
* Returns an object with metadata about the current locale.
*
Expand Down