nox-validation 1.0.6 → 1.0.8

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 CHANGED
@@ -157,31 +157,118 @@ const isEmpty = (val) => {
157
157
  return false;
158
158
  };
159
159
 
160
- const convertTypes = (field) => {
161
- // array_type:
162
- // item.type !== item.schema_definition.type &&
163
- // item.schema_definition.type !== constants.types.ALIAS
164
- // ? item.schema_definition.type
165
- // : item.type === item.schema_definition.type &&
166
- // item.type === constants.types.ARRAY
167
- // ? constants.types.OBJECT
168
- // : null,
169
-
170
- // type:
171
- // item.type === constants.types.ALIAS ||
172
- // item.schema_definition.type === constants.types.ALIAS
173
- // ? constants.types.OBJECT
174
- // : item.type,
175
-
176
- // 'list-o2m', // alias
177
- // 'list-m2o', // objectid
178
- // 'list-m2m', // alias
179
- // 'file', // objectid
180
- // 'file-image', // objectid
181
- // 'files', // alias
182
- // 'list-m2a', // alias
183
- // 'translations', // alias
160
+ // field?.field_type (Possible Values => Single, Object, Array)
161
+ // 1. Single => Root Field Then Its Single
162
+ // 2. Object => Nested Field Like Inside Array Or Object
163
+ // 3. Array => Any Kind Of Array Array Of String, Object etc
164
+
165
+ // field?.type (Possible Values)
166
+ // 1. String
167
+ // 2. Number
168
+ // 3. Date
169
+ // 4. Buffer
170
+ // 5. Boolean
171
+ // 6. Mixed
172
+ // 7. ObjectId
173
+ // 8. Object
174
+ // 9. Array
175
+ // 10. Alias
176
+
177
+ // field?.schema_definition?.type
178
+ // it is used for specially when field?.type is Array, but some times both are Array Then We Have to check
179
+
180
+ // field?.meta?.interface
181
+
182
+ const generateType = (field, api) => {
183
+ let { type, schema_definition, meta } = field;
184
+ let interfaceType = meta?.interface;
185
+ let array_type = schema_definition?.type;
186
+ let fieldType = type;
187
+ let find_relations = false;
188
+
184
189
 
190
+ // When type and Array Type Are Same
191
+ if (type === schema_definition?.type) {
192
+ // Type And Array Type Both is Array
193
+ if (type === constants.types.ARRAY) {
194
+ array_type = constants.types.OBJECT;
195
+ }
196
+ // Todo: when both is Alias type === constants.types.ALIAS
197
+ }
198
+
199
+ switch (api) {
200
+ case "v1":
201
+ // is Relational Field
202
+ if (interfaceType && interfaceType !== "none") {
203
+ // We Need to find Relation
204
+ if (
205
+ [constants.interfaces.MANY_TO_ANY, constants.interfaces.TRANSLATIONS].includes(
206
+ interfaceType
207
+ )
208
+ ) {
209
+ find_relations = true;
210
+ // update type and array type accordingly interface
211
+ if ([constants.interfaces.MANY_TO_ANY].includes(interfaceType)) {
212
+ fieldType = constants.types.ARRAY;
213
+ array_type = constants.types.OBJECT;
214
+ } else {
215
+ fieldType = constants.types.OBJECT;
216
+ }
217
+ } else {
218
+ // It is Relational Field, so we have to update type and array type accordingly interface
219
+ if ([constants.interfaces.MANY_TO_ONE].includes(interfaceType)) {
220
+ fieldType = constants.types.OBJECT_ID;
221
+ }
222
+
223
+ if (
224
+ [
225
+ constants.interfaces.ONE_TO_MANY,
226
+ constants.interfaces.MANY_TO_MANY,
227
+ constants.interfaces.FILES,
228
+ ].includes(interfaceType)
229
+ ) {
230
+ fieldType = constants.types.ARRAY;
231
+ array_type = constants.types.OBJECT_ID;
232
+ }
233
+ }
234
+ }
235
+
236
+ return {
237
+ type: fieldType,
238
+ array_type,
239
+ find_relations,
240
+ };
241
+
242
+ default:
243
+ // API V2
244
+ if (
245
+ [
246
+ constants.interfaces.ONE_TO_MANY,
247
+ constants.interfaces.MANY_TO_MANY,
248
+ constants.interfaces.MANY_TO_ANY,
249
+ constants.interfaces.MANY_TO_ONE,
250
+ constants.interfaces.TRANSLATIONS,
251
+ ].includes(interfaceType)
252
+ ) {
253
+ fieldType = constants.types.OBJECT;
254
+ array_type = null;
255
+ find_relations = true;
256
+ }
257
+
258
+ if (interfaceType === constants.interfaces.FILES) {
259
+ fieldType = constants.types.ARRAY;
260
+ array_type = constants.types.OBJECT_ID;
261
+ find_relations = false;
262
+ }
263
+ return {
264
+ type: fieldType,
265
+ array_type,
266
+ find_relations,
267
+ };
268
+ }
269
+ };
270
+
271
+ const convertTypes = (field) => {
185
272
  let { type, schema_definition, meta } = field;
186
273
  let array_type = schema_definition?.type ?? null;
187
274
  let interfaceType = meta?.interface;
@@ -207,7 +294,7 @@ const convertTypes = (field) => {
207
294
  return {
208
295
  type: constants.types.ARRAY,
209
296
  array_type: constants.types.OBJECT_ID,
210
- find_relations: true,
297
+ find_relations: false,
211
298
  };
212
299
  }
213
300
 
@@ -270,90 +357,83 @@ const convertTypesV1 = (field) => {
270
357
  return { type, array_type, find_relations };
271
358
  };
272
359
 
273
- const generateRelationalFieldV1 = (key = "", collectionFields = [], relationType) => {
274
- const generateField = (name, path, schema_definition_type, type, childrenFields = []) => {
275
- const relationalPath = key ? `${key}.${path}` : path;
276
-
360
+ const generateField = (name, path, schema_definition_type, type, childrenFields = []) => {
361
+ childrenFields = childrenFields?.map((child) => {
277
362
  return {
278
- display_label: name,
279
- key: relationalPath,
280
- value: relationalPath,
281
- children: childrenFields,
282
- type: type,
283
- meta: {
284
- required: false,
285
- nullable: false,
286
- hidden: false,
287
- },
288
- validations: [],
289
- array_type: schema_definition_type,
363
+ ...child,
364
+ value: `${path}.${child.value}`,
365
+ key: `${path}.${child.key}`,
290
366
  };
367
+ });
368
+
369
+ return {
370
+ display_label: name,
371
+ // field: name,
372
+ key: path,
373
+ value: path,
374
+ children: childrenFields,
375
+ type: type,
376
+ meta: {
377
+ required: false,
378
+ nullable: false,
379
+ hidden: false,
380
+ },
381
+ validations: [],
382
+ schema_definition: {
383
+ type: schema_definition_type,
384
+ },
291
385
  };
386
+ };
292
387
 
388
+ const generateRelationalFieldV1 = (key = "", collectionFields = [], relationType) => {
293
389
  if (relationType === constants.interfaces.MANY_TO_ANY) {
294
390
  return [
295
- generateField("collection", "collection", constants.types.STRING, constants.types.STRING),
296
- generateField("sort", "sort", constants.types.NUMBER, constants.types.NUMBER),
297
- generateField("item", "item", constants.types.OBJECT_ID, constants.types.OBJECT_ID),
391
+ generateField(
392
+ "collection",
393
+ `${key}.collection`,
394
+ constants.types.STRING,
395
+ constants.types.STRING
396
+ ),
397
+ generateField("sort", `${key}.sort`, constants.types.NUMBER, constants.types.NUMBER),
398
+ generateField("item", `${key}.item`, constants.types.OBJECT_ID, constants.types.OBJECT_ID),
298
399
  ];
299
400
  } else {
300
- return [];
401
+ return null;
301
402
  }
302
403
  };
303
404
 
304
405
  const generateRelationalField = (key = "", collectionFields = [], relationType) => {
305
- const generateField = (name, path, schema_definition_type, type, childrenFields = []) => {
306
- const relationalPath = key ? `${key}.${path}` : path;
307
- childrenFields = childrenFields?.map((child) => {
308
- return {
309
- ...child,
310
- key: `${relationalPath}.${child.key}`,
311
- value: `${relationalPath}.${child.value}`,
312
- };
313
- });
314
-
315
- return {
316
- display_label: name,
317
- key: relationalPath,
318
- value: relationalPath,
319
- children: childrenFields,
320
- type: type,
321
- meta: {
322
- required: false,
323
- nullable: false,
324
- hidden: false,
325
- },
326
- validations: [],
327
- array_type: schema_definition_type,
328
- };
329
- };
330
-
331
406
  if (relationType === constants.interfaces.MANY_TO_ANY) {
332
407
  const existingField = generateField(
333
- `${key}.existing`,
334
408
  "existing",
409
+ `${key}.existing`,
335
410
  constants.types.OBJECT,
336
411
  constants.types.ARRAY
337
412
  );
338
413
  existingField.children = [
339
414
  generateField(
340
415
  "collection",
341
- "existing.collection",
416
+ `${key}.existing.collection`,
342
417
  constants.types.STRING,
343
418
  constants.types.STRING
344
419
  ),
345
- generateField("sort", "existing.sort", constants.types.NUMBER, constants.types.NUMBER),
346
- generateField("item", "existing.item", constants.types.OBJECT_ID, constants.types.OBJECT_ID),
420
+ generateField("sort", `${key}.existing.sort`, constants.types.NUMBER, constants.types.NUMBER),
421
+ generateField(
422
+ "item",
423
+ `${key}.existing.item`,
424
+ constants.types.OBJECT_ID,
425
+ constants.types.OBJECT_ID
426
+ ),
347
427
  ];
348
428
  const deleteField = generateField(
349
429
  "delete",
350
- "delete",
430
+ `${key}.delete`,
351
431
  constants.types.OBJECT_ID,
352
432
  constants.types.ARRAY
353
433
  );
354
434
  const createField = generateField(
355
435
  "create",
356
- "create",
436
+ `${key}.create`,
357
437
  constants.types.OBJECT,
358
438
  constants.types.ARRAY,
359
439
  collectionFields
@@ -361,14 +441,14 @@ const generateRelationalField = (key = "", collectionFields = [], relationType)
361
441
  createField.children = [
362
442
  generateField(
363
443
  "collection",
364
- "create.collection",
444
+ `${key}.create.collection`,
365
445
  constants.types.STRING,
366
446
  constants.types.STRING
367
447
  ),
368
- generateField("sort", "create.sort", constants.types.NUMBER, constants.types.NUMBER),
448
+ generateField("sort", `${key}.create.sort`, constants.types.NUMBER, constants.types.NUMBER),
369
449
  generateField(
370
450
  "item",
371
- "create.item",
451
+ `${key}.create.item`,
372
452
  constants.types.OBJECT,
373
453
  constants.types.OBJECT,
374
454
  collectionFields
@@ -376,7 +456,7 @@ const generateRelationalField = (key = "", collectionFields = [], relationType)
376
456
  ];
377
457
  const updateField = generateField(
378
458
  "update",
379
- "update",
459
+ `${key}.update`,
380
460
  constants.types.OBJECT,
381
461
  constants.types.ARRAY,
382
462
  collectionFields
@@ -384,14 +464,14 @@ const generateRelationalField = (key = "", collectionFields = [], relationType)
384
464
  updateField.children = [
385
465
  generateField(
386
466
  "collection",
387
- "update.collection",
467
+ `${key}.update.collection`,
388
468
  constants.types.STRING,
389
469
  constants.types.STRING
390
470
  ),
391
- generateField("sort", "update.sort", constants.types.NUMBER, constants.types.NUMBER),
471
+ generateField("sort", `${key}.update.sort`, constants.types.NUMBER, constants.types.NUMBER),
392
472
  generateField(
393
473
  "item",
394
- "update.item",
474
+ `${key}.update.item`,
395
475
  constants.types.OBJECT,
396
476
  constants.types.OBJECT,
397
477
  collectionFields
@@ -400,18 +480,23 @@ const generateRelationalField = (key = "", collectionFields = [], relationType)
400
480
  return [existingField, deleteField, createField, updateField];
401
481
  } else {
402
482
  return [
403
- generateField("existing", "existing", constants.types.OBJECT_ID, constants.types.ARRAY),
404
- generateField("delete", "delete", constants.types.OBJECT_ID, constants.types.ARRAY),
483
+ generateField(
484
+ "existing",
485
+ `${key}.existing`,
486
+ constants.types.OBJECT_ID,
487
+ constants.types.ARRAY
488
+ ),
489
+ generateField("delete", `${key}.delete`, constants.types.OBJECT_ID, constants.types.ARRAY),
405
490
  generateField(
406
491
  "create",
407
- "create",
492
+ `${key}.create`,
408
493
  constants.types.OBJECT,
409
494
  constants.types.ARRAY,
410
495
  collectionFields
411
496
  ),
412
497
  generateField(
413
498
  "update",
414
- "update",
499
+ `${key}.update`,
415
500
  constants.types.OBJECT,
416
501
  constants.types.ARRAY,
417
502
  collectionFields
@@ -573,28 +658,50 @@ const getChildFields = (relationDetail, allFields, relational_fields, isTranslat
573
658
  }
574
659
  };
575
660
 
576
- const buildNestedStructure = (
661
+ const default_fields = [
662
+ "updated_by",
663
+ "created_by",
664
+ "created_at",
665
+ "updated_at",
666
+ "nox_created_at",
667
+ "nox_updated_at",
668
+ "nox_created_by",
669
+ "nox_updated_by",
670
+ "_id",
671
+ ];
672
+
673
+ const buildNestedStructure = ({
577
674
  schemaFields,
578
675
  allFields,
579
676
  relations,
580
- formData,
581
677
  relational_fields,
582
678
  isSeparatedFields,
583
- apiVersion
584
- ) => {
679
+ apiVersion,
680
+ maxLevel,
681
+ currentDepthMap,
682
+ rootPath,
683
+ isRoot,
684
+ }) => {
585
685
  const root = {};
586
686
  const nodeMap = new Map();
587
687
 
588
688
  schemaFields.sort((a, b) => a.path.split(".").length - b.path.split(".").length);
589
689
 
590
690
  schemaFields.forEach((item) => {
691
+ const pathParts = item.path.split(".");
692
+ const key = pathParts.join(".");
693
+
694
+ const currentDepth = currentDepthMap.get(isRoot ? item.path : rootPath) || 0;
695
+
696
+ if (currentDepth >= maxLevel) return;
697
+
591
698
  let childFields;
592
699
 
593
- const definedType =
594
- apiVersion === constants.API_VERSION.V1 ? convertTypesV1(item) : convertTypes(item);
595
- const isUserKey = item?.path?.includes("updated_by") || item?.path?.includes("created_by");
700
+ const definedType = generateType(item, apiVersion);
701
+ // apiVersion === constants.API_VERSION.V1 ? convertTypesV1(item) : convertTypes(item);
702
+ // const isUserKey = default_fields.some((field) => item?.path?.includes(field));
596
703
 
597
- if (definedType.find_relations && !isUserKey) {
704
+ if (definedType.find_relations) {
598
705
  const relationDetail = getForeignCollectionDetails({
599
706
  relations: relations,
600
707
  collection: item?.schema_id,
@@ -616,20 +723,23 @@ const buildNestedStructure = (
616
723
  }
617
724
 
618
725
  if (childFields) {
619
- childFields = buildNestedStructure(
620
- childFields,
621
- allFields,
622
- relations,
623
- formData,
624
- relational_fields,
625
- isSeparatedFields
626
- );
726
+ if (!isRoot) currentDepthMap.set(rootPath, currentDepth + 1);
727
+
728
+ childFields = buildNestedStructure({
729
+ schemaFields: childFields,
730
+ allFields: allFields,
731
+ relations: relations,
732
+ relational_fields: relational_fields,
733
+ isSeparatedFields,
734
+ apiVersion,
735
+ maxLevel,
736
+ currentDepthMap,
737
+ rootPath: isRoot ? item.path : rootPath,
738
+ isRoot: false,
739
+ });
627
740
  }
628
741
  }
629
742
 
630
- const pathParts = item.path.split(".");
631
- const key = pathParts.join(".");
632
-
633
743
  const node = {
634
744
  field_id: item?._id,
635
745
  display_label: pathParts[pathParts.length - 1],
@@ -698,12 +808,17 @@ const getAllKeys = (structure) => {
698
808
 
699
809
  const normalizeKey = (key) => key.replace(/\[\d+\]/g, "");
700
810
 
701
- const findDisallowedKeys = (formData, structure) => {
811
+ const findDisallowedKeys = (formData, structure, maxLevel) => {
702
812
  const formKeys = [];
703
813
  generateDynamicKeys(formData, formKeys);
704
814
 
705
815
  const validKeys = getAllKeys(structure);
706
- return formKeys.filter((key) => !validKeys.has(normalizeKey(key)));
816
+ return formKeys.filter((key) => {
817
+ const keyParts = normalizeKey(key).split(".");
818
+ const keyLevel = keyParts.length;
819
+ const levelParent = keyParts.slice(maxLevel - 1).join(".");
820
+ return !validKeys.has(normalizeKey(keyLevel > maxLevel ? levelParent : key));
821
+ });
707
822
  };
708
823
 
709
824
  const generateFieldCompareRules = (rule) => {
package/lib/validate.js CHANGED
@@ -7,6 +7,7 @@ const {
7
7
  getValue,
8
8
  setValue,
9
9
  isEmpty,
10
+ getParentKey,
10
11
  } = require("./helpers");
11
12
 
12
13
  const typeChecks = {
@@ -663,6 +664,7 @@ const schema = {
663
664
  },
664
665
  apiVersion: { type: constants.types.STRING, array_type: null },
665
666
  language: { type: constants.types.STRING, array_type: null },
667
+ maxLevel: { type: constants.types.NUMBER, array_type: null },
666
668
  };
667
669
 
668
670
  const validate = (data) => {
@@ -677,12 +679,12 @@ const validate = (data) => {
677
679
  byPassKeys,
678
680
  apiVersion,
679
681
  language,
682
+ maxLevel,
680
683
  } = data;
681
684
  const defaultLanguage = constants.LANGUAGES.length > 0 ? constants.LANGUAGES[0] : "en"; // Replace "en" with your actual default
682
685
  const error_messages =
683
686
  constants.LOCALE_MESSAGES[language] ?? constants.LOCALE_MESSAGES[defaultLanguage];
684
687
 
685
-
686
688
  let result = { status: true, errors: {}, data: formData };
687
689
 
688
690
  const updateValue = (key, value) => {
@@ -833,18 +835,23 @@ const validate = (data) => {
833
835
  schemaFields = fields.filter((field) => field?.schema_id?.toString() === formId?.toString());
834
836
  }
835
837
 
838
+ let currentDepthMap = new Map();
839
+
836
840
  const fieldOptions =
837
- buildNestedStructure(
838
- schemaFields || [],
839
- allFields,
840
- relations,
841
- formData,
842
- relationalFields,
841
+ buildNestedStructure({
842
+ schemaFields: schemaFields || [],
843
+ allFields: allFields,
844
+ relations: relations,
845
+ relational_fields: relationalFields,
843
846
  isSeparatedFields,
844
- apiVersion
845
- ) || [];
846
-
847
- findDisallowedKeys(formData, fieldOptions).forEach((fieldPath) => {
847
+ apiVersion,
848
+ maxLevel,
849
+ currentDepthMap,
850
+ rootPath: "",
851
+ isRoot: true,
852
+ }) || [];
853
+
854
+ findDisallowedKeys(formData, fieldOptions,maxLevel).forEach((fieldPath) => {
848
855
  if (abortEarly && !result.status) return result;
849
856
  const fieldKey = getLastChildKey(fieldPath);
850
857
  if (fieldKey && !result.errors[fieldPath]) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nox-validation",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "validate dynamic schema",
5
5
  "main": "index.js",
6
6
  "scripts": {