nox-validation 1.5.2 → 1.5.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/constant.js CHANGED
@@ -148,6 +148,7 @@ const interfaces = Object.freeze({
148
148
  MULTIPLE_DROPDOWN: "dropdown_multiple",
149
149
  TAGS: "tags",
150
150
  ARRAY_OF_VALUES: "array_of_values",
151
+ OBJECT: "object",
151
152
  });
152
153
 
153
154
  const API_VERSION = Object.freeze({
package/lib/helpers.js CHANGED
@@ -313,6 +313,7 @@ const generateField = (
313
313
  hidden: false,
314
314
  }
315
315
  ) => {
316
+ const { staticType } = meta;
316
317
  childrenFields = childrenFields?.map((child) => {
317
318
  const childKey = path ? `${path}.${child.key}` : child.key;
318
319
  const childValue = path ? `${path}.${child.value}` : child.value;
@@ -320,6 +321,7 @@ const generateField = (
320
321
  return {
321
322
  ...child,
322
323
  value: childKey,
324
+ meta: staticType ? { ...child?.meta, staticType } : child?.meta,
323
325
  key: childValue,
324
326
  isRelationalUpdate: path.includes("update"),
325
327
  };
@@ -406,7 +408,11 @@ const generateRelationalField = (
406
408
  "existing",
407
409
  `${key}.existing`,
408
410
  constants.types.OBJECT,
409
- constants.types.ARRAY
411
+ constants.types.ARRAY,
412
+ [],
413
+ "none",
414
+ [],
415
+ { staticType: "existing" }
410
416
  );
411
417
  existingField.children = [
412
418
  generateField(
@@ -442,7 +448,11 @@ const generateRelationalField = (
442
448
  "delete",
443
449
  `${key}.delete`,
444
450
  constants.types.OBJECT,
445
- constants.types.ARRAY
451
+ constants.types.ARRAY,
452
+ [],
453
+ "none",
454
+ [],
455
+ { staticType: "delete" }
446
456
  );
447
457
  deleteField.children = [
448
458
  generateField(
@@ -479,7 +489,11 @@ const generateRelationalField = (
479
489
  `${key}.create`,
480
490
  constants.types.OBJECT,
481
491
  constants.types.ARRAY,
482
- collectionFields
492
+ // collectionFields //TODO:REMOVED CHILDREN
493
+ [],
494
+ "none",
495
+ [],
496
+ { staticType: "create" }
483
497
  );
484
498
  createField.children = [
485
499
  generateField(
@@ -520,7 +534,11 @@ const generateRelationalField = (
520
534
  `${key}.update`,
521
535
  constants.types.OBJECT,
522
536
  constants.types.ARRAY,
523
- collectionFields
537
+ // collectionFields //TODO:REMOVED CHILDREN
538
+ [],
539
+ "none",
540
+ [],
541
+ { staticType: "update" }
524
542
  );
525
543
  updateField.children = [
526
544
  generateField(
@@ -563,27 +581,41 @@ const generateRelationalField = (
563
581
  "existing",
564
582
  `${key}.existing`,
565
583
  constants.types.OBJECT_ID,
566
- constants.types.ARRAY
584
+ constants.types.ARRAY,
585
+ [],
586
+ "none",
587
+ [],
588
+ { staticType: "existing" }
567
589
  ),
568
590
  generateField(
569
591
  "delete",
570
592
  `${key}.delete`,
571
593
  constants.types.OBJECT_ID,
572
- constants.types.ARRAY
594
+ constants.types.ARRAY,
595
+ [],
596
+ "none",
597
+ [],
598
+ { staticType: "delete" }
573
599
  ),
574
600
  generateField(
575
601
  "create",
576
602
  `${key}.create`,
577
603
  constants.types.OBJECT,
578
604
  constants.types.ARRAY,
579
- collectionFields
605
+ collectionFields,
606
+ "none",
607
+ [],
608
+ { staticType: "create" }
580
609
  ),
581
610
  generateField(
582
611
  "update",
583
612
  `${key}.update`,
584
613
  constants.types.OBJECT,
585
614
  constants.types.ARRAY,
586
- collectionFields
615
+ collectionFields,
616
+ "none",
617
+ [],
618
+ { staticType: "update" }
587
619
  ),
588
620
  ];
589
621
  }
@@ -830,6 +862,8 @@ const buildNestedStructure = ({
830
862
  childFields = childFields.map((f) => {
831
863
  if (
832
864
  f.field === relationDetail.foreign_field ||
865
+ f.field === relationDetail.foreign_collection ||
866
+ f.field === relationDetail.junction_field_foreign ||
833
867
  f.field === relationDetail.junction_field_this
834
868
  ) {
835
869
  return {
@@ -1364,6 +1398,23 @@ const getSelectedNodes = ({
1364
1398
  }) => {
1365
1399
  const result = [];
1366
1400
 
1401
+ function updateChildKeys(node, parentKey, newParentKey) {
1402
+ let updatedNode = { ...node };
1403
+ if (
1404
+ typeof node.key === "string" &&
1405
+ node.key.startsWith(parentKey) &&
1406
+ !node.key.startsWith(newParentKey)
1407
+ ) {
1408
+ updatedNode.key = node.key.replace(parentKey, newParentKey);
1409
+ }
1410
+ if (Array.isArray(node.children) && node.children.length > 0) {
1411
+ updatedNode.children = node.children.map((c) =>
1412
+ updateChildKeys(c, parentKey, newParentKey)
1413
+ );
1414
+ }
1415
+ return updatedNode;
1416
+ }
1417
+
1367
1418
  function traverse(currentNode) {
1368
1419
  if (conditionFn(currentNode)) {
1369
1420
  actionFn(currentNode);
@@ -1372,29 +1423,16 @@ const getSelectedNodes = ({
1372
1423
 
1373
1424
  if (Array.isArray(currentNode.children)) {
1374
1425
  currentNode.children.forEach((child) => {
1375
- let childNode = {
1376
- ...child,
1377
- key:
1378
- currentNode.type === constants.types.ARRAY
1379
- ? child.key.includes(`${currentNode.key}[`)
1380
- ? child.key
1381
- : child.key.replace(currentNode.key, `${currentNode.key}[0]`)
1382
- : child.key,
1383
- };
1426
+ let childNode = { ...child };
1384
1427
 
1385
- if (Array.isArray(child.children) && child.children.length > 0) {
1386
- const updateChildKeys = (node, parentKey, newParentKey) => {
1387
- let updatedNode = {
1388
- ...node,
1389
- key: node.key.replace(parentKey, newParentKey),
1390
- };
1391
- if (Array.isArray(node.children) && node.children.length > 0) {
1392
- updatedNode.children = node.children.map((c) =>
1393
- updateChildKeys(c, parentKey, newParentKey)
1394
- );
1395
- }
1396
- return updatedNode;
1397
- };
1428
+ if (
1429
+ currentNode.type === constants.types.ARRAY &&
1430
+ typeof child.key === "string"
1431
+ ) {
1432
+ const arrayKey = `${currentNode.key}[0]`;
1433
+ if (!childNode.key.startsWith(arrayKey)) {
1434
+ childNode = updateChildKeys(child, currentNode.key, arrayKey);
1435
+ }
1398
1436
  }
1399
1437
 
1400
1438
  if (!skipFn(currentNode)) traverse(childNode);
package/lib/validate.js CHANGED
@@ -219,12 +219,24 @@ const isEmptyRelational = ({
219
219
  case constants.interfaces.ONE_TO_MANY:
220
220
  case constants.interfaces.MANY_TO_ONE:
221
221
  return remainingItems({
222
- all: existingValue?.map((item) => item._id),
222
+ all: Array.isArray(existingValue)
223
+ ? existingValue.length === 0
224
+ ? []
225
+ : typeof existingValue[0] === "string"
226
+ ? existingValue
227
+ : existingValue.map((item) => item._id)
228
+ : typeof existingValue === "string"
229
+ ? [existingValue]
230
+ : existingValue && typeof existingValue === "object"
231
+ ? [existingValue._id]
232
+ : [],
223
233
  obj: value,
224
234
  });
225
235
  case constants.interfaces.MANY_TO_ANY:
226
236
  return remainingItems({
227
- all: existingValue?.map((item) => item.item),
237
+ all: Array.isArray(existingValue)
238
+ ? existingValue?.map((item) => item.item)
239
+ : [],
228
240
  obj: value,
229
241
  isM2A: true,
230
242
  });
@@ -250,7 +262,8 @@ const validateMetaRules = (
250
262
  fieldOptions,
251
263
  formData,
252
264
  language_codes = [],
253
- existingForm = {}
265
+ existingForm = {},
266
+ getNodes = true
254
267
  ) => {
255
268
  const fieldValue = providedValue;
256
269
 
@@ -259,6 +272,7 @@ const validateMetaRules = (
259
272
  nullable = true,
260
273
  options,
261
274
  is_m2a_item,
275
+ hidden = false,
262
276
  } = field?.meta ?? {};
263
277
 
264
278
  if (field?.validations?.find((i) => i?.case === "not_empty")) {
@@ -266,7 +280,7 @@ const validateMetaRules = (
266
280
  nullable = false;
267
281
  }
268
282
 
269
- if (field?.validations?.find((i) => i?.case === "empty")) {
283
+ if (field?.validations?.find((i) => i?.case === "empty") || hidden) {
270
284
  required = false;
271
285
  nullable = true;
272
286
  }
@@ -340,11 +354,28 @@ const validateMetaRules = (
340
354
  : true;
341
355
 
342
356
  const isEmptyVal = is_m2a_item ? !fieldValue : isEmpty(fieldValue);
343
- if ((required && !onlyFormFields && isEmptyVal) || !isValidRelational) {
344
- const message = error_messages.REQUIRED.replace(
345
- `{field}`,
346
- formatLabel(field.display_label)
347
- );
357
+
358
+ let invalidRequire;
359
+ if (onlyFormFields) {
360
+ if (typeof fieldValue !== "undefined" && fieldValue !== null && required) {
361
+ invalidRequire = isEmptyVal;
362
+ } else {
363
+ invalidRequire = false;
364
+ }
365
+ } else {
366
+ invalidRequire = required && isEmptyVal;
367
+ }
368
+
369
+ if (invalidRequire || !isValidRelational) {
370
+ const message = field?.meta?.required
371
+ ? error_messages.REQUIRED.replace(
372
+ `{field}`,
373
+ formatLabel(field.display_label)
374
+ )
375
+ : error_messages.NOT_EMPTY.replace(
376
+ `{field}`,
377
+ formatLabel(field.display_label)
378
+ );
348
379
  addError(
349
380
  currentPath,
350
381
  {
@@ -376,7 +407,7 @@ const validateMetaRules = (
376
407
 
377
408
  if (
378
409
  (isEmpty(fieldValue) &&
379
- !field?.meta?.hidden &&
410
+ required &&
380
411
  ![
381
412
  constants.interfaces.FILES,
382
413
  constants.interfaces.FILE,
@@ -389,7 +420,12 @@ const validateMetaRules = (
389
420
  ].includes(field?.meta?.interface)) ||
390
421
  (field?.meta?.interface === constants.interfaces.TRANSLATIONS &&
391
422
  language_codes?.length &&
392
- !onlyFormFields)
423
+ !onlyFormFields) ||
424
+ ([constants.interfaces.OBJECT, constants.interfaces.ITEMS].includes(
425
+ field?.meta?.interface
426
+ ) &&
427
+ !onlyFormFields &&
428
+ getNodes)
393
429
  ) {
394
430
  const isTranslationChild =
395
431
  field?.meta?.interface === constants.interfaces.TRANSLATIONS;
@@ -405,11 +441,12 @@ const validateMetaRules = (
405
441
  label: node.display_label,
406
442
  }),
407
443
  actionFn: (node) => {
408
- let fPath = node.key;
409
- if (fPath.includes("update")) return;
410
- if (fPath.includes("create") && !isTranslationChild) return;
411
- if (fPath.includes("delete") && !isTranslationChild) return;
412
- if (fPath.includes("existing") && !isTranslationChild) return;
444
+ const staticType = node?.meta?.staticType;
445
+ let fPath = node.key?.replace("[0][0]", "[0]");
446
+
447
+ if (staticType === "update") return;
448
+ if (staticType === "delete" && !isTranslationChild) return;
449
+ if (staticType === "existing" && !isTranslationChild) return;
413
450
 
414
451
  const label = formatLabel(node.display_label);
415
452
  const message = error_messages.REQUIRED.replace("{field}", label);
@@ -458,7 +495,12 @@ const validateMetaRules = (
458
495
  "create.",
459
496
  isTranslationChild ? "create[lang_code]." : "create[0]."
460
497
  );
461
- if (isEmpty(fieldValue)) buildError(singlePath);
498
+ if (
499
+ constants.interfaces.ITEMS === field?.meta?.interface
500
+ ? true
501
+ : isEmpty(fieldValue)
502
+ )
503
+ buildError(singlePath);
462
504
  }
463
505
  },
464
506
  });
@@ -504,56 +546,86 @@ const handleRegexValidation = (
504
546
 
505
547
  let message = "";
506
548
  const fieldLabel = formatLabel(field.display_label);
507
- const flags = `${rule.options.case_sensitive ? "" : "i"}${
508
- rule.options.multiline ? "m" : ""
509
- }${rule.options.global ? "g" : ""}`;
510
- const regex = new RegExp(escapeRegex(rule.value[0]), flags);
511
-
512
- const isValid = (() => {
513
- switch (rule.options.type) {
514
- case constants.regexTypes.MATCH:
515
- message = custom_message ?? error_messages.REGEX_MATCH;
516
- return regex.test(fieldValue);
517
- case constants.regexTypes.START_WITH:
518
- message = custom_message ?? error_messages.REGEX_START_WITH;
519
- return fieldValue?.startsWith(
520
- rule.value[0].replace(/^\//, "").replace(/\/$/, "")
521
- );
522
- case constants.regexTypes.ENDS_WITH:
523
- message = custom_message ?? error_messages.REGEX_ENDS_WITH;
524
- return fieldValue?.endsWith(
525
- rule.value[0].replace(/^\//, "").replace(/\/$/, "")
526
- );
527
- case constants.regexTypes.CONTAINS:
528
- message = custom_message ?? error_messages.REGEX_CONTAINS;
529
- return regex.test(fieldValue);
530
- case constants.regexTypes.EXACT:
531
- message = custom_message ?? error_messages.REGEX_EXACT;
532
- return (
533
- fieldValue === rule.value[0].replace(/^\//, "").replace(/\/$/, "")
534
- );
535
- case constants.regexTypes.NOT_START_WITH:
536
- message = custom_message ?? error_messages.REGEX_NOT_START_WITH;
537
- return !fieldValue?.startsWith(
538
- rule.value[0].replace(/^\//, "").replace(/\/$/, "")
539
- );
540
- case constants.regexTypes.NOT_ENDS_WITH:
541
- message = custom_message ?? error_messages.REGEX_NOT_ENDS_WITH;
542
- return !fieldValue?.endsWith(
543
- rule.value[0].replace(/^\//, "").replace(/\/$/, "")
544
- );
545
- case constants.regexTypes.NOT_CONTAINS:
546
- message = custom_message ?? error_messages.REGEX_NOT_CONTAINS;
547
- return !regex.test(fieldValue);
548
- default:
549
- return false;
549
+
550
+ // Determine regex flags
551
+ const flags = `${rule.options?.case_sensitive ? "" : "i"}${
552
+ rule.options?.multiline ? "m" : ""
553
+ }${rule.options?.global ? "g" : ""}`;
554
+
555
+ // Build regex for MATCH/CONTAINS/NOT_CONTAINS
556
+ let regex;
557
+ if (
558
+ rule.options?.type === constants.regexTypes.MATCH ||
559
+ rule.options?.type === constants.regexTypes.CONTAINS ||
560
+ rule.options?.type === constants.regexTypes.NOT_CONTAINS
561
+ ) {
562
+ const pattern = rule.value[0];
563
+ let rawPattern = pattern;
564
+ if (/^\/.*\/$/.test(pattern)) {
565
+ rawPattern = pattern.slice(1, -1);
550
566
  }
551
- })();
567
+ regex = new RegExp(rawPattern, flags);
568
+ }
569
+
570
+ // Evaluate validity based on type
571
+ let isValid = false;
572
+ switch (rule.options?.type) {
573
+ case constants.regexTypes.MATCH:
574
+ message = custom_message ?? error_messages.REGEX_MATCH;
575
+ isValid = regex.test(fieldValue);
576
+ break;
577
+ case constants.regexTypes.START_WITH:
578
+ message = custom_message ?? error_messages.REGEX_START_WITH;
579
+ let prefixStart = rule.value[0].replace(/^\//, "").replace(/\/$/, "");
580
+ isValid =
581
+ typeof fieldValue === "string" && fieldValue.startsWith(prefixStart);
582
+ break;
583
+ case constants.regexTypes.ENDS_WITH:
584
+ message = custom_message ?? error_messages.REGEX_ENDS_WITH;
585
+
586
+ let suffix = rule.value[0].replace(/^\//, "").replace(/\/$/, "");
587
+ isValid = typeof fieldValue === "string" && fieldValue.endsWith(suffix);
588
+ break;
589
+ case constants.regexTypes.CONTAINS:
590
+ message = custom_message ?? error_messages.REGEX_CONTAINS;
591
+ isValid = regex.test(fieldValue);
592
+ break;
593
+ case constants.regexTypes.EXACT:
594
+ message = custom_message ?? error_messages.REGEX_EXACT;
595
+ let exact = rule.value[0].replace(/^\//, "").replace(/\/$/, "");
596
+ isValid = fieldValue === exact;
597
+ break;
598
+ case constants.regexTypes.NOT_START_WITH:
599
+ message = custom_message ?? error_messages.REGEX_NOT_START_WITH;
600
+ let prefix = rule.value[0].replace(/^\//, "").replace(/\/$/, "");
601
+ isValid = !(
602
+ typeof fieldValue === "string" && fieldValue.startsWith(prefix)
603
+ );
604
+ break;
605
+ case constants.regexTypes.NOT_ENDS_WITH:
606
+ message = custom_message ?? error_messages.REGEX_NOT_ENDS_WITH;
607
+ let suffixEnd = rule.value[0].replace(/^\//, "").replace(/\/$/, "");
608
+ isValid = !(
609
+ typeof fieldValue === "string" && fieldValue.endsWith(suffixEnd)
610
+ );
611
+ break;
612
+ case constants.regexTypes.NOT_CONTAINS:
613
+ message = custom_message ?? error_messages.REGEX_NOT_CONTAINS;
614
+ isValid = !regex.test(fieldValue);
615
+ break;
616
+ default:
617
+ isValid = false;
618
+ break;
619
+ }
552
620
 
553
621
  if (!isValid) {
554
622
  message = message
555
623
  ?.replace(`{field}`, fieldLabel)
556
624
  ?.replace(`{value}`, rule.value[0]);
625
+ console.log(
626
+ "[handleRegexValidation] Validation failed. Adding error. Message:",
627
+ message
628
+ );
557
629
  addError(
558
630
  currentPath,
559
631
  { label: fieldLabel, fieldPath: currentPath, description: "", message },
@@ -911,7 +983,8 @@ const validateField = (
911
983
  apiVersion,
912
984
  fieldOptions,
913
985
  language_codes,
914
- existingForm
986
+ existingForm,
987
+ getNodes = true
915
988
  ) => {
916
989
  if (onlyFormFields == true && value === undefined) return;
917
990
 
@@ -934,7 +1007,8 @@ const validateField = (
934
1007
  fieldOptions,
935
1008
  formData,
936
1009
  language_codes,
937
- existingForm
1010
+ existingForm,
1011
+ getNodes
938
1012
  );
939
1013
 
940
1014
  if (
@@ -971,7 +1045,8 @@ const validateField = (
971
1045
  apiVersion,
972
1046
  fieldOptions,
973
1047
  language_codes,
974
- existingForm
1048
+ existingForm,
1049
+ false
975
1050
  )
976
1051
  );
977
1052
  } else if (field.type === constants.types.ARRAY && Array.isArray(value)) {
@@ -1023,7 +1098,8 @@ const validateField = (
1023
1098
  apiVersion,
1024
1099
  fieldOptions,
1025
1100
  language_codes,
1026
- existingForm
1101
+ existingForm,
1102
+ false
1027
1103
  )
1028
1104
  );
1029
1105
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nox-validation",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "description": "validate dynamic schema",
5
5
  "main": "index.js",
6
6
  "scripts": {