aboutsummaryrefslogtreecommitdiff
path: root/src/internal
diff options
context:
space:
mode:
authorDivisionByZero <[email protected]>2024-09-26 17:50:05 +0200
committerGitHub <[email protected]>2024-09-26 17:50:05 +0200
commit9537dfddba882bd93d9a429697fd44bc72428426 (patch)
treef60b5b694d5e4e8ddab228aeb20c7b7746685edc /src/internal
parent424b120a4d94b15b6e77c04a0aaffd0016a9c870 (diff)
downloadfaker-9537dfddba882bd93d9a429697fd44bc72428426.tar.xz
faker-9537dfddba882bd93d9a429697fd44bc72428426.zip
infra: update file structure for util/internal (#3141)
Diffstat (limited to 'src/internal')
-rw-r--r--src/internal/locale-proxy.ts115
-rw-r--r--src/internal/mersenne.ts48
-rw-r--r--src/internal/types.ts39
3 files changed, 154 insertions, 48 deletions
diff --git a/src/internal/locale-proxy.ts b/src/internal/locale-proxy.ts
new file mode 100644
index 00000000..dbb9f277
--- /dev/null
+++ b/src/internal/locale-proxy.ts
@@ -0,0 +1,115 @@
+import type { LocaleDefinition } from '../definitions';
+import { FakerError } from '../errors/faker-error';
+
+/**
+ * A proxy for LocaleDefinition 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]-?: LocaleProxyCategory<LocaleDefinition[key]>;
+}>;
+
+type LocaleProxyCategory<T> = Readonly<{
+ [key in keyof T]-?: LocaleProxyEntry<T[key]>;
+}>;
+
+type LocaleProxyEntry<T> = unknown extends T ? T : Readonly<NonNullable<T>>;
+
+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 (typeof categoryName === 'symbol' || categoryName === 'nodeType') {
+ return target[categoryName];
+ }
+
+ if (categoryName in proxies) {
+ return proxies[categoryName];
+ }
+
+ return (proxies[categoryName] = createCategoryProxy(
+ categoryName,
+ target[categoryName]
+ ));
+ },
+
+ set: throwReadOnlyError,
+ deleteProperty: throwReadOnlyError,
+ }) as LocaleProxy;
+}
+
+/**
+ * Checks that the value is not null or undefined and throws an error if it is.
+ *
+ * @param value The value to check.
+ * @param path The path to the locale data.
+ */
+export function assertLocaleData<T>(
+ value: T,
+ ...path: string[]
+): asserts value is NonNullable<T> {
+ if (value === null) {
+ throw new FakerError(
+ `The locale data for '${path.join('.')}' 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 '${path.join('.')}' 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://fakerjs.dev/guide/localization.html`
+ );
+ }
+}
+
+/**
+ * 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<
+ TCategoryData extends Record<string | symbol, unknown>,
+>(
+ categoryName: string,
+ categoryData: TCategoryData = {} as TCategoryData
+): Required<TCategoryData> {
+ return new Proxy(categoryData, {
+ has(target: TCategoryData, entryName: keyof TCategoryData): boolean {
+ const value = target[entryName];
+ return value != null;
+ },
+
+ get(
+ target: TCategoryData,
+ entryName: keyof TCategoryData
+ ): TCategoryData[keyof TCategoryData] {
+ const value = target[entryName];
+ if (typeof entryName === 'symbol' || entryName === 'nodeType') {
+ return value;
+ }
+
+ assertLocaleData(value, categoryName, entryName.toString());
+ return value;
+ },
+
+ set: throwReadOnlyError,
+ deleteProperty: throwReadOnlyError,
+ }) as Required<TCategoryData>;
+}
diff --git a/src/internal/mersenne.ts b/src/internal/mersenne.ts
index d01b5ee9..351faa4e 100644
--- a/src/internal/mersenne.ts
+++ b/src/internal/mersenne.ts
@@ -1,5 +1,3 @@
-import type { Randomizer } from '../randomizer';
-
/**
* Copyright (c) 2022-2023 Faker
*
@@ -325,49 +323,3 @@ export class MersenneTwister19937 {
}
// These real versions are due to Isaku Wada, 2002/01/09
}
-
-/**
- * Generates a MersenneTwister19937 randomizer with 32 bits of precision.
- * This is the default randomizer used by faker prior to v9.0.
- */
-export function generateMersenne32Randomizer(): Randomizer {
- const twister = new MersenneTwister19937();
-
- twister.initGenrand(Math.ceil(Math.random() * Number.MAX_SAFE_INTEGER));
-
- return {
- next(): number {
- return twister.genrandReal2();
- },
- seed(seed: number | number[]): void {
- if (typeof seed === 'number') {
- twister.initGenrand(seed);
- } else if (Array.isArray(seed)) {
- twister.initByArray(seed, seed.length);
- }
- },
- };
-}
-
-/**
- * Generates a MersenneTwister19937 randomizer with 53 bits of precision.
- * This is the default randomizer used by faker starting with v9.0.
- */
-export function generateMersenne53Randomizer(): Randomizer {
- const twister = new MersenneTwister19937();
-
- twister.initGenrand(Math.ceil(Math.random() * Number.MAX_SAFE_INTEGER));
-
- return {
- next(): number {
- return twister.genrandRes53();
- },
- seed(seed: number | number[]): void {
- if (typeof seed === 'number') {
- twister.initGenrand(seed);
- } else if (Array.isArray(seed)) {
- twister.initByArray(seed, seed.length);
- }
- },
- };
-}
diff --git a/src/internal/types.ts b/src/internal/types.ts
new file mode 100644
index 00000000..affdda7e
--- /dev/null
+++ b/src/internal/types.ts
@@ -0,0 +1,39 @@
+/**
+ * Type that provides auto-suggestions but also any string.
+ *
+ * @see https://github.com/microsoft/TypeScript/issues/29729#issuecomment-471566609
+ */
+export type LiteralUnion<TSuggested extends TBase, TBase = string> =
+ | TSuggested
+ | (TBase & { zz_IGNORE_ME?: never });
+
+/**
+ * A function that returns a value.
+ *
+ * `Function` cannot be used instead because it doesn't accept class declarations.
+ * These would fail when invoked since they are invoked without the `new` keyword.
+ */
+export type Callable = (
+ // TODO @Shinigami92 2023-02-14: This `any` type can be fixed by anyone if they want to.
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ ...args: any[]
+) => unknown;
+
+/**
+ * Type that represents a single method/function name of the given type.
+ */
+export type MethodOf<TObjectType, TSignature extends Callable = Callable> = {
+ [Key in keyof TObjectType]: TObjectType[Key] extends TSignature
+ ? Key extends string
+ ? Key
+ : never
+ : never;
+}[keyof TObjectType];
+
+/**
+ * Type that represents all method/function names of the given type.
+ */
+export type MethodsOf<
+ TObjectType,
+ TSignature extends Callable = Callable,
+> = ReadonlyArray<MethodOf<TObjectType, TSignature>>;