perfect-payload 1.3.0-beta.2 → 1.5.0-beta.0
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 +767 -376
- package/index.js +148 -18
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -562,7 +562,7 @@ function perfectPayloadStructured(
|
|
|
562
562
|
basePath,
|
|
563
563
|
);
|
|
564
564
|
|
|
565
|
-
|
|
565
|
+
let attributeValue = data?.[attributeName] ?? null;
|
|
566
566
|
|
|
567
567
|
const nullAllowed =
|
|
568
568
|
dataValidationRule?.[attributeName]?.["allowNull"] ?? true;
|
|
@@ -570,7 +570,78 @@ function perfectPayloadStructured(
|
|
|
570
570
|
const isMandatoryField = attributeRules?.["mandatory"] ?? false;
|
|
571
571
|
|
|
572
572
|
const attrExist = Object.keys(data ?? {}).includes(attributeName);
|
|
573
|
+
// TRANSFORMATIONS START
|
|
574
|
+
// NO MULTI TRANSFORMATION
|
|
575
|
+
if (
|
|
576
|
+
attributeRules?.lowercase === true &&
|
|
577
|
+
attributeRules?.uppercase === true
|
|
578
|
+
) {
|
|
579
|
+
throw new Error(
|
|
580
|
+
`perfect-payload:- lowercase and uppercase cannot both be enabled for attribute ${attributePath}`,
|
|
581
|
+
);
|
|
582
|
+
}
|
|
583
|
+
// TRIM
|
|
584
|
+
if (
|
|
585
|
+
attrExist &&
|
|
586
|
+
attributeValue !== null &&
|
|
587
|
+
attributeRules?.trim === true &&
|
|
588
|
+
typeof attributeValue === "string"
|
|
589
|
+
) {
|
|
590
|
+
attributeValue = attributeValue.trim();
|
|
591
|
+
}
|
|
592
|
+
// LOWERCASE
|
|
593
|
+
if (
|
|
594
|
+
attrExist &&
|
|
595
|
+
attributeValue !== null &&
|
|
596
|
+
attributeRules?.lowercase === true &&
|
|
597
|
+
typeof attributeValue === "string"
|
|
598
|
+
) {
|
|
599
|
+
attributeValue = attributeValue.toLowerCase();
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// UPPERCASE
|
|
603
|
+
|
|
604
|
+
if (
|
|
605
|
+
attrExist &&
|
|
606
|
+
attributeValue !== null &&
|
|
607
|
+
attributeRules?.uppercase === true &&
|
|
608
|
+
typeof attributeValue === "string"
|
|
609
|
+
) {
|
|
610
|
+
attributeValue = attributeValue.toUpperCase();
|
|
611
|
+
}
|
|
573
612
|
|
|
613
|
+
// CUSTOM TRANSFORM
|
|
614
|
+
|
|
615
|
+
if (
|
|
616
|
+
attrExist &&
|
|
617
|
+
attributeValue !== null &&
|
|
618
|
+
attributeRules?.transform !== undefined
|
|
619
|
+
) {
|
|
620
|
+
const transformer = attributeRules.transform;
|
|
621
|
+
|
|
622
|
+
if (typeof transformer !== "function") {
|
|
623
|
+
throw new Error(
|
|
624
|
+
`perfect-payload:- transform must be a function for attribute ${attributePath}`,
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
const transformedValue = transformer(attributeValue, data);
|
|
629
|
+
|
|
630
|
+
if (transformedValue && typeof transformedValue.then === "function") {
|
|
631
|
+
throw new Error(
|
|
632
|
+
`perfect-payload:- transform must be synchronous for attribute ${attributePath}`,
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
if (transformedValue === undefined) {
|
|
637
|
+
throw new Error(
|
|
638
|
+
`perfect-payload:- transform must not return undefined for attribute ${attributePath}`,
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
attributeValue = transformedValue;
|
|
643
|
+
}
|
|
644
|
+
// TRANSFORMATIONS END
|
|
574
645
|
for (const ruleName in attributeRules) {
|
|
575
646
|
switch (ruleName) {
|
|
576
647
|
// ==================================================
|
|
@@ -674,6 +745,9 @@ function perfectPayloadStructured(
|
|
|
674
745
|
if (isArray(attributeValue) && attributeValue.length > 0) {
|
|
675
746
|
let elementError = null;
|
|
676
747
|
|
|
748
|
+
// Clone so original payload array is not mutated
|
|
749
|
+
const transformedArray = [...attributeValue];
|
|
750
|
+
|
|
677
751
|
for (
|
|
678
752
|
let elementIndex = 0;
|
|
679
753
|
elementIndex < attributeValue.length;
|
|
@@ -681,7 +755,10 @@ function perfectPayloadStructured(
|
|
|
681
755
|
) {
|
|
682
756
|
const element = attributeValue[elementIndex];
|
|
683
757
|
|
|
684
|
-
const {
|
|
758
|
+
const {
|
|
759
|
+
errors = [],
|
|
760
|
+
validatedPayload: elementValidatedPayload,
|
|
761
|
+
} = perfectPayloadStructured(
|
|
685
762
|
{
|
|
686
763
|
[attributeName]: element,
|
|
687
764
|
},
|
|
@@ -714,17 +791,63 @@ function perfectPayloadStructured(
|
|
|
714
791
|
|
|
715
792
|
break;
|
|
716
793
|
}
|
|
794
|
+
|
|
795
|
+
// Preserve the transformed element
|
|
796
|
+
transformedArray[elementIndex] =
|
|
797
|
+
elementValidatedPayload?.[attributeName];
|
|
717
798
|
}
|
|
718
799
|
|
|
719
800
|
if (elementError) {
|
|
720
801
|
rowErrors.push(elementError);
|
|
721
802
|
addNextError = false;
|
|
803
|
+
} else {
|
|
804
|
+
// All elements passed, so use transformed values
|
|
805
|
+
attributeValue = transformedArray;
|
|
722
806
|
}
|
|
723
807
|
}
|
|
724
808
|
}
|
|
725
809
|
|
|
726
810
|
break;
|
|
727
811
|
|
|
812
|
+
case "minItems":
|
|
813
|
+
if (
|
|
814
|
+
addNextError &&
|
|
815
|
+
attrExist &&
|
|
816
|
+
attributeValue !== null &&
|
|
817
|
+
isArray(attributeValue) &&
|
|
818
|
+
attributeValue.length < attributeRules[ruleName]
|
|
819
|
+
) {
|
|
820
|
+
addStructuredError(
|
|
821
|
+
rowErrors,
|
|
822
|
+
attributePath,
|
|
823
|
+
"MIN_ITEMS",
|
|
824
|
+
`Attribute ${attributePath} must contain at least ${attributeRules[ruleName]} item(s)`,
|
|
825
|
+
);
|
|
826
|
+
|
|
827
|
+
addNextError = false;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
break;
|
|
831
|
+
|
|
832
|
+
case "maxItems":
|
|
833
|
+
if (
|
|
834
|
+
addNextError &&
|
|
835
|
+
attrExist &&
|
|
836
|
+
attributeValue !== null &&
|
|
837
|
+
isArray(attributeValue) &&
|
|
838
|
+
attributeValue.length > attributeRules[ruleName]
|
|
839
|
+
) {
|
|
840
|
+
addStructuredError(
|
|
841
|
+
rowErrors,
|
|
842
|
+
attributePath,
|
|
843
|
+
"MAX_ITEMS",
|
|
844
|
+
`Attribute ${attributePath} must contain at most ${attributeRules[ruleName]} item(s)`,
|
|
845
|
+
);
|
|
846
|
+
|
|
847
|
+
addNextError = false;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
break;
|
|
728
851
|
// ==================================================
|
|
729
852
|
// REGEX
|
|
730
853
|
// ==================================================
|
|
@@ -759,7 +882,10 @@ function perfectPayloadStructured(
|
|
|
759
882
|
|
|
760
883
|
switch (expectedType) {
|
|
761
884
|
case "number":
|
|
762
|
-
if (
|
|
885
|
+
if (
|
|
886
|
+
!isNumber(attributeValue) ||
|
|
887
|
+
Number.isNaN(attributeValue)
|
|
888
|
+
) {
|
|
763
889
|
addStructuredError(
|
|
764
890
|
rowErrors,
|
|
765
891
|
attributePath,
|
|
@@ -776,7 +902,6 @@ function perfectPayloadStructured(
|
|
|
776
902
|
}
|
|
777
903
|
|
|
778
904
|
break;
|
|
779
|
-
|
|
780
905
|
case "string":
|
|
781
906
|
if (!isString(attributeValue)) {
|
|
782
907
|
addStructuredError(
|
|
@@ -1200,24 +1325,29 @@ function perfectPayloadStructured(
|
|
|
1200
1325
|
// ==================================================
|
|
1201
1326
|
// NESTED OBJECT
|
|
1202
1327
|
// ==================================================
|
|
1203
|
-
|
|
1204
1328
|
case "objectAttr":
|
|
1205
1329
|
if (addNextError) {
|
|
1206
|
-
const { errors = [] } =
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1330
|
+
const { errors = [], validatedPayload: nestedValidatedPayload } =
|
|
1331
|
+
perfectPayloadStructured(
|
|
1332
|
+
attributeValue,
|
|
1333
|
+
attributeRules?.[ruleName],
|
|
1334
|
+
{
|
|
1335
|
+
statusCode: 200,
|
|
1336
|
+
valid: true,
|
|
1337
|
+
},
|
|
1338
|
+
{
|
|
1339
|
+
statusCode: 400,
|
|
1340
|
+
valid: false,
|
|
1341
|
+
message: "One or more attribute values are invalid",
|
|
1342
|
+
},
|
|
1343
|
+
attributePath,
|
|
1344
|
+
);
|
|
1217
1345
|
|
|
1218
|
-
|
|
1346
|
+
if (errors.length === 0) {
|
|
1347
|
+
attributeValue = nestedValidatedPayload;
|
|
1348
|
+
}
|
|
1219
1349
|
|
|
1220
|
-
|
|
1350
|
+
rowErrors = [...rowErrors, ...errors];
|
|
1221
1351
|
}
|
|
1222
1352
|
|
|
1223
1353
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "perfect-payload",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0-beta.0",
|
|
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": "index.js",
|