perfect-payload 2.0.0-beta.2 → 2.0.0-beta.4
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/framework.js +5 -21
- package/dist/index.d.ts +7 -4
- package/dist/index.js +108 -68
- package/dist/types/framework.d.ts +2 -2
- package/dist/types/options.d.ts +3 -3
- package/dist/types/rules.d.ts +4 -3
- package/package.json +1 -1
package/dist/framework.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { perfectPayloadForFramework, perfectPayloadAsyncForFramework, } from "./index.js";
|
|
2
2
|
const SUPPORTED_REQUEST_SOURCES = [
|
|
3
3
|
"headers",
|
|
4
4
|
"params",
|
|
@@ -44,7 +44,7 @@ export function validateFrameworkSources({ data = {}, rule, options = {}, } = {}
|
|
|
44
44
|
const sourceData = data?.[source] !== undefined && data?.[source] !== null
|
|
45
45
|
? data[source]
|
|
46
46
|
: {};
|
|
47
|
-
const result =
|
|
47
|
+
const result = perfectPayloadForFramework(sourceData, frameworkRule[source], options, source);
|
|
48
48
|
if (result.valid === true) {
|
|
49
49
|
validatedPayload[source] = result.validatedPayload;
|
|
50
50
|
continue;
|
|
@@ -54,15 +54,7 @@ export function validateFrameworkSources({ data = {}, rule, options = {}, } = {}
|
|
|
54
54
|
invalidResponse = response;
|
|
55
55
|
}
|
|
56
56
|
for (const error of result.errors ?? []) {
|
|
57
|
-
|
|
58
|
-
errors.push(error);
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
errors.push({
|
|
62
|
-
...error,
|
|
63
|
-
path: `${source}.${error.path}`,
|
|
64
|
-
});
|
|
65
|
-
}
|
|
57
|
+
errors.push(error);
|
|
66
58
|
}
|
|
67
59
|
}
|
|
68
60
|
if (errors.length > 0) {
|
|
@@ -86,7 +78,7 @@ export async function validateFrameworkSourcesAsync({ data = {}, rule, options =
|
|
|
86
78
|
const sourceData = data?.[source] !== undefined && data?.[source] !== null
|
|
87
79
|
? data[source]
|
|
88
80
|
: {};
|
|
89
|
-
const result = await
|
|
81
|
+
const result = await perfectPayloadAsyncForFramework(sourceData, frameworkRule[source], options, source);
|
|
90
82
|
return {
|
|
91
83
|
source,
|
|
92
84
|
result,
|
|
@@ -105,15 +97,7 @@ export async function validateFrameworkSourcesAsync({ data = {}, rule, options =
|
|
|
105
97
|
invalidResponse = response;
|
|
106
98
|
}
|
|
107
99
|
for (const error of result.errors ?? []) {
|
|
108
|
-
|
|
109
|
-
errors.push(error);
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
errors.push({
|
|
113
|
-
...error,
|
|
114
|
-
path: `${source}.${error.path}`,
|
|
115
|
-
});
|
|
116
|
-
}
|
|
100
|
+
errors.push(error);
|
|
117
101
|
}
|
|
118
102
|
}
|
|
119
103
|
if (errors.length > 0) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ValidationRules } from "./types/rules.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ValidationOptions, StructuredErrorOptions, PrettyErrorOptions } from "./types/options.js";
|
|
3
3
|
import type { ValidationResult } from "./types/results.js";
|
|
4
4
|
type LegacyPayload = Record<string, any>;
|
|
5
5
|
type LegacyValidationRules = Record<string, Record<string, any>>;
|
|
@@ -25,8 +25,11 @@ interface LegacyValidationResult {
|
|
|
25
25
|
export declare function perfectPayloadV1(data?: LegacyPayload, dataValidationRule?: LegacyValidationRules, validPayloadResponse?: LegacyValidResponse, inValidPayloadResponse?: LegacyInvalidResponse): LegacyValidationResult;
|
|
26
26
|
export declare function perfectPayload<T extends object = Record<string, unknown>>(data: Record<string, unknown>, dataValidationRule: ValidationRules, options: PrettyErrorOptions): ValidationResult<T, string>;
|
|
27
27
|
export declare function perfectPayload<T extends object = Record<string, unknown>>(data?: Record<string, unknown>, dataValidationRule?: ValidationRules, options?: StructuredErrorOptions): ValidationResult<T>;
|
|
28
|
-
export declare function perfectPayload<T extends object = Record<string, unknown>>(data: Record<string, unknown>, dataValidationRule: ValidationRules, options:
|
|
28
|
+
export declare function perfectPayload<T extends object = Record<string, unknown>>(data: Record<string, unknown>, dataValidationRule: ValidationRules, options: ValidationOptions): ValidationResult<T> | ValidationResult<T, string>;
|
|
29
|
+
export declare function perfectPayloadForFramework<T extends object = Record<string, unknown>>(data: Record<string, unknown>, dataValidationRule: ValidationRules, options: ValidationOptions | undefined, source: string): ValidationResult<T> | ValidationResult<T, string>;
|
|
29
30
|
export declare function perfectPayloadAsync<T extends object = Record<string, unknown>>(data: Record<string, unknown>, dataValidationRule: ValidationRules, options: PrettyErrorOptions): Promise<ValidationResult<T, string>>;
|
|
30
31
|
export declare function perfectPayloadAsync<T extends object = Record<string, unknown>>(data?: Record<string, unknown>, dataValidationRule?: ValidationRules, options?: StructuredErrorOptions): Promise<ValidationResult<T>>;
|
|
31
|
-
export declare function perfectPayloadAsync<T extends object = Record<string, unknown>>(data: Record<string, unknown>, dataValidationRule: ValidationRules, options:
|
|
32
|
-
export
|
|
32
|
+
export declare function perfectPayloadAsync<T extends object = Record<string, unknown>>(data: Record<string, unknown>, dataValidationRule: ValidationRules, options: ValidationOptions): Promise<ValidationResult<T> | ValidationResult<T, string>>;
|
|
33
|
+
export declare function perfectPayloadAsyncForFramework<T extends object = Record<string, unknown>>(data: Record<string, unknown>, dataValidationRule: ValidationRules, options: ValidationOptions | undefined, source: string): Promise<ValidationResult<T> | ValidationResult<T, string>>;
|
|
34
|
+
export type { AttributeValidationRules, ValidationRules, ValidationValueType, TransformFunction, CustomValidator, DependencyRule, DependencyRules, } from "./types/rules.js";
|
|
35
|
+
export type { ValidationOptions, StructuredErrorOptions, PrettyErrorOptions, UnknownFieldsMode, } from "./types/options.js";
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
const VALIDATION_RULE_ORDER = [
|
|
2
|
+
"allowNull",
|
|
3
|
+
"type",
|
|
4
|
+
"allowEmptyObject",
|
|
5
|
+
"allowEmptyArray",
|
|
6
|
+
"objectAttr",
|
|
7
|
+
"elementConstraints",
|
|
8
|
+
"minItems",
|
|
9
|
+
"maxItems",
|
|
10
|
+
"regex",
|
|
11
|
+
"minLength",
|
|
12
|
+
"maxLength",
|
|
13
|
+
"preventDecimal",
|
|
14
|
+
"min",
|
|
15
|
+
"max",
|
|
16
|
+
"range",
|
|
17
|
+
"dependency",
|
|
18
|
+
"customValidator",
|
|
19
|
+
];
|
|
1
20
|
let perfectPayloadV1DeprecationWarningShown = false;
|
|
2
21
|
function showPerfectPayloadV1DeprecationWarning() {
|
|
3
22
|
if (perfectPayloadV1DeprecationWarningShown)
|
|
@@ -443,6 +462,28 @@ export function perfectPayload(data = {}, dataValidationRule = {}, options = {})
|
|
|
443
462
|
}
|
|
444
463
|
return validationResult;
|
|
445
464
|
}
|
|
465
|
+
export function perfectPayloadForFramework(data, dataValidationRule, options = {}, source) {
|
|
466
|
+
const { unknownFields = "strip", prettyErrors = false, validPayloadResponse = {
|
|
467
|
+
statusCode: 200,
|
|
468
|
+
valid: true,
|
|
469
|
+
}, inValidPayloadResponse = {
|
|
470
|
+
statusCode: 400,
|
|
471
|
+
valid: false,
|
|
472
|
+
message: "One or more attribute values are invalid",
|
|
473
|
+
}, } = options ?? {};
|
|
474
|
+
const validationResult = perfectPayloadStructured(data, dataValidationRule, validPayloadResponse, inValidPayloadResponse, source, {
|
|
475
|
+
unknownFields,
|
|
476
|
+
});
|
|
477
|
+
if (prettyErrors &&
|
|
478
|
+
validationResult.valid === false &&
|
|
479
|
+
validationResult.errors.length) {
|
|
480
|
+
return {
|
|
481
|
+
...validationResult,
|
|
482
|
+
errors: validationResult.errors.map((error) => error.message),
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
return validationResult;
|
|
486
|
+
}
|
|
446
487
|
export async function perfectPayloadAsync(data = {}, dataValidationRule = {}, options = {}) {
|
|
447
488
|
const { validPayloadResponse = {
|
|
448
489
|
statusCode: 200,
|
|
@@ -486,6 +527,43 @@ export async function perfectPayloadAsync(data = {}, dataValidationRule = {}, op
|
|
|
486
527
|
}
|
|
487
528
|
return validationResult;
|
|
488
529
|
}
|
|
530
|
+
export async function perfectPayloadAsyncForFramework(data, dataValidationRule, options = {}, source) {
|
|
531
|
+
const { validPayloadResponse = {
|
|
532
|
+
statusCode: 200,
|
|
533
|
+
valid: true,
|
|
534
|
+
}, inValidPayloadResponse = {
|
|
535
|
+
statusCode: 400,
|
|
536
|
+
valid: false,
|
|
537
|
+
message: "One or more attribute values are invalid",
|
|
538
|
+
}, unknownFields = "strip", prettyErrors = false, } = options ?? {};
|
|
539
|
+
const validationResult = perfectPayloadStructured(data, dataValidationRule, validPayloadResponse, inValidPayloadResponse, source, {
|
|
540
|
+
skipCustomValidator: true,
|
|
541
|
+
unknownFields,
|
|
542
|
+
});
|
|
543
|
+
if (validationResult.valid === false && validationResult.errors.length) {
|
|
544
|
+
if (prettyErrors) {
|
|
545
|
+
return {
|
|
546
|
+
...validationResult,
|
|
547
|
+
errors: validationResult.errors.map((error) => error.message),
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
return validationResult;
|
|
551
|
+
}
|
|
552
|
+
const rowErrors = await runAsyncCustomValidators(validationResult.valid === true ? validationResult.validatedPayload : {}, dataValidationRule, source);
|
|
553
|
+
if (rowErrors.length > 0) {
|
|
554
|
+
if (prettyErrors) {
|
|
555
|
+
return {
|
|
556
|
+
...inValidPayloadResponse,
|
|
557
|
+
errors: rowErrors.map((error) => error.message),
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
return {
|
|
561
|
+
...inValidPayloadResponse,
|
|
562
|
+
errors: rowErrors,
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
return validationResult;
|
|
566
|
+
}
|
|
489
567
|
function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPayloadResponse = {
|
|
490
568
|
statusCode: 200,
|
|
491
569
|
valid: true,
|
|
@@ -493,7 +571,7 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
493
571
|
statusCode: 400,
|
|
494
572
|
valid: false,
|
|
495
573
|
message: "One or more attribute values are invalid",
|
|
496
|
-
}, basePath = "", options = {}) {
|
|
574
|
+
}, basePath = "", options = {}, rootPayload = data) {
|
|
497
575
|
let validatedPayload = {};
|
|
498
576
|
let rowErrors = [];
|
|
499
577
|
const skipCustomValidator = options?.skipCustomValidator === true;
|
|
@@ -506,6 +584,14 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
506
584
|
const nullAllowed = dataValidationRule?.[attributeName]?.["allowNull"] ?? true;
|
|
507
585
|
const isMandatoryField = attributeRules?.["mandatory"] ?? false;
|
|
508
586
|
const attrExist = Object.keys(data ?? {}).includes(attributeName);
|
|
587
|
+
const mandatoryValidationFailed = isMandatoryField && (!attrExist || attributeValue === "");
|
|
588
|
+
if (mandatoryValidationFailed) {
|
|
589
|
+
addNextError = false;
|
|
590
|
+
addStructuredError(rowErrors, attributePath, "REQUIRED", attributeRules?.["mandatoryError"] || `${attributePath} is mandatory`);
|
|
591
|
+
}
|
|
592
|
+
else if (!attrExist) {
|
|
593
|
+
addNextError = false;
|
|
594
|
+
}
|
|
509
595
|
// TRANSFORMATIONS START
|
|
510
596
|
// NO MULTI TRANSFORMATION
|
|
511
597
|
if (attributeRules?.lowercase === true &&
|
|
@@ -513,35 +599,41 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
513
599
|
throw new Error(`perfect-payload:- lowercase and uppercase cannot both be enabled for attribute ${attributePath}`);
|
|
514
600
|
}
|
|
515
601
|
// TRIM
|
|
516
|
-
if (
|
|
602
|
+
if (addNextError &&
|
|
603
|
+
attrExist &&
|
|
517
604
|
attributeValue !== null &&
|
|
518
605
|
attributeRules?.trim === true &&
|
|
519
606
|
typeof attributeValue === "string") {
|
|
520
607
|
attributeValue = attributeValue.trim();
|
|
521
608
|
}
|
|
522
609
|
// LOWERCASE
|
|
523
|
-
if (
|
|
610
|
+
if (addNextError &&
|
|
611
|
+
attrExist &&
|
|
524
612
|
attributeValue !== null &&
|
|
525
613
|
attributeRules?.lowercase === true &&
|
|
526
614
|
typeof attributeValue === "string") {
|
|
527
615
|
attributeValue = attributeValue.toLowerCase();
|
|
528
616
|
}
|
|
529
617
|
// UPPERCASE
|
|
530
|
-
if (
|
|
618
|
+
if (addNextError &&
|
|
619
|
+
attrExist &&
|
|
531
620
|
attributeValue !== null &&
|
|
532
621
|
attributeRules?.uppercase === true &&
|
|
533
622
|
typeof attributeValue === "string") {
|
|
534
623
|
attributeValue = attributeValue.toUpperCase();
|
|
535
624
|
}
|
|
536
625
|
// CUSTOM TRANSFORM
|
|
537
|
-
if (
|
|
626
|
+
if (addNextError &&
|
|
627
|
+
attrExist &&
|
|
538
628
|
attributeValue !== null &&
|
|
539
629
|
attributeRules?.transform !== undefined) {
|
|
540
630
|
const transformer = attributeRules.transform;
|
|
541
631
|
if (typeof transformer !== "function") {
|
|
542
632
|
throw new Error(`perfect-payload:- transform must be a function for attribute ${attributePath}`);
|
|
543
633
|
}
|
|
544
|
-
const transformedValue =
|
|
634
|
+
const transformedValue = options.elementIndex !== undefined
|
|
635
|
+
? transformer(attributeValue, options.elementIndex, rootPayload)
|
|
636
|
+
: transformer(attributeValue, rootPayload);
|
|
545
637
|
if (transformedValue &&
|
|
546
638
|
typeof transformedValue === "object" &&
|
|
547
639
|
"then" in transformedValue &&
|
|
@@ -554,24 +646,11 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
554
646
|
attributeValue = transformedValue;
|
|
555
647
|
}
|
|
556
648
|
// TRANSFORMATIONS END
|
|
557
|
-
for (const ruleName
|
|
649
|
+
for (const ruleName of VALIDATION_RULE_ORDER) {
|
|
650
|
+
if (!(ruleName in attributeRules)) {
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
558
653
|
switch (ruleName) {
|
|
559
|
-
// ==================================================
|
|
560
|
-
// MANDATORY
|
|
561
|
-
// ==================================================
|
|
562
|
-
case "mandatory":
|
|
563
|
-
if (isMandatoryField && (!attrExist || attributeValue === "")) {
|
|
564
|
-
addNextError = false;
|
|
565
|
-
addStructuredError(rowErrors, attributePath, "REQUIRED", attributeRules?.["mandatoryError"] ||
|
|
566
|
-
`${attributePath} is mandatory`);
|
|
567
|
-
}
|
|
568
|
-
else if (!attrExist) {
|
|
569
|
-
addNextError = false;
|
|
570
|
-
}
|
|
571
|
-
break;
|
|
572
|
-
// ==================================================
|
|
573
|
-
// NULL
|
|
574
|
-
// ==================================================
|
|
575
654
|
case "allowNull":
|
|
576
655
|
if (addNextError && attributeValue === null) {
|
|
577
656
|
if (!attributeRules?.[ruleName]) {
|
|
@@ -581,9 +660,6 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
581
660
|
}
|
|
582
661
|
}
|
|
583
662
|
break;
|
|
584
|
-
// ==================================================
|
|
585
|
-
// EMPTY OBJECT
|
|
586
|
-
// ==================================================
|
|
587
663
|
case "allowEmptyObject":
|
|
588
664
|
if (addNextError) {
|
|
589
665
|
if (!attributeRules?.["allowEmptyObject"] &&
|
|
@@ -595,9 +671,6 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
595
671
|
}
|
|
596
672
|
}
|
|
597
673
|
break;
|
|
598
|
-
// ==================================================
|
|
599
|
-
// EMPTY ARRAY
|
|
600
|
-
// ==================================================
|
|
601
674
|
case "allowEmptyArray":
|
|
602
675
|
if (addNextError) {
|
|
603
676
|
if (!attributeRules?.["allowEmptyArray"] &&
|
|
@@ -609,9 +682,6 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
609
682
|
}
|
|
610
683
|
}
|
|
611
684
|
break;
|
|
612
|
-
// ==================================================
|
|
613
|
-
// ARRAY ELEMENT CONSTRAINTS
|
|
614
|
-
// ==================================================
|
|
615
685
|
case "elementConstraints":
|
|
616
686
|
if (addNextError) {
|
|
617
687
|
if (isArray(attributeValue) && attributeValue.length > 0) {
|
|
@@ -632,7 +702,10 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
632
702
|
statusCode: 400,
|
|
633
703
|
valid: false,
|
|
634
704
|
message: "One or more attribute values are invalid",
|
|
635
|
-
}, "",
|
|
705
|
+
}, "", {
|
|
706
|
+
...options,
|
|
707
|
+
elementIndex,
|
|
708
|
+
}, rootPayload);
|
|
636
709
|
if (elementResult.valid === false &&
|
|
637
710
|
elementResult.errors.length > 0) {
|
|
638
711
|
const firstElementError = elementResult.errors[0];
|
|
@@ -698,9 +771,6 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
698
771
|
}
|
|
699
772
|
break;
|
|
700
773
|
}
|
|
701
|
-
// ==================================================
|
|
702
|
-
// REGEX
|
|
703
|
-
// ==================================================
|
|
704
774
|
case "regex":
|
|
705
775
|
if (addNextError) {
|
|
706
776
|
if (!isPassedRegex(attributeRules[ruleName], attributeValue)) {
|
|
@@ -710,9 +780,6 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
710
780
|
}
|
|
711
781
|
}
|
|
712
782
|
break;
|
|
713
|
-
// ==================================================
|
|
714
|
-
// TYPE
|
|
715
|
-
// ==================================================
|
|
716
783
|
case "type":
|
|
717
784
|
if (addNextError) {
|
|
718
785
|
if (attributeValue == null && nullAllowed) {
|
|
@@ -828,9 +895,6 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
828
895
|
}
|
|
829
896
|
}
|
|
830
897
|
break;
|
|
831
|
-
// ==================================================
|
|
832
|
-
// MIN LENGTH
|
|
833
|
-
// ==================================================
|
|
834
898
|
case "minLength": {
|
|
835
899
|
const minLength = attributeRules.minLength;
|
|
836
900
|
if (addNextError) {
|
|
@@ -852,9 +916,6 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
852
916
|
}
|
|
853
917
|
break;
|
|
854
918
|
}
|
|
855
|
-
// ==================================================
|
|
856
|
-
// MAX LENGTH
|
|
857
|
-
// ==================================================
|
|
858
919
|
case "maxLength": {
|
|
859
920
|
const maxLength = attributeRules.maxLength;
|
|
860
921
|
if (addNextError) {
|
|
@@ -876,9 +937,6 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
876
937
|
}
|
|
877
938
|
break;
|
|
878
939
|
}
|
|
879
|
-
// ==================================================
|
|
880
|
-
// PREVENT DECIMAL
|
|
881
|
-
// ==================================================
|
|
882
940
|
case "preventDecimal":
|
|
883
941
|
if (addNextError) {
|
|
884
942
|
if (attributeValue == null && nullAllowed) {
|
|
@@ -895,9 +953,6 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
895
953
|
}
|
|
896
954
|
}
|
|
897
955
|
break;
|
|
898
|
-
// ==================================================
|
|
899
|
-
// MIN
|
|
900
|
-
// ==================================================
|
|
901
956
|
case "min": {
|
|
902
957
|
const min = attributeRules.min;
|
|
903
958
|
if (addNextError) {
|
|
@@ -916,9 +971,6 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
916
971
|
}
|
|
917
972
|
break;
|
|
918
973
|
}
|
|
919
|
-
// ==================================================
|
|
920
|
-
// MAX
|
|
921
|
-
// ==================================================
|
|
922
974
|
case "max": {
|
|
923
975
|
const max = attributeRules.max;
|
|
924
976
|
if (addNextError) {
|
|
@@ -937,9 +989,6 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
937
989
|
}
|
|
938
990
|
break;
|
|
939
991
|
}
|
|
940
|
-
// ==================================================
|
|
941
|
-
// RANGE
|
|
942
|
-
// ==================================================
|
|
943
992
|
case "range": {
|
|
944
993
|
const range = attributeRules.range;
|
|
945
994
|
if (addNextError) {
|
|
@@ -961,9 +1010,6 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
961
1010
|
}
|
|
962
1011
|
break;
|
|
963
1012
|
}
|
|
964
|
-
// ==================================================
|
|
965
|
-
// NESTED OBJECT
|
|
966
|
-
// ==================================================
|
|
967
1013
|
case "objectAttr": {
|
|
968
1014
|
const objectAttr = attributeRules.objectAttr;
|
|
969
1015
|
if (addNextError &&
|
|
@@ -975,7 +1021,7 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
975
1021
|
statusCode: 400,
|
|
976
1022
|
valid: false,
|
|
977
1023
|
message: "One or more attribute values are invalid",
|
|
978
|
-
}, attributePath, options);
|
|
1024
|
+
}, attributePath, options, rootPayload);
|
|
979
1025
|
if (nestedResult.valid === true) {
|
|
980
1026
|
attributeValue = nestedResult.validatedPayload;
|
|
981
1027
|
}
|
|
@@ -985,9 +1031,6 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
985
1031
|
}
|
|
986
1032
|
break;
|
|
987
1033
|
}
|
|
988
|
-
// ==================================================
|
|
989
|
-
// DEPENDENCY
|
|
990
|
-
// ==================================================
|
|
991
1034
|
case "dependency": {
|
|
992
1035
|
const dependency = attributeRules.dependency;
|
|
993
1036
|
if (addNextError && dependency !== undefined) {
|
|
@@ -1024,9 +1067,6 @@ function perfectPayloadStructured(data = {}, dataValidationRule = {}, validPaylo
|
|
|
1024
1067
|
}
|
|
1025
1068
|
break;
|
|
1026
1069
|
}
|
|
1027
|
-
// ==================================================
|
|
1028
|
-
// CUSTOM VALIDATOR
|
|
1029
|
-
// ==================================================
|
|
1030
1070
|
case "customValidator":
|
|
1031
1071
|
if (!skipCustomValidator &&
|
|
1032
1072
|
addNextError &&
|
|
@@ -1179,7 +1219,7 @@ function isObjectId(id) {
|
|
|
1179
1219
|
function isPassedRegex(reExpression, value) {
|
|
1180
1220
|
return reExpression?.test(String(value)) ?? false;
|
|
1181
1221
|
}
|
|
1182
|
-
async function runAsyncCustomValidators(data
|
|
1222
|
+
async function runAsyncCustomValidators(data, dataValidationRule, basePath = "") {
|
|
1183
1223
|
const errors = [];
|
|
1184
1224
|
for (const attributeName in dataValidationRule) {
|
|
1185
1225
|
const attributeRules = dataValidationRule?.[attributeName];
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { ValidationRules } from "./rules.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ValidationOptions } from "./options.js";
|
|
3
3
|
import type { ValidationError } from "./errors.js";
|
|
4
4
|
export type RequestSource = "headers" | "params" | "query" | "body";
|
|
5
5
|
export type FrameworkRule = Partial<Record<RequestSource, ValidationRules>>;
|
|
6
6
|
export type FrameworkData = Partial<Record<RequestSource, Record<string, unknown>>>;
|
|
7
7
|
export interface FrameworkConfig {
|
|
8
8
|
rule?: FrameworkRule;
|
|
9
|
-
options?:
|
|
9
|
+
options?: ValidationOptions;
|
|
10
10
|
}
|
|
11
11
|
export interface FrameworkValidationInput extends FrameworkConfig {
|
|
12
12
|
data?: FrameworkData;
|
package/dist/types/options.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type { InvalidPayloadResponse, ValidPayloadResponse } from "./results.js";
|
|
2
2
|
export type UnknownFieldsMode = "strip" | "allow" | "reject";
|
|
3
|
-
export interface
|
|
3
|
+
export interface ValidationOptions {
|
|
4
4
|
unknownFields?: UnknownFieldsMode;
|
|
5
5
|
prettyErrors?: boolean;
|
|
6
6
|
validPayloadResponse?: ValidPayloadResponse;
|
|
7
7
|
inValidPayloadResponse?: InvalidPayloadResponse;
|
|
8
8
|
}
|
|
9
|
-
export interface StructuredErrorOptions extends
|
|
9
|
+
export interface StructuredErrorOptions extends ValidationOptions {
|
|
10
10
|
prettyErrors?: false;
|
|
11
11
|
}
|
|
12
|
-
export interface PrettyErrorOptions extends
|
|
12
|
+
export interface PrettyErrorOptions extends ValidationOptions {
|
|
13
13
|
prettyErrors: true;
|
|
14
14
|
}
|
package/dist/types/rules.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
export type ValidationValueType = "number" | "string" | "boolean" | "email" | "url" | "enum" | "uuid" | "uuidv1" | "uuidv3" | "uuidv4" | "uuidv5" | "objectId" | "array" | "object";
|
|
2
2
|
export type TransformFunction = (value: unknown, payload: Record<string, unknown>) => unknown;
|
|
3
|
+
export type ArrayElementTransformFunction = (value: unknown, index: number, payload: Record<string, unknown>) => unknown;
|
|
3
4
|
export type CustomValidator = (value: unknown, payload: Record<string, unknown>) => boolean | Promise<boolean>;
|
|
4
5
|
export interface DependencyRule {
|
|
5
6
|
setDependencyRule: (value: unknown, dependencyValue: unknown) => AttributeValidationRules;
|
|
6
7
|
}
|
|
7
8
|
export type DependencyRules = Record<string, DependencyRule>;
|
|
8
|
-
export interface AttributeValidationRules {
|
|
9
|
+
export interface AttributeValidationRules<TTransform extends (...args: any[]) => unknown = TransformFunction> {
|
|
9
10
|
mandatory?: boolean;
|
|
10
11
|
allowNull?: boolean;
|
|
11
12
|
allowEmptyObject?: boolean;
|
|
@@ -37,11 +38,11 @@ export interface AttributeValidationRules {
|
|
|
37
38
|
minItems?: number;
|
|
38
39
|
maxItems?: number;
|
|
39
40
|
regex?: RegExp;
|
|
41
|
+
transform?: TTransform;
|
|
40
42
|
objectAttr?: ValidationRules;
|
|
41
|
-
elementConstraints?: AttributeValidationRules
|
|
43
|
+
elementConstraints?: AttributeValidationRules<ArrayElementTransformFunction>;
|
|
42
44
|
dependency?: DependencyRules;
|
|
43
45
|
customValidator?: CustomValidator;
|
|
44
|
-
transform?: TransformFunction;
|
|
45
46
|
trim?: boolean;
|
|
46
47
|
lowercase?: boolean;
|
|
47
48
|
uppercase?: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "perfect-payload",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Lightweight JSON payload validation library with structured errors, nested validation, field paths, and customizable validation rules.",
|
|
6
6
|
"main": "./dist/index.js",
|