Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
24a25ba
feat: introduce FakerCore
ST-DDT Apr 20, 2024
1688003
chore: restore
ST-DDT Apr 20, 2024
2ef0270
Merge branch 'next' into feat/samfn/faker-core
ST-DDT Apr 22, 2024
790e645
chore: apply suggestions
ST-DDT Apr 22, 2024
e4da2f5
Merge branch 'next' into feat/samfn/faker-core
ST-DDT May 14, 2024
6ef3999
chore: todos
ST-DDT May 14, 2024
66f4696
chore: workaround
ST-DDT May 14, 2024
7353a69
Merge branch 'next' into feat/samfn/faker-core
ST-DDT May 18, 2024
f96a407
Merge branch 'next' into feat/samfn/faker-core
ST-DDT May 30, 2024
d99d3b4
Merge branch 'next' into feat/samfn/faker-core
ST-DDT Jun 21, 2024
aa8d8d6
Merge branch 'next' into feat/samfn/faker-core
ST-DDT Aug 1, 2024
a54120a
Merge branch 'next' into feat/samfn/faker-core
ST-DDT Sep 14, 2024
e807a8e
Merge branch 'next' into feat/samfn/faker-core
ST-DDT Sep 16, 2024
e659674
Merge branch 'next' into feat/samfn/faker-core
ST-DDT Oct 16, 2024
df2f308
Merge branch 'next' into feat/samfn/faker-core
ST-DDT Mar 22, 2026
6dada60
chore: cleanup imports
ST-DDT Mar 22, 2026
4f9907a
chore: simplify FakerOptions
ST-DDT Mar 22, 2026
24bb1bf
chore: export new functions and types
ST-DDT Mar 22, 2026
b2bf1e2
Merge branch 'next' into feat/samfn/faker-core
ST-DDT Mar 28, 2026
54add10
chore: edit after review
ST-DDT Mar 29, 2026
49ee0fb
Merge branch 'next' into feat/samfn/faker-core
ST-DDT Apr 5, 2026
9a12eee
Merge branch 'next' into feat/samfn/faker-core
ST-DDT Apr 8, 2026
1f3f42c
chore: remove comment
ST-DDT Apr 8, 2026
0c2e3de
chore: bump since version
ST-DDT Apr 8, 2026
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
20 changes: 20 additions & 0 deletions src/config.ts
Comment thread
ST-DDT marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* The possible configuration options, that can be set.
* This type exists to be extended for plugins via type augmentation.
*
* The `@default` tag is used to indicate the default value, that should be used if, the config is absent.
*/
export interface FakerConfig {
/**
* The function used to generate the `refDate` date instance, if not provided as method param.
* The function must return a new valid `Date` instance for every call.
*
* @see [Reproducible Results](https://fakerjs.dev/guide/usage.html#reproducible-results)
* @see faker.seed(): For generating reproducible values.
*
* @since 9.0.0
*
* @default () => new Date()
*/
refDate?: () => Date;
}
25 changes: 25 additions & 0 deletions src/core.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { FakerConfig } from './config';
import type { LocaleDefinition } from './definitions';
import type { Randomizer } from './randomizer';

