UNPKG

@steveesamson/microform

Version:

`microform` is a tiny library for managing forms in `svelte/sveltekit`.

178 lines (177 loc) 7.56 kB
import { makeName, isValidFileSize } from './utils.js'; const regexes = { number: /^[-+]?[0-9]+(\.[0-9]+)?$/g, alpha: /^[A-Z\s]+$/gi, alphanum: /^[A-Z]+[A-Z0-9]+$/gi, integer: /^[-+]?\d+$/g, email: /^[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}$/gi, url: /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i, ip: /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/g }; export const IS_REQUIRED = 'required'; export const IS_EMAIL = 'email'; export const IS_URL = 'url'; export const IS_IP = 'ip'; export const IS_INTEGER = 'integer'; export const IS_NUMBER = 'number'; export const IS_ALPHA = 'alpha'; export const IS_ALPHANUM = 'alphanum'; export const IS_MIN_LEN = 'minlen'; export const IS_MAX_LEN = 'maxlen'; export const IS_LEN = 'len'; export const IS_MIN = 'min'; export const IS_MAX = 'max'; export const IT_MATCHES = 'match'; export const IS_FILE_SIZE_MB = 'file-size-mb'; const getDefaultValidators = () => { const validators = { [IS_REQUIRED]: ({ label, value }) => { if (!value || (Array.isArray(value) && !value.length)) { return `${label} is mandatory.`; } return ''; }, [IS_EMAIL]: ({ value, label }) => { return !!value && !value.match(regexes['email']) ? `${label} should be a valid email.` : ''; }, [IS_URL]: ({ value, label }) => { return !!value && !value.match(regexes['url']) ? `${label} should be a valid URL.` : ''; }, [IS_IP]: ({ value, label }) => { return !!value && !value.match(regexes['ip']) ? `${label} should be a valid IP.` : ''; }, [IS_INTEGER]: ({ value, label }) => { return !!value && !value.match(regexes['integer']) ? `${label} must be an integer number.` : ''; }, [IS_NUMBER]: ({ value, label }) => { return !!value && !value.match(regexes['number']) ? `${label} must be a number.` : ''; }, [IS_ALPHA]: ({ value, label }) => { return !!value && !value.match(regexes['alpha']) ? `${label} should be a string of alphabets.` : ''; }, [IS_ALPHANUM]: ({ value, label }) => { return !!value && !value.match(regexes['alphanum']) ? `${label} should be a string of alphanumerics starting with alphabets.` : ''; }, [IS_MIN_LEN]: ({ value, label, parts }) => { if (value) { if (!parts || parts.length < 2) { return `${label}: min-length validation requires minimum length.`; } const extra = parts[1].trim(); return value.length >= parseInt(parts[1], 10) ? '' : `${label} must be at least ${extra} characters long.`; } return ''; }, [IS_MAX_LEN]: ({ value, label, parts }) => { if (value) { if (!parts || parts.length < 2) { return `${label}: max-length validation requires maximum length.`; } const extra = parts[1].trim(); return value.length <= parseInt(parts[1], 10) ? '' : `${label} must be at most ${extra} characters long.`; } return ''; }, [IS_LEN]: ({ value, label, parts }) => { if (value) { if (!parts || parts.length < 2) { return `${label}: length validation requires length.`; } const extra = parts[1].trim(); return value.length === parseInt(parts[1], 10) ? '' : `${label} must exactly be ${extra} characters long.`; } return ''; }, [IS_MAX]: ({ value, label, parts }) => { if (value) { if (!parts || parts.length < 2) { return `${label}: max validation requires the maximum value.`; } const extra = parts[1].trim(); return parseInt(value, 10) <= parseInt(parts[1], 10) ? '' : `${label} must not be greater than ${extra}.`; } return ''; }, [IS_MIN]: ({ value, label, parts }) => { if (value) { if (!parts || parts.length < 2) { return `${label}: min validation requires the minimum value.`; } const extra = parts[1].trim(); return parseInt(value, 10) >= parseInt(parts[1], 10) ? '' : `${label} must not be less than ${extra}.`; } return ''; }, [IT_MATCHES]: ({ values, value, label, parts }) => { if (value) { if (!parts || parts.length < 2) { return `${label}: match validation requires id of field to match`; } const partyName = parts[1].trim(); const partyValue = values[partyName]; return value === partyValue ? '' : `${label} does not match ${makeName(partyName)}.`; } return ''; }, [IS_FILE_SIZE_MB]: ({ value, node, label, parts }) => { if (value) { if (!parts || parts.length < 2) { return `${label}: max file size in MB validation requires maximum file size of mb value.`; } const extra = parts[1].trim(); return isValidFileSize(node, parseInt(extra, 10)); } return ''; } }; return validators; }; export const useValidator = (errors, values, validators = getDefaultValidators()) => { const setError = (name, error) => { errors[name] = error ?? ''; }; return { validate: async ({ name, value, validations = [], node = undefined }) => { if (validations.length) { const _validations = validations.includes('required') ? ['required', ...validations.filter((val) => val !== 'required')] : [...validations]; for (let i = 0; i < _validations.length; ++i) { const validation = _validations[i], parts = validation.split(':'), type = parts[0].trim(); const validator = validators[type]; if (!validator) return; const error = validator({ name, label: makeName(name), value, values, node, parts }); setError(name, error ? error : ''); if (error) { break; } } } }, validators }; };