kanun 1.0.8 → 1.0.9

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
@@ -772,7 +772,10 @@ declare abstract class IValidationRule {
772
772
  * Parse rule names from rule string or string[] definitions
773
773
  */
774
774
  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] };
775
+ type ValidatedData<T> = { [K in keyof T]: T[K] };
776
+ type RuleOutputKey<T extends string> = T extends `${infer Root}.*${string}` ? Root : T extends `${infer Root}.${string}` ? Root : T;
777
+ type RuleOutputKeys<R extends Record<string, any>> = RuleOutputKey<Extract<keyof R, string>>;
778
+ type ValidatedByRules<D extends Record<string, any>, R extends RulesForData<D>> = ValidatedData<{ [K in Extract<RuleOutputKeys<R>, keyof D>]: D[K] } & { [K in Exclude<RuleOutputKeys<R>, keyof D>]: any }>;
776
779
  /**
777
780
  * Flatten data structure into dot-notation keys
778
781
  * including wildcards (*) for arrays.
@@ -1197,7 +1200,7 @@ declare class Validator<D extends Record<string, any> = any, R extends RulesForD
1197
1200
  * @param bagName
1198
1201
  * @returns
1199
1202
  */
1200
- validateWithBag(bagName: string): Promise<ValidatedByRules<D, R>>;
1203
+ validateWithBag(bagName: string): Promise<{ [K_1 in Extract<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, keyof D>]: D[K_1] } & { [K_2 in Exclude<Extract<keyof R, string> extends infer T_2 ? T_2 extends Extract<keyof R, string> ? T_2 extends `${infer Root}.*${string}` ? Root : T_2 extends `${infer Root_1}.${string}` ? Root_1 : T_2 : never : never, keyof D>]: any } extends infer T ? { [K in keyof T]: T[K] } : never>;
1201
1204
  /**
1202
1205
  * Stop validation on first failure.
1203
1206
  */
@@ -1217,6 +1220,13 @@ declare class Validator<D extends Record<string, any> = any, R extends RulesForD
1217
1220
  * @returns The current context object
1218
1221
  */
1219
1222
  getContext(): Record<string, any>;
1223
+ /**
1224
+ * Prefer request-scoped uploaded files over scalar placeholder body values.
1225
+ *
1226
+ * @param attribute
1227
+ * @returns
1228
+ */
1229
+ private getValidatedAttributeValue;
1220
1230
  /**
1221
1231
  * Get the data that passed validation.
1222
1232
  */
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.9",
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
  }