aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorST-DDT <[email protected]>2022-04-19 20:20:51 +0200
committerGitHub <[email protected]>2022-04-19 20:20:51 +0200
commit069f4d1c08b2a314aa24a4a55b7498ff97be7c3a (patch)
tree74aac16a2df39c0cc03c2dceb66fc8b55e978584 /src
parentd94159f155cd58ba8ebfdbf0d2dd642a418175ab (diff)
downloadfaker-069f4d1c08b2a314aa24a4a55b7498ff97be7c3a.tar.xz
faker-069f4d1c08b2a314aa24a4a55b7498ff97be7c3a.zip
feat: dynamic definitions tree (#822)
Diffstat (limited to 'src')
-rw-r--r--src/definitions/definitions.ts11
-rw-r--r--src/faker.ts80
2 files changed, 52 insertions, 39 deletions
diff --git a/src/definitions/definitions.ts b/src/definitions/definitions.ts
index d59f84fc..b696d47a 100644
--- a/src/definitions/definitions.ts
+++ b/src/definitions/definitions.ts
@@ -69,7 +69,8 @@ export type LocaleDefinition = {
[module in keyof Definitions]?: Partial<Definitions[module]>;
} & {
// Unsupported & custom modules
- [group: string]: Record<string, any> | string;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ [group: string]: any;
};
/**
@@ -78,8 +79,8 @@ export type LocaleDefinition = {
* that don't require prior getter generation in the future.
*/
export type DefinitionTypes = {
- readonly title: string;
- readonly separator: string;
+ readonly title: 'metadata';
+ readonly separator: 'metadata';
} & {
readonly [module in keyof Definitions]: Array<keyof Definitions[module]>;
};
@@ -89,8 +90,8 @@ export type DefinitionTypes = {
* that needs to have a fallback generated in Faker.loadDefinitions().
*/
export const DEFINITIONS: DefinitionTypes = {
- title: '',
- separator: '',
+ title: 'metadata',
+ separator: 'metadata',
address: ADDRESS,
animal: ANIMAL,
diff --git a/src/faker.ts b/src/faker.ts
index 7b74d58c..14cb107d 100644
--- a/src/faker.ts
+++ b/src/faker.ts
@@ -47,8 +47,7 @@ export class Faker {
locale: UsableLocale;
localeFallback: UsableLocale;
- // Will be lazy init
- readonly definitions: LocaleDefinition = {} as LocaleDefinition;
+ readonly definitions: LocaleDefinition = this.initDefinitions();
seedValue?: number | number[];
@@ -98,43 +97,56 @@ export class Faker {
this.locales = opts.locales;
this.locale = opts.locale || 'en';
this.localeFallback = opts.localeFallback || 'en';
-
- this.loadDefinitions();
}
/**
- * Load the definitions contained in the locales file for the given types.
- *
- * Background: Certain localization sets contain less data then others.
- * In the case of a missing definition, use the localeFallback's values
- * to substitute the missing data.
+ * Creates a Proxy based LocaleDefinition that virtually merges the locales.
*/
- private loadDefinitions(): void {
- // TODO @Shinigami92 2022-01-11: Find a way to load this even more dynamically
- // In a way so that we don't accidentally miss a definition
- for (const [moduleName, entryNames] of Object.entries(DEFINITIONS)) {
- if (typeof entryNames === 'string') {
- // For 'title' and 'separator'
- Object.defineProperty(this.definitions, moduleName, {
- get: (): unknown /* string */ =>
- this.locales[this.locale][moduleName] ??
- this.locales[this.localeFallback][moduleName],
- });
- continue;
- }
-
- if (this.definitions[moduleName] == null) {
- this.definitions[moduleName] = {};
+ private initDefinitions(): LocaleDefinition {
+ // Returns the first LocaleDefinition[key] in any locale
+ const resolveBaseData = (key: keyof LocaleDefinition): unknown =>
+ this.locales[this.locale][key] ?? this.locales[this.localeFallback][key];
+
+ // Returns the first LocaleDefinition[module][entry] in any locale
+ const resolveModuleData = (
+ module: keyof LocaleDefinition,
+ entry: string
+ ): unknown =>
+ this.locales[this.locale][module]?.[entry] ??
+ this.locales[this.localeFallback][module]?.[entry];
+
+ // Returns a proxy that can return the entries for a module (if it exists)
+ const moduleLoader = (
+ module: keyof LocaleDefinition
+ ): Record<string, unknown> | undefined => {
+ if (resolveBaseData(module)) {
+ return new Proxy(
+ {},
+ {
+ get(target, entry: string): unknown {
+ return resolveModuleData(module, entry);
+ },
+ }
+ );
+ } else {
+ return undefined;
}
-
- for (const entryName of entryNames) {
- Object.defineProperty(this.definitions[moduleName], entryName, {
- get: (): unknown =>
- this.locales[this.locale][moduleName]?.[entryName] ??
- this.locales[this.localeFallback][moduleName]?.[entryName],
- });
- }
- }
+ };
+
+ return new Proxy({} as LocaleDefinition, {
+ get(target: LocaleDefinition, module: string): unknown {
+ let result = target[module];
+ if (result) {
+ return result;
+ } else if (DEFINITIONS[module] === 'metadata') {
+ return resolveBaseData(module);
+ } else {
+ result = moduleLoader(module);
+ target[module] = result;
+ return result;
+ }
+ },
+ });
}
seed(seed?: number | number[]): void {