New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

@de-formed/react-validations

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@de-formed/react-validations - npm Package Compare versions

Comparing version
2.0.4
to
3.0.0
+675
__tests__/useValidation.test.ts
import { renderHook, act } from '@testing-library/react-hooks';
import { useValidation } from '../';
import { ValidationSchema, ValidationState } from '@de-formed/base';
type TestSchema = {
name: string;
age: number;
dingo: boolean;
agreement: boolean;
};
const schema: ValidationSchema<TestSchema> = {
name: [
{
error: 'Name is required.',
validation: (state: TestSchema) => state.name.length > 0,
},
{
error: 'Cannot be bob.',
validation: (state: TestSchema) => state.name !== 'bob',
},
{
error: 'Must be dingo.',
validation: (state: TestSchema) => {
return state.dingo ? state.name === 'dingo' : true;
},
},
],
age: [
{
error: 'Must be 18',
validation: (state: TestSchema) => state.age >= 18,
},
],
agreement: [
{
error: 'Must accept terms.',
validation: ({ agreement }) => Boolean(agreement),
},
],
};
const mockValidationState: ValidationState = {
name: {
isValid: true,
errors: [],
},
age: {
isValid: true,
errors: [],
},
agreement: {
isValid: true,
errors: [],
},
};
const defaultState = {
name: 'jack',
dingo: false,
age: 42,
agreement: true,
};
const failingState = {
...defaultState,
name: 'bob',
age: 15,
};
describe('useValidation tests', () => {
it('should be defined', () => {
expect(useValidation).toBeDefined();
});
it('renders the hook correctly and checks types', () => {
const { result } = renderHook(() => useValidation(schema));
expect(typeof result.current.getError).toBe('function');
expect(typeof result.current.getFieldValid).toBe('function');
expect(typeof result.current.isValid).toBe('boolean');
expect(typeof result.current.validate).toBe('function');
expect(typeof result.current.validateAll).toBe('function');
expect(typeof result.current.validateAllIfTrue).toBe('function');
expect(typeof result.current.validateIfTrue).toBe('function');
expect(typeof result.current.validateOnBlur).toBe('function');
expect(typeof result.current.validateOnChange).toBe('function');
expect(typeof result.current.resetValidationState).toBe('function');
expect(typeof result.current.setValidationState).toBe('function');
expect(Array.isArray(result.current.validationErrors)).toBe(true);
expect(typeof result.current.validationState).toBe('object');
});
it('returns all functions and read-only objects defined by hook', () => {
const { result } = renderHook(() => useValidation(schema));
expect(result.current.validationState).toStrictEqual(mockValidationState);
expect(Object.keys(result.current)).toStrictEqual([
'getAllErrors',
'getError',
'getFieldValid',
'isValid',
'resetValidationState',
'setValidationState',
'validate',
'validateAll',
'validateAllIfTrue',
'validateIfTrue',
'validateOnBlur',
'validateOnChange',
'validationErrors',
'validationState',
]);
});
describe('createValidationState', () => {
it('crates a validation state when given a schema', () => {
const { result } = renderHook(() => useValidation(schema));
expect(result.current.validationState).toStrictEqual(mockValidationState);
});
it('defaults to an empty object if undefined is provided', () => {
const { result } = renderHook(() => useValidation(undefined as any));
expect(result.current.validationState).toStrictEqual({});
});
});
describe('getError', () => {
it('returns empty string by default', () => {
const { result } = renderHook(() => useValidation(schema));
const output = result.current.getError('name');
expect(output).toBe('');
});
it('returns empty string if the property does not exist', () => {
const { result } = renderHook(() => useValidation(schema));
const output = result.current.getError('balls' as keyof TestSchema);
expect(output).toBe('');
});
it('retrieves an error message', () => {
const { result } = renderHook(() => useValidation(schema));
act(() => {
result.current.validate('name', { name: '' } as any);
});
const output = result.current.getError('name');
expect(output).toBe('Name is required.');
});
});
describe('getAllErrors', () => {
it('returns empty array by default', () => {
const { result } = renderHook(() => useValidation(schema));
const output = result.current.getAllErrors('name');
expect(output).toStrictEqual([]);
});
it('returns empty array if the property does not exist', () => {
const { result } = renderHook(() => useValidation(schema));
const output = result.current.getAllErrors('balls' as keyof TestSchema);
expect(output).toStrictEqual([]);
});
it('retrieves array of all error messages', () => {
const { result } = renderHook(() => useValidation(schema));
const name = 'name';
const state = {
...defaultState,
name: '',
};
act(() => {
result.current.validate(name, state);
});
const output = result.current.getAllErrors('name');
expect(output).toStrictEqual(['Name is required.']);
});
});
describe('getFieldValid', () => {
it('returns true by default', () => {
const { result } = renderHook(() => useValidation(schema));
const output = result.current.getFieldValid('name');
expect(output).toBe(true);
});
it('returns true if the property does not exist', () => {
const { result } = renderHook(() => useValidation(schema));
const output = result.current.getFieldValid('balls' as keyof TestSchema);
expect(output).toBe(true);
});
it('retrieves an invalid state', () => {
const { result } = renderHook(() => useValidation(schema));
const name = 'name';
const state = {
...defaultState,
name: '',
};
act(() => {
result.current.validate(name, state);
});
const output = result.current.getFieldValid('name');
expect(output).toBe(false);
});
});
describe('isValid', () => {
it('returns true by default', () => {
const { result } = renderHook(() => useValidation(schema));
const output = result.current.isValid;
expect(output).toBe(true);
});
it('changes to false after a validation fails', () => {
const { result } = renderHook(() => useValidation(schema));
const name = 'name';
const state = {
...defaultState,
name: 'bob',
};
act(() => {
result.current.validate(name, state);
});
const output = result.current.isValid;
expect(output).toBe(false);
});
it('changes to true after a failed validation passes', () => {
const { result } = renderHook(() => useValidation(schema));
const name = 'name';
const state = {
...defaultState,
name: 'bob',
};
const state2 = {
...defaultState,
name: 'bob ross',
};
act(() => {
result.current.validate(name, state);
result.current.validate(name, state2);
});
const output = result.current.isValid;
expect(output).toBe(true);
});
});
describe('validate', () => {
it('returns a boolean if key exists', () => {
const { result } = renderHook(() => useValidation(schema));
let output: any;
const name = 'name';
const state = {
...defaultState,
name: 'bob',
};
act(() => {
output = result.current.validate(name, state);
});
expect(typeof output).toBe('boolean');
});
it('returns true if key does not exist', () => {
const { result } = renderHook(() => useValidation(schema));
const name = 'balls' as keyof TestSchema;
const state = {
...defaultState,
name: 'bob',
};
let output: any;
act(() => {
output = result.current.validate(name, state);
});
expect(output).toBe(true);
});
it('updates the validationState when validation fails', () => {
const { result } = renderHook(() => useValidation(schema));
const validationState = {
...mockValidationState,
name: {
isValid: false,
errors: ['Must be dingo.'],
},
};
const name = 'name';
const state = {
...defaultState,
name: 'chuck',
dingo: true,
};
act(() => {
result.current.validate(name, state);
});
expect(result.current.isValid).toBe(false);
expect(result.current.validationState).toStrictEqual(validationState);
});
});
describe('validateAll', () => {
it('returns a boolean', () => {
const { result } = renderHook(() => useValidation(schema));
let output: any;
act(() => {
output = result.current.validateAll(defaultState);
});
expect(typeof output).toBe('boolean');
});
it('returns true if validations pass', () => {
const { result } = renderHook(() => useValidation(schema));
let output: any;
act(() => {
output = result.current.validateAll(defaultState);
});
expect(output).toBe(true);
});
it('returns false if any validation fails', () => {
const { result } = renderHook(() => useValidation(schema));
act(() => {
const output = result.current.validateAll(failingState);
expect(output).toBe(false);
});
});
it('returns all failing validations', () => {
const { result } = renderHook(() => useValidation(schema));
act(() => {
result.current.validateAll(failingState);
});
expect(result.current.validationState).toStrictEqual({
name: {
errors: ['Cannot be bob.'],
isValid: false,
},
age: {
errors: ['Must be 18'],
isValid: false,
},
agreement: {
errors: [],
isValid: true,
},
});
});
it('handles nested validation reductions', () => {
const data = [defaultState, defaultState, defaultState];
const { result } = renderHook(() => useValidation(schema));
let output: boolean[];
act(() => {
output = data.map((s) => result.current.validateAll(s));
expect(output).toStrictEqual([true, true, true]);
});
});
it('validates a subsection of keys', () => {
const { result } = renderHook(() => useValidation(schema));
act(() => {
result.current.validateAll(failingState);
});
expect(result.current.getError('age')).toBe('Must be 18');
act(() => {
result.current.validateAll(failingState, ['name']);
});
expect(result.current.getError('age')).toBe('Must be 18');
});
it('handles missing properties', () => {
const wonkySchema = {
...schema,
canSave: [
{
error: 'you cannot save',
validation: (state: any) => !!state.name,
},
],
};
const { result } = renderHook(() => useValidation(wonkySchema));
act(() => {
result.current.validateAll(failingState);
});
expect(result.current.getError('canSave')).toBe('');
});
});
describe('validateAllIfTrue', () => {
it('returns a boolean', () => {
const { result } = renderHook(() => useValidation(schema));
let output: any;
act(() => {
output = result.current.validateAllIfTrue(defaultState);
});
expect(typeof output).toBe('boolean');
});
it('returns true if validations pass', () => {
const { result } = renderHook(() => useValidation(schema));
let output: any;
act(() => {
output = result.current.validateAllIfTrue(defaultState);
});
expect(output).toBe(true);
});
it('ignores failing validations', () => {
const { result } = renderHook(() => useValidation(schema));
act(() => {
const output = result.current.validateAllIfTrue(failingState);
expect(output).toBe(true);
});
});
it('handles nested validation reductions', () => {
const data = [defaultState, defaultState, defaultState];
const { result } = renderHook(() => useValidation(schema));
let output: boolean[];
act(() => {
output = data.map((s) => result.current.validateAllIfTrue(s));
expect(output).toStrictEqual([true, true, true]);
});
});
it('validates a subsection of keys', () => {
const { result } = renderHook(() => useValidation(schema));
act(() => {
result.current.validateAllIfTrue(failingState);
});
expect(result.current.getError('age')).toBe('');
act(() => {
result.current.validateAllIfTrue(failingState, ['name']);
});
expect(result.current.getError('age')).toBe('');
});
it('handles missing properties', () => {
const wonkySchema = {
...schema,
canSave: [
{
error: 'you cannot save',
validation: (state: any) => !!state.name,
},
],
};
const { result } = renderHook(() => useValidation(wonkySchema));
act(() => {
result.current.validateAllIfTrue(failingState);
});
expect(result.current.getError('canSave')).toBe('');
});
});
describe('validateIfTrue', () => {
it('returns a boolean if key exists', () => {
const { result } = renderHook(() => useValidation(schema));
let output: any;
const name = 'name';
const state = {
...defaultState,
name: 'bob',
};
act(() => {
output = result.current.validateIfTrue(name, state);
});
expect(typeof output).toBe('boolean');
});
it('returns true if key does not exist', () => {
const { result } = renderHook(() => useValidation(schema));
const name = 'balls' as keyof TestSchema;
const state = {
...defaultState,
name: 'bob',
};
let output: any;
act(() => {
output = result.current.validateIfTrue(name, state);
});
expect(output).toBe(true);
});
it('updates the validationState when validation fails', () => {
const { result } = renderHook(() => useValidation(schema));
const validationState = {
...mockValidationState,
};
const name = 'name';
const state = {
...defaultState,
name: 'chuck',
dingo: true,
};
act(() => {
result.current.validateIfTrue(name, state);
});
expect(result.current.isValid).toBe(true);
expect(result.current.validationState).toStrictEqual(validationState);
});
it('updates the validationState when an invalid validation succeeds', () => {
const { result } = renderHook(() => useValidation(schema));
const state = {
...defaultState,
name: 'bob',
};
const state2 = {
...defaultState,
name: 'jack',
};
const validationState = {
...mockValidationState,
};
act(() => {
result.current.validate('name', state);
});
expect(result.current.isValid).toBe(false);
act(() => {
result.current.validateIfTrue('name', state2);
});
expect(result.current.isValid).toBe(true);
expect(result.current.validationState).toStrictEqual(validationState);
});
});
describe('validateOnBlur', () => {
it('returns a new function', () => {
const { result } = renderHook(() => useValidation(schema));
const state = defaultState;
const handleBlur = result.current.validateOnBlur(state);
expect(typeof handleBlur).toBe('function');
});
it('updates the valdiation state when called', () => {
const { result } = renderHook(() => useValidation(schema));
const state = defaultState;
const handleBlur = result.current.validateOnBlur(state);
const event = {
target: {
name: 'name',
value: 'bob',
},
};
act(() => {
handleBlur(event as any);
});
expect(result.current.isValid).toBe(false);
});
});
describe('validateOnChange', () => {
it('returns a new function', () => {
const { result } = renderHook(() => useValidation(schema));
const state = defaultState;
const onChange = (_event: any) => 'bob ross';
const handleChange = result.current.validateOnChange(onChange, state);
expect(typeof handleChange).toBe('function');
});
it('updates the valdiation state if true and returns event', () => {
const { result } = renderHook(() => useValidation(schema));
const state = {
...defaultState,
name: 'bob',
};
act(() => {
result.current.validate('name', state);
});
expect(result.current.isValid).toBe(false);
const onChange = () => 'bob ross';
const handleChange = result.current.validateOnChange(onChange, state);
const event = {
target: {
name: 'name',
value: 'jack',
},
};
let output: any;
act(() => {
output = handleChange(event as any);
});
expect(result.current.isValid).toBe(true);
expect(output).toBe('bob ross');
});
it('updates checked properties if true and returns event', () => {
const { result } = renderHook(() => useValidation(schema));
const state = {
...defaultState,
agreement: false,
};
act(() => {
result.current.validate('agreement', state);
});
expect(result.current.isValid).toBe(false);
const onChange = () => true;
const handleChange = result.current.validateOnChange(onChange, state);
const event = {
target: {
name: 'agreement',
checked: true,
type: 'checkbox',
},
};
let output: any;
act(() => {
output = handleChange(event as any);
});
expect(result.current.isValid).toBe(true);
expect(output).toBe(true);
});
});
describe('resetValidationState', () => {
it('resets the validation state', () => {
const { result } = renderHook(() => useValidation(schema));
const state = {
...defaultState,
name: 'bob',
};
act(() => {
result.current.validate('name', state);
result.current.resetValidationState();
});
expect(result.current.isValid).toBe(true);
});
});
describe('validationErrors', () => {
it('starts as an empty array', () => {
const { result } = renderHook(() => useValidation(schema));
expect(result.current.validationErrors).toStrictEqual([]);
});
it('adds validation errors when validation state is invalid', () => {
const { result } = renderHook(() => useValidation(schema));
const state = {
...defaultState,
name: 'bob',
};
act(() => {
result.current.validate('name', state);
});
expect(result.current.validationErrors).toStrictEqual(['Cannot be bob.']);
});
it('removes validation errors when validation state is valid', () => {
const { result } = renderHook(() => useValidation(schema));
const state = {
...defaultState,
name: 'bob',
};
const state2 = {
...defaultState,
name: 'jack',
};
act(() => {
result.current.validate('name', state);
result.current.validate('name', state2);
});
expect(result.current.validationErrors).toStrictEqual([]);
});
});
describe('forceValidationState', () => {
it('overrides the existing validation state with a new one', () => {
const { result: v1 } = renderHook(() => useValidation(schema));
const { result: v2 } = renderHook(() => useValidation(schema));
act(() => {
v1.current.validateAll(failingState);
});
act(() => {
v2.current.setValidationState(v1.current.validationState);
});
expect(v1.current.validationState).toStrictEqual(
v2.current.validationState,
);
});
});
});
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Main
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x, 14.x, 16.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm install -g yarn
- name: yarn install, build, and test
run: |
yarn
yarn test --coverage
- name: Codecov
uses: codecov/codecov-action@v2
with:
# token: ${{ secrets.CODECOV_TOKEN }}
# flags: unittests
name: codecov-umbrella # optional
# fail_ci_if_error: true # optional (default = false)
verbose: true # optional (default = false)
+4
-5

