workspace/core/modules/utils/validation.util.ts
rckrdmrd 49155822ae fix: Resolve TypeScript compilation errors across all projects
Platform Marketing Content:
- Add PaginationParams, PaginationMeta, PaginatedResponse interfaces
- Fix JwtAuthGuard import paths (common/guards instead of modules/auth)
- Add missing fields to CRM interfaces (address, keywords, features, benefits)
- Install @nestjs/throttler dependency

ERP Suite - Construccion:
- Create tsconfig.node.json for web frontend
- Add vite-env.d.ts for Vite types
- Fix implicit return errors in Express controllers
- Prefix unused parameters with underscore

ERP Suite - ERP Core:
- Export PoolClient type from database config
- Fix invoice type comparison (customer/supplier vs out_invoice)
- Refactor base.service.ts query handling for proper type inference
- Rename Role type to RoleType to avoid conflict with entity
- Fix ProtectedRoute to use role?.name instead of roles array

ERP Suite - POS Micro:
- Add vite-env.d.ts for Vite types
- Fix Sale property names (discountAmount, changeAmount)
- Export TodaySummary interface from sales service

All projects now pass npm install and npm run build successfully.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 22:35:55 -06:00

329 lines
7.4 KiB
TypeScript

/**
* Validation Utilities - Core Module
*
* Framework-agnostic validation helper functions.
* Can be used in any project (NestJS, Express, Frontend, etc.)
*
* @module @core/utils/validation
* @version 1.0.0
*/
/**
* Check if value is email
*/
export const isEmail = (email: string): boolean => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
/**
* Check if value is UUID (v4)
*/
export const isUUID = (uuid: string): boolean => {
const uuidRegex =
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
return uuidRegex.test(uuid);
};
/**
* Check if value is valid URL
*/
export const isURL = (url: string): boolean => {
try {
new URL(url);
return true;
} catch {
return false;
}
};
/**
* Check if password is strong
* Requirements: 8+ chars, 1 uppercase, 1 lowercase, 1 number, 1 special char
*/
export const isStrongPassword = (password: string): boolean => {
const strongRegex =
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
return strongRegex.test(password);
};
/**
* Get password strength (0-4)
* 0: Very weak, 1: Weak, 2: Fair, 3: Strong, 4: Very strong
*/
export const getPasswordStrength = (password: string): number => {
let strength = 0;
if (password.length >= 8) strength++;
if (password.length >= 12) strength++;
if (/[a-z]/.test(password) && /[A-Z]/.test(password)) strength++;
if (/\d/.test(password)) strength++;
if (/[@$!%*?&#^()_+=[\]{};':"\\|,.<>/?-]/.test(password)) strength++;
return Math.min(strength, 4);
};
/**
* Check if value is phone number (international format)
*/
export const isPhoneNumber = (phone: string): boolean => {
const phoneRegex = /^\+?[1-9]\d{1,14}$/;
return phoneRegex.test(phone.replace(/[\s\-()]/g, ''));
};
/**
* Check if value is numeric
*/
export const isNumeric = (value: string): boolean => {
return !isNaN(Number(value)) && !isNaN(parseFloat(value));
};
/**
* Check if value is integer
*/
export const isInteger = (value: string | number): boolean => {
const num = typeof value === 'string' ? parseFloat(value) : value;
return Number.isInteger(num);
};
/**
* Check if value is alphanumeric
*/
export const isAlphanumeric = (value: string): boolean => {
const alphanumericRegex = /^[a-zA-Z0-9]+$/;
return alphanumericRegex.test(value);
};
/**
* Check if value is alphabetic only
*/
export const isAlphabetic = (value: string): boolean => {
const alphabeticRegex = /^[a-zA-Z]+$/;
return alphabeticRegex.test(value);
};
/**
* Check if value is within range (inclusive)
*/
export const isInRange = (value: number, min: number, max: number): boolean => {
return value >= min && value <= max;
};
/**
* Check if array has minimum length
*/
export const hasMinLength = <T>(array: T[], minLength: number): boolean => {
return array.length >= minLength;
};
/**
* Check if array has maximum length
*/
export const hasMaxLength = <T>(array: T[], maxLength: number): boolean => {
return array.length <= maxLength;
};
/**
* Check if string has minimum length
*/
export const hasMinStringLength = (str: string, minLength: number): boolean => {
return str.length >= minLength;
};
/**
* Check if string has maximum length
*/
export const hasMaxStringLength = (str: string, maxLength: number): boolean => {
return str.length <= maxLength;
};
/**
* Check if value is valid JSON string
*/
export const isValidJSON = (value: string): boolean => {
try {
JSON.parse(value);
return true;
} catch {
return false;
}
};
/**
* Check if value is positive number
*/
export const isPositive = (value: number): boolean => {
return value > 0;
};
/**
* Check if value is non-negative number
*/
export const isNonNegative = (value: number): boolean => {
return value >= 0;
};
/**
* Check if value is negative number
*/
export const isNegative = (value: number): boolean => {
return value < 0;
};
/**
* Check if string matches pattern
*/
export const matchesPattern = (value: string, pattern: RegExp): boolean => {
return pattern.test(value);
};
/**
* Validate required fields in object
*/
export const hasRequiredFields = <T extends object>(
obj: T,
requiredFields: (keyof T)[],
): boolean => {
return requiredFields.every(
(field) => obj[field] !== undefined && obj[field] !== null,
);
};
/**
* Check if value is valid credit card number (Luhn algorithm)
*/
export const isCreditCard = (cardNumber: string): boolean => {
const sanitized = cardNumber.replace(/\D/g, '');
if (sanitized.length < 13 || sanitized.length > 19) return false;
let sum = 0;
let isEven = false;
for (let i = sanitized.length - 1; i >= 0; i--) {
let digit = parseInt(sanitized[i], 10);
if (isEven) {
digit *= 2;
if (digit > 9) digit -= 9;
}
sum += digit;
isEven = !isEven;
}
return sum % 10 === 0;
};
/**
* Check if value is valid IP address (v4)
*/
export const isIPv4 = (ip: string): boolean => {
const ipv4Regex =
/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
return ipv4Regex.test(ip);
};
/**
* Check if value is valid hex color
*/
export const isHexColor = (color: string): boolean => {
const hexColorRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
return hexColorRegex.test(color);
};
/**
* Check if value is valid slug
*/
export const isSlug = (slug: string): boolean => {
const slugRegex = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
return slugRegex.test(slug);
};
/**
* Check if value is valid username
* Requirements: 3-30 chars, alphanumeric + underscore, starts with letter
*/
export const isValidUsername = (username: string): boolean => {
const usernameRegex = /^[a-zA-Z][a-zA-Z0-9_]{2,29}$/;
return usernameRegex.test(username);
};
/**
* Check if object is empty
*/
export const isEmptyObject = (obj: object): boolean => {
return Object.keys(obj).length === 0;
};
/**
* Check if array is empty
*/
export const isEmptyArray = <T>(arr: T[]): boolean => {
return arr.length === 0;
};
/**
* Check if value is null or undefined
*/
export const isNullOrUndefined = (value: unknown): value is null | undefined => {
return value === null || value === undefined;
};
/**
* Check if value is defined (not null and not undefined)
*/
export const isDefined = <T>(value: T | null | undefined): value is T => {
return value !== null && value !== undefined;
};
/**
* Validate Mexican RFC (tax ID)
*/
export const isMexicanRFC = (rfc: string): boolean => {
const rfcRegex =
/^([A-ZÑ&]{3,4})(\d{2})(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([A-Z\d]{2})([A\d])$/;
return rfcRegex.test(rfc.toUpperCase());
};
/**
* Validate Mexican CURP
*/
export const isMexicanCURP = (curp: string): boolean => {
const curpRegex =
/^[A-Z]{4}\d{6}[HM][A-Z]{5}[A-Z\d]\d$/;
return curpRegex.test(curp.toUpperCase());
};
/**
* Validation result type
*/
export interface ValidationResult {
isValid: boolean;
errors: string[];
}
/**
* Create a validator chain
*/
export const createValidator = <T>(value: T): {
validate: (condition: boolean, errorMessage: string) => ReturnType<typeof createValidator<T>>;
result: () => ValidationResult;
} => {
const errors: string[] = [];
const validator = {
validate: (condition: boolean, errorMessage: string) => {
if (!condition) {
errors.push(errorMessage);
}
return validator;
},
result: (): ValidationResult => ({
isValid: errors.length === 0,
errors,
}),
};
return validator;
};