import type { GetValueStringCallback, ValidationItem, ValidationResult, ValidationResultItem, ValidatorFunction } from "./types"; /** * @description check sync validations of value (will ignore async validations) * @param list list of validation * @param value the value you want to check it's validation * @param getValueString function that return value in string */ export function checkValueValidationSync(list: ValidationItem[], value: ValidationValue, getValueString: GetValueStringCallback) { const {syncValidationResult} = checkValueValidation(list,value,getValueString); return syncValidationResult; } /** * @description check validations of value * @param list list of validation * @param value the value you want to check it's validation * @param getValueString function that return value in string */ export async function checkValueValidationAsync(list: ValidationItem[], value: ValidationValue, getValueString: GetValueStringCallback) { const {syncValidationResult:result,asyncList} = checkValueValidation(list,value,getValueString); for(const item of asyncList){ const res = await item; result.isAllValid = result.isAllValid && !!res.isValid; result.validationList.push(res); } return result; } export function checkValueValidation(list: ValidationItem[], value: ValidationValue, getValueString: GetValueStringCallback) { const syncValidationResult: ValidationResult = { validationList: [], isAllValid: true, }; const stackRes = (res:ValidationResultItem)=>{ syncValidationResult.validationList.push(res); if (!res.isValid) { syncValidationResult.isAllValid = false; } }; const deferredList = list.filter(x=>x.defer === true); const earlyList = list.filter(x=>x.defer !==true); const asyncList:Promise>[] = []; for (const validation of earlyList) { const res =checkValidation(value, validation, getValueString); if(res instanceof Promise){ asyncList.push(res); }else{ stackRes(res); } } if(syncValidationResult.isAllValid){ //we only execute defer validation when all non defers were valid for (const validation of deferredList) { const res =checkValidation(value, validation, getValueString); if(res instanceof Promise){ asyncList.push(res); }else{ stackRes(res); } } } // return {syncValidationResult, asyncList}; } /** * @description check single validation item */ export function checkValidation(value: ValidationValue, validation: ValidationItem, getValueString: GetValueStringCallback): Promise> | ValidationResultItem { let testRes: boolean = true; let message = validation.message; if (validation.validator instanceof RegExp) { const text = typeof value == "string" ? value : getValueString(value); testRes = validation.validator.test(text); validation.validator.lastIndex = 0; } if (typeof validation.validator == "function") { const res = checkValidator(validation.validator, value); // if our validator were async we return promise if (res instanceof Promise) { return new Promise>((resolve) => { res.then((promRes) => { resolve({ isValid: promRes.isValid, message: typeof promRes.message == "string"? promRes.message : validation.message, validation }); }); }); } testRes = res.isValid; message = res.message ?? message; } if(validation.validator === undefined){ testRes = false; } if (!testRes) { return { isValid: false, message: message, validation: validation, }; } return { isValid: true, message: "", validation: validation, }; } type checkValidatorFunctionRes = { isValid: boolean, message: string | null } /** * * @param validator validator function * @param value the value you want to send to validator * @returns */ export function checkValidator(validator: ValidatorFunction, value: ValidationValue): Promise | checkValidatorFunctionRes { function createResponse(res: string | boolean): checkValidatorFunctionRes { let message: string | null = null; if (typeof res == "string" && res.length > 0) { message = res; } //if function return string if string was full it mean we must show custom error const isValid = typeof res == "string" ? res.length == 0 : res; return { isValid, message }; } const funcRes = validator(value); if (funcRes instanceof Promise) { return new Promise((resolve) => { funcRes.then((res) => { resolve(createResponse(res)); }); }); } else { return createResponse(funcRes); } }