envoc-form
Version:
Envoc form components
98 lines (85 loc) • 3.17 kB
text/typescript
import { ValidationFunction } from './ValidationFunction';
export const required = (value: any) =>
Array.isArray(value)
? value.length > 0
? undefined
: 'Required'
: value || value === false || value === 0
? undefined
: 'Required';
/** Asserts that the value is a certain number of characters. numbers are coerced to a string */
export const length =
(len: number) => (value: string | number | undefined | null) => {
const hasError = getLengthOfValue(value) !== len;
return !hasError ? undefined : `Length must be ${len}`;
};
export const integer = (val: string | number | undefined | null) => {
if (!val) {
return undefined;
}
if (!Number.isInteger(typeof val === 'number' ? val : parseFloat(val))) {
return 'Must be a whole number';
}
};
export const maxLength =
(len: number) => (value: string | number | undefined | null) => {
const hasError = getLengthOfValue(value) > len;
return !hasError ? undefined : `Maximum length ${len} exceeded`;
};
export const maxCount =
(count: number) => (value: { isDeleted?: boolean }[] | undefined | null) => {
const hasError =
!!value && value.filter((x) => !x.isDeleted).length > count;
return !hasError ? undefined : `Should not have more than ${count}`;
};
export const minCount =
(count: number) => (value: { isDeleted?: boolean }[] | undefined | null) => {
const hasError = !value || value.filter((x) => !x.isDeleted).length < count;
return !hasError ? undefined : `Should have at least ${count}`;
};
export const maxValue = (max: number) => (value: number | undefined | null) => {
const hasError = !!value && value > max;
return !hasError ? undefined : `Maximum value ${max} exceeded`;
};
export const minValue = (min: number) => (value: number | undefined | null) => {
const hasError = !value || value < min;
return !hasError ? undefined : `Minimum value ${min} not met`;
};
/** Validate for a ZIP Code. Accepts formats: ##### and #####-#### */
export const zipCode = (value: string | undefined | null) => {
return value && !/^[0-9]{5}(?:-[0-9]{4})?$/.test(value)
? 'Invalid ZIP Code'
: undefined;
};
/** One of the validators provided must be true. */
export const any =
<TValue>(validatorList: ValidationFunction<TValue>[]) =>
(value: TValue) => {
if (validatorList.length === 0 || !value) {
return;
}
return validatorList.reduce(
(isAnyTrue, x) => (isAnyTrue ? isAnyTrue : x(value)),
undefined as string | undefined
);
};
function getLengthOfValue(value: string | number | undefined | null) {
if (value === null) {
return 0;
}
switch (typeof value) {
case 'undefined':
return 0;
case 'string':
return value.length;
case 'number':
// TODO: this seems iffy to me - what if the actual visible value is a fixed length or some special format (e.g. with commas?)
return value.toString().length;
default:
assertUnreachable(value);
return 0;
}
}
function assertUnreachable(x: never) {
return null;
}