diff options
| author | ST-DDT <[email protected]> | 2023-04-23 18:51:27 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-04-23 18:51:27 +0200 |
| commit | 8a0bbf5faa03c294d308a13fe210ba6aaeef6968 (patch) | |
| tree | c3fc64e877992b09b0c7699201b103aac1b06071 /src/locale-proxy.ts | |
| parent | 2675ec20fe28ebf89fc8b5b939c9ae7fbde7559f (diff) | |
| download | faker-8a0bbf5faa03c294d308a13fe210ba6aaeef6968.tar.xz faker-8a0bbf5faa03c294d308a13fe210ba6aaeef6968.zip | |
feat: introduce locale proxy (#2004)
Diffstat (limited to 'src/locale-proxy.ts')
| -rw-r--r-- | src/locale-proxy.ts | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/src/locale-proxy.ts b/src/locale-proxy.ts new file mode 100644 index 00000000..c5c6aa1b --- /dev/null +++ b/src/locale-proxy.ts @@ -0,0 +1,91 @@ +import type { LocaleDefinition } from './definitions'; +import { FakerError } from './errors/faker-error'; + +/** + * A proxy for LocaleDefinitions that marks all properties as required and throws an error when an entry is accessed that is not defined. + */ +export type LocaleProxy = Readonly<{ + [key in keyof LocaleDefinition]-?: Readonly< + Required<NonNullable<LocaleDefinition[key]>> + >; +}>; + +const throwReadOnlyError: () => never = () => { + throw new FakerError('You cannot edit the locale data on the faker instance'); +}; + +/** + * Creates a proxy for LocaleDefinition that throws an error if an undefined property is accessed. + * + * @param locale The locale definition to create the proxy for. + */ +export function createLocaleProxy(locale: LocaleDefinition): LocaleProxy { + const proxies = {} as LocaleDefinition; + return new Proxy(locale, { + has(): true { + // Categories are always present (proxied), that's why we return true. + return true; + }, + + get( + target: LocaleDefinition, + categoryName: keyof LocaleDefinition + ): LocaleDefinition[keyof LocaleDefinition] { + if (categoryName in proxies) { + return proxies[categoryName]; + } + + return (proxies[categoryName] = createCategoryProxy( + categoryName, + target[categoryName] + )); + }, + + set: throwReadOnlyError, + deleteProperty: throwReadOnlyError, + }) as LocaleProxy; +} + +/** + * Creates a proxy for a category that throws an error when accessing an undefined property. + * + * @param categoryName The name of the category. + * @param categoryData The module to create the proxy for. + */ +function createCategoryProxy< + CategoryData extends Record<string | symbol, unknown> +>( + categoryName: string, + categoryData: CategoryData = {} as CategoryData +): Required<CategoryData> { + return new Proxy(categoryData, { + has(target: CategoryData, entryName: keyof CategoryData): boolean { + const value = target[entryName]; + return value != null; + }, + + get( + target: CategoryData, + entryName: keyof CategoryData + ): CategoryData[keyof CategoryData] { + const value = target[entryName]; + if (value === null) { + throw new FakerError( + `The locale data for '${categoryName}.${entryName.toString()}' aren't applicable to this locale. + If you think this is a bug, please report it at: https://github.com/faker-js/faker` + ); + } else if (value === undefined) { + throw new FakerError( + `The locale data for '${categoryName}.${entryName.toString()}' are missing in this locale. + Please contribute the missing data to the project or use a locale/Faker instance that has these data. + For more information see https://next.fakerjs.dev/guide/localization.html` + ); + } else { + return value; + } + }, + + set: throwReadOnlyError, + deleteProperty: throwReadOnlyError, + }) as Required<CategoryData>; +} |
