UNPKG

validation-box

Version:

The only validation library - with flexible regex - you need.

297 lines (293 loc) 9.43 kB
"use strict"; // src/helpers/index.ts var containsBannedWords = (value, bannedWords) => { if (!bannedWords || bannedWords.length === 0) return false; return bannedWords.some( (word) => value.toLowerCase().includes(word.toLowerCase()) ); }; // src/validators/generics.ts var validateUsername = (username, options = {}) => { const errors = []; const min = options.min ?? 3; const max = options.max ?? 20; const specialChars = options.allowSpecialChars ?? "_"; if (username.length < min) { errors.push(options.messages?.min || `Username must be at least ${min} characters`); } if (username.length > max) { errors.push(options.messages?.max || `Username must be at most ${max} characters`); } if (containsBannedWords(username, options.bannedWords)) { errors.push(options.messages?.bannedWords || "Username contains banned words"); } if (/^\d+$/.test(username)) { errors.push(options.messages?.onlyNumbers || "Username cannot contain only numbers"); } const regex = new RegExp(`^[a-zA-Z0-9${specialChars}]+$`); if (!regex.test(username)) { errors.push(options.messages?.invalidFormat || `Username can only contain letters, numbers and ${specialChars}`); } return { valid: errors.length === 0, errors: errors.length > 0 ? errors : void 0 }; }; var validateUser = (user, options = {}) => { const errors = []; const min = options.min ?? 3; const max = options.max ?? 30; const specialChars = options.allowSpecialChars ?? "''\\s"; if (user.length < min) { errors.push(options.messages?.min || `Name must be at least ${min} characters`); } if (user.length > max) { errors.push(options.messages?.max || `Name must be at most ${max} characters`); } if (containsBannedWords(user, options.bannedWords)) { errors.push(options.messages?.bannedWords || "Name contains banned words"); } if (/^\s*$/.test(user)) { errors.push(options.messages?.emptySpace || "Name cannot be empty or contain only spaces"); } const regex = new RegExp(`^[a-zA-Z\xC0-\xD6\xD8-\xF6\xF8-\xFF${specialChars}]+$`); if (!regex.test(user)) { errors.push(options.messages?.invalidFormat || `Name can only contain letters and ${specialChars}`); } return { valid: errors.length === 0, errors: errors.length > 0 ? errors : void 0 }; }; var validateEmail = (email, options = {}) => { const errors = []; const emailRegex = /^[a-zA-Z0-9._%+-]+@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})$/; const match = email.match(emailRegex); if (!match) { errors.push(options.messages?.invalidFormat || "Invalid email format"); } else if (options.allowedDomains && !options.allowedDomains.includes(match[1])) { errors.push(options.messages?.allowedDomains || `Email domain must be one of: ${options.allowedDomains.join(", ")}`); } return { valid: errors.length === 0, errors: errors.length > 0 ? errors : void 0 }; }; var validatePassword = (password, options = {}) => { const errors = []; const min = options.min ?? 8; const max = options.max ?? 100; const specialChars = options.allowSpecialChars ?? "!@#$%^&*()_+"; if (password.length < min) { errors.push(options.messages?.min || `Password must be at least ${min} characters`); } if (password.length > max) { errors.push(options.messages?.max || `Password must be at most ${max} characters`); } if (containsBannedWords(password, options.bannedWords)) { errors.push(options.messages?.bannedWords || "Password contains banned words"); } const regex = new RegExp( `^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)(?=.*[${specialChars}])[A-Za-z\\d${specialChars}]+$` ); if (!regex.test(password)) { errors.push(options.messages?.invalidFormat || "Password must contain at least one uppercase letter, one lowercase letter, one number and one special character"); } return { valid: errors.length === 0, errors: errors.length > 0 ? errors : void 0 }; }; var validateAge = (age, options = {}) => { const errors = []; const min = options.min ?? 18; const max = options.max ?? 120; if (!Number.isInteger(age)) { errors.push(options.messages?.invalidFormat || "Age must be an integer"); } if (age < min) { errors.push(options.messages?.min || `Age must be at least ${min} years`); } if (age > max) { errors.push(options.messages?.max || `Age must be at most ${max} years`); } return { valid: errors.length === 0, errors: errors.length > 0 ? errors : void 0 }; }; // src/schemas/index.ts var vboxSchema = class _vboxSchema { rules; validateAll; showErrors; constructor(rules, options) { this.rules = rules; this.validateAll = options?.validateAll ?? false; this.showErrors = options?.showErrors ?? true; } transformValue(value, transforms) { if (!transforms) return value; return transforms.reduce((acc, transform) => transform(acc), value); } validate(data) { const validatedData = {}; const errors = {}; let isValid = true; for (const field in this.rules) { const rule = this.rules[field]; const value = data[field]; const options = rule.options || {}; if (options.required && (value === void 0 || value === null || value === "")) { isValid = false; const message = options.messages?.required || `${field} is required`; errors[field] = [message]; if (!this.validateAll) break; continue; } if (!options.required && (value === void 0 || value === null || value === "")) { continue; } const transformedValue = this.transformValue(value, rule.transform); const validation = rule.fn(transformedValue, options); if (validation.valid) { validatedData[field] = transformedValue; } else { isValid = false; const errorMessages = validation.errors || []; errors[field] = errorMessages; if (!this.validateAll) break; } } return { success: isValid, data: isValid ? validatedData : void 0, errors: !isValid && this.showErrors ? errors : void 0 }; } // Method to add custom validation rule addRule(field, rule) { this.rules[field] = rule; return this; } // Method to extend schema with another schema extend(schema) { return new _vboxSchema({ ...this.rules, ...schema["rules"] }); } // Method to resolve validation for form data resolve(data, returnAllErrors = false) { const result = this.validate(data); return { values: result.success ? data : {}, errors: result.errors ? Object.keys(result.errors).reduce((acc, key) => { const errorMessages = result.errors?.[key] || []; acc[key] = { type: "manual", messages: returnAllErrors ? errorMessages : [errorMessages[0]] }; return acc; }, {}) : {} }; } }; var validator = { username: (options) => ({ fn: validateUsername, options }), user: (options) => ({ fn: validateUser, options }), email: (options) => ({ fn: validateEmail, options }), password: (options) => ({ fn: validatePassword, options }), age: (options) => ({ fn: validateAge, options }) }; // src/manual/schema.ts var userSchema = new vboxSchema( { username: validator.username({ required: true, min: 5, messages: { required: "Username is required", min: "Username must be at least 5 characters" } }), email: validator.email({ required: true, allowedDomains: ["gmail.com"], messages: { required: "Email is required", domain: "Only Gmail addresses are allowed" } }) } // { // validateAll: true, // showErrors: true // } ); var testData = [ { input: { username: "admin", email: "user@gmail.com", password: "Secure@12345678901234" } // ❌ Username "admin" is banned }, { input: { username: "test_123", email: "example@outlook.com", password: "Strong!P@ss4567890" } // ✅ All valid }, { input: { username: "valid_user", email: "test@hotmail.com", password: "Valid@123" } // ❌ Invalid email domain }, { input: { username: "ab", email: "test@gmail.com", password: "short" } // ❌ Username too short, weak password } ]; console.log("\n\u{1F4CC} Running Schema Tests...\n"); var passedTests = 0; var totalTests = testData.length; testData.forEach(({ input }, index) => { const result = userSchema.validate(input); console.log(`\u{1F539} Test ${index + 1}:`); console.log("\u{1F538} Input:", JSON.stringify(input, null, 2)); console.log("\u{1F538} Result:", JSON.stringify(result, null, 2)); const expectedSuccess = Object.values(result.errors || {}).length === 0; const expected = expectedSuccess ? { success: true, data: input } : { success: false, errors: result.errors }; console.log("\u{1F538} Expected:", JSON.stringify(expected, null, 2)); const testPassed = JSON.stringify(result) === JSON.stringify(expected); if (testPassed) passedTests++; console.log(testPassed ? "\u2705 Test Passed!\n" : "\u274C Test Failed!\n"); }); console.log("\u{1F4CA} Test Summary"); console.log(`\u2705 Passed: ${passedTests}/${totalTests}`); console.log(`\u274C Failed: ${totalTests - passedTests}/${totalTests} `); //# sourceMappingURL=schema.js.map