reslib 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
- import { ClassConstructor, MakeOptional } from '../types';
1
+ import { ClassConstructor, MakeOptional, MakeRequired } from '../types';
2
2
  import { I18n } from '../i18n';
3
3
  import { ValidatorBulkError, ValidatorClassError, ValidatorCreateBulkErrorPayload, ValidatorCreateClassErrorPayload, ValidatorCreateErrorPayload, ValidatorError } from './errors';
4
- import { ValidatorAsyncRuleResult, ValidatorBulkOptions, ValidatorBulkResult, ValidatorClassOptions, ValidatorClassResult, ValidatorDefaultMultiRule, ValidatorMultiRuleFunction, ValidatorMultiRuleNames, ValidatorMultiRuleOptions, ValidatorNestedRuleFunctionOptions, ValidatorObjectOptions, ValidatorObjectResult, ValidatorObjectRules, ValidatorObjectSchema, ValidatorOptions, ValidatorResult, ValidatorRule, ValidatorRuleFunction, ValidatorRuleFunctionsMap, ValidatorRuleName, ValidatorRuleObject, ValidatorRuleParams, ValidatorRuleResult, ValidatorRules, ValidatorSanitizedRuleObject, ValidatorSanitizedRules, ValidatorSuccess } from './types';
4
+ import { ValidatorAsyncRuleResult, ValidatorBulkOptions, ValidatorBulkResult, ValidatorClassOptions, ValidatorClassResult, ValidatorDefaultMultiRule, ValidatorIfResolver, ValidatorIfRuleFunction, ValidatorIfRuleOptions, ValidatorMultiRuleFunction, ValidatorMultiRuleNames, ValidatorMultiRuleOptions, ValidatorNestedRuleFunctionOptions, ValidatorObjectOptions, ValidatorObjectResult, ValidatorObjectRules, ValidatorObjectSchema, ValidatorOptions, ValidatorResult, ValidatorRule, ValidatorRuleConfigMessage, ValidatorRuleFunction, ValidatorRuleFunctionsMap, ValidatorRuleName, ValidatorRuleObject, ValidatorRuleParams, ValidatorRuleResult, ValidatorRules, ValidatorSanitizedRuleObject, ValidatorSanitizedRules, ValidatorSuccess } from './types';
5
5
  export declare class Validator {
6
6
  private static readonly RULES_METADATA_KEY;
7
7
  /**
@@ -290,7 +290,7 @@ export declare class Validator {
290
290
  * @see {@link ValidatorOptionalOrEmptyRuleNames} - Type constraint for registered rules
291
291
  * @public
292
292
  */
293
- static getRule<Context = unknown>(ruleName: ValidatorRuleName): ValidatorRuleFunction<[options?: import("../utils/index").IsEmailOptions | undefined], Context> | ValidatorRuleFunction<[options?: import("../utils/index").IsUrlOptions | undefined], Context> | ValidatorRuleFunction<[], Context> | ValidatorRuleFunction<[minLength: number], Context> | ValidatorRuleFunction<[maxLength: number], Context> | ValidatorRuleFunction<[length: number], Context> | ValidatorRuleFunction<any[], Context> | ValidatorRuleFunction<[date: string | number | Date], Context> | ValidatorRuleFunction<[date: string | number | Date], Context> | ValidatorRuleFunction<[minDate: string | number | Date, maxDate: string | number | Date], Context> | ValidatorRuleFunction<[date: string | number | Date], Context> | ValidatorRuleFunction<unknown[], Context> | ValidatorRuleFunction<[size: number], Context> | ValidatorRuleFunction<string[], Context> | ValidatorRuleFunction<[minSize: number], Context> | ValidatorRuleFunction<[countryCode?: "AF" | "AL" | "DZ" | "AS" | "AD" | "AO" | "AI" | "AG" | "AR" | "AM" | "AW" | "AU" | "AT" | "AZ" | "BS" | "BH" | "BD" | "BB" | "BY" | "BE" | "BZ" | "BJ" | "BM" | "BT" | "BO" | "BA" | "BW" | "BR" | "IO" | "VG" | "BN" | "BG" | "BF" | "BI" | "KH" | "CM" | "CA" | "CV" | "BQ" | "KY" | "CF" | "TD" | "CL" | "CN" | "CX" | "CC" | "CO" | "KM" | "CD" | "CG" | "CK" | "CR" | "CI" | "HR" | "CU" | "CW" | "CY" | "CZ" | "DK" | "DJ" | "DM" | "DO" | "EC" | "EG" | "SV" | "GQ" | "ER" | "EE" | "ET" | "FK" | "FO" | "FJ" | "FI" | "FR" | "GF" | "PF" | "GA" | "GM" | "GE" | "DE" | "GH" | "GI" | "GR" | "GL" | "GD" | "GP" | "GU" | "GT" | "GG" | "GN" | "GW" | "GY" | "HT" | "HN" | "HK" | "HU" | "IS" | "IN" | "ID" | "IR" | "IQ" | "IE" | "IM" | "IL" | "IT" | "JM" | "JP" | "JE" | "JO" | "KZ" | "KE" | "KI" | "KW" | "KG" | "LA" | "LV" | "LB" | "LS" | "LR" | "LY" | "LI" | "LT" | "LU" | "MO" | "MK" | "MG" | "MW" | "MY" | "MV" | "ML" | "MT" | "MH" | "MQ" | "MR" | "MU" | "YT" | "MX" | "FM" | "MD" | "MC" | "MN" | "ME" | "MS" | "MA" | "MZ" | "MM" | "NA" | "NR" | "NP" | "NL" | "NC" | "NZ" | "NI" | "NE" | "NG" | "NU" | "NF" | "KP" | "MP" | "NO" | "OM" | "PK" | "PW" | "PS" | "PA" | "PG" | "PY" | "PE" | "PH" | "PL" | "PT" | "PR" | "QA" | "RE" | "RO" | "RU" | "RW" | "BL" | "SH" | "KN" | "LC" | "MF" | "PM" | "VC" | "WS" | "SM" | "ST" | "SA" | "SN" | "RS" | "SC" | "SL" | "SG" | "SX" | "SK" | "SI" | "SB" | "SO" | "ZA" | "KR" | "SS" | "ES" | "LK" | "SD" | "SR" | "SJ" | "SZ" | "SE" | "CH" | "SY" | "TW" | "TJ" | "TZ" | "TH" | "TL" | "TG" | "TK" | "TO" | "TT" | "TN" | "TR" | "TM" | "TC" | "TV" | "VI" | "UG" | "UA" | "AE" | "GB" | "US" | "UY" | "UZ" | "VU" | "VA" | "VE" | "VN" | "WF" | "EH" | "YE" | "ZM" | "ZW" | "AX" | undefined], Context> | ValidatorRuleFunction<[options?: {
293
+ static getRule<Context = unknown>(ruleName: ValidatorRuleName): ValidatorRuleFunction<[options?: import("../utils/index").IsEmailOptions | undefined], Context> | ValidatorRuleFunction<[options?: import("../utils/index").IsUrlOptions | undefined], Context> | ValidatorRuleFunction<[], Context> | ValidatorRuleFunction<[minLength: number], Context> | ValidatorRuleFunction<[maxLength: number], Context> | ValidatorRuleFunction<[length: number], Context> | ValidatorRuleFunction<any[], Context> | ValidatorRuleFunction<[date: string | number | Date], Context> | ValidatorRuleFunction<[date: string | number | Date], Context> | ValidatorRuleFunction<[minDate: string | number | Date, maxDate: string | number | Date], Context> | ValidatorRuleFunction<[date: string | number | Date], Context> | ValidatorRuleFunction<unknown[], Context> | ValidatorRuleFunction<[size: number], Context> | ValidatorRuleFunction<string[], Context> | ValidatorRuleFunction<[minSize: number], Context> | ValidatorRuleFunction<[countryCode?: "KM" | "BD" | "CF" | "FR" | "SR" | "TL" | "AF" | "AL" | "DZ" | "AS" | "AD" | "AO" | "AI" | "AG" | "AR" | "AM" | "AW" | "AU" | "AT" | "AZ" | "BS" | "BH" | "BB" | "BY" | "BE" | "BZ" | "BJ" | "BM" | "BT" | "BO" | "BA" | "BW" | "BR" | "IO" | "VG" | "BN" | "BG" | "BF" | "BI" | "KH" | "CM" | "CA" | "CV" | "BQ" | "KY" | "TD" | "CL" | "CN" | "CX" | "CC" | "CO" | "CD" | "CG" | "CK" | "CR" | "CI" | "HR" | "CU" | "CW" | "CY" | "CZ" | "DK" | "DJ" | "DM" | "DO" | "EC" | "EG" | "SV" | "GQ" | "ER" | "EE" | "ET" | "FK" | "FO" | "FJ" | "FI" | "GF" | "PF" | "GA" | "GM" | "GE" | "DE" | "GH" | "GI" | "GR" | "GL" | "GD" | "GP" | "GU" | "GT" | "GG" | "GN" | "GW" | "GY" | "HT" | "HN" | "HK" | "HU" | "IS" | "IN" | "ID" | "IR" | "IQ" | "IE" | "IM" | "IL" | "IT" | "JM" | "JP" | "JE" | "JO" | "KZ" | "KE" | "KI" | "KW" | "KG" | "LA" | "LV" | "LB" | "LS" | "LR" | "LY" | "LI" | "LT" | "LU" | "MO" | "MK" | "MG" | "MW" | "MY" | "MV" | "ML" | "MT" | "MH" | "MQ" | "MR" | "MU" | "YT" | "MX" | "FM" | "MD" | "MC" | "MN" | "ME" | "MS" | "MA" | "MZ" | "MM" | "NA" | "NR" | "NP" | "NL" | "NC" | "NZ" | "NI" | "NE" | "NG" | "NU" | "NF" | "KP" | "MP" | "NO" | "OM" | "PK" | "PW" | "PS" | "PA" | "PG" | "PY" | "PE" | "PH" | "PL" | "PT" | "PR" | "QA" | "RE" | "RO" | "RU" | "RW" | "BL" | "SH" | "KN" | "LC" | "MF" | "PM" | "VC" | "WS" | "SM" | "ST" | "SA" | "SN" | "RS" | "SC" | "SL" | "SG" | "SX" | "SK" | "SI" | "SB" | "SO" | "ZA" | "KR" | "SS" | "ES" | "LK" | "SD" | "SJ" | "SZ" | "SE" | "CH" | "SY" | "TW" | "TJ" | "TZ" | "TH" | "TG" | "TK" | "TO" | "TT" | "TN" | "TR" | "TM" | "TC" | "TV" | "VI" | "UG" | "UA" | "AE" | "GB" | "US" | "UY" | "UZ" | "VU" | "VA" | "VE" | "VN" | "WF" | "EH" | "YE" | "ZM" | "ZW" | "AX" | undefined], Context> | ValidatorRuleFunction<[options?: {
294
294
  email?: import("../utils/index").IsEmailOptions;
295
295
  phoneNumber?: {
296
296
  countryCode?: import("../countries").CountryCode;
@@ -752,6 +752,79 @@ export declare class Validator {
752
752
  * @returns `true` if the value matches the sanitized rule structure, `false` otherwise
753
753
  */
754
754
  static isSanitizedRuleObject<TRuleParams extends ValidatorDefaultArray = ValidatorDefaultArray, Context = unknown>(rule: any): rule is ValidatorSanitizedRuleObject<TRuleParams, Context>;
755
+ /**
756
+ * ## Translate Rule Config Message
757
+ *
758
+ * Translates or processes a custom rule message from a `ValidatorRuleConfigMessage`.
759
+ * This method handles both static string messages (with optional i18n translation)
760
+ * and dynamic function-based messages.
761
+ *
762
+ * ### Purpose
763
+ * This method extracts the rule message translation logic into a reusable function
764
+ * that can be called independently of the `validate` method. It's particularly useful
765
+ * when you need to process custom rule messages in custom validation pipelines or
766
+ * when building custom error handling logic.
767
+ *
768
+ * ### Message Types
769
+ * 1. **Static String**: Can be a direct message or an i18n translation key
770
+ * - If the string is a valid i18n key, it will be translated
771
+ * - Otherwise, the string is used as-is
772
+ * 2. **Dynamic Function**: A function that receives validation options and returns a message
773
+ * - If the function throws an error, an empty string is returned
774
+ *
775
+ * ### Examples
776
+ *
777
+ * #### Static String Message
778
+ * ```typescript
779
+ * const message = Validator.translateRuleConfigMessage({
780
+ * message: 'This field is required',
781
+ * i18n: i18nInstance,
782
+ * validateOptions: { value: '', ruleName: 'Required', ruleParams: [] }
783
+ * });
784
+ * // message = 'This field is required'
785
+ * ```
786
+ *
787
+ * #### i18n Translation Key
788
+ * ```typescript
789
+ * const message = Validator.translateRuleConfigMessage({
790
+ * message: 'validation.required',
791
+ * i18n: i18nInstance,
792
+ * validateOptions: { value: '', ruleName: 'Required', ruleParams: [] }
793
+ * });
794
+ * // message = 'Ce champ est obligatoire' (if i18n is set to French)
795
+ * ```
796
+ *
797
+ * #### Dynamic Function Message
798
+ * ```typescript
799
+ * const message = Validator.translateRuleConfigMessage({
800
+ * message: ({ value, ruleName }) => `Value "${value}" failed ${ruleName} rule`,
801
+ * i18n: i18nInstance,
802
+ * validateOptions: { value: 'test', ruleName: 'Email', ruleParams: [] }
803
+ * });
804
+ * // message = 'Value "test" failed Email rule'
805
+ * ```
806
+ *
807
+ * @template Context - The type of the optional validation context
808
+ *
809
+ * @param options - The options for translating the rule message
810
+ * @param options.message - The rule message to translate (string or function)
811
+ * @param options.i18n - The i18n instance for translation
812
+ * @param options.validateOptions - The validation options passed to function messages
813
+ *
814
+ * @returns The translated/processed message string, or empty string if:
815
+ * - The message is undefined/null
816
+ * - The function message throws an error
817
+ * - The message is not a valid string or function
818
+ *
819
+ * @see {@link ValidatorRuleConfigMessage} - Type definition for rule messages
820
+ * @see {@link validate} - Main validation method that uses this internally
821
+ * @public
822
+ */
823
+ static translateRuleConfigMessage<Context = unknown>({ message, i18n, validateOptions, }: {
824
+ message: ValidatorRuleConfigMessage | undefined;
825
+ i18n: I18n;
826
+ validateOptions: MakeRequired<Omit<ValidatorOptions<ValidatorDefaultArray, Context>, 'sanitizedRules' | 'rules' | 'rule'>, 'i18n' | 'ruleName' | 'ruleParams'>;
827
+ }): string;
755
828
  static validate<Context = unknown>({ rules, ...extra }: MakeOptional<ValidatorOptions<ValidatorDefaultArray, Context>, 'i18n' | 'ruleParams'>): Promise<ValidatorResult<Context>>;
756
829
  /**
757
830
  * ## Should Skip Validation
@@ -857,6 +930,122 @@ export declare class Validator {
857
930
  *
858
931
  */
859
932
  static validateArrayOfRule<Context = unknown, RulesFunctions extends ValidatorDefaultMultiRule<Context> = ValidatorDefaultMultiRule<Context>>(options: ValidatorMultiRuleOptions<Context, RulesFunctions>): ValidatorAsyncRuleResult;
933
+ /**
934
+ * ## Validate If Rule
935
+ *
936
+ * Conditional validation method that applies rules based on a resolver function.
937
+ * The resolver dynamically determines which rules to apply (if any) based on
938
+ * runtime conditions, enabling flexible, context-aware validation.
939
+ *
940
+ * ### Resolver Pattern
941
+ * Unlike traditional condition + then/otherwise approach, this method uses a single
942
+ * resolver function that returns:
943
+ * - **Rules array**: Apply these validation rules
944
+ * - **Object with `rules` and `message`**: Apply rules with custom error message
945
+ * - **Empty array, `undefined`, or `null`**: Skip validation (return success)
946
+ *
947
+ * ### Use Cases
948
+ * - **Optional Validation**: Only validate if a value is present
949
+ * - **Role-Based Rules**: Different validation based on user role
950
+ * - **Context-Aware Validation**: Rules that depend on application state
951
+ * - **Dynamic Messages**: Custom error messages based on context
952
+ * - **Feature Flags**: Enable/disable validation based on configuration
953
+ *
954
+ * ### Examples
955
+ *
956
+ * #### Optional field validation
957
+ * ```typescript
958
+ * const result = await Validator.validateIfRule({
959
+ * value: optionalEmail,
960
+ * resolver: ({ value }) => {
961
+ * if (!value) return []; // Skip validation
962
+ * return ['Email'];
963
+ * },
964
+ * fieldName: 'email'
965
+ * });
966
+ * ```
967
+ *
968
+ * #### Role-based validation with custom message
969
+ * ```typescript
970
+ * const result = await Validator.validateIfRule({
971
+ * value: password,
972
+ * data: { role: 'admin' },
973
+ * resolver: ({ data }) => {
974
+ * if (data?.role === 'admin') {
975
+ * return {
976
+ * rules: ['Required', 'StrongPassword'],
977
+ * message: 'Admin passwords must be strong',
978
+ * };
979
+ * }
980
+ * return ['Required', { MinLength: [6] }];
981
+ * },
982
+ * fieldName: 'password'
983
+ * });
984
+ * ```
985
+ *
986
+ * #### Context-aware validation
987
+ * ```typescript
988
+ * const result = await Validator.validateIfRule({
989
+ * value: username,
990
+ * context: { strictMode: true },
991
+ * resolver: ({ context }) => {
992
+ * if (context?.strictMode) {
993
+ * return ['Required', 'Alphanumeric', { MinLength: [5] }];
994
+ * }
995
+ * return ['Required'];
996
+ * },
997
+ * fieldName: 'username'
998
+ * });
999
+ * ```
1000
+ *
1001
+ * #### Async resolver - Load rules from database
1002
+ * ```typescript
1003
+ * const result = await Validator.validateIfRule({
1004
+ * value: password,
1005
+ * context: { tenantId: 'tenant-123' },
1006
+ * resolver: async ({ context }) => {
1007
+ * // Load validation config from database
1008
+ * const config = await loadValidationConfig(context?.tenantId);
1009
+ * return config.passwordRules;
1010
+ * },
1011
+ * fieldName: 'password'
1012
+ * });
1013
+ * ```
1014
+ *
1015
+ * #### Async resolver - Feature flag check
1016
+ * ```typescript
1017
+ * const result = await Validator.validateIfRule({
1018
+ * value: username,
1019
+ * resolver: async () => {
1020
+ * const useStrictValidation = await featureFlags.isEnabled('strict-username');
1021
+ * if (useStrictValidation) {
1022
+ * return ['Required', 'Alphanumeric', { MinLength: [5] }];
1023
+ * }
1024
+ * return ['Required'];
1025
+ * },
1026
+ * fieldName: 'username'
1027
+ * });
1028
+ * ```
1029
+ *
1030
+ * @template Context - Type of the optional validation context
1031
+ *
1032
+ * @param options - The validation options including resolver function
1033
+ * @param options.resolver - Function that returns rules to apply (sync or async)
1034
+ * @param options.value - The value to validate
1035
+ * @param options.data - Optional additional data (other fields)
1036
+ * @param options.context - Optional application-specific context
1037
+ * @param options.message - Optional fallback message (used if resolver doesn't provide one)
1038
+ *
1039
+ * @returns ValidatorAsyncRuleResult - `true` if validation passes, error string otherwise
1040
+ *
1041
+ * @public
1042
+ * @async
1043
+ * @see {@link if} - Factory method to create reusable If rules
1044
+ * @see {@link ValidatorIfRuleOptions} - Options interface
1045
+ * @see {@link ValidatorIfResolver} - Resolver function type (supports sync/async)
1046
+ * @see {@link ValidatorIfResolverResult} - Resolver return type
1047
+ */
1048
+ static validateIfRule<Context = unknown>(options: ValidatorIfRuleOptions<Context>): ValidatorAsyncRuleResult;
860
1049
  static getI18nTranslateOptions<Context = unknown>({ fieldName, propertyName, fieldLabel, translatedPropertyName, context, ...rest }: Partial<ValidatorOptions<ValidatorDefaultArray, Context>>): Partial<ValidatorOptions<ValidatorDefaultArray, Context>>;
861
1050
  /**
862
1051
  * ## Validate Nested Rule (Core Nested Validation Executor)
@@ -1043,7 +1232,7 @@ export declare class Validator {
1043
1232
  * @public
1044
1233
  * @async
1045
1234
  */
1046
- static validateMultiRule<Context = unknown, RulesFunctions extends ValidatorDefaultMultiRule<Context> = ValidatorDefaultMultiRule<Context>>(ruleName: ValidatorMultiRuleNames, { value, ruleParams, startTime, ...extra }: ValidatorMultiRuleOptions<Context, RulesFunctions>): Promise<string | true>;
1235
+ static validateMultiRule<Context = unknown, RulesFunctions extends ValidatorDefaultMultiRule<Context> = ValidatorDefaultMultiRule<Context>>(ruleName: ValidatorMultiRuleNames, { value, ruleParams, startTime, message, ...extra }: ValidatorMultiRuleOptions<Context, RulesFunctions>): Promise<string | true>;
1047
1236
  /**
1048
1237
  * ## Create OneOf Validation Rule
1049
1238
  *
@@ -1237,6 +1426,129 @@ export declare class Validator {
1237
1426
  *
1238
1427
  */
1239
1428
  static arrayOf<Context = unknown>(ruleParams: ValidatorDefaultMultiRule<Context>): ValidatorRuleFunction<ValidatorDefaultArray, Context>;
1429
+ /**
1430
+ * ## Create If Validation Rule
1431
+ *
1432
+ * Factory method that creates a conditional validation rule function. This method provides
1433
+ * a programmatic way to create validation rules that apply different sub-rules based on
1434
+ * a runtime resolver function.
1435
+ *
1436
+ * ### Resolver Pattern
1437
+ * Unlike traditional condition + then/otherwise approach, this factory accepts a single
1438
+ * resolver function that returns the rules to apply. This enables:
1439
+ * - **Complex conditional logic**: Multi-branch conditions, nested checks
1440
+ * - **Dynamic messages**: Different messages based on context
1441
+ * - **Rule composition**: Build rules dynamically from multiple sources
1442
+ * - **Early exit**: Return empty array to skip validation entirely
1443
+ *
1444
+ * ### Return Value
1445
+ * Returns a `ValidatorRuleFunction` that can be used:
1446
+ * - In `Validator.validate()` calls
1447
+ * - In validation decorators like `@IsProperty()`
1448
+ * - As part of rule arrays in class-based validation
1449
+ *
1450
+ * ### Examples
1451
+ *
1452
+ * #### Optional Field Validation
1453
+ * ```typescript
1454
+ * // Only validate email format if value is present
1455
+ * const optionalEmail = Validator.if(({ value }) => {
1456
+ * if (!value) return []; // Skip validation
1457
+ * return ['Email'];
1458
+ * });
1459
+ *
1460
+ * await optionalEmail({ value: '' }); // true (resolver returns [])
1461
+ * await optionalEmail({ value: 'invalid' }); // error (Email fails)
1462
+ * await optionalEmail({ value: 'user@example.com' }); // true
1463
+ * ```
1464
+ *
1465
+ * #### Role-Based Validation
1466
+ * ```typescript
1467
+ * const passwordRule = Validator.if(({ data }) => {
1468
+ * if (data?.role === 'admin') {
1469
+ * return ['Required', 'StrongPassword'];
1470
+ * }
1471
+ * if (data?.role === 'moderator') {
1472
+ * return ['Required', { MinLength: [8] }];
1473
+ * }
1474
+ * return ['Required', { MinLength: [6] }];
1475
+ * });
1476
+ * ```
1477
+ *
1478
+ * #### With Custom Message
1479
+ * ```typescript
1480
+ * const strictModeRule = Validator.if(({ context, i18n }) => {
1481
+ * if (context?.strictMode) {
1482
+ * return {
1483
+ * rules: ['Required', { MinLength: [10] }],
1484
+ * message: i18n.t('validation.strict_mode_required'),
1485
+ * };
1486
+ * }
1487
+ * return ['Required'];
1488
+ * });
1489
+ * ```
1490
+ *
1491
+ * #### Dependent Field Validation
1492
+ * ```typescript
1493
+ * const confirmPasswordRule = Validator.if(({ value, data }) => {
1494
+ * if (!data?.password) return []; // Skip if no password
1495
+ * return {
1496
+ * rules: ['Required', { Equals: [data.password] }],
1497
+ * message: 'Passwords must match',
1498
+ * };
1499
+ * });
1500
+ * ```
1501
+ *
1502
+ * #### Async Resolver - Load from Database
1503
+ * ```typescript
1504
+ * const dynamicRule = Validator.if(async ({ context }) => {
1505
+ * const config = await loadValidationConfig(context?.tenantId);
1506
+ * return config.rules;
1507
+ * });
1508
+ * ```
1509
+ *
1510
+ * #### Async Resolver - Feature Flag
1511
+ * ```typescript
1512
+ * const featureFlagRule = Validator.if(async () => {
1513
+ * const enabled = await featureFlags.isEnabled('strict-validation');
1514
+ * return enabled ? ['Required', 'StrictFormat'] : ['Required'];
1515
+ * });
1516
+ * ```
1517
+ *
1518
+ * ### Decorator Usage
1519
+ * ```typescript
1520
+ * class UserForm {
1521
+ * @IsProperty([
1522
+ * Validator.if(({ data }) => {
1523
+ * if (data?.userType === 'business') {
1524
+ * return ['Required', { MinLength: [3] }];
1525
+ * }
1526
+ * return []; // No validation for non-business users
1527
+ * })
1528
+ * ])
1529
+ * companyName?: string;
1530
+ * }
1531
+ * ```
1532
+ *
1533
+ * ### Sync vs Async
1534
+ * The resolver supports both synchronous and asynchronous operations:
1535
+ * - **Sync**: Return the result directly for simple, non-blocking logic
1536
+ * - **Async**: Return a Promise for database lookups, API calls, or async configuration
1537
+ *
1538
+ * @template Context - Type of the optional validation context
1539
+ *
1540
+ * @param resolver - Resolver function (sync or async) that returns rules to apply
1541
+ *
1542
+ * @returns A `ValidatorRuleFunction` that performs conditional validation
1543
+ *
1544
+ * @public
1545
+ * @see {@link validateIfRule} - The underlying validation method
1546
+ * @see {@link ValidatorIfResolver} - Resolver function type (supports sync/async)
1547
+ * @see {@link ValidatorIfResolverResult} - Resolver return type
1548
+ * @see {@link oneOf} - Similar factory for OR logic validation
1549
+ * @see {@link allOf} - Similar factory for AND logic validation
1550
+ */
1551
+ static if<Context = unknown>(resolver: ValidatorIfResolver<Context>): ValidatorRuleFunction<ValidatorDefaultArray, Context>;
1240
1552
  /**
1241
1553
  * ## Create Nested Validation Rule Factory
1242
1554
  *
@@ -3237,7 +3549,27 @@ export declare class Validator {
3237
3549
  */
3238
3550
  static isAnyError(result: unknown): result is ValidatorError | ValidatorClassError | ValidatorBulkError;
3239
3551
  private static _prepareRuleDecorator;
3240
- private static _buildRuleDecorator;
3552
+ /**
3553
+ * ## Create Property Decorator from Rule
3554
+ *
3555
+ * Creates a property decorator for a validation rule with specific parameters.
3556
+ * This method combines rule registration (if a name is provided) with property decorator creation.
3557
+ * Unlike `buildRuleDecorator` which returns a factory, this returns the actual decorator
3558
+ * bound to the provided rule parameters.
3559
+ *
3560
+ * @remarks
3561
+ * **Naming Guide**:
3562
+ * - `buildRuleDecorator`: Creates a **Factory** (e.g. `IsRequired()`) that produces decorators.
3563
+ * - `createPropertyDecoratorFromRule`: Creates the **Decorator** instance directly from parameters.
3564
+ *
3565
+ * @param ruleParameters - The parameters for the validation rule
3566
+ * @param ruleFunction - The validation rule logic
3567
+ * @param ruleName - Optional name to register the rule with
3568
+ * @param symbolMarker - Internal symbol marker
3569
+ * @returns The PropertyDecorator
3570
+ * @public
3571
+ */
3572
+ static createPropertyDecoratorFromRule<TRuleParams extends ValidatorRuleParams = ValidatorRuleParams, Context = unknown>(ruleParameters: TRuleParams, ruleFunction: ValidatorRuleFunction<TRuleParams, Context>, ruleName?: ValidatorRuleName, symbolMarker?: symbol): PropertyDecorator;
3241
3573
  /**
3242
3574
  * ## Build TClass Rule Decorator Factory
3243
3575
  *
@@ -3677,6 +4009,45 @@ export declare class Validator {
3677
4009
  * @public
3678
4010
  */
3679
4011
  static buildMultiRuleDecorator<Context = unknown, RulesFunctions extends ValidatorDefaultMultiRule<Context> = ValidatorDefaultMultiRule<Context>>(ruleFunction: ValidatorMultiRuleFunction<Context, RulesFunctions>, symbolMarker?: symbol): (ruleParameters: RulesFunctions) => PropertyDecorator;
4012
+ /**
4013
+ * ## Build If Rule Decorator Factory
4014
+ *
4015
+ * Creates a specialized decorator factory for the conditional `@If` rule.
4016
+ * This method wraps `_buildRuleDecorator` to specifically handle the single
4017
+ * resolver function argument pattern used by `Validator.if`.
4018
+ *
4019
+ * ### Purpose
4020
+ * Standard decorators created by `buildRuleDecorator` typically accept rule parameters
4021
+ * as a spread of arguments (`...args`). However, the `@If` decorator accepts a
4022
+ * single resolver function argument. This factory method adapts the generic decorator
4023
+ * builder to enforce this specific signature, providing better type safety and DX
4024
+ * for conditional validation.
4025
+ *
4026
+ * ### How It Works
4027
+ * 1. Takes the `If` validation function as input
4028
+ * 2. Returns a new decorator factory function
4029
+ * 3. This factory takes a single `ValidatorIfResolver` argument
4030
+ * 4. It passes this resolver as a single-element array to the underlying `_buildRuleDecorator`
4031
+ *
4032
+ * ### Benefits
4033
+ * - **Type Safety**: Enforces that exactly one resolver is passed
4034
+ * - **Simplified API**: Users just pass the function: `@If(({ value }) => ...)`
4035
+ * - **Internal consistency**: Reuses the core decorator infrastructure
4036
+ *
4037
+ * @template Context - Type of the optional validation context
4038
+ *
4039
+ * @param ruleFunction - The core validation logic function (processes the rule)
4040
+ * @param symbolMarker - Optional symbol to tag the decorator for reflection
4041
+ *
4042
+ * @returns A decorator factory that accepts a resolver function
4043
+ *
4044
+ * @public
4045
+ * @see {@link createPropertyDecoratorFromRule} - The internal decorator builder
4046
+ * @see {@link ValidatorIfRuleFunction} - The type of the validation function
4047
+ * @see {@link ValidatorIfResolver} - The resolver type accepted by the decorator
4048
+ * @see {@link ValidatorIfResolver} - The resolver type accepted by the decorator
4049
+ */
4050
+ static buildIfRuleDecorator<Context = unknown>(ruleFunction: ValidatorIfRuleFunction<Context>, symbolMarker?: symbol): (ifRuleResolver: ValidatorIfResolver<Context>) => PropertyDecorator;
3680
4051
  /**
3681
4052
  * ## Build Property Decorator Factory
3682
4053
  *