perfect-payload 1.8.0-beta.0 → 2.0.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/package.json +25 -11
- package/express.js +0 -75
- package/fastify.js +0 -67
- package/framework.js +0 -175
- package/index.js +0 -1861
package/index.js
DELETED
|
@@ -1,1861 +0,0 @@
|
|
|
1
|
-
let perfectPayloadV1DeprecationWarningShown = false;
|
|
2
|
-
|
|
3
|
-
function showPerfectPayloadV1DeprecationWarning() {
|
|
4
|
-
if (perfectPayloadV1DeprecationWarningShown) return;
|
|
5
|
-
|
|
6
|
-
perfectPayloadV1DeprecationWarningShown = true;
|
|
7
|
-
|
|
8
|
-
const message =
|
|
9
|
-
"perfectPayloadV1() is deprecated and will no longer be supported after March 31, 2027. Use perfectPayload() instead.";
|
|
10
|
-
|
|
11
|
-
if (
|
|
12
|
-
typeof process !== "undefined" &&
|
|
13
|
-
typeof process.emitWarning === "function"
|
|
14
|
-
) {
|
|
15
|
-
process.emitWarning(message, {
|
|
16
|
-
type: "DeprecationWarning",
|
|
17
|
-
code: "PERFECT_PAYLOAD_V1_DEPRECATED",
|
|
18
|
-
});
|
|
19
|
-
} else if (
|
|
20
|
-
typeof console !== "undefined" &&
|
|
21
|
-
typeof console.warn === "function"
|
|
22
|
-
) {
|
|
23
|
-
console.warn(`[perfect-payload] DeprecationWarning: ${message}`);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function perfectPayloadV1(
|
|
28
|
-
data = {},
|
|
29
|
-
dataValidationRule = {},
|
|
30
|
-
validPayloadResponse = { statusCode: 200, valid: true },
|
|
31
|
-
inValidPayloadResponse = {
|
|
32
|
-
statusCode: 400,
|
|
33
|
-
valid: false,
|
|
34
|
-
message: "One or more attribute values are invalid",
|
|
35
|
-
},
|
|
36
|
-
) {
|
|
37
|
-
showPerfectPayloadV1DeprecationWarning();
|
|
38
|
-
let validatedPayload = {};
|
|
39
|
-
let rowErrors = [];
|
|
40
|
-
for (const attributeName in dataValidationRule) {
|
|
41
|
-
let addNextError = true;
|
|
42
|
-
const attributeRules = dataValidationRule?.[attributeName];
|
|
43
|
-
const attrPath = dataValidationRule?.[attributeName]?.path || null;
|
|
44
|
-
for (const ruleName in attributeRules) {
|
|
45
|
-
const attributePath = `${attrPath ? attrPath + "." : ""}${attributeName}`;
|
|
46
|
-
const attributeValue = data?.[attributeName] ?? null;
|
|
47
|
-
const nullAllowed =
|
|
48
|
-
dataValidationRule?.[attributeName]?.["allowNull"] ?? true;
|
|
49
|
-
const isMandatoryField = attributeRules?.["mandatory"] ?? false;
|
|
50
|
-
const attrExist = Object.keys(data)?.includes(attributeName); //Mandatory value check
|
|
51
|
-
|
|
52
|
-
switch (ruleName) {
|
|
53
|
-
case "mandatory":
|
|
54
|
-
//mandatory value check
|
|
55
|
-
if (isMandatoryField && !attrExist) {
|
|
56
|
-
addNextError = false;
|
|
57
|
-
rowErrors.push(
|
|
58
|
-
attributeRules?.["mandatoryError"] ||
|
|
59
|
-
`${attributePath} is mandatory`,
|
|
60
|
-
);
|
|
61
|
-
} else if (!attrExist) {
|
|
62
|
-
addNextError = false;
|
|
63
|
-
}
|
|
64
|
-
break;
|
|
65
|
-
case "allowNull":
|
|
66
|
-
//allowNull value check
|
|
67
|
-
if (addNextError && attributeValue == null) {
|
|
68
|
-
if (!dataValidationRule?.[attributeName]?.[ruleName]) {
|
|
69
|
-
addNextError = false;
|
|
70
|
-
rowErrors.push(
|
|
71
|
-
attributeRules?.["allowNullError"] ||
|
|
72
|
-
`value null/'' not valid for attribute ${attributePath}`,
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
break;
|
|
77
|
-
case "allowEmptyObject":
|
|
78
|
-
//allowEmptyObject check
|
|
79
|
-
if (addNextError) {
|
|
80
|
-
if (
|
|
81
|
-
!attributeRules?.["allowEmptyObject"] &&
|
|
82
|
-
Object.keys(attributeValue).length == 0
|
|
83
|
-
) {
|
|
84
|
-
rowErrors.push(
|
|
85
|
-
attributeRules?.["emptyObjectError"] ||
|
|
86
|
-
`value {} not valid for attribute ${attributePath}`,
|
|
87
|
-
);
|
|
88
|
-
addNextError = false;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
break;
|
|
93
|
-
case "allowEmptyArray":
|
|
94
|
-
//allowEmptyArray check
|
|
95
|
-
if (addNextError) {
|
|
96
|
-
if (
|
|
97
|
-
!attributeRules?.["allowEmptyArray"] &&
|
|
98
|
-
isArray(attributeValue) &&
|
|
99
|
-
attributeValue?.length == 0
|
|
100
|
-
) {
|
|
101
|
-
rowErrors.push(
|
|
102
|
-
attributeRules?.["emptyArrayError"] ||
|
|
103
|
-
`${attributePath} cannot be an empty array`,
|
|
104
|
-
);
|
|
105
|
-
addNextError = false;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
break;
|
|
110
|
-
case "elementConstraints":
|
|
111
|
-
//check array ele type
|
|
112
|
-
if (addNextError) {
|
|
113
|
-
if (isArray(attributeValue) && attributeValue?.length > 0) {
|
|
114
|
-
let elementError = false;
|
|
115
|
-
for (const element of attributeValue) {
|
|
116
|
-
const { statusCode = 200, errors } = perfectPayloadV1(
|
|
117
|
-
{ [attributeName]: element },
|
|
118
|
-
{ [attributeName]: attributeRules[ruleName] },
|
|
119
|
-
);
|
|
120
|
-
if (statusCode == 400) {
|
|
121
|
-
elementError = errors?.[0];
|
|
122
|
-
// addNextError = false;
|
|
123
|
-
break;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if (elementError) {
|
|
127
|
-
rowErrors.push(
|
|
128
|
-
attributeRules?.["elementConstraintsError"] || elementError,
|
|
129
|
-
);
|
|
130
|
-
addNextError = false;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
break;
|
|
136
|
-
case "regex":
|
|
137
|
-
//custom regex check
|
|
138
|
-
if (addNextError) {
|
|
139
|
-
if (!isPassedRegex(attributeRules[ruleName], attributeValue)) {
|
|
140
|
-
rowErrors.push(
|
|
141
|
-
attributeRules?.["regexError"] ||
|
|
142
|
-
`${attributePath} failed to pass the regex ${attributeRules[ruleName]}`,
|
|
143
|
-
);
|
|
144
|
-
addNextError = false;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
break;
|
|
148
|
-
case "type":
|
|
149
|
-
//value type check
|
|
150
|
-
if (addNextError) {
|
|
151
|
-
if (attributeValue == null && nullAllowed) {
|
|
152
|
-
addNextError = true;
|
|
153
|
-
} else {
|
|
154
|
-
switch (attributeRules[ruleName]) {
|
|
155
|
-
case "number":
|
|
156
|
-
if (!isNumber(attributeValue)) {
|
|
157
|
-
rowErrors.push(
|
|
158
|
-
attributeRules?.["typeError"] ||
|
|
159
|
-
`Invalid ${typeof attributeValue} value(${attributeValue}) found in attribute ${attributePath}, required ${
|
|
160
|
-
attributeRules[ruleName]
|
|
161
|
-
} value`,
|
|
162
|
-
);
|
|
163
|
-
addNextError = false;
|
|
164
|
-
}
|
|
165
|
-
break;
|
|
166
|
-
|
|
167
|
-
case "string":
|
|
168
|
-
if (!isString(attributeValue)) {
|
|
169
|
-
rowErrors.push(
|
|
170
|
-
attributeRules?.["typeError"] ||
|
|
171
|
-
`Invalid ${typeof attributeValue} value(${attributeValue}) found in attribute ${attributePath}, required ${
|
|
172
|
-
attributeRules[ruleName]
|
|
173
|
-
} value`,
|
|
174
|
-
);
|
|
175
|
-
addNextError = false;
|
|
176
|
-
}
|
|
177
|
-
break;
|
|
178
|
-
case "boolean":
|
|
179
|
-
if (!isBoolean(attributeValue)) {
|
|
180
|
-
rowErrors.push(
|
|
181
|
-
attributeRules?.["typeError"] ||
|
|
182
|
-
`Invalid ${typeof attributeValue} value(${attributeValue}) found in attribute ${attributePath}, required ${
|
|
183
|
-
attributeRules[ruleName]
|
|
184
|
-
} value`,
|
|
185
|
-
);
|
|
186
|
-
addNextError = false;
|
|
187
|
-
}
|
|
188
|
-
break;
|
|
189
|
-
case "email":
|
|
190
|
-
if (!isValidEmail(attributeValue)) {
|
|
191
|
-
rowErrors.push(
|
|
192
|
-
attributeRules?.["typeError"] ||
|
|
193
|
-
`Invalid email ID(${attributeValue}) found in attribute ${attributePath}`,
|
|
194
|
-
);
|
|
195
|
-
addNextError = false;
|
|
196
|
-
}
|
|
197
|
-
break;
|
|
198
|
-
|
|
199
|
-
case "url":
|
|
200
|
-
if (!isValidUrl(attributeValue)) {
|
|
201
|
-
rowErrors.push(
|
|
202
|
-
attributeRules?.["typeError"] ||
|
|
203
|
-
`Invalid URL format(${attributeValue}) found in attribute ${attributePath}`,
|
|
204
|
-
);
|
|
205
|
-
addNextError = false;
|
|
206
|
-
}
|
|
207
|
-
break;
|
|
208
|
-
case "enum":
|
|
209
|
-
if (attributeValue == null && nullAllowed) {
|
|
210
|
-
addNextError = true;
|
|
211
|
-
} else {
|
|
212
|
-
const allEnumValues = attributeRules["enumValues"];
|
|
213
|
-
if (!allEnumValues?.includes(attributeValue)) {
|
|
214
|
-
rowErrors.push(
|
|
215
|
-
attributeRules?.["typeError"] ||
|
|
216
|
-
`Invalid value(${attributeValue}) found in attribute ${attributePath}, valid values are ${allEnumValues?.join(
|
|
217
|
-
", ",
|
|
218
|
-
)}`,
|
|
219
|
-
);
|
|
220
|
-
addNextError = false;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
break;
|
|
224
|
-
case "uuid":
|
|
225
|
-
if (attributeValue == null && nullAllowed) {
|
|
226
|
-
addNextError = true;
|
|
227
|
-
} else if (!isUUID(attributeValue)) {
|
|
228
|
-
rowErrors.push(
|
|
229
|
-
attributeRules?.["typeError"] ||
|
|
230
|
-
`Invalid UUID(${attributeValue}) found in attribute ${attributePath}`,
|
|
231
|
-
);
|
|
232
|
-
addNextError = false;
|
|
233
|
-
}
|
|
234
|
-
break;
|
|
235
|
-
case "uuidv1":
|
|
236
|
-
if (attributeValue == null && nullAllowed) {
|
|
237
|
-
addNextError = true;
|
|
238
|
-
} else if (!isUUIDv1(attributeValue)) {
|
|
239
|
-
rowErrors.push(
|
|
240
|
-
attributeRules?.["typeError"] ||
|
|
241
|
-
`Invalid v1 UUID(${attributeValue}) found in attribute ${attributePath}`,
|
|
242
|
-
);
|
|
243
|
-
addNextError = false;
|
|
244
|
-
}
|
|
245
|
-
break;
|
|
246
|
-
case "uuidv3":
|
|
247
|
-
if (attributeValue == null && nullAllowed) {
|
|
248
|
-
addNextError = true;
|
|
249
|
-
} else if (!isUUIDv3(attributeValue)) {
|
|
250
|
-
rowErrors.push(
|
|
251
|
-
attributeRules?.["typeError"] ||
|
|
252
|
-
`Invalid v3 UUID(${attributeValue}) found in attribute ${attributePath}`,
|
|
253
|
-
);
|
|
254
|
-
addNextError = false;
|
|
255
|
-
}
|
|
256
|
-
break;
|
|
257
|
-
case "uuidv4":
|
|
258
|
-
if (attributeValue == null && nullAllowed) {
|
|
259
|
-
addNextError = true;
|
|
260
|
-
} else if (!isUUIDv4(attributeValue)) {
|
|
261
|
-
rowErrors.push(
|
|
262
|
-
attributeRules?.["typeError"] ||
|
|
263
|
-
`Invalid v4 UUID(${attributeValue}) found in attribute ${attributePath}`,
|
|
264
|
-
);
|
|
265
|
-
addNextError = false;
|
|
266
|
-
}
|
|
267
|
-
break;
|
|
268
|
-
case "uuidv5":
|
|
269
|
-
if (attributeValue == null && nullAllowed) {
|
|
270
|
-
addNextError = true;
|
|
271
|
-
} else if (!isUUIDv5(attributeValue)) {
|
|
272
|
-
rowErrors.push(
|
|
273
|
-
attributeRules?.["typeError"] ||
|
|
274
|
-
`Invalid v5 UUID(${attributeValue}) found in attribute ${attributePath}`,
|
|
275
|
-
);
|
|
276
|
-
addNextError = false;
|
|
277
|
-
}
|
|
278
|
-
break;
|
|
279
|
-
case "objectId":
|
|
280
|
-
if (attributeValue == null && nullAllowed) {
|
|
281
|
-
addNextError = true;
|
|
282
|
-
} else {
|
|
283
|
-
if (!isObjectId(attributeValue)) {
|
|
284
|
-
rowErrors.push(
|
|
285
|
-
attributeRules?.["typeError"] ||
|
|
286
|
-
`Invalid ObjectId(${attributeValue}) found in attribute ${attributePath}`,
|
|
287
|
-
);
|
|
288
|
-
addNextError = false;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
break;
|
|
292
|
-
|
|
293
|
-
case "array":
|
|
294
|
-
if (!isArray(attributeValue)) {
|
|
295
|
-
rowErrors.push(
|
|
296
|
-
attributeRules?.["typeError"] ||
|
|
297
|
-
`Invalid ${typeof attributeValue} value(${attributeValue}) found in attribute ${attributePath}, required ${
|
|
298
|
-
attributeRules[ruleName]
|
|
299
|
-
} value`,
|
|
300
|
-
);
|
|
301
|
-
addNextError = false;
|
|
302
|
-
}
|
|
303
|
-
break;
|
|
304
|
-
|
|
305
|
-
case "object":
|
|
306
|
-
if (!isObject(attributeValue)) {
|
|
307
|
-
rowErrors.push(
|
|
308
|
-
attributeRules?.["typeError"] ||
|
|
309
|
-
`Invalid ${typeof attributeValue} value(${attributeValue}) found in attribute ${attributePath}, required ${
|
|
310
|
-
attributeRules[ruleName]
|
|
311
|
-
} value`,
|
|
312
|
-
);
|
|
313
|
-
addNextError = false;
|
|
314
|
-
}
|
|
315
|
-
break;
|
|
316
|
-
|
|
317
|
-
default:
|
|
318
|
-
break;
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
break;
|
|
324
|
-
case "minLength":
|
|
325
|
-
//minimum string length check
|
|
326
|
-
if (addNextError) {
|
|
327
|
-
if (attributeValue == null && nullAllowed) {
|
|
328
|
-
addNextError = true;
|
|
329
|
-
} else if (typeof attributeValue == "string") {
|
|
330
|
-
if (attributeValue.length < +attributeRules[ruleName])
|
|
331
|
-
rowErrors.push(
|
|
332
|
-
attributeRules?.["minLengthError"] ||
|
|
333
|
-
`${attributePath} should be minimum of ${attributeRules[ruleName]} character`,
|
|
334
|
-
);
|
|
335
|
-
addNextError = false;
|
|
336
|
-
} else {
|
|
337
|
-
rowErrors.push(
|
|
338
|
-
`${attributePath} value should be a string type(minLength specified)`,
|
|
339
|
-
);
|
|
340
|
-
addNextError = false;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
break;
|
|
344
|
-
case "maxLength":
|
|
345
|
-
//max string length check
|
|
346
|
-
if (addNextError) {
|
|
347
|
-
if (attributeValue == null && nullAllowed) {
|
|
348
|
-
addNextError = true;
|
|
349
|
-
} else if (typeof attributeValue == "string") {
|
|
350
|
-
if (attributeValue.length > +attributeRules[ruleName])
|
|
351
|
-
rowErrors.push(
|
|
352
|
-
attributeRules?.["maxLengthError"] ||
|
|
353
|
-
`${attributePath} can have maximum of ${attributeRules[ruleName]} character`,
|
|
354
|
-
);
|
|
355
|
-
addNextError = false;
|
|
356
|
-
} else {
|
|
357
|
-
rowErrors.push(
|
|
358
|
-
`${attributePath} value should be a string type(maxLength specified)`,
|
|
359
|
-
);
|
|
360
|
-
addNextError = false;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
break;
|
|
364
|
-
case "preventDecimal":
|
|
365
|
-
//preventFraction
|
|
366
|
-
if (addNextError) {
|
|
367
|
-
if (attributeValue == null && nullAllowed) {
|
|
368
|
-
addNextError = true;
|
|
369
|
-
} else if (!isNumber(attributeValue)) {
|
|
370
|
-
rowErrors.push(
|
|
371
|
-
`Invalid ${typeof attributeValue} value(${attributeValue}) found in attribute ${attributePath}, required number value`,
|
|
372
|
-
);
|
|
373
|
-
addNextError = false;
|
|
374
|
-
} else if (+attributeValue % 1 !== 0) {
|
|
375
|
-
rowErrors.push(
|
|
376
|
-
attributeRules?.["preventDecimalError"] ||
|
|
377
|
-
`Decimal value not allowed in attribute ${attributePath}(${attributeValue})`,
|
|
378
|
-
);
|
|
379
|
-
addNextError = false;
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
break;
|
|
383
|
-
case "min":
|
|
384
|
-
//minimum value check
|
|
385
|
-
if (addNextError) {
|
|
386
|
-
if (attributeValue == null && nullAllowed) {
|
|
387
|
-
addNextError = true;
|
|
388
|
-
} else if (!isNumber(attributeValue)) {
|
|
389
|
-
rowErrors.push(
|
|
390
|
-
`Invalid ${typeof attributeValue} value(${attributeValue}) found in attribute ${attributePath}, required number value`,
|
|
391
|
-
);
|
|
392
|
-
addNextError = false;
|
|
393
|
-
} else if (+attributeValue < +attributeRules[ruleName]) {
|
|
394
|
-
rowErrors.push(
|
|
395
|
-
attributeRules?.["minError"] ||
|
|
396
|
-
`minimum value ${
|
|
397
|
-
attributeRules[ruleName]
|
|
398
|
-
} is allowed in attribute ${attributePath}, found value ${
|
|
399
|
-
data[attributeName] ?? "Nil"
|
|
400
|
-
}`,
|
|
401
|
-
);
|
|
402
|
-
addNextError = false;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
break;
|
|
406
|
-
case "max":
|
|
407
|
-
//maximum value check
|
|
408
|
-
if (addNextError) {
|
|
409
|
-
if (attributeValue == null && nullAllowed) {
|
|
410
|
-
addNextError = true;
|
|
411
|
-
} else if (!isNumber(attributeValue)) {
|
|
412
|
-
rowErrors.push(
|
|
413
|
-
`Invalid ${typeof attributeValue} value(${attributeValue}) found in attribute ${attributePath}, required number value`,
|
|
414
|
-
);
|
|
415
|
-
addNextError = false;
|
|
416
|
-
} else if (+attributeValue > +attributeRules[ruleName]) {
|
|
417
|
-
rowErrors.push(
|
|
418
|
-
attributeRules?.["maxError"] ||
|
|
419
|
-
`maximum value ${
|
|
420
|
-
attributeRules[ruleName]
|
|
421
|
-
} is allowed in attribute ${attributePath}, found value ${
|
|
422
|
-
data[attributeName] ?? "Nil"
|
|
423
|
-
}`,
|
|
424
|
-
);
|
|
425
|
-
addNextError = false;
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
break;
|
|
429
|
-
case "range":
|
|
430
|
-
//value range check
|
|
431
|
-
if (addNextError) {
|
|
432
|
-
if (attributeValue == null && nullAllowed) {
|
|
433
|
-
addNextError = true;
|
|
434
|
-
} else if (!isNumber(attributeValue)) {
|
|
435
|
-
rowErrors.push(
|
|
436
|
-
`Invalid ${typeof attributeValue} value(${attributeValue}) found in attribute ${attributePath}, required number value`,
|
|
437
|
-
);
|
|
438
|
-
addNextError = false;
|
|
439
|
-
} else {
|
|
440
|
-
const [min, max] = attributeRules[ruleName].split("-");
|
|
441
|
-
if (
|
|
442
|
-
!isNumber(attributeValue) ||
|
|
443
|
-
+attributeValue < +min ||
|
|
444
|
-
+attributeValue > +max
|
|
445
|
-
) {
|
|
446
|
-
rowErrors.push(
|
|
447
|
-
attributeRules?.["rangeError"] ||
|
|
448
|
-
`Invalid values(${attributeValue}) found in attribute ${attributePath}, value should be between ${min} and ${max} `,
|
|
449
|
-
);
|
|
450
|
-
addNextError = false;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
break;
|
|
455
|
-
case "objectAttr":
|
|
456
|
-
//nested object attributes check
|
|
457
|
-
if (addNextError) {
|
|
458
|
-
const allObjectAttr = Object.keys(attributeRules?.[ruleName]);
|
|
459
|
-
const objectAttrRules = {};
|
|
460
|
-
for (const attr of allObjectAttr) {
|
|
461
|
-
objectAttrRules[attr] = {
|
|
462
|
-
...attributeRules?.[ruleName]?.[attr],
|
|
463
|
-
path: attributeRules?.[ruleName]?.[attr]?.path
|
|
464
|
-
? attributeRules?.[ruleName]?.[attr]?.path + `.${attr}`
|
|
465
|
-
: `${attributePath}`,
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
const { errors = [] } = perfectPayloadV1(
|
|
470
|
-
attributeValue,
|
|
471
|
-
objectAttrRules,
|
|
472
|
-
);
|
|
473
|
-
rowErrors = [...rowErrors, ...errors];
|
|
474
|
-
addNextError = true;
|
|
475
|
-
}
|
|
476
|
-
break;
|
|
477
|
-
case "dependency":
|
|
478
|
-
//dependency check
|
|
479
|
-
if (addNextError) {
|
|
480
|
-
const allDependencyAttr = Object.keys(attributeRules?.[ruleName]);
|
|
481
|
-
for (const attr of allDependencyAttr) {
|
|
482
|
-
if (
|
|
483
|
-
typeof attributeRules?.[ruleName]?.[attr]?.setDependencyRule ==
|
|
484
|
-
"function"
|
|
485
|
-
) {
|
|
486
|
-
const newRule = attributeRules?.[ruleName]?.[
|
|
487
|
-
attr
|
|
488
|
-
]?.setDependencyRule(attributeValue, data?.[attr]);
|
|
489
|
-
let newData = { [attributeName]: attributeValue };
|
|
490
|
-
if (Object.keys(data).includes(attr)) {
|
|
491
|
-
newData = { ...newData, [attr]: data?.[attr] };
|
|
492
|
-
}
|
|
493
|
-
const { errors = [] } = perfectPayloadV1(newData, {
|
|
494
|
-
[attr]: newRule,
|
|
495
|
-
});
|
|
496
|
-
rowErrors = [...rowErrors, ...errors];
|
|
497
|
-
addNextError = true;
|
|
498
|
-
} else {
|
|
499
|
-
throw new Error(
|
|
500
|
-
`perfect-payload:- function setDependencyRule not found in ${attr} dependency `,
|
|
501
|
-
);
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
break;
|
|
506
|
-
default:
|
|
507
|
-
break;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
if (attrExist && rowErrors.length == 0)
|
|
511
|
-
validatedPayload[attributeName] = attributeValue;
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
if (rowErrors?.length) {
|
|
516
|
-
return { ...inValidPayloadResponse, errors: rowErrors };
|
|
517
|
-
} else {
|
|
518
|
-
return { ...validPayloadResponse, validatedPayload };
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
export function perfectPayload(
|
|
523
|
-
data = {},
|
|
524
|
-
dataValidationRule = {},
|
|
525
|
-
options = {},
|
|
526
|
-
) {
|
|
527
|
-
const {
|
|
528
|
-
unknownFields = "strip",
|
|
529
|
-
prettyErrors = false,
|
|
530
|
-
validPayloadResponse = {
|
|
531
|
-
statusCode: 200,
|
|
532
|
-
valid: true,
|
|
533
|
-
},
|
|
534
|
-
|
|
535
|
-
inValidPayloadResponse = {
|
|
536
|
-
statusCode: 400,
|
|
537
|
-
valid: false,
|
|
538
|
-
message: "One or more attribute values are invalid",
|
|
539
|
-
},
|
|
540
|
-
} = options ?? {};
|
|
541
|
-
|
|
542
|
-
if (!["strip", "allow", "reject"].includes(unknownFields)) {
|
|
543
|
-
throw new Error(
|
|
544
|
-
`perfect-payload:- unknownFields must be one of strip, allow, reject`,
|
|
545
|
-
);
|
|
546
|
-
}
|
|
547
|
-
if (typeof prettyErrors !== "boolean") {
|
|
548
|
-
throw new Error(`perfect-payload:- prettyErrors must be a boolean`);
|
|
549
|
-
}
|
|
550
|
-
const validationResult = perfectPayloadStructured(
|
|
551
|
-
data,
|
|
552
|
-
dataValidationRule,
|
|
553
|
-
validPayloadResponse,
|
|
554
|
-
inValidPayloadResponse,
|
|
555
|
-
"",
|
|
556
|
-
{
|
|
557
|
-
unknownFields,
|
|
558
|
-
},
|
|
559
|
-
);
|
|
560
|
-
|
|
561
|
-
if (prettyErrors && validationResult?.errors?.length) {
|
|
562
|
-
return {
|
|
563
|
-
...validationResult,
|
|
564
|
-
errors: validationResult.errors.map((error) => error.message),
|
|
565
|
-
};
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
return validationResult;
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
export async function perfectPayloadAsync(
|
|
572
|
-
data = {},
|
|
573
|
-
dataValidationRule = {},
|
|
574
|
-
options = {},
|
|
575
|
-
) {
|
|
576
|
-
const {
|
|
577
|
-
validPayloadResponse = {
|
|
578
|
-
statusCode: 200,
|
|
579
|
-
valid: true,
|
|
580
|
-
},
|
|
581
|
-
|
|
582
|
-
inValidPayloadResponse = {
|
|
583
|
-
statusCode: 400,
|
|
584
|
-
valid: false,
|
|
585
|
-
message: "One or more attribute values are invalid",
|
|
586
|
-
},
|
|
587
|
-
unknownFields = "strip",
|
|
588
|
-
prettyErrors = false,
|
|
589
|
-
} = options ?? {};
|
|
590
|
-
|
|
591
|
-
if (!["strip", "allow", "reject"].includes(unknownFields)) {
|
|
592
|
-
throw new Error(
|
|
593
|
-
`perfect-payload:- unknownFields must be one of strip, allow, reject`,
|
|
594
|
-
);
|
|
595
|
-
}
|
|
596
|
-
if (typeof prettyErrors !== "boolean") {
|
|
597
|
-
throw new Error(`perfect-payload:- prettyErrors must be a boolean`);
|
|
598
|
-
}
|
|
599
|
-
const validationResult = perfectPayloadStructured(
|
|
600
|
-
data,
|
|
601
|
-
dataValidationRule,
|
|
602
|
-
validPayloadResponse,
|
|
603
|
-
inValidPayloadResponse,
|
|
604
|
-
"",
|
|
605
|
-
{
|
|
606
|
-
skipCustomValidator: true,
|
|
607
|
-
unknownFields,
|
|
608
|
-
},
|
|
609
|
-
);
|
|
610
|
-
|
|
611
|
-
if (validationResult?.errors?.length) {
|
|
612
|
-
if (prettyErrors) {
|
|
613
|
-
return {
|
|
614
|
-
...validationResult,
|
|
615
|
-
errors: validationResult.errors.map((error) => error.message),
|
|
616
|
-
};
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
return validationResult;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
const rowErrors = await runAsyncCustomValidators(
|
|
623
|
-
validationResult?.validatedPayload ?? {},
|
|
624
|
-
dataValidationRule,
|
|
625
|
-
);
|
|
626
|
-
|
|
627
|
-
if (rowErrors.length > 0) {
|
|
628
|
-
return {
|
|
629
|
-
...inValidPayloadResponse,
|
|
630
|
-
errors: prettyErrors
|
|
631
|
-
? rowErrors.map((error) => error.message)
|
|
632
|
-
: rowErrors,
|
|
633
|
-
};
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
return validationResult;
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
function perfectPayloadStructured(
|
|
640
|
-
data = {},
|
|
641
|
-
dataValidationRule = {},
|
|
642
|
-
validPayloadResponse = { statusCode: 200, valid: true },
|
|
643
|
-
inValidPayloadResponse = {
|
|
644
|
-
statusCode: 400,
|
|
645
|
-
valid: false,
|
|
646
|
-
message: "One or more attribute values are invalid",
|
|
647
|
-
},
|
|
648
|
-
basePath = "",
|
|
649
|
-
options = {},
|
|
650
|
-
) {
|
|
651
|
-
let validatedPayload = {};
|
|
652
|
-
let rowErrors = [];
|
|
653
|
-
const skipCustomValidator = options?.skipCustomValidator === true;
|
|
654
|
-
const unknownFields = options?.unknownFields ?? "strip";
|
|
655
|
-
|
|
656
|
-
for (const attributeName in dataValidationRule) {
|
|
657
|
-
let addNextError = true;
|
|
658
|
-
|
|
659
|
-
const attributeRules = dataValidationRule?.[attributeName];
|
|
660
|
-
|
|
661
|
-
const attributePath = getAttributePath(
|
|
662
|
-
attributeName,
|
|
663
|
-
attributeRules,
|
|
664
|
-
basePath,
|
|
665
|
-
);
|
|
666
|
-
|
|
667
|
-
let attributeValue = data?.[attributeName] ?? null;
|
|
668
|
-
|
|
669
|
-
const nullAllowed =
|
|
670
|
-
dataValidationRule?.[attributeName]?.["allowNull"] ?? true;
|
|
671
|
-
|
|
672
|
-
const isMandatoryField = attributeRules?.["mandatory"] ?? false;
|
|
673
|
-
|
|
674
|
-
const attrExist = Object.keys(data ?? {}).includes(attributeName);
|
|
675
|
-
// TRANSFORMATIONS START
|
|
676
|
-
// NO MULTI TRANSFORMATION
|
|
677
|
-
if (
|
|
678
|
-
attributeRules?.lowercase === true &&
|
|
679
|
-
attributeRules?.uppercase === true
|
|
680
|
-
) {
|
|
681
|
-
throw new Error(
|
|
682
|
-
`perfect-payload:- lowercase and uppercase cannot both be enabled for attribute ${attributePath}`,
|
|
683
|
-
);
|
|
684
|
-
}
|
|
685
|
-
// TRIM
|
|
686
|
-
if (
|
|
687
|
-
attrExist &&
|
|
688
|
-
attributeValue !== null &&
|
|
689
|
-
attributeRules?.trim === true &&
|
|
690
|
-
typeof attributeValue === "string"
|
|
691
|
-
) {
|
|
692
|
-
attributeValue = attributeValue.trim();
|
|
693
|
-
}
|
|
694
|
-
// LOWERCASE
|
|
695
|
-
if (
|
|
696
|
-
attrExist &&
|
|
697
|
-
attributeValue !== null &&
|
|
698
|
-
attributeRules?.lowercase === true &&
|
|
699
|
-
typeof attributeValue === "string"
|
|
700
|
-
) {
|
|
701
|
-
attributeValue = attributeValue.toLowerCase();
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
// UPPERCASE
|
|
705
|
-
|
|
706
|
-
if (
|
|
707
|
-
attrExist &&
|
|
708
|
-
attributeValue !== null &&
|
|
709
|
-
attributeRules?.uppercase === true &&
|
|
710
|
-
typeof attributeValue === "string"
|
|
711
|
-
) {
|
|
712
|
-
attributeValue = attributeValue.toUpperCase();
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
// CUSTOM TRANSFORM
|
|
716
|
-
|
|
717
|
-
if (
|
|
718
|
-
attrExist &&
|
|
719
|
-
attributeValue !== null &&
|
|
720
|
-
attributeRules?.transform !== undefined
|
|
721
|
-
) {
|
|
722
|
-
const transformer = attributeRules.transform;
|
|
723
|
-
|
|
724
|
-
if (typeof transformer !== "function") {
|
|
725
|
-
throw new Error(
|
|
726
|
-
`perfect-payload:- transform must be a function for attribute ${attributePath}`,
|
|
727
|
-
);
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
const transformedValue = transformer(attributeValue, data);
|
|
731
|
-
|
|
732
|
-
if (transformedValue && typeof transformedValue.then === "function") {
|
|
733
|
-
throw new Error(
|
|
734
|
-
`perfect-payload:- transform must be synchronous for attribute ${attributePath}`,
|
|
735
|
-
);
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
if (transformedValue === undefined) {
|
|
739
|
-
throw new Error(
|
|
740
|
-
`perfect-payload:- transform must not return undefined for attribute ${attributePath}`,
|
|
741
|
-
);
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
attributeValue = transformedValue;
|
|
745
|
-
}
|
|
746
|
-
// TRANSFORMATIONS END
|
|
747
|
-
for (const ruleName in attributeRules) {
|
|
748
|
-
switch (ruleName) {
|
|
749
|
-
// ==================================================
|
|
750
|
-
// MANDATORY
|
|
751
|
-
// ==================================================
|
|
752
|
-
|
|
753
|
-
case "mandatory":
|
|
754
|
-
if (isMandatoryField && (!attrExist || attributeValue === "")) {
|
|
755
|
-
addNextError = false;
|
|
756
|
-
|
|
757
|
-
addStructuredError(
|
|
758
|
-
rowErrors,
|
|
759
|
-
attributePath,
|
|
760
|
-
"REQUIRED",
|
|
761
|
-
attributeRules?.["mandatoryError"] ||
|
|
762
|
-
`${attributePath} is mandatory`,
|
|
763
|
-
);
|
|
764
|
-
} else if (!attrExist) {
|
|
765
|
-
addNextError = false;
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
break;
|
|
769
|
-
|
|
770
|
-
// ==================================================
|
|
771
|
-
// NULL
|
|
772
|
-
// ==================================================
|
|
773
|
-
|
|
774
|
-
case "allowNull":
|
|
775
|
-
if (addNextError && attributeValue === null) {
|
|
776
|
-
if (!attributeRules?.[ruleName]) {
|
|
777
|
-
addNextError = false;
|
|
778
|
-
|
|
779
|
-
addStructuredError(
|
|
780
|
-
rowErrors,
|
|
781
|
-
attributePath,
|
|
782
|
-
"NULL_NOT_ALLOWED",
|
|
783
|
-
attributeRules?.["allowNullError"] ||
|
|
784
|
-
`value null not valid for attribute ${attributePath}`,
|
|
785
|
-
);
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
break;
|
|
790
|
-
|
|
791
|
-
// ==================================================
|
|
792
|
-
// EMPTY OBJECT
|
|
793
|
-
// ==================================================
|
|
794
|
-
|
|
795
|
-
case "allowEmptyObject":
|
|
796
|
-
if (addNextError) {
|
|
797
|
-
if (
|
|
798
|
-
!attributeRules?.["allowEmptyObject"] &&
|
|
799
|
-
attributeValue != null &&
|
|
800
|
-
Object.keys(attributeValue).length === 0
|
|
801
|
-
) {
|
|
802
|
-
addStructuredError(
|
|
803
|
-
rowErrors,
|
|
804
|
-
attributePath,
|
|
805
|
-
"EMPTY_OBJECT_NOT_ALLOWED",
|
|
806
|
-
attributeRules?.["emptyObjectError"] ||
|
|
807
|
-
`value {} not valid for attribute ${attributePath}`,
|
|
808
|
-
);
|
|
809
|
-
|
|
810
|
-
addNextError = false;
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
break;
|
|
815
|
-
|
|
816
|
-
// ==================================================
|
|
817
|
-
// EMPTY ARRAY
|
|
818
|
-
// ==================================================
|
|
819
|
-
|
|
820
|
-
case "allowEmptyArray":
|
|
821
|
-
if (addNextError) {
|
|
822
|
-
if (
|
|
823
|
-
!attributeRules?.["allowEmptyArray"] &&
|
|
824
|
-
isArray(attributeValue) &&
|
|
825
|
-
attributeValue.length === 0
|
|
826
|
-
) {
|
|
827
|
-
addStructuredError(
|
|
828
|
-
rowErrors,
|
|
829
|
-
attributePath,
|
|
830
|
-
"EMPTY_ARRAY_NOT_ALLOWED",
|
|
831
|
-
attributeRules?.["emptyArrayError"] ||
|
|
832
|
-
`${attributePath} cannot be an empty array`,
|
|
833
|
-
);
|
|
834
|
-
|
|
835
|
-
addNextError = false;
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
break;
|
|
840
|
-
|
|
841
|
-
// ==================================================
|
|
842
|
-
// ARRAY ELEMENT CONSTRAINTS
|
|
843
|
-
// ==================================================
|
|
844
|
-
|
|
845
|
-
case "elementConstraints":
|
|
846
|
-
if (addNextError) {
|
|
847
|
-
if (isArray(attributeValue) && attributeValue.length > 0) {
|
|
848
|
-
let elementError = null;
|
|
849
|
-
|
|
850
|
-
// Clone so original payload array is not mutated
|
|
851
|
-
const transformedArray = [...attributeValue];
|
|
852
|
-
|
|
853
|
-
for (
|
|
854
|
-
let elementIndex = 0;
|
|
855
|
-
elementIndex < attributeValue.length;
|
|
856
|
-
elementIndex++
|
|
857
|
-
) {
|
|
858
|
-
const element = attributeValue[elementIndex];
|
|
859
|
-
|
|
860
|
-
const {
|
|
861
|
-
errors = [],
|
|
862
|
-
validatedPayload: elementValidatedPayload,
|
|
863
|
-
} = perfectPayloadStructured(
|
|
864
|
-
{
|
|
865
|
-
[attributeName]: element,
|
|
866
|
-
},
|
|
867
|
-
{
|
|
868
|
-
[attributeName]: attributeRules[ruleName],
|
|
869
|
-
},
|
|
870
|
-
{ statusCode: 200, valid: true },
|
|
871
|
-
{
|
|
872
|
-
statusCode: 400,
|
|
873
|
-
valid: false,
|
|
874
|
-
message: "One or more attribute values are invalid",
|
|
875
|
-
},
|
|
876
|
-
"",
|
|
877
|
-
options,
|
|
878
|
-
);
|
|
879
|
-
|
|
880
|
-
if (errors.length > 0) {
|
|
881
|
-
const firstElementError = errors[0];
|
|
882
|
-
|
|
883
|
-
const indexedPath = replaceRootPath(
|
|
884
|
-
firstElementError.path,
|
|
885
|
-
attributeName,
|
|
886
|
-
`${attributePath}[${elementIndex}]`,
|
|
887
|
-
);
|
|
888
|
-
|
|
889
|
-
if (attributeRules?.["elementConstraintsError"]) {
|
|
890
|
-
elementError = {
|
|
891
|
-
path: indexedPath,
|
|
892
|
-
code: "INVALID_ARRAY_ELEMENT",
|
|
893
|
-
message: attributeRules["elementConstraintsError"],
|
|
894
|
-
};
|
|
895
|
-
} else {
|
|
896
|
-
elementError = {
|
|
897
|
-
...firstElementError,
|
|
898
|
-
path: indexedPath,
|
|
899
|
-
...(firstElementError.code === "UNKNOWN_FIELD" && {
|
|
900
|
-
message: `Unknown field ${indexedPath} is not allowed`,
|
|
901
|
-
}),
|
|
902
|
-
};
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
break;
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
// Preserve the transformed element
|
|
909
|
-
transformedArray[elementIndex] =
|
|
910
|
-
elementValidatedPayload?.[attributeName];
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
if (elementError) {
|
|
914
|
-
rowErrors.push(elementError);
|
|
915
|
-
addNextError = false;
|
|
916
|
-
} else {
|
|
917
|
-
// All elements passed, so use transformed values
|
|
918
|
-
attributeValue = transformedArray;
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
break;
|
|
924
|
-
case "minItems":
|
|
925
|
-
if (
|
|
926
|
-
addNextError &&
|
|
927
|
-
attrExist &&
|
|
928
|
-
attributeValue !== null &&
|
|
929
|
-
isArray(attributeValue) &&
|
|
930
|
-
attributeValue.length < attributeRules[ruleName]
|
|
931
|
-
) {
|
|
932
|
-
addStructuredError(
|
|
933
|
-
rowErrors,
|
|
934
|
-
attributePath,
|
|
935
|
-
"MIN_ITEMS",
|
|
936
|
-
`Attribute ${attributePath} must contain at least ${attributeRules[ruleName]} item(s)`,
|
|
937
|
-
);
|
|
938
|
-
|
|
939
|
-
addNextError = false;
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
break;
|
|
943
|
-
|
|
944
|
-
case "maxItems":
|
|
945
|
-
if (
|
|
946
|
-
addNextError &&
|
|
947
|
-
attrExist &&
|
|
948
|
-
attributeValue !== null &&
|
|
949
|
-
isArray(attributeValue) &&
|
|
950
|
-
attributeValue.length > attributeRules[ruleName]
|
|
951
|
-
) {
|
|
952
|
-
addStructuredError(
|
|
953
|
-
rowErrors,
|
|
954
|
-
attributePath,
|
|
955
|
-
"MAX_ITEMS",
|
|
956
|
-
`Attribute ${attributePath} must contain at most ${attributeRules[ruleName]} item(s)`,
|
|
957
|
-
);
|
|
958
|
-
|
|
959
|
-
addNextError = false;
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
break;
|
|
963
|
-
// ==================================================
|
|
964
|
-
// REGEX
|
|
965
|
-
// ==================================================
|
|
966
|
-
|
|
967
|
-
case "regex":
|
|
968
|
-
if (addNextError) {
|
|
969
|
-
if (!isPassedRegex(attributeRules[ruleName], attributeValue)) {
|
|
970
|
-
addStructuredError(
|
|
971
|
-
rowErrors,
|
|
972
|
-
attributePath,
|
|
973
|
-
"REGEX_MISMATCH",
|
|
974
|
-
attributeRules?.["regexError"] ||
|
|
975
|
-
`${attributePath} failed to pass the regex ${attributeRules[ruleName]}`,
|
|
976
|
-
);
|
|
977
|
-
|
|
978
|
-
addNextError = false;
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
break;
|
|
983
|
-
|
|
984
|
-
// ==================================================
|
|
985
|
-
// TYPE
|
|
986
|
-
// ==================================================
|
|
987
|
-
|
|
988
|
-
case "type":
|
|
989
|
-
if (addNextError) {
|
|
990
|
-
if (attributeValue == null && nullAllowed) {
|
|
991
|
-
addNextError = true;
|
|
992
|
-
} else {
|
|
993
|
-
const expectedType = attributeRules[ruleName];
|
|
994
|
-
|
|
995
|
-
switch (expectedType) {
|
|
996
|
-
case "number":
|
|
997
|
-
if (
|
|
998
|
-
!isNumber(attributeValue) ||
|
|
999
|
-
Number.isNaN(attributeValue)
|
|
1000
|
-
) {
|
|
1001
|
-
addStructuredError(
|
|
1002
|
-
rowErrors,
|
|
1003
|
-
attributePath,
|
|
1004
|
-
"INVALID_TYPE",
|
|
1005
|
-
attributeRules?.["typeError"] ||
|
|
1006
|
-
getInvalidTypeMessage(
|
|
1007
|
-
attributeValue,
|
|
1008
|
-
attributePath,
|
|
1009
|
-
expectedType,
|
|
1010
|
-
),
|
|
1011
|
-
);
|
|
1012
|
-
|
|
1013
|
-
addNextError = false;
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
break;
|
|
1017
|
-
case "string":
|
|
1018
|
-
if (!isString(attributeValue)) {
|
|
1019
|
-
addStructuredError(
|
|
1020
|
-
rowErrors,
|
|
1021
|
-
attributePath,
|
|
1022
|
-
"INVALID_TYPE",
|
|
1023
|
-
attributeRules?.["typeError"] ||
|
|
1024
|
-
getInvalidTypeMessage(
|
|
1025
|
-
attributeValue,
|
|
1026
|
-
attributePath,
|
|
1027
|
-
expectedType,
|
|
1028
|
-
),
|
|
1029
|
-
);
|
|
1030
|
-
|
|
1031
|
-
addNextError = false;
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
break;
|
|
1035
|
-
|
|
1036
|
-
case "boolean":
|
|
1037
|
-
if (!isBoolean(attributeValue)) {
|
|
1038
|
-
addStructuredError(
|
|
1039
|
-
rowErrors,
|
|
1040
|
-
attributePath,
|
|
1041
|
-
"INVALID_TYPE",
|
|
1042
|
-
attributeRules?.["typeError"] ||
|
|
1043
|
-
getInvalidTypeMessage(
|
|
1044
|
-
attributeValue,
|
|
1045
|
-
attributePath,
|
|
1046
|
-
expectedType,
|
|
1047
|
-
),
|
|
1048
|
-
);
|
|
1049
|
-
|
|
1050
|
-
addNextError = false;
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
break;
|
|
1054
|
-
|
|
1055
|
-
case "email":
|
|
1056
|
-
if (!isValidEmail(attributeValue)) {
|
|
1057
|
-
addStructuredError(
|
|
1058
|
-
rowErrors,
|
|
1059
|
-
attributePath,
|
|
1060
|
-
"INVALID_EMAIL",
|
|
1061
|
-
attributeRules?.["typeError"] ||
|
|
1062
|
-
`Invalid email format for attribute ${attributePath}`,
|
|
1063
|
-
);
|
|
1064
|
-
|
|
1065
|
-
addNextError = false;
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
|
-
break;
|
|
1069
|
-
case "url":
|
|
1070
|
-
if (!isValidUrl(attributeValue)) {
|
|
1071
|
-
addStructuredError(
|
|
1072
|
-
rowErrors,
|
|
1073
|
-
attributePath,
|
|
1074
|
-
"INVALID_URL",
|
|
1075
|
-
attributeRules?.["typeError"] ||
|
|
1076
|
-
`Invalid URL format for attribute ${attributePath}`,
|
|
1077
|
-
);
|
|
1078
|
-
|
|
1079
|
-
addNextError = false;
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
|
-
break;
|
|
1083
|
-
|
|
1084
|
-
case "enum": {
|
|
1085
|
-
const allEnumValues = attributeRules["enumValues"];
|
|
1086
|
-
|
|
1087
|
-
if (!allEnumValues?.includes(attributeValue)) {
|
|
1088
|
-
addStructuredError(
|
|
1089
|
-
rowErrors,
|
|
1090
|
-
attributePath,
|
|
1091
|
-
"INVALID_ENUM",
|
|
1092
|
-
attributeRules?.["typeError"] ||
|
|
1093
|
-
`Invalid value for attribute ${attributePath}, valid values are ${allEnumValues?.join(
|
|
1094
|
-
", ",
|
|
1095
|
-
)}`,
|
|
1096
|
-
);
|
|
1097
|
-
|
|
1098
|
-
addNextError = false;
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
break;
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
case "uuid":
|
|
1105
|
-
if (!isUUID(attributeValue)) {
|
|
1106
|
-
addStructuredError(
|
|
1107
|
-
rowErrors,
|
|
1108
|
-
attributePath,
|
|
1109
|
-
"INVALID_UUID",
|
|
1110
|
-
attributeRules?.["typeError"] ||
|
|
1111
|
-
`Invalid UUID for attribute ${attributePath}`,
|
|
1112
|
-
);
|
|
1113
|
-
|
|
1114
|
-
addNextError = false;
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
break;
|
|
1118
|
-
|
|
1119
|
-
case "uuidv1":
|
|
1120
|
-
if (!isUUIDv1(attributeValue)) {
|
|
1121
|
-
addStructuredError(
|
|
1122
|
-
rowErrors,
|
|
1123
|
-
attributePath,
|
|
1124
|
-
"INVALID_UUID_V1",
|
|
1125
|
-
attributeRules?.["typeError"] ||
|
|
1126
|
-
`Invalid v1 UUID for attribute ${attributePath}`,
|
|
1127
|
-
);
|
|
1128
|
-
|
|
1129
|
-
addNextError = false;
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
break;
|
|
1133
|
-
|
|
1134
|
-
case "uuidv3":
|
|
1135
|
-
if (!isUUIDv3(attributeValue)) {
|
|
1136
|
-
addStructuredError(
|
|
1137
|
-
rowErrors,
|
|
1138
|
-
attributePath,
|
|
1139
|
-
"INVALID_UUID_V3",
|
|
1140
|
-
attributeRules?.["typeError"] ||
|
|
1141
|
-
`Invalid v3 UUID for attribute ${attributePath}`,
|
|
1142
|
-
);
|
|
1143
|
-
|
|
1144
|
-
addNextError = false;
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
break;
|
|
1148
|
-
|
|
1149
|
-
case "uuidv4":
|
|
1150
|
-
if (!isUUIDv4(attributeValue)) {
|
|
1151
|
-
addStructuredError(
|
|
1152
|
-
rowErrors,
|
|
1153
|
-
attributePath,
|
|
1154
|
-
"INVALID_UUID_V4",
|
|
1155
|
-
attributeRules?.["typeError"] ||
|
|
1156
|
-
`Invalid v4 UUID for attribute ${attributePath}`,
|
|
1157
|
-
);
|
|
1158
|
-
|
|
1159
|
-
addNextError = false;
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
|
-
break;
|
|
1163
|
-
|
|
1164
|
-
case "uuidv5":
|
|
1165
|
-
if (!isUUIDv5(attributeValue)) {
|
|
1166
|
-
addStructuredError(
|
|
1167
|
-
rowErrors,
|
|
1168
|
-
attributePath,
|
|
1169
|
-
"INVALID_UUID_V5",
|
|
1170
|
-
attributeRules?.["typeError"] ||
|
|
1171
|
-
`Invalid v5 UUID for attribute ${attributePath}`,
|
|
1172
|
-
);
|
|
1173
|
-
|
|
1174
|
-
addNextError = false;
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
break;
|
|
1178
|
-
|
|
1179
|
-
case "objectId":
|
|
1180
|
-
if (!isObjectId(attributeValue)) {
|
|
1181
|
-
addStructuredError(
|
|
1182
|
-
rowErrors,
|
|
1183
|
-
attributePath,
|
|
1184
|
-
"INVALID_OBJECT_ID",
|
|
1185
|
-
attributeRules?.["typeError"] ||
|
|
1186
|
-
`Invalid ObjectId for attribute ${attributePath}`,
|
|
1187
|
-
);
|
|
1188
|
-
|
|
1189
|
-
addNextError = false;
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
break;
|
|
1193
|
-
|
|
1194
|
-
case "array":
|
|
1195
|
-
if (!isArray(attributeValue)) {
|
|
1196
|
-
addStructuredError(
|
|
1197
|
-
rowErrors,
|
|
1198
|
-
attributePath,
|
|
1199
|
-
"INVALID_TYPE",
|
|
1200
|
-
attributeRules?.["typeError"] ||
|
|
1201
|
-
getInvalidTypeMessage(
|
|
1202
|
-
attributeValue,
|
|
1203
|
-
attributePath,
|
|
1204
|
-
expectedType,
|
|
1205
|
-
),
|
|
1206
|
-
);
|
|
1207
|
-
|
|
1208
|
-
addNextError = false;
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
|
-
break;
|
|
1212
|
-
|
|
1213
|
-
case "object":
|
|
1214
|
-
if (!isObject(attributeValue)) {
|
|
1215
|
-
addStructuredError(
|
|
1216
|
-
rowErrors,
|
|
1217
|
-
attributePath,
|
|
1218
|
-
"INVALID_TYPE",
|
|
1219
|
-
attributeRules?.["typeError"] ||
|
|
1220
|
-
getInvalidTypeMessage(
|
|
1221
|
-
attributeValue,
|
|
1222
|
-
attributePath,
|
|
1223
|
-
expectedType,
|
|
1224
|
-
),
|
|
1225
|
-
);
|
|
1226
|
-
|
|
1227
|
-
addNextError = false;
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
break;
|
|
1231
|
-
|
|
1232
|
-
default:
|
|
1233
|
-
break;
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
|
|
1238
|
-
break;
|
|
1239
|
-
|
|
1240
|
-
// ==================================================
|
|
1241
|
-
// MIN LENGTH
|
|
1242
|
-
// ==================================================
|
|
1243
|
-
|
|
1244
|
-
case "minLength":
|
|
1245
|
-
if (addNextError) {
|
|
1246
|
-
if (attributeValue == null && nullAllowed) {
|
|
1247
|
-
addNextError = true;
|
|
1248
|
-
} else if (typeof attributeValue === "string") {
|
|
1249
|
-
if (attributeValue.length < +attributeRules[ruleName]) {
|
|
1250
|
-
addStructuredError(
|
|
1251
|
-
rowErrors,
|
|
1252
|
-
attributePath,
|
|
1253
|
-
"MIN_LENGTH",
|
|
1254
|
-
attributeRules?.["minLengthError"] ||
|
|
1255
|
-
`${attributePath} should be minimum of ${attributeRules[ruleName]} character`,
|
|
1256
|
-
);
|
|
1257
|
-
|
|
1258
|
-
addNextError = false;
|
|
1259
|
-
}
|
|
1260
|
-
} else {
|
|
1261
|
-
addStructuredError(
|
|
1262
|
-
rowErrors,
|
|
1263
|
-
attributePath,
|
|
1264
|
-
"INVALID_TYPE",
|
|
1265
|
-
`${attributePath} value should be a string type(minLength specified)`,
|
|
1266
|
-
);
|
|
1267
|
-
|
|
1268
|
-
addNextError = false;
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
|
|
1272
|
-
break;
|
|
1273
|
-
|
|
1274
|
-
// ==================================================
|
|
1275
|
-
// MAX LENGTH
|
|
1276
|
-
// ==================================================
|
|
1277
|
-
|
|
1278
|
-
case "maxLength":
|
|
1279
|
-
if (addNextError) {
|
|
1280
|
-
if (attributeValue == null && nullAllowed) {
|
|
1281
|
-
addNextError = true;
|
|
1282
|
-
} else if (typeof attributeValue === "string") {
|
|
1283
|
-
if (attributeValue.length > +attributeRules[ruleName]) {
|
|
1284
|
-
addStructuredError(
|
|
1285
|
-
rowErrors,
|
|
1286
|
-
attributePath,
|
|
1287
|
-
"MAX_LENGTH",
|
|
1288
|
-
attributeRules?.["maxLengthError"] ||
|
|
1289
|
-
`${attributePath} can have maximum of ${attributeRules[ruleName]} character`,
|
|
1290
|
-
);
|
|
1291
|
-
|
|
1292
|
-
addNextError = false;
|
|
1293
|
-
}
|
|
1294
|
-
} else {
|
|
1295
|
-
addStructuredError(
|
|
1296
|
-
rowErrors,
|
|
1297
|
-
attributePath,
|
|
1298
|
-
"INVALID_TYPE",
|
|
1299
|
-
`${attributePath} value should be a string type(maxLength specified)`,
|
|
1300
|
-
);
|
|
1301
|
-
|
|
1302
|
-
addNextError = false;
|
|
1303
|
-
}
|
|
1304
|
-
}
|
|
1305
|
-
|
|
1306
|
-
break;
|
|
1307
|
-
|
|
1308
|
-
// ==================================================
|
|
1309
|
-
// PREVENT DECIMAL
|
|
1310
|
-
// ==================================================
|
|
1311
|
-
|
|
1312
|
-
case "preventDecimal":
|
|
1313
|
-
if (addNextError) {
|
|
1314
|
-
if (attributeValue == null && nullAllowed) {
|
|
1315
|
-
addNextError = true;
|
|
1316
|
-
} else if (!isNumber(attributeValue)) {
|
|
1317
|
-
addStructuredError(
|
|
1318
|
-
rowErrors,
|
|
1319
|
-
attributePath,
|
|
1320
|
-
"INVALID_TYPE",
|
|
1321
|
-
`Invalid type for attribute ${attributePath}, required number value`,
|
|
1322
|
-
);
|
|
1323
|
-
|
|
1324
|
-
addNextError = false;
|
|
1325
|
-
} else if (+attributeValue % 1 !== 0) {
|
|
1326
|
-
addStructuredError(
|
|
1327
|
-
rowErrors,
|
|
1328
|
-
attributePath,
|
|
1329
|
-
"DECIMAL_NOT_ALLOWED",
|
|
1330
|
-
attributeRules?.["preventDecimalError"] ||
|
|
1331
|
-
`Decimal value not allowed in attribute ${attributePath}`,
|
|
1332
|
-
);
|
|
1333
|
-
|
|
1334
|
-
addNextError = false;
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
|
-
break;
|
|
1339
|
-
|
|
1340
|
-
// ==================================================
|
|
1341
|
-
// MIN
|
|
1342
|
-
// ==================================================
|
|
1343
|
-
|
|
1344
|
-
case "min":
|
|
1345
|
-
if (addNextError) {
|
|
1346
|
-
if (attributeValue == null && nullAllowed) {
|
|
1347
|
-
addNextError = true;
|
|
1348
|
-
} else if (!isNumber(attributeValue)) {
|
|
1349
|
-
addStructuredError(
|
|
1350
|
-
rowErrors,
|
|
1351
|
-
attributePath,
|
|
1352
|
-
"INVALID_TYPE",
|
|
1353
|
-
`Invalid type for attribute ${attributePath}, required number value`,
|
|
1354
|
-
);
|
|
1355
|
-
|
|
1356
|
-
addNextError = false;
|
|
1357
|
-
} else if (+attributeValue < +attributeRules[ruleName]) {
|
|
1358
|
-
addStructuredError(
|
|
1359
|
-
rowErrors,
|
|
1360
|
-
attributePath,
|
|
1361
|
-
"MIN_VALUE",
|
|
1362
|
-
attributeRules?.["minError"] ||
|
|
1363
|
-
`Minimum value ${attributeRules[ruleName]} is allowed in attribute ${attributePath}`,
|
|
1364
|
-
);
|
|
1365
|
-
|
|
1366
|
-
addNextError = false;
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
|
|
1370
|
-
break;
|
|
1371
|
-
// ==================================================
|
|
1372
|
-
// MAX
|
|
1373
|
-
// ==================================================
|
|
1374
|
-
case "max":
|
|
1375
|
-
if (addNextError) {
|
|
1376
|
-
if (attributeValue == null && nullAllowed) {
|
|
1377
|
-
addNextError = true;
|
|
1378
|
-
} else if (!isNumber(attributeValue)) {
|
|
1379
|
-
addStructuredError(
|
|
1380
|
-
rowErrors,
|
|
1381
|
-
attributePath,
|
|
1382
|
-
"INVALID_TYPE",
|
|
1383
|
-
`Invalid type for attribute ${attributePath}, required number value`,
|
|
1384
|
-
);
|
|
1385
|
-
|
|
1386
|
-
addNextError = false;
|
|
1387
|
-
} else if (+attributeValue > +attributeRules[ruleName]) {
|
|
1388
|
-
addStructuredError(
|
|
1389
|
-
rowErrors,
|
|
1390
|
-
attributePath,
|
|
1391
|
-
"MAX_VALUE",
|
|
1392
|
-
attributeRules?.["maxError"] ||
|
|
1393
|
-
`Maximum value ${attributeRules[ruleName]} is allowed in attribute ${attributePath}`,
|
|
1394
|
-
);
|
|
1395
|
-
|
|
1396
|
-
addNextError = false;
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
|
-
|
|
1400
|
-
break;
|
|
1401
|
-
|
|
1402
|
-
// ==================================================
|
|
1403
|
-
// RANGE
|
|
1404
|
-
// ==================================================
|
|
1405
|
-
|
|
1406
|
-
case "range":
|
|
1407
|
-
if (addNextError) {
|
|
1408
|
-
if (attributeValue == null && nullAllowed) {
|
|
1409
|
-
addNextError = true;
|
|
1410
|
-
} else if (!isNumber(attributeValue)) {
|
|
1411
|
-
addStructuredError(
|
|
1412
|
-
rowErrors,
|
|
1413
|
-
attributePath,
|
|
1414
|
-
"INVALID_TYPE",
|
|
1415
|
-
`Invalid type for attribute ${attributePath}, required number value`,
|
|
1416
|
-
);
|
|
1417
|
-
|
|
1418
|
-
addNextError = false;
|
|
1419
|
-
} else {
|
|
1420
|
-
const [min, max] = attributeRules[ruleName].split("-");
|
|
1421
|
-
|
|
1422
|
-
if (+attributeValue < +min || +attributeValue > +max) {
|
|
1423
|
-
addStructuredError(
|
|
1424
|
-
rowErrors,
|
|
1425
|
-
attributePath,
|
|
1426
|
-
"OUT_OF_RANGE",
|
|
1427
|
-
attributeRules?.["rangeError"] ||
|
|
1428
|
-
`Attribute ${attributePath} should have a value between ${min} and ${max}`,
|
|
1429
|
-
);
|
|
1430
|
-
|
|
1431
|
-
addNextError = false;
|
|
1432
|
-
}
|
|
1433
|
-
}
|
|
1434
|
-
}
|
|
1435
|
-
|
|
1436
|
-
break;
|
|
1437
|
-
// ==================================================
|
|
1438
|
-
// NESTED OBJECT
|
|
1439
|
-
// ==================================================
|
|
1440
|
-
case "objectAttr":
|
|
1441
|
-
if (addNextError) {
|
|
1442
|
-
const { errors = [], validatedPayload: nestedValidatedPayload } =
|
|
1443
|
-
perfectPayloadStructured(
|
|
1444
|
-
attributeValue,
|
|
1445
|
-
attributeRules?.[ruleName],
|
|
1446
|
-
{ statusCode: 200, valid: true },
|
|
1447
|
-
{
|
|
1448
|
-
statusCode: 400,
|
|
1449
|
-
valid: false,
|
|
1450
|
-
message: "One or more attribute values are invalid",
|
|
1451
|
-
},
|
|
1452
|
-
attributePath,
|
|
1453
|
-
options,
|
|
1454
|
-
);
|
|
1455
|
-
|
|
1456
|
-
if (errors.length === 0) {
|
|
1457
|
-
attributeValue = nestedValidatedPayload;
|
|
1458
|
-
}
|
|
1459
|
-
|
|
1460
|
-
rowErrors = [...rowErrors, ...errors];
|
|
1461
|
-
}
|
|
1462
|
-
|
|
1463
|
-
break;
|
|
1464
|
-
|
|
1465
|
-
// ==================================================
|
|
1466
|
-
// DEPENDENCY
|
|
1467
|
-
// ==================================================
|
|
1468
|
-
|
|
1469
|
-
case "dependency":
|
|
1470
|
-
if (addNextError) {
|
|
1471
|
-
const allDependencyAttr = Object.keys(attributeRules?.[ruleName]);
|
|
1472
|
-
|
|
1473
|
-
for (const attr of allDependencyAttr) {
|
|
1474
|
-
const dependencyRule = attributeRules?.[ruleName]?.[attr];
|
|
1475
|
-
|
|
1476
|
-
if (typeof dependencyRule?.setDependencyRule === "function") {
|
|
1477
|
-
const newRule = dependencyRule.setDependencyRule(
|
|
1478
|
-
attributeValue,
|
|
1479
|
-
data?.[attr],
|
|
1480
|
-
);
|
|
1481
|
-
|
|
1482
|
-
let newData = {
|
|
1483
|
-
[attributeName]: attributeValue,
|
|
1484
|
-
};
|
|
1485
|
-
|
|
1486
|
-
if (Object.keys(data ?? {}).includes(attr)) {
|
|
1487
|
-
newData = {
|
|
1488
|
-
...newData,
|
|
1489
|
-
[attr]: data?.[attr],
|
|
1490
|
-
};
|
|
1491
|
-
}
|
|
1492
|
-
|
|
1493
|
-
const { errors = [] } = perfectPayloadStructured(
|
|
1494
|
-
newData,
|
|
1495
|
-
{
|
|
1496
|
-
[attr]: newRule,
|
|
1497
|
-
},
|
|
1498
|
-
{
|
|
1499
|
-
statusCode: 200,
|
|
1500
|
-
valid: true,
|
|
1501
|
-
},
|
|
1502
|
-
{
|
|
1503
|
-
statusCode: 400,
|
|
1504
|
-
valid: false,
|
|
1505
|
-
message: "One or more attribute values are invalid",
|
|
1506
|
-
},
|
|
1507
|
-
basePath,
|
|
1508
|
-
);
|
|
1509
|
-
|
|
1510
|
-
rowErrors = [...rowErrors, ...errors];
|
|
1511
|
-
|
|
1512
|
-
addNextError = true;
|
|
1513
|
-
} else {
|
|
1514
|
-
throw new Error(
|
|
1515
|
-
`perfect-payload:- function setDependencyRule not found in ${attr} dependency `,
|
|
1516
|
-
);
|
|
1517
|
-
}
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
|
|
1521
|
-
break;
|
|
1522
|
-
|
|
1523
|
-
// ==================================================
|
|
1524
|
-
// CUSTOM VALIDATOR
|
|
1525
|
-
// ==================================================
|
|
1526
|
-
|
|
1527
|
-
case "customValidator":
|
|
1528
|
-
if (
|
|
1529
|
-
!skipCustomValidator &&
|
|
1530
|
-
addNextError &&
|
|
1531
|
-
attrExist &&
|
|
1532
|
-
attributeValue !== null
|
|
1533
|
-
) {
|
|
1534
|
-
const validator = attributeRules?.[ruleName];
|
|
1535
|
-
|
|
1536
|
-
if (typeof validator !== "function") {
|
|
1537
|
-
throw new Error(
|
|
1538
|
-
`perfect-payload:- customValidator must be a function for attribute ${attributePath}`,
|
|
1539
|
-
);
|
|
1540
|
-
}
|
|
1541
|
-
|
|
1542
|
-
const validationResult = validator(attributeValue, data);
|
|
1543
|
-
|
|
1544
|
-
if (
|
|
1545
|
-
validationResult &&
|
|
1546
|
-
typeof validationResult.then === "function"
|
|
1547
|
-
) {
|
|
1548
|
-
throw new Error(
|
|
1549
|
-
`perfect-payload:- customValidator must be synchronous for attribute ${attributePath}`,
|
|
1550
|
-
);
|
|
1551
|
-
}
|
|
1552
|
-
|
|
1553
|
-
if (validationResult !== true) {
|
|
1554
|
-
addStructuredError(
|
|
1555
|
-
rowErrors,
|
|
1556
|
-
attributePath,
|
|
1557
|
-
attributeRules?.["customValidatorCode"] ||
|
|
1558
|
-
"CUSTOM_VALIDATION_FAILED",
|
|
1559
|
-
attributeRules?.["customValidatorError"] ||
|
|
1560
|
-
`Custom validation failed for attribute ${attributePath}`,
|
|
1561
|
-
);
|
|
1562
|
-
|
|
1563
|
-
addNextError = false;
|
|
1564
|
-
}
|
|
1565
|
-
}
|
|
1566
|
-
|
|
1567
|
-
break;
|
|
1568
|
-
|
|
1569
|
-
default:
|
|
1570
|
-
break;
|
|
1571
|
-
}
|
|
1572
|
-
}
|
|
1573
|
-
|
|
1574
|
-
if (
|
|
1575
|
-
attrExist &&
|
|
1576
|
-
!rowErrors.some(
|
|
1577
|
-
(error) =>
|
|
1578
|
-
error.path === attributePath ||
|
|
1579
|
-
error.path.startsWith(`${attributePath}.`) ||
|
|
1580
|
-
error.path.startsWith(`${attributePath}[`),
|
|
1581
|
-
)
|
|
1582
|
-
) {
|
|
1583
|
-
validatedPayload[attributeName] = attributeValue;
|
|
1584
|
-
}
|
|
1585
|
-
}
|
|
1586
|
-
|
|
1587
|
-
// UNKNOWN FIELD HANDLING
|
|
1588
|
-
if (unknownFields === "allow") {
|
|
1589
|
-
for (const attributeName in data) {
|
|
1590
|
-
if (
|
|
1591
|
-
Object.prototype.hasOwnProperty.call(data, attributeName) &&
|
|
1592
|
-
!Object.prototype.hasOwnProperty.call(dataValidationRule, attributeName)
|
|
1593
|
-
) {
|
|
1594
|
-
validatedPayload[attributeName] = data[attributeName];
|
|
1595
|
-
}
|
|
1596
|
-
}
|
|
1597
|
-
}
|
|
1598
|
-
|
|
1599
|
-
if (unknownFields === "reject") {
|
|
1600
|
-
for (const attributeName in data) {
|
|
1601
|
-
if (
|
|
1602
|
-
Object.prototype.hasOwnProperty.call(data, attributeName) &&
|
|
1603
|
-
!Object.prototype.hasOwnProperty.call(dataValidationRule, attributeName)
|
|
1604
|
-
) {
|
|
1605
|
-
const path = basePath ? `${basePath}.${attributeName}` : attributeName;
|
|
1606
|
-
|
|
1607
|
-
rowErrors.push({
|
|
1608
|
-
path,
|
|
1609
|
-
code: "UNKNOWN_FIELD",
|
|
1610
|
-
message: `Unknown field ${path} is not allowed`,
|
|
1611
|
-
});
|
|
1612
|
-
}
|
|
1613
|
-
}
|
|
1614
|
-
}
|
|
1615
|
-
|
|
1616
|
-
// INVALID RESPONSE
|
|
1617
|
-
if (rowErrors.length > 0) {
|
|
1618
|
-
return {
|
|
1619
|
-
...inValidPayloadResponse,
|
|
1620
|
-
errors: rowErrors,
|
|
1621
|
-
};
|
|
1622
|
-
}
|
|
1623
|
-
|
|
1624
|
-
// VALID RESPONSE
|
|
1625
|
-
return {
|
|
1626
|
-
...validPayloadResponse,
|
|
1627
|
-
validatedPayload,
|
|
1628
|
-
};
|
|
1629
|
-
}
|
|
1630
|
-
|
|
1631
|
-
function addStructuredError(errors, path, code, message) {
|
|
1632
|
-
errors.push({
|
|
1633
|
-
path,
|
|
1634
|
-
code,
|
|
1635
|
-
message,
|
|
1636
|
-
});
|
|
1637
|
-
}
|
|
1638
|
-
|
|
1639
|
-
function getAttributePath(attributeName, attributeRules, basePath) {
|
|
1640
|
-
const customPath = attributeRules?.path;
|
|
1641
|
-
|
|
1642
|
-
if (customPath) {
|
|
1643
|
-
return `${customPath}.${attributeName}`;
|
|
1644
|
-
}
|
|
1645
|
-
|
|
1646
|
-
if (basePath) {
|
|
1647
|
-
return `${basePath}.${attributeName}`;
|
|
1648
|
-
}
|
|
1649
|
-
|
|
1650
|
-
return attributeName;
|
|
1651
|
-
}
|
|
1652
|
-
|
|
1653
|
-
function replaceRootPath(currentPath, currentRoot, replacementRoot) {
|
|
1654
|
-
if (currentPath === currentRoot) {
|
|
1655
|
-
return replacementRoot;
|
|
1656
|
-
}
|
|
1657
|
-
|
|
1658
|
-
if (currentPath.startsWith(`${currentRoot}.`)) {
|
|
1659
|
-
return `${replacementRoot}${currentPath.slice(currentRoot.length)}`;
|
|
1660
|
-
}
|
|
1661
|
-
|
|
1662
|
-
if (currentPath.startsWith(`${currentRoot}[`)) {
|
|
1663
|
-
return `${replacementRoot}${currentPath.slice(currentRoot.length)}`;
|
|
1664
|
-
}
|
|
1665
|
-
|
|
1666
|
-
return replacementRoot;
|
|
1667
|
-
}
|
|
1668
|
-
|
|
1669
|
-
function getInvalidTypeMessage(value, attributePath, expectedType) {
|
|
1670
|
-
return `Invalid type for attribute ${attributePath}, required ${expectedType} value`;
|
|
1671
|
-
// return `Invalid ${typeof value} value(${value}) found in attribute ${attributePath}, required ${expectedType} value`;
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1674
|
-
function isNumber(value) {
|
|
1675
|
-
return typeof value == "number";
|
|
1676
|
-
}
|
|
1677
|
-
|
|
1678
|
-
function isString(value) {
|
|
1679
|
-
return typeof value == "string";
|
|
1680
|
-
}
|
|
1681
|
-
|
|
1682
|
-
function isBoolean(value) {
|
|
1683
|
-
return typeof value == "boolean";
|
|
1684
|
-
}
|
|
1685
|
-
|
|
1686
|
-
function isArray(value) {
|
|
1687
|
-
return Array.isArray(value);
|
|
1688
|
-
}
|
|
1689
|
-
|
|
1690
|
-
function isObject(value) {
|
|
1691
|
-
return typeof value == "object";
|
|
1692
|
-
}
|
|
1693
|
-
|
|
1694
|
-
function isValidEmail(email) {
|
|
1695
|
-
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
|
1696
|
-
return emailRegex.test(email);
|
|
1697
|
-
}
|
|
1698
|
-
|
|
1699
|
-
function isValidUrl(url) {
|
|
1700
|
-
const urlRegex =
|
|
1701
|
-
/^(https?:\/\/)([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})(:[0-9]+)?(\/[^\s]*)?(\?[^\s]*)?$/;
|
|
1702
|
-
return urlRegex.test(url);
|
|
1703
|
-
}
|
|
1704
|
-
|
|
1705
|
-
function isUUID(uuid) {
|
|
1706
|
-
const uuidRegex =
|
|
1707
|
-
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
1708
|
-
|
|
1709
|
-
return uuidRegex.test(uuid);
|
|
1710
|
-
}
|
|
1711
|
-
|
|
1712
|
-
function isUUIDv1(uuid) {
|
|
1713
|
-
const uuidRegex =
|
|
1714
|
-
/^[0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
1715
|
-
|
|
1716
|
-
return uuidRegex.test(uuid);
|
|
1717
|
-
}
|
|
1718
|
-
|
|
1719
|
-
function isUUIDv3(uuid) {
|
|
1720
|
-
const uuidRegex =
|
|
1721
|
-
/^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
1722
|
-
|
|
1723
|
-
return uuidRegex.test(uuid);
|
|
1724
|
-
}
|
|
1725
|
-
|
|
1726
|
-
function isUUIDv4(uuid) {
|
|
1727
|
-
const uuidRegex =
|
|
1728
|
-
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
1729
|
-
|
|
1730
|
-
return uuidRegex.test(uuid);
|
|
1731
|
-
}
|
|
1732
|
-
|
|
1733
|
-
function isUUIDv5(uuid) {
|
|
1734
|
-
const uuidRegex =
|
|
1735
|
-
/^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
1736
|
-
|
|
1737
|
-
return uuidRegex.test(uuid);
|
|
1738
|
-
}
|
|
1739
|
-
|
|
1740
|
-
function isObjectId(id) {
|
|
1741
|
-
return /^[0-9a-fA-F]{24}$/.test(id);
|
|
1742
|
-
}
|
|
1743
|
-
|
|
1744
|
-
function isPassedRegex(reExpression, value) {
|
|
1745
|
-
return reExpression.test(value);
|
|
1746
|
-
}
|
|
1747
|
-
|
|
1748
|
-
async function runAsyncCustomValidators(
|
|
1749
|
-
data = {},
|
|
1750
|
-
dataValidationRule = {},
|
|
1751
|
-
basePath = "",
|
|
1752
|
-
) {
|
|
1753
|
-
const errors = [];
|
|
1754
|
-
|
|
1755
|
-
for (const attributeName in dataValidationRule) {
|
|
1756
|
-
const attributeRules = dataValidationRule?.[attributeName];
|
|
1757
|
-
|
|
1758
|
-
const attrExist = Object.keys(data ?? {}).includes(attributeName);
|
|
1759
|
-
|
|
1760
|
-
if (!attrExist) {
|
|
1761
|
-
continue;
|
|
1762
|
-
}
|
|
1763
|
-
|
|
1764
|
-
const attributeValue = data?.[attributeName];
|
|
1765
|
-
|
|
1766
|
-
const attributePath = getAttributePath(
|
|
1767
|
-
attributeName,
|
|
1768
|
-
attributeRules,
|
|
1769
|
-
basePath,
|
|
1770
|
-
);
|
|
1771
|
-
|
|
1772
|
-
// customValidator
|
|
1773
|
-
if (
|
|
1774
|
-
Object.prototype.hasOwnProperty.call(
|
|
1775
|
-
attributeRules ?? {},
|
|
1776
|
-
"customValidator",
|
|
1777
|
-
)
|
|
1778
|
-
) {
|
|
1779
|
-
if (typeof attributeRules.customValidator !== "function") {
|
|
1780
|
-
throw new Error(
|
|
1781
|
-
`perfect-payload:- customValidator must be a function for attribute ${attributePath}`,
|
|
1782
|
-
);
|
|
1783
|
-
}
|
|
1784
|
-
|
|
1785
|
-
if (attributeValue !== null) {
|
|
1786
|
-
const validationResponse = await attributeRules.customValidator(
|
|
1787
|
-
attributeValue,
|
|
1788
|
-
data,
|
|
1789
|
-
);
|
|
1790
|
-
|
|
1791
|
-
if (validationResponse !== true) {
|
|
1792
|
-
addStructuredError(
|
|
1793
|
-
errors,
|
|
1794
|
-
attributePath,
|
|
1795
|
-
attributeRules?.customValidatorCode || "CUSTOM_VALIDATION_FAILED",
|
|
1796
|
-
attributeRules?.customValidatorError ||
|
|
1797
|
-
`Custom validation failed for attribute ${attributePath}`,
|
|
1798
|
-
);
|
|
1799
|
-
}
|
|
1800
|
-
}
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
|
-
// nested objectAttr
|
|
1804
|
-
if (
|
|
1805
|
-
attributeValue !== null &&
|
|
1806
|
-
typeof attributeValue === "object" &&
|
|
1807
|
-
!Array.isArray(attributeValue) &&
|
|
1808
|
-
attributeRules?.objectAttr
|
|
1809
|
-
) {
|
|
1810
|
-
const nestedErrors = await runAsyncCustomValidators(
|
|
1811
|
-
attributeValue,
|
|
1812
|
-
attributeRules.objectAttr,
|
|
1813
|
-
attributePath,
|
|
1814
|
-
);
|
|
1815
|
-
|
|
1816
|
-
errors.push(...nestedErrors);
|
|
1817
|
-
}
|
|
1818
|
-
|
|
1819
|
-
// nested elementConstraints
|
|
1820
|
-
if (Array.isArray(attributeValue) && attributeRules?.elementConstraints) {
|
|
1821
|
-
for (
|
|
1822
|
-
let elementIndex = 0;
|
|
1823
|
-
elementIndex < attributeValue.length;
|
|
1824
|
-
elementIndex++
|
|
1825
|
-
) {
|
|
1826
|
-
const element = attributeValue[elementIndex];
|
|
1827
|
-
|
|
1828
|
-
const elementErrors = await runAsyncCustomValidators(
|
|
1829
|
-
{
|
|
1830
|
-
[attributeName]: element,
|
|
1831
|
-
},
|
|
1832
|
-
{
|
|
1833
|
-
[attributeName]: attributeRules.elementConstraints,
|
|
1834
|
-
},
|
|
1835
|
-
);
|
|
1836
|
-
|
|
1837
|
-
for (const elementError of elementErrors) {
|
|
1838
|
-
const indexedPath = replaceRootPath(
|
|
1839
|
-
elementError.path,
|
|
1840
|
-
attributeName,
|
|
1841
|
-
`${attributePath}[${elementIndex}]`,
|
|
1842
|
-
);
|
|
1843
|
-
|
|
1844
|
-
errors.push({
|
|
1845
|
-
...elementError,
|
|
1846
|
-
path: indexedPath,
|
|
1847
|
-
|
|
1848
|
-
message:
|
|
1849
|
-
elementError.code === "CUSTOM_VALIDATION_FAILED" &&
|
|
1850
|
-
elementError.message ===
|
|
1851
|
-
`Custom validation failed for attribute ${elementError.path}`
|
|
1852
|
-
? `Custom validation failed for attribute ${indexedPath}`
|
|
1853
|
-
: elementError.message,
|
|
1854
|
-
});
|
|
1855
|
-
}
|
|
1856
|
-
}
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
|
|
1860
|
-
return errors;
|
|
1861
|
-
}
|