nox-validation 1.4.2 → 1.4.3
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/lib/helpers.js +83 -5
- package/lib/validate.js +123 -52
- package/package.json +1 -1
package/lib/helpers.js
CHANGED
|
@@ -59,6 +59,52 @@ const keyExists = (obj, key, separator = ".") => {
|
|
|
59
59
|
});
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
+
const remainingItems = ({ all = [], obj = {}, isM2A = false }) => {
|
|
63
|
+
const resultSet = new Set(all);
|
|
64
|
+
|
|
65
|
+
if (Array.isArray(obj.existing)) {
|
|
66
|
+
obj.existing.forEach((id) => {
|
|
67
|
+
if (isM2A && id && typeof id === "object" && "item" in id) {
|
|
68
|
+
resultSet.add(id.item);
|
|
69
|
+
} else {
|
|
70
|
+
resultSet.add(id);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (Array.isArray(obj.create)) {
|
|
76
|
+
obj.create.forEach((item, idx) => {
|
|
77
|
+
if (item && item._id) {
|
|
78
|
+
resultSet.add(item._id);
|
|
79
|
+
} else if (item) {
|
|
80
|
+
resultSet.add(`create_${idx}`);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (Array.isArray(obj.update)) {
|
|
86
|
+
obj.update.forEach((item) => {
|
|
87
|
+
if (isM2A && item && item.item) {
|
|
88
|
+
resultSet.add(item.item);
|
|
89
|
+
} else if (item && item._id) {
|
|
90
|
+
resultSet.add(item._id);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (Array.isArray(obj.delete)) {
|
|
96
|
+
obj.delete.forEach((id) => {
|
|
97
|
+
if (isM2A && id && typeof id === "object" && "item" in id) {
|
|
98
|
+
resultSet.delete(id.item);
|
|
99
|
+
} else {
|
|
100
|
+
resultSet.delete(id);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return resultSet.size > 0;
|
|
106
|
+
};
|
|
107
|
+
|
|
62
108
|
const formatLabel = (str) => {
|
|
63
109
|
return str
|
|
64
110
|
?.replace(/_/g, " ")
|
|
@@ -275,6 +321,7 @@ const generateField = (
|
|
|
275
321
|
...child,
|
|
276
322
|
value: childKey,
|
|
277
323
|
key: childValue,
|
|
324
|
+
isRelationalUpdate: path.includes("update"),
|
|
278
325
|
};
|
|
279
326
|
});
|
|
280
327
|
|
|
@@ -780,7 +827,7 @@ const buildNestedStructure = ({
|
|
|
780
827
|
childFields = getCachedFields(relationDetail, relational_fields);
|
|
781
828
|
}
|
|
782
829
|
if (item.meta.interface === constants.interfaces.TRANSLATIONS) {
|
|
783
|
-
childFields = childFields.map(f => {
|
|
830
|
+
childFields = childFields.map((f) => {
|
|
784
831
|
if (
|
|
785
832
|
f.field === relationDetail.foreign_field ||
|
|
786
833
|
f.field === relationDetail.junction_field_this
|
|
@@ -789,8 +836,8 @@ const buildNestedStructure = ({
|
|
|
789
836
|
...f,
|
|
790
837
|
meta: {
|
|
791
838
|
...f.meta,
|
|
792
|
-
interface: "none"
|
|
793
|
-
}
|
|
839
|
+
interface: "none",
|
|
840
|
+
},
|
|
794
841
|
};
|
|
795
842
|
}
|
|
796
843
|
return f;
|
|
@@ -926,7 +973,7 @@ const buildNestedStructure = ({
|
|
|
926
973
|
|
|
927
974
|
if (parentNode) {
|
|
928
975
|
parentNode.children.push(node);
|
|
929
|
-
}
|
|
976
|
+
}
|
|
930
977
|
// else {
|
|
931
978
|
// console.warn("[WARN] Parent node not found for:", node);
|
|
932
979
|
// }
|
|
@@ -1325,7 +1372,37 @@ const getSelectedNodes = ({
|
|
|
1325
1372
|
|
|
1326
1373
|
if (Array.isArray(currentNode.children)) {
|
|
1327
1374
|
currentNode.children.forEach((child) => {
|
|
1328
|
-
|
|
1375
|
+
let childNode = {
|
|
1376
|
+
...child,
|
|
1377
|
+
key:
|
|
1378
|
+
currentNode.type === constants.types.ARRAY
|
|
1379
|
+
? child.key.replace(currentNode.key, `${currentNode.key}[0]`)
|
|
1380
|
+
: child.key,
|
|
1381
|
+
};
|
|
1382
|
+
|
|
1383
|
+
if (Array.isArray(child.children) && child.children.length > 0) {
|
|
1384
|
+
const updateChildKeys = (node, parentKey, newParentKey) => {
|
|
1385
|
+
let updatedNode = {
|
|
1386
|
+
...node,
|
|
1387
|
+
key: node.key.replace(parentKey, newParentKey),
|
|
1388
|
+
};
|
|
1389
|
+
if (Array.isArray(node.children) && node.children.length > 0) {
|
|
1390
|
+
updatedNode.children = node.children.map((c) =>
|
|
1391
|
+
updateChildKeys(c, parentKey, newParentKey)
|
|
1392
|
+
);
|
|
1393
|
+
}
|
|
1394
|
+
return updatedNode;
|
|
1395
|
+
};
|
|
1396
|
+
if (currentNode.type === constants.types.ARRAY) {
|
|
1397
|
+
childNode = updateChildKeys(
|
|
1398
|
+
child,
|
|
1399
|
+
currentNode.key,
|
|
1400
|
+
`${currentNode.key}[0]`
|
|
1401
|
+
);
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
if (!skipFn(currentNode)) traverse(childNode);
|
|
1329
1406
|
});
|
|
1330
1407
|
}
|
|
1331
1408
|
}
|
|
@@ -1355,4 +1432,5 @@ module.exports = {
|
|
|
1355
1432
|
extractRelationalParents,
|
|
1356
1433
|
getM2AItemParentPath,
|
|
1357
1434
|
getSelectedNodes,
|
|
1435
|
+
remainingItems,
|
|
1358
1436
|
};
|
package/lib/validate.js
CHANGED
|
@@ -11,6 +11,7 @@ const {
|
|
|
11
11
|
extractRelationalParents,
|
|
12
12
|
getM2AItemParentPath,
|
|
13
13
|
getSelectedNodes,
|
|
14
|
+
remainingItems,
|
|
14
15
|
} = require("./helpers");
|
|
15
16
|
|
|
16
17
|
const choices = ["radio", "checkboxes", "dropdown_multiple", "dropdown"];
|
|
@@ -171,36 +172,70 @@ const handleMinMaxValidation = (
|
|
|
171
172
|
}
|
|
172
173
|
};
|
|
173
174
|
|
|
174
|
-
const isEmptyRelational = ({
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
175
|
+
const isEmptyRelational = ({
|
|
176
|
+
api_version,
|
|
177
|
+
value,
|
|
178
|
+
interface,
|
|
179
|
+
onlyFormFields,
|
|
180
|
+
existingValue,
|
|
181
|
+
}) => {
|
|
182
|
+
if (!onlyFormFields) {
|
|
183
|
+
if (
|
|
184
|
+
api_version === constants.API_VERSION.V1 &&
|
|
185
|
+
interface !== constants.interfaces.TRANSLATIONS
|
|
186
|
+
) {
|
|
187
|
+
if (interface === constants.interfaces.MANY_TO_ANY) {
|
|
188
|
+
return (
|
|
189
|
+
value &&
|
|
190
|
+
typeChecks[constants.types.OBJECT](value) &&
|
|
191
|
+
value.hasOwnProperty("collection") &&
|
|
192
|
+
value.hasOwnProperty("sort") &&
|
|
193
|
+
value.hasOwnProperty("item") &&
|
|
194
|
+
value.collection !== null &&
|
|
195
|
+
value.collection !== "" &&
|
|
196
|
+
value.sort !== null &&
|
|
197
|
+
value.sort !== "" &&
|
|
198
|
+
value.item !== null &&
|
|
199
|
+
value.item !== ""
|
|
200
|
+
);
|
|
201
|
+
} else {
|
|
202
|
+
return value?.length > 0;
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
180
205
|
return (
|
|
181
|
-
value
|
|
182
|
-
|
|
183
|
-
value
|
|
184
|
-
value.hasOwnProperty("sort") &&
|
|
185
|
-
value.hasOwnProperty("item") &&
|
|
186
|
-
value.collection !== null &&
|
|
187
|
-
value.collection !== "" &&
|
|
188
|
-
value.sort !== null &&
|
|
189
|
-
value.sort !== "" &&
|
|
190
|
-
value.item !== null &&
|
|
191
|
-
value.item !== ""
|
|
206
|
+
value?.create?.length > 0 ||
|
|
207
|
+
value?.existing?.length > 0 ||
|
|
208
|
+
value?.update?.length > 0
|
|
192
209
|
);
|
|
193
|
-
}
|
|
194
|
-
|
|
210
|
+
}
|
|
211
|
+
} else if (api_version === constants.API_VERSION.V2) {
|
|
212
|
+
if (isEmpty(existingValue)) return true;
|
|
213
|
+
|
|
214
|
+
switch (interface) {
|
|
215
|
+
case constants.interfaces.FILE:
|
|
216
|
+
case constants.interfaces.FILE_IMAGE:
|
|
217
|
+
case constants.interfaces.FILES:
|
|
218
|
+
case constants.interfaces.MANY_TO_MANY:
|
|
219
|
+
case constants.interfaces.ONE_TO_MANY:
|
|
220
|
+
case constants.interfaces.MANY_TO_ONE:
|
|
221
|
+
return remainingItems({
|
|
222
|
+
all: existingValue.map((item) => item._id),
|
|
223
|
+
obj: value,
|
|
224
|
+
});
|
|
225
|
+
case constants.interfaces.MANY_TO_ANY:
|
|
226
|
+
return remainingItems({
|
|
227
|
+
all: existingValue.map((item) => item.item),
|
|
228
|
+
obj: value,
|
|
229
|
+
isM2A: true,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// constants.interfaces.TRANSLATIONS,
|
|
233
|
+
default:
|
|
234
|
+
return true;
|
|
195
235
|
}
|
|
196
236
|
} else {
|
|
197
|
-
return
|
|
198
|
-
value?.create?.length > 0 ||
|
|
199
|
-
value?.existing?.length > 0 ||
|
|
200
|
-
value?.update?.length > 0
|
|
201
|
-
);
|
|
237
|
+
return true;
|
|
202
238
|
}
|
|
203
|
-
return false;
|
|
204
239
|
};
|
|
205
240
|
|
|
206
241
|
const validateMetaRules = (
|
|
@@ -214,12 +249,16 @@ const validateMetaRules = (
|
|
|
214
249
|
apiVersion,
|
|
215
250
|
fieldOptions,
|
|
216
251
|
formData,
|
|
217
|
-
language_codes = []
|
|
252
|
+
language_codes = [],
|
|
253
|
+
existingForm = {}
|
|
218
254
|
) => {
|
|
219
255
|
const fieldValue = providedValue;
|
|
220
256
|
|
|
221
257
|
const { required = false, nullable = false, options } = field?.meta ?? {};
|
|
222
258
|
|
|
259
|
+
if (field.isRelationalUpdate) {
|
|
260
|
+
onlyFormFields = true;
|
|
261
|
+
}
|
|
223
262
|
const isRelational = relational_interfaces.includes(field?.meta?.interface);
|
|
224
263
|
|
|
225
264
|
if (
|
|
@@ -275,15 +314,20 @@ const validateMetaRules = (
|
|
|
275
314
|
}
|
|
276
315
|
|
|
277
316
|
const isValidRelational =
|
|
278
|
-
required && isRelational
|
|
317
|
+
required && isRelational
|
|
279
318
|
? isEmptyRelational({
|
|
280
319
|
api_version: apiVersion,
|
|
281
320
|
value: fieldValue,
|
|
282
321
|
interface: field?.meta?.interface,
|
|
322
|
+
onlyFormFields,
|
|
323
|
+
existingValue: getValue(existingForm, currentPath),
|
|
283
324
|
})
|
|
284
325
|
: true;
|
|
285
326
|
|
|
286
|
-
if (
|
|
327
|
+
if (
|
|
328
|
+
(required && !onlyFormFields && isEmpty(fieldValue)) ||
|
|
329
|
+
!isValidRelational
|
|
330
|
+
) {
|
|
287
331
|
const message = error_messages.REQUIRED.replace(
|
|
288
332
|
`{field}`,
|
|
289
333
|
formatLabel(field.display_label)
|
|
@@ -318,18 +362,21 @@ const validateMetaRules = (
|
|
|
318
362
|
}
|
|
319
363
|
|
|
320
364
|
if (
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
365
|
+
(isEmpty(fieldValue) &&
|
|
366
|
+
!field?.meta?.hidden &&
|
|
367
|
+
![
|
|
368
|
+
constants.interfaces.FILES,
|
|
369
|
+
constants.interfaces.FILE,
|
|
370
|
+
constants.interfaces.FILE_IMAGE,
|
|
371
|
+
constants.interfaces.MANY_TO_MANY,
|
|
372
|
+
constants.interfaces.ONE_TO_MANY,
|
|
373
|
+
constants.interfaces.MANY_TO_ONE,
|
|
374
|
+
constants.interfaces.MANY_TO_ANY,
|
|
375
|
+
"none",
|
|
376
|
+
].includes(field?.meta?.interface)) ||
|
|
377
|
+
(field?.meta?.interface === constants.interfaces.TRANSLATIONS &&
|
|
378
|
+
language_codes?.length &&
|
|
379
|
+
!onlyFormFields)
|
|
333
380
|
) {
|
|
334
381
|
const isTranslationChild =
|
|
335
382
|
field?.meta?.interface === constants.interfaces.TRANSLATIONS;
|
|
@@ -338,11 +385,14 @@ const validateMetaRules = (
|
|
|
338
385
|
node: field,
|
|
339
386
|
skipFn: (node) =>
|
|
340
387
|
node.meta?.interface === constants.interfaces.MANY_TO_ANY,
|
|
341
|
-
conditionFn: (node) =>
|
|
342
|
-
|
|
388
|
+
conditionFn: (node) =>
|
|
389
|
+
node.meta?.required === true && !node.isRelationalUpdate,
|
|
390
|
+
mapFn: (node) => ({
|
|
391
|
+
key: node.key,
|
|
392
|
+
label: node.display_label,
|
|
393
|
+
}),
|
|
343
394
|
actionFn: (node) => {
|
|
344
395
|
let fPath = node.key;
|
|
345
|
-
|
|
346
396
|
if (fPath.includes("update.")) return;
|
|
347
397
|
if (fPath.includes("create.") && !isTranslationChild) return;
|
|
348
398
|
if (fPath.includes("delete.") && !isTranslationChild) return;
|
|
@@ -371,16 +421,31 @@ const validateMetaRules = (
|
|
|
371
421
|
|
|
372
422
|
if (isMultiLang) {
|
|
373
423
|
language_codes.forEach((lang, index) => {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
424
|
+
let langPath,
|
|
425
|
+
transformedPath,
|
|
426
|
+
isAdded = false;
|
|
427
|
+
|
|
428
|
+
if (fPath.includes("create[0].")) {
|
|
429
|
+
const exist = fieldValue?.create?.find(
|
|
430
|
+
(item) => item.languages_code === lang
|
|
431
|
+
);
|
|
432
|
+
if (exist) isAdded = true;
|
|
433
|
+
|
|
434
|
+
langPath = fPath.replace("create[0].", `create[${index}].`);
|
|
435
|
+
transformedPath = fPath.replace("create[0].", `create[${lang}].`);
|
|
436
|
+
} else {
|
|
437
|
+
langPath = fPath.replace("create.", `create[${index}].`);
|
|
438
|
+
transformedPath = fPath.replace("create.", `create[${lang}].`);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if (!isAdded) buildError(langPath, transformedPath);
|
|
377
442
|
});
|
|
378
443
|
} else {
|
|
379
444
|
const singlePath = fPath.replace(
|
|
380
445
|
"create.",
|
|
381
446
|
isTranslationChild ? "create[lang_code]." : "create[0]."
|
|
382
447
|
);
|
|
383
|
-
buildError(singlePath);
|
|
448
|
+
if (isEmpty(fieldValue)) buildError(singlePath);
|
|
384
449
|
}
|
|
385
450
|
},
|
|
386
451
|
});
|
|
@@ -828,7 +893,8 @@ const validateField = (
|
|
|
828
893
|
onlyFormFields,
|
|
829
894
|
apiVersion,
|
|
830
895
|
fieldOptions,
|
|
831
|
-
language_codes
|
|
896
|
+
language_codes,
|
|
897
|
+
existingForm
|
|
832
898
|
) => {
|
|
833
899
|
if (onlyFormFields == true && (value === undefined || value === null)) return;
|
|
834
900
|
|
|
@@ -850,7 +916,8 @@ const validateField = (
|
|
|
850
916
|
apiVersion,
|
|
851
917
|
fieldOptions,
|
|
852
918
|
formData,
|
|
853
|
-
language_codes
|
|
919
|
+
language_codes,
|
|
920
|
+
existingForm
|
|
854
921
|
);
|
|
855
922
|
|
|
856
923
|
if (
|
|
@@ -886,7 +953,8 @@ const validateField = (
|
|
|
886
953
|
onlyFormFields,
|
|
887
954
|
apiVersion,
|
|
888
955
|
fieldOptions,
|
|
889
|
-
language_codes
|
|
956
|
+
language_codes,
|
|
957
|
+
existingForm
|
|
890
958
|
)
|
|
891
959
|
);
|
|
892
960
|
} else if (field.type === constants.types.ARRAY && Array.isArray(value)) {
|
|
@@ -937,7 +1005,8 @@ const validateField = (
|
|
|
937
1005
|
onlyFormFields,
|
|
938
1006
|
apiVersion,
|
|
939
1007
|
fieldOptions,
|
|
940
|
-
language_codes
|
|
1008
|
+
language_codes,
|
|
1009
|
+
existingForm
|
|
941
1010
|
)
|
|
942
1011
|
);
|
|
943
1012
|
});
|
|
@@ -1044,6 +1113,7 @@ const validate = (data) => {
|
|
|
1044
1113
|
language,
|
|
1045
1114
|
maxLevel,
|
|
1046
1115
|
onlyFormFields,
|
|
1116
|
+
existingForm = {},
|
|
1047
1117
|
} = data;
|
|
1048
1118
|
|
|
1049
1119
|
const error_messages =
|
|
@@ -1294,7 +1364,8 @@ const validate = (data) => {
|
|
|
1294
1364
|
onlyFormFields,
|
|
1295
1365
|
apiVersion,
|
|
1296
1366
|
fieldOptions,
|
|
1297
|
-
data.language_codes
|
|
1367
|
+
data.language_codes,
|
|
1368
|
+
existingForm
|
|
1298
1369
|
);
|
|
1299
1370
|
});
|
|
1300
1371
|
return result;
|