nox-validation 1.7.3 → 1.7.5
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 +18 -0
- package/lib/validate.js +160 -95
- package/package.json +1 -1
package/lib/helpers.js
CHANGED
|
@@ -1604,6 +1604,23 @@ const rebuildFullPath = (nodePath, fullPath, modifierFn) => {
|
|
|
1604
1604
|
: `${modifiedNodePath}`.replace(/\.+/g, ".");
|
|
1605
1605
|
};
|
|
1606
1606
|
|
|
1607
|
+
const trimBasicPath = (basePath, staticType = "update") => {
|
|
1608
|
+
const regex = new RegExp(`${staticType}\\[\\d+\\]`, "g");
|
|
1609
|
+
const matches = [...basePath.matchAll(regex)];
|
|
1610
|
+
|
|
1611
|
+
if (matches.length === 0) return basePath; // no update/create/delete/etc found
|
|
1612
|
+
|
|
1613
|
+
// Last matched dynamic segment (e.g. "update[3]")
|
|
1614
|
+
const lastSegment = matches[matches.length - 1][0];
|
|
1615
|
+
|
|
1616
|
+
// Find starting index of this last segment
|
|
1617
|
+
const idx = basePath.lastIndexOf(lastSegment);
|
|
1618
|
+
|
|
1619
|
+
// Return everything BEFORE this segment (and remove trailing dot)
|
|
1620
|
+
const result = basePath.substring(0, idx).replace(/\.$/, "");
|
|
1621
|
+
return result;
|
|
1622
|
+
};
|
|
1623
|
+
|
|
1607
1624
|
module.exports = {
|
|
1608
1625
|
generateModifiedRules,
|
|
1609
1626
|
getFieldsGroupBySchemaId,
|
|
@@ -1628,4 +1645,5 @@ module.exports = {
|
|
|
1628
1645
|
remainingItems,
|
|
1629
1646
|
formatDate,
|
|
1630
1647
|
rebuildFullPath,
|
|
1648
|
+
trimBasicPath,
|
|
1631
1649
|
};
|
package/lib/validate.js
CHANGED
|
@@ -14,6 +14,7 @@ const {
|
|
|
14
14
|
remainingItems,
|
|
15
15
|
formatDate,
|
|
16
16
|
rebuildFullPath,
|
|
17
|
+
trimBasicPath,
|
|
17
18
|
} = require("./helpers");
|
|
18
19
|
|
|
19
20
|
const choices = ["radio", "checkboxes", "dropdown_multiple", "dropdown"];
|
|
@@ -228,13 +229,13 @@ const isEmptyRelational = ({
|
|
|
228
229
|
? existingValue.length === 0
|
|
229
230
|
? []
|
|
230
231
|
: typeof existingValue[0] === "string"
|
|
231
|
-
|
|
232
|
-
|
|
232
|
+
? existingValue
|
|
233
|
+
: existingValue.map((item) => item._id)
|
|
233
234
|
: typeof existingValue === "string"
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
235
|
+
? [existingValue]
|
|
236
|
+
: existingValue && typeof existingValue === "object"
|
|
237
|
+
? [existingValue._id]
|
|
238
|
+
: [];
|
|
238
239
|
all = Array.isArray(all) ? all?.filter(Boolean) : all;
|
|
239
240
|
switch (interface) {
|
|
240
241
|
case constants.interfaces.FILE:
|
|
@@ -359,21 +360,21 @@ const validateMetaRules = (
|
|
|
359
360
|
const isValidRelational =
|
|
360
361
|
required && isRelational
|
|
361
362
|
? isEmptyRelational({
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
363
|
+
api_version: apiVersion,
|
|
364
|
+
value: fieldValue,
|
|
365
|
+
interface: field?.meta?.interface,
|
|
366
|
+
onlyFormFields,
|
|
367
|
+
existingValue:
|
|
368
|
+
getValue(existingForm, currentPath) ||
|
|
369
|
+
getValue(
|
|
370
|
+
existingForm,
|
|
371
|
+
currentPath
|
|
372
|
+
?.replace(".create", "")
|
|
373
|
+
?.replace(".update", "")
|
|
374
|
+
?.replace(".existing", "")
|
|
375
|
+
?.replace(".delete", "")
|
|
376
|
+
), // TODO: Need to Generate Form Path Without create, update, existing, delete
|
|
377
|
+
})
|
|
377
378
|
: true;
|
|
378
379
|
|
|
379
380
|
const isEmptyVal = is_m2a_item ? !fieldValue : isEmpty(fieldValue);
|
|
@@ -392,29 +393,30 @@ const validateMetaRules = (
|
|
|
392
393
|
if (invalidRequire || !isValidRelational) {
|
|
393
394
|
const message = field?.meta?.required
|
|
394
395
|
? error_messages.REQUIRED.replace(
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
396
|
+
`{field}`,
|
|
397
|
+
formatLabel(field.display_label)
|
|
398
|
+
)
|
|
398
399
|
: error_messages.NOT_EMPTY.replace(
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
400
|
+
`{field}`,
|
|
401
|
+
formatLabel(field.display_label)
|
|
402
|
+
);
|
|
403
|
+
|
|
402
404
|
addError(
|
|
403
405
|
currentPath,
|
|
404
406
|
translatedPath
|
|
405
407
|
? {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
408
|
+
label: formatLabel(field.display_label),
|
|
409
|
+
fieldPath: currentPath,
|
|
410
|
+
description: "",
|
|
411
|
+
translation_path: translatedPath,
|
|
412
|
+
message,
|
|
413
|
+
}
|
|
412
414
|
: {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
415
|
+
label: formatLabel(field.display_label),
|
|
416
|
+
fieldPath: currentPath,
|
|
417
|
+
description: "",
|
|
418
|
+
message,
|
|
419
|
+
},
|
|
418
420
|
field
|
|
419
421
|
);
|
|
420
422
|
}
|
|
@@ -472,16 +474,20 @@ const validateMetaRules = (
|
|
|
472
474
|
node: field,
|
|
473
475
|
skipFn: (node) => {
|
|
474
476
|
let status = false;
|
|
477
|
+
if (node.meta?.interface === constants.interfaces.MANY_TO_ANY)
|
|
478
|
+
status = true;
|
|
479
|
+
|
|
475
480
|
if (
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
481
|
+
[
|
|
482
|
+
constants.interfaces.MANY_TO_MANY,
|
|
483
|
+
constants.interfaces.ONE_TO_MANY,
|
|
484
|
+
constants.interfaces.MANY_TO_ONE,
|
|
485
|
+
constants.interfaces.SEO,
|
|
486
|
+
].includes(node.meta?.interface) &&
|
|
487
|
+
(!node.meta?.required || !node.meta?.hidden)
|
|
488
|
+
)
|
|
489
|
+
status = true;
|
|
490
|
+
return status;
|
|
485
491
|
},
|
|
486
492
|
conditionFn: (node) =>
|
|
487
493
|
node.meta?.required === true && !node.isRelationalUpdate,
|
|
@@ -490,6 +496,24 @@ const validateMetaRules = (
|
|
|
490
496
|
label: node.display_label,
|
|
491
497
|
}),
|
|
492
498
|
actionFn: (node) => {
|
|
499
|
+
const normalize = (path) => path.replace(/\[\d+\]/g, "");
|
|
500
|
+
|
|
501
|
+
const getRoot = (path) => normalize(path).split(".")[0];
|
|
502
|
+
|
|
503
|
+
const buildError = (path, translated) => {
|
|
504
|
+
if (!isEmpty(getValue(formData, path))) return;
|
|
505
|
+
let obj = {
|
|
506
|
+
label,
|
|
507
|
+
fieldPath: path,
|
|
508
|
+
description: "",
|
|
509
|
+
message,
|
|
510
|
+
};
|
|
511
|
+
if (translated) {
|
|
512
|
+
obj.translation_path = translated;
|
|
513
|
+
}
|
|
514
|
+
addError(path, obj, node);
|
|
515
|
+
};
|
|
516
|
+
|
|
493
517
|
const isTranslationNode =
|
|
494
518
|
node?.meta?.parentInterface === constants.interfaces.TRANSLATIONS ||
|
|
495
519
|
field?.meta?.interface === constants.interfaces.TRANSLATIONS;
|
|
@@ -509,12 +533,27 @@ const validateMetaRules = (
|
|
|
509
533
|
|
|
510
534
|
if (
|
|
511
535
|
currentPath &&
|
|
512
|
-
currentPath
|
|
513
|
-
!fPath.
|
|
536
|
+
currentPath.trim() !== "" &&
|
|
537
|
+
!normalize(fPath).startsWith(normalize(currentPath)) &&
|
|
538
|
+
getRoot(fPath) !== getRoot(currentPath)
|
|
514
539
|
) {
|
|
515
|
-
fPath
|
|
540
|
+
if (!currentPath.includes(fPath)) {
|
|
541
|
+
fPath = `${currentPath}.${fPath}`;
|
|
542
|
+
}
|
|
543
|
+
} else if (fPath !== currentPath) {
|
|
544
|
+
fPath = currentPath;
|
|
516
545
|
}
|
|
517
546
|
|
|
547
|
+
// if (
|
|
548
|
+
// currentPath &&
|
|
549
|
+
// currentPath?.trim() !== "" &&
|
|
550
|
+
// !fPath.includes(currentPath)
|
|
551
|
+
// // TODO: Need to Optimize This fPath => group.items.dropdown currentPath => group.items[0].dropdown final path becomes => group.items[0].dropdown.group.items.dropdown
|
|
552
|
+
// // also translations.create[0].meta_description <=fPath condition currentPath => seo.create[0].translations.create[0].meta_description then condition becomes true but parent is not same then need to merge
|
|
553
|
+
// ) {
|
|
554
|
+
// fPath = `${currentPath}.${fPath}`;
|
|
555
|
+
// }
|
|
556
|
+
|
|
518
557
|
if (staticType === "update") return;
|
|
519
558
|
if (staticType === "delete" && !isTranslationNode) return;
|
|
520
559
|
if (staticType === "existing" && !isTranslationNode) return;
|
|
@@ -522,34 +561,21 @@ const validateMetaRules = (
|
|
|
522
561
|
const label = formatLabel(node.display_label);
|
|
523
562
|
const message = error_messages.REQUIRED.replace("{field}", label);
|
|
524
563
|
|
|
525
|
-
const buildError = (path, translated) => {
|
|
526
|
-
if (!isEmpty(getValue(formData, path))) return;
|
|
527
|
-
let obj = {
|
|
528
|
-
label,
|
|
529
|
-
fieldPath: path,
|
|
530
|
-
description: "",
|
|
531
|
-
message,
|
|
532
|
-
};
|
|
533
|
-
if (translated) {
|
|
534
|
-
obj.translation_path = translated;
|
|
535
|
-
}
|
|
536
|
-
addError(path, obj, node);
|
|
537
|
-
};
|
|
538
|
-
|
|
539
564
|
const isMultiLang =
|
|
540
565
|
isTranslationNode &&
|
|
541
566
|
Array.isArray(language_codes) &&
|
|
542
567
|
language_codes.length > 1;
|
|
568
|
+
|
|
543
569
|
if (isMultiLang) {
|
|
570
|
+
const fullPath = fPath;
|
|
571
|
+
|
|
544
572
|
language_codes.forEach((lang, index) => {
|
|
545
573
|
let langPath, transformedPath;
|
|
546
574
|
let isAdded = false;
|
|
547
|
-
|
|
548
575
|
// Check if current language entry exists in fieldValue.create
|
|
549
576
|
if (
|
|
550
577
|
Array.isArray(fieldValue?.create) &&
|
|
551
578
|
fieldValue?.create.some((item, idx) => {
|
|
552
|
-
// Check by languages_code or by index match
|
|
553
579
|
return item.languages_code === lang || idx === index;
|
|
554
580
|
})
|
|
555
581
|
) {
|
|
@@ -560,25 +586,21 @@ const validateMetaRules = (
|
|
|
560
586
|
node?.value?.includes("create[0].") ||
|
|
561
587
|
node?.value?.includes("create[0]")
|
|
562
588
|
) {
|
|
563
|
-
langPath = rebuildFullPath(node.value,
|
|
589
|
+
langPath = rebuildFullPath(node.value, fPath, (path) =>
|
|
564
590
|
path.replace(/create\[0\]\./, `create[${index}].`)
|
|
565
591
|
);
|
|
566
|
-
transformedPath = rebuildFullPath(
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
?.replace("create", "");
|
|
573
|
-
return newPath;
|
|
574
|
-
}
|
|
575
|
-
);
|
|
592
|
+
transformedPath = rebuildFullPath(node.value, fPath, (path) => {
|
|
593
|
+
const newPath = path
|
|
594
|
+
.replace(/\[0\]\./, `.${lang}.`)
|
|
595
|
+
?.replace("create", "");
|
|
596
|
+
return newPath;
|
|
597
|
+
});
|
|
576
598
|
} else {
|
|
577
|
-
langPath = rebuildFullPath(node.value,
|
|
599
|
+
langPath = rebuildFullPath(node.value, fPath, (path) => {
|
|
578
600
|
return path.replace(/create\./, `create[${index}].`);
|
|
579
601
|
});
|
|
580
602
|
|
|
581
|
-
transformedPath = rebuildFullPath(node.value,
|
|
603
|
+
transformedPath = rebuildFullPath(node.value, fPath, (path) =>
|
|
582
604
|
path.replace(/\[0\]\./, `.${lang}.`)?.replace("create", "")
|
|
583
605
|
);
|
|
584
606
|
}
|
|
@@ -606,8 +628,8 @@ const validateMetaRules = (
|
|
|
606
628
|
const validType =
|
|
607
629
|
field?.alternateType?.length > 0
|
|
608
630
|
? [field.type, ...field?.alternateType].some((type) =>
|
|
609
|
-
|
|
610
|
-
|
|
631
|
+
typeChecks[type](fieldValue)
|
|
632
|
+
)
|
|
611
633
|
: typeChecks[field.type](fieldValue, { key: currentPath, updateValue });
|
|
612
634
|
|
|
613
635
|
if (!isEmpty(fieldValue) && !validType) {
|
|
@@ -645,8 +667,9 @@ const handleRegexValidation = (
|
|
|
645
667
|
const fieldLabel = formatLabel(field.display_label);
|
|
646
668
|
|
|
647
669
|
// Determine regex flags
|
|
648
|
-
const flags = `${rule.options?.case_sensitive ? "" : "i"}${
|
|
649
|
-
|
|
670
|
+
const flags = `${rule.options?.case_sensitive ? "" : "i"}${
|
|
671
|
+
rule.options?.multiline ? "m" : ""
|
|
672
|
+
}${rule.options?.global ? "g" : ""}`;
|
|
650
673
|
|
|
651
674
|
// Build regex for MATCH/CONTAINS/NOT_CONTAINS
|
|
652
675
|
let regex;
|
|
@@ -1138,16 +1161,7 @@ const validateField = (
|
|
|
1138
1161
|
timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
1139
1162
|
translatedPath = null
|
|
1140
1163
|
) => {
|
|
1141
|
-
|
|
1142
|
-
onlyFormFields == true &&
|
|
1143
|
-
value === undefined &&
|
|
1144
|
-
![constants.interfaces.TRANSLATIONS, constants.interfaces.SEO].includes(
|
|
1145
|
-
field?.meta?.interface
|
|
1146
|
-
)
|
|
1147
|
-
)
|
|
1148
|
-
return;
|
|
1149
|
-
|
|
1150
|
-
const { is_m2a_item } = field?.meta;
|
|
1164
|
+
const { is_m2a_item, staticType = null, parentInterface } = field?.meta;
|
|
1151
1165
|
const currentPath = fieldPath
|
|
1152
1166
|
? `${fieldPath}.${field.key.split(".").pop()}`
|
|
1153
1167
|
: field.key;
|
|
@@ -1157,6 +1171,50 @@ const validateField = (
|
|
|
1157
1171
|
? `${translatedPath}.${field.key.split(".").pop()}`
|
|
1158
1172
|
: field.key;
|
|
1159
1173
|
}
|
|
1174
|
+
|
|
1175
|
+
if (
|
|
1176
|
+
onlyFormFields == true &&
|
|
1177
|
+
value === undefined &&
|
|
1178
|
+
![constants.interfaces.TRANSLATIONS, constants.interfaces.SEO].includes(
|
|
1179
|
+
field?.meta?.interface
|
|
1180
|
+
)
|
|
1181
|
+
) {
|
|
1182
|
+
if (
|
|
1183
|
+
onlyFormFields == true &&
|
|
1184
|
+
value === undefined &&
|
|
1185
|
+
staticType === "update" &&
|
|
1186
|
+
parentInterface === constants.interfaces.TRANSLATIONS &&
|
|
1187
|
+
field?.meta.required
|
|
1188
|
+
) {
|
|
1189
|
+
const langCode = getValue(formData, fieldPath)?.languages_code;
|
|
1190
|
+
const translationFieldPath = trimBasicPath(currentPath, staticType);
|
|
1191
|
+
const existingItemValue = getValue(
|
|
1192
|
+
existingForm,
|
|
1193
|
+
translationFieldPath
|
|
1194
|
+
)?.find((item) => item.languages_code === langCode)?.[
|
|
1195
|
+
`${field.key.split(".").pop()}`
|
|
1196
|
+
];
|
|
1197
|
+
|
|
1198
|
+
if (isEmpty(existingItemValue)) {
|
|
1199
|
+
const message = error_messages.REQUIRED.replace(
|
|
1200
|
+
`{field}`,
|
|
1201
|
+
formatLabel(`${field.key.split(".").pop()}`)
|
|
1202
|
+
);
|
|
1203
|
+
addError(
|
|
1204
|
+
currentPath,
|
|
1205
|
+
{
|
|
1206
|
+
label: formatLabel(`${field.key.split(".").pop()}`),
|
|
1207
|
+
fieldPath: currentPath,
|
|
1208
|
+
translation_path: translatedPath,
|
|
1209
|
+
description: "",
|
|
1210
|
+
message,
|
|
1211
|
+
},
|
|
1212
|
+
field
|
|
1213
|
+
);
|
|
1214
|
+
}
|
|
1215
|
+
} else return;
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1160
1218
|
const fieldLabel = formatLabel(field.display_label);
|
|
1161
1219
|
|
|
1162
1220
|
validateMetaRules(
|
|
@@ -1273,6 +1331,13 @@ const validateField = (
|
|
|
1273
1331
|
)
|
|
1274
1332
|
trPath = trPath.replace(".update.", ".");
|
|
1275
1333
|
|
|
1334
|
+
if (
|
|
1335
|
+
trPath &&
|
|
1336
|
+
field.meta?.staticType === "create" &&
|
|
1337
|
+
trPath.includes(".create.")
|
|
1338
|
+
)
|
|
1339
|
+
trPath = trPath.replace(".create.", ".");
|
|
1340
|
+
|
|
1276
1341
|
validateField(
|
|
1277
1342
|
child,
|
|
1278
1343
|
item[child.key.split(".").pop()],
|
|
@@ -1445,7 +1510,7 @@ const validate = (data) => {
|
|
|
1445
1510
|
if (
|
|
1446
1511
|
secondParentField &&
|
|
1447
1512
|
secondParentField?.meta?.interface ===
|
|
1448
|
-
|
|
1513
|
+
constants.interfaces.TRANSLATIONS
|
|
1449
1514
|
) {
|
|
1450
1515
|
const languageKey = secondParentField?.meta?.options?.language_field;
|
|
1451
1516
|
const firstParentValue = getValue(formData, firstParent);
|
|
@@ -1470,7 +1535,7 @@ const validate = (data) => {
|
|
|
1470
1535
|
}
|
|
1471
1536
|
}
|
|
1472
1537
|
|
|
1473
|
-
result.errors[fieldPath] = obj;
|
|
1538
|
+
result.errors[fieldPath] = { ...obj, fieldId: field?.field_id };
|
|
1474
1539
|
result.status = false;
|
|
1475
1540
|
}
|
|
1476
1541
|
if (abortEarly && !result.status) return result;
|