diff --git a/package.json b/package.json index 769e2bd9f84..77aa4d4c5f9 100644 --- a/package.json +++ b/package.json @@ -143,5 +143,8 @@ "engines": { "node": ">=12.22.0" }, - "packageManager": "pnpm@7.18.0" + "packageManager": "pnpm@7.18.0", + "dependencies": { + "@hookform/core": "0.0.2" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7e4bcea089e..265485c0137 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,6 +1,7 @@ lockfileVersion: 5.4 specifiers: + '@hookform/core': 0.0.2 '@microsoft/api-extractor': ^7.33.7 '@rollup/plugin-commonjs': ^22.0.2 '@rollup/plugin-node-resolve': ^14.1.0 @@ -43,6 +44,9 @@ specifiers: tsd: ^0.25.0 typescript: ^4.9.4 +dependencies: + '@hookform/core': 0.0.2 + devDependencies: '@microsoft/api-extractor': 7.33.7 '@rollup/plugin-commonjs': 22.0.2_rollup@2.79.1 @@ -496,6 +500,10 @@ packages: - supports-color dev: true + /@hookform/core/0.0.2: + resolution: {integrity: sha512-MZlFb5J1tA0a1mdTNYehJ4BdVY0ny0cwiyyKg+JHfSWUTdPUwiDDMg4RAt+khRlBWCzfVrvorjbeGgGRSQdkeQ==} + dev: false + /@humanwhocodes/config-array/0.11.8: resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==} engines: {node: '>=10.10.0'} @@ -2316,6 +2324,7 @@ packages: /commander/9.5.0: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} + requiresBuild: true dev: true optional: true diff --git a/reports/api-extractor.md b/reports/api-extractor.md index 6a9900b60cd..33a2676bfef 100644 --- a/reports/api-extractor.md +++ b/reports/api-extractor.md @@ -6,710 +6,447 @@ /// +import { appendErrors } from '@hookform/core'; +import { ArrayKey } from '@hookform/core'; +import { ArrayPath } from '@hookform/core'; +import { AsKey } from '@hookform/core'; +import { AsPathTuple } from '@hookform/core'; +import { BatchFieldArrayUpdate } from '@hookform/core'; +import { BrowserNativeObject } from '@hookform/core'; +import { ChangeHandler } from '@hookform/core'; +import { CheckKeyConstraint } from '@hookform/core'; +import { ContainsIndexable } from '@hookform/core'; +import { Control } from '@hookform/core'; +import { ControllerFieldState } from '@hookform/core'; +import { ControllerProps } from '@hookform/core'; +import { ControllerRenderProps } from '@hookform/core'; +import { CriteriaMode } from '@hookform/core'; +import { CustomElement } from '@hookform/core'; +import { DeepMap } from '@hookform/core'; +import { DeepPartial } from '@hookform/core'; +import { DeepPartialSkipArrayKey } from '@hookform/core'; +import { DeepRequired } from '@hookform/core'; +import { DefaultValues } from '@hookform/core'; +import { DelayCallback } from '@hookform/core'; +import { EmptyObject } from '@hookform/core'; +import { ErrorOption } from '@hookform/core'; +import { EvaluateKey } from '@hookform/core'; +import { EvaluatePath } from '@hookform/core'; +import { EventType } from '@hookform/core'; +import { Field } from '@hookform/core'; +import { FieldArray } from '@hookform/core'; +import { FieldArrayMethodProps } from '@hookform/core'; +import { FieldArrayPath } from '@hookform/core'; +import { FieldArrayPathValue } from '@hookform/core'; +import { FieldArrayWithId } from '@hookform/core'; +import { FieldElement } from '@hookform/core'; +import { FieldError } from '@hookform/core'; +import { FieldErrors } from '@hookform/core'; +import { FieldErrorsImpl } from '@hookform/core'; +import { FieldName } from '@hookform/core'; +import { FieldNamesMarkedBoolean } from '@hookform/core'; +import { FieldPath } from '@hookform/core'; +import { FieldPathByValue } from '@hookform/core'; +import { FieldPathValue } from '@hookform/core'; +import { FieldPathValues } from '@hookform/core'; +import { FieldRefs } from '@hookform/core'; +import { FieldValue } from '@hookform/core'; +import { FieldValues } from '@hookform/core'; +import { FormProviderProps } from '@hookform/core'; +import { FormState } from '@hookform/core'; +import { FormStateProxy } from '@hookform/core'; +import { FormStateSubjectRef } from '@hookform/core'; +import { get } from '@hookform/core'; +import { GetIsDirty } from '@hookform/core'; +import { GlobalError } from '@hookform/core'; +import { HasKey } from '@hookform/core'; +import { HasPath } from '@hookform/core'; +import { InternalFieldErrors } from '@hookform/core'; +import { InternalFieldName } from '@hookform/core'; +import { InternalNameSet } from '@hookform/core'; +import { IsAny } from '@hookform/core'; +import { IsEqual } from '@hookform/core'; +import { IsFlatObject } from '@hookform/core'; +import { IsNever } from '@hookform/core'; +import { IsTuple } from '@hookform/core'; +import { JoinPathTuple } from '@hookform/core'; import { JSXElementConstructor } from 'react'; -import { default as React_2 } from 'react'; +import { KeepStateOptions } from '@hookform/core'; +import { Key } from '@hookform/core'; +import { Keys } from '@hookform/core'; +import { LiteralUnion } from '@hookform/core'; +import { Merge } from '@hookform/core'; +import { Message } from '@hookform/core'; +import { Mode } from '@hookform/core'; +import { MultipleFieldErrors } from '@hookform/core'; +import { Names } from '@hookform/core'; +import { NativeFieldValue } from '@hookform/core'; +import { NestedValue } from '@hookform/core'; +import { NonUndefined } from '@hookform/core'; +import { Noop } from '@hookform/core'; +import { NumericKeys } from '@hookform/core'; +import { ObjectKeys } from '@hookform/core'; +import { Path } from '@hookform/core'; +import { PathString } from '@hookform/core'; +import { PathTuple } from '@hookform/core'; +import { PathValue } from '@hookform/core'; +import { Primitive } from '@hookform/core'; import { ReactElement } from 'react'; - -// @public (undocumented) -export const appendErrors: (name: InternalFieldName, validateAllFieldCriteria: boolean, errors: InternalFieldErrors, type: string, message: ValidateResult) => {}; - -// Warning: (ae-forgotten-export) The symbol "ArrayPathInternal" needs to be exported by the entry point index.d.ts -// -// @public -export type ArrayPath = T extends any ? ArrayPathInternal : never; - -// @public (undocumented) -export type BatchFieldArrayUpdate = = FieldArrayPath>(name: InternalFieldName, updatedFieldArrayValues?: Partial>[], method?: T, args?: Partial<{ - argA: unknown; - argB: unknown; -}>, shouldSetValue?: boolean, shouldUpdateFieldsAndErrors?: boolean) => void; - -// Warning: (ae-forgotten-export) The symbol "FileList_2" needs to be exported by the entry point index.d.ts -// Warning: (ae-forgotten-export) The symbol "File_2" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export type BrowserNativeObject = Date | FileList_2 | File_2; - -// @public (undocumented) -export type ChangeHandler = (event: { - target: any; - type?: any; -}) => Promise; - -// @public (undocumented) -export type Control = { - _subjects: Subjects; - _removeUnmounted: Noop; - _focusError: Noop; - _names: Names; - _stateFlags: { - mount: boolean; - action: boolean; - watch: boolean; - }; - _reset: UseFormReset; - _options: UseFormProps; - _getDirty: GetIsDirty; - _formState: FormState; - _updateValid: (shouldUpdateValid?: boolean) => void; - _updateFormState: (formState: Partial>) => void; - _fields: FieldRefs; - _formValues: FieldValues; - _proxyFormState: ReadFormState; - _defaultValues: Partial>; - _getWatch: WatchInternal; - _updateFieldArray: BatchFieldArrayUpdate; - _getFieldArray: (name: InternalFieldName) => Partial[]; - _executeSchema: (names: InternalFieldName[]) => Promise<{ - errors: FieldErrors; - }>; - register: UseFormRegister; - unregister: UseFormUnregister; - getFieldState: UseFormGetFieldState; -}; +import { ReadFormState } from '@hookform/core'; +import { Ref } from '@hookform/core'; +import { RefCallBack } from '@hookform/core'; +import { RegisterOptions } from '@hookform/core'; +import { Resolver } from '@hookform/core'; +import { ResolverError } from '@hookform/core'; +import { ResolverOptions } from '@hookform/core'; +import { ResolverResult } from '@hookform/core'; +import { ResolverSuccess } from '@hookform/core'; +import { set } from '@hookform/core'; +import { SetFieldValue } from '@hookform/core'; +import { SetFocusOptions } from '@hookform/core'; +import { SetValueConfig } from '@hookform/core'; +import { SplitPathString } from '@hookform/core'; +import { Subjects } from '@hookform/core'; +import { SubmitErrorHandler } from '@hookform/core'; +import { SubmitHandler } from '@hookform/core'; +import { ToKey } from '@hookform/core'; +import { Traversable } from '@hookform/core'; +import { TriggerConfig } from '@hookform/core'; +import { TupleKeys } from '@hookform/core'; +import { UnionToIntersection } from '@hookform/core'; +import { UseControllerProps } from '@hookform/core'; +import { UseControllerReturn } from '@hookform/core'; +import { UseFieldArrayAppend } from '@hookform/core'; +import { UseFieldArrayInsert } from '@hookform/core'; +import { UseFieldArrayMove } from '@hookform/core'; +import { UseFieldArrayPrepend } from '@hookform/core'; +import { UseFieldArrayProps } from '@hookform/core'; +import { UseFieldArrayRemove } from '@hookform/core'; +import { UseFieldArrayReplace } from '@hookform/core'; +import { UseFieldArrayReturn } from '@hookform/core'; +import { UseFieldArraySwap } from '@hookform/core'; +import { UseFieldArrayUpdate } from '@hookform/core'; +import { UseFormClearErrors } from '@hookform/core'; +import { UseFormGetFieldState } from '@hookform/core'; +import { UseFormGetValues } from '@hookform/core'; +import { UseFormHandleSubmit } from '@hookform/core'; +import { UseFormProps } from '@hookform/core'; +import { UseFormRegister } from '@hookform/core'; +import { UseFormRegisterReturn } from '@hookform/core'; +import { UseFormReset } from '@hookform/core'; +import { UseFormResetField } from '@hookform/core'; +import { UseFormReturn } from '@hookform/core'; +import { UseFormSetError } from '@hookform/core'; +import { UseFormSetFocus } from '@hookform/core'; +import { UseFormSetValue } from '@hookform/core'; +import { UseFormStateProps } from '@hookform/core'; +import { UseFormStateReturn } from '@hookform/core'; +import { UseFormTrigger } from '@hookform/core'; +import { UseFormUnregister } from '@hookform/core'; +import { UseFormWatch } from '@hookform/core'; +import { UseWatchProps } from '@hookform/core'; +import { Validate } from '@hookform/core'; +import { ValidateResult } from '@hookform/core'; +import { ValidationMode } from '@hookform/core'; +import { ValidationRule } from '@hookform/core'; +import { ValidationValue } from '@hookform/core'; +import { ValidationValueMessage } from '@hookform/core'; +import { ValidPathPrefix } from '@hookform/core'; +import { WatchInternal } from '@hookform/core'; +import { WatchObserver } from '@hookform/core'; + +export { appendErrors } + +export { ArrayKey } + +export { ArrayPath } + +export { AsKey } + +export { AsPathTuple } + +export { BatchFieldArrayUpdate } + +export { BrowserNativeObject } + +export { ChangeHandler } + +export { CheckKeyConstraint } + +export { ContainsIndexable } + +export { Control } // @public export const Controller: = Path>(props: ControllerProps) => ReactElement>; -// @public (undocumented) -export type ControllerFieldState = { - invalid: boolean; - isTouched: boolean; - isDirty: boolean; - error?: FieldError; -}; +export { ControllerFieldState } -// @public -export type ControllerProps = FieldPath> = { - render: ({ field, fieldState, formState, }: { - field: ControllerRenderProps; - fieldState: ControllerFieldState; - formState: UseFormStateReturn; - }) => React_2.ReactElement; -} & UseControllerProps; - -// @public (undocumented) -export type ControllerRenderProps = FieldPath> = { - onChange: (...event: any[]) => void; - onBlur: Noop; - value: FieldPathValue; - name: TName; - ref: RefCallBack; -}; - -// @public (undocumented) -export type CriteriaMode = 'firstError' | 'all'; - -// @public (undocumented) -export type CustomElement = { - name: FieldName; - type?: string; - value?: any; - disabled?: boolean; - checked?: boolean; - options?: HTMLOptionsCollection; - files?: FileList | null; - focus?: Noop; -}; - -// @public (undocumented) -export type DeepMap = IsAny extends true ? any : T extends BrowserNativeObject | NestedValue ? TValue : T extends object ? { - [K in keyof T]: DeepMap, TValue>; -} : TValue; - -// @public (undocumented) -export type DeepPartial = T extends BrowserNativeObject | NestedValue ? T : { - [K in keyof T]?: DeepPartial; -}; - -// @public (undocumented) -export type DeepPartialSkipArrayKey = T extends BrowserNativeObject | NestedValue ? T : T extends ReadonlyArray ? { - [K in keyof T]: DeepPartialSkipArrayKey; -} : { - [K in keyof T]?: DeepPartialSkipArrayKey; -}; - -// @public (undocumented) -export type DeepRequired = T extends BrowserNativeObject | Blob ? T : { - [K in keyof T]-?: NonNullable>; -}; - -// @public (undocumented) -export type DefaultValues = DeepPartial; - -// @public (undocumented) -export type DelayCallback = (wait: number) => void; - -// @public (undocumented) -export type EmptyObject = { - [K in string | number]: never; -}; - -// @public (undocumented) -export type ErrorOption = { - message?: Message; - type?: LiteralUnion; - types?: MultipleFieldErrors; -}; - -// @public (undocumented) -export type EventType = 'focus' | 'blur' | 'change' | 'changeText' | 'valueChange' | 'contentSizeChange' | 'endEditing' | 'keyPress' | 'submitEditing' | 'layout' | 'selectionChange' | 'longPress' | 'press' | 'pressIn' | 'pressOut' | 'momentumScrollBegin' | 'momentumScrollEnd' | 'scroll' | 'scrollBeginDrag' | 'scrollEndDrag' | 'load' | 'error' | 'progress' | 'custom'; - -// @public (undocumented) -export type Field = { - _f: { - ref: Ref; - name: InternalFieldName; - refs?: HTMLInputElement[]; - mount?: boolean; - } & RegisterOptions; -}; - -// @public (undocumented) -export type FieldArray = FieldArrayPath> = FieldArrayPathValue extends ReadonlyArray | null | undefined ? U : never; +export { ControllerProps } -// @public -export type FieldArrayMethodProps = { - shouldFocus?: boolean; - focusIndex?: number; - focusName?: string; -}; +export { ControllerRenderProps } -// @public -export type FieldArrayPath = ArrayPath; +export { CriteriaMode } -// @public -export type FieldArrayPathValue> = PathValue; +export { CustomElement } -// @public -export type FieldArrayWithId = FieldArrayPath, TKeyName extends string = 'id'> = FieldArray & Record; +export { DeepMap } -// @public (undocumented) -export type FieldElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | CustomElement; +export { DeepPartial } -// @public (undocumented) -export type FieldError = { - type: LiteralUnion; - root?: FieldError; - ref?: Ref; - types?: MultipleFieldErrors; - message?: Message; -}; +export { DeepPartialSkipArrayKey } -// @public (undocumented) -export type FieldErrors = Partial ? any : FieldErrorsImpl>> & { - root?: Record & GlobalError; -}; +export { DeepRequired } -// @public (undocumented) -export type FieldErrorsImpl = { - [K in keyof T]?: T[K] extends BrowserNativeObject | Blob ? FieldError : K extends 'root' | `root.${string}` ? GlobalError : T[K] extends object ? Merge> : FieldError; -}; +export { DefaultValues } -// @public (undocumented) -export type FieldName = IsFlatObject extends true ? Extract : string; +export { DelayCallback } -// @public (undocumented) -export type FieldNamesMarkedBoolean = DeepMap, boolean>; +export { EmptyObject } -// @public -export type FieldPath = Path; +export { ErrorOption } -// @public -export type FieldPathByValue = { - [Key in FieldPath]: FieldPathValue extends TValue ? Key : never; -}[FieldPath]; +export { EvaluateKey } -// @public -export type FieldPathValue> = PathValue; +export { EvaluatePath } -// @public -export type FieldPathValues[] | readonly FieldPath[]> = {} & { - [K in keyof TPath]: FieldPathValue>; -}; +export { EventType } + +export { Field } + +export { FieldArray } + +export { FieldArrayMethodProps } + +export { FieldArrayPath } -// @public (undocumented) -export type FieldRefs = Partial>; +export { FieldArrayPathValue } -// @public (undocumented) -export type FieldValue = TFieldValues[InternalFieldName]; +export { FieldArrayWithId } -// @public (undocumented) -export type FieldValues = Record; +export { FieldElement } + +export { FieldError } + +export { FieldErrors } + +export { FieldErrorsImpl } + +export { FieldName } + +export { FieldNamesMarkedBoolean } + +export { FieldPath } + +export { FieldPathByValue } + +export { FieldPathValue } + +export { FieldPathValues } + +export { FieldRefs } + +export { FieldValue } + +export { FieldValues } // @public export const FormProvider: (props: FormProviderProps) => JSX.Element; -// @public (undocumented) -export type FormProviderProps = { - children: React_2.ReactNode | React_2.ReactNode[]; -} & UseFormReturn; - -// @public (undocumented) -export type FormState = { - isDirty: boolean; - isLoading: boolean; - isSubmitted: boolean; - isSubmitSuccessful: boolean; - isSubmitting: boolean; - isValidating: boolean; - isValid: boolean; - submitCount: number; - defaultValues?: undefined | Readonly>; - dirtyFields: Partial>>; - touchedFields: Partial>>; - errors: FieldErrors; -}; - -// @public (undocumented) -export type FormStateProxy = { - isDirty: boolean; - isValidating: boolean; - dirtyFields: FieldNamesMarkedBoolean; - touchedFields: FieldNamesMarkedBoolean; - errors: boolean; - isValid: boolean; -}; - -// Warning: (ae-forgotten-export) The symbol "Subject" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export type FormStateSubjectRef = Subject> & { - name?: InternalFieldName; -}>; - -// @public (undocumented) -export const get: (obj: T, path: string, defaultValue?: unknown) => any; - -// @public (undocumented) -export type GetIsDirty = (name?: TName, data?: TData) => boolean; - -// @public (undocumented) -export type GlobalError = Partial<{ - type: string | number; - message: string; -}>; - -// @public (undocumented) -export type InternalFieldErrors = Partial>; - -// @public (undocumented) -export type InternalFieldName = string; - -// @public (undocumented) -export type InternalNameSet = Set; +export { FormProviderProps } -// @public -export type IsAny = 0 extends 1 & T ? true : false; +export { FormState } -// @public -export type IsEqual = T1 extends T2 ? (() => G extends T1 ? 1 : 2) extends () => G extends T2 ? 1 : 2 ? true : false : false; +export { FormStateProxy } -// @public (undocumented) -export type IsFlatObject = Extract, any[] | object> extends never ? true : false; +export { FormStateSubjectRef } -// @public -export type IsNever = [T] extends [never] ? true : false; - -// @public (undocumented) -export type KeepStateOptions = Partial<{ - keepDirtyValues: boolean; - keepErrors: boolean; - keepDirty: boolean; - keepValues: boolean; - keepDefaultValues: boolean; - keepIsSubmitted: boolean; - keepTouched: boolean; - keepIsValid: boolean; - keepSubmitCount: boolean; -}>; - -// @public (undocumented) -export type LiteralUnion = T | (U & { - _?: never; -}); - -// @public (undocumented) -export type Merge = { - [K in keyof A | keyof B]?: K extends keyof A & keyof B ? [A[K], B[K]] extends [object, object] ? Merge : A[K] | B[K] : K extends keyof A ? A[K] : K extends keyof B ? B[K] : never; -}; - -// @public (undocumented) -export type Message = string; - -// @public (undocumented) -export type Mode = keyof ValidationMode; - -// @public (undocumented) -export type MultipleFieldErrors = { - [K in keyof RegisterOptions]?: ValidateResult; -} & { - [key: string]: ValidateResult; -}; - -// @public (undocumented) -export type Names = { - mount: InternalNameSet; - unMount: InternalNameSet; - array: InternalNameSet; - watch: InternalNameSet; - focus?: InternalFieldName; - watchAll?: boolean; -}; - -// @public (undocumented) -export type NativeFieldValue = string | number | boolean | null | undefined | unknown[]; - -// @public @deprecated (undocumented) -export type NestedValue = { - [$NestedValue]: never; -} & TValue; - -// @public (undocumented) -export type NonUndefined = T extends undefined ? never : T; - -// @public (undocumented) -export type Noop = () => void; - -// Warning: (ae-forgotten-export) The symbol "PathInternal" needs to be exported by the entry point index.d.ts -// -// @public -export type Path = T extends any ? PathInternal : never; +export { get } -// @public -export type PathString = string; +export { GetIsDirty } -// Warning: (ae-forgotten-export) The symbol "ArrayKey" needs to be exported by the entry point index.d.ts -// -// @public -export type PathValue | ArrayPath> = T extends any ? P extends `${infer K}.${infer R}` ? K extends keyof T ? R extends Path ? PathValue : never : K extends `${ArrayKey}` ? T extends ReadonlyArray ? PathValue> : never : never : P extends keyof T ? T[P] : P extends `${ArrayKey}` ? T extends ReadonlyArray ? V : never : never : never; - -// @public (undocumented) -export type Primitive = null | undefined | string | number | boolean | symbol | bigint; - -// @public (undocumented) -export type ReadFormState = { - [K in keyof FormStateProxy]: boolean | 'all'; -}; - -// @public (undocumented) -export type Ref = FieldElement; - -// @public (undocumented) -export type RefCallBack = (instance: any) => void; - -// @public (undocumented) -export type RegisterOptions = FieldPath> = Partial<{ - required: Message | ValidationRule; - min: ValidationRule; - max: ValidationRule; - maxLength: ValidationRule; - minLength: ValidationRule; - validate: Validate, TFieldValues> | Record, TFieldValues>>; - value: FieldPathValue; - setValueAs: (value: any) => any; - shouldUnregister?: boolean; - onChange?: (event: any) => void; - onBlur?: (event: any) => void; - disabled: boolean; - deps: InternalFieldName | InternalFieldName[]; -}> & ({ - pattern?: ValidationRule; - valueAsNumber?: false; - valueAsDate?: false; -} | { - pattern?: undefined; - valueAsNumber?: false; - valueAsDate?: true; -} | { - pattern?: undefined; - valueAsNumber?: true; - valueAsDate?: false; -}); - -// @public (undocumented) -export type Resolver = (values: TFieldValues, context: TContext | undefined, options: ResolverOptions) => Promise> | ResolverResult; - -// @public (undocumented) -export type ResolverError = { - values: {}; - errors: FieldErrors; -}; - -// @public (undocumented) -export interface ResolverOptions { - // (undocumented) - criteriaMode?: CriteriaMode; - // (undocumented) - fields: Record; - // (undocumented) - names?: FieldName[]; - // (undocumented) - shouldUseNativeValidation: boolean | undefined; -} - -// @public (undocumented) -export type ResolverResult = ResolverSuccess | ResolverError; - -// @public (undocumented) -export type ResolverSuccess = { - values: TFieldValues; - errors: {}; -}; - -// @public (undocumented) -export function set(object: FieldValues, path: string, value?: unknown): FieldValues; - -// @public (undocumented) -export type SetFieldValue = FieldValue; - -// @public (undocumented) -export type SetFocusOptions = Partial<{ - shouldSelect: boolean; -}>; - -// @public (undocumented) -export type SetValueConfig = Partial<{ - shouldValidate: boolean; - shouldDirty: boolean; - shouldTouch: boolean; -}>; - -// @public (undocumented) -export type Subjects = { - watch: Subject<{ - name?: InternalFieldName; - type?: EventType; - values?: FieldValues; - }>; - array: Subject<{ - name?: InternalFieldName; - values?: FieldValues; - }>; - state: FormStateSubjectRef; -}; - -// @public (undocumented) -export type SubmitErrorHandler = (errors: FieldErrors, event?: React_2.BaseSyntheticEvent) => any | Promise; - -// @public (undocumented) -export type SubmitHandler = (data: TFieldValues, event?: React_2.BaseSyntheticEvent) => any | Promise; - -// @public (undocumented) -export type TriggerConfig = Partial<{ - shouldFocus: boolean; -}>; - -// @public @deprecated (undocumented) -export type UnpackNestedValue = T extends NestedValue ? U : T extends Date | FileList | File | Blob ? T : T extends object ? { - [K in keyof T]: UnpackNestedValue; -} : T; +export { GlobalError } + +export { HasKey } + +export { HasPath } + +export { InternalFieldErrors } + +export { InternalFieldName } + +export { InternalNameSet } + +export { IsAny } + +export { IsEqual } + +export { IsFlatObject } + +export { IsNever } + +export { IsTuple } + +export { JoinPathTuple } + +export { KeepStateOptions } + +export { Key } + +export { Keys } + +export { LiteralUnion } + +export { Merge } + +export { Message } + +export { Mode } + +export { MultipleFieldErrors } + +export { Names } + +export { NativeFieldValue } + +export { NestedValue } + +export { NonUndefined } + +export { Noop } + +export { NumericKeys } + +export { ObjectKeys } + +export { Path } + +export { PathString } + +export { PathTuple } + +export { PathValue } + +export { Primitive } + +export { ReadFormState } + +export { Ref } + +export { RefCallBack } + +export { RegisterOptions } + +export { Resolver } + +export { ResolverError } + +export { ResolverOptions } + +export { ResolverResult } + +export { ResolverSuccess } + +export { set } + +export { SetFieldValue } + +export { SetFocusOptions } + +export { SetValueConfig } + +export { SplitPathString } + +export { Subjects } + +export { SubmitErrorHandler } + +export { SubmitHandler } + +export { ToKey } + +export { Traversable } + +export { TriggerConfig } + +export { TupleKeys } + +export { UnionToIntersection } // @public export function useController = FieldPath>(props: UseControllerProps): UseControllerReturn; -// @public (undocumented) -export type UseControllerProps = FieldPath> = { - name: TName; - rules?: Omit, 'valueAsNumber' | 'valueAsDate' | 'setValueAs' | 'disabled'>; - shouldUnregister?: boolean; - defaultValue?: FieldPathValue; - control?: Control; -}; +export { UseControllerProps } -// @public (undocumented) -export type UseControllerReturn = FieldPath> = { - field: ControllerRenderProps; - formState: UseFormStateReturn; - fieldState: ControllerFieldState; -}; +export { UseControllerReturn } // @public export function useFieldArray = FieldArrayPath, TKeyName extends string = 'id'>(props: UseFieldArrayProps): UseFieldArrayReturn; -// @public -export type UseFieldArrayAppend = FieldArrayPath> = (value: FieldArray | FieldArray[], options?: FieldArrayMethodProps) => void; +export { UseFieldArrayAppend } -// @public -export type UseFieldArrayInsert = FieldArrayPath> = (index: number, value: FieldArray | FieldArray[], options?: FieldArrayMethodProps) => void; +export { UseFieldArrayInsert } -// @public -export type UseFieldArrayMove = (indexA: number, indexB: number) => void; +export { UseFieldArrayMove } -// @public -export type UseFieldArrayPrepend = FieldArrayPath> = (value: FieldArray | FieldArray[], options?: FieldArrayMethodProps) => void; +export { UseFieldArrayPrepend } -// @public (undocumented) -export type UseFieldArrayProps = FieldArrayPath, TKeyName extends string = 'id'> = { - name: TFieldArrayName; - keyName?: TKeyName; - control?: Control; - rules?: { - validate?: Validate[], TFieldValues> | Record[], TFieldValues>>; - } & Pick, 'maxLength' | 'minLength' | 'required'>; - shouldUnregister?: boolean; -}; +export { UseFieldArrayProps } -// @public -export type UseFieldArrayRemove = (index?: number | number[]) => void; +export { UseFieldArrayRemove } -// @public -export type UseFieldArrayReplace = FieldArrayPath> = (value: FieldArray | FieldArray[]) => void; - -// @public (undocumented) -export type UseFieldArrayReturn = FieldArrayPath, TKeyName extends string = 'id'> = { - swap: UseFieldArraySwap; - move: UseFieldArrayMove; - prepend: UseFieldArrayPrepend; - append: UseFieldArrayAppend; - remove: UseFieldArrayRemove; - insert: UseFieldArrayInsert; - update: UseFieldArrayUpdate; - replace: UseFieldArrayReplace; - fields: FieldArrayWithId[]; -}; +export { UseFieldArrayReplace } -// @public -export type UseFieldArraySwap = (indexA: number, indexB: number) => void; +export { UseFieldArrayReturn } -// @public -export type UseFieldArrayUpdate = FieldArrayPath> = (index: number, value: FieldArray) => void; +export { UseFieldArraySwap } + +export { UseFieldArrayUpdate } // @public export function useForm(props?: UseFormProps): UseFormReturn; -// @public -export type UseFormClearErrors = (name?: FieldPath | FieldPath[] | readonly FieldPath[] | `root.${string}` | 'root') => void; +export { UseFormClearErrors } // @public export const useFormContext: () => UseFormReturn; -// @public -export type UseFormGetFieldState = >(name: TFieldName, formState?: FormState) => { - invalid: boolean; - isDirty: boolean; - isTouched: boolean; - error?: FieldError; -}; - -// @public (undocumented) -export type UseFormGetValues = { - (): TFieldValues; - >(name: TFieldName): FieldPathValue; - []>(names: readonly [...TFieldNames]): [...FieldPathValues]; -}; +export { UseFormGetFieldState } -// @public -export type UseFormHandleSubmit = (onValid: SubmitHandler, onInvalid?: SubmitErrorHandler) => (e?: React_2.BaseSyntheticEvent) => Promise; - -// @public (undocumented) -export type UseFormProps = Partial<{ - mode: Mode; - reValidateMode: Exclude; - defaultValues: DefaultValues | AsyncDefaultValues; - values: TFieldValues; - resetOptions: Parameters>[1]; - resolver: Resolver; - context: TContext; - shouldFocusError: boolean; - shouldUnregister: boolean; - shouldUseNativeValidation: boolean; - criteriaMode: CriteriaMode; - delayError: number; -}>; +export { UseFormGetValues } -// @public -export type UseFormRegister = = FieldPath>(name: TFieldName, options?: RegisterOptions) => UseFormRegisterReturn; +export { UseFormHandleSubmit } -// @public (undocumented) -export type UseFormRegisterReturn = { - onChange: ChangeHandler; - onBlur: ChangeHandler; - ref: RefCallBack; - name: TFieldName; - min?: string | number; - max?: string | number; - maxLength?: number; - minLength?: number; - pattern?: string; - required?: boolean; - disabled?: boolean; -}; +export { UseFormProps } -// Warning: (ae-forgotten-export) The symbol "ResetAction" needs to be exported by the entry point index.d.ts -// -// @public -export type UseFormReset = (values?: DefaultValues | TFieldValues | ResetAction, keepStateOptions?: KeepStateOptions) => void; +export { UseFormRegister } -// @public -export type UseFormResetField = = FieldPath>(name: TFieldName, options?: Partial<{ - keepDirty: boolean; - keepTouched: boolean; - keepError: boolean; - defaultValue: any; -}>) => void; - -// @public (undocumented) -export type UseFormReturn = { - watch: UseFormWatch; - getValues: UseFormGetValues; - getFieldState: UseFormGetFieldState; - setError: UseFormSetError; - clearErrors: UseFormClearErrors; - setValue: UseFormSetValue; - trigger: UseFormTrigger; - formState: FormState; - resetField: UseFormResetField; - reset: UseFormReset; - handleSubmit: UseFormHandleSubmit; - unregister: UseFormUnregister; - control: Control; - register: UseFormRegister; - setFocus: UseFormSetFocus; -}; +export { UseFormRegisterReturn } -// @public -export type UseFormSetError = (name: FieldPath | `root.${string}` | 'root', error: ErrorOption, options?: { - shouldFocus: boolean; -}) => void; +export { UseFormReset } -// @public -export type UseFormSetFocus = = FieldPath>(name: TFieldName, options?: SetFocusOptions) => void; +export { UseFormResetField } -// @public -export type UseFormSetValue = = FieldPath>(name: TFieldName, value: FieldPathValue, options?: SetValueConfig) => void; +export { UseFormReturn } + +export { UseFormSetError } + +export { UseFormSetFocus } + +export { UseFormSetValue } // @public export function useFormState(props?: UseFormStateProps): UseFormStateReturn; -// @public (undocumented) -export type UseFormStateProps = Partial<{ - control?: Control; - disabled?: boolean; - name?: FieldPath | FieldPath[] | readonly FieldPath[]; - exact?: boolean; -}>; +export { UseFormStateProps } -// @public (undocumented) -export type UseFormStateReturn = FormState; +export { UseFormStateReturn } -// @public -export type UseFormTrigger = (name?: FieldPath | FieldPath[] | readonly FieldPath[], options?: TriggerConfig) => Promise; +export { UseFormTrigger } -// @public -export type UseFormUnregister = (name?: FieldPath | FieldPath[] | readonly FieldPath[], options?: Omit & { - keepValue?: boolean; - keepDefaultValue?: boolean; - keepError?: boolean; -}) => void; - -// @public (undocumented) -export type UseFormWatch = { - (): TFieldValues; - []>(names: readonly [...TFieldNames], defaultValue?: DeepPartial): FieldPathValues; - >(name: TFieldName, defaultValue?: FieldPathValue): FieldPathValue; - (callback: WatchObserver, defaultValues?: DeepPartial): Subscription; -}; +export { UseFormUnregister } + +export { UseFormWatch } // @public export function useWatch(props: { @@ -740,55 +477,25 @@ export function useWatch(): DeepPartialSkipArrayKey; -// @public (undocumented) -export type UseWatchProps = { - defaultValue?: unknown; - disabled?: boolean; - name?: FieldPath | FieldPath[] | readonly FieldPath[]; - control?: Control; - exact?: boolean; -}; - -// @public (undocumented) -export type Validate = (value: TFieldValue, formValues: TFormValues) => ValidateResult | Promise; - -// @public (undocumented) -export type ValidateResult = Message | boolean | undefined; - -// @public (undocumented) -export type ValidationMode = { - onBlur: 'onBlur'; - onChange: 'onChange'; - onSubmit: 'onSubmit'; - onTouched: 'onTouched'; - all: 'all'; -}; - -// @public (undocumented) -export type ValidationRule = TValidationValue | ValidationValueMessage; - -// @public (undocumented) -export type ValidationValue = boolean | number | string | RegExp; - -// @public (undocumented) -export type ValidationValueMessage = { - value: TValidationValue; - message: Message; -}; - -// @public (undocumented) -export type WatchInternal = (fieldNames?: InternalFieldName | InternalFieldName[], defaultValue?: DeepPartial, isMounted?: boolean, isGlobal?: boolean) => FieldPathValue | FieldPathValues; - -// @public (undocumented) -export type WatchObserver = (value: DeepPartial, info: { - name?: FieldPath; - type?: EventType; -}) => void; - -// Warnings were encountered during analysis: -// -// src/types/form.ts:97:3 - (ae-forgotten-export) The symbol "AsyncDefaultValues" needs to be exported by the entry point index.d.ts -// src/types/form.ts:419:3 - (ae-forgotten-export) The symbol "Subscription" needs to be exported by the entry point index.d.ts +export { UseWatchProps } + +export { Validate } + +export { ValidateResult } + +export { ValidationMode } + +export { ValidationRule } + +export { ValidationValue } + +export { ValidationValueMessage } + +export { ValidPathPrefix } + +export { WatchInternal } + +export { WatchObserver } // (No @packageDocumentation comment for this package) diff --git a/scripts/rollup/assert-cjs-exports.cjs b/scripts/rollup/assert-cjs-exports.cjs index f56c60a33ba..4d5ba1bac7a 100644 --- a/scripts/rollup/assert-cjs-exports.cjs +++ b/scripts/rollup/assert-cjs-exports.cjs @@ -19,4 +19,10 @@ const expected = JSON.parse( ), ); -assert.deepStrictEqual(Object.keys(exported), expected); +const methods = Object.keys(exported); + +assert.equal(expected.length, Object.keys(exported).length); + +expected.forEach((name) => { + assert(!!methods.includes(name)); +}); diff --git a/scripts/rollup/assert-esm-exports.mjs b/scripts/rollup/assert-esm-exports.mjs index 70e84bd5c24..21d9c568631 100644 --- a/scripts/rollup/assert-esm-exports.mjs +++ b/scripts/rollup/assert-esm-exports.mjs @@ -10,17 +10,20 @@ import fs from 'fs'; import path from 'path'; import url from 'url'; -const __dirname = path.dirname(url.fileURLToPath(import.meta.url)) +const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); /** * A shell one-liner to update this array when neccessary (run from root of repo): * node -e "import('react-hook-form').then((mod) => console.log(JSON.stringify(Object.keys(mod), null, 2)))" > scripts/rollup/all-exports.json */ const expected = JSON.parse( - fs.readFileSync( - path.resolve(__dirname, './all-exports.json'), - 'utf-8', - ), + fs.readFileSync(path.resolve(__dirname, './all-exports.json'), 'utf-8'), ); -assert.deepStrictEqual(Object.keys(exported), expected); +const methods = Object.keys(exported); + +assert.equal(expected.length, Object.keys(exported).length); + +expected.forEach((name) => { + assert(!!methods.includes(name)); +}); diff --git a/src/__tests__/__snapshots__/useWatch.test.tsx.snap b/src/__tests__/__snapshots__/useWatch.test.tsx.snap index fe435a2cd09..d74519c93e3 100644 --- a/src/__tests__/__snapshots__/useWatch.test.tsx.snap +++ b/src/__tests__/__snapshots__/useWatch.test.tsx.snap @@ -1,66 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`useWatch fieldArray with shouldUnregister true should watch correct input update with single field array input 1`] = ` -[ - [ - { - "id": "0", - "prop": "test", - }, - { - "id": "1", - "prop": "test1", - }, - ], - [ - { - "prop": "test", - }, - { - "prop": "test1", - }, - ], - [ - { - "prop": "test", - }, - { - "prop": "test1", - }, - ], - [ - { - "prop": "test", - }, - { - "prop": "ShouldBeTHere", - }, - { - "prop": "test1", - }, - ], - [ - { - "prop": "test", - }, - { - "prop": "ShouldBeTHere", - }, - { - "prop": "test1", - }, - ], - [ - { - "prop": "ShouldBeTHere", - }, - { - "prop": "test1", - }, - ], -] -`; - exports[`useWatch reset with useFieldArray should return current value with radio type 1`] = ` [ {}, diff --git a/src/__tests__/controller.test.tsx b/src/__tests__/controller.test.tsx index b98e1598699..dfe2b97d8b5 100644 --- a/src/__tests__/controller.test.tsx +++ b/src/__tests__/controller.test.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { ControllerRenderProps, FieldValues } from '@hookform/core'; import { fireEvent, render, @@ -8,7 +9,6 @@ import { } from '@testing-library/react'; import { Controller } from '../controller'; -import { ControllerRenderProps, FieldValues } from '../types'; import { useFieldArray } from '../useFieldArray'; import { useForm } from '../useForm'; import { FormProvider } from '../useFormContext'; diff --git a/src/__tests__/isPlainObject.test.ts b/src/__tests__/isPlainObject.test.ts deleted file mode 100644 index 04990bc46c7..00000000000 --- a/src/__tests__/isPlainObject.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import isPlainObject from '../utils/isPlainObject'; - -describe('isPlainObject', function () { - it('should identify plan object or not', function () { - function test() { - return { - test: () => {}, - }; - } - - expect(isPlainObject(Object.create({}))).toBeTruthy(); - expect(isPlainObject(Object.create(Object.prototype))).toBeTruthy(); - expect(isPlainObject({ foo: 'bar' })).toBeTruthy(); - expect(isPlainObject({})).toBeTruthy(); - expect(isPlainObject(Object.create(null))).toBeFalsy(); - expect(!isPlainObject(/foo/)).toBeTruthy(); - expect(!isPlainObject(function () {})).toBeTruthy(); - expect(!isPlainObject(['foo', 'bar'])).toBeTruthy(); - expect(!isPlainObject([])).toBeTruthy(); - expect(!isPlainObject(test)).toBeTruthy(); - }); -}); diff --git a/src/__tests__/logic/appendErrors.test.ts b/src/__tests__/logic/appendErrors.test.ts deleted file mode 100644 index 840179acb2d..00000000000 --- a/src/__tests__/logic/appendErrors.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import appendErrors from '../../logic/appendErrors'; - -describe('appendErrors', () => { - it('should return empty object when validateAllFieldCriteria is false', () => { - const errors = { - test: { - type: 'required', - message: 'test', - }, - }; - expect(appendErrors('test', false, errors, 'min', 'test')).toEqual({}); - }); - - it('should return error object when validateAllFieldCriteria is true', () => { - const errors = { - test: { - type: 'required', - message: 'test', - types: {}, - }, - }; - - expect(appendErrors('test', true, errors, 'required', 'test')).toEqual({ - message: 'test', - type: 'required', - types: { - required: 'test', - }, - }); - - errors.test.types = { required: 'test' }; - expect(appendErrors('test', true, errors, 'min', 'test')).toEqual({ - message: 'test', - type: 'required', - types: { - required: 'test', - min: 'test', - }, - }); - - errors.test.types = { ...errors.test.types, min: 'test' }; - expect(appendErrors('test', true, errors, 'max', 'test')).toEqual({ - message: 'test', - type: 'required', - types: { - required: 'test', - min: 'test', - max: 'test', - }, - }); - - errors.test.types = { ...errors.test.types, max: 'test' }; - expect(appendErrors('test', true, errors, 'undefined', undefined)).toEqual({ - message: 'test', - type: 'required', - types: { - required: 'test', - min: 'test', - max: 'test', - undefined: true, - }, - }); - }); -}); diff --git a/src/__tests__/logic/focusFieldBy.test.ts b/src/__tests__/logic/focusFieldBy.test.ts deleted file mode 100644 index a55655cc6e8..00000000000 --- a/src/__tests__/logic/focusFieldBy.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -import focusFieldBy from '../../logic/focusFieldBy'; -import get from '../../utils/get'; - -describe('focusFieldBy', () => { - it('should focus on the first error it encounter', () => { - const focus = jest.fn(); - focusFieldBy( - { - test: { - _f: { - name: 'test', - ref: { - name: 'test', - focus, - }, - }, - }, - }, - (key) => - get( - { - test: { - message: 'test', - type: 'required', - }, - }, - String(key), - ), - ); - - expect(focus).toBeCalled(); - }); - - it('should focus on first option when options input error encounters', () => { - const focus = jest.fn(); - focusFieldBy( - { - test: { - _f: { - name: 'test', - ref: { - name: 'test', - }, - refs: [ - // @ts-expect-error - { - focus, - }, - ], - }, - }, - }, - (key) => - get( - { - test: { - message: 'test', - type: 'required', - }, - }, - String(key), - ), - ); - - expect(focus).toBeCalled(); - }); - - it('should not call focus when field is undefined', () => { - expect(() => { - focusFieldBy( - { - test: undefined, - }, - (key) => - get( - { - test: { - message: 'test', - type: 'required', - }, - }, - String(key), - ), - ); - }).not.toThrow(); - }); -}); diff --git a/src/__tests__/logic/generateId.test.ts b/src/__tests__/logic/generateId.test.ts deleted file mode 100644 index 38f619b4032..00000000000 --- a/src/__tests__/logic/generateId.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import generateId from '../../logic/generateId'; - -describe('generateId', () => { - it('should generate a unique id', () => { - expect(/\w{8}-\w{4}-4\w{3}-\w{4}-\w{12}/i.test(generateId())).toBeTruthy(); - }); - - it('should fallback to current date if performance is undefined', () => { - // @ts-ignore - delete window.performance; - expect(/\w{8}-\w{4}-4\w{3}-\w{4}-\w{12}/i.test(generateId())).toBeTruthy(); - }); -}); diff --git a/src/__tests__/logic/getCheckboxValue.test.ts b/src/__tests__/logic/getCheckboxValue.test.ts deleted file mode 100644 index bdc5378d682..00000000000 --- a/src/__tests__/logic/getCheckboxValue.test.ts +++ /dev/null @@ -1,219 +0,0 @@ -import getCheckboxValue from '../../logic/getCheckboxValue'; - -describe('getCheckboxValue', () => { - it('should return default value if not valid or empty options', () => { - expect(getCheckboxValue(undefined)).toEqual({ - value: false, - isValid: false, - }); - }); - - it('should return checked value if single checkbox is checked', () => { - expect( - getCheckboxValue([ - { - name: 'bill', - checked: true, - value: '3', - // @ts-expect-error - attributes: { value: '3' }, - }, - ]), - ).toEqual({ value: '3', isValid: true }); - }); - - it('should return true if single checkbox is checked and has no value', () => { - expect( - // @ts-expect-error - getCheckboxValue([{ name: 'bill', checked: true, attributes: {} }]), - ).toEqual({ value: true, isValid: true }); - }); - - it('should return true if single checkbox is checked and has empty value', () => { - expect( - getCheckboxValue([ - { - name: 'bill', - checked: true, - value: '', - // @ts-expect-error - attributes: { value: 'test' }, - }, - ]), - ).toEqual({ value: true, isValid: true }); - expect( - getCheckboxValue([ - { - name: 'bill', - checked: true, - // @ts-expect-error - attributes: { value: 'test' }, - }, - ]), - ).toEqual({ value: true, isValid: true }); - }); - - it('should return false if single checkbox is un-checked', () => { - expect( - getCheckboxValue([ - { - name: 'bill', - checked: false, - // @ts-expect-error - attributes: {}, - }, - ]), - ).toEqual({ value: false, isValid: false }); - }); - - it('should return multiple selected values', () => { - expect( - getCheckboxValue([ - { - name: 'bill', - checked: true, - value: '2', - // @ts-expect-error - attributes: { value: '2' }, - }, - { - name: 'bill', - checked: true, - value: '3', - // @ts-expect-error - attributes: { value: '3' }, - }, - ]), - ).toEqual({ value: ['2', '3'], isValid: true }); - }); - - it('should return values for checked boxes only', () => { - expect( - getCheckboxValue([ - { - name: 'bill', - checked: false, - value: '2', - // @ts-expect-error - attributes: { value: '2' }, - }, - { - name: 'bill', - checked: true, - value: '3', - // @ts-expect-error - attributes: { value: '3' }, - }, - { - name: 'bill', - checked: false, - value: '4', - // @ts-expect-error - attributes: { value: '4' }, - }, - ]), - ).toEqual({ value: ['3'], isValid: true }); - }); - - it('should return empty array for multi checkbox with no checked box', () => { - expect( - getCheckboxValue([ - { - name: 'bill', - checked: false, - value: '2', - // @ts-expect-error - attributes: { value: '2' }, - }, - { - name: 'bill', - checked: false, - value: '3', - // @ts-expect-error - attributes: { value: '3' }, - }, - ]), - ).toEqual({ value: [], isValid: false }); - }); - - it('should not return error when check box ref is undefined', () => { - expect( - getCheckboxValue([ - // @ts-expect-error - undefined, - { - name: 'bill', - checked: false, - value: '2', - // @ts-expect-error - attributes: { value: '2' }, - }, - ]), - ).toEqual({ value: [], isValid: false }); - }); - - it('should return disabled input result', () => { - expect( - getCheckboxValue([ - { - name: 'bill', - checked: true, - value: '2', - disabled: true, - // @ts-expect-error - attributes: { value: '2' }, - }, - { - name: 'bill', - checked: true, - value: '3', - // @ts-expect-error - attributes: { value: '3' }, - }, - ]), - ).toEqual({ - value: ['3'], - isValid: true, - }); - - expect( - getCheckboxValue([ - { - name: 'bill', - checked: true, - value: '2', - disabled: true, - // @ts-expect-error - attributes: { value: '2' }, - }, - { - name: 'bill', - disabled: true, - checked: true, - value: '3', - // @ts-expect-error - attributes: { value: '3' }, - }, - ]), - ).toEqual({ - value: [], - isValid: false, - }); - - expect( - getCheckboxValue([ - { - name: 'bill', - checked: true, - value: '2', - disabled: true, - // @ts-expect-error - attributes: { value: '2' }, - }, - ]), - ).toEqual({ - value: false, - isValid: false, - }); - }); -}); diff --git a/src/__tests__/logic/getDirtyFields.test.ts b/src/__tests__/logic/getDirtyFields.test.ts deleted file mode 100644 index b08a990a221..00000000000 --- a/src/__tests__/logic/getDirtyFields.test.ts +++ /dev/null @@ -1,341 +0,0 @@ -import getDirtyFields from '../../logic/getDirtyFields'; - -describe('getDirtyFields', () => { - it('should return all the dirty fields', () => { - expect( - getDirtyFields( - {}, - { - test: { - test1: 'bill', - test2: 'luo', - }, - test1: ['1', '2', '3'], - test2: [ - { - test1: 'bill', - test2: 'luo', - }, - ], - }, - ), - ).toEqual({ - test: { - test1: true, - test2: true, - }, - test1: [true, true, true], - test2: [ - { - test1: true, - test2: true, - }, - ], - }); - - expect( - getDirtyFields( - { - test: { - test1: '', - test2: 'luo', - }, - test1: ['1'], - test2: [ - { - test1: 'bill', - test2: '', - }, - ], - }, - { - test: { - test1: 'bill', - test2: 'luo', - }, - test1: ['1', '2', '3'], - test2: [ - { - test1: 'bill', - test2: 'luo', - }, - ], - }, - ), - ).toEqual({ - test: { - test1: true, - }, - test1: [undefined, true, true], - test2: [ - { - test2: true, - }, - ], - }); - }); - - it('should set correctly dirty', () => { - expect( - getDirtyFields( - { - test: [{ data: 'bill' }, { data: 'luo', data1: 'luo1' }], - }, - { - test: [{ data: 'bill1' }, { data: 'luo2' }], - }, - ), - ).toEqual({ - test: [ - { - data: true, - }, - { - data: true, - data1: true, - }, - ], - }); - }); - - it('should not set dirtyFields fields for nested input data which are deep equal', () => { - expect( - getDirtyFields( - { test: [{ data: 'luo', data1: 'luo1' }] }, - { test: [{ data: 'luo', data1: 'luo1' }] }, - ), - ).toEqual({ test: [{}] }); - }); - - it('should unset dirtyFields fields when value matches', () => { - expect( - getDirtyFields( - { test: [{ data: 'bill' }, { data: 'luo2', data1: 'luo1' }] }, - { test: [{ data: 'bill1' }, { data: 'luo2' }] }, - ), - ).toEqual({ test: [{ data: true }, { data1: true }] }); - }); - - it('should works in reverse dirtyFields fields check', () => { - expect( - getDirtyFields( - { test: [{ data: 'bill1' }, { data: 'luo2' }] }, - { test: [{ data: 'bill' }, { data: 'luo', data1: 'luo1' }] }, - ), - ).toEqual({ test: [{ data: true }, { data: true, data1: true }] }); - - expect( - getDirtyFields( - { test: [{ data: 'bill1' }, { data: 'luo2' }] }, - { test: [{ data: 'bill' }, { data: 'luo2', data1: 'luo1' }] }, - ), - ).toEqual({ test: [{ data: true }, { data1: true }] }); - }); - - it('should work for empty values compare with defaultValues', () => { - expect( - getDirtyFields( - { test: [] }, - { test: [{ data: 'bill' }, { data: 'luo2', data1: 'luo1' }] }, - ), - ).toEqual({ - test: [ - { - data: true, - }, - { - data: true, - data1: true, - }, - ], - }); - }); - - it('should set correctly with nested dirty', () => { - expect( - getDirtyFields( - { - test: [ - { data: 'bill' }, - { - data: 'luo', - data1: 'luo1', - nested: [{ data: 'luo', data1: 'luo1' }], - nested1: [{ data: 'luo', data1: 'luo1' }], - }, - ], - }, - { test: [{ data: 'bill1' }, { data: 'luo2' }] }, - ), - ).toEqual({ - test: [ - { - data: true, - }, - { - data: true, - data1: true, - nested: [{ data: true, data1: true }], - nested1: [{ data: true, data1: true }], - }, - ], - }); - }); - - it('should keep nested dirtyFields fields when value matches', () => { - expect( - getDirtyFields( - { - test: [ - { data: 'bill' }, - { - data: 'luo', - data1: 'luo1', - nested: [{ data: 'luo', data1: 'luo1' }], - nested1: [{ data: 'luo', data1: 'luo1' }], - }, - ], - }, - { - test: [ - { data: 'bill1' }, - { - data: 'luo2', - data1: 'luo1', - nested: [{ data: 'luo', data1: 'luo1' }], - }, - ], - }, - ), - ).toEqual({ - test: [ - { - data: true, - }, - { - data: true, - nested: [{}], - nested1: [{ data: true, data1: true }], - }, - ], - }); - }); - - it('should reset dirtyFields fields', () => { - expect( - getDirtyFields( - { test: [{ data: 'bill' }] }, - { test: [{ data: 'bill' }] }, - ), - ).toEqual({ test: [{}] }); - }); - - it('should reset dirtyFields fields', () => { - expect( - getDirtyFields( - { - test: [ - { - test1: 'test', - test: [ - { - test: 'test1', - }, - ], - }, - ], - }, - { - test: [ - { - test1: 'test1', - test: null, - }, - - { - test1: 'test', - test: [ - { - test: 'test1', - }, - ], - }, - ], - }, - ), - ).toEqual({ - test: [ - { - test: [ - { - test: true, - }, - ], - test1: true, - }, - { - test: [ - { - test: true, - }, - ], - test1: true, - }, - ], - }); - }); - - it('should work out with different data type', () => { - expect( - getDirtyFields( - { - test: [ - { - test1: 'test', - test: [ - { - test: 'test1', - }, - ], - }, - ], - }, - { - test: [ - { - test1: 'test1', - test: true, - }, - { - test1: 'test', - test: [ - { - test: 'test1', - }, - ], - }, - ], - }, - ), - ).toEqual({ - test: [ - { - test: [ - { - test: true, - }, - ], - test1: true, - }, - { - test: [ - { - test: true, - }, - ], - test1: true, - }, - ], - }); - }); -}); diff --git a/src/__tests__/logic/getEventValue.test.ts b/src/__tests__/logic/getEventValue.test.ts deleted file mode 100644 index aea4b29cdc2..00000000000 --- a/src/__tests__/logic/getEventValue.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import getEventValue from '../../logic/getEventValue'; - -test('getEventValue should return correct value', () => { - expect( - getEventValue({ - target: { checked: true, type: 'checkbox' }, - }), - ).toEqual(true); - expect( - getEventValue({ - target: { checked: true, type: 'checkbox', value: 'test' }, - }), - ).toEqual(true); - expect(getEventValue({ target: { value: 'test' }, type: 'test' })).toEqual( - 'test', - ); - expect(getEventValue({ data: 'test' })).toEqual({ data: 'test' }); - expect(getEventValue('test')).toEqual('test'); - expect(getEventValue(undefined)).toEqual(undefined); - expect(getEventValue(null)).toEqual(null); -}); diff --git a/src/__tests__/logic/getFieldValue.test.ts b/src/__tests__/logic/getFieldValue.test.ts deleted file mode 100644 index b63174072b2..00000000000 --- a/src/__tests__/logic/getFieldValue.test.ts +++ /dev/null @@ -1,97 +0,0 @@ -import getFieldValue from '../../logic/getFieldValue'; -import { Field } from '../../types'; - -jest.mock('../../logic/getRadioValue', () => ({ - __esModule: true, - default: () => ({ - value: 2, - }), -})); - -jest.mock('../../logic/getCheckboxValue', () => ({ - __esModule: true, - default: () => ({ - value: 'testValue', - }), -})); - -describe('getFieldValue', () => { - it('should return correct value when type is radio', () => { - expect( - getFieldValue({ - name: 'test', - ref: { - type: 'radio', - name: 'test', - }, - }), - ).toBe(2); - }); - - it('should return the correct value when type is checkbox', () => { - expect( - getFieldValue({ - name: 'test', - ref: { - name: 'test', - type: 'checkbox', - }, - }), - ).toBe('testValue'); - }); - - it('should return it value for other types', () => { - expect( - getFieldValue({ - name: 'test', - ref: { - type: 'text', - name: 'bill', - value: 'value', - }, - }), - ).toBe('value'); - }); - - it('should return empty string when radio input value is not found', () => { - expect(getFieldValue({ ref: {} } as Field['_f'])).toEqual(undefined); - }); - - it('should return files for input type file', () => { - expect( - getFieldValue({ - name: 'test', - ref: { - type: 'file', - name: 'test', - files: null, - }, - }), - ).toEqual(null); - }); - - it('should return undefined when input is not found', () => { - expect( - getFieldValue({ - name: 'test', - ref: { - name: 'file', - files: null, - }, - }), - ).toEqual(undefined); - }); - - it('should not return value when the input is disabled', () => { - expect( - getFieldValue({ - name: 'test', - ref: { - name: 'radio', - disabled: true, - type: 'radio', - }, - }), - ).toEqual(undefined); - }); -}); diff --git a/src/__tests__/logic/getFieldValueAs.test.ts b/src/__tests__/logic/getFieldValueAs.test.ts deleted file mode 100644 index f99545f7fff..00000000000 --- a/src/__tests__/logic/getFieldValueAs.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import getFieldValueAs from '../../logic/getFieldValueAs'; - -describe('getFieldValueAs', () => { - it('should return undefined when value is undefined', () => { - expect( - getFieldValueAs(undefined, { - ref: { - name: 'test', - }, - name: 'test', - valueAsNumber: true, - valueAsDate: false, - }), - ).toBeUndefined(); - }); -}); diff --git a/src/__tests__/logic/getFocusFieldName.test.ts b/src/__tests__/logic/getFocusFieldName.test.ts deleted file mode 100644 index 4fa28f17ec8..00000000000 --- a/src/__tests__/logic/getFocusFieldName.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import getFocusFieldName from '../../logic/getFocusFieldName'; - -describe('getFocusFieldName', () => { - it('should return expected focus name', () => { - expect(getFocusFieldName('test', 0, { shouldFocus: false })).toEqual(''); - expect( - getFocusFieldName('test', 0, { shouldFocus: true, focusName: 'test' }), - ).toEqual('test'); - expect( - getFocusFieldName('test', 0, { shouldFocus: true, focusIndex: 1 }), - ).toEqual('test.1.'); - expect(getFocusFieldName('test', 0)).toEqual('test.0.'); - }); -}); diff --git a/src/__tests__/logic/getNodeParentName.test.ts b/src/__tests__/logic/getNodeParentName.test.ts deleted file mode 100644 index 85752d09818..00000000000 --- a/src/__tests__/logic/getNodeParentName.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import getNodeParentName from '../../logic/getNodeParentName'; - -describe('getNodeParentName', () => { - it('should return parent name when name is field array', () => { - expect(getNodeParentName('test.0')).toBe('test'); - expect(getNodeParentName('test1.1')).toBe('test1'); - expect(getNodeParentName('test.0.data.0')).toBe('test'); - expect(getNodeParentName('test.data.0')).toBe('test.data'); - expect(getNodeParentName('test.1st')).toBe('test.1st'); - }); - - it('should return empty string when name is not field array', () => { - expect(getNodeParentName('test')).toBe('test'); - expect(getNodeParentName('test0')).toBe('test0'); - expect(getNodeParentName('te1st')).toBe('te1st'); - }); -}); diff --git a/src/__tests__/logic/getRadioValue.test.ts b/src/__tests__/logic/getRadioValue.test.ts deleted file mode 100644 index 0f5fef83ec5..00000000000 --- a/src/__tests__/logic/getRadioValue.test.ts +++ /dev/null @@ -1,58 +0,0 @@ -import getRadioValue from '../../logic/getRadioValue'; - -describe('getRadioValue', () => { - it('should return default value if not valid or empty options', () => { - expect(getRadioValue(undefined)).toEqual({ - isValid: false, - value: null, - }); - }); - - it('should return valid to true when value found', () => { - expect( - getRadioValue([ - { name: 'bill', checked: false, value: '1' } as HTMLInputElement, - { name: 'bill', checked: true, value: '2' } as HTMLInputElement, - ]), - ).toEqual({ - isValid: true, - value: '2', - }); - }); - - it('should return disabled input correctly', () => { - expect( - getRadioValue([ - { - name: 'bill', - checked: false, - value: '1', - disabled: true, - } as HTMLInputElement, - { name: 'bill', checked: true, value: '2' } as HTMLInputElement, - ]), - ).toEqual({ - isValid: true, - value: '2', - }); - - expect( - getRadioValue([ - { - name: 'bill', - checked: false, - value: '1', - } as HTMLInputElement, - { - name: 'bill', - checked: true, - disabled: true, - value: '2', - } as HTMLInputElement, - ]), - ).toEqual({ - isValid: false, - value: null, - }); - }); -}); diff --git a/src/__tests__/logic/getResolverOptions.test.ts b/src/__tests__/logic/getResolverOptions.test.ts deleted file mode 100644 index b12cf8c2211..00000000000 --- a/src/__tests__/logic/getResolverOptions.test.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { InternalFieldName } from '../..'; -import getResolverOptions from '../../logic/getResolverOptions'; - -describe('getFielfs', () => { - it('should return fields from `fieldsNames` and `fieldsRef`', () => { - const fieldNames: Set = new Set(['test.sub', 'test1']); - const fieldsRef: any = { - test: { - sub: { - _f: { - ref: { name: 'test.sub', value: 'test' }, - name: 'test.sub', - value: 'test', - }, - }, - }, - test1: { - _f: { - ref: { name: 'test1', value: 'test1' }, - name: 'test1', - value: 'test1', - }, - }, - }; - - expect(getResolverOptions(fieldNames, fieldsRef, undefined, true)) - .toMatchInlineSnapshot(` - { - "criteriaMode": undefined, - "fields": { - "test": { - "sub": { - "name": "test.sub", - "ref": { - "name": "test.sub", - "value": "test", - }, - "value": "test", - }, - }, - "test1": { - "name": "test1", - "ref": { - "name": "test1", - "value": "test1", - }, - "value": "test1", - }, - }, - "names": [ - "test.sub", - "test1", - ], - "shouldUseNativeValidation": true, - } - `); - }); -}); diff --git a/src/__tests__/logic/getRuleValue.test.ts b/src/__tests__/logic/getRuleValue.test.ts deleted file mode 100644 index 936ef16421b..00000000000 --- a/src/__tests__/logic/getRuleValue.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import getRuleValue from '../../logic/getRuleValue'; - -describe('getRuleValue', () => { - it('should return associated rule value', () => { - expect(getRuleValue('1990/09/09')).toEqual('1990/09/09'); - expect(getRuleValue('2')).toEqual('2'); - expect(getRuleValue(2)).toEqual(2); - - expect(getRuleValue(/test/)).toEqual('test'); - - expect(getRuleValue({ value: '2', message: 'data' })).toEqual('2'); - expect(getRuleValue({ value: '1990/09/09', message: 'data' })).toEqual( - '1990/09/09', - ); - expect(getRuleValue({ value: 2, message: 'data' })).toEqual(2); - expect(getRuleValue({ value: /test/, message: 'data' })).toEqual('test'); - }); - - it('should return undefined when no value is set', () => { - expect(getRuleValue(undefined)).toBeUndefined(); - }); -}); diff --git a/src/__tests__/logic/getValidateError.test.ts b/src/__tests__/logic/getValidateError.test.ts deleted file mode 100644 index 9148df20687..00000000000 --- a/src/__tests__/logic/getValidateError.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import getValidateError from '../../logic/getValidateError'; - -describe('getValidateError', () => { - it('should return field error in correct format', () => { - expect( - getValidateError( - 'This is a required field', - { - name: 'test1', - value: '', - }, - 'required', - ), - ).toEqual({ - type: 'required', - message: 'This is a required field', - ref: { - name: 'test1', - value: '', - }, - }); - - expect( - getValidateError( - false, - { - name: 'test1', - value: '', - }, - 'required', - ), - ).toEqual({ - type: 'required', - message: '', - ref: { - name: 'test1', - value: '', - }, - }); - }); - - it('should return undefined when called with non string result', () => { - expect(getValidateError(undefined, () => {})).toBeUndefined(); - }); -}); diff --git a/src/__tests__/logic/getValueAndMessage.test.ts b/src/__tests__/logic/getValueAndMessage.test.ts deleted file mode 100644 index 69101850856..00000000000 --- a/src/__tests__/logic/getValueAndMessage.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import getValueAndMessage from '../../logic/getValueAndMessage'; - -describe('getValueAndMessage', () => { - it('should return message and value correctly', () => { - expect(getValueAndMessage(0).value).toEqual(0); - expect(getValueAndMessage(3).value).toEqual(3); - expect(getValueAndMessage({ value: 0, message: 'what' }).value).toEqual(0); - expect(getValueAndMessage({ value: 2, message: 'what' }).value).toEqual(2); - expect(getValueAndMessage({ value: 1, message: 'test' }).message).toEqual( - 'test', - ); - }); -}); diff --git a/src/__tests__/logic/isNameInFieldArray.test.ts b/src/__tests__/logic/isNameInFieldArray.test.ts deleted file mode 100644 index 41f06dee619..00000000000 --- a/src/__tests__/logic/isNameInFieldArray.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import isNameInFieldArray from '../../logic/isNameInFieldArray'; - -describe('isNameInFieldArray', () => { - it('should find match array field', () => { - expect(isNameInFieldArray(new Set(['test']), 'test.0')).toBeTruthy(); - expect(isNameInFieldArray(new Set(['te']), 'test.0')).toBeFalsy(); - expect(isNameInFieldArray(new Set(['te']), 'test.0')).toBeFalsy(); - expect(isNameInFieldArray(new Set(['test1']), 'test[0]')).toBeFalsy(); - expect(isNameInFieldArray(new Set(['test1']), 'test.0')).toBeFalsy(); - expect( - isNameInFieldArray(new Set(['test']), 'test.0.data[0]'), - ).toBeTruthy(); - expect(isNameInFieldArray(new Set(['test']), 'test.0.data.0')).toBeTruthy(); - expect(isNameInFieldArray(new Set(['test']), 'test1.0.data.0')).toBeFalsy(); - expect(isNameInFieldArray(new Set(['test']), 'data.0.data.0')).toBeFalsy(); - }); -}); diff --git a/src/__tests__/logic/isWatched.test.ts b/src/__tests__/logic/isWatched.test.ts deleted file mode 100644 index e6b60448b8a..00000000000 --- a/src/__tests__/logic/isWatched.test.ts +++ /dev/null @@ -1,125 +0,0 @@ -import isWatched from '../../logic/isWatched'; - -describe('isWatched', () => { - it('should return watched fields', () => { - expect( - isWatched('', { - mount: new Set(), - unMount: new Set(), - array: new Set(), - watch: new Set(), - focus: '', - watchAll: true, - }), - ).toBeTruthy(); - - expect( - isWatched('test', { - mount: new Set(), - unMount: new Set(), - array: new Set(), - watch: new Set(['test']), - focus: '', - watchAll: false, - }), - ).toBeTruthy(); - }); - - it('should return true when watched with parent node', () => { - expect( - isWatched('test.test', { - mount: new Set(), - unMount: new Set(), - array: new Set(), - watch: new Set(['test']), - focus: '', - watchAll: false, - }), - ).toBeTruthy(); - - expect( - isWatched('test.test.test', { - mount: new Set(), - unMount: new Set(), - array: new Set(), - watch: new Set(['test.test']), - focus: '', - watchAll: false, - }), - ).toBeTruthy(); - - expect( - isWatched('test.test.test', { - mount: new Set(), - unMount: new Set(), - array: new Set(), - watch: new Set(['testFail.test', 'test.test']), - focus: '', - watchAll: false, - }), - ).toBeTruthy(); - - expect( - isWatched('test.0', { - mount: new Set(), - unMount: new Set(), - array: new Set(), - watch: new Set(['test']), - focus: '', - watchAll: false, - }), - ).toBeTruthy(); - - expect( - isWatched('test.0.test', { - mount: new Set(), - unMount: new Set(), - array: new Set(), - watch: new Set(['test.0']), - focus: '', - watchAll: false, - }), - ).toBeTruthy(); - }); - - it("should return false when watched with parent node that doesn't match child name", () => { - expect( - isWatched('test.test.test', { - mount: new Set(), - unMount: new Set(), - array: new Set(), - watch: new Set(['tesk.test']), - focus: '', - watchAll: false, - }), - ).toBeFalsy(); - - expect( - isWatched('test.test.test', { - mount: new Set(), - unMount: new Set(), - array: new Set(), - watch: new Set(['testFail.test']), - focus: '', - watchAll: false, - }), - ).toBeFalsy(); - }); - - it('should return falsy for blur event', () => { - expect( - isWatched( - '', - { - mount: new Set(), - unMount: new Set(), - array: new Set(), - watch: new Set(), - focus: '', - watchAll: true, - }, - true, - ), - ).toBeFalsy(); - }); -}); diff --git a/src/__tests__/logic/schemaErrorLookup.test.ts b/src/__tests__/logic/schemaErrorLookup.test.ts deleted file mode 100644 index 0c680fca0a8..00000000000 --- a/src/__tests__/logic/schemaErrorLookup.test.ts +++ /dev/null @@ -1,235 +0,0 @@ -import schemaErrorLookup from '../../logic/schemaErrorLookup'; - -describe('errorsLookup', () => { - it('should be able to look up the error', () => { - expect( - schemaErrorLookup<{ - test: { - deep: string; - }; - }>( - { - test: { - type: 'test', - message: 'error', - deep: { - type: 'deep', - message: 'error', - }, - }, - }, - {}, - 'test.deep.whatever', - ), - ).toEqual({ - error: { - type: 'deep', - message: 'error', - }, - name: 'test.deep', - }); - - expect( - schemaErrorLookup( - { - test: { - type: 'test', - message: 'error', - }, - }, - {}, - 'test.0.whatever', - ), - ).toEqual({ - error: { - type: 'test', - message: 'error', - }, - name: 'test', - }); - - expect( - schemaErrorLookup( - { - test: { - type: 'test', - message: 'error', - }, - }, - {}, - 'test', - ), - ).toEqual({ - error: { - type: 'test', - message: 'error', - }, - name: 'test', - }); - - expect( - schemaErrorLookup<{ - test: { - deep: string; - }; - test1: { - nested: { - deepNested: string; - }; - }; - }>( - { - test: { - type: 'test', - message: 'error', - }, - test1: { - type: 'test', - message: 'error', - nested: { - type: 'test', - message: 'error', - deepNested: { - type: 'deepNested', - message: 'error', - }, - }, - }, - }, - {}, - 'test1.nested.deepNested.whatever', - ), - ).toEqual({ - error: { message: 'error', type: 'deepNested' }, - name: 'test1.nested.deepNested', - }); - }); - - it('should return undefined when not found', () => { - expect( - schemaErrorLookup( - { - test: { - type: 'test', - message: 'error', - }, - }, - {}, - 'test1234', - ), - ).toEqual({ error: undefined, name: 'test1234' }); - - expect( - schemaErrorLookup( - { - test: { - type: 'test', - message: 'error', - }, - }, - {}, - 'testX.1.test', - ), - ).toEqual({ - name: 'testX.1.test', - }); - - expect( - schemaErrorLookup<{ - test: { - test: string; - test1: string; - }; - }>( - { - test: { - test: { - type: 'test', - message: 'error', - }, - test1: { - type: 'test', - message: 'error', - }, - }, - }, - {}, - 'test.test2', - ), - ).toEqual({ - name: 'test.test2', - }); - }); - - it('should prevent error from reported when field is identified', () => { - expect( - schemaErrorLookup<{ - test: { - test: string; - test1: string; - }; - }>( - { - test: { - test: { - type: 'test', - message: 'error', - }, - test1: { - type: 'test', - message: 'error', - }, - }, - }, - { - test: { - test1: { - _f: { - ref: {}, - name: 'test', - }, - }, - }, - }, - 'test.test1.whatever', - ), - ).toEqual({ - name: 'test.test1.whatever', - }); - - expect( - schemaErrorLookup<{ - test: { - test: string; - test1: string; - }; - }>( - { - test: { - test: { - type: 'test', - message: 'error', - }, - test1: { - type: 'test', - message: 'error', - }, - }, - }, - { - test: { - test1: { - _f: { - ref: {}, - name: 'test', - }, - }, - }, - }, - 'test.testXYZ', - ), - ).toEqual({ - name: 'test.testXYZ', - }); - }); -}); diff --git a/src/__tests__/logic/shouldSubscribeByName.test.ts b/src/__tests__/logic/shouldSubscribeByName.test.ts deleted file mode 100644 index 9165fb18c57..00000000000 --- a/src/__tests__/logic/shouldSubscribeByName.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import shouldSubscribeByName from '../../logic/shouldSubscribeByName'; - -describe('shouldSubscribeByName', () => { - it('should return correct response for subscription name coverage', () => { - expect(shouldSubscribeByName(undefined, 'test')).toBeTruthy(); - expect(shouldSubscribeByName('test', undefined)).toBeTruthy(); - expect(shouldSubscribeByName(['test'], undefined)).toBeTruthy(); - expect(shouldSubscribeByName(['test'], 'test')).toBeTruthy(); - expect(shouldSubscribeByName(['tes'], 'test')).toBeTruthy(); - expect(shouldSubscribeByName(['test1'], 'test')).toBeTruthy(); - expect(shouldSubscribeByName('test1', 'test')).toBeTruthy(); - expect(shouldSubscribeByName('tes', 'test')).toBeTruthy(); - - expect(shouldSubscribeByName('testXXX', 'data')).toBeFalsy(); - expect(shouldSubscribeByName(['testXXX'], 'data')).toBeFalsy(); - }); -}); diff --git a/src/__tests__/logic/skipValidation.test.ts b/src/__tests__/logic/skipValidation.test.ts deleted file mode 100644 index 0559f56dc4f..00000000000 --- a/src/__tests__/logic/skipValidation.test.ts +++ /dev/null @@ -1,195 +0,0 @@ -import skipValidation from '../../logic/skipValidation'; - -describe('should skip validation', () => { - it('when is onChange mode and blur event', () => { - expect( - skipValidation( - false, - false, - false, - { - isOnChange: true, - isOnBlur: false, - }, - { - isOnChange: true, - isOnBlur: true, - isOnTouch: false, - }, - ), - ).toBeTruthy(); - }); - - it('when is onSubmit mode and re-validate on Submit', () => { - expect( - skipValidation( - false, - false, - false, - { - isOnChange: false, - isOnBlur: false, - }, - { - isOnChange: false, - isOnBlur: false, - isOnTouch: false, - }, - ), - ).toBeTruthy(); - }); - - it('when is onSubmit mode and not submitted yet', () => { - expect( - skipValidation( - false, - false, - false, - { - isOnChange: true, - isOnBlur: false, - }, - { - isOnChange: false, - isOnBlur: false, - isOnTouch: false, - }, - ), - ).toBeTruthy(); - }); - - it('when on blur mode, not blur event and error gets clear', () => { - expect( - skipValidation( - false, - false, - false, - { - isOnChange: true, - isOnBlur: false, - }, - { - isOnChange: false, - isOnBlur: true, - isOnTouch: false, - }, - ), - ).toBeTruthy(); - }); - - it('when re-validate mode is blur, not blur event and has error ', () => { - expect( - skipValidation( - false, - false, - true, - { - isOnChange: true, - isOnBlur: true, - }, - { - isOnChange: false, - isOnBlur: false, - isOnTouch: false, - }, - ), - ).toBeTruthy(); - }); - - it('when is re-validate mode on submit and have error', () => { - expect( - skipValidation( - false, - false, - true, - { - isOnChange: false, - isOnBlur: false, - }, - { - isOnChange: false, - isOnBlur: false, - isOnTouch: false, - }, - ), - ).toBeTruthy(); - }); -}); - -describe('should validate the input', () => { - it('when form is submitted and there is error', () => { - expect( - skipValidation( - false, - false, - true, - { - isOnChange: true, - isOnBlur: false, - }, - { - isOnChange: false, - isOnBlur: false, - isOnTouch: false, - }, - ), - ).toBeFalsy(); - }); - - it('when mode is under all', () => { - expect( - skipValidation( - false, - false, - false, - { - isOnChange: false, - isOnBlur: false, - }, - { - isOnChange: false, - isOnBlur: false, - isOnAll: true, - }, - ), - ).toBeFalsy(); - }); - - it('when user blur input and there is no more error', () => { - expect( - skipValidation( - true, - false, - false, - { - isOnChange: true, - isOnBlur: false, - }, - { - isOnChange: false, - isOnBlur: true, - isOnTouch: false, - }, - ), - ).toBeFalsy(); - }); - - it('when user blur and there is an error', () => { - expect( - skipValidation( - true, - false, - false, - { - isOnChange: true, - isOnBlur: false, - }, - { - isOnChange: false, - isOnBlur: true, - isOnTouch: false, - }, - ), - ).toBeFalsy(); - }); -}); diff --git a/src/__tests__/logic/validateField.test.tsx b/src/__tests__/logic/validateField.test.tsx deleted file mode 100644 index d5f5c2561c1..00000000000 --- a/src/__tests__/logic/validateField.test.tsx +++ /dev/null @@ -1,2335 +0,0 @@ -import getCheckboxValue from '../../logic/getCheckboxValue'; -import getRadioValue from '../../logic/getRadioValue'; -import validateField from '../../logic/validateField'; - -jest.mock('../../logic/getRadioValue'); -jest.mock('../../logic/getCheckboxValue'); - -describe('validateField', () => { - it('should return required true when input not filled with required', async () => { - (getRadioValue as jest.Mock).mockImplementation(() => ({ - value: '2', - })); - (getCheckboxValue as jest.Mock).mockImplementation(() => ({ - value: false, - isValid: false, - })); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'text', value: '', name: 'test' }, - required: true, - }, - }, - { - test: '', - }, - false, - ), - ).toEqual({ - test: { - ref: { type: 'text', value: '', name: 'test' }, - message: '', - type: 'required', - }, - }); - - const input = document.createElement('input'); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: input, - required: true, - valueAsNumber: true, - }, - }, - // @ts-expect-error - NaN, - false, - ), - ).toEqual({ - test: { - ref: input, - message: '', - type: 'required', - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'text', value: '', name: 'test' }, - required: 'required', - }, - }, - { - test: '', - }, - false, - ), - ).toEqual({ - test: { - ref: { type: 'text', value: '', name: 'test' }, - message: 'required', - type: 'required', - }, - }); - - expect( - await validateField( - { - _f: { - valueAsNumber: true, - mount: true, - name: 'test', - ref: { name: 'test' }, - required: 'required', - }, - }, - { - test: 2, - }, - false, - ), - ).toEqual({}); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'text', value: '', name: 'test' }, - required: 'required', - }, - }, - { - test: '', - }, - false, - ), - ).toEqual({ - test: { - ref: { type: 'text', value: '', name: 'test' }, - message: 'required', - type: 'required', - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'text', value: '', name: 'test' }, - required: { - value: true, - message: 'required', - }, - }, - }, - { - test: '', - }, - false, - ), - ).toEqual({ - test: { - ref: { type: 'text', value: '', name: 'test' }, - message: 'required', - type: 'required', - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'text', value: '', name: 'test' }, - required: { - value: true, - message: 'required', - }, - }, - }, - { - test: '', - }, - false, - ), - ).toEqual({ - test: { - ref: { type: 'text', value: '', name: 'test' }, - message: 'required', - type: 'required', - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'text', value: '', name: 'test' }, - required: { - value: false, - message: 'required', - }, - }, - }, - { - test: '', - }, - false, - ), - ).toEqual({}); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'radio', name: 'test' }, - required: true, - }, - }, - { - test: false, - }, - false, - ), - ).toEqual({ - test: { - message: '', - type: 'required', - ref: { type: 'radio', name: 'test' }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'text', value: '', name: 'test' }, - required: 'test', - }, - }, - { - test: '', - }, - false, - ), - ).toEqual({ - test: { - message: 'test', - type: 'required', - ref: { type: 'text', name: 'test', value: '' }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'radio', value: '', name: 'test' }, - required: 'test', - }, - }, - { - test: '', - }, - false, - ), - ).toEqual({ - test: { - message: 'test', - type: 'required', - ref: { type: 'radio', name: 'test', value: '' }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'checkbox', name: 'test' }, - required: 'test', - }, - }, - { - test: false, - }, - false, - ), - ).toEqual({ - test: { - message: 'test', - type: 'required', - ref: { type: 'checkbox', name: 'test' }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'text', value: '0', name: 'test' }, - required: true, - value: '0', - }, - }, - { - test: '0', - }, - false, - ), - ).toEqual({}); - - (getCheckboxValue as jest.Mock).mockImplementation(() => ({ - value: 'test', - isValid: true, - })); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'checkbox', name: 'test' }, - required: 'test', - }, - }, - { - test: '', - }, - false, - ), - ).toEqual({}); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - valueAsNumber: true, - ref: { name: 'test', value: '' }, - required: true, - value: NaN, - }, - }, - { - test: '', - }, - false, - ), - ).toEqual({ - test: { - type: 'required', - message: '', - ref: { - name: 'test', - value: '', - }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { name: 'test', type: 'file', value: '' }, - required: true, - value: {}, - }, - }, - { - test: '', - }, - false, - ), - ).toEqual({ - test: { - type: 'required', - message: '', - ref: { - type: 'file', - name: 'test', - value: '', - }, - }, - }); - }); - - it('should return max error', async () => { - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'number', name: 'test', valueAsNumber: 10 }, - value: 10, - required: true, - max: 0, - }, - }, - { - test: 10, - }, - false, - ), - ).toEqual({ - test: { - type: 'max', - message: '', - ref: { type: 'number', name: 'test', valueAsNumber: 10 }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'number', name: 'test', valueAsNumber: 10 }, - value: 10, - required: true, - max: { - value: 0, - message: 'max', - }, - }, - }, - { - test: 10, - }, - false, - ), - ).toEqual({ - test: { - type: 'max', - message: 'max', - ref: { type: 'number', name: 'test', valueAsNumber: 10 }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'number', name: 'test', valueAsNumber: 10 }, - required: true, - max: { - value: 0, - message: 'max', - }, - value: 10, - }, - }, - { - test: 10, - }, - false, - ), - ).toEqual({ - test: { - type: 'max', - message: 'max', - ref: { type: 'number', name: 'test', valueAsNumber: 10 }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'number', name: 'test', valueAsNumber: 8 }, - value: 8, - required: true, - max: 8, - }, - }, - { - test: 8, - }, - false, - ), - ).toEqual({}); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'number', name: 'test', valueAsNumber: 10 }, - value: 10, - max: 8, - }, - }, - { - test: 10, - }, - true, - ), - ).toEqual({ - test: { - type: 'max', - message: '', - ref: { type: 'number', name: 'test', valueAsNumber: 10 }, - types: { - max: true, - }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'custom', name: 'test', valueAsNumber: NaN }, - value: '', - required: true, - }, - }, - { - test: '', - }, - false, - ), - ).toEqual({ - test: { - type: 'required', - message: '', - ref: { type: 'custom', name: 'test', valueAsNumber: NaN }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'custom', - name: 'test', - valueAsNumber: NaN, - }, - value: undefined, - required: true, - }, - }, - { - test: undefined, - }, - false, - ), - ).toEqual({ - test: { - type: 'required', - message: '', - ref: { - type: 'custom', - name: 'test', - value: undefined, - valueAsNumber: NaN, - }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'custom', - name: 'test', - valueAsNumber: NaN, - }, - value: null, - required: true, - }, - }, - { - test: null, - }, - false, - ), - ).toEqual({ - test: { - type: 'required', - message: '', - ref: { type: 'custom', name: 'test', valueAsNumber: NaN }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'custom', name: 'test' }, - required: true, - value: 'ok', - }, - }, - { - test: 'ok', - }, - false, - ), - ).toEqual({}); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'date', - name: 'test', - }, - value: '2019-2-13', - required: true, - max: '2019-1-12', - }, - }, - { - test: '2019-2-13', - }, - false, - ), - ).toEqual({ - test: { - type: 'max', - message: '', - ref: { - type: 'date', - name: 'test', - }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'week', - name: 'test', - }, - value: '2022-W18', - required: true, - max: { - value: '2022-W17', - message: 'max', - }, - }, - }, - { - test: '2022-W18', - }, - false, - ), - ).toEqual({ - test: { - type: 'max', - message: 'max', - ref: { - type: 'week', - name: 'test', - }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'time', - name: 'test', - }, - value: '14:00', - required: true, - max: { - value: '13:00', - message: 'max', - }, - }, - }, - { - test: '14:00', - }, - false, - ), - ).toEqual({ - test: { - type: 'max', - message: 'max', - ref: { - type: 'time', - name: 'test', - }, - }, - }); - }); - - it('should return min error', async () => { - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'number', name: 'test', valueAsNumber: -1 }, - value: -1, - required: true, - min: 0, - }, - }, - { - test: -1, - }, - false, - ), - ).toEqual({ - test: { - type: 'min', - message: '', - ref: { type: 'number', name: 'test', valueAsNumber: -1 }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'number', name: 'test', valueAsNumber: -1 }, - value: -1, - required: true, - min: { - value: 0, - message: 'min', - }, - }, - }, - { - test: -1, - }, - false, - ), - ).toEqual({ - test: { - type: 'min', - message: 'min', - ref: { type: 'number', name: 'test', valueAsNumber: -1 }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'number', name: 'test', valueAsNumber: -1 }, - value: -1, - required: true, - min: { - value: 0, - message: 'min', - }, - }, - }, - { - test: -1, - }, - false, - ), - ).toEqual({ - test: { - type: 'min', - message: 'min', - ref: { type: 'number', name: 'test', valueAsNumber: -1 }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'number', name: 'test', valueAsNumber: 10 }, - value: 10, - required: true, - min: 12, - }, - }, - { - test: 10, - }, - false, - ), - ).toEqual({ - test: { - type: 'min', - message: '', - ref: { type: 'number', name: 'test', valueAsNumber: 10 }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'date', - name: 'test', - valueAsDate: new Date('2019-2-12'), - }, - value: '2019-2-12', - required: true, - min: '2019-3-12', - }, - }, - { - test: '2019-2-12', - }, - false, - ), - ).toEqual({ - test: { - type: 'min', - message: '', - ref: { - type: 'date', - name: 'test', - valueAsDate: new Date('2019-2-12'), - }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'date', - name: 'test', - }, - value: '2019-2-12', - required: true, - min: { - value: '2019-3-12', - message: 'min', - }, - }, - }, - { - test: '2019-2-12', - }, - false, - ), - ).toEqual({ - test: { - type: 'min', - message: 'min', - ref: { - type: 'date', - name: 'test', - }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'date', - name: 'test', - valueAsDate: new Date('2019-2-12'), - }, - value: '2019-2-12', - required: true, - min: { - value: '2019-3-12', - message: 'min', - }, - }, - }, - { - test: '2019-2-12', - }, - false, - ), - ).toEqual({ - test: { - type: 'min', - message: 'min', - ref: { - type: 'date', - name: 'test', - valueAsDate: new Date('2019-2-12'), - }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'week', - name: 'test', - }, - value: '2022-W15', - required: true, - min: { - value: '2022-W17', - message: 'min', - }, - }, - }, - { - test: '2022-W15', - }, - false, - ), - ).toEqual({ - test: { - type: 'min', - message: 'min', - ref: { - type: 'week', - name: 'test', - }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'time', - name: 'test', - }, - value: '12:00', - required: true, - min: { - value: '13:00', - message: 'min', - }, - }, - }, - { - test: '12:00', - }, - false, - ), - ).toEqual({ - test: { - type: 'min', - message: 'min', - ref: { - type: 'time', - name: 'test', - }, - }, - }); - }); - - it('should return min and max error for custom input', async () => { - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: '', name: 'test' }, - value: '1', - required: true, - min: '4', - }, - }, - { - test: '1', - }, - false, - ), - ).toEqual({ - test: { - type: 'min', - message: '', - ref: { type: '', name: 'test' }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: '', name: 'test' }, - value: '4', - required: true, - max: '2', - }, - }, - { - test: '4', - }, - false, - ), - ).toEqual({ - test: { - type: 'max', - message: '', - ref: { type: '', name: 'test' }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: '', - name: 'test', - valueAsDate: new Date('2019-2-12'), - }, - value: '2019-2-12', - required: true, - max: '2019-1-12', - }, - }, - { - test: '2019-2-12', - }, - false, - ), - ).toEqual({ - test: { - type: 'max', - message: '', - ref: { - type: '', - name: 'test', - valueAsDate: new Date('2019-2-12'), - }, - }, - }); - }); - - it('should return max length error ', async () => { - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input', - required: true, - maxLength: 12, - }, - }, - { - test: 'This is a long text input', - }, - false, - ), - ).toEqual({ - test: { - ref: { - type: 'text', - name: 'test', - }, - message: '', - type: 'maxLength', - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input', - required: true, - maxLength: { - value: 12, - message: 'maxLength', - }, - }, - }, - { - test: 'This is a long text input', - }, - false, - ), - ).toEqual({ - test: { - ref: { - type: 'text', - name: 'test', - }, - message: 'maxLength', - type: 'maxLength', - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input', - required: true, - maxLength: { - value: 12, - message: 'maxLength', - }, - }, - }, - { - test: 'This is a long text input', - }, - false, - ), - ).toEqual({ - test: { - ref: { - type: 'text', - name: 'test', - }, - message: 'maxLength', - type: 'maxLength', - }, - }); - }); - - it('should return min length error ', async () => { - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input', - required: true, - minLength: 200, - }, - }, - { - test: 'This is a long text input', - }, - false, - ), - ).toEqual({ - test: { - ref: { - type: 'text', - name: 'test', - }, - message: '', - type: 'minLength', - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input', - required: true, - minLength: { - value: 200, - message: 'minLength', - }, - }, - }, - { - test: 'This is a long text input', - }, - false, - ), - ).toEqual({ - test: { - ref: { - type: 'text', - name: 'test', - }, - message: 'minLength', - type: 'minLength', - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input', - required: true, - minLength: { - value: 200, - message: 'minLength', - }, - }, - }, - { - test: 'This is a long text input', - }, - false, - ), - ).toEqual({ - test: { - ref: { - type: 'text', - name: 'test', - }, - message: 'minLength', - type: 'minLength', - }, - }); - }); - - it('should return pattern error when not matching', async () => { - const emailRegex = - /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/; - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input', - required: true, - pattern: emailRegex, - }, - }, - { - test: 'This is a long text input', - }, - false, - ), - ).toEqual({ - test: { - ref: { - type: 'text', - name: 'test', - }, - message: '', - type: 'pattern', - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - required: true, - value: 'This is a long text input', - pattern: { - value: emailRegex, - message: 'regex failed', - }, - }, - }, - { - test: 'This is a long text input', - }, - false, - ), - ).toEqual({ - test: { - ref: { - type: 'text', - name: 'test', - }, - message: 'regex failed', - type: 'pattern', - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input', - required: true, - pattern: { - value: emailRegex, - message: 'regex failed', - }, - }, - }, - { - test: 'This is a long text input', - }, - false, - ), - ).toEqual({ - test: { - ref: { - type: 'text', - name: 'test', - }, - message: 'regex failed', - type: 'pattern', - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'test@test.com', - required: true, - pattern: emailRegex, - }, - }, - { - test: 'test@test.com', - }, - false, - ), - ).toEqual({}); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: null, - required: false, - pattern: emailRegex, - }, - }, - { - test: null, - }, - false, - ), - ).toEqual({}); - }); - - it('should validate for custom validation', async () => { - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input', - required: true, - validate: (value) => value.toString().length > 3, - }, - }, - { - test: 'This is a long text input', - }, - false, - ), - ).toEqual({}); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input', - required: true, - validate: (value) => value.toString().length < 3, - }, - }, - { - test: 'This is a long text input', - }, - false, - ), - ).toEqual({ - test: { - message: '', - ref: { - type: 'text', - name: 'test', - }, - type: 'validate', - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input', - required: true, - validate: { - test: (value) => value.toString().length < 3, - test1: (value) => value.toString().length > 10, - }, - }, - }, - { - test: 'This is a long text input', - }, - false, - ), - ).toEqual({ - test: { - ref: { - type: 'text', - name: 'test', - }, - type: 'test', - message: '', - }, - }); - - (getRadioValue as jest.Mock).mockImplementation(() => { - return { - isValid: false, - value: 'test', - }; - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input!', - validate: { - test: (value) => value.toString().length < 3, - test1: (value) => value.toString().length > 10, - }, - }, - }, - { - test: 'This is a long text input!', - }, - false, - ), - ).toEqual({ - test: { - ref: { - name: 'test', - type: 'text', - }, - type: 'test', - message: '', - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'radio', - name: 'test', - }, - value: 'This is a long text input!', - validate: { - test: (value) => value.toString().length < 3, - test1: (value) => value.toString().length > 10, - }, - refs: [{ type: 'data' } as HTMLInputElement], - }, - }, - { - test: 'This is a long text input!', - }, - false, - ), - ).toEqual({ - test: { - ref: { type: 'data' }, - type: 'test', - message: '', - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'radio', - name: 'test', - }, - value: 'This is a long text input!', - validate: { - test: () => true, - }, - refs: [ - { - type: 'data', - } as HTMLInputElement, - ], - }, - }, - { - test: 'This is a long text input!', - }, - false, - ), - ).toEqual({}); - }); - - it('should return error message when it is defined', async () => { - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input', - validate: { - test: (value) => { - if (value.toString().length > 3) { - return 'max 3'; - } - return true; - }, - }, - }, - }, - { - test: 'This is a long text input', - }, - false, - ), - ).toEqual({ - test: { - type: 'test', - message: 'max 3', - ref: { - type: 'text', - name: 'test', - }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input', - validate: { - test: (value) => { - if (value.toString().length > 3) { - return 'max 3'; - } - return true; - }, - }, - }, - }, - { - test: 'This is a long text input', - }, - false, - ), - ).toEqual({ - test: { - type: 'test', - message: 'max 3', - ref: { - type: 'text', - name: 'test', - }, - }, - }); - }); - - it('should return result or empty string when validate has error', async () => { - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input', - validate: (value) => value.toString().length < 3 || 'bill', - }, - }, - { - test: 'This is a long text input', - }, - false, - ), - ).toEqual({ - test: { - type: 'validate', - message: 'bill', - ref: { - type: 'text', - name: 'test', - }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input', - validate: (value) => value.toString().length < 3 || 'bill', - }, - }, - { - test: 'This is a long text input', - }, - false, - ), - ).toEqual({ - test: { - type: 'validate', - message: 'bill', - ref: { - type: 'text', - name: 'test', - }, - }, - }); - }); - - it('if undefined returned from validate, no error is reported', async () => { - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input', - validate: () => undefined, - }, - }, - { - test: 'This is a long text input', - }, - false, - ), - ).toEqual({}); - }); - - it('should do nothing when validate is not an object nor function', async () => { - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { - type: 'text', - name: 'test', - }, - value: 'This is a long text input', - // @ts-expect-error - validate: 'validate', - }, - }, - 'This is a long text input', - false, - ), - ).toEqual({}); - }); - - it('should return all validation errors', async () => { - (getRadioValue as jest.Mock).mockImplementation(() => ({ - value: '', - })); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'text', name: 'test' }, - value: '', - required: true, - minLength: 10, - pattern: /d/i, - validate: (value) => value === 'test', - }, - }, - { - test: '', - }, - true, - ), - ).toEqual({ - test: { - message: '', - ref: { - name: 'test', - type: 'text', - }, - type: 'required', - types: { - required: true, - validate: true, - }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'text', name: 'test' }, - value: '123', - required: true, - minLength: 10, - pattern: /d/i, - validate: (value) => value === 'test', - }, - }, - { - test: '123', - }, - true, - ), - ).toEqual({ - test: { - message: '', - ref: { - name: 'test', - type: 'text', - }, - type: 'minLength', - types: { - minLength: true, - pattern: true, - validate: true, - }, - }, - }); - }); - - it('should handle pattern with g flag', async () => { - const reusedRe = /a/g; - - (getRadioValue as jest.Mock).mockImplementation(() => ({ - value: '', - })); - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'text', name: 'test' }, - value: 'a', - required: true, - minLength: 10, - pattern: reusedRe, - validate: (value) => value === 'test', - }, - }, - { - test: 'a', - }, - true, - ), - ).toEqual({ - test: { - message: '', - ref: { - name: 'test', - type: 'text', - }, - type: 'minLength', - types: { - minLength: true, - validate: true, - }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'text', name: 'test' }, - value: 'a', - required: true, - minLength: 10, - pattern: reusedRe, - validate: (value) => value === 'test', - }, - }, - { - test: 'a', - }, - true, - ), - ).toEqual({ - test: { - message: '', - ref: { - name: 'test', - type: 'text', - }, - type: 'minLength', - types: { - minLength: true, - validate: true, - }, - }, - }); - }); - - it('should return all validation error messages', async () => { - (getRadioValue as jest.Mock).mockImplementation(() => ({ - value: '', - })); - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'text', name: 'test' }, - value: '', - required: 'test', - minLength: { - value: 10, - message: 'minLength', - }, - pattern: { - value: /d/i, - message: 'pattern', - }, - validate: { - test: (value) => value === 'test', - test1: (value) => value == 'test' || 'Luo', - test2: (value) => value == 'test' || 'Bill', - }, - }, - }, - { - test: '', - }, - true, - ), - ).toEqual({ - test: { - message: 'test', - ref: { - name: 'test', - type: 'text', - }, - type: 'required', - types: { - required: 'test', - test: true, - test1: 'Luo', - test2: 'Bill', - }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'text', name: 'test' }, - value: 'bil', - required: 'test', - minLength: { - value: 10, - message: 'minLength', - }, - pattern: { - value: /d/i, - message: 'pattern', - }, - validate: { - test: (value) => value === 'test', - test1: (value) => value == 'test' || 'Luo', - test2: (value) => value == 'test' || 'Bill', - }, - }, - }, - { - test: 'bil', - }, - true, - ), - ).toEqual({ - test: { - message: 'minLength', - ref: { - name: 'test', - type: 'text', - }, - type: 'minLength', - types: { - minLength: 'minLength', - pattern: 'pattern', - test: true, - test1: 'Luo', - test2: 'Bill', - }, - }, - }); - - expect( - await validateField( - { - _f: { - mount: true, - name: 'test', - ref: { type: 'text', name: 'test' }, - value: 'bil', - required: 'test', - minLength: { - value: 10, - message: 'minLength', - }, - pattern: { - value: /d/i, - message: 'pattern', - }, - validate: { - test: (value) => value === 'test', - test1: (value) => value == 'test' || 'Luo', - test2: (value) => value == 'test' || 'Bill', - }, - }, - }, - { - test: 'bil', - }, - true, - ), - ).toEqual({ - test: { - message: 'minLength', - ref: { - name: 'test', - type: 'text', - }, - type: 'minLength', - types: { - minLength: 'minLength', - pattern: 'pattern', - test: true, - test1: 'Luo', - test2: 'Bill', - }, - }, - }); - }); - - describe('with Browser native validation', () => { - it('should invoke setCustomValidity for invalid input', () => { - const setCustomValidity = jest.fn(); - const reportValidity = jest.fn(); - - validateField( - { - _f: { - name: 'test', - ref: { - setCustomValidity, - reportValidity, - name: 'test', - value: '', - }, - value: '', - required: true, - mount: true, - }, - }, - { - test: '', - }, - false, - true, - ); - - expect(setCustomValidity).toBeCalledWith(''); - expect(reportValidity).toBeCalled(); - }); - - it('should invoke setCustomValidity for invalid input with its message', () => { - const setCustomValidity = jest.fn(); - const reportValidity = jest.fn(); - - validateField( - { - _f: { - name: 'test', - ref: { - setCustomValidity, - reportValidity, - name: 'test', - value: '', - }, - value: '', - required: 'something is wrong', - mount: true, - }, - }, - { - test: '', - }, - false, - true, - ); - - expect(setCustomValidity).toBeCalledWith('something is wrong'); - expect(reportValidity).toBeCalled(); - }); - - it('should invoke setCustomValidity with empty string for a valid input', () => { - const setCustomValidity = jest.fn(); - const reportValidity = jest.fn(); - - validateField( - { - _f: { - name: 'test', - ref: { - setCustomValidity, - reportValidity, - name: 'test', - value: 'test', - }, - value: 'test', - required: true, - mount: true, - }, - }, - { - test: 'test', - }, - false, - true, - ); - - expect(setCustomValidity).toBeCalledWith(''); - expect(reportValidity).toBeCalled(); - }); - - it('should abort validation early when input is disabled', async () => { - expect( - await validateField( - { - _f: { - name: 'test', - ref: { - name: 'test', - value: '', - }, - value: '', - required: 'something is wrong', - disabled: true, - }, - }, - { - test: '', - }, - false, - ), - ).toEqual({}); - }); - }); - - it('should validate field array with required attribute', async () => { - expect( - await validateField( - { - _f: { - name: 'test', - ref: { - name: 'test', - value: '', - }, - value: undefined, - required: true, - mount: true, - }, - }, - { - test: undefined, - }, - false, - false, - true, - ), - ).toEqual({ - test: { - message: '', - ref: { - name: 'test', - value: '', - }, - type: 'required', - }, - }); - - expect( - await validateField( - { - _f: { - name: 'test', - ref: { - name: 'test', - value: '', - }, - value: [], - required: true, - mount: true, - }, - }, - [], - false, - false, - true, - ), - ).toEqual({ - test: { - message: '', - ref: { - name: 'test', - value: '', - }, - type: 'required', - }, - }); - - expect( - await validateField( - { - _f: { - name: 'test', - ref: { - name: 'test', - value: '', - }, - value: null, - required: true, - mount: true, - }, - }, - { - test: null, - }, - false, - false, - true, - ), - ).toEqual({ - test: { - message: '', - ref: { - name: 'test', - value: '', - }, - type: 'required', - }, - }); - - expect( - await validateField( - { - _f: { - name: 'test', - ref: { - name: 'test', - value: '', - }, - value: [], - required: true, - mount: true, - }, - }, - { - test: [{}], - }, - false, - false, - true, - ), - ).toEqual({}); - }); -}); diff --git a/src/__tests__/type.test.tsx b/src/__tests__/type.test.tsx index 6c922ee1572..83f0f84d64d 100644 --- a/src/__tests__/type.test.tsx +++ b/src/__tests__/type.test.tsx @@ -1,6 +1,4 @@ import React from 'react'; - -import { Controller } from '../controller'; import { FieldErrors, FieldPath, @@ -8,7 +6,9 @@ import { Path, PathValue, UseFormRegister, -} from '../types'; +} from '@hookform/core'; + +import { Controller } from '../controller'; import { useController } from '../useController'; import { useFieldArray } from '../useFieldArray'; import { useForm } from '../useForm'; diff --git a/src/__tests__/useController.test.tsx b/src/__tests__/useController.test.tsx index 8a97e9e7ac8..8472a2a5e25 100644 --- a/src/__tests__/useController.test.tsx +++ b/src/__tests__/useController.test.tsx @@ -1,8 +1,8 @@ import React from 'react'; +import { Control, FieldPath, FieldValues } from '@hookform/core'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { Controller } from '../controller'; -import { Control, FieldPath, FieldValues } from '../types'; import { useController } from '../useController'; import { useForm } from '../useForm'; import { FormProvider, useFormContext } from '../useFormContext'; diff --git a/src/__tests__/useFieldArray.test.tsx b/src/__tests__/useFieldArray.test.tsx index 700a5515c0a..339929f53f0 100644 --- a/src/__tests__/useFieldArray.test.tsx +++ b/src/__tests__/useFieldArray.test.tsx @@ -1,4 +1,11 @@ import React from 'react'; +import { + Control, + FieldValues, + SubmitHandler, + UseFormRegister, + UseFormReturn, +} from '@hookform/core'; import { act as actComponent, fireEvent, @@ -9,27 +16,12 @@ import { import { act, renderHook } from '@testing-library/react-hooks'; import { Controller } from '../controller'; -import { - Control, - FieldValues, - SubmitHandler, - UseFormRegister, - UseFormReturn, -} from '../types'; import { useFieldArray } from '../useFieldArray'; import { useForm } from '../useForm'; import { FormProvider } from '../useFormContext'; import { useFormState } from '../useFormState'; -let i = 0; - -jest.mock('../logic/generateId', () => () => String(i++)); - describe('useFieldArray', () => { - beforeEach(() => { - i = 0; - }); - describe('initialize', () => { it('should return default fields value', () => { const { result } = renderHook(() => { @@ -55,8 +47,8 @@ describe('useFieldArray', () => { }); expect(result.current.fields).toEqual([ - { test: '1', id: '0' }, - { test: '2', id: '1' }, + { test: '1', id: expect.any(String) }, + { test: '2', id: expect.any(String) }, ]); }); @@ -637,14 +629,16 @@ describe('useFieldArray', () => { const { unmount } = render(); - expect(fieldsTemp).toEqual([{ id: '0', value: 'default' }]); + expect(fieldsTemp).toEqual([ + { id: expect.any(String), value: 'default' }, + ]); fireEvent.click(screen.getByRole('button')); expect(fieldsTemp).toEqual([ - { id: '0', value: 'default' }, + { id: expect.any(String), value: 'default' }, { - id: '1', + id: expect.any(String), value: 'test', }, ]); @@ -653,9 +647,9 @@ describe('useFieldArray', () => { expect(controlTemp._names.array).toEqual(new Set(['test'])); expect(fieldsTemp).toEqual([ - { id: '0', value: 'default' }, + { id: expect.any(String), value: 'default' }, { - id: '1', + id: expect.any(String), value: 'test', }, ]); @@ -956,7 +950,9 @@ describe('useFieldArray', () => { fireEvent.click(screen.getByRole('button', { name: 'reset' })); - expect(fieldsTemp).toEqual([{ id: '4', value: 'default' }]); + expect(fieldsTemp).toEqual([ + { id: expect.any(String), value: 'default' }, + ]); }); it('should reset with field array with shouldUnregister set to false', () => { @@ -983,7 +979,9 @@ describe('useFieldArray', () => { result.current.reset(); }); - expect(result.current.fields).toEqual([{ id: '4', value: 'default' }]); + expect(result.current.fields).toEqual([ + { id: expect.any(String), value: 'default' }, + ]); act(() => { result.current.reset({ @@ -991,7 +989,9 @@ describe('useFieldArray', () => { }); }); - expect(result.current.fields).toEqual([{ id: '6', value: 'data' }]); + expect(result.current.fields).toEqual([ + { id: expect.any(String), value: 'data' }, + ]); }); it('should reset with async', async () => { diff --git a/src/__tests__/useFieldArray/append.test.tsx b/src/__tests__/useFieldArray/append.test.tsx index 60c0735b028..e58eb25748a 100644 --- a/src/__tests__/useFieldArray/append.test.tsx +++ b/src/__tests__/useFieldArray/append.test.tsx @@ -1,22 +1,13 @@ import React from 'react'; +import { Control, FieldPath, VALIDATION_MODE } from '@hookform/core'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react-hooks'; -import { VALIDATION_MODE } from '../../constants'; -import { Control, FieldPath } from '../../types'; import { useController } from '../../useController'; import { useFieldArray } from '../../useFieldArray'; import { useForm } from '../../useForm'; -let i = 0; - -jest.mock('../../logic/generateId', () => () => String(i++)); - describe('append', () => { - beforeEach(() => { - i = 0; - }); - it('should append dirtyFields fields correctly', async () => { let dirtyInputs = {}; const Component = () => { @@ -117,22 +108,22 @@ describe('append', () => { fireEvent.click(screen.getByRole('button', { name: 'append' })); - expect(currentFields).toEqual([{ id: '0', test: 'test' }]); + expect(currentFields).toEqual([{ id: expect.any(String), test: 'test' }]); fireEvent.click(screen.getByRole('button', { name: 'append' })); expect(currentFields).toEqual([ - { id: '0', test: 'test' }, - { id: '2', test: 'test' }, + { id: expect.any(String), test: 'test' }, + { id: expect.any(String), test: 'test' }, ]); fireEvent.click(screen.getByRole('button', { name: 'appendBatch' })); expect(currentFields).toEqual([ - { id: '0', test: 'test' }, - { id: '2', test: 'test' }, - { id: '5', test: 'test-batch' }, - { id: '6', test: 'test-batch1' }, + { id: expect.any(String), test: 'test' }, + { id: expect.any(String), test: 'test' }, + { id: expect.any(String), test: 'test-batch' }, + { id: expect.any(String), test: 'test-batch1' }, ]); }); diff --git a/src/__tests__/useFieldArray/insert.test.tsx b/src/__tests__/useFieldArray/insert.test.tsx index aa30c93af65..b80c65b008f 100644 --- a/src/__tests__/useFieldArray/insert.test.tsx +++ b/src/__tests__/useFieldArray/insert.test.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { Control, FieldPath, VALIDATION_MODE } from '@hookform/core'; import { act as actComponent, fireEvent, @@ -8,23 +9,13 @@ import { } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react-hooks'; -import { VALIDATION_MODE } from '../../constants'; -import { Control, FieldPath } from '../../types'; import { useController } from '../../useController'; import { useFieldArray } from '../../useFieldArray'; import { useForm } from '../../useForm'; jest.useFakeTimers(); -let i = 0; - -jest.mock('../../logic/generateId', () => () => String(i++)); - describe('insert', () => { - beforeEach(() => { - i = 0; - }); - it('should insert data at index with single value', () => { const { result } = renderHook(() => { const { control } = useForm({ @@ -44,9 +35,9 @@ describe('insert', () => { }); expect(result.current.fields).toEqual([ - { id: '0', test: '1' }, - { id: '2', test: '3' }, - { id: '1', test: '2' }, + { id: expect.any(String), test: '1' }, + { id: expect.any(String), test: '3' }, + { id: expect.any(String), test: '2' }, ]); }); @@ -69,10 +60,10 @@ describe('insert', () => { }); expect(result.current.fields).toEqual([ - { id: '0', test: '1' }, - { id: '2', test: '3' }, - { id: '3', test: '4' }, - { id: '1', test: '2' }, + { id: expect.any(String), test: '1' }, + { id: expect.any(String), test: '3' }, + { id: expect.any(String), test: '4' }, + { id: expect.any(String), test: '2' }, ]); }); diff --git a/src/__tests__/useFieldArray/move.test.tsx b/src/__tests__/useFieldArray/move.test.tsx index acbaf073ab2..686d2085ff2 100644 --- a/src/__tests__/useFieldArray/move.test.tsx +++ b/src/__tests__/useFieldArray/move.test.tsx @@ -1,20 +1,12 @@ import React from 'react'; +import { VALIDATION_MODE } from '@hookform/core'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react-hooks'; -import { VALIDATION_MODE } from '../../constants'; import { useFieldArray } from '../../useFieldArray'; import { useForm } from '../../useForm'; -let i = 0; - -jest.mock('../../logic/generateId', () => () => String(i++)); - describe('move', () => { - beforeEach(() => { - i = 0; - }); - it.each(['isDirty', 'dirtyFields'])( 'should move dirtyFields into pointed position when formState.%s is defined', () => { diff --git a/src/__tests__/useFieldArray/prepend.test.tsx b/src/__tests__/useFieldArray/prepend.test.tsx index 7774d2d35fc..bcf1b2a7329 100644 --- a/src/__tests__/useFieldArray/prepend.test.tsx +++ b/src/__tests__/useFieldArray/prepend.test.tsx @@ -1,22 +1,13 @@ import React from 'react'; +import { Control, FieldPath, VALIDATION_MODE } from '@hookform/core'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react-hooks'; -import { VALIDATION_MODE } from '../../constants'; -import { Control, FieldPath } from '../../types'; import { useController } from '../../useController'; import { useFieldArray } from '../../useFieldArray'; import { useForm } from '../../useForm'; -let i = 0; - -jest.mock('../../logic/generateId', () => () => String(i++)); - describe('prepend', () => { - beforeEach(() => { - i = 0; - }); - it('should pre-append data into the fields', async () => { let currentFields: any = []; @@ -59,22 +50,22 @@ describe('prepend', () => { fireEvent.click(screen.getByRole('button', { name: 'prepend' })); - expect(currentFields).toEqual([{ id: '0', test: 'test' }]); + expect(currentFields).toEqual([{ id: expect.any(String), test: 'test' }]); fireEvent.click(screen.getByRole('button', { name: 'prepend' })); expect(currentFields).toEqual([ - { id: '2', test: 'test' }, - { id: '0', test: 'test' }, + { id: expect.any(String), test: 'test' }, + { id: expect.any(String), test: 'test' }, ]); fireEvent.click(screen.getByRole('button', { name: 'prependBatch' })); expect(currentFields).toEqual([ - { id: '5', test: 'test-batch' }, - { id: '6', test: 'test-batch1' }, - { id: '2', test: 'test' }, - { id: '0', test: 'test' }, + { id: expect.any(String), test: 'test-batch' }, + { id: expect.any(String), test: 'test-batch1' }, + { id: expect.any(String), test: 'test' }, + { id: expect.any(String), test: 'test' }, ]); }); diff --git a/src/__tests__/useFieldArray/remove.test.tsx b/src/__tests__/useFieldArray/remove.test.tsx index 672d3978514..35dd038dc25 100644 --- a/src/__tests__/useFieldArray/remove.test.tsx +++ b/src/__tests__/useFieldArray/remove.test.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { Control, DeepMap, FieldError, VALIDATION_MODE } from '@hookform/core'; import { act as actComponent, fireEvent, @@ -8,23 +9,13 @@ import { } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react-hooks'; -import { VALIDATION_MODE } from '../../constants'; import { Controller } from '../../controller'; -import { Control, DeepMap, FieldError } from '../../types'; import { useFieldArray } from '../../useFieldArray'; import { useForm } from '../../useForm'; jest.useFakeTimers(); -let i = 0; - -jest.mock('../../logic/generateId', () => () => String(i++)); - describe('remove', () => { - beforeEach(() => { - i = 0; - }); - it('should update isDirty formState when item removed', () => { let formState: any; const Component = () => { @@ -166,7 +157,9 @@ describe('remove', () => { result.current.remove(1); }); - expect(result.current.fields).toEqual([{ id: '0', value: 'default' }]); + expect(result.current.fields).toEqual([ + { id: expect.any(String), value: 'default' }, + ]); act(() => { result.current.remove(0); diff --git a/src/__tests__/useFieldArray/replace.test.tsx b/src/__tests__/useFieldArray/replace.test.tsx index 6bc46c5579e..9fac303fbb7 100644 --- a/src/__tests__/useFieldArray/replace.test.tsx +++ b/src/__tests__/useFieldArray/replace.test.tsx @@ -14,15 +14,7 @@ interface DefaultValues { test: TestValue[]; } -let i = 0; - -jest.mock('../../logic/generateId', () => () => String(i++)); - describe('replace', () => { - beforeEach(() => { - i = 0; - }); - it('should replace fields correctly', () => { let currentFields: any = []; const defaultValues: DefaultValues = { @@ -69,13 +61,13 @@ describe('replace', () => { fireEvent.click(screen.getByRole('button', { name: labelSingle })); - expect(currentFields).toEqual([{ id: '3', x: '201' }]); + expect(currentFields).toEqual([{ id: expect.any(String), x: '201' }]); fireEvent.click(screen.getByRole('button', { name: labelBatch })); expect(currentFields).toEqual([ - { id: '5', x: '301' }, - { id: '6', x: '302' }, + { id: expect.any(String), x: '301' }, + { id: expect.any(String), x: '302' }, ]); }); it('should not omit keyName when provided', async () => { diff --git a/src/__tests__/useFieldArray/swap.test.tsx b/src/__tests__/useFieldArray/swap.test.tsx index 3ee8a0ab1c6..789c089f335 100644 --- a/src/__tests__/useFieldArray/swap.test.tsx +++ b/src/__tests__/useFieldArray/swap.test.tsx @@ -1,20 +1,12 @@ import React from 'react'; +import { VALIDATION_MODE } from '@hookform/core'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react-hooks'; -import { VALIDATION_MODE } from '../../constants'; import { useFieldArray } from '../../useFieldArray'; import { useForm } from '../../useForm'; -let i = 0; - -jest.mock('../../logic/generateId', () => () => String(i++)); - describe('swap', () => { - beforeEach(() => { - i = 0; - }); - it('should swap into pointed position', () => { const { result } = renderHook(() => { const { register, control } = useForm({ @@ -37,8 +29,8 @@ describe('swap', () => { }); expect(result.current.fields).toEqual([ - { id: '1', value: '2' }, - { id: '0', value: '1' }, + { id: expect.any(String), value: '2' }, + { id: expect.any(String), value: '1' }, ]); }); @@ -64,8 +56,8 @@ describe('swap', () => { }); expect(result.current.fields).toEqual([ - { id: '1', value: '2' }, - { id: '0', value: '1' }, + { id: expect.any(String), value: '2' }, + { id: expect.any(String), value: '1' }, ]); }); diff --git a/src/__tests__/useFieldArray/update.test.tsx b/src/__tests__/useFieldArray/update.test.tsx index ac6fb8cca16..d4e4cf8f704 100644 --- a/src/__tests__/useFieldArray/update.test.tsx +++ b/src/__tests__/useFieldArray/update.test.tsx @@ -1,22 +1,13 @@ import React from 'react'; +import { Control, VALIDATION_MODE } from '@hookform/core'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react-hooks'; -import { VALIDATION_MODE } from '../../constants'; -import { Control } from '../../types'; import { useController } from '../../useController'; import { useFieldArray } from '../../useFieldArray'; import { useForm } from '../../useForm'; -let i = 0; - -jest.mock('../../logic/generateId', () => () => String(i++)); - describe('update', () => { - beforeEach(() => { - i = 0; - }); - it('should update dirtyFields fields correctly', async () => { let dirtyInputs = {}; const Component = () => { @@ -302,7 +293,7 @@ describe('update', () => { expect(fieldArrayValues.at(-1)).toEqual([ { - id: '0', + id: expect.any(String), value: { firstName: 'bill', lastName: 'luo', @@ -323,7 +314,7 @@ describe('update', () => { expect(fieldArrayValues).toEqual([ [ { - id: '0', + id: expect.any(String), value: { firstName: 'bill', lastName: 'luo', @@ -332,7 +323,7 @@ describe('update', () => { ], [ { - id: '1', + id: expect.any(String), value: { firstName: 'firstName', lastName: 'lastName', @@ -438,12 +429,12 @@ describe('update', () => { expect(fieldArrayValues).toEqual([ { firstName: 'bill', - id: '0', + id: expect.any(String), lastName: 'luo', }, { firstName: 'bill1', - id: '1', + id: expect.any(String), lastName: 'luo1', }, ]); @@ -466,12 +457,12 @@ describe('update', () => { expect(fieldArrayValues).toEqual([ { firstName: 'test1', - id: '2', + id: expect.any(String), lastName: 'test2', }, { firstName: 'test3', - id: '3', + id: expect.any(String), lastName: 'test4', }, ]); diff --git a/src/__tests__/useForm.test.tsx b/src/__tests__/useForm.test.tsx index 668226be406..e9b28878b26 100644 --- a/src/__tests__/useForm.test.tsx +++ b/src/__tests__/useForm.test.tsx @@ -1,4 +1,12 @@ import React from 'react'; +import { + Control, + isFunction, + RegisterOptions, + UseFormRegister, + UseFormReturn, + VALIDATION_MODE, +} from '@hookform/core'; import { act as actComponent, fireEvent, @@ -9,14 +17,6 @@ import { } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react-hooks'; -import { VALIDATION_MODE } from '../constants'; -import { - Control, - RegisterOptions, - UseFormRegister, - UseFormReturn, -} from '../types'; -import isFunction from '../utils/isFunction'; import { sleep } from '../utils/sleep'; import { Controller, useFieldArray, useForm } from '../'; diff --git a/src/__tests__/useForm/formState.test.tsx b/src/__tests__/useForm/formState.test.tsx index 0a6ef34dbac..0b5a6e2860c 100644 --- a/src/__tests__/useForm/formState.test.tsx +++ b/src/__tests__/useForm/formState.test.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { VALIDATION_MODE } from '@hookform/core'; import { act as actComponent, fireEvent, @@ -8,7 +9,6 @@ import { } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react-hooks'; -import { VALIDATION_MODE } from '../../constants'; import { Controller } from '../../controller'; import { useFieldArray } from '../../useFieldArray'; import { useForm } from '../../useForm'; diff --git a/src/__tests__/useForm/getFieldState.test.tsx b/src/__tests__/useForm/getFieldState.test.tsx index 2e55bda8423..5c052cc5622 100644 --- a/src/__tests__/useForm/getFieldState.test.tsx +++ b/src/__tests__/useForm/getFieldState.test.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; +import { Control } from '@hookform/core'; import { fireEvent, render, screen } from '@testing-library/react'; -import { Control } from '../../types'; import { useController } from '../../useController'; import { useForm } from '../../useForm'; diff --git a/src/__tests__/useForm/handleSubmit.test.tsx b/src/__tests__/useForm/handleSubmit.test.tsx index a5d98cf00e8..9e11a427488 100644 --- a/src/__tests__/useForm/handleSubmit.test.tsx +++ b/src/__tests__/useForm/handleSubmit.test.tsx @@ -1,11 +1,10 @@ import React from 'react'; +import { isFunction, VALIDATION_MODE } from '@hookform/core'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react-hooks'; -import { VALIDATION_MODE } from '../../constants'; import { useFieldArray } from '../../useFieldArray'; import { useForm } from '../../useForm'; -import isFunction from '../../utils/isFunction'; describe('handleSubmit', () => { it('should invoke the callback when validation pass', async () => { diff --git a/src/__tests__/useForm/register.test.tsx b/src/__tests__/useForm/register.test.tsx index 6d1001b050f..0d75fbb4774 100644 --- a/src/__tests__/useForm/register.test.tsx +++ b/src/__tests__/useForm/register.test.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { isFunction, UseFormRegister, VALIDATION_MODE } from '@hookform/core'; import { fireEvent, render, @@ -8,13 +9,9 @@ import { } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react-hooks'; -import { VALIDATION_MODE } from '../../constants'; import { Controller } from '../../controller'; -import { UseFormRegister } from '../../types'; import { useForm } from '../../useForm'; import { FormProvider, useFormContext } from '../../useFormContext'; -import isFunction from '../../utils/isFunction'; -import isString from '../../utils/isString'; describe('register', () => { it('should support register passed to ref', async () => { @@ -1106,7 +1103,7 @@ describe('register', () => { { - return !isString(data); + return !(typeof data === 'string'); }, })} /> diff --git a/src/__tests__/useForm/reset.test.tsx b/src/__tests__/useForm/reset.test.tsx index 834e89fa51c..75b543bb3ce 100644 --- a/src/__tests__/useForm/reset.test.tsx +++ b/src/__tests__/useForm/reset.test.tsx @@ -1,4 +1,10 @@ import React from 'react'; +import { + Control, + UseFormRegister, + UseFormReset, + UseFormReturn, +} from '@hookform/core'; import { act as actComponent, fireEvent, @@ -9,12 +15,6 @@ import { import { act, renderHook } from '@testing-library/react-hooks'; import { Controller } from '../../controller'; -import { - Control, - UseFormRegister, - UseFormReset, - UseFormReturn, -} from '../../types'; import { useController } from '../../useController'; import { useFieldArray } from '../../useFieldArray'; import { useForm } from '../../useForm'; diff --git a/src/__tests__/useForm/setError.test.tsx b/src/__tests__/useForm/setError.test.tsx index 8486c13bd68..4889701530b 100644 --- a/src/__tests__/useForm/setError.test.tsx +++ b/src/__tests__/useForm/setError.test.tsx @@ -1,8 +1,8 @@ import React from 'react'; +import { DeepMap, ErrorOption, FieldError, GlobalError } from '@hookform/core'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react-hooks'; -import { DeepMap, ErrorOption, FieldError, GlobalError } from '../../types'; import { useForm } from '../../useForm'; describe('setError', () => { diff --git a/src/__tests__/useForm/setValue.test.tsx b/src/__tests__/useForm/setValue.test.tsx index 1e0ae9a9f9f..91463dcee0c 100644 --- a/src/__tests__/useForm/setValue.test.tsx +++ b/src/__tests__/useForm/setValue.test.tsx @@ -1,14 +1,11 @@ import React from 'react'; +import { Control, get, isFunction, VALIDATION_MODE } from '@hookform/core'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react-hooks'; -import { VALIDATION_MODE } from '../../constants'; import { Controller } from '../../controller'; -import { Control } from '../../types'; import { useFieldArray } from '../../useFieldArray'; import { useForm } from '../../useForm'; -import get from '../../utils/get'; -import isFunction from '../../utils/isFunction'; import { sleep } from '../../utils/sleep'; jest.useFakeTimers(); diff --git a/src/__tests__/useForm/trigger.test.tsx b/src/__tests__/useForm/trigger.test.tsx index 470ff4cec46..42219eee322 100644 --- a/src/__tests__/useForm/trigger.test.tsx +++ b/src/__tests__/useForm/trigger.test.tsx @@ -1,9 +1,8 @@ import React from 'react'; +import { Control, FieldPath, VALIDATION_MODE } from '@hookform/core'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react-hooks'; -import { VALIDATION_MODE } from '../../constants'; -import { Control, FieldPath } from '../../types'; import { useController } from '../../useController'; import { useForm } from '../../useForm'; import { FormProvider } from '../../useFormContext'; diff --git a/src/__tests__/useForm/watch.test.tsx b/src/__tests__/useForm/watch.test.tsx index 77ac01058ba..49b352142c0 100644 --- a/src/__tests__/useForm/watch.test.tsx +++ b/src/__tests__/useForm/watch.test.tsx @@ -1,13 +1,12 @@ import React from 'react'; +import { Control, FieldValues, isFunction } from '@hookform/core'; import { fireEvent, render, screen } from '@testing-library/react'; import { act, renderHook } from '@testing-library/react-hooks'; import { Controller } from '../../controller'; -import { Control, FieldValues } from '../../types'; import { useFieldArray } from '../../useFieldArray'; import { useForm } from '../../useForm'; import { useWatch } from '../../useWatch'; -import isFunction from '../../utils/isFunction'; describe('watch', () => { it('should return undefined when input gets unregister', async () => { diff --git a/src/__tests__/useFormContext.test.tsx b/src/__tests__/useFormContext.test.tsx index 3e28d84ca61..93669c965e4 100644 --- a/src/__tests__/useFormContext.test.tsx +++ b/src/__tests__/useFormContext.test.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { deepEqual } from '@hookform/core'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { useController } from '../useController'; @@ -6,7 +7,6 @@ import { useForm } from '../useForm'; import { FormProvider, useFormContext } from '../useFormContext'; import { useFormState } from '../useFormState'; import { useWatch } from '../useWatch'; -import deepEqual from '../utils/deepEqual'; describe('FormProvider', () => { it('should have access to all methods with useFormContext', () => { diff --git a/src/__tests__/useFormState.test.tsx b/src/__tests__/useFormState.test.tsx index 96454b4ebbe..affb693d732 100644 --- a/src/__tests__/useFormState.test.tsx +++ b/src/__tests__/useFormState.test.tsx @@ -1,13 +1,12 @@ import React from 'react'; +import { Control, deepEqual } from '@hookform/core'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { Controller } from '../controller'; -import { Control } from '../types'; import { useFieldArray } from '../useFieldArray'; import { useForm } from '../useForm'; import { FormProvider } from '../useFormContext'; import { useFormState } from '../useFormState'; -import deepEqual from '../utils/deepEqual'; describe('useFormState', () => { it('should render correct form state with isDirty, dirty, touched', () => { diff --git a/src/__tests__/useWatch.test.tsx b/src/__tests__/useWatch.test.tsx index cae3e99f26e..f57ece1aea7 100644 --- a/src/__tests__/useWatch.test.tsx +++ b/src/__tests__/useWatch.test.tsx @@ -1,4 +1,10 @@ import React from 'react'; +import { + Control, + UseFieldArrayReturn, + UseFormRegister, + UseFormReturn, +} from '@hookform/core'; import { fireEvent, render, @@ -8,27 +14,13 @@ import { } from '@testing-library/react'; import { renderHook } from '@testing-library/react-hooks'; -import { - Control, - UseFieldArrayReturn, - UseFormRegister, - UseFormReturn, -} from '../types'; import { useController } from '../useController'; import { useFieldArray } from '../useFieldArray'; import { useForm } from '../useForm'; import { FormProvider, useFormContext } from '../useFormContext'; import { useWatch } from '../useWatch'; -let i = 0; - -jest.mock('../logic/generateId', () => () => String(i++)); - describe('useWatch', () => { - beforeEach(() => { - i = 0; - }); - it('should return default value in useForm', () => { let method; let watched; @@ -1016,7 +1008,17 @@ describe('useWatch', () => { screen.queryByText('Value 2: ShouldBeTHere'), ).not.toBeInTheDocument(); - expect(watchData).toMatchSnapshot(); + expect(watchData).toEqual([ + [ + { prop: 'test', id: expect.any(String) }, + { prop: 'test1', id: expect.any(String) }, + ], + [{ prop: 'test' }, { prop: 'test1' }], + [{ prop: 'test' }, { prop: 'test1' }], + [{ prop: 'test' }, { prop: 'ShouldBeTHere' }, { prop: 'test1' }], + [{ prop: 'test' }, { prop: 'ShouldBeTHere' }, { prop: 'test1' }], + [{ prop: 'ShouldBeTHere' }, { prop: 'test1' }], + ]); }); }); diff --git a/src/__tests__/utils/cloneObject.test.ts b/src/__tests__/utils/cloneObject.test.ts deleted file mode 100644 index 609cfcaac45..00000000000 --- a/src/__tests__/utils/cloneObject.test.ts +++ /dev/null @@ -1,117 +0,0 @@ -import cloneObject from '../../utils/cloneObject'; - -describe('clone', () => { - it('should clone object and not mutate the original object', () => { - const fileData = new File([''], 'filename'); - const data = { - items: [], - test: { - date: new Date('2020-10-15'), - test0: 12, - test1: '12', - test2: [1, 2, 3, 4], - deep: { - date: new Date('2020-10-15'), - test0: 12, - test1: '12', - test2: [ - 1, - 2, - 3, - 4, - { - file: fileData, - }, - ], - file: fileData, - }, - }, - file: fileData, - test2: new Set([1, 2]), - test1: new Map([ - [1, 'one'], - [2, 'two'], - [3, 'three'], - ]), - }; - - const copy = cloneObject(data); - expect(cloneObject(data)).toEqual(copy); - - // @ts-expect-error - copy.test.what = '1243'; - copy.test.date = new Date('2020-10-16'); - // @ts-expect-error - copy.items[0] = 2; - - expect(data).toEqual({ - items: [], - test: { - date: new Date('2020-10-15'), - test0: 12, - test1: '12', - test2: [1, 2, 3, 4], - deep: { - date: new Date('2020-10-15'), - test0: 12, - test1: '12', - test2: [ - 1, - 2, - 3, - 4, - { - file: fileData, - }, - ], - file: fileData, - }, - }, - file: fileData, - test2: new Set([1, 2]), - test1: new Map([ - [1, 'one'], - [2, 'two'], - [3, 'three'], - ]), - }); - - // @ts-expect-error - data.items = [1, 2, 3]; - - expect(copy.items).toEqual([2]); - }); - - it('should skip clone if a node is instance of function', () => { - function testFunction() {} - - const data = { - test: { - testFunction, - test: 'inner-string', - deep: { - testFunction, - test: 'deep-string', - }, - }, - testFunction, - other: 'string', - }; - - const copy = cloneObject(data); - data.test.deep.test = 'changed-deep-string'; - - expect(copy).toEqual({ - test: { - test: 'inner-string', - deep: { - testFunction, - test: 'deep-string', - }, - testFunction, - }, - testFunction, - other: 'string', - }); - }); -}); diff --git a/src/__tests__/utils/compact.test.ts b/src/__tests__/utils/compact.test.ts deleted file mode 100644 index 52f39f86100..00000000000 --- a/src/__tests__/utils/compact.test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import filterOutFalsy from '../../utils/compact'; - -describe('filterOutFalsy', () => { - it('should return filtered array when array value is falsy ', () => { - expect(filterOutFalsy([1, 2, 3, 4])).toEqual([1, 2, 3, 4]); - expect(filterOutFalsy([1, 2, false, 4])).toEqual([1, 2, 4]); - expect(filterOutFalsy([1, 2, '', 4])).toEqual([1, 2, 4]); - expect(filterOutFalsy([1, 2, undefined, 4])).toEqual([1, 2, 4]); - expect(filterOutFalsy([0, 1, 2, 3, 4])).toEqual([1, 2, 3, 4]); - }); -}); diff --git a/src/__tests__/utils/createSubject.test.ts b/src/__tests__/utils/createSubject.test.ts deleted file mode 100644 index c80fb89eebd..00000000000 --- a/src/__tests__/utils/createSubject.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import createSubject from '../../utils/createSubject'; - -describe('createSubject', () => { - it('should subscribe to all the correct observer', () => { - const subject = createSubject(); - const next = jest.fn(); - - subject.subscribe({ - next, - }); - - subject.subscribe({ - next, - }); - - expect(subject.observers.length).toBe(2); - - subject.next(2); - - expect(next).toBeCalledTimes(2); - expect(next).toBeCalledWith(2); - }); - - it('should unsubscribe observers', () => { - const subject = createSubject(); - const next1 = jest.fn(); - const next2 = jest.fn(); - - const subscription = subject.subscribe({ - next: next1, - }); - - subject.subscribe({ - next: next2, - }); - - expect(subject.observers.length).toBe(2); - - subscription.unsubscribe(); - - expect(subject.observers.length).toBe(1); - - subject.next(2); - - expect(next1).not.toBeCalled(); - expect(next2).toBeCalledWith(2); - }); - - it('should unsubscribe all observers', () => { - const subject = createSubject(); - const next = jest.fn(); - - subject.subscribe({ - next, - }); - - subject.subscribe({ - next, - }); - - expect(subject.observers.length).toBe(2); - - subject.unsubscribe(); - - expect(subject.observers.length).toBe(0); - - subject.next(2); - subject.next(2); - - expect(next).not.toBeCalled(); - }); -}); diff --git a/src/__tests__/utils/deepEqual.test.ts b/src/__tests__/utils/deepEqual.test.ts deleted file mode 100644 index e4ac199437f..00000000000 --- a/src/__tests__/utils/deepEqual.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -import deepEqual from '../../utils/deepEqual'; - -describe('deepEqual', () => { - it('should return false when two sets not match', () => { - expect( - deepEqual([{ test: '123' }, { test: '455' }, { test: '455' }], []), - ).toBeFalsy(); - - expect( - deepEqual( - [{ test: '123' }, { test: '455' }, { test: '455' }], - [{ test: '123' }, { test: '455' }, { test: '455', test1: 'what' }], - ), - ).toBeFalsy(); - - expect(deepEqual([{}], [])).toBeFalsy(); - - expect(deepEqual([], [{}])).toBeFalsy(); - expect(deepEqual(new Date(), new Date('1999'))).toBeFalsy(); - - expect( - deepEqual( - { - unknown: undefined, - userName: '', - fruit: '', - }, - { - userName: '', - fruit: '', - break: {}, - }, - ), - ).toBeFalsy(); - }); - - it('should return false when either type is primitive', () => { - expect(deepEqual(null, [])).toBeFalsy(); - expect(deepEqual([], null)).toBeFalsy(); - expect(deepEqual({}, undefined)).toBeFalsy(); - expect(deepEqual(undefined, {})).toBeFalsy(); - }); - - it('should return true when two sets matches', () => { - expect( - deepEqual([{ name: 'useFieldArray' }], [{ name: 'useFieldArray' }]), - ).toBeTruthy(); - - expect( - deepEqual( - [{ test: '123' }, { test: '455' }, { test: '455' }], - [{ test: '123' }, { test: '455' }, { test: '455' }], - ), - ).toBeTruthy(); - - expect(deepEqual({}, {})).toBeTruthy(); - - expect(deepEqual([], [])).toBeTruthy(); - - expect( - deepEqual( - [{ test: '123' }, { test: '455' }], - [{ test: '123' }, { test: '455' }], - ), - ).toBeTruthy(); - - expect( - deepEqual( - [ - { - test: '123', - nestedArray: [{ test: '123' }, { test: '455' }, { test: '455' }], - }, - { - test: '455', - nestedArray: [{ test: '123' }, { test: '455' }, { test: '455' }], - }, - ], - [ - { - test: '123', - nestedArray: [{ test: '123' }, { test: '455' }, { test: '455' }], - }, - { - test: '455', - nestedArray: [{ test: '123' }, { test: '455' }, { test: '455' }], - }, - ], - ), - ).toBeTruthy(); - }); - - it('should compare date time object valueOf', () => { - expect( - deepEqual({ test: new Date('1990') }, { test: new Date('1990') }), - ).toBeTruthy(); - }); -}); diff --git a/src/__tests__/utils/deepMerge.test.ts b/src/__tests__/utils/deepMerge.test.ts deleted file mode 100644 index 0e62d50b910..00000000000 --- a/src/__tests__/utils/deepMerge.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { deepMerge } from '../../utils/deepMerge'; - -describe('deepMerge', () => { - it('should deep merge object correctly', () => { - expect( - deepMerge( - { test: { value: 1, data: { test: 1 } } }, - { test: { value2: 2 } }, - ), - ).toEqual({ - test: { value: 1, value2: 2, data: { test: 1 } }, - }); - - expect(deepMerge({ test: { value: 1 } }, {})).toEqual({ - test: { value: 1 }, - }); - - expect(deepMerge({}, { test: [{ value: '1' }] })).toEqual({ - test: [{ value: '1' }], - }); - - expect(deepMerge({ data: {} }, { test: [{ value: '1' }] })).toEqual({ - data: {}, - test: [{ value: '1' }], - }); - }); - - it('should overwrite array value ', () => { - expect( - deepMerge({ test: [{ value: '2' }] }, { test: [{ value: '1' }] }), - ).toEqual({ - test: [{ value: '1' }], - }); - }); - - it('should overwrite different data type', () => { - expect(deepMerge({ test: [{ value: '2' }] }, { test: {} })).toEqual({ - test: {}, - }); - }); - - it('should not merge object with date type', () => { - expect( - deepMerge({ test: new Date() }, { test: new Date('1999-02-02') }), - ).toEqual({ - test: new Date('1999-02-02'), - }); - }); - - it('should deep merge array values ', () => { - expect(deepMerge([{ hey: 'test' }], [{ id: 'id', text: '' }])).toEqual([ - { hey: 'test', id: 'id', text: '' }, - ]); - - expect(deepMerge([{ id: 'id', text: '' }], [{ hey: 'test' }])).toEqual([ - { hey: 'test', id: 'id', text: '' }, - ]); - - expect( - deepMerge( - { - test: [{ id: 'id', text: '' }], - }, - { - test: [{ hey: 'test' }], - }, - ), - ).toEqual({ - test: [{ hey: 'test', id: 'id', text: '' }], - }); - }); - - it("should never merge non-objects, and always return the 'source' object", () => { - expect(deepMerge({}, 0)).toEqual(0); - expect(deepMerge(0, {})).toEqual({}); - }); -}); diff --git a/src/__tests__/utils/fillBooleanArray.test.ts b/src/__tests__/utils/fillBooleanArray.test.ts deleted file mode 100644 index 94e97f75e59..00000000000 --- a/src/__tests__/utils/fillBooleanArray.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import fillBooleanArray from '../../utils/fillBooleanArray'; - -describe('filterBooleanArray', () => { - it('should be filtered array', () => { - expect( - fillBooleanArray([ - { test: 'test', test1: 'test1' }, - 'test2', - { test3: 'test3', test4: 'test4' }, - ]), - ).toEqual([ - { - test: true, - test1: true, - }, - true, - { test3: true, test4: true }, - ]); - }); - - it('should be filtered object', () => { - expect(fillBooleanArray({ test: 'test', test1: 'test1' })).toEqual([ - { - test: true, - test1: true, - }, - ]); - }); - - it('should be filtered string', () => { - expect(fillBooleanArray('test')).toEqual([true]); - }); -}); diff --git a/src/__tests__/utils/fillEmptyArray.test.ts b/src/__tests__/utils/fillEmptyArray.test.ts deleted file mode 100644 index a9541d99e3d..00000000000 --- a/src/__tests__/utils/fillEmptyArray.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import fillEmptyArray from '../../utils/fillEmptyArray'; - -describe('fillEmptyArray', () => { - it('should return an array of undefined or empty array when value is an array', () => { - expect(fillEmptyArray([1])).toEqual([undefined]); - expect(fillEmptyArray([])).toEqual([]); - expect(fillEmptyArray(['2', true])).toEqual([undefined, undefined]); - expect(fillEmptyArray([{}, {}])).toEqual([undefined, undefined]); - expect(fillEmptyArray([[], [3]])).toEqual([undefined, undefined]); - }); - - it('should return undefined when value is not an array', () => { - expect(fillEmptyArray(1)).toEqual(undefined); - expect(fillEmptyArray({})).toEqual(undefined); - expect(fillEmptyArray('')).toEqual(undefined); - expect(fillEmptyArray(true)).toEqual(undefined); - }); -}); diff --git a/src/__tests__/utils/get.test.ts b/src/__tests__/utils/get.test.ts deleted file mode 100644 index 14f8c930abb..00000000000 --- a/src/__tests__/utils/get.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import get from '../../utils/get'; - -describe('get', () => { - it('should get the right data', () => { - const test = { - bill: [1, 2, 3], - luo: [1, 3, { betty: 'test' }], - betty: { test: { test1: [{ test2: 'bill' }] } }, - 'betty.test.test1[0].test1': 'test', - 'dotted.filled': 'content', - 'dotted.empty': '', - }; - expect(get(test, 'bill')).toEqual([1, 2, 3]); - expect(get(test, 'bill[0]')).toEqual(1); - expect(get(test, 'luo[2].betty')).toEqual('test'); - expect(get(test, 'betty.test.test1[0].test2')).toEqual('bill'); - expect(get(test, 'betty.test.test1[0].test1')).toEqual('test'); - expect(get(test, 'betty.test.test1[0].test3')).toEqual(undefined); - expect(get(test, 'dotted.filled')).toEqual(test['dotted.filled']); - expect(get(test, 'dotted.empty')).toEqual(test['dotted.empty']); - expect(get(test, 'dotted.nonexistent', 'default')).toEqual('default'); - }); - - it('should get from the flat data', () => { - const test = { - bill: 'test', - }; - expect(get(test, 'bill')).toEqual('test'); - }); - - it('should return undefined when provided with empty path', () => { - const test = { - bill: 'test', - }; - expect(get(test, '')).toEqual(undefined); - // @ts-expect-error - expect(get(test, undefined)).toEqual(undefined); - // @ts-expect-error - expect(get(test, null)).toEqual(undefined); - }); -}); diff --git a/src/__tests__/utils/insert.test.ts b/src/__tests__/utils/insert.test.ts deleted file mode 100644 index 6e82c1ef1be..00000000000 --- a/src/__tests__/utils/insert.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import insert from '../../utils/insert'; - -describe('insert', () => { - it('should insert value at specific index in array', () => { - expect(insert([1, 3, 4], 1, 2)).toEqual([1, 2, 3, 4]); - expect( - insert( - [ - { - firstName: '1', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '2', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '4', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - ], - 2, - { - firstName: '3', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - ), - ).toEqual([ - { - firstName: '1', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '2', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '3', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '4', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - ]); - }); - - it('should insert undefined as value when value to be inserted is falsy', () => { - expect(insert([1, 2, 4], 2)).toEqual([1, 2, undefined, 4]); - expect(insert([1, 2, 4], 2, 0)).toEqual([1, 2, 0, 4]); - // @ts-expect-error - expect(insert([1, 2, 4], 2, false)).toEqual([1, 2, false, 4]); - // @ts-expect-error - expect(insert([1, 2, 4], 2, '')).toEqual([1, 2, '', 4]); - expect(insert([1, 2, 4], 2, undefined)).toEqual([1, 2, undefined, 4]); - }); - - it('should spread value when it is an array at one deep-level', () => { - expect(insert([1, 2], 2, [3, 4])).toEqual([1, 2, 3, 4]); - expect(insert([1, 2], 2, [3, [4]])).toEqual([1, 2, 3, [4]]); - }); -}); diff --git a/src/__tests__/utils/isBoolean.test.ts b/src/__tests__/utils/isBoolean.test.ts deleted file mode 100644 index 30dabe115ae..00000000000 --- a/src/__tests__/utils/isBoolean.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import isBoolean from '../../utils/isBoolean'; - -describe('isBoolean', () => { - it('should return true when value is a boolean', () => { - expect(isBoolean(true)).toBeTruthy(); - expect(isBoolean(false)).toBeTruthy(); - }); - - it('should return false when value is not a boolean', () => { - expect(isBoolean(null)).toBeFalsy(); - expect(isBoolean(undefined)).toBeFalsy(); - expect(isBoolean(-1)).toBeFalsy(); - expect(isBoolean(0)).toBeFalsy(); - expect(isBoolean(1)).toBeFalsy(); - expect(isBoolean('')).toBeFalsy(); - expect(isBoolean({})).toBeFalsy(); - expect(isBoolean([])).toBeFalsy(); - expect(isBoolean(() => null)).toBeFalsy(); - }); -}); diff --git a/src/__tests__/utils/isCheckBoxInput.test.ts b/src/__tests__/utils/isCheckBoxInput.test.ts deleted file mode 100644 index e4d084e1c51..00000000000 --- a/src/__tests__/utils/isCheckBoxInput.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import isCheckBoxInput from '../../utils/isCheckBoxInput'; - -describe('isCheckBoxInput', () => { - it('should return true when type is checkbox', () => { - expect(isCheckBoxInput({ name: 'test', type: 'checkbox' })).toBeTruthy(); - }); -}); diff --git a/src/__tests__/utils/isEmptyObject.test.ts b/src/__tests__/utils/isEmptyObject.test.ts deleted file mode 100644 index 71da4f1c53b..00000000000 --- a/src/__tests__/utils/isEmptyObject.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import isEmptyObject from '../../utils/isEmptyObject'; - -describe('isEmptyObject', () => { - it('should return true when value is an empty object', () => { - expect(isEmptyObject({})).toBeTruthy(); - }); - - it('should return false when value is not an empty object', () => { - expect(isEmptyObject(null)).toBeFalsy(); - expect(isEmptyObject(undefined)).toBeFalsy(); - expect(isEmptyObject(-1)).toBeFalsy(); - expect(isEmptyObject(0)).toBeFalsy(); - expect(isEmptyObject(1)).toBeFalsy(); - expect(isEmptyObject('')).toBeFalsy(); - expect(isEmptyObject(() => null)).toBeFalsy(); - expect(isEmptyObject({ foo: 'bar' })).toBeFalsy(); - expect(isEmptyObject([])).toBeFalsy(); - expect(isEmptyObject(['foo', 'bar'])).toBeFalsy(); - }); -}); diff --git a/src/__tests__/utils/isFileInput.test.ts b/src/__tests__/utils/isFileInput.test.ts deleted file mode 100644 index 412d5482f9e..00000000000 --- a/src/__tests__/utils/isFileInput.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import isFileInput from '../../utils/isFileInput'; - -describe('isFileInput', () => { - it('should return true when type is file', () => { - expect(isFileInput({ name: 'test', type: 'file' })).toBeTruthy(); - }); -}); diff --git a/src/__tests__/utils/isFunction.test.ts b/src/__tests__/utils/isFunction.test.ts deleted file mode 100644 index 2c5fecd6d9f..00000000000 --- a/src/__tests__/utils/isFunction.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import isFunction from '../../utils/isFunction'; - -describe('isFunction', () => { - it('should return true when value is a function', () => { - expect(isFunction(() => null)).toBeTruthy(); - expect( - isFunction(function foo() { - return null; - }), - ).toBeTruthy(); - }); - - it('should return false when value is not a function', () => { - expect(isFunction(null)).toBeFalsy(); - expect(isFunction(undefined)).toBeFalsy(); - expect(isFunction(-1)).toBeFalsy(); - expect(isFunction(0)).toBeFalsy(); - expect(isFunction(1)).toBeFalsy(); - expect(isFunction('')).toBeFalsy(); - expect(isFunction({})).toBeFalsy(); - expect(isFunction([])).toBeFalsy(); - }); -}); diff --git a/src/__tests__/utils/isHTMLElement.test.ts b/src/__tests__/utils/isHTMLElement.test.ts deleted file mode 100644 index efb142adcfd..00000000000 --- a/src/__tests__/utils/isHTMLElement.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import isHTMLElement from '../../utils/isHTMLElement'; - -describe('isHTMLElement', () => { - it('should return true when value is HTMLElement', () => { - expect(isHTMLElement(document.createElement('input'))).toBeTruthy(); - }); - - it('should return true when HTMLElement is inside an iframe', () => { - const iframe = document.createElement('iframe'); - document.body.append(iframe); - - const iframeDocument = iframe.contentDocument!; - const input = iframeDocument.createElement('input'); - iframeDocument.body.append(input); - expect(isHTMLElement(input)).toBeTruthy(); - }); -}); diff --git a/src/__tests__/utils/isKey.test.ts b/src/__tests__/utils/isKey.test.ts deleted file mode 100644 index 69f97eceb80..00000000000 --- a/src/__tests__/utils/isKey.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import isKey from '../../utils/isKey'; - -describe('isKey', () => { - it('should return true when it is not a deep key', () => { - expect(isKey('test')).toBeTruthy(); - expect(isKey('fooBar')).toBeTruthy(); - }); - - it('should return false when it is a deep key', () => { - expect(isKey('test.foo')).toBeFalsy(); - expect(isKey('test.foo[0]')).toBeFalsy(); - expect(isKey('test[1]')).toBeFalsy(); - expect(isKey('test.foo[0].bar')).toBeFalsy(); - }); -}); diff --git a/src/__tests__/utils/isMessage.test.ts b/src/__tests__/utils/isMessage.test.ts deleted file mode 100644 index e90c59fb72f..00000000000 --- a/src/__tests__/utils/isMessage.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import isMessage from '../../utils/isMessage'; - -describe('isBoolean', () => { - it('should return true when value is a Message', () => { - expect(isMessage('test')).toBeTruthy(); - }); - - it('should return false when value is not a Message', () => { - expect(isMessage(null)).toBeFalsy(); - expect(isMessage(undefined)).toBeFalsy(); - expect(isMessage(-1)).toBeFalsy(); - expect(isMessage(1)).toBeFalsy(); - expect(isMessage({})).toBeFalsy(); - expect(isMessage([])).toBeFalsy(); - expect(isMessage(() => null)).toBeFalsy(); - }); -}); diff --git a/src/__tests__/utils/isMultipleSelect.test.ts b/src/__tests__/utils/isMultipleSelect.test.ts deleted file mode 100644 index f423c55482d..00000000000 --- a/src/__tests__/utils/isMultipleSelect.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import isMultipleSelect from '../../utils/isMultipleSelect'; - -describe('isMultipleSelect', () => { - it('should return true when type is select-multiple', () => { - expect( - isMultipleSelect({ name: 'test', type: 'select-multiple' }), - ).toBeTruthy(); - }); -}); diff --git a/src/__tests__/utils/isNullOrUndefined.test.ts b/src/__tests__/utils/isNullOrUndefined.test.ts deleted file mode 100644 index 3511f3b685b..00000000000 --- a/src/__tests__/utils/isNullOrUndefined.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import isNullOrUndefined from '../../utils/isNullOrUndefined'; - -describe('isNullOrUndefined', () => { - it('should return true when object is null or undefined', () => { - expect(isNullOrUndefined(null)).toBeTruthy(); - expect(isNullOrUndefined(undefined)).toBeTruthy(); - }); - - it('should return false when object is neither null nor undefined', () => { - expect(isNullOrUndefined(-1)).toBeFalsy(); - expect(isNullOrUndefined(0)).toBeFalsy(); - expect(isNullOrUndefined(1)).toBeFalsy(); - expect(isNullOrUndefined('')).toBeFalsy(); - expect(isNullOrUndefined({})).toBeFalsy(); - expect(isNullOrUndefined([])).toBeFalsy(); - }); -}); diff --git a/src/__tests__/utils/isObject.test.ts b/src/__tests__/utils/isObject.test.ts deleted file mode 100644 index 4d03dbfcc7f..00000000000 --- a/src/__tests__/utils/isObject.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import isObject from '../../utils/isObject'; - -describe('isObject', () => { - it('should return true when value is an object', () => { - expect(isObject({})).toBeTruthy(); - expect(isObject({ foo: 'bar' })).toBeTruthy(); - expect(isObject(new Blob())).toBeTruthy(); - }); - - it('should return false when value is not an object or is null', () => { - expect(isObject(null)).toBeFalsy(); - expect(isObject(undefined)).toBeFalsy(); - expect(isObject(-1)).toBeFalsy(); - expect(isObject(0)).toBeFalsy(); - expect(isObject(1)).toBeFalsy(); - expect(isObject('')).toBeFalsy(); - expect(isObject([])).toBeFalsy(); - expect(isObject(['foo', 'bar'])).toBeFalsy(); - expect(isObject(() => null)).toBeFalsy(); - }); -}); diff --git a/src/__tests__/utils/isPrimitive.test.ts b/src/__tests__/utils/isPrimitive.test.ts deleted file mode 100644 index 7674ded3311..00000000000 --- a/src/__tests__/utils/isPrimitive.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import isPrimitive from '../../utils/isPrimitive'; - -describe('isPrimitive', () => { - it('should return true when value is a string', () => { - expect(isPrimitive('foobar')).toBeTruthy(); - }); - - it('should return true when value is a boolean', () => { - expect(isPrimitive(false)).toBeTruthy(); - }); - - it('should return true when value is a number', () => { - expect(isPrimitive(123)).toBeTruthy(); - }); - - it('should return true when value is a symbol', () => { - expect(isPrimitive(Symbol())).toBeTruthy(); - }); - - it('should return true when value is null', () => { - expect(isPrimitive(null)).toBeTruthy(); - }); - - it('should return true when value is undefined', () => { - expect(isPrimitive(undefined)).toBeTruthy(); - }); - - it('should return false when value is an object', () => { - expect(isPrimitive({})).toBeFalsy(); - }); - - it('should return false when value is an array', () => { - expect(isPrimitive([])).toBeFalsy(); - }); -}); diff --git a/src/__tests__/utils/isRadioInput.test.ts b/src/__tests__/utils/isRadioInput.test.ts deleted file mode 100644 index 4fd09c9df80..00000000000 --- a/src/__tests__/utils/isRadioInput.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import isRadioInput from '../../utils/isRadioInput'; - -describe('isRadioInput', () => { - it('should return true when type is radio', () => { - expect(isRadioInput({ name: 'test', type: 'radio' })).toBeTruthy(); - }); -}); diff --git a/src/__tests__/utils/isRadioOrCheckbox.test.ts b/src/__tests__/utils/isRadioOrCheckbox.test.ts deleted file mode 100644 index c30b7390bad..00000000000 --- a/src/__tests__/utils/isRadioOrCheckbox.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import isRadioOrCheckbox from '../../utils/isRadioOrCheckbox'; - -describe('isRadioOrCheckbox', () => { - it('should return true when type is either radio or checkbox', () => { - expect(isRadioOrCheckbox({ name: 'test', type: 'radio' })).toBeTruthy(); - expect(isRadioOrCheckbox({ name: 'test', type: 'checkbox' })).toBeTruthy(); - }); - - it('shoudl return false when type is neither radio nor checkbox', () => { - expect(isRadioOrCheckbox({ name: 'test', type: 'text' })).toBeFalsy(); - expect(isRadioOrCheckbox({ name: 'test', type: 'email' })).toBeFalsy(); - expect(isRadioOrCheckbox({ name: 'test', type: 'date' })).toBeFalsy(); - }); -}); diff --git a/src/__tests__/utils/isRegex.test.ts b/src/__tests__/utils/isRegex.test.ts deleted file mode 100644 index 8f28e72180d..00000000000 --- a/src/__tests__/utils/isRegex.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import isRegex from '../../utils/isRegex'; - -describe('isRegex', () => { - it('should return true when it is a regex', () => { - expect(isRegex(new RegExp('[a-z]'))).toBeTruthy(); - }); -}); diff --git a/src/__tests__/utils/isSelectInput.test.ts b/src/__tests__/utils/isSelectInput.test.ts deleted file mode 100644 index 232c7a37f61..00000000000 --- a/src/__tests__/utils/isSelectInput.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import isRadioInput from '../../utils/isSelectInput'; - -describe('isSelectInput', () => { - it('should return true when type is select-one', () => { - expect(isRadioInput({ name: 'test', type: 'select-one' })).toBeTruthy(); - }); -}); diff --git a/src/__tests__/utils/isString.test.ts b/src/__tests__/utils/isString.test.ts deleted file mode 100644 index f7949fda211..00000000000 --- a/src/__tests__/utils/isString.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import isString from '../../utils/isString'; - -describe('isString', () => { - it('should return true when value is a string', () => { - expect(isString('')).toBeTruthy(); - expect(isString('foobar')).toBeTruthy(); - }); - - it('should return false when value is not a string', () => { - expect(isString(null)).toBeFalsy(); - expect(isString(undefined)).toBeFalsy(); - expect(isString(-1)).toBeFalsy(); - expect(isString(0)).toBeFalsy(); - expect(isString(1)).toBeFalsy(); - expect(isString({})).toBeFalsy(); - expect(isString([])).toBeFalsy(); - expect(isString(new String('test'))).toBeFalsy(); - expect(isString(() => null)).toBeFalsy(); - }); -}); diff --git a/src/__tests__/utils/isUndefined.test.ts b/src/__tests__/utils/isUndefined.test.ts deleted file mode 100644 index 652acec6d90..00000000000 --- a/src/__tests__/utils/isUndefined.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import isUndefined from '../../utils/isUndefined'; - -describe('isUndefined', () => { - it('should return true when it is an undefined value', () => { - expect(isUndefined(undefined)).toBeTruthy(); - }); - - it('should return false when it is not an undefined value', () => { - expect(isUndefined(null)).toBeFalsy(); - expect(isUndefined('')).toBeFalsy(); - expect(isUndefined('undefined')).toBeFalsy(); - expect(isUndefined(0)).toBeFalsy(); - expect(isUndefined([])).toBeFalsy(); - expect(isUndefined({})).toBeFalsy(); - }); -}); diff --git a/src/__tests__/utils/move.test.ts b/src/__tests__/utils/move.test.ts deleted file mode 100644 index fb7f50ff52c..00000000000 --- a/src/__tests__/utils/move.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import move from '../../utils/move'; - -describe('move', () => { - it('should be able to move element of array', () => { - const data = [ - { - firstName: '1', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '2', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '3', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - ]; - move(data, 0, 2); - expect(data).toEqual([ - { - firstName: '2', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '3', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '1', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - ]); - }); - - it('should return empty array when data passed was not an array', () => { - // @ts-expect-error - expect(move({}, 0, 3)).toEqual([]); - }); - - it('should move nested item with empty slot', () => { - expect(move([{ subFields: [{ test: '1' }] }], 0, 1)).toEqual([ - undefined, - { subFields: [{ test: '1' }] }, - ]); - - expect(move([{ subFields: [{ test: '1' }] }], 0, 2)).toEqual([ - undefined, - undefined, - { subFields: [{ test: '1' }] }, - ]); - }); -}); diff --git a/src/__tests__/utils/objectHasFunction.test.ts b/src/__tests__/utils/objectHasFunction.test.ts deleted file mode 100644 index ba9f70be57d..00000000000 --- a/src/__tests__/utils/objectHasFunction.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import objectHasFunction from '../../utils/objectHasFunction'; - -describe('objectHasFunction', () => { - it('should detect if any object has function', () => { - expect(objectHasFunction({})).toBeFalsy(); - expect( - objectHasFunction({ - test: '', - }), - ).toBeFalsy(); - - expect( - objectHasFunction({ - test: () => {}, - }), - ).toBeTruthy(); - }); -}); diff --git a/src/__tests__/utils/prepend.test.ts b/src/__tests__/utils/prepend.test.ts deleted file mode 100644 index e8494fe5cf8..00000000000 --- a/src/__tests__/utils/prepend.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import prepend from '../../utils/prepend'; - -describe('prepend', () => { - it('should prepend value to an array', () => { - expect(prepend([2, 3, 4], 1)).toEqual([1, 2, 3, 4]); - expect( - prepend( - [ - { - firstName: '2', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '3', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '4', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - ], - { - firstName: '1', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - ), - ).toEqual([ - { - firstName: '1', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '2', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '3', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '4', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - ]); - }); - - it('should prepend undefined as value when value to be prepended is falsy', () => { - expect(prepend([2, 3, 4], 0)).toEqual([0, 2, 3, 4]); - // @ts-expect-error - expect(prepend([2, 3, 4], false)).toEqual([false, 2, 3, 4]); - // @ts-expect-error - expect(prepend([2, 3, 4], '')).toEqual(['', 2, 3, 4]); - expect(prepend([2, 3, 4], undefined)).toEqual([undefined, 2, 3, 4]); - }); - - it('should spread value when it is an array at one deep-level', () => { - expect(prepend([3, 4], [1, 2])).toEqual([1, 2, 3, 4]); - expect(prepend([3, 4], [[1], 2])).toEqual([[1], 2, 3, 4]); - }); -}); diff --git a/src/__tests__/utils/remove.test.ts b/src/__tests__/utils/remove.test.ts deleted file mode 100644 index c57f6d17c5e..00000000000 --- a/src/__tests__/utils/remove.test.ts +++ /dev/null @@ -1,140 +0,0 @@ -import remove from '../../utils/remove'; - -describe('remove', () => { - it('should remove item accordingly', () => { - expect( - remove([, , { type: 'required', message: '', ref: 'test' }], 1), - ).toEqual([undefined, { type: 'required', message: '', ref: 'test' }]); - - expect( - remove([, , { type: 'required', message: '', ref: 'test' }], [1, 2]), - ).toEqual([]); - - expect( - remove([, , { type: 'required', message: '', ref: 'test' }], [0, 1]), - ).toEqual([{ type: 'required', message: '', ref: 'test' }]); - - expect( - remove( - [ - , - , - { type: 'required', message: '', ref: 'test' }, - { type: 'required', message: '', ref: 'test' }, - null, - , - ], - [3, 2], - ), - ).toEqual([]); - - expect( - remove( - [ - , - , - { type: 'required', message: '', ref: 'test' }, - { type: 'required', message: '', ref: 'test' }, - null, - , - ], - [1, 4], - ), - ).toEqual([ - undefined, - { type: 'required', message: '', ref: 'test' }, - { type: 'required', message: '', ref: 'test' }, - undefined, - ]); - - expect(remove([true, true, true], [1])).toEqual([true, true]); - expect(remove([true, true, true], [0])).toEqual([true, true]); - - expect( - remove([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [6, 7, 8, 9, 10, 11]), - ).toEqual([0, 1, 2, 3, 4, 5]); - expect( - remove([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [11, 10, 9, 8, 7, 6]), - ).toEqual([0, 1, 2, 3, 4, 5]); - }); - - it('should remove correctly with indexes which contains gap', () => { - expect( - remove( - [ - , - , - { type: 'required', message: '', ref: 'test' }, - { type: 'required', message: '', ref: 'test' }, - null, - { type: 'required', message: '', ref: 'test' }, - , - { type: 'required', message: '', ref: 'test' }, - ], - [2, 5], - ), - ).toEqual([ - , - , - { type: 'required', message: '', ref: 'test' }, - null, - , - { type: 'required', message: '', ref: 'test' }, - ]); - }); - - it('should remove all items', () => { - expect( - remove( - [ - { - firstName: '1', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '2', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '3', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '4', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '5', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '6', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '7', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '8', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '9', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - ], - [0, 1, 2, 3, 4, 5, 6, 7, 8], - ), - ).toEqual([]); - }); -}); diff --git a/src/__tests__/utils/set.test.ts b/src/__tests__/utils/set.test.ts deleted file mode 100644 index d89e06c1961..00000000000 --- a/src/__tests__/utils/set.test.ts +++ /dev/null @@ -1,60 +0,0 @@ -import set from '../../utils/set'; - -describe('set', () => { - it('should set the correct values', () => { - const test1 = { a: [{ b: { c: 3 } }] }; - expect(set(test1, 'a[0].b.c', 4)).toEqual(4); - expect(test1.a[0].b.c).toEqual(4); - - const test2 = { foo: { bar: 'baz' } }; - expect(set(test2, 'foo.arr[0]', 3)).toEqual(3); - expect(test2).toEqual({ - foo: { - bar: 'baz', - arr: [3], - }, - }); - - const test3 = { foo: { bar: 'baz' } }; - expect(set(test3, 'foo.arr["1"]', true)).toEqual(true); - expect(test3).toEqual({ - foo: { - bar: 'baz', - arr: [, true], - }, - }); - - const test4 = { foo: { bar: 'baz' } }; - expect(set(test4, 'foo.obj.key', 'test')).toEqual('test'); - expect(test4).toEqual({ - foo: { - bar: 'baz', - obj: { key: 'test' }, - }, - }); - - const test5 = { foo: 1 }; - expect(set(test5, 'foo.obj.key', 3)).toEqual(3); - expect(test5).toEqual({ - foo: { - obj: { - key: 3, - }, - }, - }); - - const test6 = {}; - expect(set(test6, 'foo.arr[0].obj.key', 1)).toEqual(1); - expect(test6).toEqual({ - foo: { - arr: [ - { - obj: { - key: 1, - }, - }, - ], - }, - }); - }); -}); diff --git a/src/__tests__/utils/stringToPath.test.ts b/src/__tests__/utils/stringToPath.test.ts deleted file mode 100644 index 99226061567..00000000000 --- a/src/__tests__/utils/stringToPath.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -import stringToPath from '../../utils/stringToPath'; - -describe('stringToPath', () => { - it('should convert string to path', () => { - expect(stringToPath('test')).toEqual(['test']); - - expect(stringToPath('[test]]')).toEqual(['test']); - - expect(stringToPath('test.test[2].data')).toEqual([ - 'test', - 'test', - '2', - 'data', - ]); - - expect(stringToPath('test.test["2"].data')).toEqual([ - 'test', - 'test', - '2', - 'data', - ]); - - expect(stringToPath("test.test['test'].data")).toEqual([ - 'test', - 'test', - 'test', - 'data', - ]); - - expect(stringToPath('test.test.2.data')).toEqual([ - 'test', - 'test', - '2', - 'data', - ]); - }); -}); diff --git a/src/__tests__/utils/swap.test.ts b/src/__tests__/utils/swap.test.ts deleted file mode 100644 index 0c8742ebcb1..00000000000 --- a/src/__tests__/utils/swap.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import swap from '../../utils/swap'; - -describe('swap', () => { - it('should swap value positions', () => { - const test1 = [1, 2, 3, 4]; - swap(test1, 1, 2); - expect(test1).toEqual([1, 3, 2, 4]); - - const test2 = [ - { - firstName: '1', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '2', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '3', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - ]; - swap(test2, 0, 2); - expect(test2).toEqual([ - { - firstName: '3', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '2', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - { - firstName: '1', - lastName: 'Luo', - id: '75309979-e340-49eb-8016-5f67bfb56c1c', - }, - ]); - }); - - it('should swap undefined position when index is not exists', () => { - const test1 = [1, 2, 3, 4]; - swap(test1, 0, 4); - expect(test1).toEqual([undefined, 2, 3, 4, 1]); - - const test2 = [1, 2, 3, 4]; - swap(test2, 2, 6); - expect(test2).toEqual([1, 2, undefined, 4, undefined, undefined, 3]); - }); -}); diff --git a/src/__tests__/utils/unset.test.ts b/src/__tests__/utils/unset.test.ts deleted file mode 100644 index 8ced221c919..00000000000 --- a/src/__tests__/utils/unset.test.ts +++ /dev/null @@ -1,314 +0,0 @@ -import unset from '../../utils/unset'; - -describe('unset', () => { - it('should unset the array', () => { - const test = ['test', 'test1', 'test2']; - expect(unset(test, '[0]')).toEqual([undefined, 'test1', 'test2']); - expect(unset(test, '[1]')).toEqual([undefined, undefined, 'test2']); - expect(unset(test, '[2]')).toEqual([undefined, undefined, undefined]); - }); - - it('should return original object when path is not defined', () => { - const test = { - test: 'test', - }; - - expect(unset(test, '')).toEqual(test); - }); - - it('should unset the flat object', () => { - const test = { - test: 'test', - }; - - expect(unset(test, 'test')).toEqual({}); - }); - - it('should not unset if specified field is undefined', () => { - const test = { - test: { - test1: 'test', - }, - }; - - expect(unset(test, 'testDummy.test1')).toEqual({ test: { test1: 'test' } }); - }); - - it('should unset the nest object', () => { - const test = { - test: { - min: 'test', - }, - }; - - expect(unset(test, 'test.min')).toEqual({}); - }); - - it('should unset deep object', () => { - const test = { - test: { - bill: { - min: 'test', - }, - }, - }; - - expect(unset(test, 'test.bill.min')).toEqual({}); - }); - - it('should unset the including multiple field object', () => { - const deep = { - data: { - firstName: 'test', - clear: undefined, - test: [{ data1: '' }, { data2: '' }], - data: { - test: undefined, - test1: { - ref: { - test: '', - }, - }, - }, - }, - }; - - const test = { - test: { - bill: { - min: [{ deep }], - }, - test: 'ha', - }, - }; - - expect(unset(test, 'test.bill.min[0].deep')).toEqual({ - test: { - test: 'ha', - }, - }); - }); - - it('should unset the object in array', () => { - const test = { - test: [{ min: 'required' }], - }; - expect(unset(test, 'test[0].min')).toEqual({}); - }); - - it('should return empty object when inner object is empty object', () => { - const test = { - data: { - firstName: {}, - }, - }; - - expect(unset(test, 'data.firstName')).toEqual({}); - }); - - it('should clear empty array', () => { - const test = { - data: { - firstName: { - test: [ - { name: undefined, email: undefined }, - { name: 'test', email: 'last' }, - ], - deep: { - last: [ - { name: undefined, email: undefined }, - { name: 'test', email: 'last' }, - ], - }, - }, - }, - }; - - expect(unset(test, 'data.firstName.test[0]')).toEqual({ - data: { - firstName: { - test: [undefined, { name: 'test', email: 'last' }], - deep: { - last: [ - { name: undefined, email: undefined }, - { name: 'test', email: 'last' }, - ], - }, - }, - }, - }); - - const test2 = { - arrayItem: [ - { - test1: undefined, - test2: undefined, - }, - ], - data: 'test', - }; - - expect(unset(test2, 'arrayItem[0].test1')).toEqual({ - arrayItem: [ - { - test2: undefined, - }, - ], - data: 'test', - }); - }); - - it('should only remove relevant data', () => { - const data = { - test: {}, - testing: { - key1: 1, - key2: [ - { - key4: 4, - key5: [], - key6: null, - key7: '', - key8: undefined, - key9: {}, - }, - ], - key3: [], - }, - }; - - expect(unset(data, 'test')).toEqual({ - testing: { - key1: 1, - key2: [ - { - key4: 4, - key5: [], - key6: null, - key7: '', - key8: undefined, - key9: {}, - }, - ], - key3: [], - }, - }); - }); - - it('should remove empty array item', () => { - const data = { - name: [ - { - message: 'test', - }, - ], - }; - - expect(unset(data, 'name[0]')).toEqual({}); - }); - - it('should not remove nested empty array item', () => { - const data = { - scenario: { - steps: [ - { - content: { - question: 'isRequired', - }, - }, - ], - }, - }; - - expect(unset(data, 'scenario.steps[1].messages[0]')).toEqual({ - scenario: { - steps: [ - { - content: { - question: 'isRequired', - }, - }, - ], - }, - }); - }); - - it('should not remove parent if boolean value exists in array', () => { - const data = { - test: [true, undefined, true], - }; - - expect(unset(data, 'test[2]')).toEqual({ - test: [true, undefined, undefined], - }); - }); - - it('should reset the array index', () => { - const data = { - test: [[{ name: 'test' }], [{ name: 'test1' }]], - }; - unset(data, 'test.0.0.name'); - - expect(data).toEqual({ - test: [undefined, [{ name: 'test1' }]], - }); - - const data1 = { - test: [[{ name: 'test' }], [{ name: 'test1' }]], - }; - unset(data1, 'test.1.0.name'); - - expect(data1).toEqual({ - test: [[{ name: 'test' }], undefined], - }); - - const data2 = { - test: [[[{ name: 'test' }]], [{ name: 'test1' }]], - }; - unset(data2, 'test.0.0.0.name'); - - expect(data2).toEqual({ - test: [undefined, [{ name: 'test1' }]], - }); - - const data3 = { - test: [[[{ name: 'test' }]], [[{ name: 'test1' }]]], - }; - unset(data3, 'test.1.0.0.name'); - - expect(data3).toEqual({ - test: [[[{ name: 'test' }]], undefined], - }); - - const data4 = { - test: { - fields: ['1', '2'], - }, - }; - unset(data4, 'test.fields.1'); - - expect(data4).toEqual({ - test: { - fields: ['1', undefined], - }, - }); - }); - - describe('when there are remaining props', () => { - it('should not unset the array', () => { - const test = { - test: [{ firstName: 'test' }], - }; - - // @ts-ignore - test.test.root = { - test: 'message', - }; - - unset(test, 'test.0.firstName'); - - // @ts-ignore - expect(test.test.root).toBeDefined(); - }); - }); -}); diff --git a/src/__tests__/utils/validationModeChecker.test.ts b/src/__tests__/utils/validationModeChecker.test.ts deleted file mode 100644 index 26f26c872dd..00000000000 --- a/src/__tests__/utils/validationModeChecker.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { VALIDATION_MODE } from '../../constants'; -import validationModeChecker from '../../logic/getValidationModes'; - -describe('validationModeChecker', () => { - it('should return correct mode', () => { - expect(validationModeChecker(VALIDATION_MODE.onBlur)).toEqual({ - isOnSubmit: false, - isOnBlur: true, - isOnChange: false, - isOnAll: false, - isOnTouch: false, - }); - - expect(validationModeChecker(VALIDATION_MODE.onChange)).toEqual({ - isOnSubmit: false, - isOnBlur: false, - isOnChange: true, - isOnAll: false, - isOnTouch: false, - }); - - expect(validationModeChecker(VALIDATION_MODE.onSubmit)).toEqual({ - isOnSubmit: true, - isOnBlur: false, - isOnChange: false, - isOnAll: false, - isOnTouch: false, - }); - - expect(validationModeChecker(undefined)).toEqual({ - isOnSubmit: true, - isOnBlur: false, - isOnChange: false, - isOnAll: false, - isOnTouch: false, - }); - - expect(validationModeChecker(VALIDATION_MODE.all)).toEqual({ - isOnSubmit: false, - isOnBlur: false, - isOnChange: false, - isOnAll: true, - isOnTouch: false, - }); - - expect(validationModeChecker(VALIDATION_MODE.onTouched)).toEqual({ - isOnSubmit: false, - isOnBlur: false, - isOnChange: false, - isOnAll: false, - isOnTouch: true, - }); - }); -}); diff --git a/src/__typetest__/errors.test-d.ts b/src/__typetest__/errors.test-d.ts deleted file mode 100644 index f99ca44ffa0..00000000000 --- a/src/__typetest__/errors.test-d.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { expectType } from 'tsd'; - -import { FieldError, FieldErrors, GlobalError, Merge } from '../types'; - -import { _ } from './__fixtures__'; - -/** {@link FieldErrors} */ { - /** it should support optional record fields */ - { - const actual = _ as FieldErrors<{ - test?: string; - test1?: string; - attachment: { - data: string; - data1: string; - }; - }>; - expectType< - { - test?: FieldError; - test1?: FieldError; - attachment?: Merge< - FieldError, - { - data?: FieldError; - data1?: FieldError; - } - >; - } & { - root?: Record & GlobalError; - } - >(actual); - } - - /** it should support nullable record fields */ - { - const actual = _ as FieldErrors<{ - test?: string; - test1?: string | null; - attachment: { - data: string; - data1: string; - } | null; - }>; - expectType< - { - test?: FieldError; - test1?: FieldError; - attachment?: Merge< - FieldError, - { - data?: FieldError; - data1?: FieldError; - } - >; - } & { - root?: Record & GlobalError; - } - >(actual); - } - - /** it should not treat Date, File, FileList or Blob as record fields */ - { - const actual = _ as FieldErrors<{ - date: Date; - file: File; - fileList: FileList; - record: { - date: Date; - file: File; - fileList: FileList; - }; - }>; - expectType(actual.date); - expectType(actual.file); - expectType(actual.fileList); - expectType(actual.record?.date); - expectType(actual.record?.file); - expectType(actual.record?.fileList); - } -} diff --git a/src/__typetest__/form.test-d.ts b/src/__typetest__/form.test-d.ts index b795c3e2552..cb72d159832 100644 --- a/src/__typetest__/form.test-d.ts +++ b/src/__typetest__/form.test-d.ts @@ -1,6 +1,6 @@ +import { FieldError } from '@hookform/core'; import { expectType } from 'tsd'; -import { FieldError } from '../types'; import { useForm } from '../useForm'; /** {@link UseFormHandleSubmit} */ { diff --git a/src/__typetest__/path/common.test-d.ts b/src/__typetest__/path/common.test-d.ts deleted file mode 100644 index bb7208d3bf9..00000000000 --- a/src/__typetest__/path/common.test-d.ts +++ /dev/null @@ -1,813 +0,0 @@ -import { expectType } from 'tsd'; - -import { - ArrayKey, - AsKey, - AsPathTuple, - CheckKeyConstraint, - ContainsIndexable, - EvaluateKey, - EvaluatePath, - HasKey, - HasPath, - IsTuple, - JoinPathTuple, - Key, - Keys, - NumericKeys, - ObjectKeys, - PathString, - SplitPathString, - ToKey, - TupleKeys, - UnionToIntersection, - ValidPathPrefix, -} from '../../types/path/common'; -import { - _, - HundredPathString, - HundredTuple, - InfiniteType, - Nested, - NullableInfiniteType, -} from '../__fixtures__'; - -/** {@link IsTuple} */ { - /** it should evaluate to true if it's a tuple */ { - const actual = _ as IsTuple<[string, number]>; - expectType(actual); - } - - /** it should evaluate to false if it's not a tuple */ { - const actual = _ as IsTuple; - expectType(actual); - } -} - -/** {@link TupleKeys} */ { - /** it should evaluate to the own keys of the tuple */ { - const actual = _ as TupleKeys<[string, number]>; - expectType<'0' | '1'>(actual); - } - - /** it should evaluate to never if an array type is passed */ { - const actual = _ as TupleKeys; - expectType(actual); - } -} - -/** {@link AsKey} */ { - /** it should behave like a noop type when a Key is passed */ { - const actual = _ as AsKey<'foo'>; - expectType<'foo'>(actual); - } - - /** it should evaluate to never if not a Key is passed */ { - const actual = _ as AsKey; - expectType(actual); - } -} - -/** {@link ToKey} */ { - /** it should behave like a noop type when a Key is passed */ { - const actual = _ as ToKey<'foo'>; - expectType<'foo'>(actual); - } - - /** it should evaluate to never if not a Key or ArrayKey is passed */ { - const actual = _ as ToKey; - expectType(actual); - } - - /** it should convert an ArrayKey to a template literal type */ { - const actual = _ as ToKey; - expectType<`${ArrayKey}`>(actual); - } -} - -/** {@link AsPathTuple} */ { - /** it should behave like a noop type when a PathTuple is passed */ { - const actual = _ as AsPathTuple<['foo']>; - expectType<['foo']>(actual); - } - - /** it should evaluate to never if not a PathTuple is passed */ { - const actual = _ as AsPathTuple<[42]>; - expectType(actual); - } -} - -/** {@link SplitPathString} */ { - /** it should split the PathString */ { - const actual = _ as SplitPathString<'foo.bar.0.baz'>; - expectType<['foo', 'bar', '0', 'baz']>(actual); - } - - /** it should split a PathString which does not contain a "." */ { - const actual = _ as SplitPathString<'foo'>; - expectType<['foo']>(actual); - } - - /** it should return an empty tuple for a blank PathString */ { - const actual = _ as SplitPathString<''>; - expectType<[]>(actual); - } - - /** it should return an empty tuple for a PathString containing only a "." */ { - const actual = _ as SplitPathString<'.'>; - expectType<[]>(actual); - } - - /** it should be implemented tail recursively */ { - const actual = _ as SplitPathString>; - expectType>(actual); - } - - /** it should work on unions */ { - const actual = _ as SplitPathString<'foo.bar' | 'bar.foo'>; - expectType<['foo', 'bar'] | ['bar', 'foo']>(actual); - } - - /** it should split a PathString containing a number template */ { - const actual = _ as SplitPathString<`foo.bar.${number}.baz`>; - expectType<['foo', 'bar', `${number}`, 'baz']>(actual); - } - - /** it should split a PathString containing a string template */ { - const actual = _ as SplitPathString<`foo.bar.${string}.baz`>; - expectType<['foo', 'bar', string, 'baz']>(actual); - } -} - -/** {@link JoinPathTuple} */ { - /** it should join the PathTuple */ { - const actual = _ as JoinPathTuple<['foo', 'bar', '0', 'baz']>; - expectType<'foo.bar.0.baz'>(actual); - } - - /** it should join a PathTuple of length 1 */ { - const actual = _ as JoinPathTuple<['foo']>; - expectType<'foo'>(actual); - } - - /** it should evaluate to never when passed an empty PathTuple */ { - const actual = _ as JoinPathTuple<[]>; - expectType(actual); - } - - /** it should be implemented tail recursively */ { - const actual = _ as JoinPathTuple>; - expectType>(actual); - } - - /** it should work on unions */ { - const actual = _ as JoinPathTuple<['foo', 'bar'] | ['bar', 'foo']>; - expectType<'foo.bar' | 'bar.foo'>(actual); - } - - /** it should evaluate to never if a keys is never */ { - const actual = _ as JoinPathTuple<['foo', never]>; - expectType(actual); - } -} - -/** {@link CheckKeyConstraint} */ { - /** it should remove the keys which don't match the constraint */ { - const actual = _ as CheckKeyConstraint< - { foo: string; bar: number }, - 'foo' | 'bar', - string - >; - expectType<'foo'>(actual); - } -} - -/** {@link UnionToIntersection} */ { - /** it should intersect a union of objects */ { - const actual = _ as UnionToIntersection<{ foo: string } | { bar: number }>; - expectType<{ foo: string } & { bar: number }>(actual); - } - - /** it should intersect wrapped unions */ { - const actual = _ as UnionToIntersection<[0 | 1] | [1 | 2]>[never]; - expectType<1>(actual); - } -} - -/** {@link ContainsIndexable} */ { - /** it should evaluate to true when an array is passed */ { - const actual = _ as ContainsIndexable; - expectType(actual); - } - - /** it should evaluate to true when a tuple is passed */ { - const actual = _ as ContainsIndexable<[number]>; - expectType(actual); - } - - /** it should evaluate to false when a string is passed */ { - const actual = _ as ContainsIndexable; - expectType(actual); - } - - /** it should evaluate to false when an object is passed */ { - const actual = _ as ContainsIndexable<{ foo: string }>; - expectType(actual); - } - - /** it should evaluate to true when an array is part of the union */ { - const actual = _ as ContainsIndexable<{ foo: string } | number[]>; - expectType(actual); - } - - /** it should evaluate to true when a tuple is part of the union */ { - const actual = _ as ContainsIndexable<{ foo: string } | [number]>; - expectType(actual); - } -} - -/** {@link NumericKeys} */ { - /** it should return the numeric keys of an object */ { - const actual = _ as NumericKeys<{ 0: string; '1': string; foo: string }>; - expectType<'0' | '1'>(actual); - } - - /** it should return the numeric keys of an array */ { - const actual = _ as NumericKeys; - expectType<`${number}`>(actual); - } - - /** it should return the numeric keys of a tuple */ { - const actual = _ as NumericKeys<[string, number]>; - expectType<'0' | '1'>(actual); - } - - /** it should return the overlapping numeric keys of a tuple and array */ { - const actual = _ as NumericKeys<[number, string] | number[]>; - expectType<'0' | '1'>(actual); - } - - /** it should return the overlapping numeric keys of an object and array */ { - const actual = _ as NumericKeys<{ 0: string; '1': string } | number[]>; - expectType<'0' | '1'>(actual); - } - - /** it should return the overlapping numeric keys of an object and tuple */ { - const actual = _ as NumericKeys<{ 1: string } | [number, string]>; - expectType<'1'>(actual); - } -} - -/** {@link ObjectKeys} */ { - /** it should return the keys of an object */ { - const actual = _ as ObjectKeys<{ foo: string; bar: number }>; - expectType<'foo' | 'bar'>(actual); - } - - /** it should return the overlapping keys of a union of objects */ { - const actual = _ as ObjectKeys< - { foo: string; bar: number } | { bar: number; baz: string } - >; - expectType<'bar'>(actual); - } - - /** it should not return keys which contain dots */ { - const actual = _ as ObjectKeys<{ foo: string; 'foo.bar': number }>; - expectType<'foo'>(actual); - } - - /** it should not return blank keys */ { - const actual = _ as ObjectKeys<{ foo: string; '': number }>; - expectType<'foo'>(actual); - } -} - -/** {@link Keys} */ { - /** it should return the keys of an object */ { - const actual = _ as Keys<{ foo: string; bar: number }>; - expectType<'foo' | 'bar'>(actual); - } - - /** it should return the keys of a tuple */ { - const actual = _ as Keys<[number, string]>; - expectType<'0' | '1'>(actual); - } - - /** it should return the keys of an array */ { - const actual = _ as Keys; - expectType<`${number}`>(actual); - } - - /** it should return the optional keys of an object */ { - const actual = _ as Keys<{ foo?: string; bar?: number }>; - expectType<'foo' | 'bar'>(actual); - } - - /** it should return the keys of a nullable type */ { - const actual = _ as Keys<{ foo: string; bar: number } | null>; - expectType<'foo' | 'bar'>(actual); - } - - /** it should return the keys of an undefinable type */ { - const actual = _ as Keys<{ foo: string; bar: number } | undefined>; - expectType<'foo' | 'bar'>(actual); - } - - /** it should return the optional keys of a tuple */ { - const actual = _ as Keys<[foo?: string, bar?: number]>; - expectType<'0' | '1'>(actual); - } - - /** it should return the optional keys of a union of tuple and object */ { - const actual = _ as Keys<[foo?: string] | { 0?: string; 1?: string }>; - expectType<'0'>(actual); - } - - /** it should only return the keys of string properties */ { - const actual = _ as Keys<{ foo: string; bar: number }, string>; - expectType<'foo'>(actual); - } - - /** it should only return the keys of string properties */ { - const actual = _ as Keys<{ 1: string; 2: number }, string>; - expectType<'1'>(actual); - } - - /** it should return only the required keys when undefined is excluded */ { - const actual = _ as Keys<{ foo: string; bar?: string }, string>; - expectType<'foo'>(actual); - } - - /** it should return the optional keys when undefined is included */ { - const actual = _ as Keys<{ foo: string; bar?: string }, string | undefined>; - expectType<'foo' | 'bar'>(actual); - } - - /** it should return the overlapping keys of a union of objects */ { - const actual = _ as Keys< - { foo: string; bar: number } | { bar: number; baz: string } - >; - expectType<'bar'>(actual); - } - - /** it should return the keys of the tuple when given a tuple and an array */ { - const actual = _ as Keys; - expectType<'0'>(actual); - } - - /** it should return the overlapping keys when given a tuple and an object */ { - const actual = _ as Keys<{ 0: string; 1: number } | [number]>; - expectType<'0'>(actual); - } - - /** it should return the overlapping keys when given a tuple and an object */ { - const actual = _ as Keys<{ foo: string } | [number]>; - expectType(actual); - } - - /** it should return the numeric keys when given an array and an object */ { - const actual = _ as Keys<{ 0: string; foo: number } | number[]>; - expectType<'0'>(actual); - } - - /** it should return {@link Key} when given any */ { - const actual = _ as Keys; - expectType(actual); - } - - /** it should return {@link Key} when given never */ { - const actual = _ as Keys; - expectType(actual); - } - - /** it should return never when given unknown */ { - const actual = _ as Keys; - expectType(actual); - } - - /** it should return never when given a string */ { - const actual = _ as Keys; - expectType(actual); - } - - /** it should return never when given undefined */ { - const actual = _ as Keys; - expectType(actual); - } - - /** it should return never when given null */ { - const actual = _ as Keys; - expectType(actual); - } -} - -/** {@link HasKey} */ { - /** it should return true when the key exists */ { - const actual = _ as HasKey<{ foo: string }, 'foo'>; - expectType(actual); - } - - /** it should return false when the key doesn't exist */ { - const actual = _ as HasKey<{ foo: string }, 'bar'>; - expectType(actual); - } - - /** it should return false when one of the keys doesn't exist */ { - const actual = _ as HasKey<{ foo: string }, 'foo' | 'bar'>; - expectType(actual); - } - - /** it should return false when one key doesn't exist in one of the types */ { - const actual = _ as HasKey<{ foo: string } | { bar: string }, 'foo'>; - expectType(actual); - } -} - -/** {@link EvaluateKey} */ { - /** it should traverse an object */ { - const actual = _ as EvaluateKey<{ foo: number; bar: string }, 'foo'>; - expectType(actual); - } - - /** it should traverse an index signature */ { - const actual = _ as EvaluateKey, string>; - expectType(actual); - } - - /** it should traverse a numeric index signature */ { - const actual = _ as EvaluateKey, `${number}`>; - expectType(actual); - } - - /** it should traverse an object with numeric keys */ { - const actual = _ as EvaluateKey<{ 0: number }, '0'>; - expectType(actual); - } - - /** it should traverse a tuple */ { - const actual = _ as EvaluateKey<[boolean, string], '1'>; - expectType(actual); - } - - /** it should traverse an array */ { - const actual = _ as EvaluateKey; - expectType(actual); - } - - /** it should handle optional keys */ { - const actual = _ as EvaluateKey<{ foo?: number }, 'foo'>; - expectType(actual); - } - - /** it should handle optional indexes */ { - const actual = _ as EvaluateKey<[foo?: number], '0'>; - expectType(actual); - } - - /** it should add undefined if the key is not valid */ { - const actual = _ as EvaluateKey<{ foo: string }, 'foobar'>; - expectType(actual); - } - - /** it should evaluate to undefined if the key is out of bounds */ { - const actual = _ as EvaluateKey<[string], '1'>; - expectType(actual); - } - - /** it should work on path unions */ { - const actual = _ as EvaluateKey< - { foo: number; bar: string }, - 'foo' | 'bar' - >; - expectType(actual); - } - - /** it should add undefined if one of the keys doesn't exist */ { - const actual = _ as EvaluateKey<{ foo: number }, 'foo' | 'bar'>; - expectType(actual); - } - - /** it should add null if the type may be null */ { - const actual = _ as EvaluateKey; - expectType(actual); - } - - /** it should add undefined if the type may be undefined */ { - const actual = _ as EvaluateKey; - expectType(actual); - } - - /** it should add null and undefined if the type may be null or undefined */ { - const actual = _ as EvaluateKey; - expectType(actual); - } - - /** it should evaluate to undefined if the type is not traversable */ { - const actual = _ as EvaluateKey; - expectType(actual); - } - - /** it should evaluate to undefined if the key is non-numeric */ { - const actual = _ as EvaluateKey; - expectType(actual); - } - - /** it should work on unions of object */ { - const actual = _ as EvaluateKey<{ foo: number } | { foo: string }, 'foo'>; - expectType(actual); - } - - /** it should work on unions of object and tuple */ { - const actual = _ as EvaluateKey<{ 0: number } | [string], '0'>; - expectType(actual); - } - - /** it should work on unions of object and array */ { - const actual = _ as EvaluateKey<{ 0: number } | string[], '0'>; - expectType(actual); - } - - /** it should work on unions of tuple and array */ { - const actual = _ as EvaluateKey<[number] | string[], '0'>; - expectType(actual); - } - - /** it should add undefined if the key doesn't exist in one of the types */ { - const actual = _ as EvaluateKey<{ foo: number } | { bar: string }, 'foo'>; - expectType(actual); - } - - /** it should add undefined if the key is out of bounds in one of the types */ { - const actual = _ as EvaluateKey<[] | [number], '0'>; - expectType(actual); - } - - /** it should evaluate to any if the type is any */ { - const actual = _ as EvaluateKey; - expectType(actual); - } - - /** it should access methods on primitives */ { - const actual = _ as EvaluateKey; - expectType<() => string>(actual); - } - - /** it should access methods on arrays */ { - const actual = _ as EvaluateKey; - expectType<() => string>(actual); - } - - /** it should access methods on tuples */ { - const actual = _ as EvaluateKey<[number], 'toString'>; - expectType<() => string>(actual); - } -} - -/** {@link ValidPathPrefix} */ { - /** it should return the entire path if it is valid */ { - const actual = _ as ValidPathPrefix< - InfiniteType, - ['foo', 'bar', '0', 'baz', '42'] - >; - expectType<['foo', 'bar', '0', 'baz', '42']>(actual); - } - - /** it should return the entire nullable path if it is valid */ { - const actual = _ as ValidPathPrefix< - NullableInfiniteType, - ['foo', 'bar', '0', 'baz', '42'] - >; - expectType<['foo', 'bar', '0', 'baz', '42']>(actual); - } - - /** it should return the longest valid prefix */ { - const actual = _ as ValidPathPrefix< - InfiniteType, - ['foo', 'bar', '0', 'ba', '42'] - >; - expectType<['foo', 'bar', '0']>(actual); - } - - /** it should return the longest common valid prefix */ { - const actual = _ as ValidPathPrefix< - InfiniteType | { foo: string }, - ['foo', 'value'] - >; - expectType<['foo']>(actual); - } - - /** it should return an empty tuple when the path is an empty tuple */ { - const actual = _ as ValidPathPrefix, []>; - expectType<[]>(actual); - } - - /** it should be implemented tail recursively */ { - const actual = _ as ValidPathPrefix< - InfiniteType, - HundredTuple<'foo'> - >; - expectType>(actual); - } - - /** it should be distributive on path unions */ { - const actual = _ as ValidPathPrefix< - InfiniteType, - ['foo', 'bar', '0', 'ba', '42'] | ['foo', 'ba'] - >; - expectType<['foo', 'bar', '0'] | ['foo']>(actual); - } -} - -/** {@link HasPath} */ { - /** it should return true if the path exists */ { - const actual = _ as HasPath< - InfiniteType, - ['foo', 'bar', '0', 'baz', '42'] - >; - expectType(actual); - } - - /** it should return false if the path doesn't exist */ { - const actual = _ as HasPath< - InfiniteType, - ['foo', 'bar', '0', 'ba', '42'] - >; - expectType(actual); - } - - /** it should return true if the path exist in both types */ { - const actual = _ as HasPath< - InfiniteType | { foo: { bar: string } }, - ['foo', 'bar'] - >; - expectType(actual); - } - - /** it should return false if the path doesn't exist in both types */ { - const actual = _ as HasPath< - InfiniteType | { foo: { bar: string } }, - ['foo', 'value'] - >; - expectType(actual); - } - - /** it should return false if either of the paths is invalid */ { - const actual = _ as HasPath< - InfiniteType, - ['foo', 'bar'] | ['foo', 'ba'] - >; - expectType(actual); - } - - /** it should return true if both of the path are valid */ { - const actual = _ as HasPath< - InfiniteType, - ['foo', 'baz'] | ['foo', 'bar'] - >; - expectType(actual); - } - - /** it should evaluate to true when any is encountered */ { - const actual = _ as HasPath<{ foo: any }, ['foo', 'bar', 'baz']>; - expectType(actual); - } - - /** it should evaluate to false when any is not encountered */ { - const actual = _ as HasPath<{ foo: any }, ['bar', 'baz']>; - expectType(actual); - } -} - -/** {@link EvaluatePath} */ { - /** it should traverse an object */ { - const actual = _ as EvaluatePath< - InfiniteType, - ['foo', 'foo', 'value'] - >; - expectType(actual); - } - - /** it should traverse an index signature */ { - const actual = _ as EvaluatePath, [string]>; - expectType(actual); - } - - /** it should traverse a numeric index signature */ { - const actual = _ as EvaluatePath, [`${number}`]>; - expectType(actual); - } - - /** it should traverse a tuple */ { - const actual = _ as EvaluatePath< - InfiniteType, - ['bar', '0', 'value'] - >; - expectType(actual); - } - - /** it should traverse an array */ { - const actual = _ as EvaluatePath< - InfiniteType, - ['baz', '42', 'value'] - >; - expectType(actual); - } - - /** it should evaluate to never if the path is not valid */ { - const actual = _ as EvaluatePath, ['foobar']>; - expectType(actual); - } - - /** it should be implemented tail recursively */ { - const actual = _ as EvaluatePath, HundredTuple<'foo'>>; - expectType>(actual); - } - - /** it should work on path unions */ { - const actual = _ as EvaluatePath< - InfiniteType, - ['foo', 'foo'] | ['foo', 'value'] - >; - expectType>(actual); - } - - /** it should add undefined if one of the paths doesn't exist */ { - const actual = _ as EvaluatePath< - InfiniteType, - ['foo', 'value'] | ['foo', 'foobar'] - >; - expectType(actual); - } - - /** it should add null if the path contains a nullable */ { - const actual = _ as EvaluatePath< - { foo: null | { bar: string } }, - ['foo', 'bar'] - >; - expectType(actual); - } - - /** it should add undefined if the path contains an optional */ { - const actual = _ as EvaluatePath<{ foo?: { bar: string } }, ['foo', 'bar']>; - expectType(actual); - } - - /** it should add undefined if the path contains an undefineable */ { - const actual = _ as EvaluatePath< - { foo: undefined | { bar: string } }, - ['foo', 'bar'] - >; - expectType(actual); - } - - /** it should evaluate to undefined if the type is not traversable */ { - const actual = _ as EvaluatePath; - expectType(actual); - } - - /** it should work on type unions */ { - const actual = _ as EvaluatePath< - InfiniteType | InfiniteType, - ['foo', 'value'] - >; - expectType(actual); - } - - /** it should add undefined if the path doesn't exist in one of the types */ { - const actual = _ as EvaluatePath< - InfiniteType | Nested, - ['foo', 'value'] - >; - expectType(actual); - } - - /** it should evaluate to any if the type is any */ { - const actual = _ as EvaluatePath; - expectType(actual); - } - - /** it should evaluate to any if it encounters any */ { - const actual = _ as EvaluatePath<{ foo: any }, ['foo', 'bar', 'baz']>; - expectType(actual); - } - - /** it should not evaluate to any if it doesn't encounter any */ { - const actual = _ as EvaluatePath<{ foo: any }, ['bar', 'baz']>; - expectType(actual); - } - - /** it should not create a union which is too complex to represent */ { - const makeSetter = - () => - ( - _: PS, - value: EvaluatePath>, - ) => - value; - - const setter = makeSetter<{ foo: string }>(); - - const actual = setter('foo', 'bar'); - expectType(actual); - } -} diff --git a/src/__typetest__/path/eager.test-d.ts b/src/__typetest__/path/eager.test-d.ts deleted file mode 100644 index f53078cbf7a..00000000000 --- a/src/__typetest__/path/eager.test-d.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { expectType } from 'tsd'; - -import { ArrayPath, FieldPathValues, Path, PathValue } from '../../types'; -import { _, Depth3Type } from '../__fixtures__'; - -/** {@link Path} */ { - /** it should evaluate to never for an empty object */ { - const actual = _ as Path<{}>; - expectType(actual); - } - - /** it should evaluate to all paths of an object */ { - const actual = _ as Path<{ foo: { bar: string; baz: string } }>; - expectType<'foo' | 'foo.bar' | 'foo.baz'>(actual); - } - - /** it should include paths through tuples */ { - const actual = _ as Path<{ foo: [string, number] }>; - expectType<'foo' | 'foo.0' | 'foo.1'>(actual); - } - - /** it should include paths through arrays */ { - const actual = _ as Path<{ foo: string[] }>; - expectType<'foo' | `foo.${number}`>(actual); - } - - /** it should be able to avoid self-referencing/recursion, not crashing on self-referencing types. */ { - type Foo = { foo: Foo }; - const actual = _ as Path; - expectType<'foo'>(actual); - } - - /** it should not erroneously match subtypes as traversed */ { - type Foo = - | { - foo?: Foo; - bar?: { - baz: 1; - }; - } - | {}; - const actual = _ as Path; - expectType<'foo' | 'bar' | 'bar.baz'>(actual); - } -} - -/** {@link ArrayPath} */ { - /** it should evaluate to all paths pointing to a non-primitive array */ { - const actual = _ as ArrayPath<{ - foo: Array<{ bar: string[]; baz: string[] }>; - }>; - expectType<'foo'>(actual); - } - - /** it should include paths through tuples */ { - const actual = _ as ArrayPath<{ foo: [object[], object[]] }>; - expectType<'foo' | 'foo.0' | 'foo.1'>(actual); - } - - /** it should include paths through arrays */ { - const actual = _ as ArrayPath<{ foo: string[][][] }>; - expectType<'foo' | `foo.${number}`>(actual); - } - - /** it should be able to avoid self-referencing/recursion, not crashing on self-referencing types. */ { - type Foo = { foo: Foo[] }; - const actual = _ as ArrayPath; - expectType<'foo'>(actual); - } - - /** it should not erroneously match subtypes as traversed */ { - type Foo = - | { - bar?: { - baz?: 1; - fooArr?: Foo[]; - }; - } - | {}; - const actual = _ as ArrayPath; - expectType<'bar.fooArr'>(actual); - } -} - -/** {@link PathValue} */ { - /** it should traverse an object */ { - const actual = _ as PathValue, 'foo.foo.value'>; - expectType(actual); - } - - /** it should traverse a tuple */ { - const actual = _ as PathValue, 'bar.0.value'>; - expectType(actual); - } - - /** it should traverse an array */ { - const actual = _ as PathValue, 'baz.42.value'>; - expectType(actual); - } -} - -/** {@link FieldPathValues} */ { - /** it should resolve all paths */ { - const actual = _ as FieldPathValues< - Depth3Type, - ['foo.foo.value', 'bar.0.value', 'baz.42.value'] - >; - expectType<[string, string, string]>(actual); - } -} diff --git a/src/__typetest__/util.test-d.ts b/src/__typetest__/util.test-d.ts deleted file mode 100644 index c3e6e973e41..00000000000 --- a/src/__typetest__/util.test-d.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { expectType } from 'tsd'; - -import { IsAny, IsNever } from '../types'; - -import { _ } from './__fixtures__'; - -/** {@link IsAny} */ { - /** it should evaluate to true for any */ { - const actual = _ as IsAny; - expectType(actual); - } - - /** it should evaluate to false for never */ { - const actual = _ as IsAny; - expectType(actual); - } - - /** it should evaluate to false for unknown */ { - const actual = _ as IsAny; - expectType(actual); - } - - /** it should evaluate to false for string */ { - const actual = _ as IsAny; - expectType(actual); - } -} - -/** {@link IsNever} */ { - /** it should evaluate to false for any */ { - const actual = _ as IsNever; - expectType(actual); - } - - /** it should evaluate to true for never */ { - const actual = _ as IsNever; - expectType(actual); - } - - /** it should evaluate to false for unknown */ { - const actual = _ as IsNever; - expectType(actual); - } - - /** it should evaluate to false for string */ { - const actual = _ as IsNever; - expectType(actual); - } -} diff --git a/src/constants.ts b/src/constants.ts deleted file mode 100644 index a268c785a56..00000000000 --- a/src/constants.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ValidationMode } from './types'; - -export const EVENTS = { - BLUR: 'blur', - FOCUS_OUT: 'focusout', - CHANGE: 'change', -}; - -export const VALIDATION_MODE: ValidationMode = { - onBlur: 'onBlur', - onChange: 'onChange', - onSubmit: 'onSubmit', - onTouched: 'onTouched', - all: 'all', -}; - -export const INPUT_VALIDATION_RULES = { - max: 'max', - min: 'min', - maxLength: 'maxLength', - minLength: 'minLength', - pattern: 'pattern', - required: 'required', - validate: 'validate', -}; diff --git a/src/controller.tsx b/src/controller.tsx index f6bd560fe1d..1b7de828878 100644 --- a/src/controller.tsx +++ b/src/controller.tsx @@ -1,4 +1,5 @@ -import { ControllerProps, FieldPath, FieldValues } from './types'; +import { ControllerProps, FieldPath, FieldValues } from '@hookform/core'; + import { useController } from './useController'; /** diff --git a/src/index.ts b/src/index.ts index 7d1ccea48ea..3b36a5e6035 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,304 @@ +import { + appendErrors, + ArrayKey, + ArrayPath, + AsKey, + AsPathTuple, + BatchFieldArrayUpdate, + BrowserNativeObject, + ChangeHandler, + CheckKeyConstraint, + ContainsIndexable, + Control, + ControllerFieldState, + ControllerProps, + ControllerRenderProps, + CriteriaMode, + CustomElement, + DeepMap, + DeepPartial, + DeepPartialSkipArrayKey, + DeepRequired, + DefaultValues, + DelayCallback, + EmptyObject, + ErrorOption, + EvaluateKey, + EvaluatePath, + EventType, + Field, + FieldArray, + FieldArrayMethodProps, + FieldArrayPath, + FieldArrayPathValue, + FieldArrayWithId, + FieldElement, + FieldError, + FieldErrors, + FieldErrorsImpl, + FieldName, + FieldNamesMarkedBoolean, + FieldPath, + FieldPathByValue, + FieldPathValue, + FieldPathValues, + FieldRefs, + FieldValue, + FieldValues, + FormProviderProps, + FormState, + FormStateProxy, + FormStateSubjectRef, + get, + GetIsDirty, + GlobalError, + HasKey, + HasPath, + InternalFieldErrors, + InternalFieldName, + InternalNameSet, + IsAny, + IsEqual, + IsFlatObject, + IsNever, + IsTuple, + JoinPathTuple, + KeepStateOptions, + Key, + Keys, + LiteralUnion, + Merge, + Message, + Mode, + MultipleFieldErrors, + Names, + NativeFieldValue, + NestedValue, + NonUndefined, + Noop, + NumericKeys, + ObjectKeys, + Path, + PathString, + PathTuple, + PathValue, + Primitive, + ReadFormState, + Ref, + RefCallBack, + RegisterOptions, + Resolver, + ResolverError, + ResolverOptions, + ResolverResult, + ResolverSuccess, + set, + SetFieldValue, + SetFocusOptions, + SetValueConfig, + SplitPathString, + Subjects, + SubmitErrorHandler, + SubmitHandler, + ToKey, + Traversable, + TriggerConfig, + TupleKeys, + UnionToIntersection, + UseControllerProps, + UseControllerReturn, + UseFieldArrayAppend, + UseFieldArrayInsert, + UseFieldArrayMove, + UseFieldArrayPrepend, + UseFieldArrayProps, + UseFieldArrayRemove, + UseFieldArrayReplace, + UseFieldArrayReturn, + UseFieldArraySwap, + UseFieldArrayUpdate, + UseFormClearErrors, + UseFormGetFieldState, + UseFormGetValues, + UseFormHandleSubmit, + UseFormProps, + UseFormRegister, + UseFormRegisterReturn, + UseFormReset, + UseFormResetField, + UseFormReturn, + UseFormSetError, + UseFormSetFocus, + UseFormSetValue, + UseFormStateProps, + UseFormStateReturn, + UseFormTrigger, + UseFormUnregister, + UseFormWatch, + UseWatchProps, + Validate, + ValidateResult, + ValidationMode, + ValidationRule, + ValidationValue, + ValidationValueMessage, + ValidPathPrefix, + WatchInternal, + WatchObserver, +} from '@hookform/core'; + export * from './controller'; -export * from './logic'; -export * from './types'; export * from './useController'; export * from './useFieldArray'; export * from './useForm'; export * from './useFormContext'; export * from './useFormState'; export * from './useWatch'; -export * from './utils'; + +export { + ArrayKey, + ArrayPath, + AsKey, + AsPathTuple, + BatchFieldArrayUpdate, + BrowserNativeObject, + ChangeHandler, + CheckKeyConstraint, + ContainsIndexable, + Control, + ControllerFieldState, + ControllerProps, + ControllerRenderProps, + CriteriaMode, + CustomElement, + DeepMap, + DeepPartial, + DeepPartialSkipArrayKey, + DeepRequired, + DefaultValues, + DelayCallback, + EmptyObject, + ErrorOption, + EvaluateKey, + EvaluatePath, + EventType, + Field, + FieldArray, + FieldArrayMethodProps, + FieldArrayPath, + FieldArrayPathValue, + FieldArrayWithId, + FieldElement, + FieldError, + FieldErrors, + FieldErrorsImpl, + FieldName, + FieldNamesMarkedBoolean, + FieldPath, + FieldPathByValue, + FieldPathValue, + FieldPathValues, + FieldRefs, + FieldValue, + FieldValues, + FormProviderProps, + FormState, + FormStateProxy, + FormStateSubjectRef, + GetIsDirty, + GlobalError, + HasKey, + HasPath, + InternalFieldErrors, + InternalFieldName, + InternalNameSet, + IsAny, + IsEqual, + IsFlatObject, + IsNever, + IsTuple, + JoinPathTuple, + KeepStateOptions, + Key, + Keys, + LiteralUnion, + Merge, + Message, + Mode, + MultipleFieldErrors, + Names, + NativeFieldValue, + NestedValue, + NonUndefined, + Noop, + NumericKeys, + ObjectKeys, + Path, + PathString, + PathTuple, + PathValue, + Primitive, + ReadFormState, + Ref, + RefCallBack, + RegisterOptions, + Resolver, + ResolverError, + ResolverOptions, + ResolverResult, + ResolverSuccess, + SetFieldValue, + SetFocusOptions, + SetValueConfig, + SplitPathString, + Subjects, + SubmitErrorHandler, + SubmitHandler, + ToKey, + Traversable, + TriggerConfig, + TupleKeys, + UnionToIntersection, + UseControllerProps, + UseControllerReturn, + UseFieldArrayAppend, + UseFieldArrayInsert, + UseFieldArrayMove, + UseFieldArrayPrepend, + UseFieldArrayProps, + UseFieldArrayRemove, + UseFieldArrayReplace, + UseFieldArrayReturn, + UseFieldArraySwap, + UseFieldArrayUpdate, + UseFormClearErrors, + UseFormGetFieldState, + UseFormGetValues, + UseFormHandleSubmit, + UseFormProps, + UseFormRegister, + UseFormRegisterReturn, + UseFormReset, + UseFormResetField, + UseFormReturn, + UseFormSetError, + UseFormSetFocus, + UseFormSetValue, + UseFormStateProps, + UseFormStateReturn, + UseFormTrigger, + UseFormUnregister, + UseFormWatch, + UseWatchProps, + Validate, + ValidateResult, + ValidationMode, + ValidationRule, + ValidationValue, + ValidationValueMessage, + ValidPathPrefix, + WatchInternal, + WatchObserver, +}; + +export { appendErrors, get, set }; diff --git a/src/logic/appendErrors.ts b/src/logic/appendErrors.ts deleted file mode 100644 index db2dc7d8d5c..00000000000 --- a/src/logic/appendErrors.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { - InternalFieldErrors, - InternalFieldName, - ValidateResult, -} from '../types'; - -export default ( - name: InternalFieldName, - validateAllFieldCriteria: boolean, - errors: InternalFieldErrors, - type: string, - message: ValidateResult, -) => - validateAllFieldCriteria - ? { - ...errors[name], - types: { - ...(errors[name] && errors[name]!.types ? errors[name]!.types : {}), - [type]: message || true, - }, - } - : {}; diff --git a/src/logic/createFormControl.ts b/src/logic/createFormControl.ts deleted file mode 100644 index eef9232332e..00000000000 --- a/src/logic/createFormControl.ts +++ /dev/null @@ -1,1314 +0,0 @@ -import { EVENTS, VALIDATION_MODE } from '../constants'; -import { - BatchFieldArrayUpdate, - ChangeHandler, - DeepPartial, - DelayCallback, - EventType, - Field, - FieldError, - FieldNamesMarkedBoolean, - FieldPath, - FieldRefs, - FieldValues, - FormState, - GetIsDirty, - InternalFieldName, - Names, - Path, - Ref, - SetFieldValue, - SetValueConfig, - Subjects, - UseFormClearErrors, - UseFormGetFieldState, - UseFormGetValues, - UseFormHandleSubmit, - UseFormProps, - UseFormRegister, - UseFormReset, - UseFormResetField, - UseFormReturn, - UseFormSetError, - UseFormSetFocus, - UseFormSetValue, - UseFormTrigger, - UseFormUnregister, - UseFormWatch, - WatchInternal, - WatchObserver, -} from '../types'; -import cloneObject from '../utils/cloneObject'; -import compact from '../utils/compact'; -import convertToArrayPayload from '../utils/convertToArrayPayload'; -import createSubject from '../utils/createSubject'; -import deepEqual from '../utils/deepEqual'; -import get from '../utils/get'; -import isBoolean from '../utils/isBoolean'; -import isCheckBoxInput from '../utils/isCheckBoxInput'; -import isDateObject from '../utils/isDateObject'; -import isEmptyObject from '../utils/isEmptyObject'; -import isFileInput from '../utils/isFileInput'; -import isFunction from '../utils/isFunction'; -import isHTMLElement from '../utils/isHTMLElement'; -import isMultipleSelect from '../utils/isMultipleSelect'; -import isNullOrUndefined from '../utils/isNullOrUndefined'; -import isObject from '../utils/isObject'; -import isPrimitive from '../utils/isPrimitive'; -import isRadioOrCheckbox from '../utils/isRadioOrCheckbox'; -import isString from '../utils/isString'; -import isUndefined from '../utils/isUndefined'; -import isWeb from '../utils/isWeb'; -import live from '../utils/live'; -import set from '../utils/set'; -import unset from '../utils/unset'; - -import focusFieldBy from './focusFieldBy'; -import generateWatchOutput from './generateWatchOutput'; -import getDirtyFields from './getDirtyFields'; -import getEventValue from './getEventValue'; -import getFieldValue from './getFieldValue'; -import getFieldValueAs from './getFieldValueAs'; -import getResolverOptions from './getResolverOptions'; -import getRuleValue from './getRuleValue'; -import getValidationModes from './getValidationModes'; -import hasValidation from './hasValidation'; -import isNameInFieldArray from './isNameInFieldArray'; -import isWatched from './isWatched'; -import schemaErrorLookup from './schemaErrorLookup'; -import skipValidation from './skipValidation'; -import unsetEmptyArray from './unsetEmptyArray'; -import updateFieldArrayRootError from './updateFieldArrayRootError'; -import validateField from './validateField'; - -const defaultOptions = { - mode: VALIDATION_MODE.onSubmit, - reValidateMode: VALIDATION_MODE.onChange, - shouldFocusError: true, -} as const; - -export function createFormControl< - TFieldValues extends FieldValues = FieldValues, - TContext = any, ->( - props: UseFormProps = {}, - flushRootRender: () => void, -): Omit, 'formState'> { - let _options = { - ...defaultOptions, - ...props, - }; - const shouldCaptureDirtyFields = - props.resetOptions && props.resetOptions.keepDirtyValues; - let _formState: FormState = { - submitCount: 0, - isDirty: false, - isLoading: true, - isValidating: false, - isSubmitted: false, - isSubmitting: false, - isSubmitSuccessful: false, - isValid: false, - touchedFields: {}, - dirtyFields: {}, - errors: {}, - }; - let _fields = {}; - let _defaultValues = - isObject(_options.defaultValues) || isObject(_options.values) - ? cloneObject(_options.defaultValues || _options.values) || {} - : {}; - let _formValues = _options.shouldUnregister - ? {} - : cloneObject(_defaultValues); - let _stateFlags = { - action: false, - mount: false, - watch: false, - }; - let _names: Names = { - mount: new Set(), - unMount: new Set(), - array: new Set(), - watch: new Set(), - }; - let delayErrorCallback: DelayCallback | null; - let timer = 0; - const _proxyFormState = { - isDirty: false, - dirtyFields: false, - touchedFields: false, - isValidating: false, - isValid: false, - errors: false, - }; - const _subjects: Subjects = { - watch: createSubject(), - array: createSubject(), - state: createSubject(), - }; - const validationModeBeforeSubmit = getValidationModes(_options.mode); - const validationModeAfterSubmit = getValidationModes(_options.reValidateMode); - const shouldDisplayAllAssociatedErrors = - _options.criteriaMode === VALIDATION_MODE.all; - - const debounce = - (callback: T) => - (wait: number) => { - clearTimeout(timer); - timer = window.setTimeout(callback, wait); - }; - - const _updateValid = async (shouldUpdateValid?: boolean) => { - if (_proxyFormState.isValid || shouldUpdateValid) { - const isValid = _options.resolver - ? isEmptyObject((await _executeSchema()).errors) - : await executeBuiltInValidation(_fields, true); - - if (isValid !== _formState.isValid) { - _subjects.state.next({ - isValid, - }); - } - } - }; - - const _updateIsValidating = (value: boolean) => - _proxyFormState.isValidating && - _subjects.state.next({ - isValidating: value, - }); - - const _updateFieldArray: BatchFieldArrayUpdate = ( - name, - values = [], - method, - args, - shouldSetValues = true, - shouldUpdateFieldsAndState = true, - ) => { - if (args && method) { - _stateFlags.action = true; - if (shouldUpdateFieldsAndState && Array.isArray(get(_fields, name))) { - const fieldValues = method(get(_fields, name), args.argA, args.argB); - shouldSetValues && set(_fields, name, fieldValues); - } - - if ( - shouldUpdateFieldsAndState && - Array.isArray(get(_formState.errors, name)) - ) { - const errors = method( - get(_formState.errors, name), - args.argA, - args.argB, - ); - shouldSetValues && set(_formState.errors, name, errors); - unsetEmptyArray(_formState.errors, name); - } - - if ( - _proxyFormState.touchedFields && - shouldUpdateFieldsAndState && - Array.isArray(get(_formState.touchedFields, name)) - ) { - const touchedFields = method( - get(_formState.touchedFields, name), - args.argA, - args.argB, - ); - shouldSetValues && set(_formState.touchedFields, name, touchedFields); - } - - if (_proxyFormState.dirtyFields) { - _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues); - } - - _subjects.state.next({ - name, - isDirty: _getDirty(name, values), - dirtyFields: _formState.dirtyFields, - errors: _formState.errors, - isValid: _formState.isValid, - }); - } else { - set(_formValues, name, values); - } - }; - - const updateErrors = (name: InternalFieldName, error: FieldError) => { - set(_formState.errors, name, error); - _subjects.state.next({ - errors: _formState.errors, - }); - }; - - const updateValidAndValue = ( - name: InternalFieldName, - shouldSkipSetValueAs: boolean, - value?: unknown, - ref?: Ref, - ) => { - const field: Field = get(_fields, name); - - if (field) { - const defaultValue = get( - _formValues, - name, - isUndefined(value) ? get(_defaultValues, name) : value, - ); - - isUndefined(defaultValue) || - (ref && (ref as HTMLInputElement).defaultChecked) || - shouldSkipSetValueAs - ? set( - _formValues, - name, - shouldSkipSetValueAs ? defaultValue : getFieldValue(field._f), - ) - : setFieldValue(name, defaultValue); - - _stateFlags.mount && _updateValid(); - } - }; - - const updateTouchAndDirty = ( - name: InternalFieldName, - fieldValue: unknown, - isBlurEvent?: boolean, - shouldDirty?: boolean, - shouldRender?: boolean, - ): Partial< - Pick, 'dirtyFields' | 'isDirty' | 'touchedFields'> - > => { - let shouldUpdateField = false; - let isPreviousDirty = false; - const output: Partial> & { name: string } = { - name, - }; - - if (!isBlurEvent || shouldDirty) { - if (_proxyFormState.isDirty) { - isPreviousDirty = _formState.isDirty; - _formState.isDirty = output.isDirty = _getDirty(); - shouldUpdateField = isPreviousDirty !== output.isDirty; - } - - const isCurrentFieldPristine = deepEqual( - get(_defaultValues, name), - fieldValue, - ); - - isPreviousDirty = get(_formState.dirtyFields, name); - isCurrentFieldPristine - ? unset(_formState.dirtyFields, name) - : set(_formState.dirtyFields, name, true); - output.dirtyFields = _formState.dirtyFields; - shouldUpdateField = - shouldUpdateField || - (_proxyFormState.dirtyFields && - isPreviousDirty !== !isCurrentFieldPristine); - } - - if (isBlurEvent) { - const isPreviousFieldTouched = get(_formState.touchedFields, name); - - if (!isPreviousFieldTouched) { - set(_formState.touchedFields, name, isBlurEvent); - output.touchedFields = _formState.touchedFields; - shouldUpdateField = - shouldUpdateField || - (_proxyFormState.touchedFields && - isPreviousFieldTouched !== isBlurEvent); - } - } - - shouldUpdateField && shouldRender && _subjects.state.next(output); - - return shouldUpdateField ? output : {}; - }; - - const shouldRenderByError = ( - name: InternalFieldName, - isValid?: boolean, - error?: FieldError, - fieldState?: { - dirty?: FieldNamesMarkedBoolean; - isDirty?: boolean; - touched?: FieldNamesMarkedBoolean; - }, - ) => { - const previousFieldError = get(_formState.errors, name); - const shouldUpdateValid = - _proxyFormState.isValid && - isBoolean(isValid) && - _formState.isValid !== isValid; - - if (props.delayError && error) { - delayErrorCallback = debounce(() => updateErrors(name, error)); - delayErrorCallback(props.delayError); - } else { - clearTimeout(timer); - delayErrorCallback = null; - error - ? set(_formState.errors, name, error) - : unset(_formState.errors, name); - } - - if ( - (error ? !deepEqual(previousFieldError, error) : previousFieldError) || - !isEmptyObject(fieldState) || - shouldUpdateValid - ) { - const updatedFormState = { - ...fieldState, - ...(shouldUpdateValid && isBoolean(isValid) ? { isValid } : {}), - errors: _formState.errors, - name, - }; - - _formState = { - ..._formState, - ...updatedFormState, - }; - - _subjects.state.next(updatedFormState); - } - - _updateIsValidating(false); - }; - - const _executeSchema = async (name?: InternalFieldName[]) => - await _options.resolver!( - _formValues as TFieldValues, - _options.context, - getResolverOptions( - name || _names.mount, - _fields, - _options.criteriaMode, - _options.shouldUseNativeValidation, - ), - ); - - const executeSchemaAndUpdateState = async (names?: InternalFieldName[]) => { - const { errors } = await _executeSchema(); - - if (names) { - for (const name of names) { - const error = get(errors, name); - error - ? set(_formState.errors, name, error) - : unset(_formState.errors, name); - } - } else { - _formState.errors = errors; - } - - return errors; - }; - - const executeBuiltInValidation = async ( - fields: FieldRefs, - shouldOnlyCheckValid?: boolean, - context: { - valid: boolean; - } = { - valid: true, - }, - ) => { - for (const name in fields) { - const field = fields[name]; - - if (field) { - const { _f, ...fieldValue } = field; - - if (_f) { - const isFieldArrayRoot = _names.array.has(_f.name); - const fieldError = await validateField( - field, - _formValues, - shouldDisplayAllAssociatedErrors, - _options.shouldUseNativeValidation, - isFieldArrayRoot, - ); - - if (fieldError[_f.name]) { - context.valid = false; - if (shouldOnlyCheckValid) { - break; - } - } - - !shouldOnlyCheckValid && - (get(fieldError, _f.name) - ? isFieldArrayRoot - ? updateFieldArrayRootError( - _formState.errors, - fieldError, - _f.name, - ) - : set(_formState.errors, _f.name, fieldError[_f.name]) - : unset(_formState.errors, _f.name)); - } - - fieldValue && - (await executeBuiltInValidation( - fieldValue, - shouldOnlyCheckValid, - context, - )); - } - } - - return context.valid; - }; - - const _removeUnmounted = () => { - for (const name of _names.unMount) { - const field: Field = get(_fields, name); - - field && - (field._f.refs - ? field._f.refs.every((ref) => !live(ref)) - : !live(field._f.ref)) && - unregister(name as FieldPath); - } - - _names.unMount = new Set(); - }; - - const _getDirty: GetIsDirty = (name, data) => ( - name && data && set(_formValues, name, data), - !deepEqual(getValues(), _defaultValues) - ); - - const _getWatch: WatchInternal = ( - names, - defaultValue, - isGlobal, - ) => - generateWatchOutput( - names, - _names, - { - ...(_stateFlags.mount - ? _formValues - : isUndefined(defaultValue) - ? _defaultValues - : isString(names) - ? { [names]: defaultValue } - : defaultValue), - }, - isGlobal, - defaultValue, - ); - - const _getFieldArray = ( - name: InternalFieldName, - ): Partial[] => - compact( - get( - _stateFlags.mount ? _formValues : _defaultValues, - name, - props.shouldUnregister ? get(_defaultValues, name, []) : [], - ), - ); - - const setFieldValue = ( - name: InternalFieldName, - value: SetFieldValue, - options: SetValueConfig = {}, - ) => { - const field: Field = get(_fields, name); - let fieldValue: unknown = value; - - if (field) { - const fieldReference = field._f; - - if (fieldReference) { - !fieldReference.disabled && - set(_formValues, name, getFieldValueAs(value, fieldReference)); - - fieldValue = - isHTMLElement(fieldReference.ref) && isNullOrUndefined(value) - ? '' - : value; - - if (isMultipleSelect(fieldReference.ref)) { - [...fieldReference.ref.options].forEach( - (optionRef) => - (optionRef.selected = ( - fieldValue as InternalFieldName[] - ).includes(optionRef.value)), - ); - } else if (fieldReference.refs) { - if (isCheckBoxInput(fieldReference.ref)) { - fieldReference.refs.length > 1 - ? fieldReference.refs.forEach( - (checkboxRef) => - (!checkboxRef.defaultChecked || !checkboxRef.disabled) && - (checkboxRef.checked = Array.isArray(fieldValue) - ? !!(fieldValue as []).find( - (data: string) => data === checkboxRef.value, - ) - : fieldValue === checkboxRef.value), - ) - : fieldReference.refs[0] && - (fieldReference.refs[0].checked = !!fieldValue); - } else { - fieldReference.refs.forEach( - (radioRef: HTMLInputElement) => - (radioRef.checked = radioRef.value === fieldValue), - ); - } - } else if (isFileInput(fieldReference.ref)) { - fieldReference.ref.value = ''; - } else { - fieldReference.ref.value = fieldValue; - - if (!fieldReference.ref.type) { - _subjects.watch.next({ - name, - }); - } - } - } - } - - (options.shouldDirty || options.shouldTouch) && - updateTouchAndDirty( - name, - fieldValue, - options.shouldTouch, - options.shouldDirty, - true, - ); - - options.shouldValidate && trigger(name as Path); - }; - - const setValues = < - T extends InternalFieldName, - K extends SetFieldValue, - U extends SetValueConfig, - >( - name: T, - value: K, - options: U, - ) => { - for (const fieldKey in value) { - const fieldValue = value[fieldKey]; - const fieldName = `${name}.${fieldKey}`; - const field = get(_fields, fieldName); - - (_names.array.has(name) || - !isPrimitive(fieldValue) || - (field && !field._f)) && - !isDateObject(fieldValue) - ? setValues(fieldName, fieldValue, options) - : setFieldValue(fieldName, fieldValue, options); - } - }; - - const setValue: UseFormSetValue = ( - name, - value, - options = {}, - ) => { - const field = get(_fields, name); - const isFieldArray = _names.array.has(name); - const cloneValue = cloneObject(value); - - set(_formValues, name, cloneValue); - - if (isFieldArray) { - _subjects.array.next({ - name, - values: _formValues, - }); - - if ( - (_proxyFormState.isDirty || _proxyFormState.dirtyFields) && - options.shouldDirty - ) { - _subjects.state.next({ - name, - dirtyFields: getDirtyFields(_defaultValues, _formValues), - isDirty: _getDirty(name, cloneValue), - }); - } - } else { - field && !field._f && !isNullOrUndefined(cloneValue) - ? setValues(name, cloneValue, options) - : setFieldValue(name, cloneValue, options); - } - - isWatched(name, _names) && _subjects.state.next({}); - _subjects.watch.next({ - name, - }); - !_stateFlags.mount && flushRootRender(); - }; - - const onChange: ChangeHandler = async (event) => { - const target = event.target; - let name = target.name; - const field: Field = get(_fields, name); - const getCurrentFieldValue = () => - target.type ? getFieldValue(field._f) : getEventValue(event); - - if (field) { - let error; - let isValid; - const fieldValue = getCurrentFieldValue(); - const isBlurEvent = - event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT; - const shouldSkipValidation = - (!hasValidation(field._f) && - !_options.resolver && - !get(_formState.errors, name) && - !field._f.deps) || - skipValidation( - isBlurEvent, - get(_formState.touchedFields, name), - _formState.isSubmitted, - validationModeAfterSubmit, - validationModeBeforeSubmit, - ); - const watched = isWatched(name, _names, isBlurEvent); - - set(_formValues, name, fieldValue); - - if (isBlurEvent) { - field._f.onBlur && field._f.onBlur(event); - delayErrorCallback && delayErrorCallback(0); - } else if (field._f.onChange) { - field._f.onChange(event); - } - - const fieldState = updateTouchAndDirty( - name, - fieldValue, - isBlurEvent, - false, - ); - - const shouldRender = !isEmptyObject(fieldState) || watched; - - !isBlurEvent && - _subjects.watch.next({ - name, - type: event.type, - }); - - if (shouldSkipValidation) { - _proxyFormState.isValid && _updateValid(); - - return ( - shouldRender && - _subjects.state.next({ name, ...(watched ? {} : fieldState) }) - ); - } - - !isBlurEvent && watched && _subjects.state.next({}); - - _updateIsValidating(true); - - if (_options.resolver) { - const { errors } = await _executeSchema([name]); - const previousErrorLookupResult = schemaErrorLookup( - _formState.errors, - _fields, - name, - ); - const errorLookupResult = schemaErrorLookup( - errors, - _fields, - previousErrorLookupResult.name || name, - ); - - error = errorLookupResult.error; - name = errorLookupResult.name; - - isValid = isEmptyObject(errors); - } else { - error = ( - await validateField( - field, - _formValues, - shouldDisplayAllAssociatedErrors, - _options.shouldUseNativeValidation, - ) - )[name]; - - if (error) { - isValid = false; - } else if (_proxyFormState.isValid) { - isValid = await executeBuiltInValidation(_fields, true); - } - } - - field._f.deps && - trigger( - field._f.deps as FieldPath | FieldPath[], - ); - shouldRenderByError(name, isValid, error, fieldState); - } - }; - - const trigger: UseFormTrigger = async (name, options = {}) => { - let isValid; - let validationResult; - const fieldNames = convertToArrayPayload(name) as InternalFieldName[]; - - _updateIsValidating(true); - - if (_options.resolver) { - const errors = await executeSchemaAndUpdateState( - isUndefined(name) ? name : fieldNames, - ); - - isValid = isEmptyObject(errors); - validationResult = name - ? !fieldNames.some((name) => get(errors, name)) - : isValid; - } else if (name) { - validationResult = ( - await Promise.all( - fieldNames.map(async (fieldName) => { - const field = get(_fields, fieldName); - return await executeBuiltInValidation( - field && field._f ? { [fieldName]: field } : field, - ); - }), - ) - ).every(Boolean); - !(!validationResult && !_formState.isValid) && _updateValid(); - } else { - validationResult = isValid = await executeBuiltInValidation(_fields); - } - - _subjects.state.next({ - ...(!isString(name) || - (_proxyFormState.isValid && isValid !== _formState.isValid) - ? {} - : { name }), - ...(_options.resolver || !name ? { isValid } : {}), - errors: _formState.errors, - isValidating: false, - }); - - options.shouldFocus && - !validationResult && - focusFieldBy( - _fields, - (key) => key && get(_formState.errors, key), - name ? fieldNames : _names.mount, - ); - - return validationResult; - }; - - const getValues: UseFormGetValues = ( - fieldNames?: - | FieldPath - | ReadonlyArray>, - ) => { - const values = { - ..._defaultValues, - ...(_stateFlags.mount ? _formValues : {}), - }; - - return isUndefined(fieldNames) - ? values - : isString(fieldNames) - ? get(values, fieldNames) - : fieldNames.map((name) => get(values, name)); - }; - - const getFieldState: UseFormGetFieldState = ( - name, - formState, - ) => ({ - invalid: !!get((formState || _formState).errors, name), - isDirty: !!get((formState || _formState).dirtyFields, name), - isTouched: !!get((formState || _formState).touchedFields, name), - error: get((formState || _formState).errors, name), - }); - - const clearErrors: UseFormClearErrors = (name) => { - name && - convertToArrayPayload(name).forEach((inputName) => - unset(_formState.errors, inputName), - ); - - _subjects.state.next({ - errors: name ? _formState.errors : {}, - }); - }; - - const setError: UseFormSetError = (name, error, options) => { - const ref = (get(_fields, name, { _f: {} })._f || {}).ref; - - set(_formState.errors, name, { - ...error, - ref, - }); - - _subjects.state.next({ - name, - errors: _formState.errors, - isValid: false, - }); - - options && options.shouldFocus && ref && ref.focus && ref.focus(); - }; - - const watch: UseFormWatch = ( - name?: - | FieldPath - | ReadonlyArray> - | WatchObserver, - defaultValue?: DeepPartial, - ) => - isFunction(name) - ? _subjects.watch.subscribe({ - next: (payload) => - name( - _getWatch(undefined, defaultValue), - payload as { - name?: FieldPath; - type?: EventType; - value?: unknown; - }, - ), - }) - : _getWatch( - name as InternalFieldName | InternalFieldName[], - defaultValue, - true, - ); - - const unregister: UseFormUnregister = (name, options = {}) => { - for (const fieldName of name ? convertToArrayPayload(name) : _names.mount) { - _names.mount.delete(fieldName); - _names.array.delete(fieldName); - - if (get(_fields, fieldName)) { - if (!options.keepValue) { - unset(_fields, fieldName); - unset(_formValues, fieldName); - } - - !options.keepError && unset(_formState.errors, fieldName); - !options.keepDirty && unset(_formState.dirtyFields, fieldName); - !options.keepTouched && unset(_formState.touchedFields, fieldName); - !_options.shouldUnregister && - !options.keepDefaultValue && - unset(_defaultValues, fieldName); - } - } - - _subjects.watch.next({}); - - _subjects.state.next({ - ..._formState, - ...(!options.keepDirty ? {} : { isDirty: _getDirty() }), - }); - - !options.keepIsValid && _updateValid(); - }; - - const register: UseFormRegister = (name, options = {}) => { - let field = get(_fields, name); - const disabledIsDefined = isBoolean(options.disabled); - - set(_fields, name, { - ...(field || {}), - _f: { - ...(field && field._f ? field._f : { ref: { name } }), - name, - mount: true, - ...options, - }, - }); - _names.mount.add(name); - - field - ? disabledIsDefined && - set( - _formValues, - name, - options.disabled - ? undefined - : get(_formValues, name, getFieldValue(field._f)), - ) - : updateValidAndValue(name, true, options.value); - - return { - ...(disabledIsDefined ? { disabled: options.disabled } : {}), - ...(_options.shouldUseNativeValidation - ? { - required: !!options.required, - min: getRuleValue(options.min), - max: getRuleValue(options.max), - minLength: getRuleValue(options.minLength) as number, - maxLength: getRuleValue(options.maxLength) as number, - pattern: getRuleValue(options.pattern) as string, - } - : {}), - name, - onChange, - onBlur: onChange, - ref: (ref: HTMLInputElement | null): void => { - if (ref) { - register(name, options); - field = get(_fields, name); - - const fieldRef = isUndefined(ref.value) - ? ref.querySelectorAll - ? (ref.querySelectorAll('input,select,textarea')[0] as Ref) || ref - : ref - : ref; - const radioOrCheckbox = isRadioOrCheckbox(fieldRef); - const refs = field._f.refs || []; - - if ( - radioOrCheckbox - ? refs.find((option: Ref) => option === fieldRef) - : fieldRef === field._f.ref - ) { - return; - } - - set(_fields, name, { - _f: { - ...field._f, - ...(radioOrCheckbox - ? { - refs: [ - ...refs.filter(live), - fieldRef, - ...(Array.isArray(get(_defaultValues, name)) ? [{}] : []), - ], - ref: { type: fieldRef.type, name }, - } - : { ref: fieldRef }), - }, - }); - - updateValidAndValue(name, false, undefined, fieldRef); - } else { - field = get(_fields, name, {}); - - if (field._f) { - field._f.mount = false; - } - - (_options.shouldUnregister || options.shouldUnregister) && - !(isNameInFieldArray(_names.array, name) && _stateFlags.action) && - _names.unMount.add(name); - } - }, - }; - }; - - const _focusError = () => - _options.shouldFocusError && - focusFieldBy( - _fields, - (key) => key && get(_formState.errors, key), - _names.mount, - ); - - const handleSubmit: UseFormHandleSubmit = - (onValid, onInvalid) => async (e) => { - if (e) { - e.preventDefault && e.preventDefault(); - e.persist && e.persist(); - } - let fieldValues = cloneObject(_formValues); - - _subjects.state.next({ - isSubmitting: true, - }); - - if (_options.resolver) { - const { errors, values } = await _executeSchema(); - _formState.errors = errors; - fieldValues = values; - } else { - await executeBuiltInValidation(_fields); - } - - unset(_formState.errors, 'root'); - - if (isEmptyObject(_formState.errors)) { - _subjects.state.next({ - errors: {}, - }); - await onValid(fieldValues as TFieldValues, e); - } else { - if (onInvalid) { - await onInvalid({ ..._formState.errors }, e); - } - _focusError(); - } - - _subjects.state.next({ - isSubmitted: true, - isSubmitting: false, - isSubmitSuccessful: isEmptyObject(_formState.errors), - submitCount: _formState.submitCount + 1, - errors: _formState.errors, - }); - }; - - const resetField: UseFormResetField = (name, options = {}) => { - if (get(_fields, name)) { - if (isUndefined(options.defaultValue)) { - setValue(name, get(_defaultValues, name)); - } else { - setValue(name, options.defaultValue); - set(_defaultValues, name, options.defaultValue); - } - - if (!options.keepTouched) { - unset(_formState.touchedFields, name); - } - - if (!options.keepDirty) { - unset(_formState.dirtyFields, name); - _formState.isDirty = options.defaultValue - ? _getDirty(name, get(_defaultValues, name)) - : _getDirty(); - } - - if (!options.keepError) { - unset(_formState.errors, name); - _proxyFormState.isValid && _updateValid(); - } - - _subjects.state.next({ ..._formState }); - } - }; - - const _reset: UseFormReset = ( - formValues, - keepStateOptions = {}, - ) => { - const updatedValues = formValues || _defaultValues; - const cloneUpdatedValues = cloneObject(updatedValues); - const values = - formValues && !isEmptyObject(formValues) - ? cloneUpdatedValues - : _defaultValues; - - if (!keepStateOptions.keepDefaultValues) { - _defaultValues = updatedValues; - } - - if (!keepStateOptions.keepValues) { - if (keepStateOptions.keepDirtyValues || shouldCaptureDirtyFields) { - for (const fieldName of _names.mount) { - get(_formState.dirtyFields, fieldName) - ? set(values, fieldName, get(_formValues, fieldName)) - : setValue( - fieldName as FieldPath, - get(values, fieldName), - ); - } - } else { - if (isWeb && isUndefined(formValues)) { - for (const name of _names.mount) { - const field = get(_fields, name); - if (field && field._f) { - const fieldReference = Array.isArray(field._f.refs) - ? field._f.refs[0] - : field._f.ref; - - if (isHTMLElement(fieldReference)) { - const form = fieldReference.closest('form'); - if (form) { - form.reset(); - break; - } - } - } - } - } - - _fields = {}; - } - - _formValues = props.shouldUnregister - ? keepStateOptions.keepDefaultValues - ? cloneObject(_defaultValues) - : {} - : cloneUpdatedValues; - - _subjects.array.next({ - values, - }); - - _subjects.watch.next({ - values, - }); - } - - _names = { - mount: new Set(), - unMount: new Set(), - array: new Set(), - watch: new Set(), - watchAll: false, - focus: '', - }; - - !_stateFlags.mount && flushRootRender(); - - _stateFlags.mount = - !_proxyFormState.isValid || !!keepStateOptions.keepIsValid; - - _stateFlags.watch = !!props.shouldUnregister; - - _subjects.state.next({ - submitCount: keepStateOptions.keepSubmitCount - ? _formState.submitCount - : 0, - isDirty: - keepStateOptions.keepDirty || keepStateOptions.keepDirtyValues - ? _formState.isDirty - : !!( - keepStateOptions.keepDefaultValues && - !deepEqual(formValues, _defaultValues) - ), - isSubmitted: keepStateOptions.keepIsSubmitted - ? _formState.isSubmitted - : false, - dirtyFields: - keepStateOptions.keepDirty || keepStateOptions.keepDirtyValues - ? _formState.dirtyFields - : keepStateOptions.keepDefaultValues && formValues - ? getDirtyFields(_defaultValues, formValues) - : {}, - touchedFields: keepStateOptions.keepTouched - ? _formState.touchedFields - : {}, - errors: keepStateOptions.keepErrors ? _formState.errors : {}, - isSubmitting: false, - isSubmitSuccessful: false, - }); - }; - - const reset: UseFormReset = (formValues, keepStateOptions) => - _reset( - isFunction(formValues) - ? formValues(_formValues as TFieldValues) - : formValues, - keepStateOptions, - ); - - const setFocus: UseFormSetFocus = (name, options = {}) => { - const field = get(_fields, name); - const fieldReference = field && field._f; - - if (fieldReference) { - const fieldRef = fieldReference.refs - ? fieldReference.refs[0] - : fieldReference.ref; - - if (fieldRef.focus) { - fieldRef.focus(); - options.shouldSelect && fieldRef.select(); - } - } - }; - - const _updateFormState = ( - updatedFormState: Partial>, - ) => { - _formState = { - ..._formState, - ...updatedFormState, - }; - }; - - if (isFunction(_options.defaultValues)) { - _options.defaultValues().then((values) => { - reset(values, _options.resetOptions); - _subjects.state.next({ - isLoading: false, - }); - }); - } - - return { - control: { - register, - unregister, - getFieldState, - _executeSchema, - _focusError, - _getWatch, - _getDirty, - _updateValid, - _removeUnmounted, - _updateFieldArray, - _getFieldArray, - _reset, - _updateFormState, - _subjects, - _proxyFormState, - get _fields() { - return _fields; - }, - get _formValues() { - return _formValues; - }, - get _stateFlags() { - return _stateFlags; - }, - set _stateFlags(value) { - _stateFlags = value; - }, - get _defaultValues() { - return _defaultValues; - }, - get _names() { - return _names; - }, - set _names(value) { - _names = value; - }, - get _formState() { - return _formState; - }, - set _formState(value) { - _formState = value; - }, - get _options() { - return _options; - }, - set _options(value) { - _options = { - ..._options, - ...value, - }; - }, - }, - trigger, - register, - handleSubmit, - watch, - setValue, - getValues, - reset, - resetField, - clearErrors, - unregister, - setError, - setFocus, - getFieldState, - }; -} diff --git a/src/logic/focusFieldBy.ts b/src/logic/focusFieldBy.ts deleted file mode 100644 index d341bb80fcb..00000000000 --- a/src/logic/focusFieldBy.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { FieldRefs, InternalFieldName } from '../types'; -import { get } from '../utils'; -import isObject from '../utils/isObject'; - -const focusFieldBy = ( - fields: FieldRefs, - callback: (name?: string) => boolean, - fieldsNames?: Set | InternalFieldName[], -) => { - for (const key of fieldsNames || Object.keys(fields)) { - const field = get(fields, key); - - if (field) { - const { _f, ...currentField } = field; - - if (_f && callback(_f.name)) { - if (_f.ref.focus) { - _f.ref.focus(); - break; - } else if (_f.refs && _f.refs[0].focus) { - _f.refs[0].focus(); - break; - } - } else if (isObject(currentField)) { - focusFieldBy(currentField, callback); - } - } - } -}; - -export default focusFieldBy; diff --git a/src/logic/generateId.ts b/src/logic/generateId.ts deleted file mode 100644 index a19c2f4ad99..00000000000 --- a/src/logic/generateId.ts +++ /dev/null @@ -1,10 +0,0 @@ -export default () => { - const d = - typeof performance === 'undefined' ? Date.now() : performance.now() * 1000; - - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { - const r = (Math.random() * 16 + d) % 16 | 0; - - return (c == 'x' ? r : (r & 0x3) | 0x8).toString(16); - }); -}; diff --git a/src/logic/generateWatchOutput.ts b/src/logic/generateWatchOutput.ts deleted file mode 100644 index ef5a76ddbf1..00000000000 --- a/src/logic/generateWatchOutput.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { DeepPartial, FieldValues, Names } from '../types'; -import get from '../utils/get'; -import isString from '../utils/isString'; - -export default ( - names: string | string[] | undefined, - _names: Names, - formValues?: FieldValues, - isGlobal?: boolean, - defaultValue?: DeepPartial | unknown, -) => { - if (isString(names)) { - isGlobal && _names.watch.add(names); - return get(formValues, names, defaultValue); - } - - if (Array.isArray(names)) { - return names.map( - (fieldName) => ( - isGlobal && _names.watch.add(fieldName), get(formValues, fieldName) - ), - ); - } - - isGlobal && (_names.watchAll = true); - - return formValues; -}; diff --git a/src/logic/getCheckboxValue.ts b/src/logic/getCheckboxValue.ts deleted file mode 100644 index 8b036588181..00000000000 --- a/src/logic/getCheckboxValue.ts +++ /dev/null @@ -1,35 +0,0 @@ -import isUndefined from '../utils/isUndefined'; - -type CheckboxFieldResult = { - isValid: boolean; - value: string | string[] | boolean | undefined; -}; - -const defaultResult: CheckboxFieldResult = { - value: false, - isValid: false, -}; - -const validResult = { value: true, isValid: true }; - -export default (options?: HTMLInputElement[]): CheckboxFieldResult => { - if (Array.isArray(options)) { - if (options.length > 1) { - const values = options - .filter((option) => option && option.checked && !option.disabled) - .map((option) => option.value); - return { value: values, isValid: !!values.length }; - } - - return options[0].checked && !options[0].disabled - ? // @ts-expect-error expected to work in the browser - options[0].attributes && !isUndefined(options[0].attributes.value) - ? isUndefined(options[0].value) || options[0].value === '' - ? validResult - : { value: options[0].value, isValid: true } - : validResult - : defaultResult; - } - - return defaultResult; -}; diff --git a/src/logic/getDirtyFields.ts b/src/logic/getDirtyFields.ts deleted file mode 100644 index 01435f6616d..00000000000 --- a/src/logic/getDirtyFields.ts +++ /dev/null @@ -1,71 +0,0 @@ -import deepEqual from '../utils/deepEqual'; -import isNullOrUndefined from '../utils/isNullOrUndefined'; -import isObject from '../utils/isObject'; -import isPrimitive from '../utils/isPrimitive'; -import isUndefined from '../utils/isUndefined'; -import objectHasFunction from '../utils/objectHasFunction'; - -function markFieldsDirty(data: U, fields: Record = {}) { - const isParentNodeArray = Array.isArray(data); - - if (isObject(data) || isParentNodeArray) { - for (const key in data) { - if ( - Array.isArray(data[key]) || - (isObject(data[key]) && !objectHasFunction(data[key])) - ) { - fields[key] = Array.isArray(data[key]) ? [] : {}; - markFieldsDirty(data[key], fields[key]); - } else if (!isNullOrUndefined(data[key])) { - fields[key] = true; - } - } - } - - return fields; -} - -function getDirtyFieldsFromDefaultValues( - data: T, - formValues: T, - dirtyFieldsFromValues: any, -) { - const isParentNodeArray = Array.isArray(data); - - if (isObject(data) || isParentNodeArray) { - for (const key in data) { - if ( - Array.isArray(data[key]) || - (isObject(data[key]) && !objectHasFunction(data[key])) - ) { - if ( - isUndefined(formValues) || - isPrimitive(dirtyFieldsFromValues[key]) - ) { - dirtyFieldsFromValues[key] = Array.isArray(data[key]) - ? markFieldsDirty(data[key], []) - : { ...markFieldsDirty(data[key]) }; - } else { - getDirtyFieldsFromDefaultValues( - data[key], - isNullOrUndefined(formValues) ? {} : formValues[key], - dirtyFieldsFromValues[key], - ); - } - } else { - deepEqual(data[key], formValues[key]) - ? delete dirtyFieldsFromValues[key] - : (dirtyFieldsFromValues[key] = true); - } - } - } - - return dirtyFieldsFromValues; -} - -export default (defaultValues: T, formValues: T) => - getDirtyFieldsFromDefaultValues( - defaultValues, - formValues, - markFieldsDirty(formValues), - ); diff --git a/src/logic/getEventValue.ts b/src/logic/getEventValue.ts deleted file mode 100644 index abade454de1..00000000000 --- a/src/logic/getEventValue.ts +++ /dev/null @@ -1,11 +0,0 @@ -import isCheckBoxInput from '../utils/isCheckBoxInput'; -import isObject from '../utils/isObject'; - -type Event = { target: any }; - -export default (event: unknown) => - isObject(event) && (event as Event).target - ? isCheckBoxInput((event as Event).target) - ? (event as Event).target.checked - : (event as Event).target.value - : event; diff --git a/src/logic/getFieldValue.ts b/src/logic/getFieldValue.ts deleted file mode 100644 index e2fc8bd0718..00000000000 --- a/src/logic/getFieldValue.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Field } from '../types'; -import isCheckBox from '../utils/isCheckBoxInput'; -import isFileInput from '../utils/isFileInput'; -import isMultipleSelect from '../utils/isMultipleSelect'; -import isRadioInput from '../utils/isRadioInput'; -import isUndefined from '../utils/isUndefined'; - -import getCheckboxValue from './getCheckboxValue'; -import getFieldValueAs from './getFieldValueAs'; -import getRadioValue from './getRadioValue'; - -export default function getFieldValue(_f: Field['_f']) { - const ref = _f.ref; - - if (_f.refs ? _f.refs.every((ref) => ref.disabled) : ref.disabled) { - return; - } - - if (isFileInput(ref)) { - return ref.files; - } - - if (isRadioInput(ref)) { - return getRadioValue(_f.refs).value; - } - - if (isMultipleSelect(ref)) { - return [...ref.selectedOptions].map(({ value }) => value); - } - - if (isCheckBox(ref)) { - return getCheckboxValue(_f.refs).value; - } - - return getFieldValueAs(isUndefined(ref.value) ? _f.ref.value : ref.value, _f); -} diff --git a/src/logic/getFieldValueAs.ts b/src/logic/getFieldValueAs.ts deleted file mode 100644 index e0b4ed4f703..00000000000 --- a/src/logic/getFieldValueAs.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Field, NativeFieldValue } from '../types'; -import isString from '../utils/isString'; -import isUndefined from '../utils/isUndefined'; - -export default ( - value: T, - { valueAsNumber, valueAsDate, setValueAs }: Field['_f'], -) => - isUndefined(value) - ? value - : valueAsNumber - ? value === '' - ? NaN - : value - ? +value - : value - : valueAsDate && isString(value) - ? new Date(value) - : setValueAs - ? setValueAs(value) - : value; diff --git a/src/logic/getFocusFieldName.ts b/src/logic/getFocusFieldName.ts deleted file mode 100644 index a468079576c..00000000000 --- a/src/logic/getFocusFieldName.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { FieldArrayMethodProps, InternalFieldName } from '../types'; -import isUndefined from '../utils/isUndefined'; - -export default ( - name: InternalFieldName, - index: number, - options: FieldArrayMethodProps = {}, -): string => - options.shouldFocus || isUndefined(options.shouldFocus) - ? options.focusName || - `${name}.${isUndefined(options.focusIndex) ? index : options.focusIndex}.` - : ''; diff --git a/src/logic/getNodeParentName.ts b/src/logic/getNodeParentName.ts deleted file mode 100644 index bd8640e743a..00000000000 --- a/src/logic/getNodeParentName.ts +++ /dev/null @@ -1,2 +0,0 @@ -export default (name: string) => - name.substring(0, name.search(/\.\d+(\.|$)/)) || name; diff --git a/src/logic/getProxyFormState.ts b/src/logic/getProxyFormState.ts deleted file mode 100644 index 2c7402c6e71..00000000000 --- a/src/logic/getProxyFormState.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { VALIDATION_MODE } from '../constants'; -import { Control, FieldValues, FormState, ReadFormState } from '../types'; - -export default ( - formState: FormState, - control: Control, - localProxyFormState?: ReadFormState, - isRoot = true, -) => { - const result = { - defaultValues: control._defaultValues, - } as typeof formState; - - for (const key in formState) { - Object.defineProperty(result, key, { - get: () => { - const _key = key as keyof FormState & keyof ReadFormState; - - if (control._proxyFormState[_key] !== VALIDATION_MODE.all) { - control._proxyFormState[_key] = !isRoot || VALIDATION_MODE.all; - } - - localProxyFormState && (localProxyFormState[_key] = true); - return formState[_key]; - }, - }); - } - - return result; -}; diff --git a/src/logic/getRadioValue.ts b/src/logic/getRadioValue.ts deleted file mode 100644 index 5d94bb1ed7f..00000000000 --- a/src/logic/getRadioValue.ts +++ /dev/null @@ -1,23 +0,0 @@ -type RadioFieldResult = { - isValid: boolean; - value: number | string | null; -}; - -const defaultReturn: RadioFieldResult = { - isValid: false, - value: null, -}; - -export default (options?: HTMLInputElement[]): RadioFieldResult => - Array.isArray(options) - ? options.reduce( - (previous, option): RadioFieldResult => - option && option.checked && !option.disabled - ? { - isValid: true, - value: option.value, - } - : previous, - defaultReturn, - ) - : defaultReturn; diff --git a/src/logic/getResolverOptions.ts b/src/logic/getResolverOptions.ts deleted file mode 100644 index 2199295dcfd..00000000000 --- a/src/logic/getResolverOptions.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { - CriteriaMode, - Field, - FieldName, - FieldRefs, - FieldValues, - InternalFieldName, -} from '../types'; -import { get } from '../utils'; -import set from '../utils/set'; - -export default ( - fieldsNames: Set | InternalFieldName[], - _fields: FieldRefs, - criteriaMode?: CriteriaMode, - shouldUseNativeValidation?: boolean | undefined, -) => { - const fields: Record = {}; - - for (const name of fieldsNames) { - const field: Field = get(_fields, name); - - field && set(fields, name, field._f); - } - - return { - criteriaMode, - names: [...fieldsNames] as FieldName[], - fields, - shouldUseNativeValidation, - }; -}; diff --git a/src/logic/getRuleValue.ts b/src/logic/getRuleValue.ts deleted file mode 100644 index 095456ac144..00000000000 --- a/src/logic/getRuleValue.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { - ValidationRule, - ValidationValue, - ValidationValueMessage, -} from '../types'; -import isObject from '../utils/isObject'; -import isRegex from '../utils/isRegex'; -import isUndefined from '../utils/isUndefined'; - -export default ( - rule?: ValidationRule | ValidationValueMessage, -) => - isUndefined(rule) - ? rule - : isRegex(rule) - ? rule.source - : isObject(rule) - ? isRegex(rule.value) - ? rule.value.source - : rule.value - : rule; diff --git a/src/logic/getValidateError.ts b/src/logic/getValidateError.ts deleted file mode 100644 index 347331724c9..00000000000 --- a/src/logic/getValidateError.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { FieldError, Ref, ValidateResult } from '../types'; -import isBoolean from '../utils/isBoolean'; -import isMessage from '../utils/isMessage'; - -export default function getValidateError( - result: ValidateResult, - ref: Ref, - type = 'validate', -): FieldError | void { - if ( - isMessage(result) || - (Array.isArray(result) && result.every(isMessage)) || - (isBoolean(result) && !result) - ) { - return { - type, - message: isMessage(result) ? result : '', - ref, - }; - } -} diff --git a/src/logic/getValidationModes.ts b/src/logic/getValidationModes.ts deleted file mode 100644 index 9c7f373d8f4..00000000000 --- a/src/logic/getValidationModes.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { VALIDATION_MODE } from '../constants'; -import { Mode } from '../types'; - -export default ( - mode?: Mode, -): { - isOnSubmit: boolean; - isOnBlur: boolean; - isOnChange: boolean; - isOnAll: boolean; - isOnTouch: boolean; -} => ({ - isOnSubmit: !mode || mode === VALIDATION_MODE.onSubmit, - isOnBlur: mode === VALIDATION_MODE.onBlur, - isOnChange: mode === VALIDATION_MODE.onChange, - isOnAll: mode === VALIDATION_MODE.all, - isOnTouch: mode === VALIDATION_MODE.onTouched, -}); diff --git a/src/logic/getValueAndMessage.ts b/src/logic/getValueAndMessage.ts deleted file mode 100644 index ab213b9b881..00000000000 --- a/src/logic/getValueAndMessage.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ValidationRule } from '../types'; -import isObject from '../utils/isObject'; -import isRegex from '../utils/isRegex'; - -export default (validationData?: ValidationRule) => - isObject(validationData) && !isRegex(validationData) - ? validationData - : { - value: validationData, - message: '', - }; diff --git a/src/logic/hasValidation.ts b/src/logic/hasValidation.ts deleted file mode 100644 index e52720b4fb8..00000000000 --- a/src/logic/hasValidation.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Field } from '../types'; - -export default (options: Field['_f']) => - options.mount && - (options.required || - options.min || - options.max || - options.maxLength || - options.minLength || - options.pattern || - options.validate); diff --git a/src/logic/index.ts b/src/logic/index.ts deleted file mode 100644 index 59d97f04782..00000000000 --- a/src/logic/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import appendErrors from './appendErrors'; - -export { appendErrors }; diff --git a/src/logic/isNameInFieldArray.ts b/src/logic/isNameInFieldArray.ts deleted file mode 100644 index 4d8ca52063a..00000000000 --- a/src/logic/isNameInFieldArray.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { InternalFieldName } from '../types'; - -import getNodeParentName from './getNodeParentName'; - -export default (names: Set, name: InternalFieldName) => - names.has(getNodeParentName(name)); diff --git a/src/logic/isWatched.ts b/src/logic/isWatched.ts deleted file mode 100644 index 2341a40390c..00000000000 --- a/src/logic/isWatched.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { InternalFieldName, Names } from '../types'; - -export default ( - name: InternalFieldName, - _names: Names, - isBlurEvent?: boolean, -) => - !isBlurEvent && - (_names.watchAll || - _names.watch.has(name) || - [..._names.watch].some( - (watchName) => - name.startsWith(watchName) && - /^\.\w+/.test(name.slice(watchName.length)), - )); diff --git a/src/logic/schemaErrorLookup.ts b/src/logic/schemaErrorLookup.ts deleted file mode 100644 index c51d5fdec6e..00000000000 --- a/src/logic/schemaErrorLookup.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { FieldError, FieldErrors, FieldValues } from '../types'; -import get from '../utils/get'; -import isKey from '../utils/isKey'; - -export default function schemaErrorLookup( - errors: FieldErrors, - _fields: FieldValues, - name: string, -): { - error?: FieldError; - name: string; -} { - const error = get(errors, name); - - if (error || isKey(name)) { - return { - error, - name, - }; - } - - const names = name.split('.'); - - while (names.length) { - const fieldName = names.join('.'); - const field = get(_fields, fieldName); - const foundError = get(errors, fieldName); - - if (field && !Array.isArray(field) && name !== fieldName) { - return { name }; - } - - if (foundError && foundError.type) { - return { - name: fieldName, - error: foundError, - }; - } - - names.pop(); - } - - return { - name, - }; -} diff --git a/src/logic/shouldRenderFormState.ts b/src/logic/shouldRenderFormState.ts deleted file mode 100644 index 468dd033c23..00000000000 --- a/src/logic/shouldRenderFormState.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { VALIDATION_MODE } from '../constants'; -import { - Control, - FieldValues, - FormState, - InternalFieldName, - ReadFormState, -} from '../types'; -import isEmptyObject from '../utils/isEmptyObject'; - -export default ( - formStateData: Partial> & { name?: InternalFieldName }, - _proxyFormState: K, - updateFormState: Control['_updateFormState'], - isRoot?: boolean, -) => { - updateFormState(formStateData); - const { name, ...formState } = formStateData; - - return ( - isEmptyObject(formState) || - Object.keys(formState).length >= Object.keys(_proxyFormState).length || - Object.keys(formState).find( - (key) => - _proxyFormState[key as keyof ReadFormState] === - (!isRoot || VALIDATION_MODE.all), - ) - ); -}; diff --git a/src/logic/shouldSubscribeByName.ts b/src/logic/shouldSubscribeByName.ts deleted file mode 100644 index 7ff784ee3ff..00000000000 --- a/src/logic/shouldSubscribeByName.ts +++ /dev/null @@ -1,18 +0,0 @@ -import convertToArrayPayload from '../utils/convertToArrayPayload'; - -export default ( - name?: T, - signalName?: string, - exact?: boolean, -) => - exact && signalName - ? name === signalName - : !name || - !signalName || - name === signalName || - convertToArrayPayload(name).some( - (currentName) => - currentName && - (currentName.startsWith(signalName) || - signalName.startsWith(currentName)), - ); diff --git a/src/logic/skipValidation.ts b/src/logic/skipValidation.ts deleted file mode 100644 index 31c1a5b18b4..00000000000 --- a/src/logic/skipValidation.ts +++ /dev/null @@ -1,27 +0,0 @@ -export default ( - isBlurEvent: boolean, - isTouched: boolean, - isSubmitted: boolean, - reValidateMode: { - isOnBlur: boolean; - isOnChange: boolean; - }, - mode: Partial<{ - isOnSubmit: boolean; - isOnBlur: boolean; - isOnChange: boolean; - isOnTouch: boolean; - isOnAll: boolean; - }>, -) => { - if (mode.isOnAll) { - return false; - } else if (!isSubmitted && mode.isOnTouch) { - return !(isTouched || isBlurEvent); - } else if (isSubmitted ? reValidateMode.isOnBlur : mode.isOnBlur) { - return !isBlurEvent; - } else if (isSubmitted ? reValidateMode.isOnChange : mode.isOnChange) { - return isBlurEvent; - } - return true; -}; diff --git a/src/logic/unsetEmptyArray.ts b/src/logic/unsetEmptyArray.ts deleted file mode 100644 index d12c60dac16..00000000000 --- a/src/logic/unsetEmptyArray.ts +++ /dev/null @@ -1,6 +0,0 @@ -import compact from '../utils/compact'; -import get from '../utils/get'; -import unset from '../utils/unset'; - -export default (ref: T, name: string) => - !compact(get(ref, name)).length && unset(ref, name); diff --git a/src/logic/updateFieldArrayRootError.ts b/src/logic/updateFieldArrayRootError.ts deleted file mode 100644 index 534b09ecfdf..00000000000 --- a/src/logic/updateFieldArrayRootError.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { - FieldError, - FieldErrors, - FieldValues, - InternalFieldName, -} from '../types'; -import compact from '../utils/compact'; -import get from '../utils/get'; -import set from '../utils/set'; - -export default ( - errors: FieldErrors, - error: Partial>, - name: InternalFieldName, -): FieldErrors => { - const fieldArrayErrors = compact(get(errors, name)); - set(fieldArrayErrors, 'root', error[name]); - set(errors, name, fieldArrayErrors); - return errors; -}; diff --git a/src/logic/validateField.ts b/src/logic/validateField.ts deleted file mode 100644 index 01f4bc8981b..00000000000 --- a/src/logic/validateField.ts +++ /dev/null @@ -1,284 +0,0 @@ -import { INPUT_VALIDATION_RULES } from '../constants'; -import { - Field, - FieldError, - FieldValues, - InternalFieldErrors, - Message, - NativeFieldValue, -} from '../types'; -import get from '../utils/get'; -import isBoolean from '../utils/isBoolean'; -import isCheckBoxInput from '../utils/isCheckBoxInput'; -import isEmptyObject from '../utils/isEmptyObject'; -import isFileInput from '../utils/isFileInput'; -import isFunction from '../utils/isFunction'; -import isHTMLElement from '../utils/isHTMLElement'; -import isMessage from '../utils/isMessage'; -import isNullOrUndefined from '../utils/isNullOrUndefined'; -import isObject from '../utils/isObject'; -import isRadioInput from '../utils/isRadioInput'; -import isRegex from '../utils/isRegex'; -import isString from '../utils/isString'; -import isUndefined from '../utils/isUndefined'; - -import appendErrors from './appendErrors'; -import getCheckboxValue from './getCheckboxValue'; -import getRadioValue from './getRadioValue'; -import getValidateError from './getValidateError'; -import getValueAndMessage from './getValueAndMessage'; - -export default async ( - field: Field, - formValues: T, - validateAllFieldCriteria: boolean, - shouldUseNativeValidation?: boolean, - isFieldArray?: boolean, -): Promise => { - const { - ref, - refs, - required, - maxLength, - minLength, - min, - max, - pattern, - validate, - name, - valueAsNumber, - mount, - disabled, - } = field._f; - const inputValue: NativeFieldValue = get(formValues, name); - if (!mount || disabled) { - return {}; - } - const inputRef: HTMLInputElement = refs ? refs[0] : (ref as HTMLInputElement); - const setCustomValidity = (message?: string | boolean) => { - if (shouldUseNativeValidation && inputRef.reportValidity) { - inputRef.setCustomValidity(isBoolean(message) ? '' : message || ''); - inputRef.reportValidity(); - } - }; - const error: InternalFieldErrors = {}; - const isRadio = isRadioInput(ref); - const isCheckBox = isCheckBoxInput(ref); - const isRadioOrCheckbox = isRadio || isCheckBox; - const isEmpty = - ((valueAsNumber || isFileInput(ref)) && - isUndefined(ref.value) && - isUndefined(inputValue)) || - (isHTMLElement(ref) && ref.value === '') || - inputValue === '' || - (Array.isArray(inputValue) && !inputValue.length); - const appendErrorsCurry = appendErrors.bind( - null, - name, - validateAllFieldCriteria, - error, - ); - const getMinMaxMessage = ( - exceedMax: boolean, - maxLengthMessage: Message, - minLengthMessage: Message, - maxType = INPUT_VALIDATION_RULES.maxLength, - minType = INPUT_VALIDATION_RULES.minLength, - ) => { - const message = exceedMax ? maxLengthMessage : minLengthMessage; - error[name] = { - type: exceedMax ? maxType : minType, - message, - ref, - ...appendErrorsCurry(exceedMax ? maxType : minType, message), - }; - }; - - if ( - isFieldArray - ? !Array.isArray(inputValue) || !inputValue.length - : required && - ((!isRadioOrCheckbox && (isEmpty || isNullOrUndefined(inputValue))) || - (isBoolean(inputValue) && !inputValue) || - (isCheckBox && !getCheckboxValue(refs).isValid) || - (isRadio && !getRadioValue(refs).isValid)) - ) { - const { value, message } = isMessage(required) - ? { value: !!required, message: required } - : getValueAndMessage(required); - - if (value) { - error[name] = { - type: INPUT_VALIDATION_RULES.required, - message, - ref: inputRef, - ...appendErrorsCurry(INPUT_VALIDATION_RULES.required, message), - }; - if (!validateAllFieldCriteria) { - setCustomValidity(message); - return error; - } - } - } - - if (!isEmpty && (!isNullOrUndefined(min) || !isNullOrUndefined(max))) { - let exceedMax; - let exceedMin; - const maxOutput = getValueAndMessage(max); - const minOutput = getValueAndMessage(min); - - if (!isNullOrUndefined(inputValue) && !isNaN(inputValue as number)) { - const valueNumber = - (ref as HTMLInputElement).valueAsNumber || - (inputValue ? +inputValue : inputValue); - if (!isNullOrUndefined(maxOutput.value)) { - exceedMax = valueNumber > maxOutput.value; - } - if (!isNullOrUndefined(minOutput.value)) { - exceedMin = valueNumber < minOutput.value; - } - } else { - const valueDate = - (ref as HTMLInputElement).valueAsDate || new Date(inputValue as string); - const convertTimeToDate = (time: unknown) => - new Date(new Date().toDateString() + ' ' + time); - const isTime = ref.type == 'time'; - const isWeek = ref.type == 'week'; - - if (isString(maxOutput.value) && inputValue) { - exceedMax = isTime - ? convertTimeToDate(inputValue) > convertTimeToDate(maxOutput.value) - : isWeek - ? inputValue > maxOutput.value - : valueDate > new Date(maxOutput.value); - } - - if (isString(minOutput.value) && inputValue) { - exceedMin = isTime - ? convertTimeToDate(inputValue) < convertTimeToDate(minOutput.value) - : isWeek - ? inputValue < minOutput.value - : valueDate < new Date(minOutput.value); - } - } - - if (exceedMax || exceedMin) { - getMinMaxMessage( - !!exceedMax, - maxOutput.message, - minOutput.message, - INPUT_VALIDATION_RULES.max, - INPUT_VALIDATION_RULES.min, - ); - if (!validateAllFieldCriteria) { - setCustomValidity(error[name]!.message); - return error; - } - } - } - - if ( - (maxLength || minLength) && - !isEmpty && - (isString(inputValue) || (isFieldArray && Array.isArray(inputValue))) - ) { - const maxLengthOutput = getValueAndMessage(maxLength); - const minLengthOutput = getValueAndMessage(minLength); - const exceedMax = - !isNullOrUndefined(maxLengthOutput.value) && - inputValue.length > maxLengthOutput.value; - const exceedMin = - !isNullOrUndefined(minLengthOutput.value) && - inputValue.length < minLengthOutput.value; - - if (exceedMax || exceedMin) { - getMinMaxMessage( - exceedMax, - maxLengthOutput.message, - minLengthOutput.message, - ); - if (!validateAllFieldCriteria) { - setCustomValidity(error[name]!.message); - return error; - } - } - } - - if (pattern && !isEmpty && isString(inputValue)) { - const { value: patternValue, message } = getValueAndMessage(pattern); - - if (isRegex(patternValue) && !inputValue.match(patternValue)) { - error[name] = { - type: INPUT_VALIDATION_RULES.pattern, - message, - ref, - ...appendErrorsCurry(INPUT_VALIDATION_RULES.pattern, message), - }; - if (!validateAllFieldCriteria) { - setCustomValidity(message); - return error; - } - } - } - - if (validate) { - if (isFunction(validate)) { - const result = await validate(inputValue, formValues); - const validateError = getValidateError(result, inputRef); - - if (validateError) { - error[name] = { - ...validateError, - ...appendErrorsCurry( - INPUT_VALIDATION_RULES.validate, - validateError.message, - ), - }; - if (!validateAllFieldCriteria) { - setCustomValidity(validateError.message); - return error; - } - } - } else if (isObject(validate)) { - let validationResult = {} as FieldError; - - for (const key in validate) { - if (!isEmptyObject(validationResult) && !validateAllFieldCriteria) { - break; - } - - const validateError = getValidateError( - await validate[key](inputValue, formValues), - inputRef, - key, - ); - - if (validateError) { - validationResult = { - ...validateError, - ...appendErrorsCurry(key, validateError.message), - }; - - setCustomValidity(validateError.message); - - if (validateAllFieldCriteria) { - error[name] = validationResult; - } - } - } - - if (!isEmptyObject(validationResult)) { - error[name] = { - ref: inputRef, - ...validationResult, - }; - if (!validateAllFieldCriteria) { - return error; - } - } - } - } - - setCustomValidity(true); - return error; -}; diff --git a/src/types/controller.ts b/src/types/controller.ts deleted file mode 100644 index 5197d3881f7..00000000000 --- a/src/types/controller.ts +++ /dev/null @@ -1,90 +0,0 @@ -import React from 'react'; - -import { RegisterOptions } from './validator'; -import { - Control, - FieldError, - FieldPath, - FieldPathValue, - FieldValues, - Noop, - RefCallBack, - UseFormStateReturn, -} from './'; - -export type ControllerFieldState = { - invalid: boolean; - isTouched: boolean; - isDirty: boolean; - error?: FieldError; -}; - -export type ControllerRenderProps< - TFieldValues extends FieldValues = FieldValues, - TName extends FieldPath = FieldPath, -> = { - onChange: (...event: any[]) => void; - onBlur: Noop; - value: FieldPathValue; - name: TName; - ref: RefCallBack; -}; - -export type UseControllerProps< - TFieldValues extends FieldValues = FieldValues, - TName extends FieldPath = FieldPath, -> = { - name: TName; - rules?: Omit< - RegisterOptions, - 'valueAsNumber' | 'valueAsDate' | 'setValueAs' | 'disabled' - >; - shouldUnregister?: boolean; - defaultValue?: FieldPathValue; - control?: Control; -}; - -export type UseControllerReturn< - TFieldValues extends FieldValues = FieldValues, - TName extends FieldPath = FieldPath, -> = { - field: ControllerRenderProps; - formState: UseFormStateReturn; - fieldState: ControllerFieldState; -}; - -/** - * Render function to provide the control for the field. - * - * @returns all the event handler, and relevant field and form state. - * - * @example - * ```tsx - * const { field, fieldState, formState } = useController(); - * - * ({ - * - * })} - * /> - * ``` - */ -export type ControllerProps< - TFieldValues extends FieldValues = FieldValues, - TName extends FieldPath = FieldPath, -> = { - render: ({ - field, - fieldState, - formState, - }: { - field: ControllerRenderProps; - fieldState: ControllerFieldState; - formState: UseFormStateReturn; - }) => React.ReactElement; -} & UseControllerProps; diff --git a/src/types/errors.ts b/src/types/errors.ts deleted file mode 100644 index a400f6a4528..00000000000 --- a/src/types/errors.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { FieldValues, InternalFieldName, Ref } from './fields'; -import { BrowserNativeObject, IsAny, LiteralUnion, Merge } from './utils'; -import { RegisterOptions, ValidateResult } from './validator'; - -export type Message = string; - -export type MultipleFieldErrors = { - [K in keyof RegisterOptions]?: ValidateResult; -} & { - [key: string]: ValidateResult; -}; - -export type FieldError = { - type: LiteralUnion; - root?: FieldError; - ref?: Ref; - types?: MultipleFieldErrors; - message?: Message; -}; - -export type ErrorOption = { - message?: Message; - type?: LiteralUnion; - types?: MultipleFieldErrors; -}; - -export type DeepRequired = T extends BrowserNativeObject | Blob - ? T - : { - [K in keyof T]-?: NonNullable>; - }; - -export type FieldErrorsImpl = { - [K in keyof T]?: T[K] extends BrowserNativeObject | Blob - ? FieldError - : K extends 'root' | `root.${string}` - ? GlobalError - : T[K] extends object - ? Merge> - : FieldError; -}; - -export type GlobalError = Partial<{ - type: string | number; - message: string; -}>; - -export type FieldErrors = Partial< - FieldValues extends IsAny - ? any - : FieldErrorsImpl> -> & { - root?: Record & GlobalError; -}; - -export type InternalFieldErrors = Partial< - Record ->; diff --git a/src/types/events.ts b/src/types/events.ts deleted file mode 100644 index 1bc57f1082b..00000000000 --- a/src/types/events.ts +++ /dev/null @@ -1,25 +0,0 @@ -export type EventType = - | 'focus' - | 'blur' - | 'change' - | 'changeText' - | 'valueChange' - | 'contentSizeChange' - | 'endEditing' - | 'keyPress' - | 'submitEditing' - | 'layout' - | 'selectionChange' - | 'longPress' - | 'press' - | 'pressIn' - | 'pressOut' - | 'momentumScrollBegin' - | 'momentumScrollEnd' - | 'scroll' - | 'scrollBeginDrag' - | 'scrollEndDrag' - | 'load' - | 'error' - | 'progress' - | 'custom'; diff --git a/src/types/fieldArray.ts b/src/types/fieldArray.ts deleted file mode 100644 index b58ea217259..00000000000 --- a/src/types/fieldArray.ts +++ /dev/null @@ -1,270 +0,0 @@ -import { FieldValues } from './fields'; -import { Control } from './form'; -import { FieldArrayPath, FieldArrayPathValue } from './path'; -import { RegisterOptions, Validate } from './validator'; - -export type UseFieldArrayProps< - TFieldValues extends FieldValues = FieldValues, - TFieldArrayName extends FieldArrayPath = FieldArrayPath, - TKeyName extends string = 'id', -> = { - name: TFieldArrayName; - keyName?: TKeyName; - control?: Control; - rules?: { - validate?: - | Validate[], TFieldValues> - | Record< - string, - Validate[], TFieldValues> - >; - } & Pick< - RegisterOptions, - 'maxLength' | 'minLength' | 'required' - >; - shouldUnregister?: boolean; -}; - -/** - * `useFieldArray` returned `fields` with unique id - */ -export type FieldArrayWithId< - TFieldValues extends FieldValues = FieldValues, - TFieldArrayName extends FieldArrayPath = FieldArrayPath, - TKeyName extends string = 'id', -> = FieldArray & Record; - -export type FieldArray< - TFieldValues extends FieldValues = FieldValues, - TFieldArrayName extends FieldArrayPath = FieldArrayPath, -> = FieldArrayPathValue extends - | ReadonlyArray - | null - | undefined - ? U - : never; - -/** - * `useFieldArray` focus option, ability to toggle focus on and off with `shouldFocus` and setting focus by either field index or name. - */ -export type FieldArrayMethodProps = { - shouldFocus?: boolean; - focusIndex?: number; - focusName?: string; -}; - -/** - * Swap field array by supplying from and to index - * - * @remarks - * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/calc-i231d) - * - * @param indexA - from index - * @param indexB - to index - * - * @example - * ```tsx - * - * ``` - */ -export type UseFieldArraySwap = (indexA: number, indexB: number) => void; - -/** - * Move field array by supplying from and to index - * - * @remarks - * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/calc-i231d) - * - * @param indexA - from index - * @param indexB - to index - * - * @example - * ```tsx - * - * ``` - */ -export type UseFieldArrayMove = (indexA: number, indexB: number) => void; - -/** - * Prepend field/fields to the start of the fields and optionally focus. The input value will be registered during this action. - * - * @remarks - * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/calc-i231d) - * - * @param value - prepend items or items - * @param options - focus options - * - * @example - * ```tsx - * - * - * - * ``` - */ -export type UseFieldArrayPrepend< - TFieldValues extends FieldValues, - TFieldArrayName extends FieldArrayPath = FieldArrayPath, -> = ( - value: - | FieldArray - | FieldArray[], - options?: FieldArrayMethodProps, -) => void; - -/** - * Append field/fields to the end of your fields and focus. The input value will be registered during this action. - * - * @remarks - * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/calc-i231d) - * - * @param value - append items or items. - * @param options - focus options - * - * @example - * ```tsx - * - * - * - * ``` - */ -export type UseFieldArrayAppend< - TFieldValues extends FieldValues, - TFieldArrayName extends FieldArrayPath = FieldArrayPath, -> = ( - value: - | FieldArray - | FieldArray[], - options?: FieldArrayMethodProps, -) => void; - -/** - * Remove field/fields at particular position. - * - * @remarks - * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/calc-i231d) - * - * @param index - index to remove at, or remove all when no index provided. - * - * @example - * ```tsx - * - * - * ``` - */ -export type UseFieldArrayRemove = (index?: number | number[]) => void; - -/** - * Insert field/fields at particular position and focus. - * - * @remarks - * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/calc-i231d) - * - * @param index - insert position - * @param value - insert field or fields - * @param options - focus options - * - * @example - * ```tsx - * - * - * - * ``` - */ -export type UseFieldArrayInsert< - TFieldValues extends FieldValues, - TFieldArrayName extends FieldArrayPath = FieldArrayPath, -> = ( - index: number, - value: - | FieldArray - | FieldArray[], - options?: FieldArrayMethodProps, -) => void; - -/** - * Update field/fields at particular position. - * - * @remarks - * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/calc-i231d) - * - * @param index - insert position - * @param value - insert field or fields - * - * @example - * ```tsx - * - * - * ``` - */ -export type UseFieldArrayUpdate< - TFieldValues extends FieldValues, - TFieldArrayName extends FieldArrayPath = FieldArrayPath, -> = (index: number, value: FieldArray) => void; - -/** - * Replace the entire field array values. - * - * @remarks - * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/calc-i231d) - * - * @param value - the entire field values. - * - * @example - * ```tsx - * - * ``` - */ -export type UseFieldArrayReplace< - TFieldValues extends FieldValues, - TFieldArrayName extends FieldArrayPath = FieldArrayPath, -> = ( - value: - | FieldArray - | FieldArray[], -) => void; - -export type UseFieldArrayReturn< - TFieldValues extends FieldValues = FieldValues, - TFieldArrayName extends FieldArrayPath = FieldArrayPath, - TKeyName extends string = 'id', -> = { - swap: UseFieldArraySwap; - move: UseFieldArrayMove; - prepend: UseFieldArrayPrepend; - append: UseFieldArrayAppend; - remove: UseFieldArrayRemove; - insert: UseFieldArrayInsert; - update: UseFieldArrayUpdate; - replace: UseFieldArrayReplace; - fields: FieldArrayWithId[]; -}; diff --git a/src/types/fields.ts b/src/types/fields.ts deleted file mode 100644 index a3f3ccca49e..00000000000 --- a/src/types/fields.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { IsFlatObject, Noop } from './utils'; -import { RegisterOptions } from './validator'; - -export type InternalFieldName = string; - -export type FieldName = - IsFlatObject extends true - ? Extract - : string; - -export type CustomElement = { - name: FieldName; - type?: string; - value?: any; - disabled?: boolean; - checked?: boolean; - options?: HTMLOptionsCollection; - files?: FileList | null; - focus?: Noop; -}; - -export type FieldValue = - TFieldValues[InternalFieldName]; - -export type FieldValues = Record; - -export type NativeFieldValue = - | string - | number - | boolean - | null - | undefined - | unknown[]; - -export type FieldElement = - | HTMLInputElement - | HTMLSelectElement - | HTMLTextAreaElement - | CustomElement; - -export type Ref = FieldElement; - -export type Field = { - _f: { - ref: Ref; - name: InternalFieldName; - refs?: HTMLInputElement[]; - mount?: boolean; - } & RegisterOptions; -}; - -export type FieldRefs = Partial>; diff --git a/src/types/form.ts b/src/types/form.ts deleted file mode 100644 index fd91579a011..00000000000 --- a/src/types/form.ts +++ /dev/null @@ -1,829 +0,0 @@ -import React from 'react'; - -import { Subject, Subscription } from '../utils/createSubject'; - -import { ErrorOption, FieldError, FieldErrors } from './errors'; -import { EventType } from './events'; -import { FieldArray } from './fieldArray'; -import { - FieldRefs, - FieldValue, - FieldValues, - InternalFieldName, -} from './fields'; -import { - FieldArrayPath, - FieldPath, - FieldPathValue, - FieldPathValues, -} from './path'; -import { Resolver } from './resolvers'; -import { DeepMap, DeepPartial, Noop } from './utils'; -import { RegisterOptions } from './validator'; - -declare const $NestedValue: unique symbol; - -/** - * @deprecated to be removed in the next major version - */ -export type NestedValue = { - [$NestedValue]: never; -} & TValue; - -/** - * @deprecated to be removed in the next major version - */ -export type UnpackNestedValue = T extends NestedValue - ? U - : T extends Date | FileList | File | Blob - ? T - : T extends object - ? { [K in keyof T]: UnpackNestedValue } - : T; - -export type DefaultValues = DeepPartial; - -export type InternalNameSet = Set; - -export type ValidationMode = { - onBlur: 'onBlur'; - onChange: 'onChange'; - onSubmit: 'onSubmit'; - onTouched: 'onTouched'; - all: 'all'; -}; - -export type Mode = keyof ValidationMode; - -export type CriteriaMode = 'firstError' | 'all'; - -export type SubmitHandler = ( - data: TFieldValues, - event?: React.BaseSyntheticEvent, -) => any | Promise; - -export type SubmitErrorHandler = ( - errors: FieldErrors, - event?: React.BaseSyntheticEvent, -) => any | Promise; - -export type SetValueConfig = Partial<{ - shouldValidate: boolean; - shouldDirty: boolean; - shouldTouch: boolean; -}>; - -export type TriggerConfig = Partial<{ - shouldFocus: boolean; -}>; - -export type ChangeHandler = (event: { - target: any; - type?: any; -}) => Promise; - -export type DelayCallback = (wait: number) => void; - -type AsyncDefaultValues = ( - payload?: unknown, -) => Promise; - -export type UseFormProps< - TFieldValues extends FieldValues = FieldValues, - TContext = any, -> = Partial<{ - mode: Mode; - reValidateMode: Exclude; - defaultValues: DefaultValues | AsyncDefaultValues; - values: TFieldValues; - resetOptions: Parameters>[1]; - resolver: Resolver; - context: TContext; - shouldFocusError: boolean; - shouldUnregister: boolean; - shouldUseNativeValidation: boolean; - criteriaMode: CriteriaMode; - delayError: number; -}>; - -export type FieldNamesMarkedBoolean = DeepMap< - DeepPartial, - boolean ->; - -export type FormStateProxy = { - isDirty: boolean; - isValidating: boolean; - dirtyFields: FieldNamesMarkedBoolean; - touchedFields: FieldNamesMarkedBoolean; - errors: boolean; - isValid: boolean; -}; - -export type ReadFormState = { [K in keyof FormStateProxy]: boolean | 'all' }; - -export type FormState = { - isDirty: boolean; - isLoading: boolean; - isSubmitted: boolean; - isSubmitSuccessful: boolean; - isSubmitting: boolean; - isValidating: boolean; - isValid: boolean; - submitCount: number; - defaultValues?: undefined | Readonly>; - dirtyFields: Partial>>; - touchedFields: Partial>>; - errors: FieldErrors; -}; - -export type KeepStateOptions = Partial<{ - keepDirtyValues: boolean; - keepErrors: boolean; - keepDirty: boolean; - keepValues: boolean; - keepDefaultValues: boolean; - keepIsSubmitted: boolean; - keepTouched: boolean; - keepIsValid: boolean; - keepSubmitCount: boolean; -}>; - -export type SetFieldValue = - FieldValue; - -export type RefCallBack = (instance: any) => void; - -export type UseFormRegisterReturn< - TFieldName extends InternalFieldName = InternalFieldName, -> = { - onChange: ChangeHandler; - onBlur: ChangeHandler; - ref: RefCallBack; - name: TFieldName; - min?: string | number; - max?: string | number; - maxLength?: number; - minLength?: number; - pattern?: string; - required?: boolean; - disabled?: boolean; -}; - -/** - * Register field into hook form with or without the actual DOM ref. You can invoke register anywhere in the component including at `useEffect`. - * - * @remarks - * [API](https://react-hook-form.com/api/useform/register) • [Demo](https://codesandbox.io/s/react-hook-form-register-ts-ip2j3) • [Video](https://www.youtube.com/watch?v=JFIpCoajYkA) - * - * @param name - the path name to the form field value, name is required and unique - * @param options - register options include validation, disabled, unregister, value as and dependent validation - * - * @returns onChange, onBlur, name, ref, and native contribute attribute if browser validation is enabled. - * - * @example - * ```tsx - * // Register HTML native input - * - *