UNPKG

@resk/core

Version:

An innovative TypeScript framework that empowers developers to build applications with a fully decorator-based architecture for efficient resource management. By combining the power of decorators with a resource-oriented design, DecorRes enhances code cla

1,428 lines 50 kB
import { IValidatorRule, IValidatorValidateOptions, IValidatorRules, IValidatorRuleName, IValidatorRuleFunction, IValidatorSanitizedRules } from "./types"; import { IClassConstructor } from "../types"; /** * # Validator Class * * A comprehensive validation system that provides flexible and powerful validation capabilities * for TypeScript/JavaScript applications. This class supports both synchronous and asynchronous * validation, decorator-based validation for classes, and a rich ecosystem of validation rules. * * ## Key Features * - **Type-Safe Validation**: Full TypeScript support with generic types * - **Decorator Support**: Class property validation using decorators * - **Async Validation**: Support for asynchronous validation rules * - **Internationalization**: Built-in i18n support for error messages * - **Extensible**: Easy to register custom validation rules * - **Rule Composition**: Combine multiple validation rules * * ## Basic Usage * ```typescript * // Register a custom validation rule * Validator.registerRule('CustomRule', ({ value }) => { * return value > 10 || 'Value must be greater than 10'; * }); * * // Validate a single value * const result = await Validator.validate({ * value: 15, * rules: ['Required', 'CustomRule'] * }); * * // Use with decorators * class User { * @IsRequired * @IsEmail * email: string; * * @IsRequired * @MinLength([3]) * name: string; * } * * const userData = { email: 'user@example.com', name: 'John' }; * const validated = await Validator.validateTarget(User, userData); * ``` * * ## Advanced Usage * ```typescript * // Complex validation with context * const validationOptions = { * value: userData, * rules: [ * 'required', * { minLength: [5] }, * async ({ value, context }) => { * const exists = await checkIfUserExists(value); * return !exists || 'User already exists'; * } * ], * context: { userId: 123 } * }; * * try { * const result = await Validator.validate(validationOptions); * console.log('Validation passed!', result); * } catch (error) { * console.error('Validation failed:', error.message); * } * ``` * * @author Resk Framework Team * @since 1.0.0 * @version 2.1.0 * @see {@link https://docs.resk.dev/validation | Validation Documentation} * @public */ export declare class Validator { /** * ## Metadata Storage Key * * Private symbol used to store validation rules in metadata. This ensures * that the validation rules don't conflict with other metadata keys. * * @private * @readonly * @since 1.0.0 */ private static readonly RULES_METADATA_KEY; /** * ## Register Validation Rule * * Registers a new custom validation rule that can be used throughout the application. * This method provides type-safe registration of validation functions with proper * error handling and validation of input parameters. * * ### Type Parameters * - `ParamType` - Array type defining the parameters the rule function accepts * - `Context` - Type of the validation context object passed to the rule * * ### Rule Function Signature * ```typescript * type RuleFunction<ParamType, Context> = (options: { * value: any; * ruleParams: ParamType; * context?: Context; * fieldName?: string; * translatedPropertyName?: string; * }) => boolean | string | Promise<boolean | string>; * ``` * * ### Rule Return Values * - `true` - Validation passed * - `false` - Validation failed (uses default error message) * - `string` - Validation failed with custom error message * - `Promise<boolean|string>` - Async validation * * @example * ```typescript * // Simple synchronous rule * Validator.registerRule('MinValue', ({ value, ruleParams }) => { * const [minValue] = ruleParams; * return value >= minValue || `Value must be at least ${minValue}`; * }); * * // Async rule with database check * Validator.registerRule('UniqueEmail', async ({ value, context }) => { * const exists = await database.user.findByEmail(value); * return !exists || 'Email address is already taken'; * }); * * // Rule with multiple parameters * Validator.registerRule('Between', ({ value, ruleParams }) => { * const [min, max] = ruleParams; * return (value >= min && value <= max) || * `Value must be between ${min} and ${max}`; * }); * * // Rule with context * Validator.registerRule('DifferentFrom', ({ value, ruleParams, context }) => { * const [fieldName] = ruleParams; * const otherValue = context?.data?.[fieldName]; * return value !== otherValue || * `Must be different from ${fieldName}`; * }); * ``` * * @template ParamType - Array type for rule parameters * @template Context - Type for validation context * * @param ruleName - Unique identifier for the validation rule (must be non-empty string) * @param ruleHandler - Function that performs the validation logic * * @throws {Error} When ruleName is not a non-empty string * @throws {Error} When ruleHandler is not a function * * @since 1.0.0 * @see {@link findRegisteredRule} - Find a registered rule * @see {@link getRules} - Get all registered rules * @public */ static registerRule<ParamType extends Array<any> = Array<any>, Context = unknown>(ruleName: IValidatorRuleName, ruleHandler: IValidatorRuleFunction<ParamType, Context>): void; /** * ## Get All Registered Rules * * Retrieves an immutable copy of all currently registered validation rules. * This method returns a shallow copy to prevent external modification of * the internal rules registry while allowing inspection of available rules. * * ### Use Cases * - Debugging: Check what rules are available * - Rule Discovery: List all registered rules for documentation * - Testing: Verify rule registration in unit tests * - Introspection: Build dynamic validation UIs * * @example * ```typescript * // Get all registered rules * const allRules = Validator.getRules(); * console.log('Available rules:', Object.keys(allRules)); * * // Check if a specific rule exists * const hasEmailRule = 'Email' in Validator.getRules(); * * // Get rule function directly (not recommended, use findRegisteredRule instead) * const emailRule = Validator.getRules()['Email']; * ``` * * @returns An immutable copy of all registered validation rules * * @since 1.0.0 * @see {@link registerRule} - Register a new rule * @see {@link findRegisteredRule} - Find a specific rule * @public */ static getRules(): IValidatorRules; /** * ## Get Error Message Separators * * Retrieves the configured separators used for formatting validation error messages. * These separators are internationalized and can be customized through the i18n system. * This method provides a centralized way to get consistent error message formatting. * * ### Separator Types * - `multiple` - Used when joining multiple error messages * - `single` - Used for single error message formatting * * ### Internationalization * The separators are loaded from the i18n translation system under the key * `validator.separators`. This allows different languages to use appropriate * punctuation and formatting conventions. * * @example * ```typescript * // Get current separators * const separators = Validator.getErrorMessageSeparators(); * console.log(separators); // { multiple: ", ", single: ", " } * * // Use separators for custom error formatting * const errors = ['Field is required', 'Must be an email', 'Too short']; * const errorMessage = errors.join(separators.multiple); * console.log(errorMessage); // "Field is required, Must be an email, Too short" * * // Custom error message builder * function buildErrorMessage(fieldName: string, errors: string[]) { * const seps = Validator.getErrorMessageSeparators(); * return `${fieldName}: ${errors.join(seps.multiple)}`; * } * ``` * * @returns Object containing separator strings for error message formatting * @returns returns.multiple - Separator for joining multiple error messages * @returns returns.single - Separator for single error message formatting * * @since 1.0.0 * @see {@link validate} - Uses these separators for error formatting * @see {@link validateTarget} - Also uses these separators * @public */ static getErrorMessageSeparators(): { multiple: string; single: string; }; /** * ## Find Registered Rule * * Locates and returns a specific validation rule by its name. This method provides * type-safe access to registered validation rules with proper error handling for * invalid rule names. Returns undefined if the rule doesn't exist. * * ### Type Safety * This method is fully type-safe and will return the correctly typed rule function * based on the generic parameters provided. The rule function signature will match * the expected parameter and context types. * * @example * ```typescript * // Find a simple rule * const emailRule = Validator.findRegisteredRule('Email'); * if (emailRule) { * const result = await emailRule({ * value: 'test@example.com', * ruleParams: [] * }); * } * * // Find a rule with specific parameter types * const minLengthRule = Validator.findRegisteredRule<[number]>('MinLength'); * if (minLengthRule) { * const result = await minLengthRule({ * value: 'hello', * ruleParams: [5] * }); * } * * // Find a rule with context * interface UserContext { * userId: number; * permissions: string[]; * } * * const permissionRule = Validator.findRegisteredRule<string[], UserContext>('HasPermission'); * if (permissionRule) { * const result = await permissionRule({ * value: 'admin', * ruleParams: ['admin', 'moderator'], * context: { userId: 123, permissions: ['user', 'admin'] } * }); * } * * // Safe rule checking * const unknownRule = Validator.findRegisteredRule('NonExistentRule'); * console.log(unknownRule); // undefined * ``` * * @template ParamType - Array type specifying the rule parameter types * @template Context - Type of the validation context object * * @param ruleName - The name of the rule to find * * @returns The validation rule function if found, undefined otherwise * * @since 1.0.0 * @see {@link registerRule} - Register a new rule * @see {@link getRules} - Get all rules * @public */ static findRegisteredRule<ParamType extends Array<any> = Array<any>, Context = unknown>(ruleName: IValidatorRuleName): IValidatorRuleFunction<ParamType, Context> | undefined; /** * ## Parse and Validate Rules * * Converts various input rule formats into a standardized, executable format while * identifying and reporting any invalid rules. This method handles the complex task * of normalizing different rule input formats into a consistent internal representation. * * ### Supported Input Formats * * #### 1. Function Rules * ```typescript * const functionRule = ({ value }) => value > 0 || 'Must be positive'; * ``` * * #### 2. String Rules * ```typescript * 'Required' // Simple rule * 'MinLength[5]' // Rule with single parameter * 'Between[10,20]' // Rule with multiple parameters * ``` * * #### 3. Object Rules * ```typescript * { Required: [] } // Rule without parameters * { MinLength: [5] } // Rule with parameters * { Between: [10, 20] } // Rule with multiple parameters * ``` * * ### Processing Logic * 1. **Function Detection**: Direct function rules are passed through unchanged * 2. **String Parsing**: Extracts rule names and parameters from bracketed syntax * 3. **Object Processing**: Converts object notation to standardized format * 4. **Validation**: Verifies that all referenced rules are registered * 5. **Error Tracking**: Collects invalid rules for reporting * * @example * ```typescript * // Mixed rule formats * const mixedRules = [ * 'Required', * 'MinLength[3]', * { MaxLength: [50] }, * ({ value }) => value.includes('@') || 'Must contain @', * 'InvalidRule' // This will be reported as invalid * ]; * * const { sanitizedRules, invalidRules } = Validator.parseAndValidateRules(mixedRules); * * console.log('Valid rules:', sanitizedRules.length); // 4 * console.log('Invalid rules:', invalidRules); // ['InvalidRule'] * * // Empty or undefined input * const { sanitizedRules: empty } = Validator.parseAndValidateRules(); * console.log(empty.length); // 0 * * // Complex rule with parameters * const complexRules = [ * 'Between[1,100]', * { CustomRule: ['param1', 'param2'] } * ]; * * const result = Validator.parseAndValidateRules(complexRules); * // Each sanitized rule will have: ruleName, params, ruleFunction, rawRuleName * ``` * * @param inputRules - Array of validation rules in various formats, or undefined * * @returns Object containing processed results * @returns returns.sanitizedRules - Array of standardized, executable rule objects * @returns returns.invalidRules - Array of rules that couldn't be processed (unregistered) * * @since 1.22.0 * @see {@link parseStringRule} - Internal string rule parser * @see {@link parseObjectRules} - Internal object rule parser * @see {@link validate} - Uses this method for rule processing * @public */ static parseAndValidateRules(inputRules?: IValidatorValidateOptions["rules"]): { sanitizedRules: IValidatorSanitizedRules; invalidRules: IValidatorRule[]; }; /** * ## Parse String-Based Validation Rules * * Internal helper method that parses string-format validation rules into standardized * rule objects. Handles both simple rule names and rules with parameters using * bracket notation syntax. * * ### Supported String Formats * - `"ruleName"` - Simple rule without parameters * - `"ruleName[param]"` - Rule with single parameter * - `"ruleName[param1,param2,param3]"` - Rule with multiple parameters * * ### Parameter Parsing * - Parameters are extracted from content within square brackets * - Multiple parameters are separated by commas * - Leading/trailing whitespace is automatically trimmed * - All parameters are treated as strings (conversion happens in rule functions) * * @example * ```typescript * // These calls demonstrate the parsing logic (internal method) * // Simple rule * parseStringRule("Required", registeredRules) * // Returns: { ruleName: "Required", params: [], ruleFunction: fn, rawRuleName: "Required" } * * // Rule with single parameter * parseStringRule("MinLength[5]", registeredRules) * // Returns: { ruleName: "MinLength", params: ["5"], ruleFunction: fn, rawRuleName: "MinLength[5]" } * * // Rule with multiple parameters * parseStringRule("Between[10, 20]", registeredRules) * // Returns: { ruleName: "Between", params: ["10", "20"], ruleFunction: fn, rawRuleName: "Between[10, 20]" } * ``` * * @internal * @param ruleString - The string representation of the rule to parse * @param registeredRules - Map of all currently registered validation rules * * @returns Parsed rule object with standardized structure, or null if rule not found * @returns returns.ruleName - The extracted rule name * @returns returns.params - Array of string parameters * @returns returns.ruleFunction - The actual validation function * @returns returns.rawRuleName - The original unparsed rule string * * @since 1.22.0 * @see {@link parseAndValidateRules} - Public method that uses this parser * @private */ private static parseStringRule; /** * ## Parse Object-Based Validation Rules * * Internal helper method that processes object-format validation rules into standardized * rule objects. This method handles the conversion of key-value pair rules where the * key is the rule name and the value contains the parameters. * * ### Object Format Structure * ```typescript * { * ruleName: parameters, // parameters can be array or single value * anotherRule: [param1, param2], // array of parameters * simpleRule: [] // no parameters * } * ``` * * ### Processing Logic * 1. **Iteration**: Loops through each property in the rules object * 2. **Validation**: Checks if the rule name corresponds to a registered rule * 3. **Parameter Handling**: Ensures parameters are in array format * 4. **Categorization**: Separates valid rules from invalid ones * 5. **Standardization**: Converts to consistent internal format * * @example * ```typescript * // Object rules input * const objectRules = { * Required: [], * MinLength: [5], * Between: [10, 20], * CustomRule: 'singleParam', * InvalidRule: [] // Will be marked as invalid if not registered * }; * * const result = parseObjectRules(objectRules, registeredRules); * // result.valid contains standardized rule objects * // result.invalid contains ['InvalidRule'] if not registered * ``` * * @internal * @param rulesObject - Object containing rule names as keys and parameters as values * @param registeredRules - Map of all currently registered validation rules * * @returns Object containing categorized rule processing results * @returns returns.valid - Array of successfully parsed and validated rule objects * @returns returns.invalid - Array of rule names that couldn't be processed * * @since 1.22.0 * @see {@link parseAndValidateRules} - Public method that uses this parser * @private */ private static parseObjectRules; /** * ## Validate Value Against Rules * * Performs comprehensive validation of a single value against a set of validation rules. * This is the core validation method that supports both synchronous and asynchronous * validation with detailed error reporting and internationalization support. * * ### Validation Process * 1. **Rule Parsing**: Converts input rules to standardized format * 2. **Rule Validation**: Checks that all rules are registered and valid * 3. **Sequential Execution**: Runs rules one by one, stopping at first failure * 4. **Error Handling**: Provides detailed error information with context * 5. **Internationalization**: Supports localized error messages * * ### Rule Execution Order * Rules are executed in the order they appear in the rules array. Validation stops * at the first rule that fails, ensuring efficient validation and consistent behavior. * * ### Error Handling * - **Invalid Rules**: Immediately rejects with list of unregistered rules * - **Validation Failures**: Rejects with detailed error context * - **Rule Exceptions**: Catches and formats rule execution errors * * @example * ```typescript * // Basic validation * try { * const result = await Validator.validate({ * value: 'user@example.com', * rules: ['Required', 'Email'], * fieldName: 'email' * }); * console.log('Validation passed!', result); * } catch (error) { * console.error('Validation failed:', error.message); * } * * // Complex validation with context * const validationOptions = { * value: 'newPassword123', * rules: [ * 'Required', * 'MinLength[8]', * { StrongPassword: [] }, * async ({ value, context }) => { * const isUsed = await checkPasswordHistory(value, context.userId); * return !isUsed || 'Password was recently used'; * } * ], * fieldName: 'password', * translatedPropertyName: 'Password', * context: { userId: 123 } * }; * * try { * await Validator.validate(validationOptions); * } catch (error) { * // Error contains: message, status, rule, ruleName, ruleParams, etc. * console.log('Failed rule:', error.ruleName); * console.log('Error message:', error.message); * } * * // Validation with custom parameters * const numericValidation = await Validator.validate({ * value: 25, * rules: ['Required', 'Number', 'Between[18,65]'], * fieldName: 'age', * propertyName: 'userAge' * }); * ``` * * ### Advanced Usage * ```typescript * // Custom validation context * interface ValidationContext { * currentUser: { id: number; role: string }; * formData: Record<string, any>; * } * * const contextValidation = await Validator.validate<ValidationContext>({ * value: 'admin-action', * rules: [ * 'required', * ({ value, context }) => { * return context.currentUser.role === 'admin' || 'Admin access required'; * } * ], * context: { * currentUser: { id: 1, role: 'user' }, * formData: { action: 'admin-action' } * } * }); * ``` * * @template Context - Type of the validation context object passed to rules * * @param options - Validation configuration object * @param options.rules - Array of validation rules to apply * @param options.value - The value to validate * @param options.fieldName - Name of the field being validated * @param options.propertyName - Property name (alias for fieldName) * @param options.translatedPropertyName - Localized field name for error messages * @param options.context - Additional context data passed to validation rules * @param options.extra - Any additional properties passed through to rules * * @returns Promise that resolves with validation success data or rejects with error details * * @throws {ValidationError} When validation fails, includes detailed error context * @throws {RuleError} When invalid rules are detected * * @since 1.0.0 * @see {@link parseAndValidateRules} - Rule parsing used internally * @see {@link validateTarget} - Class-based validation * @see {@link registerRule} - Register custom rules * @public */ static validate<Context = unknown>({ rules, value, ...extra }: IValidatorValidateOptions<Array<any>, Context>): Promise<IValidatorValidateOptions<Array<any>, Context>>; /** * ## Validate Class Target with Decorators * * Validates data against a class that has been decorated with validation rules using * property decorators. This method provides a powerful way to define validation schemas * at the class level and validate entire objects against those schemas. * * ### Decorator-Based Validation * This method works with classes that use validation decorators on their properties. * Each decorated property defines the validation rules that should be applied to * the corresponding data field. * * ### Validation Process * 1. **Rule Extraction**: Retrieves validation rules from class metadata * 2. **Property Translation**: Gets localized property names for error messages * 3. **Parallel Validation**: Validates all properties concurrently for performance * 4. **Error Aggregation**: Collects all validation errors across properties * 5. **Result Formatting**: Provides comprehensive success/failure information * * ### Error Message Customization * The optional `errorMessageBuilder` function allows complete customization of * how validation errors are formatted and presented. * * @example * ```typescript * // Define a class with validation decorators * class UserRegistration { * @IsRequired * @IsEmail * email: string; * * @IsRequired * @MinLength([8]) * @HasPattern([/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/, 'Must contain uppercase, lowercase and number']) * password: string; * * @IsRequired * @MinLength([2]) * @MaxLength([50]) * name: string; * * @IsOptional * @IsNumber * @Between([18, 120]) * age?: number; * } * * // Validate user data * const userData = { * email: 'user@example.com', * password: 'SecurePass123', * name: 'John Doe', * age: 25 * }; * * try { * const result = await Validator.validateTarget(UserRegistration, userData); * console.log('User data is valid!', result.data); * } catch (error) { * console.error('Validation failed:'); * error.errors.forEach(err => { * console.log(`${err.fieldName}: ${err.message}`); * }); * } * ``` * * ### Advanced Usage with Custom Error Builder * ```typescript * const customOptions = { * errorMessageBuilder: (translatedName, error, builderOptions) => { * // Custom error format with field highlighting * return `⚠️ ${translatedName.toUpperCase()}: ${error}`; * } * }; * * try { * await Validator.validateTarget(UserRegistration, invalidData, customOptions); * } catch (error) { * // Errors will use custom format: "⚠️ EMAIL: Invalid email format" * } * ``` * * ### Context-Aware Validation * ```typescript * // Class with context-dependent validation * class AdminUser { * @IsRequired * @IsEmail * email: string; * * @CustomRule([ * ({ value, context }) => { * return context.isAdmin || 'Admin privileges required'; * } * ]) * adminAction: string; * } * * const adminData = { * email: 'admin@company.com', * adminAction: 'delete-user' * }; * * // Validate with context * interface AdminContext { * isAdmin: boolean; * permissions: string[]; * } * * const result = await Validator.validateTarget<typeof AdminUser, AdminContext>( * AdminUser, * adminData, * { context: { isAdmin: true, permissions: ['delete', 'modify'] } } * ); * ``` * * ### Internationalization Support * ```typescript * // Property names are automatically translated based on i18n configuration * // Error messages will use localized property names * * // English: "Email: Invalid email format" * // French: "E-mail : Format d'e-mail invalide" * // Spanish: "Correo electrónico: Formato de correo inválido" * ``` * * @template T - The class constructor type being validated * @template Context - Type of validation context passed to rules * * @param target - The class constructor with validation decorators * @param data - Object containing data to validate against the class schema * @param options - Optional configuration for validation behavior * @param options.errorMessageBuilder - Custom function to format error messages * * @returns Promise resolving to object with validated data * @returns returns.data - The input data (potentially transformed by validation) * * @throws {ValidationError} Contains detailed validation failure information * @throws returns.status - Always "error" for validation failures * @throws returns.message - Summary message with failure count * @throws returns.errors - Array of individual field validation errors * @throws returns.success - Always false for validation failures * * @since 1.0.0 * @see {@link getTargetRules} - Extracts validation rules from class * @see {@link validate} - Core validation method used internally * @see {@link IsRequired} - Common validation decorator * @see {@link IsEmail} - Email validation decorator * @public */ static validateTarget<T extends IClassConstructor = any, Context = unknown>(target: T, data: Partial<Record<keyof InstanceType<T>, any>>, options?: { context?: Context; errorMessageBuilder?: (translatedPropertyName: string, error: string, builderOptions: { propertyName: string; translatedPropertyName: string; message: string; ruleName: string; ruleParams: any[]; value: any; separators: { multiple: string; single: string; }; data: Partial<Record<keyof InstanceType<T>, any>>; }) => string; }): Promise<{ data: Partial<Record<keyof InstanceType<T>, any>>; }>; /** * ## Extract Validation Rules from Class * * Retrieves all validation rules that have been applied to a class through property * decorators. This method introspects the class metadata to extract the complete * validation schema defined by decorators. * * ### Metadata Introspection * This method uses reflection to access metadata that was stored when validation * decorators were applied to class properties. It provides a programmatic way to * inspect the validation schema of any decorated class. * * ### Use Cases * - **Schema Inspection**: Understand what validation rules apply to a class * - **Dynamic Validation**: Build validation logic based on class structure * - **Documentation**: Generate validation documentation from code * - **Testing**: Verify that proper decorators are applied * * @example * ```typescript * class User { * @IsRequired * @IsEmail * email: string; * * @IsRequired * @MinLength([3]) * @MaxLength([50]) * name: string; * * @IsOptional * @IsNumber * age?: number; * } * * // Extract validation rules * const rules = Validator.getTargetRules(User); * console.log(rules); * // Output: * // { * // email: ['required', 'email'], * // name: ['required', 'minLength', 'maxLength'], * // age: ['number'] // IsOptional doesn't add a rule * // } * * // Check if a property has specific rules * const emailRules = rules.email; * const hasEmailValidation = emailRules.includes('email'); * * // Programmatic rule inspection * function analyzeClass(targetClass: any) { * const rules = Validator.getTargetRules(targetClass); * const analysis = { * totalProperties: Object.keys(rules).length, * requiredProperties: [], * optionalProperties: [] * }; * * for (const [property, propertyRules] of Object.entries(rules)) { * if (propertyRules.includes('required')) { * analysis.requiredProperties.push(property); * } else { * analysis.optionalProperties.push(property); * } * } * * return analysis; * } * ``` * * @template T - The class constructor type to extract rules from * * @param target - Class constructor with validation decorators * * @returns Record mapping property names to their validation rules * * @since 1.0.0 * @see {@link validateTarget} - Uses this method to get validation rules * @see {@link createPropertyDecorator} - How rules are attached to properties * @public */ static getTargetRules<T extends IClassConstructor = any>(target: T): Record<keyof InstanceType<T>, IValidatorRule[]>; /** * ## Get Target Validation Options * * Retrieves validation options that have been configured for a specific class * through the `@ValidationTargetOptions` decorator. These options control how * validation behaves when `validateTarget` is called on the class. * * ### Configuration Options * Options can include custom error message builders, validation contexts, * and other class-level validation behaviors that should be applied consistently * whenever the class is validated. * * @example * ```typescript * // Class with custom validation options * @ValidationTargetOptions({ * errorMessageBuilder: (translatedName, error) => { * return `❌ ${translatedName}: ${error}`; * } * }) * class CustomUser { * @IsRequired * @IsEmail * email: string; * } * * // Get the configured options * const options = Validator.getValidateTargetOptions(CustomUser); * console.log(typeof options.errorMessageBuilder); // 'function' * * // These options will be automatically used when validating * const result = await Validator.validateTarget(CustomUser, userData); * // Error messages will use the custom format * ``` * * @template T - The class constructor type to get options for * * @param target - Class constructor that may have validation options * * @returns Validation options object, or empty object if none configured * * @since 1.0.0 * @see {@link validateTarget} - Uses these options during validation * @see {@link ValidationTargetOptions} - Decorator to set these options * @public */ static getValidateTargetOptions<T extends IClassConstructor = any>(target: T): Parameters<typeof Validator.validateTarget>[2]; /** * ## Create Rule Decorator Factory * * Creates a decorator factory that can be used to apply validation rules to class * properties. This method provides a way to create reusable decorators from * validation rule functions with enhanced type safety and parameter handling. * * ### Decorator Factory Pattern * The returned function is a decorator factory that accepts parameters and returns * a property decorator. This allows for flexible rule configuration while maintaining * type safety and proper parameter validation. * * ### Parameter Handling * Parameters passed to the decorator factory are automatically forwarded to the * validation rule function during validation. This enables parameterized validation * rules that can be configured at decoration time. * * @example * ```typescript * // Create a custom validation rule * const validateAge = ({ value, ruleParams }) => { * const [minAge, maxAge] = ruleParams; * if (value < minAge) return `Must be at least ${minAge} years old`; * if (value > maxAge) return `Must be no more than ${maxAge} years old`; * return true; * }; * * // Create a decorator factory * const AgeRange = Validator.createRuleDecorator(validateAge); * * // Use the decorator * class Person { * @IsRequired * name: string; * * @IsRequired * @IsNumber * @AgeRange([18, 120]) // Min 18, Max 120 * age: number; * } * * // Create specialized decorators * const IsAdult = AgeRange([18, 150]); * const IsChild = AgeRange([0, 17]); * * class User { * @IsAdult * userAge: number; * } * * class Student { * @IsChild * studentAge: number; * } * ``` * * ### Advanced Usage with Context * ```typescript * // Context-aware validation rule * const validatePermission = ({ value, ruleParams, context }) => { * const [requiredPermission] = ruleParams; * const userPermissions = context?.permissions || []; * return userPermissions.includes(requiredPermission) || * `Requires ${requiredPermission} permission`; * }; * * const RequiresPermission = Validator.createRuleDecorator(validatePermission); * * class AdminAction { * @RequiresPermission(['admin']) * action: string; * * @RequiresPermission(['delete', 'modify']) * destructiveAction: string; * } * ``` * * ### Async Rule Decorators * ```typescript * // Async validation rule * const validateUniqueEmail = async ({ value, context }) => { * const exists = await database.user.findByEmail(value); * return !exists || 'Email is already registered'; * }; * * const IsUniqueEmail = Validator.createRuleDecorator(validateUniqueEmail); * * class Registration { * @IsRequired * @IsEmail * @IsUniqueEmail([]) * email: string; * } * ``` * * @template RuleParamsType - Array type defining parameter structure for the rule * * @param ruleFunction - Validation function that will be wrapped in a decorator * * @returns Decorator factory function that accepts parameters and returns a property decorator * * @since 1.22.0 * @see {@link createPropertyDecorator} - Lower-level decorator creation * @see {@link registerRule} - Alternative way to create reusable rules * @public */ static createRuleDecorator<RuleParamsType extends Array<any> = Array<any>>(ruleFunction: IValidatorRuleFunction<RuleParamsType>): (ruleParameters: RuleParamsType) => PropertyDecorator; /** * ## Create Property Decorator * * Low-level method for creating property decorators that attach validation rules * to class properties. This method handles the metadata storage and provides * the foundation for all validation decorators in the system. * * ### Metadata Storage * This method uses TypeScript's metadata system to attach validation rules to * class properties. The rules are stored in a way that allows them to be * retrieved later during validation. * * ### Rule Accumulation * Multiple decorators can be applied to the same property, and this method * ensures that all rules are properly accumulated and stored together. * * @example * ```typescript * // Create a simple validation decorator * const IsPositive = Validator.createPropertyDecorator( * ({ value }) => value > 0 || 'Must be positive' * ); * * // Create a decorator with multiple rules * const IsValidEmail = Validator.createPropertyDecorator([ * 'required', * 'email' * ]); * * // Use the decorators * class Product { * @IsPositive * price: number; * * @IsValidEmail * contactEmail: string; * } * ``` * * @template RuleParamsType - Array type for rule parameters * * @param rule - Single rule or array of rules to attach to the property * * @returns Property decorator function that can be applied to class properties * * @since 1.0.0 * @see {@link createRuleDecorator} - Higher-level decorator creation * @internal */ static createPropertyDecorator<RuleParamsType extends Array<any> = Array<any>>(rule: IValidatorRule<RuleParamsType> | IValidatorRule<RuleParamsType>[]): PropertyDecorator; } /** * ## Pre-Built Validation Decorators * * Collection of commonly used validation decorators that provide immediate * validation capabilities for standard data types and formats. These decorators * are built on top of registered validation rules and provide a convenient * way to apply common validations. */ /** * ### IsNumber Decorator * * Validates that a property value is a valid number. This decorator checks * for numeric values and rejects non-numeric inputs. * * @example * ```typescript * class Product { * @IsNumber * price: number; * * @IsNumber * quantity: number; * * @IsRequired * @IsNumber * weight: number; * } * * // Valid data * const product = { price: 19.99, quantity: 5, weight: 2.5 }; * * // Invalid data * const invalid = { price: "not-a-number", quantity: 5, weight: 2.5 }; * // Will fail validation with error: "Price must be a number" * ``` * * @decorator * @since 1.0.0 * @see {@link IsRequired} - Often used together * @public */ export declare const IsNumber: PropertyDecorator; /** * ### IsRequired Decorator * * Validates that a property has a non-null, non-undefined value. This is * one of the most commonly used validation decorators and should be applied * to any property that must have a value. * * @example * ```typescript * class User { * @IsRequired * username: string; * * @IsRequired * @IsEmail * email: string; * * // Optional field - no @IsRequired * bio?: string; * } * * // Valid data * const user = { username: "john_doe", email: "john@example.com" }; * * // Invalid data * const invalid = { email: "john@example.com" }; // Missing username * // Will fail validation with error: "Username is required" * ``` * * @decorator * @since 1.0.0 * @see {@link IsOptional} - For optional fields * @public */ export declare const IsRequired: PropertyDecorator; /** * ### IsEmail Decorator * * Validates that a property value is a properly formatted email address. * Uses comprehensive email validation that checks for valid email format * according to RFC standards. * * @example * ```typescript * class Contact { * @IsRequired * @IsEmail * primaryEmail: string; * * @IsEmail // Optional email * secondaryEmail?: string; * } * * // Valid data * const contact = { * primaryEmail: "user@example.com", * secondaryEmail: "backup@company.org" * }; * * // Invalid data * const invalid = { * primaryEmail: "not-an-email", * secondaryEmail: "user@" * }; * // Will fail validation with errors about invalid email format * ``` * * @decorator * @since 1.0.0 * @see {@link IsRequired} - Often used together * @public */ export declare const IsEmail: PropertyDecorator; /** * ### IsUrl Decorator * * Validates that a property value is a properly formatted URL. Checks for * valid URL structure including protocol, domain, and optional path components. * * @example * ```typescript * class Website { * @IsRequired * @IsUrl * homepage: string; * * @IsUrl * blogUrl?: string; * * @IsUrl * apiEndpoint: string; * } * * // Valid data * const website = { * homepage: "https://example.com", * blogUrl: "https://blog.example.com/posts", * apiEndpoint: "https://api.example.com/v1" * }; * * // Invalid data * const invalid = { * homepage: "not-a-url", * apiEndpoint: "ftp://invalid-protocol" * }; * ``` * * @decorator * @since 1.0.0 * @public */ export declare const IsUrl: PropertyDecorator; /** * ### IsFileName Decorator * * Validates that a property value is a valid filename. Checks for proper * filename format and excludes invalid characters that are not allowed * in file systems. * * @example * ```typescript * class FileUpload { * @IsRequired * @IsFileName * filename: string; * * @IsFileName * thumbnailName?: string; * } * * // Valid data * const upload = { * filename: "document.pdf", * thumbnailName: "thumb_001.jpg" * }; * * // Invalid data * const invalid = { * filename: "file<with>invalid:chars.txt" * }; * ``` * * @decorator * @since 1.0.0 * @public */ export declare const IsFileName: PropertyDecorator; /** * ### IsNonNullString Decorator * * Validates that a property value is a non-null, non-empty string. This * decorator is stricter than IsRequired as it also ensures the value is * a string with actual content (not just whitespace). * * @example * ```typescript * class Article { * @IsNonNullString * title: string; * * @IsNonNullString * content: string; * * @IsNonNullString * author: string; * } * * // Valid data * const article = { * title: "How to Validate Data", * content: "This article explains validation...", * author: "John Doe" * }; * * // Invalid data * const invalid = { * title: "", // Empty string * content: " ", // Only whitespace * author: null // Null value * }; * ``` * * @decorator * @since 1.0.0 * @see {@link IsRequired} - Less strict alternative * @public */ export declare const IsNonNullString: PropertyDecorator; /** * ## ValidationTargetOptions Class Decorator * * Class decorator that configures validation behavior for a target class. * This decorator allows you to set class-level validation options that will * be automatically applied whenever `validateTarget` is called on the class. * * ### Configuration Options * - **errorMessageBuilder**: Custom function to format validation error messages * - **context**: Default validation context for all validations * - **stopOnFirstError**: Whether to stop validation at first error (future feature) * - **locale**: Specific locale for error messages (future feature) * * ### Use Cases * - **Consistent Error Formatting**: Apply uniform error message styling across a class * - **Context Injection**: Provide default context for validation rules * - **Custom Validation Behavior**: Override default validation behavior per class * * @example * ```typescript * // Basic usage with custom error formatting * @ValidationTargetOptions({ * errorMessageBuilder: (fieldName, error) => { * return `🚫 ${fieldName.toUpperCase()}: ${error}`; * // { * // email: ['Required', 'Email'], * // name: ['Required', 'MinLength', 'MaxLength'], * // age: ['Number'] // IsOptional doesn't add a rule * // } * * // Check if a property has specific rules * const emailRules = rules.email; * const hasEmailValidation = emailRules.includes('Email'); * name: string; * } * * // When validation fails, errors will be formatted as: * // "🚫 EMAIL: Invalid email format" * // "🚫 NAME: Must be at least 3 characters" * * // Advanced usage with context and detailed formatting * @ValidationTargetOptions({ * errorMessageBuilder: (translatedName, error, builderOptions) => { * const { propertyName, ruleName, separators } = builderOptions; * * // Custom formatting based on rule type * if (ruleName === 'required') { * return `❗ ${translatedName} is mandatory`; * } * * if (ruleName === 'email') { * return `📧 Please enter a valid email for ${translatedName}`; * } * * return `⚠️ ${translatedName}: ${error}`; * } * }) * class DetailedUser { * @IsRequired * @IsEmail * email: string; * * @IsRequired * name: string; * } * ``` * * ### Context-Aware Validation * ```typescript * interface UserValidationContext { * isAdmin: boolean; * permissions: string[]; * organizationId: string; * } * * @ValidationTargetOptions({ * errorMessageBuilder: (fieldName, error, { context }) => { * const userContext = context as UserValidationContext; * if (userContext?.isAdmin) { * return `[ADMIN] ${fieldName}: ${error}`; * } * return `${fieldName}: ${error}`; * } * }) * class AdminUser { * @IsRequired * @IsEmail * email: string; * * @CustomRule([ * ({ value, context }) => { * const { isAdmin, permissions } = context as UserValidationContext; * return isAdmin && permissions.includes('manage-users') || * 'Admin privileges required'; * } * ]) * adminAction: string; * } * ``` * * ### Internationalization Support * ```typescript * @ValidationTargetOptions({ * errorMessageBuilder: (translatedName, error, { data }) => { * // Use translated property names and localized error formatting * const locale = data.preferredLocale || 'en'; * * switch (locale) { * case 'fr': * return `❌ ${translatedName} : ${error}`; * case 'es': * return `❌ ${translatedName}: ${error}`; * default: * return `❌ ${translatedName}: ${error}`; * } * } * }) * class InternationalUser { * @IsRequired * @IsEmail * email: string; * * preferredLocale?: string; * } * ``` * * @param validationOptions - Configuration object for validation behavior * @param validationOptions.errorMessageBuilder - Custom error message formatting function * * @returns Class decorator function that applies the validation configuration * * @since 1.22.0 * @see {@link validateTarget} - Method that uses these options * @see {@link getValidateTargetOptions} - Retrieves configured options * @decorator * @public */ export declare function ValidationTargetOptions(validationOptions: Parameters<typeof Validator.validateTarget>[2]): ClassDecora