11import type { LocaleDefinition } from '../definitions' ;
22import { FakerError } from '../errors/faker-error' ;
33
4+ const LOCALE_PROXY_TAG = Symbol ( 'FakerLocaleProxy' ) ;
5+
46/**
57 * A proxy for LocaleDefinition that marks all properties as required and throws an error when an entry is accessed that is not defined.
68 */
7- export type LocaleProxy = Readonly < {
8- [ key in keyof LocaleDefinition ] -?: LocaleProxyCategory < LocaleDefinition [ key ] > ;
9- } > ;
9+ export type LocaleProxy = Readonly <
10+ {
11+ [ key in keyof LocaleDefinition ] -?: LocaleProxyCategory <
12+ LocaleDefinition [ key ]
13+ > ;
14+ } & {
15+ /**
16+ * The raw locale definition used to create this proxy.
17+ * This can be useful to check if a category/entry exists without triggering the proxy's error.
18+ */
19+ raw : LocaleDefinition ;
20+ /**
21+ * Marker to identify a `LocaleProxy`.
22+ */
23+ [ LOCALE_PROXY_TAG ] : true ;
24+ }
25+ > ;
1026
1127type LocaleProxyCategory < T > = Readonly < {
1228 [ key in keyof T ] -?: LocaleProxyEntry < T [ key ] > ;
@@ -18,13 +34,35 @@ const throwReadOnlyError: () => never = () => {
1834 throw new FakerError ( 'You cannot edit the locale data on the faker instance' ) ;
1935} ;
2036
37+ /**
38+ * Checks if the given value is a LocaleProxy.
39+ *
40+ * @param value The value to check.
41+ *
42+ * @returns True if the value is a LocaleProxy, false otherwise.
43+ */
44+ function isLocaleProxy ( value : unknown ) : value is LocaleProxy {
45+ return (
46+ value != null &&
47+ typeof value === 'object' &&
48+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
49+ ( value as any ) ?. [ LOCALE_PROXY_TAG ] === true
50+ ) ;
51+ }
52+
2153/**
2254 * Creates a proxy for LocaleDefinition that throws an error if an undefined property is accessed.
2355 *
2456 * @param locale The locale definition to create the proxy for.
2557 */
26- export function createLocaleProxy ( locale : LocaleDefinition ) : LocaleProxy {
27- const proxies = { } as LocaleDefinition ;
58+ export function createLocaleProxy (
59+ locale : LocaleDefinition | LocaleProxy
60+ ) : LocaleProxy {
61+ if ( isLocaleProxy ( locale ) ) {
62+ return locale ;
63+ }
64+
65+ const proxies = { raw : locale } as LocaleDefinition ;
2866 return new Proxy ( locale , {
2967 has ( ) : true {
3068 // Categories are always present (proxied), that's why we return true.
@@ -33,25 +71,29 @@ export function createLocaleProxy(locale: LocaleDefinition): LocaleProxy {
3371
3472 get (
3573 target : LocaleDefinition ,
36- categoryName : keyof LocaleDefinition
37- ) : LocaleDefinition [ keyof LocaleDefinition ] {
38- if ( typeof categoryName === 'symbol' || categoryName === 'nodeType' ) {
74+ categoryName : keyof LocaleProxy
75+ ) : LocaleProxy [ keyof LocaleProxy ] {
76+ if ( typeof categoryName === 'symbol' ) {
77+ if ( categoryName === LOCALE_PROXY_TAG ) {
78+ return true ;
79+ }
80+
3981 return target [ categoryName ] ;
4082 }
4183
42- if ( categoryName in proxies ) {
43- return proxies [ categoryName ] ;
84+ if ( categoryName === 'nodeType' ) {
85+ return target [ categoryName ] ;
4486 }
4587
46- return ( proxies [ categoryName ] = createCategoryProxy (
88+ return ( proxies [ categoryName ] ?? = createCategoryProxy (
4789 categoryName ,
4890 target [ categoryName ]
4991 ) ) ;
5092 } ,
5193
5294 set : throwReadOnlyError ,
5395 deleteProperty : throwReadOnlyError ,
54- } ) as LocaleProxy ;
96+ } ) as unknown as LocaleProxy ;
5597}
5698
5799/**
0 commit comments