aboutsummaryrefslogtreecommitdiff
path: root/src/locale-proxy.ts
diff options
context:
space:
mode:
authorST-DDT <[email protected]>2023-04-23 18:51:27 +0200
committerGitHub <[email protected]>2023-04-23 18:51:27 +0200
commit8a0bbf5faa03c294d308a13fe210ba6aaeef6968 (patch)
treec3fc64e877992b09b0c7699201b103aac1b06071 /src/locale-proxy.ts
parent2675ec20fe28ebf89fc8b5b939c9ae7fbde7559f (diff)
downloadfaker-8a0bbf5faa03c294d308a13fe210ba6aaeef6968.tar.xz
faker-8a0bbf5faa03c294d308a13fe210ba6aaeef6968.zip
feat: introduce locale proxy (#2004)
Diffstat (limited to 'src/locale-proxy.ts')
-rw-r--r--src/locale-proxy.ts91
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>;
+}