UNPKG

@dbs-portal/tool-mock

Version:

API mocking toolkit using MSW for DBS Portal development workflows

358 lines 10.7 kB
/** * Validation utilities for mock data */ /** * Validate data against a schema */ export function validateSchema(data, schema) { const errors = []; const fieldErrors = {}; // Validate each field for (const fieldValidation of schema.fields) { const fieldName = String(fieldValidation.field); const fieldValue = data[fieldValidation.field]; const fieldErrorList = []; // Check required if (fieldValidation.required && (fieldValue === undefined || fieldValue === null || fieldValue === '')) { const message = fieldValidation.requiredMessage || `${fieldName} is required`; fieldErrorList.push(message); errors.push(message); } else if (fieldValue !== undefined && fieldValue !== null) { // Run validation rules for (const rule of fieldValidation.rules) { const result = rule.validate(fieldValue, data); if (result === false) { const message = rule.message || `${fieldName} failed ${rule.name} validation`; fieldErrorList.push(message); errors.push(message); } else if (typeof result === 'string') { fieldErrorList.push(result); errors.push(result); } } } if (fieldErrorList.length > 0) { fieldErrors[fieldName] = fieldErrorList; } } // Run custom validation if (schema.customValidation) { const customErrors = schema.customValidation(data); if (customErrors) { errors.push(...customErrors); } } return { valid: errors.length === 0, errors, fieldErrors: Object.keys(fieldErrors).length > 0 ? fieldErrors : {}, }; } /** * Common validation rules */ export const validationRules = { /** * Email validation rule */ email: () => ({ name: 'email', validate: (value) => { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(value); }, message: 'Must be a valid email address', }), /** * Minimum length validation rule */ minLength: (min) => ({ name: 'minLength', validate: (value) => { return value.length >= min; }, message: `Must be at least ${min} characters long`, }), /** * Maximum length validation rule */ maxLength: (max) => ({ name: 'maxLength', validate: (value) => { return value.length <= max; }, message: `Must be no more than ${max} characters long`, }), /** * Minimum value validation rule */ min: (min) => ({ name: 'min', validate: (value) => { return value >= min; }, message: `Must be at least ${min}`, }), /** * Maximum value validation rule */ max: (max) => ({ name: 'max', validate: (value) => { return value <= max; }, message: `Must be no more than ${max}`, }), /** * Pattern validation rule */ pattern: (pattern, message) => ({ name: 'pattern', validate: (value) => { return pattern.test(value); }, message: message || 'Invalid format', }), /** * URL validation rule */ url: () => ({ name: 'url', validate: (value) => { try { new URL(value); return true; } catch { return false; } }, message: 'Must be a valid URL', }), /** * Phone number validation rule */ phone: () => ({ name: 'phone', validate: (value) => { const phoneRegex = /^[\+]?[1-9][\d]{0,15}$/; return phoneRegex.test(value.replace(/[\s\-\(\)]/g, '')); }, message: 'Must be a valid phone number', }), /** * Date validation rule */ date: () => ({ name: 'date', validate: (value) => { const date = new Date(value); return !isNaN(date.getTime()); }, message: 'Must be a valid date', }), /** * Future date validation rule */ futureDate: () => ({ name: 'futureDate', validate: (value) => { const date = new Date(value); return date > new Date(); }, message: 'Must be a future date', }), /** * Past date validation rule */ pastDate: () => ({ name: 'pastDate', validate: (value) => { const date = new Date(value); return date < new Date(); }, message: 'Must be a past date', }), /** * One of validation rule */ oneOf: (values) => ({ name: 'oneOf', validate: (value) => { return values.includes(value); }, message: `Must be one of: ${values.join(', ')}`, }), /** * Array validation rule */ array: (minLength, maxLength) => ({ name: 'array', validate: (value) => { if (!Array.isArray(value)) return false; if (minLength !== undefined && value.length < minLength) return false; if (maxLength !== undefined && value.length > maxLength) return false; return true; }, message: `Must be an array${minLength !== undefined ? ` with at least ${minLength} items` : ''}${maxLength !== undefined ? ` and no more than ${maxLength} items` : ''}`, }), /** * Object validation rule */ object: () => ({ name: 'object', validate: (value) => { return typeof value === 'object' && value !== null && !Array.isArray(value); }, message: 'Must be an object', }), /** * Number validation rule */ number: () => ({ name: 'number', validate: (value) => { return typeof value === 'number' && !isNaN(value); }, message: 'Must be a number', }), /** * Integer validation rule */ integer: () => ({ name: 'integer', validate: (value) => { return Number.isInteger(value); }, message: 'Must be an integer', }), /** * Boolean validation rule */ boolean: () => ({ name: 'boolean', validate: (value) => { return typeof value === 'boolean'; }, message: 'Must be a boolean', }), /** * String validation rule */ string: () => ({ name: 'string', validate: (value) => { return typeof value === 'string'; }, message: 'Must be a string', }), /** * Custom validation rule */ custom: (validator, message = 'Custom validation failed') => ({ name: 'custom', validate: validator, message, }), }; /** * Create a field validation configuration */ export function createFieldValidation(field, rules, required = false, requiredMessage) { return { field, rules, required, requiredMessage: requiredMessage || `${String(field)} is required`, }; } /** * Create a schema validation configuration */ export function createSchemaValidation(fields, customValidation) { return { fields, customValidation: customValidation || (() => null), }; } /** * Quick validation for common data types */ export const quickValidation = { /** * Validate user data */ user: (data) => { const schema = createSchemaValidation([ createFieldValidation('email', [validationRules.email()], true), createFieldValidation('firstName', [validationRules.minLength(1)], true), createFieldValidation('lastName', [validationRules.minLength(1)], true), createFieldValidation('phone', [validationRules.phone()], false), ]); return validateSchema(data, schema); }, /** * Validate product data */ product: (data) => { const schema = createSchemaValidation([ createFieldValidation('name', [validationRules.minLength(1)], true), createFieldValidation('price', [validationRules.number(), validationRules.min(0)], true), createFieldValidation('description', [validationRules.maxLength(1000)], false), createFieldValidation('category', [validationRules.minLength(1)], true), ]); return validateSchema(data, schema); }, /** * Validate order data */ order: (data) => { const schema = createSchemaValidation([ createFieldValidation('customerId', [validationRules.minLength(1)], true), createFieldValidation('items', [validationRules.array(1)], true), createFieldValidation('total', [validationRules.number(), validationRules.min(0)], true), createFieldValidation('status', [validationRules.oneOf(['pending', 'processing', 'shipped', 'delivered', 'cancelled'])], true), ]); return validateSchema(data, schema); }, /** * Validate address data */ address: (data) => { const schema = createSchemaValidation([ createFieldValidation('street', [validationRules.minLength(1)], true), createFieldValidation('city', [validationRules.minLength(1)], true), createFieldValidation('state', [validationRules.minLength(1)], true), createFieldValidation('zipCode', [validationRules.pattern(/^\d{5}(-\d{4})?$/, 'Invalid ZIP code format')], true), createFieldValidation('country', [validationRules.minLength(2)], true), ]); return validateSchema(data, schema); }, }; /** * Validate and sanitize input data */ export function validateAndSanitize(data, schema, sanitizers) { // First, sanitize the data if sanitizers are provided let sanitizedData = { ...data }; if (sanitizers) { for (const [field, sanitizer] of Object.entries(sanitizers)) { if (sanitizedData[field] !== undefined) { sanitizedData[field] = sanitizer(sanitizedData[field]); } } } // Then validate const validation = validateSchema(sanitizedData, schema); return { valid: validation.valid, data: sanitizedData, errors: validation.errors, }; } //# sourceMappingURL=validation.js.map