diff options
| author | ST-DDT <[email protected]> | 2022-04-19 20:20:51 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-04-19 20:20:51 +0200 |
| commit | 069f4d1c08b2a314aa24a4a55b7498ff97be7c3a (patch) | |
| tree | 74aac16a2df39c0cc03c2dceb66fc8b55e978584 /src | |
| parent | d94159f155cd58ba8ebfdbf0d2dd642a418175ab (diff) | |
| download | faker-069f4d1c08b2a314aa24a4a55b7498ff97be7c3a.tar.xz faker-069f4d1c08b2a314aa24a4a55b7498ff97be7c3a.zip | |
feat: dynamic definitions tree (#822)
Diffstat (limited to 'src')
| -rw-r--r-- | src/definitions/definitions.ts | 11 | ||||
| -rw-r--r-- | src/faker.ts | 80 |
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 { |
