kanun 1.0.8 → 1.0.10

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/dist/index.cjs CHANGED
@@ -3330,6 +3330,19 @@ var Validator = class Validator {
3330
3330
  };
3331
3331
  }
3332
3332
  /**
3333
+ * Prefer request-scoped uploaded files over scalar placeholder body values.
3334
+ *
3335
+ * @param attribute
3336
+ * @returns
3337
+ */
3338
+ getValidatedAttributeValue(attribute) {
3339
+ const dataValue = deepFind(this.data, attribute);
3340
+ const requestFileValue = deepFind(this.getContext().requestFiles ?? {}, attribute);
3341
+ if (typeof requestFileValue === "undefined") return dataValue;
3342
+ if (typeof dataValue === "undefined" || dataValue === null || typeof dataValue === "string" || typeof dataValue === "number" || typeof dataValue === "boolean") return requestFileValue;
3343
+ return dataValue;
3344
+ }
3345
+ /**
3333
3346
  * Get the data that passed validation.
3334
3347
  */
3335
3348
  validatedData() {
@@ -3338,8 +3351,7 @@ var Validator = class Validator {
3338
3351
  const clean = {};
3339
3352
  for (const key of validKeys) {
3340
3353
  if (excluded.has(key)) continue;
3341
- const value = deepFind(this.data, key);
3342
- const resolvedValue = typeof value !== "undefined" ? value : deepFind(this.getContext().requestFiles ?? {}, key);
3354
+ const resolvedValue = this.getValidatedAttributeValue(key);
3343
3355
  if (typeof resolvedValue !== "undefined") deepSet(clean, key, resolvedValue);
3344
3356
  }
3345
3357
  return clean;
package/dist/index.d.ts CHANGED
@@ -119,6 +119,7 @@ declare class RequiredIf extends BaseRule {
119
119
  //#region src/Contracts/ValidationRuleName.d.ts
120
120
  type ValidationRuleAutocompleteKind = 'plain' | 'paramable';
121
121
  interface ValidationRuleAutocompleteMap {}
122
+ interface ValidationRuleOutputTypeMap {}
122
123
  /**
123
124
  * Backward-compatible alias for older plugin augmentations.
124
125
  */
@@ -772,7 +773,12 @@ declare abstract class IValidationRule {
772
773
  * Parse rule names from rule string or string[] definitions
773
774
  */
774
775
  type ExtractRules<R> = R extends string ? R extends `${infer Head}|${infer Tail}` ? Head extends `${infer Rule}:${string}` ? Rule | ExtractRules<Tail> : Head | ExtractRules<Tail> : R extends `${infer Rule}:${string}` ? Rule : R : R extends string[] ? ExtractRules<R[number]> : never;
775
- type ValidatedByRules<D extends Record<string, any>, R extends RulesForData<D>> = { [K in Extract<keyof R, keyof D>]: D[K] };
776
+ type ValidatedData<T> = { [K in keyof T]: T[K] };
777
+ type RuleOutputKey<T extends string> = T extends `${infer Root}.*${string}` ? Root : T extends `${infer Root}.${string}` ? Root : T;
778
+ type RuleOutputKeys<R extends Record<string, any>> = RuleOutputKey<Extract<keyof R, string>>;
779
+ type RuleOutputOverride<R> = 'files' extends ExtractRules<R> ? ('files' extends keyof ValidationRuleOutputTypeMap ? ValidationRuleOutputTypeMap['files'] : never) : ValidationRuleOutputTypeMap[Extract<ExtractRules<R>, keyof ValidationRuleOutputTypeMap>];
780
+ type FieldOutputValue<D extends Record<string, any>, K extends string, FieldRules> = K extends keyof D ? [RuleOutputOverride<FieldRules>] extends [never] ? D[K] : D[K] extends RuleOutputOverride<FieldRules> ? D[K] : RuleOutputOverride<FieldRules> : [RuleOutputOverride<FieldRules>] extends [never] ? any : RuleOutputOverride<FieldRules>;
781
+ type ValidatedByRules<D extends Record<string, any>, R extends RulesForData<D>> = ValidatedData<{ [K in RuleOutputKeys<R>]: FieldOutputValue<D, K, K extends keyof R ? R[K] : never> }>;
776
782
  /**
777
783
  * Flatten data structure into dot-notation keys
778
784
  * including wildcards (*) for arrays.
@@ -1197,7 +1203,7 @@ declare class Validator<D extends Record<string, any> = any, R extends RulesForD
1197
1203
  * @param bagName
1198
1204
  * @returns
1199
1205
  */
1200
- validateWithBag(bagName: string): Promise<ValidatedByRules<D, R>>;
1206
+ validateWithBag(bagName: string): Promise<{ [K_1 in Extract<keyof R, string> extends infer T_1 ? T_1 extends Extract<keyof R, string> ? T_1 extends `${infer Root}.*${string}` ? Root : T_1 extends `${infer Root_1}.${string}` ? Root_1 : T_1 : never : never]: K_1 extends keyof D ? ["files" extends ExtractRules<K_1 extends keyof R ? R[K_1] : never> ? never : ValidationRuleOutputTypeMap[Extract<ExtractRules<K_1 extends keyof R ? R[K_1] : never>, never>]] extends [never] ? D[K_1] : D[K_1] extends ("files" extends ExtractRules<K_1 extends keyof R ? R[K_1] : never> ? never : ValidationRuleOutputTypeMap[Extract<ExtractRules<K_1 extends keyof R ? R[K_1] : never>, never>]) ? D[K_1] : "files" extends ExtractRules<K_1 extends keyof R ? R[K_1] : never> ? never : ValidationRuleOutputTypeMap[Extract<ExtractRules<K_1 extends keyof R ? R[K_1] : never>, never>] : ["files" extends ExtractRules<K_1 extends keyof R ? R[K_1] : never> ? never : ValidationRuleOutputTypeMap[Extract<ExtractRules<K_1 extends keyof R ? R[K_1] : never>, never>]] extends [never] ? any : "files" extends ExtractRules<K_1 extends keyof R ? R[K_1] : never> ? never : ValidationRuleOutputTypeMap[Extract<ExtractRules<K_1 extends keyof R ? R[K_1] : never>, never>] } extends infer T ? { [K in keyof T]: T[K] } : never>;
1201
1207
  /**
1202
1208
  * Stop validation on first failure.
1203
1209
  */
@@ -1217,6 +1223,13 @@ declare class Validator<D extends Record<string, any> = any, R extends RulesForD
1217
1223
  * @returns The current context object
1218
1224
  */
1219
1225
  getContext(): Record<string, any>;
1226
+ /**
1227
+ * Prefer request-scoped uploaded files over scalar placeholder body values.
1228
+ *
1229
+ * @param attribute
1230
+ * @returns
1231
+ */
1232
+ private getValidatedAttributeValue;
1220
1233
  /**
1221
1234
  * Get the data that passed validation.
1222
1235
  */
@@ -1629,4 +1642,4 @@ declare class ValidationException extends Error {
1629
1642
  getResponse(): any;
1630
1643
  }
1631
1644
  //#endregion
1632
- 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 };
1645
+ 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, ValidationRuleOutputTypeMap, 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
@@ -3300,6 +3300,19 @@ var Validator = class Validator {
3300
3300
  };
3301
3301
  }
3302
3302
  /**
3303
+ * Prefer request-scoped uploaded files over scalar placeholder body values.
3304
+ *
3305
+ * @param attribute
3306
+ * @returns
3307
+ */
3308
+ getValidatedAttributeValue(attribute) {
3309
+ const dataValue = deepFind(this.data, attribute);
3310
+ const requestFileValue = deepFind(this.getContext().requestFiles ?? {}, attribute);
3311
+ if (typeof requestFileValue === "undefined") return dataValue;
3312
+ if (typeof dataValue === "undefined" || dataValue === null || typeof dataValue === "string" || typeof dataValue === "number" || typeof dataValue === "boolean") return requestFileValue;
3313
+ return dataValue;
3314
+ }
3315
+ /**
3303
3316
  * Get the data that passed validation.
3304
3317
  */
3305
3318
  validatedData() {
@@ -3308,8 +3321,7 @@ var Validator = class Validator {
3308
3321
  const clean = {};
3309
3322
  for (const key of validKeys) {
3310
3323
  if (excluded.has(key)) continue;
3311
- const value = deepFind(this.data, key);
3312
- const resolvedValue = typeof value !== "undefined" ? value : deepFind(this.getContext().requestFiles ?? {}, key);
3324
+ const resolvedValue = this.getValidatedAttributeValue(key);
3313
3325
  if (typeof resolvedValue !== "undefined") deepSet(clean, key, resolvedValue);
3314
3326
  }
3315
3327
  return clean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kanun",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "Framework-agnostic TypeScript-first validation library.",
5
5
  "type": "module",
6
6
  "files": [
@@ -44,11 +44,13 @@
44
44
  "@types/multer": "^2.1.0",
45
45
  "@types/node": "^20.11.0",
46
46
  "@vitest/coverage-v8": "4.0.18",
47
+ "axios": "^1.13.6",
47
48
  "barrelize": "^1.7.4",
48
49
  "eslint": "^10.0.2",
49
50
  "express": "^5.2.1",
50
51
  "fastify": "^5.8.2",
51
52
  "h3": "2.0.1-rc.16",
53
+ "happy-dom": "^20.8.4",
52
54
  "hono": "^4.12.8",
53
55
  "multer": "^2.1.1",
54
56
  "tsdown": "0.21.0-beta.2",
@@ -64,6 +66,7 @@
64
66
  "scripts": {
65
67
  "lint": "eslint",
66
68
  "test": "vitest",
69
+ "test:browser": "vitest --project browser",
67
70
  "test:file-plugin": "vitest --watch=false tests/file-plugin-validator.test.ts",
68
71
  "test:coverage": "vitest --coverage --watch=false",
69
72
  "build": "tsdown",
@@ -73,6 +76,7 @@
73
76
  "barrel": "barrelize",
74
77
  "docs:dev": "vitepress dev docs",
75
78
  "docs:build": "vitepress build docs",
76
- "docs:preview": "vitepress preview docs"
79
+ "docs:preview": "vitepress preview docs",
80
+ "publish:packages": "pnpm publish --filter './packages/*' --access public"
77
81
  }
78
82
  }