/**
* The core grants access to the locale data, the randomizer and config settings.
*/
export interface FakerCore {
/**
* The locale data associated with this instance.
*
* Always present, but it might be empty if the locale data is not available.
*/
readonly locale: LocaleDefinition;

/**
* The randomizer used to generate random values.
*/
readonly randomizer: Randomizer;

/**
* The configuration settings used by this instance.
*/
readonly config: FakerConfig;
}
61 changes: 40 additions & 21 deletions src/faker.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { FakerCore } from './core';
import type { LocaleDefinition, MetadataDefinition } from './definitions';
import { FakerError } from './errors/faker-error';
import { deprecated } from './internal/deprecated';
import { generateMersenne53Randomizer } from './internal/mersenne';
import type { LocaleProxy } from './locale-proxy';
import { createLocaleProxy } from './locale-proxy';
import { AirlineModule } from './modules/airline';
Expand Down Expand Up @@ -58,7 +60,6 @@ import { mergeLocales } from './utils/merge-locales';
* customFaker.music.genre(); // throws Error as this data is not available in `es`
*/
export class Faker extends SimpleFaker {
readonly rawDefinitions: LocaleDefinition;
readonly definitions: LocaleProxy;

readonly airline: AirlineModule = new AirlineModule(this);
Expand All @@ -85,6 +86,10 @@ export class Faker extends SimpleFaker {
readonly vehicle: VehicleModule = new VehicleModule(this);
readonly word: WordModule = new WordModule(this);

get rawDefinitions(): LocaleDefinition {
return this.fakerCore.locale;
}
Comment thread
ST-DDT marked this conversation as resolved.

// Aliases
/** @deprecated Use {@link Faker#location} instead */
get address(): AddressModule {
Expand Down Expand Up @@ -138,27 +143,40 @@ export class Faker extends SimpleFaker {
*
* @since 8.0.0
*/
constructor(options: {
/**
* The locale data to use for this instance.
* If an array is provided, the first locale that has a definition for a given property will be used.
*
* @see mergeLocales(): For more information about how the locales are merged.
*/
locale: LocaleDefinition | LocaleDefinition[];
constructor(
options:
| {
/**
* The locale data to use for this instance.
* If an array is provided, the first locale that has a definition for a given property will be used.
*
* @see mergeLocales(): For more information about how the locales are merged.
*/
locale: LocaleDefinition | LocaleDefinition[];

/**
* The Randomizer to use.
* Specify this only if you want to use it to achieve a specific goal,
* such as sharing the same random generator with other instances/tools.
*
* @default generateMersenne53Randomizer()
*/
/**
* The Randomizer to use.
* Specify this only if you want to use it to achieve a specific goal,
* such as sharing the same random generator with other instances/tools.
*
* @default generateMersenne53Randomizer()
*/
randomizer?: Randomizer;
}
| {
/**
* The faker core with the randomizer, locale data and config to use.
*/
fakerCore: FakerCore;
}
);
constructor(options: {
locale?: LocaleDefinition | LocaleDefinition[];
randomizer?: Randomizer;
fakerCore?: FakerCore;
}) {
super({ randomizer: options.randomizer });

let { locale } = options;
const { randomizer = generateMersenne53Randomizer(), fakerCore } = options;
let { locale = {} } = options;

if (Array.isArray(locale)) {
if (locale.length === 0) {
Expand All @@ -170,7 +188,8 @@ export class Faker extends SimpleFaker {
locale = mergeLocales(locale);
}

this.rawDefinitions = locale;
super({ fakerCore: fakerCore ?? { locale, randomizer, config: {} } });

this.definitions = createLocaleProxy(this.rawDefinitions);
}
Comment thread
ST-DDT marked this conversation as resolved.

Expand All @@ -186,7 +205,7 @@ export class Faker extends SimpleFaker {
* @since 8.1.0
*/
getMetadata(): MetadataDefinition {
return this.rawDefinitions.metadata ?? {};
return this.fakerCore.locale.metadata ?? {};
}
}

Expand Down
6 changes: 2 additions & 4 deletions src/modules/number/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ export class NumberModule extends SimpleModuleBase {
throw new FakerError(`Max ${max} should be greater than min ${min}.`);
}

// @ts-expect-error: access private member field
const randomizer = this.faker._randomizer;
const { randomizer } = this.faker.fakerCore;
const real = randomizer.next();
const delta = effectiveMax - effectiveMin + 1; // +1 for inclusive max bounds and even distribution
return Math.floor(real * delta + effectiveMin) * multipleOf;
Expand Down Expand Up @@ -214,8 +213,7 @@ export class NumberModule extends SimpleModuleBase {
return int / factor;
}

// @ts-expect-error: access private member field
const randomizer = this.faker._randomizer;
const { randomizer } = this.faker.fakerCore;
const real = randomizer.next();
return real * (max - min) + min;
}
Expand Down
48 changes: 31 additions & 17 deletions src/simple-faker.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { FakerCore } from './core';
import { generateMersenne53Randomizer } from './internal/mersenne';
import { DatatypeModule } from './modules/datatype';
import { SimpleDateModule } from './modules/date';
Expand Down Expand Up @@ -26,13 +27,13 @@ import type { Randomizer } from './randomizer';
* simpleFaker.string.uuid(); // 'c50e1f5c-86e8-4aa9-888e-168e0a182519'
*/
export class SimpleFaker {
protected _defaultRefDate: () => Date = () => new Date();
readonly fakerCore: FakerCore;

/**
* Gets a new reference date used to generate relative dates.
*/
get defaultRefDate(): () => Date {
return this._defaultRefDate;
return this.fakerCore.config.refDate ?? (() => new Date());
}
Comment thread
ST-DDT marked this conversation as resolved.

/**
Expand Down Expand Up @@ -72,15 +73,12 @@ export class SimpleFaker {
dateOrSource: string | Date | number | (() => Date) = () => new Date()
): void {
if (typeof dateOrSource === 'function') {
this._defaultRefDate = dateOrSource;
this.fakerCore.config.refDate = dateOrSource;
} else {
this._defaultRefDate = () => new Date(dateOrSource);
this.fakerCore.config.refDate = () => new Date(dateOrSource);
}
}

/** @internal */
private readonly _randomizer: Randomizer;

readonly datatype: DatatypeModule = new DatatypeModule(this);
readonly date: SimpleDateModule = new SimpleDateModule(this);
readonly helpers: SimpleHelpersModule = new SimpleHelpersModule(this);
Expand Down Expand Up @@ -110,21 +108,37 @@ export class SimpleFaker {
*
* @since 8.1.0
*/
constructor(
options?:
| {
/**
* The Randomizer to use.
* Specify this only if you want to use it to achieve a specific goal,
* such as sharing the same random generator with other instances/tools.
*
* @default generateMersenne53Randomizer()
*/
randomizer?: Randomizer;
}
| {
/**
* The faker core with the randomizer and config to use.
*/
fakerCore: FakerCore;
}
);
constructor(
options: {
/**
* The Randomizer to use.
* Specify this only if you want to use it to achieve a specific goal,
* such as sharing the same random generator with other instances/tools.
*
* @default generateMersenne53Randomizer()
*/
randomizer?: Randomizer;
fakerCore?: FakerCore;
} = {}
) {
const { randomizer = generateMersenne53Randomizer() } = options;
const {
randomizer = generateMersenne53Randomizer(),
fakerCore = { locale: {}, randomizer, config: {} },
} = options;

this._randomizer = randomizer;
this.fakerCore = fakerCore;
}

/**
Expand Down Expand Up @@ -250,7 +264,7 @@ export class SimpleFaker {
seed(
seed: number | number[] = Math.ceil(Math.random() * Number.MAX_SAFE_INTEGER)
): number | number[] {
this._randomizer.seed(seed);
this.fakerCore.randomizer.seed(seed);

return seed;
}
Expand Down
8 changes: 1 addition & 7 deletions test/all-functional.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,7 @@ import type { Faker, allLocales } from '../src';
import { allFakers, fakerEN } from '../src';
import { keys } from '../src/internal/keys';

const IGNORED_MODULES = new Set([
'rawDefinitions',
'definitions',
'helpers',
'_randomizer',
'_defaultRefDate',
]);
const IGNORED_MODULES = new Set(['rawDefinitions', 'helpers', 'fakerCore']);

function getMethodNamesByModules(faker: Faker): { [module: string]: string[] } {
return Object.fromEntries(
Expand Down
3 changes: 1 addition & 2 deletions test/modules/number.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -629,8 +629,7 @@ describe('number', () => {

describe('value range tests', () => {
const customFaker = new SimpleFaker();
// @ts-expect-error: access private member field
const randomizer = customFaker._randomizer;
const { randomizer } = customFaker.fakerCore;
describe('int', () => {
it('should be able to return 0', () => {
randomizer.next = () => 0;
Expand Down