-
Notifications
You must be signed in to change notification settings - Fork 199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ballerine Validator(WIP) #2874
base: dev
Are you sure you want to change the base?
Ballerine Validator(WIP) #2874
Changes from 5 commits
75d4a34
b2c7a44
e471f81
7cb51fe
4d2c708
c2987da
ce18a0c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
./_Validator |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { ValidatorContext } from './context'; | ||
import { IValidatorRef, useValidatorRef } from './hooks/internal/useValidatorRef'; | ||
import { IValidationSchema } from './types'; | ||
|
||
export interface IValidatorProviderProps<TValue> { | ||
children: React.ReactNode | React.ReactNode[]; | ||
schema: IValidationSchema[]; | ||
value: TValue; | ||
|
||
ref?: React.RefObject<IValidatorRef>; | ||
validateOnChange?: boolean; | ||
validateSync?: boolean; | ||
} | ||
|
||
export const ValidatorProvider = <TValue,>({ | ||
children, | ||
schema, | ||
value, | ||
ref, | ||
}: IValidatorProviderProps<TValue>) => { | ||
useValidatorRef(ref); | ||
|
||
return <ValidatorContext.Provider value={{}}>{children}</ValidatorContext.Provider>; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './types'; | ||
export * from './validator-context'; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,8 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { IValidationError } from '../types'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
export interface IValidatorContext<TValues> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
errors: IValidationError[]; | ||||||||||||||||||||||||||||||||||||||||||||||||||
values: TValues; | ||||||||||||||||||||||||||||||||||||||||||||||||||
isValid: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||||||
validate: () => void; | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+3
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance type definitions for better validation control The current interface could be improved to provide better type safety and flexibility: Consider these enhancements: +/** Options for validation execution */
+export interface IValidationOptions {
+ validateAll?: boolean;
+ stopOnFirst?: boolean;
+}
+
+/** Result of validation execution */
+export interface IValidationResult {
+ isValid: boolean;
+ errors: IValidationError[];
+}
export interface IValidatorContext<TValues> {
errors: IValidationError[];
values: TValues;
isValid: boolean;
- validate: () => void;
+ validate: (options?: IValidationOptions) => Promise<IValidationResult>;
} This provides:
Consider adding JSDoc comments to document the interface and its generic parameter usage. 📝 Committable suggestion
Suggested change
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { createContext } from 'react'; | ||
import { IValidatorContext } from './types'; | ||
|
||
export const ValidatorContext = createContext<IValidatorContext<unknown>>({ | ||
errors: [], | ||
values: {}, | ||
isValid: true, | ||
validate: () => { | ||
throw new Error('Validator context is not provided.'); | ||
}, | ||
}); | ||
Comment on lines
+4
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider using a more specific generic type parameter The context is currently typed with -export const ValidatorContext = createContext<IValidatorContext<unknown>>({
+export const ValidatorContext = createContext<IValidatorContext<TValue extends object>>({ Also, the error message could be more descriptive about where to add the provider: validate: () => {
- throw new Error('Validator context is not provided.');
+ throw new Error('ValidatorContext.Provider is not found in component tree. Wrap your component with ValidatorProvider.');
},
Comment on lines
+1
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Confirmed: Two separate validator contexts exist with overlapping functionality There are indeed two separate validator contexts with similar purposes but different implementations:
Both contexts handle form validation but have different interfaces and are used in separate components. This creates technical debt and potential confusion:
Recommendations:
🔗 Analysis chainVerify potential context naming conflicts There appears to be two validator contexts in the codebase ( Let me check the actual content of these files to understand if there's a real conflict or if these are related components. 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Search for validator context definitions and usages
rg -l "validatorContext|ValidatorContext" --type ts
Length of output: 602 Script: #!/bin/bash
# Check the content of both validator context files and their usages
echo "=== validator-context.ts ==="
cat packages/ui/src/components/organisms/Form/Validator/context/validator-context.ts
echo -e "\n=== validator.context.ts ==="
cat packages/ui/src/components/organisms/Form/_Validator/validator.context.ts
echo -e "\n=== Checking imports in _Validator/Validator.tsx ==="
rg "import.*[Vv]alidator[Cc]ontext" packages/ui/src/components/organisms/Form/_Validator/Validator.tsx
echo -e "\n=== Checking imports in Validator/ValidatorProvider.tsx ==="
rg "import.*[Vv]alidator[Cc]ontext" packages/ui/src/components/organisms/Form/Validator/ValidatorProvider.tsx
Length of output: 1534 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './useValidator'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { useContext } from 'react'; | ||
import { ValidatorContext } from '../../../context'; | ||
|
||
export const useValidator = () => { | ||
const context = useContext(ValidatorContext); | ||
|
||
if (!context) { | ||
throw new Error('Validator context is not provided.'); | ||
} | ||
|
||
return context; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './useValidate'; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,46 @@ | ||||||||||||||||||||||||||||||
import { IValidationSchema } from '../../../types'; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
import debounce from 'lodash/debounce'; | ||||||||||||||||||||||||||||||
import { useCallback, useEffect, useState } from 'react'; | ||||||||||||||||||||||||||||||
import { IValidationError } from '../../../types'; | ||||||||||||||||||||||||||||||
import { validate } from '../../../utils/validate'; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
export interface IUseAsyncValidateParams { | ||||||||||||||||||||||||||||||
validationDelay?: number; | ||||||||||||||||||||||||||||||
validateAsync?: boolean; | ||||||||||||||||||||||||||||||
validateOnChange?: boolean; | ||||||||||||||||||||||||||||||
abortEarly?: boolean; | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
export const useAsyncValidate = ( | ||||||||||||||||||||||||||||||
context: object, | ||||||||||||||||||||||||||||||
schema: IValidationSchema[], | ||||||||||||||||||||||||||||||
params: IUseAsyncValidateParams = {}, | ||||||||||||||||||||||||||||||
) => { | ||||||||||||||||||||||||||||||
const { | ||||||||||||||||||||||||||||||
validationDelay = 500, | ||||||||||||||||||||||||||||||
validateAsync = false, | ||||||||||||||||||||||||||||||
validateOnChange = true, | ||||||||||||||||||||||||||||||
abortEarly = false, | ||||||||||||||||||||||||||||||
} = params; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
const [validationErrors, setValidationErrors] = useState<IValidationError[]>(() => | ||||||||||||||||||||||||||||||
validateAsync ? validate(context, schema, { abortEarly }) : [], | ||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||
Comment on lines
+27
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider adding error handling for initial validation. The initial validation in useState could throw an error and crash the component. Apply this fix: const [validationErrors, setValidationErrors] = useState<IValidationError[]>(() =>
- validateAsync ? validate(context, schema, { abortEarly }) : [],
+ validateAsync ?
+ try {
+ return validate(context, schema, { abortEarly });
+ } catch (error) {
+ console.error('Initial validation failed:', error);
+ return [];
+ }
+ : [],
);
|
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
const validateWithDebounce = useCallback( | ||||||||||||||||||||||||||||||
debounce((context: object, schema: IValidationSchema[], params: IUseAsyncValidateParams) => { | ||||||||||||||||||||||||||||||
const errors = validate(context, schema, params); | ||||||||||||||||||||||||||||||
setValidationErrors(errors); | ||||||||||||||||||||||||||||||
}, validationDelay), | ||||||||||||||||||||||||||||||
[validationDelay], | ||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||
Comment on lines
+31
to
+37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix dependency array in useCallback and handle stale closures. The current implementation has potential issues with stale closures and unnecessary recreations. Apply this fix: const validateWithDebounce = useCallback(
- debounce((context: object, schema: IValidationSchema[], params: IUseAsyncValidateParams) => {
+ debounce((context: object, schema: IValidationSchema[]) => {
const errors = validate(context, schema, params);
setValidationErrors(errors);
}, validationDelay),
- [validationDelay],
+ [validationDelay, params.abortEarly],
);
|
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
useEffect(() => { | ||||||||||||||||||||||||||||||
if (!validateAsync || !validateOnChange) return; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
validateWithDebounce(context, schema, { abortEarly }); | ||||||||||||||||||||||||||||||
}, [context, schema, validateAsync, validateOnChange, abortEarly, validateWithDebounce]); | ||||||||||||||||||||||||||||||
Comment on lines
+39
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prevent memory leaks by cleaning up pending validations. The current implementation doesn't cancel pending validations on unmount or when dependencies change. Apply this fix: useEffect(() => {
if (!validateAsync || !validateOnChange) return;
validateWithDebounce(context, schema, { abortEarly });
+
+ return () => {
+ validateWithDebounce.cancel();
+ };
}, [context, schema, validateAsync, validateOnChange, abortEarly, validateWithDebounce]); 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
return validationErrors; | ||||||||||||||||||||||||||||||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import { renderHook } from '@testing-library/react'; | ||
import { beforeEach, describe, expect, it, vi } from 'vitest'; | ||
import { validate } from '../../../utils/validate'; | ||
import { useAsyncValidate } from './useAsyncValidate'; | ||
|
||
// Mock dependencies | ||
vi.mock('../../../utils/validate', () => ({ | ||
validate: vi.fn().mockReturnValue([ | ||
{ | ||
id: 'name', | ||
originId: 'name', | ||
message: ['error'], | ||
invalidValue: 'John', | ||
}, | ||
]), | ||
})); | ||
|
||
vi.mock('lodash/debounce', () => ({ | ||
default: (fn: any) => fn, | ||
})); | ||
|
||
describe('useAsyncValidate', () => { | ||
const mockContext = { name: 'John' }; | ||
const mockSchema = [{ id: 'name', validators: [], rules: [] }]; | ||
|
||
beforeEach(() => { | ||
vi.clearAllMocks(); | ||
}); | ||
|
||
it('should initialize with empty validation errors', () => { | ||
const { result } = renderHook(() => useAsyncValidate(mockContext, mockSchema)); | ||
expect(result.current).toEqual([]); | ||
}); | ||
|
||
it('should not validate when validateAsync is false', () => { | ||
renderHook(() => useAsyncValidate(mockContext, mockSchema, { validateAsync: false })); | ||
expect(validate).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('should not validate when validateOnChange is false', () => { | ||
renderHook(() => useAsyncValidate(mockContext, mockSchema, { validateOnChange: false })); | ||
expect(validate).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('should validate and set errors when validateAsync and validateOnChange are true', () => { | ||
const { result } = renderHook(() => | ||
useAsyncValidate(mockContext, mockSchema, { | ||
validateAsync: true, | ||
validateOnChange: true, | ||
}), | ||
); | ||
|
||
expect(validate).toHaveBeenCalledWith(mockContext, mockSchema, { abortEarly: false }); | ||
expect(result.current).toEqual([ | ||
{ | ||
id: 'name', | ||
originId: 'name', | ||
message: ['error'], | ||
invalidValue: 'John', | ||
}, | ||
]); | ||
}); | ||
|
||
it('should pass abortEarly param to validate function', () => { | ||
renderHook(() => | ||
useAsyncValidate(mockContext, mockSchema, { | ||
validateAsync: true, | ||
validateOnChange: true, | ||
abortEarly: true, | ||
}), | ||
); | ||
|
||
expect(validate).toHaveBeenCalledWith(mockContext, mockSchema, { abortEarly: true }); | ||
}); | ||
Comment on lines
+45
to
+74
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add error handling test cases. The current tests don't verify behavior when validation fails unexpectedly. Add test cases for error scenarios to ensure robust error handling. it('should handle validation errors gracefully', async () => {
vi.mocked(validate).mockImplementationOnce(() => {
throw new Error('Validation failed');
});
const { result } = renderHook(() =>
useAsyncValidate(mockContext, mockSchema, {
validateAsync: true,
validateOnChange: true,
}),
);
expect(result.current).toEqual([]);
// Optionally, verify error was logged or handled appropriately
}); |
||
|
||
it('should revalidate when context changes', () => { | ||
const { rerender } = renderHook( | ||
({ context }) => | ||
useAsyncValidate(context, mockSchema, { | ||
validateAsync: true, | ||
validateOnChange: true, | ||
}), | ||
{ | ||
initialProps: { context: mockContext }, | ||
}, | ||
); | ||
|
||
const newContext = { name: 'Jane' }; | ||
rerender({ context: newContext }); | ||
|
||
expect(validate).toHaveBeenCalledWith(newContext, mockSchema, { abortEarly: false }); | ||
}); | ||
|
||
it('should revalidate when schema changes', () => { | ||
const { rerender } = renderHook( | ||
({ schema }) => | ||
useAsyncValidate(mockContext, schema, { | ||
validateAsync: true, | ||
validateOnChange: true, | ||
}), | ||
{ | ||
initialProps: { schema: mockSchema }, | ||
}, | ||
); | ||
|
||
const newSchema = [{ id: 'email', validators: [], rules: [] }]; | ||
rerender({ schema: newSchema }); | ||
|
||
expect(validate).toHaveBeenCalledWith(mockContext, newSchema, { abortEarly: false }); | ||
}); | ||
}); | ||
Comment on lines
+76
to
+111
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add cleanup behavior test cases. Add tests to verify proper cleanup when the component unmounts, especially important for async operations. it('should cleanup pending validations on unmount', () => {
const { unmount } = renderHook(() =>
useAsyncValidate(mockContext, mockSchema, {
validateAsync: true,
validateOnChange: true,
}),
);
unmount();
// Verify that pending validations are cancelled
// and resources are cleaned up
}); |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,24 @@ | ||||||||||||||||||||||||||||||||||
import { useCallback, useState } from 'react'; | ||||||||||||||||||||||||||||||||||
import { IValidationError, IValidationSchema } from '../../../types'; | ||||||||||||||||||||||||||||||||||
import { validate } from '../../../utils/validate'; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
export interface IUseManualValidateParams { | ||||||||||||||||||||||||||||||||||
abortEarly?: boolean; | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
export const useManualValidate = ( | ||||||||||||||||||||||||||||||||||
context: object, | ||||||||||||||||||||||||||||||||||
schema: IValidationSchema[], | ||||||||||||||||||||||||||||||||||
params: IUseManualValidateParams = {}, | ||||||||||||||||||||||||||||||||||
): [IValidationError[], () => void] => { | ||||||||||||||||||||||||||||||||||
const [validationErrors, setValidationErrors] = useState<IValidationError[]>([]); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
const { abortEarly = false } = params; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
const _validate = useCallback(() => { | ||||||||||||||||||||||||||||||||||
const errors = validate(context, schema, { abortEarly }); | ||||||||||||||||||||||||||||||||||
setValidationErrors(errors); | ||||||||||||||||||||||||||||||||||
}, [context, schema, abortEarly]); | ||||||||||||||||||||||||||||||||||
Comment on lines
+18
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling for the validate function. The validation function should handle potential errors that might occur during validation to prevent uncaught exceptions. const _validate = useCallback(() => {
- const errors = validate(context, schema, { abortEarly });
- setValidationErrors(errors);
+ try {
+ const errors = validate(context, schema, { abortEarly });
+ setValidationErrors(errors);
+ } catch (error) {
+ console.error('Validation failed:', error);
+ setValidationErrors([{
+ path: '',
+ message: 'An unexpected error occurred during validation'
+ }]);
+ }
}, [context, schema, abortEarly]); 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
return [validationErrors, _validate]; | ||||||||||||||||||||||||||||||||||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { act, renderHook } from '@testing-library/react'; | ||
import { beforeEach, describe, expect, it, vi } from 'vitest'; | ||
import { validate } from '../../../utils/validate'; | ||
import { useManualValidate } from './useManualValidate'; | ||
|
||
vi.mock('../../../utils/validate', () => ({ | ||
validate: vi.fn().mockReturnValue([ | ||
{ | ||
id: 'name', | ||
originId: 'name', | ||
message: ['error'], | ||
invalidValue: 'John', | ||
}, | ||
]), | ||
})); | ||
|
||
describe('useManualValidate', () => { | ||
const mockContext = { name: 'John' }; | ||
const mockSchema = [{ id: 'name', validators: [], rules: [] }]; | ||
|
||
beforeEach(() => { | ||
vi.clearAllMocks(); | ||
}); | ||
|
||
it('should initialize with empty validation errors', () => { | ||
const { result } = renderHook(() => useManualValidate(mockContext, mockSchema)); | ||
|
||
expect(result.current.validationErrors).toEqual([]); | ||
}); | ||
|
||
it('should validate and set errors when validate is called', () => { | ||
const { result } = renderHook(() => useManualValidate(mockContext, mockSchema)); | ||
|
||
act(() => { | ||
result.current.validate(); | ||
}); | ||
|
||
expect(validate).toHaveBeenCalledWith(mockContext, mockSchema, { abortEarly: false }); | ||
expect(result.current.validationErrors).toEqual([ | ||
{ | ||
id: 'name', | ||
originId: 'name', | ||
message: ['error'], | ||
invalidValue: 'John', | ||
}, | ||
]); | ||
}); | ||
|
||
it('should pass abortEarly param to validate function', () => { | ||
const { result } = renderHook(() => | ||
useManualValidate(mockContext, mockSchema, { abortEarly: true }), | ||
); | ||
|
||
act(() => { | ||
result.current.validate(); | ||
}); | ||
|
||
expect(validate).toHaveBeenCalledWith(mockContext, mockSchema, { abortEarly: true }); | ||
}); | ||
|
||
it('should memoize validate callback with correct dependencies', () => { | ||
const { result, rerender } = renderHook( | ||
({ context, schema, params }) => useManualValidate(context, schema, params), | ||
{ | ||
initialProps: { | ||
context: mockContext, | ||
schema: mockSchema, | ||
params: { abortEarly: false }, | ||
}, | ||
}, | ||
); | ||
|
||
const firstValidate = result.current.validate; | ||
|
||
// Rerender with same props | ||
rerender({ | ||
context: mockContext, | ||
schema: mockSchema, | ||
params: { abortEarly: false }, | ||
}); | ||
|
||
expect(result.current.validate).toBe(firstValidate); | ||
|
||
// Rerender with different context | ||
rerender({ | ||
context: { ...mockContext, newField: 'value' } as any, | ||
schema: mockSchema, | ||
params: { abortEarly: false }, | ||
}); | ||
|
||
Comment on lines
+85
to
+90
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Remove type assertion and use proper typing The use of - context: { ...mockContext, newField: 'value' } as any,
+ context: { ...mockContext, newField: 'value' }, Consider creating an interface for the context type to make the test more type-safe: interface TestContext {
name: string;
newField?: string;
}
const mockContext: TestContext = { name: 'John' }; |
||
expect(result.current.validate).not.toBe(firstValidate); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,23 @@ | ||||||||||||||||||||
import { useMemo } from 'react'; | ||||||||||||||||||||
import { IValidationSchema } from '../../../types'; | ||||||||||||||||||||
import { validate } from '../../../utils/validate'; | ||||||||||||||||||||
|
||||||||||||||||||||
export interface IUseSyncValidateParams { | ||||||||||||||||||||
abortEarly?: boolean; | ||||||||||||||||||||
validateSync?: boolean; | ||||||||||||||||||||
validateOnChange?: boolean; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
export const useSyncValidate = ( | ||||||||||||||||||||
context: object, | ||||||||||||||||||||
schema: IValidationSchema[], | ||||||||||||||||||||
params: IUseSyncValidateParams = {}, | ||||||||||||||||||||
) => { | ||||||||||||||||||||
const { abortEarly = false, validateSync = false, validateOnChange = true } = params; | ||||||||||||||||||||
|
||||||||||||||||||||
return useMemo(() => { | ||||||||||||||||||||
if (!validateSync || !validateOnChange) return []; | ||||||||||||||||||||
|
||||||||||||||||||||
return validate(context, schema, { abortEarly }); | ||||||||||||||||||||
}, [context, schema, abortEarly, validateSync, validateOnChange]); | ||||||||||||||||||||
Comment on lines
+21
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle potential validation errors. The return useMemo(() => {
- return validate(context, schema, { abortEarly });
+ try {
+ return validate(context, schema, { abortEarly });
+ } catch (error) {
+ console.error('Validation error:', error);
+ return []; // Return empty array on validation failure
+ }
}, [context, schema, abortEarly, validateSync, validateOnChange]); 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implement proper context value
The context provider is initialized with an empty object, which doesn't match the expected interface from the AI summary.
Implement the required context value structure: