perfect-payload 1.5.0 → 1.6.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 +791 -350
- package/index.js +172 -6
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -537,6 +537,45 @@ export function perfectPayload(
|
|
|
537
537
|
);
|
|
538
538
|
}
|
|
539
539
|
|
|
540
|
+
export async function perfectPayloadAsync(
|
|
541
|
+
data = {},
|
|
542
|
+
dataValidationRule = {},
|
|
543
|
+
validPayloadResponse = { statusCode: 200, valid: true },
|
|
544
|
+
inValidPayloadResponse = {
|
|
545
|
+
statusCode: 400,
|
|
546
|
+
valid: false,
|
|
547
|
+
message: "One or more attribute values are invalid",
|
|
548
|
+
},
|
|
549
|
+
) {
|
|
550
|
+
const validationResult = perfectPayloadStructured(
|
|
551
|
+
data,
|
|
552
|
+
dataValidationRule,
|
|
553
|
+
validPayloadResponse,
|
|
554
|
+
inValidPayloadResponse,
|
|
555
|
+
"",
|
|
556
|
+
{
|
|
557
|
+
skipCustomValidator: true,
|
|
558
|
+
},
|
|
559
|
+
);
|
|
560
|
+
|
|
561
|
+
if (validationResult?.errors?.length) {
|
|
562
|
+
return validationResult;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
const rowErrors = await runAsyncCustomValidators(
|
|
566
|
+
validationResult?.validatedPayload ?? {},
|
|
567
|
+
dataValidationRule,
|
|
568
|
+
);
|
|
569
|
+
if (rowErrors.length > 0) {
|
|
570
|
+
return {
|
|
571
|
+
...inValidPayloadResponse,
|
|
572
|
+
errors: rowErrors,
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
return validationResult;
|
|
577
|
+
}
|
|
578
|
+
|
|
540
579
|
function perfectPayloadStructured(
|
|
541
580
|
data = {},
|
|
542
581
|
dataValidationRule = {},
|
|
@@ -547,9 +586,11 @@ function perfectPayloadStructured(
|
|
|
547
586
|
message: "One or more attribute values are invalid",
|
|
548
587
|
},
|
|
549
588
|
basePath = "",
|
|
589
|
+
options = {},
|
|
550
590
|
) {
|
|
551
591
|
let validatedPayload = {};
|
|
552
592
|
let rowErrors = [];
|
|
593
|
+
const skipCustomValidator = options?.skipCustomValidator === true;
|
|
553
594
|
|
|
554
595
|
for (const attributeName in dataValidationRule) {
|
|
555
596
|
let addNextError = true;
|
|
@@ -765,6 +806,14 @@ function perfectPayloadStructured(
|
|
|
765
806
|
{
|
|
766
807
|
[attributeName]: attributeRules[ruleName],
|
|
767
808
|
},
|
|
809
|
+
{ statusCode: 200, valid: true },
|
|
810
|
+
{
|
|
811
|
+
statusCode: 400,
|
|
812
|
+
valid: false,
|
|
813
|
+
message: "One or more attribute values are invalid",
|
|
814
|
+
},
|
|
815
|
+
"",
|
|
816
|
+
options,
|
|
768
817
|
);
|
|
769
818
|
|
|
770
819
|
if (errors.length > 0) {
|
|
@@ -808,7 +857,6 @@ function perfectPayloadStructured(
|
|
|
808
857
|
}
|
|
809
858
|
|
|
810
859
|
break;
|
|
811
|
-
|
|
812
860
|
case "minItems":
|
|
813
861
|
if (
|
|
814
862
|
addNextError &&
|
|
@@ -1331,16 +1379,14 @@ function perfectPayloadStructured(
|
|
|
1331
1379
|
perfectPayloadStructured(
|
|
1332
1380
|
attributeValue,
|
|
1333
1381
|
attributeRules?.[ruleName],
|
|
1334
|
-
{
|
|
1335
|
-
statusCode: 200,
|
|
1336
|
-
valid: true,
|
|
1337
|
-
},
|
|
1382
|
+
{ statusCode: 200, valid: true },
|
|
1338
1383
|
{
|
|
1339
1384
|
statusCode: 400,
|
|
1340
1385
|
valid: false,
|
|
1341
1386
|
message: "One or more attribute values are invalid",
|
|
1342
1387
|
},
|
|
1343
1388
|
attributePath,
|
|
1389
|
+
options,
|
|
1344
1390
|
);
|
|
1345
1391
|
|
|
1346
1392
|
if (errors.length === 0) {
|
|
@@ -1415,7 +1461,12 @@ function perfectPayloadStructured(
|
|
|
1415
1461
|
// ==================================================
|
|
1416
1462
|
|
|
1417
1463
|
case "customValidator":
|
|
1418
|
-
if (
|
|
1464
|
+
if (
|
|
1465
|
+
!skipCustomValidator &&
|
|
1466
|
+
addNextError &&
|
|
1467
|
+
attrExist &&
|
|
1468
|
+
attributeValue !== null
|
|
1469
|
+
) {
|
|
1419
1470
|
const validator = attributeRules?.[ruleName];
|
|
1420
1471
|
|
|
1421
1472
|
if (typeof validator !== "function") {
|
|
@@ -1598,3 +1649,118 @@ function isObjectId(id) {
|
|
|
1598
1649
|
function isPassedRegex(reExpression, value) {
|
|
1599
1650
|
return reExpression.test(value);
|
|
1600
1651
|
}
|
|
1652
|
+
|
|
1653
|
+
async function runAsyncCustomValidators(
|
|
1654
|
+
data = {},
|
|
1655
|
+
dataValidationRule = {},
|
|
1656
|
+
basePath = "",
|
|
1657
|
+
) {
|
|
1658
|
+
const errors = [];
|
|
1659
|
+
|
|
1660
|
+
for (const attributeName in dataValidationRule) {
|
|
1661
|
+
const attributeRules = dataValidationRule?.[attributeName];
|
|
1662
|
+
|
|
1663
|
+
const attrExist = Object.keys(data ?? {}).includes(attributeName);
|
|
1664
|
+
|
|
1665
|
+
if (!attrExist) {
|
|
1666
|
+
continue;
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
const attributeValue = data?.[attributeName];
|
|
1670
|
+
|
|
1671
|
+
const attributePath = getAttributePath(
|
|
1672
|
+
attributeName,
|
|
1673
|
+
attributeRules,
|
|
1674
|
+
basePath,
|
|
1675
|
+
);
|
|
1676
|
+
|
|
1677
|
+
// customValidator
|
|
1678
|
+
if (
|
|
1679
|
+
Object.prototype.hasOwnProperty.call(
|
|
1680
|
+
attributeRules ?? {},
|
|
1681
|
+
"customValidator",
|
|
1682
|
+
)
|
|
1683
|
+
) {
|
|
1684
|
+
if (typeof attributeRules.customValidator !== "function") {
|
|
1685
|
+
throw new Error(
|
|
1686
|
+
`perfect-payload:- customValidator must be a function for attribute ${attributePath}`,
|
|
1687
|
+
);
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
if (attributeValue !== null) {
|
|
1691
|
+
const validationResponse = await attributeRules.customValidator(
|
|
1692
|
+
attributeValue,
|
|
1693
|
+
data,
|
|
1694
|
+
);
|
|
1695
|
+
|
|
1696
|
+
if (validationResponse !== true) {
|
|
1697
|
+
addStructuredError(
|
|
1698
|
+
errors,
|
|
1699
|
+
attributePath,
|
|
1700
|
+
attributeRules?.customValidatorCode || "CUSTOM_VALIDATION_FAILED",
|
|
1701
|
+
attributeRules?.customValidatorError ||
|
|
1702
|
+
`Custom validation failed for attribute ${attributePath}`,
|
|
1703
|
+
);
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
// nested objectAttr
|
|
1709
|
+
if (
|
|
1710
|
+
attributeValue !== null &&
|
|
1711
|
+
typeof attributeValue === "object" &&
|
|
1712
|
+
!Array.isArray(attributeValue) &&
|
|
1713
|
+
attributeRules?.objectAttr
|
|
1714
|
+
) {
|
|
1715
|
+
const nestedErrors = await runAsyncCustomValidators(
|
|
1716
|
+
attributeValue,
|
|
1717
|
+
attributeRules.objectAttr,
|
|
1718
|
+
attributePath,
|
|
1719
|
+
);
|
|
1720
|
+
|
|
1721
|
+
errors.push(...nestedErrors);
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
// nested elementConstraints
|
|
1725
|
+
if (Array.isArray(attributeValue) && attributeRules?.elementConstraints) {
|
|
1726
|
+
for (
|
|
1727
|
+
let elementIndex = 0;
|
|
1728
|
+
elementIndex < attributeValue.length;
|
|
1729
|
+
elementIndex++
|
|
1730
|
+
) {
|
|
1731
|
+
const element = attributeValue[elementIndex];
|
|
1732
|
+
|
|
1733
|
+
const elementErrors = await runAsyncCustomValidators(
|
|
1734
|
+
{
|
|
1735
|
+
[attributeName]: element,
|
|
1736
|
+
},
|
|
1737
|
+
{
|
|
1738
|
+
[attributeName]: attributeRules.elementConstraints,
|
|
1739
|
+
},
|
|
1740
|
+
);
|
|
1741
|
+
|
|
1742
|
+
for (const elementError of elementErrors) {
|
|
1743
|
+
const indexedPath = replaceRootPath(
|
|
1744
|
+
elementError.path,
|
|
1745
|
+
attributeName,
|
|
1746
|
+
`${attributePath}[${elementIndex}]`,
|
|
1747
|
+
);
|
|
1748
|
+
|
|
1749
|
+
errors.push({
|
|
1750
|
+
...elementError,
|
|
1751
|
+
path: indexedPath,
|
|
1752
|
+
|
|
1753
|
+
message:
|
|
1754
|
+
elementError.code === "CUSTOM_VALIDATION_FAILED" &&
|
|
1755
|
+
elementError.message ===
|
|
1756
|
+
`Custom validation failed for attribute ${elementError.path}`
|
|
1757
|
+
? `Custom validation failed for attribute ${indexedPath}`
|
|
1758
|
+
: elementError.message,
|
|
1759
|
+
});
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
return errors;
|
|
1766
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "perfect-payload",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.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",
|