@@ -1,4 +0,3 @@

/// <reference types="react" />
import { GetAllErrors, GetError, GetFieldValid, ResetValidationState, Validate, ValidateAll, ValidateAllIfTrue, ValidateIfTrue, ValidateOnBlur, ValidateOnChange, ValidationSchema } from './types';
export * from './types';
import React from 'react';
import { GetAllErrors, GetError, GetFieldValid, ResetValidationState, Validate, ValidateAll, ValidateAllIfTrue, ValidateIfTrue, ValidateOnBlur, ValidateOnChange, ValidationSchema, ValidationState } from '@de-formed/base';
export declare const useValidation: <S>(validationSchema: ValidationSchema<S>) => {

@@ -10,3 +9,3 @@ getAllErrors: GetAllErrors<S>;

resetValidationState: ResetValidationState;
setValidationState: import("react").Dispatch<import("react").SetStateAction<import("@de-formed/base").ValidationState>>;
setValidationState: React.Dispatch<React.SetStateAction<ValidationState>>;
validate: Validate<S>;

@@ -19,3 +18,3 @@ validateAll: ValidateAll<S>;

validationErrors: string[];
validationState: import("@de-formed/base").ValidationState;
validationState: ValidationState;
};
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.useValidation = void 0;
const react_1 = require("react");
const react_1 = __importDefault(require("react"));
const base_1 = require("@de-formed/base");
__exportStar(require("./types"), exports);
const useValidation = (validationSchema) => {
const [validationState, setValidationState] = (0, react_1.useState)(() => (0, base_1.createValidationState)(validationSchema));
const [validationErrors, setValidationErros] = (0, react_1.useState)([]);
const [isValid, setIsValid] = (0, react_1.useState)(true);
const [validationState, setValidationState] = react_1.default.useState(() => (0, base_1.createValidationState)(validationSchema));
const [validationErrors, setValidationErrors] = react_1.default.useState([]);
const [isValid, setIsValid] = react_1.default.useState(true);
const resetValidationState = () => setValidationState((0, base_1.createValidationState)(validationSchema));

@@ -31,5 +23,4 @@ const validate = (0, base_1.createValidate)(validationSchema, validationState, setValidationState);

const getFieldValid = (0, base_1.createGetFieldValid)(validationState);
const generateValidationErrors = (state = validationState) => (0, base_1.gatherValidationErrors)(state);
(0, react_1.useEffect)(() => {
setValidationErros(generateValidationErrors(validationState));
react_1.default.useEffect(() => {
setValidationErrors((0, base_1.gatherValidationErrors)(validationState));
setIsValid((0, base_1.calculateIsValid)(validationState));

@@ -36,0 +27,0 @@ }, [validationState]);

@@ -1,1 +0,1 @@

{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,iCAA4C;AAC5C,0CAayB;AAezB,0CAAwB;AAQjB,MAAM,aAAa,GAAG,CAAI,gBAAqC,EAAE,EAAE;IAExE,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,IAAA,gBAAQ,EAAC,GAAG,EAAE,CAC1D,IAAA,4BAAqB,EAAC,gBAAgB,CAAC,CACxC,CAAC;IACF,MAAM,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,GAAG,IAAA,gBAAQ,EAAW,EAAE,CAAC,CAAC;IACtE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,IAAA,gBAAQ,EAAC,IAAI,CAAC,CAAC;IAK7C,MAAM,oBAAoB,GAAyB,GAAG,EAAE,CACtD,kBAAkB,CAAC,IAAA,4BAAqB,EAAC,gBAAgB,CAAC,CAAC,CAAC;IAG9D,MAAM,QAAQ,GAAgB,IAAA,qBAAc,EAC1C,gBAAgB,EAChB,eAAe,EACf,kBAAkB,CACnB,CAAC;IAGF,MAAM,cAAc,GAAsB,IAAA,2BAAoB,EAC5D,gBAAgB,EAChB,eAAe,EACf,kBAAkB,CACnB,CAAC;IAGF,MAAM,WAAW,GAAmB,IAAA,wBAAiB,EACnD,gBAAgB,EAChB,eAAe,EACf,kBAAkB,CACnB,CAAC;IAGF,MAAM,iBAAiB,GAAyB,IAAA,8BAAuB,EACrE,gBAAgB,EAChB,eAAe,EACf,kBAAkB,CACnB,CAAC;IAGF,MAAM,cAAc,GAAsB,IAAA,2BAAoB,EAC5D,gBAAgB,EAChB,eAAe,EACf,kBAAkB,CACnB,CAAC;IAGF,MAAM,gBAAgB,GAAwB,IAAA,6BAAsB,EAClE,gBAAgB,EAChB,eAAe,EACf,kBAAkB,CACnB,CAAC;IAGF,MAAM,YAAY,GAAoB,IAAA,yBAAkB,EAAC,eAAe,CAAC,CAAC;IAG1E,MAAM,QAAQ,GAAgB,IAAA,qBAAc,EAAC,eAAe,CAAC,CAAC;IAG9D,MAAM,aAAa,GAAqB,IAAA,0BAAmB,EAAC,eAAe,CAAC,CAAC;IAG7E,MAAM,wBAAwB,GAAG,CAAC,KAAK,GAAG,eAAe,EAAE,EAAE,CAC3D,IAAA,6BAAsB,EAAC,KAAK,CAAC,CAAC;IAGhC,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,kBAAkB,CAAC,wBAAwB,CAAC,eAAe,CAAQ,CAAC,CAAC;QACrE,UAAU,CAAC,IAAA,uBAAgB,EAAC,eAAe,CAAC,CAAC,CAAC;IAChD,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC;IAEtB,MAAM,gBAAgB,GAAG;QACvB,YAAY;QACZ,QAAQ;QACR,aAAa;QACb,OAAO;QACP,oBAAoB;QACpB,kBAAkB;QAClB,QAAQ;QACR,WAAW;QACX,iBAAiB;QACjB,cAAc;QACd,cAAc;QACd,gBAAgB;QAChB,gBAAgB;QAChB,eAAe;KAChB,CAAC;IAEF,OAAO,gBAAgB,CAAC;AAC1B,CAAC,CAAC;AA7FW,QAAA,aAAa,iBA6FxB"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAAA,kDAA0B;AAC1B,0CAyByB;AAQlB,MAAM,aAAa,GAAG,CAAI,gBAAqC,EAAE,EAAE;IAExE,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,eAAK,CAAC,QAAQ,CAC1D,GAAG,EAAE,CAAC,IAAA,4BAAqB,EAAC,gBAAgB,CAAC,CAC9C,CAAC;IACF,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,eAAK,CAAC,QAAQ,CAAW,EAAE,CAAC,CAAC;IAC7E,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,eAAK,CAAC,QAAQ,CAAU,IAAI,CAAC,CAAC;IAI5D,MAAM,oBAAoB,GAAyB,GAAG,EAAE,CACtD,kBAAkB,CAAC,IAAA,4BAAqB,EAAC,gBAAgB,CAAC,CAAC,CAAC;IAE9D,MAAM,QAAQ,GAAgB,IAAA,qBAAc,EAC1C,gBAAgB,EAChB,eAAe,EACf,kBAAkB,CACnB,CAAC;IAEF,MAAM,cAAc,GAAsB,IAAA,2BAAoB,EAC5D,gBAAgB,EAChB,eAAe,EACf,kBAAkB,CACnB,CAAC;IAEF,MAAM,WAAW,GAAmB,IAAA,wBAAiB,EACnD,gBAAgB,EAChB,eAAe,EACf,kBAAkB,CACnB,CAAC;IAEF,MAAM,iBAAiB,GAAyB,IAAA,8BAAuB,EACrE,gBAAgB,EAChB,eAAe,EACf,kBAAkB,CACnB,CAAC;IAEF,MAAM,cAAc,GAAsB,IAAA,2BAAoB,EAC5D,gBAAgB,EAChB,eAAe,EACf,kBAAkB,CACnB,CAAC;IAEF,MAAM,gBAAgB,GAAwB,IAAA,6BAAsB,EAClE,gBAAgB,EAChB,eAAe,EACf,kBAAkB,CACnB,CAAC;IAEF,MAAM,YAAY,GAAoB,IAAA,yBAAkB,EAAC,eAAe,CAAC,CAAC;IAE1E,MAAM,QAAQ,GAAgB,IAAA,qBAAc,EAAC,eAAe,CAAC,CAAC;IAE9D,MAAM,aAAa,GAAqB,IAAA,0BAAmB,EAAC,eAAe,CAAC,CAAC;IAG7E,eAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,mBAAmB,CAAC,IAAA,6BAAsB,EAAC,eAAe,CAAC,CAAC,CAAC;QAC7D,UAAU,CAAC,IAAA,uBAAgB,EAAC,eAAe,CAAC,CAAC,CAAC;IAChD,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC;IAEtB,MAAM,gBAAgB,GAAG;QACvB,YAAY;QACZ,QAAQ;QACR,aAAa;QACb,OAAO;QACP,oBAAoB;QACpB,kBAAkB;QAClB,QAAQ;QACR,WAAW;QACX,iBAAiB;QACjB,cAAc;QACd,cAAc;QACd,gBAAgB;QAChB,gBAAgB;QAChB,eAAe;KAChB,CAAC;IAEF,OAAO,gBAAgB,CAAC;AAC1B,CAAC,CAAC;AA/EW,QAAA,aAAa,iBA+ExB"}
module.exports = {
roots: ['<rootDir>/src'],
roots: ['<rootDir>/__tests__'],
transform: {

@@ -4,0 +4,0 @@ '^.+\\.tsx?$': 'ts-jest',

{
"name": "@de-formed/react-validations",
"version": "2.0.4",
"version": "3.0.0",
"description": "Modular, Function-driven Validations",

@@ -22,3 +22,3 @@ "main": "dist/index",

"dependencies": {
"@de-formed/base": "1.0.1"
"@de-formed/base": "3.0.0"
},

@@ -34,5 +34,7 @@ "peerDependencies": {

"@types/jest": "^27.0.1",
"@types/react": "^17.0.20",
"@types/testing-library__dom": "^7.5.0",
"jest": "^27.1.1",
"prettier": "^2.4.0",
"react": "^17.0.2",
"react-test-renderer": "^17.0.2",

@@ -44,13 +46,2 @@ "ts-jest": "^27.0.5",

},
"jest": {
"transform": {
".(ts|tsx)": "ts-jest"
},
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
"moduleFileExtensions": [
"ts",
"tsx",
"js"
]
},
"keywords": [

@@ -57,0 +48,0 @@ "composable",

@@ -1,3 +0,11 @@

# @De-Formed / React Validations
<p align="center">
<img src="https://user-images.githubusercontent.com/35798153/157611790-96f35e8b-ee4f-44e4-b3c9-1864900a02f2.png" />
</p>
[![npm version](https://badge.fury.io/js/@de-formed%2Fbase.svg)](https://badge.fury.io/js/@de-formed%2Fbase)
[![Known Vulnerabilities](https://snyk.io/test/github/prescottbreeden/de-formed/badge.svg)](https://snyk.io/test/github/prescottbreeden/de-formed)
![example workflow](https://github.com/prescottbreeden/de-formed/actions/workflows/main.yml/badge.svg)
[![codecov](https://codecov.io/gh/prescottbreeden/de-formed/branch/main/graph/badge.svg?token=a1u71NhJwb)](https://codecov.io/gh/prescottbreeden/de-formed)
![size](https://img.shields.io/bundlephobia/minzip/@de-formed/base)
@De-Formed Validations offers a robust and unopinionated API to customize form and data validations. With only a handful of properties to learn, @de-formed maintains its own internal state with simple function calls so that you can design your architecture the way you want to.

@@ -13,5 +21,7 @@

## Install
```
yarn add @de-formed/react-validations
```
```

@@ -24,2 +34,3 @@ npm i @de-formed/react-validations

### Step 1: Create a file to define your validations.
```ts

@@ -62,2 +73,3 @@ // usePersonValidation.ts

### Step 2: Use the hook anywhere you need it.
```tsx

@@ -109,4 +121,5 @@ // PersonForm.component.tsx

```
***
---
## Documentation

@@ -113,0 +126,0 @@

@@ -1,2 +0,2 @@

import { useState, useEffect } from 'react';
import React from 'react';
import {

@@ -15,4 +15,2 @@ calculateIsValid,

gatherValidationErrors,
} from '@de-formed/base';
import {
GetAllErrors,

@@ -29,6 +27,5 @@ GetError,

ValidationSchema,
} from './types';
ValidationState,
} from '@de-formed/base';
export * from './types';
/**

@@ -42,15 +39,13 @@ * A hook that can be used to generate an object containing functions and

// --[ local states ]--------------------------------------------------------
const [validationState, setValidationState] = useState(() =>
createValidationState(validationSchema),
const [validationState, setValidationState] = React.useState<ValidationState>(
() => createValidationState(validationSchema),
);
const [validationErrors, setValidationErros] = useState<string[]>([]);
const [isValid, setIsValid] = useState(true);
const [validationErrors, setValidationErrors] = React.useState<string[]>([]);
const [isValid, setIsValid] = React.useState<boolean>(true);
// --[ validation logic ] ---------------------------------------------------
// resetValidationState :: () -> void
const resetValidationState: ResetValidationState = () =>
setValidationState(createValidationState(validationSchema));
// validate :: string -> value -> boolean
const validate: Validate<S> = createValidate(

@@ -62,3 +57,2 @@ validationSchema,

// validateIfTrue :: string -> value -> boolean
const validateIfTrue: ValidateIfTrue<S> = createValidateIfTrue(

@@ -70,3 +64,2 @@ validationSchema,

// validationAllIfTrue :: (x, [string]) -> boolean
const validateAll: ValidateAll<S> = createValidateAll(

@@ -78,3 +71,2 @@ validationSchema,

// validationAllIfTrue :: (x, [string]) -> boolean
const validateAllIfTrue: ValidateAllIfTrue<S> = createValidateAllIfTrue(

@@ -86,3 +78,2 @@ validationSchema,

// validateOnBlur :: state -> (event -> any)
const validateOnBlur: ValidateOnBlur<S> = createValidateOnBlur(

@@ -94,3 +85,2 @@ validationSchema,

// validateOnChange :: (onChange, state) -> (event -> any)
const validateOnChange: ValidateOnChange<S> = createValidateOnChange(

@@ -102,20 +92,13 @@ validationSchema,

// getAllErrors :: (string, ValidationState) -> [string]
const getAllErrors: GetAllErrors<S> = createGetAllErrors(validationState);
// getError :: (string, ValidationState) -> string
const getError: GetError<S> = createGetError(validationState);
// getFieldValid :: (string, ValidationState) -> boolean
const getFieldValid: GetFieldValid<S> = createGetFieldValid(validationState);
// generateValidationErrors :: ValidationState -> [string]
const generateValidationErrors = (state = validationState) =>
gatherValidationErrors(state);
// -- update validation error array when validation state changes
useEffect(() => {
setValidationErros(generateValidationErrors(validationState) as any);
// -- update validation error array and isValid when validation state changes
React.useEffect(() => {
setValidationErrors(gatherValidationErrors(validationState));
setIsValid(calculateIsValid(validationState));
}, [validationState]); // eslint-disable-line
}, [validationState]);

@@ -140,2 +123,2 @@ const validationObject = {

return validationObject;
};
};

Sorry, the diff of this file is not supported yet

export declare class Maybe {
$value: any;
get isNothing(): boolean;
get isJust(): boolean;
constructor(x: any);
static of(x: any): Maybe;
map(fn: any): Maybe;
chain(fn: any): any;
join(): any;
}
export declare const maybe: (x: any) => Maybe;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.maybe = exports.Maybe = void 0;
class Maybe {
constructor(x) {
this.$value = x;
}
get isNothing() {
return this.$value === null || this.$value === undefined;
}
get isJust() {
return !this.isNothing;
}
static of(x) {
return new Maybe(x);
}
map(fn) {
return this.isNothing ? this : Maybe.of(fn(this.$value));
}
chain(fn) {
return this.map(fn).join();
}
join() {
return this.isNothing ? this : this.$value;
}
}
exports.Maybe = Maybe;
exports.maybe = (x) => Maybe.of(x);
//# sourceMappingURL=maybe.js.map
{"version":3,"file":"maybe.js","sourceRoot":"","sources":["../src/maybe.ts"],"names":[],"mappings":";;;AAAA,MAAa,KAAK;IAWhB,YAAY,CAAM;QAChB,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAClB,CAAC;IAVD,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,MAAM,KAAK,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC;IAC3D,CAAC;IAED,IAAI,MAAM;QACR,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC;IACzB,CAAC;IAOD,MAAM,CAAC,EAAE,CAAC,CAAM;QACd,OAAO,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IAGD,GAAG,CAAC,EAAO;QACT,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3D,CAAC;IAQD,KAAK,CAAC,EAAO;QACX,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7B,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IAC7C,CAAC;CAUF;AA/CD,sBA+CC;AACY,QAAA,KAAK,GAAG,CAAC,CAAM,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC"}
export declare type GetAllErrors<S> = (property: keyof S) => string[];
export declare type GetError<S> = (property: keyof S) => string;
export declare type GetFieldValid<S> = (property: keyof S) => boolean;
export declare type IsValid = boolean;
export declare type ResetValidationState = () => void;
export declare type SetValidationState = (validationState: ValidationState) => void;
export declare type Validate<S> = (property: keyof S, value: S) => boolean;
export declare type ValidateAll<S> = (value: S, keys?: (keyof S)[]) => boolean;
export declare type ValidateAllIfTrue<S> = (value: S, keys?: (keyof S)[]) => boolean;
export declare type ValidateIfTrue<S> = (property: keyof S, value: S) => boolean;
export declare type ValidateOnBlur<S> = (value: S) => (event: any) => any;
export declare type ValidateOnChange<S> = (onChange: (event: any) => any, value: S) => (event: any) => any;
export declare type ValidationFunction<S> = (value: S) => boolean;
export interface ValidationObject<S> {
getAllErrors: GetAllErrors<S>;
getError: GetError<S>;
getFieldValid: GetFieldValid<S>;
isValid: boolean;
resetValidationState: ResetValidationState;
setValidationState: SetValidationState;
validate: Validate<S>;
validateAll: ValidateAll<S>;
validateAllIfTrue: ValidateAllIfTrue<S>;
validateIfTrue: ValidateIfTrue<S>;
validateOnBlur: ValidateOnBlur<S>;
validateOnChange: ValidateOnChange<S>;
validationErrors: string[];
validationState: ValidationState;
}
export interface ValidationProps<S> {
error: string;
validation: ValidationFunction<S>;
}
export interface ValidationSchema<S> {
[key: string]: ValidationProps<S>[];
}
export interface ValidationState {
[key: string]: {
isValid: boolean;
errors: string[];
};
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=types.js.map
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
export declare const compose: (...fns: any[]) => (...args: any[]) => any;
export declare const prop: (...args: any[]) => any;
export declare const isPropertyValid: <S>(property: keyof S) => any;
export declare const executeSideEffect: (...args: any[]) => any;
export declare const stringIsNotEmpty: (...args: any[]) => any;
export declare const stringIsLessThan: (...args: any[]) => any;
export declare const stringIsMoreThan: (...args: any[]) => any;
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.stringIsMoreThan = exports.stringIsLessThan = exports.stringIsNotEmpty = exports.executeSideEffect = exports.isPropertyValid = exports.prop = exports.compose = void 0;
const R = __importStar(require("ramda"));
function curry(fn) {
const arity = fn.length;
return function $curry(...args) {
if (args.length < arity) {
return $curry.bind(null, ...args);
}
return fn.call(null, ...args);
};
}
exports.compose = (...fns) => (...args) => fns.reduceRight((res, fn) => [fn.call(null, ...res)], args)[0];
exports.prop = curry((p, obj) => (obj ? obj[p] : undefined));
exports.isPropertyValid = (property) => exports.compose(R.defaultTo(true), R.path([property, 'isValid']));
exports.executeSideEffect = curry((f, x) => f(x) || x);
exports.stringIsNotEmpty = exports.compose(R.gt(R.__, 0), R.length, R.trim);
exports.stringIsLessThan = curry((num, str) => {
return exports.compose(R.lt(R.__, num), R.length, R.trim)(str);
});
exports.stringIsMoreThan = curry((num, str) => {
return exports.compose(R.gt(R.__, num), R.length, R.trim)(str);
});
//# sourceMappingURL=utilities.js.map
{"version":3,"file":"utilities.js","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,yCAA2B;AAG3B,SAAS,KAAK,CAAC,EAAO;IACpB,MAAM,KAAK,GAAG,EAAE,CAAC,MAAM,CAAC;IAExB,OAAO,SAAS,MAAM,CAAC,GAAG,IAAW;QACnC,IAAI,IAAI,CAAC,MAAM,GAAG,KAAK,EAAE;YACvB,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC;SACnC;QAED,OAAO,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC;IAChC,CAAC,CAAC;AACJ,CAAC;AAGY,QAAA,OAAO,GAAG,CAAC,GAAG,GAAU,EAAE,EAAE,CAAC,CAAC,GAAG,IAAW,EAAE,EAAE,CAC3D,GAAG,CAAC,WAAW,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAGpD,QAAA,IAAI,GAAG,KAAK,CAAC,CAAC,CAAS,EAAE,GAAQ,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAElE,QAAA,eAAe,GAAG,CAAI,QAAiB,EAAO,EAAE,CAAC,eAAO,CACnE,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,EACjB,CAAC,CAAC,IAAI,CAAC,CAAC,QAAe,EAAE,SAAS,CAAC,CAAC,CACrC,CAAC;AAEW,QAAA,iBAAiB,GAAG,KAAK,CAAC,CAAC,CAAM,EAAE,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAIzD,QAAA,gBAAgB,GAAG,eAAO,CACrC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EACb,CAAC,CAAC,MAAM,EACR,CAAC,CAAC,IAAI,CACP,CAAC;AAGW,QAAA,gBAAgB,GAAG,KAAK,CAAC,CAAC,GAAW,EAAE,GAAW,EAAE,EAAE;IACjE,OAAO,eAAO,CACZ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,EACf,CAAC,CAAC,MAAM,EACR,CAAC,CAAC,IAAI,CACP,CAAC,GAAG,CAAC,CAAC;AACT,CAAC,CAAC,CAAC;AAGU,QAAA,gBAAgB,GAAG,KAAK,CAAC,CAAC,GAAW,EAAE,GAAW,EAAE,EAAE;IACjE,OAAO,eAAO,CACZ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,EACf,CAAC,CAAC,MAAM,EACR,CAAC,CAAC,IAAI,CACP,CAAC,GAAG,CAAC,CAAC;AACT,CAAC,CAAC,CAAC"}
export declare type ValidationFunction<S> = (state: S) => boolean;
export declare type ForceValidationState = (validationState: ValidationState) => void;
export declare type GetAllErrors<S> = (property: keyof S) => string[];
export declare type GetError<S> = (property: keyof S) => string;
export declare type GetFieldValid<S> = (property: keyof S) => boolean;
export declare type ResetValidationState = () => void;
export declare type Validate<S> = (property: keyof S, state: S) => boolean;
export declare type ValidateAll<S> = (state: S, keys?: (keyof S)[]) => boolean;
export declare type ValidateCustom = (vals: CustomValidation[]) => boolean;
export declare type ValidateIfTrue<S> = (property: keyof S, state: S) => boolean;
export declare type ValidateOnBlur<S> = (state: S) => (event: any) => any;
export declare type ValidateOnChange<S> = (onChange: (event: any) => any, state: S) => (event: any) => any;
export interface ValidationObject<S> {
forceValidationState: ForceValidationState;
getError: GetError<S>;
getAllErrors: GetAllErrors<S>;
getFieldValid: GetFieldValid<S>;
isValid: boolean;
resetValidationState: ResetValidationState;
validate: Validate<S>;
validateAll: ValidateAll<S>;
validateCustom: ValidateCustom;
validateIfTrue: ValidateIfTrue<S>;
validateOnBlur: ValidateOnBlur<S>;
validateOnChange: ValidateOnChange<S>;
validationErrors: string[];
validationState: ValidationState;
}
export interface ValidationProps<S> {
errorMessage: string;
validation: ValidationFunction<S>;
}
export interface ValidationSchema<S> {
[key: string]: ValidationProps<S>[];
}
export interface ValidationState {
[key: string]: {
isValid: boolean;
errors: string[];
};
}
export interface CustomValidation {
key: string;
value: any;
state?: any;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=types.js.map
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/validations/types.ts"],"names":[],"mappings":""}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=useValidation-old.js.map
{"version":3,"file":"useValidation-old.js","sourceRoot":"","sources":["../../src/validations/useValidation-old.ts"],"names":[],"mappings":""}
/// <reference types="react" />
import { ValidateOnBlur, ValidateOnChange, ValidationSchema } from "../types";
export declare const useValidation: <S>(validationSchema: ValidationSchema<S>) => {
getAllErrors: (property: keyof S, vState?: any) => any;
getError: (property: keyof S, vState?: any) => any;
getFieldValid: (property: keyof S, vState?: any) => any;
isValid: (state?: any) => boolean;
resetValidationState: () => void;
setValidationState: import("react").Dispatch<any>;
validate: (property: keyof S, value: any) => any;
validateIfTrue: (property: keyof S, value: any) => any;
validateAll: (value: any, props?: string[]) => any;
validateAllIfTrue: (value: any, props?: string[]) => any;
validateOnBlur: ValidateOnBlur<S>;
validateOnChange: ValidateOnChange<S>;
validationErrors: never[];
validationState: any;
};
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.useValidation = void 0;
const react_1 = require("react");
const R = __importStar(require("ramda"));
const maybe_1 = require("../maybe");
const utilities_1 = require("../utilities");
exports.useValidation = (validationSchema) => {
const createValidationsState = (schema) => {
const buildState = (acc, key) => ({
...acc,
[key]: { isValid: true, errors: [] },
});
const state = maybe_1.maybe(schema)
.map(R.keys)
.map(R.reduce(buildState, {}));
return state.isJust ? state.join() : {};
};
const [validationState, setValidationState] = react_1.useState(createValidationsState(validationSchema));
const [validationErrors, setValidationErros] = react_1.useState([]);
const updateValidationState = utilities_1.executeSideEffect(setValidationState);
const resetValidationState = () => R.pipe(createValidationsState, setValidationState)(validationSchema);
const updatePropertyOnState = R.curry((property, value) => {
const valueIsValid = R.pipe(utilities_1.prop("validation"), R.applyTo(value));
const getErrorOrNone = R.ifElse(valueIsValid, R.always(''), R.prop('error'));
const state = maybe_1.maybe(validationSchema)
.map(utilities_1.prop(property))
.map(R.values)
.map(R.map(getErrorOrNone))
.map(R.filter((x) => x.length > 0))
.map((errors) => ({ errors, isValid: !errors.length }))
.map(R.assoc(property, R.__, validationState));
return state.isJust ? state.join() : validationState;
});
const validate = (property, value) => maybe_1.maybe(value)
.map(updatePropertyOnState(property))
.map(R.mergeRight(validationState))
.map(updateValidationState)
.map(utilities_1.isPropertyValid(property))
.chain(R.defaultTo(true));
const validateIfTrue = (property, value) => maybe_1.maybe(value)
.map(updatePropertyOnState(property))
.map(R.mergeRight(validationState))
.map(R.ifElse(utilities_1.isPropertyValid(property), updateValidationState, R.always(null)))
.chain(R.defaultTo(true));
const validateAll = (value, props = Object.keys(validationSchema)) => {
const reduceStateUpdates = (acc, property) => ({
...acc,
...updatePropertyOnState(property, value),
});
return maybe_1.maybe(props)
.map(R.reduce(reduceStateUpdates, {}))
.map(R.mergeRight(validationState))
.map(updateValidationState)
.map(isValid)
.chain(R.defaultTo(true));
};
const validateAllIfTrue = (value, props = Object.keys(validationSchema)) => {
const reduceValids = (acc, property) => {
const updated = updatePropertyOnState(property, value);
return updated[property].isValid
? { ...acc, ...updated }
: { ...acc, ...validationState[property] };
};
return maybe_1.maybe(props)
.map(R.reduce(reduceValids, {}))
.map(R.mergeRight(validationState))
.map(isValid)
.chain(R.defaultTo(true));
};
const validateOnBlur = (value) => (event) => {
const { name } = event.target;
validate(name, value);
};
const validateOnChange = (onChange, value) => (event) => {
const { name } = event.target;
validateIfTrue(name, value);
return onChange(event);
};
const getAllErrors = (property, vState = validationState) => {
const errors = maybe_1.maybe(vState)
.map(utilities_1.prop(property))
.map(utilities_1.prop("errors"));
return errors.isJust ? errors.join() : [];
};
const getError = (property, vState = validationState) => {
const error = maybe_1.maybe(vState)
.map(utilities_1.prop(property))
.map(utilities_1.prop("errors"))
.map(R.head);
return error.isJust ? error.join() : "";
};
const getFieldValid = (property, vState = validationState) => {
const valid = maybe_1.maybe(vState)
.map(utilities_1.prop(property))
.map(utilities_1.prop("isValid"));
return valid.isJust ? valid.join() : true;
};
const isValid = (state = validationState) => {
return R.reduce((acc, curr) => acc ? utilities_1.isPropertyValid(curr)(state) : acc, true, Object.keys(state));
};
const generateValidationErrors = (state) => {
return R.reduce((acc, curr) => getError(curr) ? [...acc, getError(curr)] : acc, [], Object.keys(state));
};
react_1.useEffect(() => {
setValidationErros(generateValidationErrors(validationState));
}, [validationState]);
return {
getAllErrors,
getError,
getFieldValid,
isValid,
resetValidationState,
setValidationState,
validate,
validateIfTrue,
validateAll,
validateAllIfTrue,
validateOnBlur,
validateOnChange,
validationErrors,
validationState,
};
};
//# sourceMappingURL=useValidation.js.map
{"version":3,"file":"useValidation.js","sourceRoot":"","sources":["../../src/validations/useValidation.ts"],"names":[],"mappings":"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"}
import { ForceValidationState, GetAllErrors, GetError, GetFieldValid, ResetValidationState, Validate, ValidateAll, ValidateCustom, ValidateIfTrue, ValidateOnBlur, ValidateOnChange, ValidationSchema, ValidationState } from './types';
export declare class Validation<S> {
private _validationSchema;
private _validationState;
get isValid(): boolean;
get validationErrors(): string[];
get validationState(): ValidationState;
constructor(props: ValidationSchema<S>);
private createValidationsState;
resetValidationState: ResetValidationState;
forceValidationState: ForceValidationState;
private allValid;
private runAllValidators;
getError: GetError<S>;
getAllErrors: GetAllErrors<S>;
getFieldValid: GetFieldValid<S>;
validate: Validate<S>;
validateAll: ValidateAll<S>;
validateCustom: ValidateCustom;
validateIfTrue: ValidateIfTrue<S>;
validateOnBlur: ValidateOnBlur<S>;
validateOnChange: ValidateOnChange<S>;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Validation = void 0;
const utilities_1 = require("../utilities");
const ramda_1 = require("ramda");
class Validation {
constructor(props) {
this.createValidationsState = (schema) => {
return ramda_1.reduce((acc, item) => ({
...acc,
[item]: {
isValid: true,
errors: [],
},
}), {}, Object.keys(schema));
};
this.resetValidationState = () => {
this._validationState = this.createValidationsState(this._validationSchema);
};
this.forceValidationState = (newValidationState) => {
this._validationState = newValidationState;
};
this.allValid = (state) => {
const keys = Object.keys(state);
const valid = ramda_1.reduce((acc, current) => {
return acc ? utilities_1.isPropertyValid(current, this._validationState) : acc;
}, true, keys);
return valid;
};
this.runAllValidators = (property, state) => {
const runValidator = utilities_1.compose((func) => func(state), utilities_1.prop('validation'));
const bools = ramda_1.map(runValidator, utilities_1.prop(property, this._validationSchema));
const allValidationsValid = utilities_1.all(bools);
const errors = bools.reduce((acc, curr, idx) => {
const errorOf = utilities_1.compose(utilities_1.prop('errorMessage'), utilities_1.prop(idx), utilities_1.prop(property));
return curr ? acc : [...acc, errorOf(this._validationSchema)];
}, []);
return {
[property]: {
isValid: allValidationsValid,
errors: allValidationsValid ? [] : errors,
},
};
};
this.getError = (property) => {
if (property in this._validationSchema) {
const val = utilities_1.compose(ramda_1.head, utilities_1.prop('errors'), utilities_1.prop(property));
return val(this._validationState) ? val(this._validationState) : '';
}
return '';
};
this.getAllErrors = (property) => {
if (property in this._validationSchema) {
const val = utilities_1.compose(utilities_1.prop('errors'), utilities_1.prop(property));
return val(this._validationState);
}
return [];
};
this.getFieldValid = (property, vState = this._validationState) => {
if (property in this._validationSchema) {
return utilities_1.isPropertyValid(property, vState);
}
return true;
};
this.validate = (property, state) => {
if (property in this._validationSchema) {
const validations = this.runAllValidators(property, state);
this._validationState = {
...this._validationState,
...validations,
};
return utilities_1.isPropertyValid(property, validations);
}
return true;
};
this.validateAll = (state, props) => {
const newState = ramda_1.reduce((acc, property) => {
return { ...acc, ...this.runAllValidators(property, state) };
}, {}, props !== null && props !== void 0 ? props : Object.keys(this._validationSchema));
this._validationState = newState;
return this.allValid(newState);
};
this.validateCustom = (customValidations) => {
const zip = ramda_1.converge(this.runAllValidators, [
utilities_1.prop('key'),
utilities_1.prop('value'),
utilities_1.prop('state'),
]);
const state = ramda_1.reduce((acc, current) => {
return {
...acc,
...zip(current),
};
}, {}, customValidations);
this._validationState = state;
return this.allValid(state);
};
this.validateIfTrue = (property, state) => {
if (property in this._validationSchema) {
const validations = this.runAllValidators(property, state);
if (utilities_1.isPropertyValid(property, validations)) {
const updated = { ...this._validationState, ...validations };
this._validationState = updated;
}
return utilities_1.isPropertyValid(property, validations);
}
return true;
};
this.validateOnBlur = (state) => {
return (event) => {
const { value, name } = event.target;
this.validate(name, { ...state, [name]: value });
};
};
this.validateOnChange = (onChange, state) => {
return (event) => {
const { value, name } = event.target;
this.validateIfTrue(name, { ...state, [name]: value });
return onChange(event);
};
};
this._validationSchema = props;
this._validationState = this.createValidationsState(props);
}
get isValid() {
return this.allValid(this._validationState);
}
get validationErrors() {
const props = Object.keys(this._validationState);
const errors = ramda_1.reduce((acc, curr) => {
const err = this.getError(curr);
return err ? [...acc, err] : acc;
}, [], props);
return errors;
}
get validationState() {
return this._validationState;
}
}
exports.Validation = Validation;
//# sourceMappingURL=validation.js.map
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/validations/validation.ts"],"names":[],"mappings":"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"}
import { renderHook, act } from '@testing-library/react-hooks';
import { useValidation } from '../';
import { ValidationSchema, ValidationState } from '../types';
type TestSchema = {
name: string;
age: number;
dingo: boolean;
agreement: boolean;
};
const schema: ValidationSchema<TestSchema> = {
name: [
{
error: 'Name is required.',
validation: (state: TestSchema) => state.name.length > 0,
},
{
error: 'Cannot be bob.',
validation: (state: TestSchema) => state.name !== 'bob',
},
{
error: 'Must be dingo.',
validation: (state: TestSchema) => {
return state.dingo ? state.name === 'dingo' : true;
},
},
],
age: [
{
error: 'Must be 18',
validation: (state: TestSchema) => state.age >= 18,
},
],
agreement: [
{
error: 'Must accept terms.',
validation: ({ agreement }) => Boolean(agreement),
},
],
};
const mockValidationState: ValidationState = {
name: {
isValid: true,
errors: [],
},
age: {
isValid: true,
errors: [],
},
agreement: {
isValid: true,
errors: [],
},
};
const defaultState = {
name: 'jack',
dingo: false,
age: 42,
agreement: true,
};
const failingState = {
...defaultState,
name: 'bob',
age: 15,
};
describe('useValidation tests', () => {
it('should be defined', () => {
expect(useValidation).toBeDefined();
});
it('renders the hook correctly and checks types', () => {
const { result } = renderHook(() => useValidation(schema));
expect(typeof result.current.getError).toBe('function');
expect(typeof result.current.getFieldValid).toBe('function');
expect(typeof result.current.isValid).toBe('boolean');
expect(typeof result.current.validate).toBe('function');
expect(typeof result.current.validateAll).toBe('function');
expect(typeof result.current.validateAllIfTrue).toBe('function');
expect(typeof result.current.validateIfTrue).toBe('function');
expect(typeof result.current.validateOnBlur).toBe('function');
expect(typeof result.current.validateOnChange).toBe('function');
expect(typeof result.current.resetValidationState).toBe('function');
expect(typeof result.current.setValidationState).toBe('function');
expect(Array.isArray(result.current.validationErrors)).toBe(true);
expect(typeof result.current.validationState).toBe('object');
});
it('returns all functions and read-only objects defined by hook', () => {
const { result } = renderHook(() => useValidation(schema));
expect(result.current.validationState).toStrictEqual(mockValidationState);
expect(Object.keys(result.current)).toStrictEqual([
'getAllErrors',
'getError',
'getFieldValid',
'isValid',
'resetValidationState',
'setValidationState',
'validate',
'validateAll',
'validateAllIfTrue',
'validateIfTrue',
'validateOnBlur',
'validateOnChange',
'validationErrors',
'validationState',
]);
});
describe('createValidationState', () => {
it('crates a validation state when given a schema', () => {
const { result } = renderHook(() => useValidation(schema));
expect(result.current.validationState).toStrictEqual(mockValidationState);
});
it('defaults to an empty object if null or undefined is provided', () => {
const { result } = renderHook(() => useValidation(null as any));
expect(result.current.validationState).toStrictEqual({});
});
});
describe('getError', () => {
it('returns empty string by default', () => {
const { result } = renderHook(() => useValidation(schema));
const output = result.current.getError('name');
expect(output).toBe('');
});
it('returns empty string if the property does not exist', () => {
const { result } = renderHook(() => useValidation(schema));
const output = result.current.getError('balls' as keyof TestSchema);
expect(output).toBe('');
});
it('retrieves an error message', () => {
const { result } = renderHook(() => useValidation(schema));
act(() => {
result.current.validate('name', { name: '' } as any);
});
const output = result.current.getError('name');
expect(output).toBe('Name is required.');
});
});
describe('getAllErrors', () => {
it('returns empty array by default', () => {
const { result } = renderHook(() => useValidation(schema));
const output = result.current.getAllErrors('name');
expect(output).toStrictEqual([]);
});
it('returns empty array if the property does not exist', () => {
const { result } = renderHook(() => useValidation(schema));
const output = result.current.getAllErrors('balls' as keyof TestSchema);
expect(output).toStrictEqual([]);
});
it('retrieves array of all error messages', () => {
const { result } = renderHook(() => useValidation(schema));
const name = 'name';
const state = {
...defaultState,
name: '',
};
act(() => {
result.current.validate(name, state);
});
const output = result.current.getAllErrors('name');
expect(output).toStrictEqual(['Name is required.']);
});
});
describe('getFieldValid', () => {
it('returns true by default', () => {
const { result } = renderHook(() => useValidation(schema));
const output = result.current.getFieldValid('name');
expect(output).toBe(true);
});
it('returns true if the property does not exist', () => {
const { result } = renderHook(() => useValidation(schema));
const output = result.current.getFieldValid('balls' as keyof TestSchema);
expect(output).toBe(true);
});
it('retrieves an invalid state', () => {
const { result } = renderHook(() => useValidation(schema));
const name = 'name';
const state = {
...defaultState,
name: '',
};
act(() => {
result.current.validate(name, state);
});
const output = result.current.getFieldValid('name');
expect(output).toBe(false);
});
});
describe('isValid', () => {
it('returns true by default', () => {
const { result } = renderHook(() => useValidation(schema));
const output = result.current.isValid;
expect(output).toBe(true);
});
it('changes to false after a validation fails', () => {
const { result } = renderHook(() => useValidation(schema));
const name = 'name';
const state = {
...defaultState,
name: 'bob',
};
act(() => {
result.current.validate(name, state);
});
const output = result.current.isValid;
expect(output).toBe(false);
});
it('changes to true after a failed validation passes', () => {
const { result } = renderHook(() => useValidation(schema));
const name = 'name';
const state = {
...defaultState,
name: 'bob',
};
const state2 = {
...defaultState,
name: 'bob ross',
};
act(() => {
result.current.validate(name, state);
result.current.validate(name, state2);
});
const output = result.current.isValid;
expect(output).toBe(true);
});
});
describe('validate', () => {
it('returns a boolean if key exists', () => {
const { result } = renderHook(() => useValidation(schema));
let output: any;
const name = 'name';
const state = {
...defaultState,
name: 'bob',
};
act(() => {
output = result.current.validate(name, state);
});
expect(typeof output).toBe('boolean');
});
it('returns true if key does not exist', () => {
const { result } = renderHook(() => useValidation(schema));
const name = 'balls' as keyof TestSchema;
const state = {
...defaultState,
name: 'bob',
};
let output: any;
act(() => {
output = result.current.validate(name, state);
});
expect(output).toBe(true);
});
it('updates the validationState when validation fails', () => {
const { result } = renderHook(() => useValidation(schema));
const validationState = {
...mockValidationState,
name: {
isValid: false,
errors: ['Must be dingo.'],
},
};
const name = 'name';
const state = {
...defaultState,
name: 'chuck',
dingo: true,
};
act(() => {
result.current.validate(name, state);
});
expect(result.current.isValid).toBe(false);
expect(result.current.validationState).toStrictEqual(validationState);
});
});
describe('validateAll', () => {
it('returns a boolean', () => {
const { result } = renderHook(() => useValidation(schema));
let output: any;
act(() => {
output = result.current.validateAll(defaultState);
});
expect(typeof output).toBe('boolean');
});
it('returns true if validations pass', () => {
const { result } = renderHook(() => useValidation(schema));
let output: any;
act(() => {
output = result.current.validateAll(defaultState);
});
expect(output).toBe(true);
});
it('returns false if any validation fails', () => {
const { result } = renderHook(() => useValidation(schema));
act(() => {
const output = result.current.validateAll(failingState);
expect(output).toBe(false);
});
});
it('returns all failing validations', () => {
const { result } = renderHook(() => useValidation(schema));
act(() => {
result.current.validateAll(failingState);
});
expect(result.current.validationState).toStrictEqual({
name: {
errors: ['Cannot be bob.'],
isValid: false,
},
age: {
errors: ['Must be 18'],
isValid: false,
},
agreement: {
errors: [],
isValid: true,
},
});
});
it('handles nested validation reductions', () => {
const data = [defaultState, defaultState, defaultState];
const { result } = renderHook(() => useValidation(schema));
let output: boolean[];
act(() => {
output = data.map((s) => result.current.validateAll(s));
expect(output).toStrictEqual([true, true, true]);
});
});
it('validates a subsection of keys', () => {
const { result } = renderHook(() => useValidation(schema));
act(() => {
result.current.validateAll(failingState);
});
expect(result.current.getError('age')).toBe('Must be 18');
act(() => {
result.current.validateAll(failingState, ['name']);
});
expect(result.current.getError('age')).toBe('Must be 18');
});
it('handles missing properties', () => {
const wonkySchema = {
...schema,
canSave: [
{
error: 'you cannot save',
validation: (state: any) => !!state.name,
},
],
};
const { result } = renderHook(() => useValidation(wonkySchema));
act(() => {
result.current.validateAll(failingState);
});
expect(result.current.getError('canSave')).toBe('');
});
});
describe('validateAllIfTrue', () => {
it('returns a boolean', () => {
const { result } = renderHook(() => useValidation(schema));
let output: any;
act(() => {
output = result.current.validateAllIfTrue(defaultState);
});
expect(typeof output).toBe('boolean');
});
it('returns true if validations pass', () => {
const { result } = renderHook(() => useValidation(schema));
let output: any;
act(() => {
output = result.current.validateAllIfTrue(defaultState);
});
expect(output).toBe(true);
});
it('ignores failing validations', () => {
const { result } = renderHook(() => useValidation(schema));
act(() => {
const output = result.current.validateAllIfTrue(failingState);
expect(output).toBe(true);
});
});
it('handles nested validation reductions', () => {
const data = [defaultState, defaultState, defaultState];
const { result } = renderHook(() => useValidation(schema));
let output: boolean[];
act(() => {
output = data.map((s) => result.current.validateAllIfTrue(s));
expect(output).toStrictEqual([true, true, true]);
});
});
it('validates a subsection of keys', () => {
const { result } = renderHook(() => useValidation(schema));
act(() => {
result.current.validateAllIfTrue(failingState);
});
expect(result.current.getError('age')).toBe('');
act(() => {
result.current.validateAllIfTrue(failingState, ['name']);
});
expect(result.current.getError('age')).toBe('');
});
it('handles missing properties', () => {
const wonkySchema = {
...schema,
canSave: [
{
error: 'you cannot save',
validation: (state: any) => !!state.name,
},
],
};
const { result } = renderHook(() => useValidation(wonkySchema));
act(() => {
result.current.validateAllIfTrue(failingState);
});
expect(result.current.getError('canSave')).toBe('');
});
});
describe('validateIfTrue', () => {
it('returns a boolean if key exists', () => {
const { result } = renderHook(() => useValidation(schema));
let output: any;
const name = 'name';
const state = {
...defaultState,
name: 'bob',
};
act(() => {
output = result.current.validateIfTrue(name, state);
});
expect(typeof output).toBe('boolean');
});
it('returns true if key does not exist', () => {
const { result } = renderHook(() => useValidation(schema));
const name = 'balls' as keyof TestSchema;
const state = {
...defaultState,
name: 'bob',
};
let output: any;
act(() => {
output = result.current.validateIfTrue(name, state);
});
expect(output).toBe(true);
});
it('updates the validationState when validation fails', () => {
const { result } = renderHook(() => useValidation(schema));
const validationState = {
...mockValidationState,
};
const name = 'name';
const state = {
...defaultState,
name: 'chuck',
dingo: true,
};
act(() => {
result.current.validateIfTrue(name, state);
});
expect(result.current.isValid).toBe(true);
expect(result.current.validationState).toStrictEqual(validationState);
});
it('updates the validationState when an invalid validation succeeds', () => {
const { result } = renderHook(() => useValidation(schema));
const state = {
...defaultState,
name: 'bob',
};
const state2 = {
...defaultState,
name: 'jack',
};
const validationState = {
...mockValidationState,
};
act(() => {
result.current.validate('name', state);
});
expect(result.current.isValid).toBe(false);
act(() => {
result.current.validateIfTrue('name', state2);
});
expect(result.current.isValid).toBe(true);
expect(result.current.validationState).toStrictEqual(validationState);
});
});
describe('validateOnBlur', () => {
it('returns a new function', () => {
const { result } = renderHook(() => useValidation(schema));
const state = defaultState;
const handleBlur = result.current.validateOnBlur(state);
expect(typeof handleBlur).toBe('function');
});
it('updates the valdiation state when called', () => {
const { result } = renderHook(() => useValidation(schema));
const state = defaultState;
const handleBlur = result.current.validateOnBlur(state);
const event = {
target: {
name: 'name',
value: 'bob',
dispatchEvent: new Event('blur'),
},
};
act(() => {
handleBlur(event as any);
});
expect(result.current.isValid).toBe(false);
});
});
describe('validateOnChange', () => {
it('returns a new function', () => {
const { result } = renderHook(() => useValidation(schema));
const state = defaultState;
const onChange = (event: any) => 'bob ross';
const handleChange = result.current.validateOnChange(onChange, state);
expect(typeof handleChange).toBe('function');
});
it('updates the valdiation state if true and returns event', () => {
const { result } = renderHook(() => useValidation(schema));
const state = {
...defaultState,
name: 'bob',
};
act(() => {
result.current.validate('name', state);
});
expect(result.current.isValid).toBe(false);
const onChange = () => 'bob ross';
const handleChange = result.current.validateOnChange(onChange, state);
const event = {
target: {
name: 'name',
value: 'jack',
dispatchEvent: new Event('change'),
},
};
let output: any;
act(() => {
output = handleChange(event as any);
});
expect(result.current.isValid).toBe(true);
expect(output).toBe('bob ross');
});
it('updates checked properties if true and returns event', () => {
const { result } = renderHook(() => useValidation(schema));
const state = {
...defaultState,
agreement: false,
};
act(() => {
result.current.validate('agreement', state);
});
expect(result.current.isValid).toBe(false);
const onChange = () => true;
const handleChange = result.current.validateOnChange(onChange, state);
const event = {
target: {
name: 'agreement',
checked: true,
dispatchEvent: new Event('change'),
type: 'checkbox',
},
};
let output: any;
act(() => {
output = handleChange(event as any);
});
expect(result.current.isValid).toBe(true);
expect(output).toBe(true);
});
});
describe('resetValidationState', () => {
it('resets the validation state', () => {
const { result } = renderHook(() => useValidation(schema));
const state = {
...defaultState,
name: 'bob',
};
act(() => {
result.current.validate('name', state);
result.current.resetValidationState();
});
expect(result.current.isValid).toBe(true);
});
});
describe('validationErrors', () => {
it('starts as an empty array', () => {
const { result } = renderHook(() => useValidation(schema));
expect(result.current.validationErrors).toStrictEqual([]);
});
it('adds validation errors when validation state is invalid', () => {
const { result } = renderHook(() => useValidation(schema));
const state = {
...defaultState,
name: 'bob',
};
act(() => {
result.current.validate('name', state);
});
expect(result.current.validationErrors).toStrictEqual(['Cannot be bob.']);
});
it('removes validation errors when validation state is valid', () => {
const { result } = renderHook(() => useValidation(schema));
const state = {
...defaultState,
name: 'bob',
};
const state2 = {
...defaultState,
name: 'jack',
};
act(() => {
result.current.validate('name', state);
result.current.validate('name', state2);
});
expect(result.current.validationErrors).toStrictEqual([]);
});
});
describe('forceValidationState', () => {
it('overrides the existing validation state with a new one', () => {
const { result: v1 } = renderHook(() => useValidation(schema));
const { result: v2 } = renderHook(() => useValidation(schema));
act(() => {
v1.current.validateAll(failingState);
});
act(() => {
v2.current.setValidationState(v1.current.validationState);
});
expect(v1.current.validationState).toStrictEqual(
v2.current.validationState,
);
});
});
});
export type GetAllErrors<S> = (property: keyof S) => string[];
export type GetError<S> = (property: keyof S) => string;
export type GetFieldValid<S> = (property: keyof S) => boolean;
export type IsValid = boolean;
export type ResetValidationState = () => void;
export type SetValidationState = (validationState: ValidationState) => void;
export type Validate<S> = (property: keyof S, value: S) => boolean;
export type ValidateAll<S> = (value: S, keys?: (keyof S)[]) => boolean;
export type ValidateAllIfTrue<S> = (value: S, keys?: (keyof S)[]) => boolean;
export type ValidateIfTrue<S> = (property: keyof S, value: S) => boolean;
export type ValidateOnBlur<S> = (value: S) => (event: any) => any;
export type ValidateOnChange<S> = (
onChange: (event: any) => any,
value: S,
) => (event: any) => any;
export type ValidationFunction<S> = (value: S) => boolean;
export interface ValidationObject<S> {
getAllErrors: GetAllErrors<S>;
getError: GetError<S>;
getFieldValid: GetFieldValid<S>;
isValid: boolean;
resetValidationState: ResetValidationState;
setValidationState: SetValidationState;
validate: Validate<S>;
validateAll: ValidateAll<S>;
validateAllIfTrue: ValidateAllIfTrue<S>;
validateIfTrue: ValidateIfTrue<S>;
validateOnBlur: ValidateOnBlur<S>;
validateOnChange: ValidateOnChange<S>;
validationErrors: string[];
validationState: ValidationState;
}
export interface ValidationProps<S> {
error: string;
validation: ValidationFunction<S>;
}
export interface ValidationSchema<S> {
[key: string]: ValidationProps<S>[];
}
export interface ValidationState {
[key: string]: {
isValid: boolean;
errors: string[];
};
}