kanun 1.0.1 → 1.0.3

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.
package/README.md CHANGED
@@ -16,7 +16,7 @@ npm install kanun
16
16
  For file validation, install the separate plugin package:
17
17
 
18
18
  ```bash
19
- npm install kanun kanun-plugin-file
19
+ npm install kanun @kanun-hq/plugin-file
20
20
  ```
21
21
 
22
22
  ## Features
@@ -157,7 +157,7 @@ const validator = new Validator(
157
157
 
158
158
  ### Plugins
159
159
 
160
- Kanun supports installable plugins such as `kanun-plugin-file`.
160
+ Kanun supports installable plugins such as `@kanun-hq/plugin-file`.
161
161
 
162
162
  Plugin usage, file validation rules, and framework upload adapters are fully documented:
163
163
 
package/dist/index.cjs CHANGED
@@ -2355,7 +2355,7 @@ var BaseValidator = class BaseValidator {
2355
2355
  [rule, parameters] = validationRuleParser.parse(rule);
2356
2356
  const keys = this.getExplicitKeys(attribute);
2357
2357
  if (keys.length > 0 && parameters.length > 0) parameters = this.replaceAsterisksInParameters(parameters, keys);
2358
- const value = deepFind(this.data, attribute);
2358
+ const value = this.getAttributeValue(attribute);
2359
2359
  const validatable = this.isValidatable(attribute, value, rule);
2360
2360
  if (rule instanceof IRuleContract) return validatable ? this.validateUsingCustomRule(attribute, value, rule) : void 0;
2361
2361
  const method = `validate${buildValidationMethodName(rule)}`;
@@ -2423,14 +2423,14 @@ var BaseValidator = class BaseValidator {
2423
2423
  * Determine if the attribute is validatable.
2424
2424
  */
2425
2425
  isValidatable(attribute, value, rule) {
2426
- return this.presentOrRuleIsImplicit(attribute, value, rule) && this.passesOptionalCheck(attribute) && this.isNotNullIfMarkedAsNullable(attribute, rule);
2426
+ return this.presentOrRuleIsImplicit(attribute, value, rule) && this.passesOptionalCheck(attribute) && this.isNotNullIfMarkedAsNullable(attribute, value, rule);
2427
2427
  }
2428
2428
  /**
2429
2429
  * Determine if the field is present, or the rule implies required.
2430
2430
  */
2431
2431
  presentOrRuleIsImplicit(attribute, value, rule) {
2432
2432
  if (typeof value === "string" && value.trim() === "") return isImplicitRule(rule);
2433
- return typeof deepFind(this.data, attribute) !== "undefined" || isImplicitRule(rule);
2433
+ return typeof value !== "undefined" || isImplicitRule(rule);
2434
2434
  }
2435
2435
  /**
2436
2436
  * Determine if the attribute passes any optional check.
@@ -2438,14 +2438,23 @@ var BaseValidator = class BaseValidator {
2438
2438
  passesOptionalCheck(attribute) {
2439
2439
  if (!validationRuleParser.hasRule(attribute, ["sometimes"], this.rules)) return true;
2440
2440
  const data = validationData.initializeAndGatherData(attribute, this.data);
2441
- return Object.prototype.hasOwnProperty.call(data, attribute) || Object.prototype.hasOwnProperty.call(this.data, attribute);
2441
+ const requestFiles = validationData.initializeAndGatherData(attribute, this.getContext().requestFiles ?? {});
2442
+ return Object.prototype.hasOwnProperty.call(data, attribute) || Object.prototype.hasOwnProperty.call(this.data, attribute) || Object.prototype.hasOwnProperty.call(requestFiles, attribute) || Object.prototype.hasOwnProperty.call(this.getContext().requestFiles ?? {}, attribute);
2442
2443
  }
2443
2444
  /**
2444
2445
  * Determine if the attribute fails the nullable check.
2445
2446
  */
2446
- isNotNullIfMarkedAsNullable(attribute, rule) {
2447
+ isNotNullIfMarkedAsNullable(attribute, value, rule) {
2447
2448
  if (isImplicitRule(rule) || !validationRuleParser.hasRule(attribute, ["nullable"], this.rules)) return true;
2448
- return deepFind(this.data, attribute) !== null;
2449
+ return value !== null;
2450
+ }
2451
+ /**
2452
+ * Resolve an attribute value from validator data first, then request-scoped file context.
2453
+ */
2454
+ getAttributeValue(attribute) {
2455
+ const dataValue = deepFind(this.data, attribute);
2456
+ if (typeof dataValue !== "undefined") return dataValue;
2457
+ return deepFind(this.getContext().requestFiles ?? {}, attribute);
2449
2458
  }
2450
2459
  /**
2451
2460
  * Get the primary attribute name
package/dist/index.d.ts CHANGED
@@ -45,6 +45,100 @@ declare abstract class IRuleContract {
45
45
  trans(path: string, params?: GenericObject): string;
46
46
  }
47
47
  //#endregion
48
+ //#region src/Rules/in.d.ts
49
+ declare class In extends BaseRule {
50
+ /**
51
+ * The name of the rule.
52
+ */
53
+ rule: string;
54
+ /**
55
+ * The accepted values.
56
+ */
57
+ values: (string | number)[];
58
+ /**
59
+ * Create a new In rule instance.
60
+ */
61
+ constructor(values: (string | number)[]);
62
+ /**
63
+ * Convert the rule to a validation string.
64
+ */
65
+ toString(): string;
66
+ }
67
+ //#endregion
68
+ //#region src/Rules/notIn.d.ts
69
+ declare class NotIn extends BaseRule {
70
+ /**
71
+ * The name of the rule.
72
+ */
73
+ rule: string;
74
+ /**
75
+ * The accepted values.
76
+ */
77
+ values: (string | number)[];
78
+ /**
79
+ * Create a new NotIn rule instance.
80
+ */
81
+ constructor(values: (string | number)[]);
82
+ /**
83
+ * Convert the rule to a validation string.
84
+ */
85
+ toString(): string;
86
+ }
87
+ //#endregion
88
+ //#region src/Rules/regex.d.ts
89
+ declare class Regex extends IRuleContract {
90
+ /**
91
+ * The Regular expression to validate
92
+ */
93
+ regex: RegExp;
94
+ /**
95
+ * Flag that decides whether the value should match the regular expression or not
96
+ */
97
+ shouldMatch: boolean;
98
+ constructor(regex: RegExp, shouldMatch?: boolean);
99
+ passes(value: any): boolean;
100
+ getMessage(): string;
101
+ }
102
+ //#endregion
103
+ //#region src/Rules/requiredIf.d.ts
104
+ declare class RequiredIf extends BaseRule {
105
+ /**
106
+ * The condition that validates the attribute
107
+ */
108
+ condition: boolean | CallableFunction;
109
+ /**
110
+ * Create a new required validation rule based on a condition.
111
+ */
112
+ constructor(condition: boolean | CallableFunction);
113
+ /**
114
+ * Convert the rule to a validation string.
115
+ */
116
+ toString(): string;
117
+ }
118
+ //#endregion
119
+ //#region src/Contracts/ValidationRuleName.d.ts
120
+ type ValidationRuleAutocompleteKind = 'plain' | 'paramable';
121
+ interface ValidationRuleAutocompleteMap {}
122
+ /**
123
+ * Backward-compatible alias for older plugin augmentations.
124
+ */
125
+ interface CustomValidationRuleNameMap {}
126
+ type LiteralUnion<T extends U, U = string> = T | (U & Record<never, never>);
127
+ type PluginValidationRuleNameMap = ValidationRuleAutocompleteMap & CustomValidationRuleNameMap;
128
+ type CustomParamableValidationRuleName = Extract<{ [K in keyof PluginValidationRuleNameMap]: PluginValidationRuleNameMap[K] extends 'paramable' ? K : never }[keyof PluginValidationRuleNameMap], string>;
129
+ type CustomPlainRuleName = Extract<{ [K in keyof PluginValidationRuleNameMap]: PluginValidationRuleNameMap[K] extends 'plain' ? K : never }[keyof PluginValidationRuleNameMap], string>;
130
+ type ParamableValidationRuleName = 'accepted_if' | 'after' | 'after_or_equal' | 'before' | 'before_or_equal' | 'between' | 'date_equals' | 'datetime' | 'declined_if' | 'digits_between' | 'different' | 'exists' | 'ends_with' | 'gt' | 'gte' | 'in' | 'includes' | 'lt' | 'lte' | 'max' | 'min' | 'not_in' | 'not_includes' | 'required_if' | 'required_unless' | 'required_with' | 'required_with_all' | 'required_without' | 'required_without_all' | 'same' | 'size' | 'starts_with' | 'unique' | CustomParamableValidationRuleName;
131
+ type PlainRuleName = 'accepted' | 'alpha' | 'alpha_dash' | 'alpha_num' | 'array' | 'array_unique' | 'bail' | 'boolean' | 'confirmed' | 'date' | 'declined' | 'digits' | 'email' | 'integer' | 'json' | 'not_regex' | 'nullable' | 'numeric' | 'object' | 'present' | 'regex' | 'required' | 'sometimes' | 'string' | 'url' | 'hex' | 'uuid' | CustomPlainRuleName;
132
+ type ValidationRuleName = ParamableValidationRuleName | PlainRuleName;
133
+ type MethodRules = Regex | In | NotIn | RequiredIf;
134
+ type ParamableRuleString = `${ParamableValidationRuleName}:${string}`;
135
+ type ValidationRuleString = LiteralUnion<ValidationRuleName | ParamableRuleString>;
136
+ /**
137
+ * Single rule value (supports autocomplete + arbitrary strings + RuleContract instances)
138
+ */
139
+ type ValidationRuleEntry = ValidationRuleString | IRuleContract | MethodRules;
140
+ type ValidationRuleSet = ValidationRuleEntry | readonly ValidationRuleEntry[] | LiteralUnion<`${ValidationRuleName}${string & `|${string}`}` | `${ParamableRuleString}${string & `|${string}`}`>;
141
+ //#endregion
48
142
  //#region src/payloads/replaceAttributePayload.d.ts
49
143
  declare class replaceAttributePayload {
50
144
  /**
@@ -71,7 +165,7 @@ declare class replaceAttributePayload {
71
165
  }
72
166
  //#endregion
73
167
  //#region src/Contracts/BaseContract.d.ts
74
- type InitialRule = string | ValidationCallback | IRuleContract | BaseRule;
168
+ type InitialRule = ValidationRuleEntry | ValidationCallback | BaseRule;
75
169
  type TRule = string | IRuleContract;
76
170
  type NestedStringMap = {
77
171
  [key: string]: string | NestedStringMap;
@@ -509,6 +603,10 @@ declare class BaseValidator<D extends GenericObject = GenericObject> {
509
603
  * Determine if the attribute fails the nullable check.
510
604
  */
511
605
  private isNotNullIfMarkedAsNullable;
606
+ /**
607
+ * Resolve an attribute value from validator data first, then request-scoped file context.
608
+ */
609
+ private getAttributeValue;
512
610
  /**
513
611
  * Get the primary attribute name
514
612
  *
@@ -664,93 +762,6 @@ declare abstract class IValidationRule {
664
762
  passes(value: any, attribute: string): boolean | Promise<boolean>;
665
763
  }
666
764
  //#endregion
667
- //#region src/Rules/in.d.ts
668
- declare class In extends BaseRule {
669
- /**
670
- * The name of the rule.
671
- */
672
- rule: string;
673
- /**
674
- * The accepted values.
675
- */
676
- values: (string | number)[];
677
- /**
678
- * Create a new In rule instance.
679
- */
680
- constructor(values: (string | number)[]);
681
- /**
682
- * Convert the rule to a validation string.
683
- */
684
- toString(): string;
685
- }
686
- //#endregion
687
- //#region src/Rules/notIn.d.ts
688
- declare class NotIn extends BaseRule {
689
- /**
690
- * The name of the rule.
691
- */
692
- rule: string;
693
- /**
694
- * The accepted values.
695
- */
696
- values: (string | number)[];
697
- /**
698
- * Create a new NotIn rule instance.
699
- */
700
- constructor(values: (string | number)[]);
701
- /**
702
- * Convert the rule to a validation string.
703
- */
704
- toString(): string;
705
- }
706
- //#endregion
707
- //#region src/Rules/regex.d.ts
708
- declare class Regex extends IRuleContract {
709
- /**
710
- * The Regular expression to validate
711
- */
712
- regex: RegExp;
713
- /**
714
- * Flag that decides whether the value should match the regular expression or not
715
- */
716
- shouldMatch: boolean;
717
- constructor(regex: RegExp, shouldMatch?: boolean);
718
- passes(value: any): boolean;
719
- getMessage(): string;
720
- }
721
- //#endregion
722
- //#region src/Rules/requiredIf.d.ts
723
- declare class RequiredIf extends BaseRule {
724
- /**
725
- * The condition that validates the attribute
726
- */
727
- condition: boolean | CallableFunction;
728
- /**
729
- * Create a new required validation rule based on a condition.
730
- */
731
- constructor(condition: boolean | CallableFunction);
732
- /**
733
- * Convert the rule to a validation string.
734
- */
735
- toString(): string;
736
- }
737
- //#endregion
738
- //#region src/Contracts/ValidationRuleName.d.ts
739
- interface CustomValidationRuleNameMap {
740
- [key: string]: any;
741
- }
742
- type CustomParamableValidationRuleName = Extract<{ [K in keyof CustomValidationRuleNameMap]: CustomValidationRuleNameMap[K] extends 'paramable' ? K : never }[keyof CustomValidationRuleNameMap], string>;
743
- type CustomPlainRuleName = Extract<{ [K in keyof CustomValidationRuleNameMap]: CustomValidationRuleNameMap[K] extends 'plain' ? K : never }[keyof CustomValidationRuleNameMap], string>;
744
- type ParamableValidationRuleName = 'accepted_if' | 'after' | 'after_or_equal' | 'before' | 'before_or_equal' | 'between' | 'date_equals' | 'datetime' | 'declined_if' | 'digits_between' | 'different' | 'exists' | 'ends_with' | 'gt' | 'gte' | 'in' | 'includes' | 'lt' | 'lte' | 'max' | 'min' | 'not_in' | 'not_includes' | 'required_if' | 'required_unless' | 'required_with' | 'required_with_all' | 'required_without' | 'required_without_all' | 'same' | 'size' | 'starts_with' | 'unique' | CustomParamableValidationRuleName;
745
- type PlainRuleName = 'accepted' | 'alpha' | 'alpha_dash' | 'alpha_num' | 'array' | 'array_unique' | 'bail' | 'boolean' | 'confirmed' | 'date' | 'declined' | 'digits' | 'email' | 'integer' | 'json' | 'not_regex' | 'nullable' | 'numeric' | 'object' | 'present' | 'regex' | 'required' | 'sometimes' | 'string' | 'url' | 'hex' | 'uuid' | CustomPlainRuleName;
746
- type ValidationRuleName = ParamableValidationRuleName | PlainRuleName;
747
- type MethodRules = Regex | In | NotIn | RequiredIf;
748
- /**
749
- * Single rule value (supports autocomplete + arbitrary strings + RuleContract instances)
750
- */
751
- type RuleName = ValidationRuleName | `${ParamableValidationRuleName}:${string}` | IRuleContract | MethodRules;
752
- type ValidationRuleSet = RuleName | RuleName[] | `${ValidationRuleName}${string & `|${string}`}`;
753
- //#endregion
754
765
  //#region src/Contracts/ValidatorContracts.d.ts
755
766
  /**
756
767
  * Parse rule names from rule string or string[] definitions
@@ -1613,4 +1624,4 @@ declare class ValidationException extends Error {
1613
1624
  getResponse(): any;
1614
1625
  }
1615
1626
  //#endregion
1616
- export { BaseValidationRuleClass, BaseValidator, CustomAttributes, CustomErrors, CustomMessages, CustomParamableValidationRuleName, CustomPlainRuleName, CustomValidationRuleNameMap, CustomValidationRules, DotPaths, ErrorBag, ErrorMessage, Errors, ExtendedRules, ExtractRules, FieldMessages, GenericCallable, GenericObject, IDatabaseDriver, IMessageBag, IValidationRule, IValidator, ImplicitAttributes, ImplicitRule, InitialRule, InitialRules, Lang, MessageBag, Messages, MessagesForRules, NestedStringMap, ParamableValidationRuleName, Password, PlainRuleName, ReplaceAttributeInterface, Rules, RulesForData, TRule, ValidatedByRules, ValidationCallback, ValidationDataInterface, ValidationDatabaseExistsInput, ValidationException, ValidationMessageProvider, ValidationRule, ValidationRuleCallable, ValidationRuleName, ValidationRuleParserInterface, ValidationRuleSet, ValidationServiceProvider, ValidationValueInspector, Validator, ValidatorPlugin, ValidatorPluginApi, addImplicitRule, buildValidationMethodName, compare, convertValuesToBoolean, convertValuesToNull, convertValuesToNumber, deepEqual, deepFind, deepFindMessage, deepSet, definePlugin, dotify, getFormattedAttribute, getKeyCombinations, getMessage, getNumericRules, getSize, getValidationMessageType, getValidationSize, getValidationValueInspector, getValidatorContext, isArrayOfRules, isImplicitRule, isInteger, isNumericRule, isObject, isRule, isSizeRule, make, mergeDeep, notRegex, plural, regex, register, registerImplicit, registerValueInspector, requiredIf, ruleIn, ruleNotIn, runWithValidatorContext, sameType, toDate, toSnakeCase, usePlugin, useValidatorContext };
1627
+ export { BaseValidationRuleClass, BaseValidator, CustomAttributes, CustomErrors, CustomMessages, CustomParamableValidationRuleName, CustomPlainRuleName, CustomValidationRuleNameMap, CustomValidationRules, DotPaths, ErrorBag, ErrorMessage, Errors, ExtendedRules, ExtractRules, FieldMessages, GenericCallable, GenericObject, IDatabaseDriver, IMessageBag, IValidationRule, IValidator, ImplicitAttributes, ImplicitRule, InitialRule, InitialRules, Lang, MessageBag, Messages, MessagesForRules, NestedStringMap, ParamableValidationRuleName, Password, PlainRuleName, ReplaceAttributeInterface, Rules, RulesForData, TRule, ValidatedByRules, ValidationCallback, ValidationDataInterface, ValidationDatabaseExistsInput, ValidationException, ValidationMessageProvider, ValidationRule, ValidationRuleAutocompleteKind, ValidationRuleAutocompleteMap, ValidationRuleCallable, ValidationRuleEntry, ValidationRuleName, ValidationRuleParserInterface, ValidationRuleSet, ValidationServiceProvider, ValidationValueInspector, Validator, ValidatorPlugin, ValidatorPluginApi, addImplicitRule, buildValidationMethodName, compare, convertValuesToBoolean, convertValuesToNull, convertValuesToNumber, deepEqual, deepFind, deepFindMessage, deepSet, definePlugin, dotify, getFormattedAttribute, getKeyCombinations, getMessage, getNumericRules, getSize, getValidationMessageType, getValidationSize, getValidationValueInspector, getValidatorContext, isArrayOfRules, isImplicitRule, isInteger, isNumericRule, isObject, isRule, isSizeRule, make, mergeDeep, notRegex, plural, regex, register, registerImplicit, registerValueInspector, requiredIf, ruleIn, ruleNotIn, runWithValidatorContext, sameType, toDate, toSnakeCase, usePlugin, useValidatorContext };
package/dist/index.js CHANGED
@@ -2325,7 +2325,7 @@ var BaseValidator = class BaseValidator {
2325
2325
  [rule, parameters] = validationRuleParser.parse(rule);
2326
2326
  const keys = this.getExplicitKeys(attribute);
2327
2327
  if (keys.length > 0 && parameters.length > 0) parameters = this.replaceAsterisksInParameters(parameters, keys);
2328
- const value = deepFind(this.data, attribute);
2328
+ const value = this.getAttributeValue(attribute);
2329
2329
  const validatable = this.isValidatable(attribute, value, rule);
2330
2330
  if (rule instanceof IRuleContract) return validatable ? this.validateUsingCustomRule(attribute, value, rule) : void 0;
2331
2331
  const method = `validate${buildValidationMethodName(rule)}`;
@@ -2393,14 +2393,14 @@ var BaseValidator = class BaseValidator {
2393
2393
  * Determine if the attribute is validatable.
2394
2394
  */
2395
2395
  isValidatable(attribute, value, rule) {
2396
- return this.presentOrRuleIsImplicit(attribute, value, rule) && this.passesOptionalCheck(attribute) && this.isNotNullIfMarkedAsNullable(attribute, rule);
2396
+ return this.presentOrRuleIsImplicit(attribute, value, rule) && this.passesOptionalCheck(attribute) && this.isNotNullIfMarkedAsNullable(attribute, value, rule);
2397
2397
  }
2398
2398
  /**
2399
2399
  * Determine if the field is present, or the rule implies required.
2400
2400
  */
2401
2401
  presentOrRuleIsImplicit(attribute, value, rule) {
2402
2402
  if (typeof value === "string" && value.trim() === "") return isImplicitRule(rule);
2403
- return typeof deepFind(this.data, attribute) !== "undefined" || isImplicitRule(rule);
2403
+ return typeof value !== "undefined" || isImplicitRule(rule);
2404
2404
  }
2405
2405
  /**
2406
2406
  * Determine if the attribute passes any optional check.
@@ -2408,14 +2408,23 @@ var BaseValidator = class BaseValidator {
2408
2408
  passesOptionalCheck(attribute) {
2409
2409
  if (!validationRuleParser.hasRule(attribute, ["sometimes"], this.rules)) return true;
2410
2410
  const data = validationData.initializeAndGatherData(attribute, this.data);
2411
- return Object.prototype.hasOwnProperty.call(data, attribute) || Object.prototype.hasOwnProperty.call(this.data, attribute);
2411
+ const requestFiles = validationData.initializeAndGatherData(attribute, this.getContext().requestFiles ?? {});
2412
+ return Object.prototype.hasOwnProperty.call(data, attribute) || Object.prototype.hasOwnProperty.call(this.data, attribute) || Object.prototype.hasOwnProperty.call(requestFiles, attribute) || Object.prototype.hasOwnProperty.call(this.getContext().requestFiles ?? {}, attribute);
2412
2413
  }
2413
2414
  /**
2414
2415
  * Determine if the attribute fails the nullable check.
2415
2416
  */
2416
- isNotNullIfMarkedAsNullable(attribute, rule) {
2417
+ isNotNullIfMarkedAsNullable(attribute, value, rule) {
2417
2418
  if (isImplicitRule(rule) || !validationRuleParser.hasRule(attribute, ["nullable"], this.rules)) return true;
2418
- return deepFind(this.data, attribute) !== null;
2419
+ return value !== null;
2420
+ }
2421
+ /**
2422
+ * Resolve an attribute value from validator data first, then request-scoped file context.
2423
+ */
2424
+ getAttributeValue(attribute) {
2425
+ const dataValue = deepFind(this.data, attribute);
2426
+ if (typeof dataValue !== "undefined") return dataValue;
2427
+ return deepFind(this.getContext().requestFiles ?? {}, attribute);
2419
2428
  }
2420
2429
  /**
2421
2430
  * Get the primary attribute name
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kanun",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Framework-agnostic TypeScript-first validation library.",
5
5
  "type": "module",
6
6
  "files": [