nox-validation 1.7.3 → 1.7.4
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 +158 -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,25 @@ 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;
|
|
542
|
+
} else fPath = `${currentPath}.${fPath}`;
|
|
516
543
|
}
|
|
517
544
|
|
|
545
|
+
// if (
|
|
546
|
+
// currentPath &&
|
|
547
|
+
// currentPath?.trim() !== "" &&
|
|
548
|
+
// !fPath.includes(currentPath)
|
|
549
|
+
// // TODO: Need to Optimize This fPath => group.items.dropdown currentPath => group.items[0].dropdown final path becomes => group.items[0].dropdown.group.items.dropdown
|
|
550
|
+
// // 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
|
|
551
|
+
// ) {
|
|
552
|
+
// fPath = `${currentPath}.${fPath}`;
|
|
553
|
+
// }
|
|
554
|
+
|
|
518
555
|
if (staticType === "update") return;
|
|
519
556
|
if (staticType === "delete" && !isTranslationNode) return;
|
|
520
557
|
if (staticType === "existing" && !isTranslationNode) return;
|
|
@@ -522,34 +559,21 @@ const validateMetaRules = (
|
|
|
522
559
|
const label = formatLabel(node.display_label);
|
|
523
560
|
const message = error_messages.REQUIRED.replace("{field}", label);
|
|
524
561
|
|
|
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
562
|
const isMultiLang =
|
|
540
563
|
isTranslationNode &&
|
|
541
564
|
Array.isArray(language_codes) &&
|
|
542
565
|
language_codes.length > 1;
|
|
566
|
+
|
|
543
567
|
if (isMultiLang) {
|
|
568
|
+
const fullPath = fPath;
|
|
569
|
+
|
|
544
570
|
language_codes.forEach((lang, index) => {
|
|
545
571
|
let langPath, transformedPath;
|
|
546
572
|
let isAdded = false;
|
|
547
|
-
|
|
548
|
-
// Check if current language entry exists in fieldValue.create
|
|
573
|
+
// // Check if current language entry exists in fieldValue.create
|
|
549
574
|
if (
|
|
550
575
|
Array.isArray(fieldValue?.create) &&
|
|
551
576
|
fieldValue?.create.some((item, idx) => {
|
|
552
|
-
// Check by languages_code or by index match
|
|
553
577
|
return item.languages_code === lang || idx === index;
|
|
554
578
|
})
|
|
555
579
|
) {
|
|
@@ -560,25 +584,21 @@ const validateMetaRules = (
|
|
|
560
584
|
node?.value?.includes("create[0].") ||
|
|
561
585
|
node?.value?.includes("create[0]")
|
|
562
586
|
) {
|
|
563
|
-
langPath = rebuildFullPath(node.value,
|
|
587
|
+
langPath = rebuildFullPath(node.value, fPath, (path) =>
|
|
564
588
|
path.replace(/create\[0\]\./, `create[${index}].`)
|
|
565
589
|
);
|
|
566
|
-
transformedPath = rebuildFullPath(
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
?.replace("create", "");
|
|
573
|
-
return newPath;
|
|
574
|
-
}
|
|
575
|
-
);
|
|
590
|
+
transformedPath = rebuildFullPath(node.value, fPath, (path) => {
|
|
591
|
+
const newPath = path
|
|
592
|
+
.replace(/\[0\]\./, `.${lang}.`)
|
|
593
|
+
?.replace("create", "");
|
|
594
|
+
return newPath;
|
|
595
|
+
});
|
|
576
596
|
} else {
|
|
577
|
-
langPath = rebuildFullPath(node.value,
|
|
597
|
+
langPath = rebuildFullPath(node.value, fPath, (path) => {
|
|
578
598
|
return path.replace(/create\./, `create[${index}].`);
|
|
579
599
|
});
|
|
580
600
|
|
|
581
|
-
transformedPath = rebuildFullPath(node.value,
|
|
601
|
+
transformedPath = rebuildFullPath(node.value, fPath, (path) =>
|
|
582
602
|
path.replace(/\[0\]\./, `.${lang}.`)?.replace("create", "")
|
|
583
603
|
);
|
|
584
604
|
}
|
|
@@ -606,8 +626,8 @@ const validateMetaRules = (
|
|
|
606
626
|
const validType =
|
|
607
627
|
field?.alternateType?.length > 0
|
|
608
628
|
? [field.type, ...field?.alternateType].some((type) =>
|
|
609
|
-
|
|
610
|
-
|
|
629
|
+
typeChecks[type](fieldValue)
|
|
630
|
+
)
|
|
611
631
|
: typeChecks[field.type](fieldValue, { key: currentPath, updateValue });
|
|
612
632
|
|
|
613
633
|
if (!isEmpty(fieldValue) && !validType) {
|
|
@@ -645,8 +665,9 @@ const handleRegexValidation = (
|
|
|
645
665
|
const fieldLabel = formatLabel(field.display_label);
|
|
646
666
|
|
|
647
667
|
// Determine regex flags
|
|
648
|
-
const flags = `${rule.options?.case_sensitive ? "" : "i"}${
|
|
649
|
-
|
|
668
|
+
const flags = `${rule.options?.case_sensitive ? "" : "i"}${
|
|
669
|
+
rule.options?.multiline ? "m" : ""
|
|
670
|
+
}${rule.options?.global ? "g" : ""}`;
|
|
650
671
|
|
|
651
672
|
// Build regex for MATCH/CONTAINS/NOT_CONTAINS
|
|
652
673
|
let regex;
|
|
@@ -1138,16 +1159,7 @@ const validateField = (
|
|
|
1138
1159
|
timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
1139
1160
|
translatedPath = null
|
|
1140
1161
|
) => {
|
|
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;
|
|
1162
|
+
const { is_m2a_item, staticType = null, parentInterface } = field?.meta;
|
|
1151
1163
|
const currentPath = fieldPath
|
|
1152
1164
|
? `${fieldPath}.${field.key.split(".").pop()}`
|
|
1153
1165
|
: field.key;
|
|
@@ -1157,6 +1169,50 @@ const validateField = (
|
|
|
1157
1169
|
? `${translatedPath}.${field.key.split(".").pop()}`
|
|
1158
1170
|
: field.key;
|
|
1159
1171
|
}
|
|
1172
|
+
|
|
1173
|
+
if (
|
|
1174
|
+
onlyFormFields == true &&
|
|
1175
|
+
value === undefined &&
|
|
1176
|
+
![constants.interfaces.TRANSLATIONS, constants.interfaces.SEO].includes(
|
|
1177
|
+
field?.meta?.interface
|
|
1178
|
+
)
|
|
1179
|
+
) {
|
|
1180
|
+
if (
|
|
1181
|
+
onlyFormFields == true &&
|
|
1182
|
+
value === undefined &&
|
|
1183
|
+
staticType === "update" &&
|
|
1184
|
+
parentInterface === constants.interfaces.TRANSLATIONS &&
|
|
1185
|
+
field?.meta.required
|
|
1186
|
+
) {
|
|
1187
|
+
const langCode = getValue(formData, fieldPath)?.languages_code;
|
|
1188
|
+
const translationFieldPath = trimBasicPath(currentPath, staticType);
|
|
1189
|
+
const existingItemValue = getValue(
|
|
1190
|
+
existingForm,
|
|
1191
|
+
translationFieldPath
|
|
1192
|
+
)?.find((item) => item.languages_code === langCode)?.[
|
|
1193
|
+
`${field.key.split(".").pop()}`
|
|
1194
|
+
];
|
|
1195
|
+
|
|
1196
|
+
if (isEmpty(existingItemValue)) {
|
|
1197
|
+
const message = error_messages.REQUIRED.replace(
|
|
1198
|
+
`{field}`,
|
|
1199
|
+
formatLabel(`${field.key.split(".").pop()}`)
|
|
1200
|
+
);
|
|
1201
|
+
addError(
|
|
1202
|
+
currentPath,
|
|
1203
|
+
{
|
|
1204
|
+
label: formatLabel(`${field.key.split(".").pop()}`),
|
|
1205
|
+
fieldPath: currentPath,
|
|
1206
|
+
translation_path: translatedPath,
|
|
1207
|
+
description: "",
|
|
1208
|
+
message,
|
|
1209
|
+
},
|
|
1210
|
+
field
|
|
1211
|
+
);
|
|
1212
|
+
}
|
|
1213
|
+
} else return;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1160
1216
|
const fieldLabel = formatLabel(field.display_label);
|
|
1161
1217
|
|
|
1162
1218
|
validateMetaRules(
|
|
@@ -1273,6 +1329,13 @@ const validateField = (
|
|
|
1273
1329
|
)
|
|
1274
1330
|
trPath = trPath.replace(".update.", ".");
|
|
1275
1331
|
|
|
1332
|
+
if (
|
|
1333
|
+
trPath &&
|
|
1334
|
+
field.meta?.staticType === "create" &&
|
|
1335
|
+
trPath.includes(".create.")
|
|
1336
|
+
)
|
|
1337
|
+
trPath = trPath.replace(".create.", ".");
|
|
1338
|
+
|
|
1276
1339
|
validateField(
|
|
1277
1340
|
child,
|
|
1278
1341
|
item[child.key.split(".").pop()],
|
|
@@ -1445,7 +1508,7 @@ const validate = (data) => {
|
|
|
1445
1508
|
if (
|
|
1446
1509
|
secondParentField &&
|
|
1447
1510
|
secondParentField?.meta?.interface ===
|
|
1448
|
-
|
|
1511
|
+
constants.interfaces.TRANSLATIONS
|
|
1449
1512
|
) {
|
|
1450
1513
|
const languageKey = secondParentField?.meta?.options?.language_field;
|
|
1451
1514
|
const firstParentValue = getValue(formData, firstParent);
|