workspace-v1/core/modules/utils/validation.util.ts
rckrdmrd 66161b1566 feat: Workspace-v1 complete migration with NEXUS v3.4
Sistema NEXUS v3.4 migrado con:

Estructura principal:
- core/orchestration: Sistema SIMCO + CAPVED (27 directivas, 28 perfiles)
- core/catalog: Catalogo de funcionalidades reutilizables
- shared/knowledge-base: Base de conocimiento compartida
- devtools/scripts: Herramientas de desarrollo
- control-plane/registries: Control de servicios y CI/CD
- orchestration/: Configuracion de orquestacion de agentes

Proyectos incluidos (11):
- gamilit (submodule -> GitHub)
- trading-platform (OrbiquanTIA)
- erp-suite con 5 verticales:
  - erp-core, construccion, vidrio-templado
  - mecanicas-diesel, retail, clinicas
- betting-analytics
- inmobiliaria-analytics
- platform_marketing_content
- pos-micro, erp-basico

Configuracion:
- .gitignore completo para Node.js/Python/Docker
- gamilit como submodule (git@github.com:rckrdmrd/gamilit-workspace.git)
- Sistema de puertos estandarizado (3005-3199)

Generated with NEXUS v3.4 Migration System
EPIC-010: Configuracion Git y Repositorios
2026-01-04 03:37:42 -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;
};