nox-validation 1.7.0 → 1.7.2
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/index.js +21 -6
- package/lib/helpers.optimized.js +52 -13
- package/lib/validate.js +57 -34
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -5,19 +5,34 @@ const {
|
|
|
5
5
|
buildNestedStructure,
|
|
6
6
|
getValue,
|
|
7
7
|
setValue,
|
|
8
|
-
getDefaultValues
|
|
8
|
+
getDefaultValues,
|
|
9
9
|
} = require("./lib/helpers");
|
|
10
10
|
|
|
11
|
+
const optimizedValidate = require("./lib/validate.optimized");
|
|
12
|
+
const helpersOptimized = require("./lib/helpers.optimized");
|
|
13
|
+
|
|
11
14
|
module.exports = {
|
|
12
15
|
validate,
|
|
13
16
|
CONSTANTS: constants,
|
|
14
17
|
helpers: {
|
|
15
18
|
validateSingleField: validateField,
|
|
16
19
|
validateType: typeChecks,
|
|
17
|
-
fieldsMapping:getFieldsGroupBySchemaId,
|
|
18
|
-
convertTree:buildNestedStructure,
|
|
19
|
-
getValueByDynamicKey:getValue,
|
|
20
|
-
setValueByDynamicKey:setValue,
|
|
21
|
-
getTreeDefaultValues:getDefaultValues
|
|
20
|
+
fieldsMapping: getFieldsGroupBySchemaId,
|
|
21
|
+
convertTree: buildNestedStructure,
|
|
22
|
+
getValueByDynamicKey: getValue,
|
|
23
|
+
setValueByDynamicKey: setValue,
|
|
24
|
+
getTreeDefaultValues: getDefaultValues,
|
|
25
|
+
},
|
|
26
|
+
optimized: {
|
|
27
|
+
validate: optimizedValidate.validate,
|
|
28
|
+
helpers: {
|
|
29
|
+
validateSingleField: helpersOptimized.validateField,
|
|
30
|
+
validateType: helpersOptimized.typeChecks,
|
|
31
|
+
fieldsMapping: helpersOptimized.getFieldsGroupBySchemaId,
|
|
32
|
+
convertTree: helpersOptimized.buildNestedStructure,
|
|
33
|
+
getValueByDynamicKey: helpersOptimized.getValue,
|
|
34
|
+
setValueByDynamicKey: helpersOptimized.setValue,
|
|
35
|
+
getTreeDefaultValues: helpersOptimized.getDefaultValues,
|
|
36
|
+
},
|
|
22
37
|
},
|
|
23
38
|
};
|
package/lib/helpers.optimized.js
CHANGED
|
@@ -1105,21 +1105,53 @@ const buildNestedStructure = ({
|
|
|
1105
1105
|
const root = {};
|
|
1106
1106
|
const nodeMap = new Map();
|
|
1107
1107
|
|
|
1108
|
-
// Sort fields by path depth once
|
|
1109
1108
|
const sortedFields = [...schemaFields].sort(
|
|
1110
1109
|
(a, b) => a.path.split(".").length - b.path.split(".").length
|
|
1111
1110
|
);
|
|
1112
1111
|
|
|
1113
|
-
|
|
1114
|
-
const isV2FileInterface = (interface) =>
|
|
1112
|
+
const isV2FileInterface = (interfaceName) =>
|
|
1115
1113
|
apiVersion === constants.API_VERSION.V2 &&
|
|
1116
1114
|
[
|
|
1117
1115
|
constants.interfaces.FILES,
|
|
1118
1116
|
constants.interfaces.FILE,
|
|
1119
1117
|
constants.interfaces.FILE_IMAGE,
|
|
1120
|
-
].includes(
|
|
1118
|
+
].includes(interfaceName);
|
|
1119
|
+
|
|
1120
|
+
// utility to adjust children keys as required
|
|
1121
|
+
function adjustChildKeys(
|
|
1122
|
+
children,
|
|
1123
|
+
parentType,
|
|
1124
|
+
parentKey,
|
|
1125
|
+
parentMetaInterface
|
|
1126
|
+
) {
|
|
1127
|
+
if (!Array.isArray(children) || children.length === 0) return children;
|
|
1128
|
+
// For array parent type
|
|
1129
|
+
if (parentType === constants.types.ARRAY) {
|
|
1130
|
+
// If translation
|
|
1131
|
+
if (parentMetaInterface === constants.interfaces.TRANSLATIONS) {
|
|
1132
|
+
// e.g., parent.key[lang_code].child.key
|
|
1133
|
+
return children.map((child) => ({
|
|
1134
|
+
...child,
|
|
1135
|
+
key: `${parentKey}[lang_code].${child.key.split(".").pop()}`,
|
|
1136
|
+
value: `${parentKey}[lang_code].${child.key.split(".").pop()}`,
|
|
1137
|
+
}));
|
|
1138
|
+
} else {
|
|
1139
|
+
// e.g., parent.key[idx].child.key
|
|
1140
|
+
return children.map((child) => ({
|
|
1141
|
+
...child,
|
|
1142
|
+
key: `${parentKey}[idx].${child.key.split(".").pop()}`,
|
|
1143
|
+
value: `${parentKey}[idx].${child.key.split(".").pop()}`,
|
|
1144
|
+
}));
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
// For normal object type, just parent.key.child.key
|
|
1148
|
+
return children.map((child) => ({
|
|
1149
|
+
...child,
|
|
1150
|
+
key: `${parentKey}.${child.key.split(".").pop()}`,
|
|
1151
|
+
value: `${parentKey}.${child.key.split(".").pop()}`,
|
|
1152
|
+
}));
|
|
1153
|
+
}
|
|
1121
1154
|
|
|
1122
|
-
// Process each field in a single pass
|
|
1123
1155
|
for (const item of sortedFields) {
|
|
1124
1156
|
const pathParts = item.path.split(".");
|
|
1125
1157
|
const key = pathParts.join(".");
|
|
@@ -1215,6 +1247,13 @@ const buildNestedStructure = ({
|
|
|
1215
1247
|
} else {
|
|
1216
1248
|
children = childFields;
|
|
1217
1249
|
}
|
|
1250
|
+
// Now, adjust children keys as required
|
|
1251
|
+
children = adjustChildKeys(
|
|
1252
|
+
children,
|
|
1253
|
+
definedType.type,
|
|
1254
|
+
key,
|
|
1255
|
+
item.meta?.interface
|
|
1256
|
+
);
|
|
1218
1257
|
}
|
|
1219
1258
|
|
|
1220
1259
|
// Add _id field for arrays
|
|
@@ -1382,7 +1421,7 @@ const RULE_TRANSFORM_MAP = {
|
|
|
1382
1421
|
case: constants.rulesTypes.REGEX,
|
|
1383
1422
|
options: (rule) => ({
|
|
1384
1423
|
type: constants.regexTypes.CONTAINS,
|
|
1385
|
-
case_sensitive: !rule[rule.type]
|
|
1424
|
+
case_sensitive: !rule[rule.type]?.insensitive,
|
|
1386
1425
|
multiline: false,
|
|
1387
1426
|
global: false,
|
|
1388
1427
|
}),
|
|
@@ -1391,7 +1430,7 @@ const RULE_TRANSFORM_MAP = {
|
|
|
1391
1430
|
case: constants.rulesTypes.REGEX,
|
|
1392
1431
|
options: (rule) => ({
|
|
1393
1432
|
type: constants.regexTypes.NOT_CONTAINS,
|
|
1394
|
-
case_sensitive: !rule[rule.type]
|
|
1433
|
+
case_sensitive: !rule[rule.type]?.insensitive,
|
|
1395
1434
|
multiline: false,
|
|
1396
1435
|
global: false,
|
|
1397
1436
|
}),
|
|
@@ -1400,28 +1439,28 @@ const RULE_TRANSFORM_MAP = {
|
|
|
1400
1439
|
case: constants.rulesTypes.REGEX,
|
|
1401
1440
|
options: (rule) => ({
|
|
1402
1441
|
type: constants.regexTypes.START_WITH,
|
|
1403
|
-
case_sensitive: !rule[rule.type]
|
|
1442
|
+
case_sensitive: !rule[rule.type]?.insensitive,
|
|
1404
1443
|
}),
|
|
1405
1444
|
},
|
|
1406
1445
|
doesNotStartWith: {
|
|
1407
1446
|
case: constants.rulesTypes.REGEX,
|
|
1408
1447
|
options: (rule) => ({
|
|
1409
1448
|
type: constants.regexTypes.NOT_START_WITH,
|
|
1410
|
-
case_sensitive: !rule[rule.type]
|
|
1449
|
+
case_sensitive: !rule[rule.type]?.insensitive,
|
|
1411
1450
|
}),
|
|
1412
1451
|
},
|
|
1413
1452
|
endsWith: {
|
|
1414
1453
|
case: constants.rulesTypes.REGEX,
|
|
1415
1454
|
options: (rule) => ({
|
|
1416
1455
|
type: constants.regexTypes.ENDS_WITH,
|
|
1417
|
-
case_sensitive: !rule[rule.type]
|
|
1456
|
+
case_sensitive: !rule[rule.type]?.insensitive,
|
|
1418
1457
|
}),
|
|
1419
1458
|
},
|
|
1420
1459
|
doesNotEndWith: {
|
|
1421
1460
|
case: constants.rulesTypes.REGEX,
|
|
1422
1461
|
options: (rule) => ({
|
|
1423
1462
|
type: constants.regexTypes.NOT_ENDS_WITH,
|
|
1424
|
-
case_sensitive: !rule[rule.type]
|
|
1463
|
+
case_sensitive: !rule[rule.type]?.insensitive,
|
|
1425
1464
|
}),
|
|
1426
1465
|
},
|
|
1427
1466
|
matchesRegExp: {
|
|
@@ -1465,12 +1504,12 @@ const RULE_TRANSFORM_MAP = {
|
|
|
1465
1504
|
isOneOf: {
|
|
1466
1505
|
case: constants.rulesTypes.ONE_OF,
|
|
1467
1506
|
options: () => ({}),
|
|
1468
|
-
value: (rule) => rule[rule.type]
|
|
1507
|
+
value: (rule) => rule[rule.type]?.value,
|
|
1469
1508
|
},
|
|
1470
1509
|
isNotOneOf: {
|
|
1471
1510
|
case: constants.rulesTypes.NOT_ONE_OF,
|
|
1472
1511
|
options: () => ({}),
|
|
1473
|
-
value: (rule) => [rule[rule.type]
|
|
1512
|
+
value: (rule) => [rule[rule.type]?.value],
|
|
1474
1513
|
},
|
|
1475
1514
|
};
|
|
1476
1515
|
|
package/lib/validate.js
CHANGED
|
@@ -224,7 +224,18 @@ const isEmptyRelational = ({
|
|
|
224
224
|
}
|
|
225
225
|
} else if (api_version === constants.API_VERSION.V2) {
|
|
226
226
|
if (isEmpty(existingValue)) return true;
|
|
227
|
-
|
|
227
|
+
let all = Array.isArray(existingValue)
|
|
228
|
+
? existingValue.length === 0
|
|
229
|
+
? []
|
|
230
|
+
: typeof existingValue[0] === "string"
|
|
231
|
+
? existingValue
|
|
232
|
+
: existingValue.map((item) => item._id)
|
|
233
|
+
: typeof existingValue === "string"
|
|
234
|
+
? [existingValue]
|
|
235
|
+
: existingValue && typeof existingValue === "object"
|
|
236
|
+
? [existingValue._id]
|
|
237
|
+
: [];
|
|
238
|
+
all = Array.isArray(all) ? all?.filter(Boolean) : all;
|
|
228
239
|
switch (interface) {
|
|
229
240
|
case constants.interfaces.FILE:
|
|
230
241
|
case constants.interfaces.FILE_IMAGE:
|
|
@@ -232,30 +243,17 @@ const isEmptyRelational = ({
|
|
|
232
243
|
case constants.interfaces.MANY_TO_MANY:
|
|
233
244
|
case constants.interfaces.ONE_TO_MANY:
|
|
234
245
|
case constants.interfaces.MANY_TO_ONE:
|
|
235
|
-
case constants.interfaces.
|
|
246
|
+
case constants.interfaces.MANY_TO_ANY:
|
|
236
247
|
return remainingItems({
|
|
237
|
-
all:
|
|
238
|
-
? existingValue.length === 0
|
|
239
|
-
? []
|
|
240
|
-
: typeof existingValue[0] === "string"
|
|
241
|
-
? existingValue
|
|
242
|
-
: existingValue.map((item) => item._id)
|
|
243
|
-
: typeof existingValue === "string"
|
|
244
|
-
? [existingValue]
|
|
245
|
-
: existingValue && typeof existingValue === "object"
|
|
246
|
-
? [existingValue._id]
|
|
247
|
-
: [],
|
|
248
|
+
all: all,
|
|
248
249
|
obj: value,
|
|
250
|
+
isM2A: interface === constants.interfaces.MANY_TO_ANY,
|
|
249
251
|
});
|
|
250
|
-
case constants.interfaces.
|
|
252
|
+
case constants.interfaces.SEO:
|
|
251
253
|
return remainingItems({
|
|
252
|
-
all:
|
|
253
|
-
? existingValue?.map((item) => item.item)
|
|
254
|
-
: [],
|
|
254
|
+
all: all,
|
|
255
255
|
obj: value,
|
|
256
|
-
isM2A: true,
|
|
257
256
|
});
|
|
258
|
-
|
|
259
257
|
// constants.interfaces.TRANSLATIONS,
|
|
260
258
|
default:
|
|
261
259
|
return true;
|
|
@@ -365,7 +363,16 @@ const validateMetaRules = (
|
|
|
365
363
|
value: fieldValue,
|
|
366
364
|
interface: field?.meta?.interface,
|
|
367
365
|
onlyFormFields,
|
|
368
|
-
existingValue:
|
|
366
|
+
existingValue:
|
|
367
|
+
getValue(existingForm, currentPath) ||
|
|
368
|
+
getValue(
|
|
369
|
+
existingForm,
|
|
370
|
+
currentPath
|
|
371
|
+
?.replace(".create", "")
|
|
372
|
+
?.replace(".update", "")
|
|
373
|
+
?.replace(".existing", "")
|
|
374
|
+
?.replace(".delete", "")
|
|
375
|
+
), // TODO: Need to Generate Form Path Without create, update, existing, delete
|
|
369
376
|
})
|
|
370
377
|
: true;
|
|
371
378
|
|
|
@@ -475,6 +482,7 @@ const validateMetaRules = (
|
|
|
475
482
|
const isTranslationNode =
|
|
476
483
|
node?.meta?.parentInterface === constants.interfaces.TRANSLATIONS ||
|
|
477
484
|
field?.meta?.interface === constants.interfaces.TRANSLATIONS;
|
|
485
|
+
|
|
478
486
|
let fPath = node.key?.replace("[0][0]", "[0]");
|
|
479
487
|
const types = ["update", "delete", "existing", "create"];
|
|
480
488
|
const extractFirstType = (key) => {
|
|
@@ -1203,10 +1211,12 @@ const validateField = (
|
|
|
1203
1211
|
if (itemType) {
|
|
1204
1212
|
value.forEach((item, index) => {
|
|
1205
1213
|
const itemPath = `${currentPath}[${index}]`;
|
|
1206
|
-
|
|
1207
1214
|
if (
|
|
1208
1215
|
(choices.includes(field?.meta?.interface) && !isEmpty(item)) ||
|
|
1209
|
-
([
|
|
1216
|
+
([
|
|
1217
|
+
constants.interfaces.TAGS,
|
|
1218
|
+
constants.interfaces.ARRAY_OF_VALUES,
|
|
1219
|
+
].includes(field?.meta?.interface) &&
|
|
1210
1220
|
!isEmpty(item))
|
|
1211
1221
|
) {
|
|
1212
1222
|
applyValidations(
|
|
@@ -1239,7 +1249,20 @@ const validateField = (
|
|
|
1239
1249
|
}
|
|
1240
1250
|
if (field.children?.length > 0) {
|
|
1241
1251
|
value.forEach((item, index) => {
|
|
1242
|
-
field.children.forEach((child) =>
|
|
1252
|
+
field.children.forEach((child) => {
|
|
1253
|
+
let trPath =
|
|
1254
|
+
field?.meta?.parentInterface ===
|
|
1255
|
+
constants.interfaces.TRANSLATIONS && item["languages_code"]
|
|
1256
|
+
? `${currentPath}.${item["languages_code"]}`
|
|
1257
|
+
: null;
|
|
1258
|
+
|
|
1259
|
+
if (
|
|
1260
|
+
trPath &&
|
|
1261
|
+
field.meta?.staticType === "update" &&
|
|
1262
|
+
trPath.includes(".update.")
|
|
1263
|
+
)
|
|
1264
|
+
trPath = trPath.replace(".update.", ".");
|
|
1265
|
+
|
|
1243
1266
|
validateField(
|
|
1244
1267
|
child,
|
|
1245
1268
|
item[child.key.split(".").pop()],
|
|
@@ -1255,12 +1278,9 @@ const validateField = (
|
|
|
1255
1278
|
existingForm,
|
|
1256
1279
|
false,
|
|
1257
1280
|
timeZone,
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
: null
|
|
1262
|
-
)
|
|
1263
|
-
);
|
|
1281
|
+
trPath
|
|
1282
|
+
);
|
|
1283
|
+
});
|
|
1264
1284
|
});
|
|
1265
1285
|
}
|
|
1266
1286
|
} else {
|
|
@@ -1394,11 +1414,14 @@ const validate = (data) => {
|
|
|
1394
1414
|
};
|
|
1395
1415
|
|
|
1396
1416
|
const addError = (fieldPath, obj, field) => {
|
|
1397
|
-
fieldPath = [
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1417
|
+
// fieldPath = [
|
|
1418
|
+
// ...choices,
|
|
1419
|
+
// constants.interfaces.TAGS,
|
|
1420
|
+
// constants.interfaces.ARRAY_OF_VALUES,
|
|
1421
|
+
// ].includes(field?.meta?.interface)
|
|
1422
|
+
// ? fieldPath?.replace(/\[\d+\].*$/, "")
|
|
1423
|
+
// : fieldPath;
|
|
1424
|
+
// TODO: Path is Sometimes Become Wrong (Like Unflatten) if we uncomment this
|
|
1402
1425
|
|
|
1403
1426
|
const fieldKey = getLastChildKey(fieldPath);
|
|
1404
1427
|
const isBypass = byPassKeys?.some((key) => key === fieldKey);
|