kanun 1.0.7 → 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 +17 -13
- package/dist/index.d.ts +12 -7
- package/dist/index.js +17 -13
- package/package.json +6 -2
package/dist/index.cjs
CHANGED
|
@@ -2301,7 +2301,6 @@ var BaseValidator = class BaseValidator {
|
|
|
2301
2301
|
*/
|
|
2302
2302
|
withContext(context = {}) {
|
|
2303
2303
|
this.context = context;
|
|
2304
|
-
this.addRules(this.initalRules);
|
|
2305
2304
|
return this;
|
|
2306
2305
|
}
|
|
2307
2306
|
/**
|
|
@@ -2552,8 +2551,7 @@ var BaseValidator = class BaseValidator {
|
|
|
2552
2551
|
* Parse the given rules add assign them to the current rules
|
|
2553
2552
|
*/
|
|
2554
2553
|
addRules(rules) {
|
|
2555
|
-
const
|
|
2556
|
-
const response = validationRuleParser.explodeRules(dotify(rules, true), availableData);
|
|
2554
|
+
const response = validationRuleParser.explodeRules(dotify(rules, true), this.data);
|
|
2557
2555
|
this.rules = response.rules;
|
|
2558
2556
|
this.implicitAttributes = response.implicitAttributes;
|
|
2559
2557
|
}
|
|
@@ -2660,17 +2658,11 @@ var BaseValidator = class BaseValidator {
|
|
|
2660
2658
|
}
|
|
2661
2659
|
/**
|
|
2662
2660
|
* Resolve an attribute value from validator data first, then request-scoped file context.
|
|
2663
|
-
* When the data value is empty (null or empty string), prefer a file from requestFiles
|
|
2664
|
-
* because framework body-parsers commonly set file input fields to '' or null.
|
|
2665
|
-
*
|
|
2666
|
-
* @param attribute
|
|
2667
|
-
* @returns
|
|
2668
2661
|
*/
|
|
2669
2662
|
getAttributeValue(attribute) {
|
|
2670
2663
|
const dataValue = deepFind(this.data, attribute);
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
return dataValue;
|
|
2664
|
+
if (typeof dataValue !== "undefined") return dataValue;
|
|
2665
|
+
return deepFind(this.getContext().requestFiles ?? {}, attribute);
|
|
2674
2666
|
}
|
|
2675
2667
|
/**
|
|
2676
2668
|
* Get the primary attribute name
|
|
@@ -3338,6 +3330,19 @@ var Validator = class Validator {
|
|
|
3338
3330
|
};
|
|
3339
3331
|
}
|
|
3340
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
|
+
/**
|
|
3341
3346
|
* Get the data that passed validation.
|
|
3342
3347
|
*/
|
|
3343
3348
|
validatedData() {
|
|
@@ -3346,8 +3351,7 @@ var Validator = class Validator {
|
|
|
3346
3351
|
const clean = {};
|
|
3347
3352
|
for (const key of validKeys) {
|
|
3348
3353
|
if (excluded.has(key)) continue;
|
|
3349
|
-
const
|
|
3350
|
-
const resolvedValue = typeof value !== "undefined" ? value : deepFind(this.getContext().requestFiles ?? {}, key);
|
|
3354
|
+
const resolvedValue = this.getValidatedAttributeValue(key);
|
|
3351
3355
|
if (typeof resolvedValue !== "undefined") deepSet(clean, key, resolvedValue);
|
|
3352
3356
|
}
|
|
3353
3357
|
return clean;
|
package/dist/index.d.ts
CHANGED
|
@@ -610,11 +610,6 @@ declare class BaseValidator<D extends GenericObject = GenericObject> {
|
|
|
610
610
|
private isNotNullIfMarkedAsNullable;
|
|
611
611
|
/**
|
|
612
612
|
* Resolve an attribute value from validator data first, then request-scoped file context.
|
|
613
|
-
* When the data value is empty (null or empty string), prefer a file from requestFiles
|
|
614
|
-
* because framework body-parsers commonly set file input fields to '' or null.
|
|
615
|
-
*
|
|
616
|
-
* @param attribute
|
|
617
|
-
* @returns
|
|
618
613
|
*/
|
|
619
614
|
private getAttributeValue;
|
|
620
615
|
/**
|
|
@@ -777,7 +772,10 @@ declare abstract class IValidationRule {
|
|
|
777
772
|
* Parse rule names from rule string or string[] definitions
|
|
778
773
|
*/
|
|
779
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;
|
|
780
|
-
type
|
|
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 }>;
|
|
781
779
|
/**
|
|
782
780
|
* Flatten data structure into dot-notation keys
|
|
783
781
|
* including wildcards (*) for arrays.
|
|
@@ -1202,7 +1200,7 @@ declare class Validator<D extends Record<string, any> = any, R extends RulesForD
|
|
|
1202
1200
|
* @param bagName
|
|
1203
1201
|
* @returns
|
|
1204
1202
|
*/
|
|
1205
|
-
validateWithBag(bagName: string): Promise<
|
|
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>;
|
|
1206
1204
|
/**
|
|
1207
1205
|
* Stop validation on first failure.
|
|
1208
1206
|
*/
|
|
@@ -1222,6 +1220,13 @@ declare class Validator<D extends Record<string, any> = any, R extends RulesForD
|
|
|
1222
1220
|
* @returns The current context object
|
|
1223
1221
|
*/
|
|
1224
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;
|
|
1225
1230
|
/**
|
|
1226
1231
|
* Get the data that passed validation.
|
|
1227
1232
|
*/
|
package/dist/index.js
CHANGED
|
@@ -2271,7 +2271,6 @@ var BaseValidator = class BaseValidator {
|
|
|
2271
2271
|
*/
|
|
2272
2272
|
withContext(context = {}) {
|
|
2273
2273
|
this.context = context;
|
|
2274
|
-
this.addRules(this.initalRules);
|
|
2275
2274
|
return this;
|
|
2276
2275
|
}
|
|
2277
2276
|
/**
|
|
@@ -2522,8 +2521,7 @@ var BaseValidator = class BaseValidator {
|
|
|
2522
2521
|
* Parse the given rules add assign them to the current rules
|
|
2523
2522
|
*/
|
|
2524
2523
|
addRules(rules) {
|
|
2525
|
-
const
|
|
2526
|
-
const response = validationRuleParser.explodeRules(dotify(rules, true), availableData);
|
|
2524
|
+
const response = validationRuleParser.explodeRules(dotify(rules, true), this.data);
|
|
2527
2525
|
this.rules = response.rules;
|
|
2528
2526
|
this.implicitAttributes = response.implicitAttributes;
|
|
2529
2527
|
}
|
|
@@ -2630,17 +2628,11 @@ var BaseValidator = class BaseValidator {
|
|
|
2630
2628
|
}
|
|
2631
2629
|
/**
|
|
2632
2630
|
* Resolve an attribute value from validator data first, then request-scoped file context.
|
|
2633
|
-
* When the data value is empty (null or empty string), prefer a file from requestFiles
|
|
2634
|
-
* because framework body-parsers commonly set file input fields to '' or null.
|
|
2635
|
-
*
|
|
2636
|
-
* @param attribute
|
|
2637
|
-
* @returns
|
|
2638
2631
|
*/
|
|
2639
2632
|
getAttributeValue(attribute) {
|
|
2640
2633
|
const dataValue = deepFind(this.data, attribute);
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
return dataValue;
|
|
2634
|
+
if (typeof dataValue !== "undefined") return dataValue;
|
|
2635
|
+
return deepFind(this.getContext().requestFiles ?? {}, attribute);
|
|
2644
2636
|
}
|
|
2645
2637
|
/**
|
|
2646
2638
|
* Get the primary attribute name
|
|
@@ -3308,6 +3300,19 @@ var Validator = class Validator {
|
|
|
3308
3300
|
};
|
|
3309
3301
|
}
|
|
3310
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
|
+
/**
|
|
3311
3316
|
* Get the data that passed validation.
|
|
3312
3317
|
*/
|
|
3313
3318
|
validatedData() {
|
|
@@ -3316,8 +3321,7 @@ var Validator = class Validator {
|
|
|
3316
3321
|
const clean = {};
|
|
3317
3322
|
for (const key of validKeys) {
|
|
3318
3323
|
if (excluded.has(key)) continue;
|
|
3319
|
-
const
|
|
3320
|
-
const resolvedValue = typeof value !== "undefined" ? value : deepFind(this.getContext().requestFiles ?? {}, key);
|
|
3324
|
+
const resolvedValue = this.getValidatedAttributeValue(key);
|
|
3321
3325
|
if (typeof resolvedValue !== "undefined") deepSet(clean, key, resolvedValue);
|
|
3322
3326
|
}
|
|
3323
3327
|
return clean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kanun",
|
|
3
|
-
"version": "1.0.
|
|
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
|
}
|