validno 0.1.0
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/.eslintrc.cjs +13 -0
- package/.eslintrc.json +16 -0
- package/README.md +1 -0
- package/dist/Schema.js +15 -0
- package/dist/Validator.js +100 -0
- package/dist/checkRules.js +122 -0
- package/dist/checkType.js +151 -0
- package/dist/index.js +2 -0
- package/dist/utils/validations.js +87 -0
- package/dist/validate.js +110 -0
- package/jest.config.ts +199 -0
- package/nodemon.json +4 -0
- package/package.json +26 -0
- package/src/Schema.ts +40 -0
- package/src/app.ts +199 -0
- package/src/checkRules.ts +146 -0
- package/src/checkType.ts +172 -0
- package/src/index.ts +3 -0
- package/src/tsconfig.json +103 -0
- package/src/utils/validations.ts +111 -0
- package/src/validate.ts +166 -0
- package/tests/types.test.js +311 -0
package/.eslintrc.cjs
ADDED
package/.eslintrc.json
ADDED
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#TODO
|
package/dist/Schema.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import validate from "./validate.js";
|
|
2
|
+
export const defaultSchemaKeys = [
|
|
3
|
+
"required",
|
|
4
|
+
"type",
|
|
5
|
+
"eachType",
|
|
6
|
+
"rules"
|
|
7
|
+
];
|
|
8
|
+
export class Schema {
|
|
9
|
+
constructor(inputSchema) {
|
|
10
|
+
this.schema = inputSchema;
|
|
11
|
+
}
|
|
12
|
+
validate(data) {
|
|
13
|
+
return validate.call(this, this, data);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import checkRules from "./checkRules.js";
|
|
2
|
+
import checkType from "./checkType.js";
|
|
3
|
+
import { defaultSchemaKeys } from "./Schema.js";
|
|
4
|
+
const getResultDefault = () => {
|
|
5
|
+
return {
|
|
6
|
+
ok: null,
|
|
7
|
+
missed: [],
|
|
8
|
+
failed: [],
|
|
9
|
+
passed: [],
|
|
10
|
+
errors: [],
|
|
11
|
+
byKeys: {}
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
const checkIsNested = (obj) => {
|
|
15
|
+
const objKeys = Object.keys(obj);
|
|
16
|
+
if (objKeys.every((k) => defaultSchemaKeys.includes(k))) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const handleReqKey = (key, data, reqs, deepKey = key) => {
|
|
24
|
+
console.log('..................... ', key);
|
|
25
|
+
const results = getResultDefault();
|
|
26
|
+
const hasNested = checkIsNested(reqs);
|
|
27
|
+
const missedCheck = [];
|
|
28
|
+
const typeChecked = [];
|
|
29
|
+
const rulesChecked = [];
|
|
30
|
+
if (hasNested) {
|
|
31
|
+
const nestedReqKeys = Object.keys(reqs);
|
|
32
|
+
let i = 0;
|
|
33
|
+
while (i < nestedReqKeys.length) {
|
|
34
|
+
const reqKeyI = nestedReqKeys[i];
|
|
35
|
+
const deepResults = handleReqKey(reqKeyI, data[key], reqs[reqKeyI], deepKey + '.' + reqKeyI);
|
|
36
|
+
results.failed = [...results.failed, ...deepResults.failed];
|
|
37
|
+
results.errors = [...results.errors, ...deepResults.errors];
|
|
38
|
+
results.missed = [...results.missed, ...deepResults.missed];
|
|
39
|
+
results.passed = [...results.passed, ...deepResults.passed];
|
|
40
|
+
results.byKeys = Object.assign(Object.assign({}, results.byKeys), deepResults.byKeys);
|
|
41
|
+
i++;
|
|
42
|
+
}
|
|
43
|
+
return results;
|
|
44
|
+
}
|
|
45
|
+
if (reqs.required === true && key in data === false) {
|
|
46
|
+
missedCheck.push(false);
|
|
47
|
+
results.errors.push(`Missing key '${deepKey}'`);
|
|
48
|
+
return results;
|
|
49
|
+
}
|
|
50
|
+
const typeCheck = checkType(key, data[key], reqs, deepKey);
|
|
51
|
+
typeCheck.forEach(res => {
|
|
52
|
+
if (res.passed === false) {
|
|
53
|
+
typeChecked.push(res.passed);
|
|
54
|
+
results.errors.push(res.details);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
const ruleCheck = checkRules(deepKey, data[key], reqs);
|
|
58
|
+
if (!ruleCheck.ok) {
|
|
59
|
+
rulesChecked.push(false);
|
|
60
|
+
ruleCheck.details.forEach((el) => results.errors.push(el));
|
|
61
|
+
}
|
|
62
|
+
if (missedCheck.length) {
|
|
63
|
+
results.missed.push(deepKey);
|
|
64
|
+
}
|
|
65
|
+
if (typeChecked.length || rulesChecked.length) {
|
|
66
|
+
results.failed.push(deepKey);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
results.passed.push(deepKey);
|
|
70
|
+
}
|
|
71
|
+
console.log(missedCheck.length, typeChecked.length, rulesChecked.length);
|
|
72
|
+
results.byKeys[deepKey] = (missedCheck.length + typeChecked.length + rulesChecked.length) === 0;
|
|
73
|
+
console.log(results);
|
|
74
|
+
return results;
|
|
75
|
+
};
|
|
76
|
+
const validate = (schema, data) => {
|
|
77
|
+
const results = getResultDefault();
|
|
78
|
+
for (const [key, reqs] of Object.entries(schema.schema)) {
|
|
79
|
+
const keyResult = handleReqKey(key, data, reqs);
|
|
80
|
+
results.failed = [...results.failed, ...keyResult.failed];
|
|
81
|
+
results.errors = [...results.errors, ...keyResult.errors];
|
|
82
|
+
results.missed = [...results.missed, ...keyResult.missed];
|
|
83
|
+
results.passed = [...results.passed, ...keyResult.passed];
|
|
84
|
+
results.byKeys = Object.assign(Object.assign({}, results.byKeys), keyResult.byKeys);
|
|
85
|
+
}
|
|
86
|
+
if (results.failed.length)
|
|
87
|
+
results.ok = false;
|
|
88
|
+
else
|
|
89
|
+
results.ok = true;
|
|
90
|
+
results.missed = [...new Set(results.missed)];
|
|
91
|
+
results.failed = [...new Set(results.failed)];
|
|
92
|
+
results.passed = [...new Set(results.passed)];
|
|
93
|
+
results.errors = [...new Set(results.errors)];
|
|
94
|
+
return results;
|
|
95
|
+
};
|
|
96
|
+
class Validator {
|
|
97
|
+
constructor() { }
|
|
98
|
+
}
|
|
99
|
+
Validator.validate = validate;
|
|
100
|
+
export default Validator;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import _validations from "./utils/validations.js";
|
|
2
|
+
const rulesFunctions = {
|
|
3
|
+
custom: (key, val, func) => {
|
|
4
|
+
return func(val);
|
|
5
|
+
},
|
|
6
|
+
isEmail: (key, val) => {
|
|
7
|
+
return {
|
|
8
|
+
result: _validations.isEmail(val),
|
|
9
|
+
details: `Значение должно соответствовать формату name@email.ru`
|
|
10
|
+
};
|
|
11
|
+
},
|
|
12
|
+
is: (key, val, equalTo) => {
|
|
13
|
+
return {
|
|
14
|
+
result: _validations.is(val, equalTo),
|
|
15
|
+
details: `Значение должно быть "${equalTo}"`
|
|
16
|
+
};
|
|
17
|
+
},
|
|
18
|
+
isNot: (key, val, notEqualTo) => {
|
|
19
|
+
return {
|
|
20
|
+
result: _validations.isNot(val, notEqualTo),
|
|
21
|
+
details: `Значение не должно быть "${notEqualTo}"`
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
min: (key, val, min) => {
|
|
25
|
+
return {
|
|
26
|
+
result: _validations.isNumberGte(val, min),
|
|
27
|
+
details: "Значение не может быть меньше " + min
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
max: (key, val, max) => {
|
|
31
|
+
return {
|
|
32
|
+
result: _validations.isNumberLte(val, max),
|
|
33
|
+
details: "Значение не может быть больше " + max
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
minMax: (key, val, minMax) => {
|
|
37
|
+
const [min, max] = minMax;
|
|
38
|
+
return {
|
|
39
|
+
result: _validations.isNumberGte(val, min) && _validations.isNumberLte(val, max),
|
|
40
|
+
details: `Значение должно быть в пределах ${min}-${max}`
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
length: (key, val, length) => {
|
|
44
|
+
return {
|
|
45
|
+
result: _validations.lengthIs(val, length),
|
|
46
|
+
details: "Количество символов должно быть равным " + length
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
lengthNot: (key, val, lengthNot) => {
|
|
50
|
+
return {
|
|
51
|
+
result: _validations.lengthNot(val, lengthNot),
|
|
52
|
+
details: "Количество символов не должно быть равным " + lengthNot
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
lengthMinMax: (key, val, minMax) => {
|
|
56
|
+
const [min, max] = minMax;
|
|
57
|
+
return {
|
|
58
|
+
result: _validations.lengthMin(val, min) && _validations.lengthMin(val, max),
|
|
59
|
+
details: `Длина должна быть от ${min} до ${max} символов`
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
lengthMin: (key, val, min) => {
|
|
63
|
+
return {
|
|
64
|
+
result: _validations.lengthMin(val, min),
|
|
65
|
+
details: `Длина не может быть меньше ${min} символов`
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
lengthMax: (key, val, max) => {
|
|
69
|
+
return {
|
|
70
|
+
result: _validations.lengthMax(val, max),
|
|
71
|
+
details: `Длина не может быть больше ${max} символов`
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
regex: (key, val, regex) => {
|
|
75
|
+
return {
|
|
76
|
+
result: _validations.regexTested(val, regex),
|
|
77
|
+
details: "Значение не соответствует допустимому формату"
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
enum: (key, value, allowedList) => {
|
|
81
|
+
return {
|
|
82
|
+
result: allowedList.includes(value),
|
|
83
|
+
details: `Значение "${value}" не допустимо`
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const checkRules = (key, value, requirements) => {
|
|
88
|
+
const result = {
|
|
89
|
+
ok: true,
|
|
90
|
+
details: []
|
|
91
|
+
};
|
|
92
|
+
if (requirements.required !== true && value === undefined)
|
|
93
|
+
return result;
|
|
94
|
+
if ('rules' in requirements === false)
|
|
95
|
+
return result;
|
|
96
|
+
if (!requirements || !requirements.rules || !Object.keys(requirements.rules).length) {
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
const rules = requirements.rules;
|
|
100
|
+
const allResults = [];
|
|
101
|
+
const allRules = Object.keys(rules);
|
|
102
|
+
let i = 0;
|
|
103
|
+
while (i < allRules.length) {
|
|
104
|
+
const ruleName = allRules[i];
|
|
105
|
+
if (ruleName in rulesFunctions === false) {
|
|
106
|
+
i++;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const func = rulesFunctions[ruleName];
|
|
110
|
+
const args = rules[ruleName];
|
|
111
|
+
const result = func(key, value, args);
|
|
112
|
+
allResults.push(result);
|
|
113
|
+
i++;
|
|
114
|
+
}
|
|
115
|
+
const failedResults = allResults.filter(el => el.result === false);
|
|
116
|
+
if (failedResults.length) {
|
|
117
|
+
result.ok = false;
|
|
118
|
+
result.details = failedResults.map(el => el.details);
|
|
119
|
+
}
|
|
120
|
+
return result;
|
|
121
|
+
};
|
|
122
|
+
export default checkRules;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import _validations from "./utils/validations.js";
|
|
2
|
+
const getErrorDetails = (key, expectedType, receivedValue) => {
|
|
3
|
+
let receivedType = '';
|
|
4
|
+
if (typeof receivedValue === 'string')
|
|
5
|
+
receivedType = 'String';
|
|
6
|
+
else if (typeof receivedValue === 'number')
|
|
7
|
+
receivedType = 'Number';
|
|
8
|
+
else if (typeof receivedValue === 'boolean')
|
|
9
|
+
receivedType = 'Noolean';
|
|
10
|
+
else if (receivedValue === null)
|
|
11
|
+
receivedType = 'null';
|
|
12
|
+
else if (Array.isArray(receivedValue))
|
|
13
|
+
receivedType = 'Array';
|
|
14
|
+
else if (_validations.isDate(receivedValue))
|
|
15
|
+
receivedType = 'Date';
|
|
16
|
+
else if (_validations.isObject(receivedValue))
|
|
17
|
+
receivedType = 'Object';
|
|
18
|
+
else if (receivedValue === undefined)
|
|
19
|
+
receivedType = 'undefined';
|
|
20
|
+
return `Проверьте тип "${key}": ожидался ${(expectedType === null || expectedType === void 0 ? void 0 : expectedType.name) || expectedType}, получен ${receivedType || 'unknown'}`;
|
|
21
|
+
};
|
|
22
|
+
const checkTypeMultiple = (key, value, requirements, keyName = key) => {
|
|
23
|
+
const constructorNames = requirements.type.map((el) => String((el === null || el === void 0 ? void 0 : el.name) || el));
|
|
24
|
+
const result = {
|
|
25
|
+
key: keyName,
|
|
26
|
+
passed: false,
|
|
27
|
+
details: getErrorDetails(keyName, constructorNames.join('/'), value)
|
|
28
|
+
};
|
|
29
|
+
let i = 0;
|
|
30
|
+
while (i < requirements.type.length) {
|
|
31
|
+
const requirementsRe = Object.assign(Object.assign({}, requirements), { type: requirements.type[i] });
|
|
32
|
+
const check = checkType(key, value, requirementsRe);
|
|
33
|
+
if (check[0].passed === true) {
|
|
34
|
+
result.passed = true;
|
|
35
|
+
result.details = 'Passed';
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
i++;
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
const checkType = (key, value, requirements, keyName = key) => {
|
|
43
|
+
if (value === undefined && requirements.required) {
|
|
44
|
+
return [{ key: keyName, passed: false, details: `Key ${keyName} is missing` }];
|
|
45
|
+
}
|
|
46
|
+
let result = [];
|
|
47
|
+
if (Array.isArray(requirements.type)) {
|
|
48
|
+
return [checkTypeMultiple(key, value, requirements)];
|
|
49
|
+
}
|
|
50
|
+
if (value === undefined && requirements.required !== true) {
|
|
51
|
+
result.push({
|
|
52
|
+
key: keyName,
|
|
53
|
+
passed: true,
|
|
54
|
+
details: 'Passed'
|
|
55
|
+
});
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
switch (requirements.type) {
|
|
59
|
+
case 'any':
|
|
60
|
+
result.push({
|
|
61
|
+
key: keyName,
|
|
62
|
+
passed: true,
|
|
63
|
+
details: 'Passed'
|
|
64
|
+
});
|
|
65
|
+
break;
|
|
66
|
+
case Number:
|
|
67
|
+
const isNumber = _validations.isNumber(value);
|
|
68
|
+
result.push({
|
|
69
|
+
key: keyName,
|
|
70
|
+
passed: isNumber,
|
|
71
|
+
details: isNumber ? 'Passed' : getErrorDetails(keyName, requirements.type, value)
|
|
72
|
+
});
|
|
73
|
+
break;
|
|
74
|
+
case String:
|
|
75
|
+
const isString = _validations.isString(value);
|
|
76
|
+
result.push({
|
|
77
|
+
key: keyName,
|
|
78
|
+
passed: isString,
|
|
79
|
+
details: isString ? 'Passed' : getErrorDetails(keyName, requirements.type, value)
|
|
80
|
+
});
|
|
81
|
+
break;
|
|
82
|
+
case Date:
|
|
83
|
+
const isDate = _validations.isDate(value);
|
|
84
|
+
result.push({
|
|
85
|
+
key: keyName,
|
|
86
|
+
passed: isDate,
|
|
87
|
+
details: isDate ? 'Passed' : getErrorDetails(keyName, requirements.type, value)
|
|
88
|
+
});
|
|
89
|
+
break;
|
|
90
|
+
case Boolean:
|
|
91
|
+
const isBoolean = _validations.isBoolean(value);
|
|
92
|
+
result.push({
|
|
93
|
+
key: keyName,
|
|
94
|
+
passed: isBoolean,
|
|
95
|
+
details: isBoolean ? 'Passed' : getErrorDetails(keyName, requirements.type, value)
|
|
96
|
+
});
|
|
97
|
+
break;
|
|
98
|
+
case Array:
|
|
99
|
+
const isArray = _validations.isArray(value);
|
|
100
|
+
let isEachChecked = { passed: true, details: "" };
|
|
101
|
+
if ('eachType' in requirements) {
|
|
102
|
+
isEachChecked.passed = value.every((el) => {
|
|
103
|
+
const checkResult = checkType('each of ' + key, el, { type: requirements.eachType, required: true });
|
|
104
|
+
if (!checkResult[0].passed) {
|
|
105
|
+
isEachChecked.details = checkResult[0].details;
|
|
106
|
+
isEachChecked.passed = false;
|
|
107
|
+
}
|
|
108
|
+
return true;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
const isOk = isArray && isEachChecked.passed;
|
|
112
|
+
result.push({
|
|
113
|
+
key: keyName,
|
|
114
|
+
passed: isOk,
|
|
115
|
+
details: isOk ? 'Passed' : !isEachChecked.passed ? isEachChecked.details : getErrorDetails(keyName, requirements.type, value)
|
|
116
|
+
});
|
|
117
|
+
break;
|
|
118
|
+
case Object:
|
|
119
|
+
const isObject = _validations.isObject(value);
|
|
120
|
+
result.push({
|
|
121
|
+
key: keyName,
|
|
122
|
+
passed: isObject,
|
|
123
|
+
details: isObject ? 'Passed' : getErrorDetails(keyName, requirements.type, value)
|
|
124
|
+
});
|
|
125
|
+
break;
|
|
126
|
+
case RegExp:
|
|
127
|
+
const isRegex = _validations.isRegex(value);
|
|
128
|
+
result.push({
|
|
129
|
+
key: keyName,
|
|
130
|
+
passed: isRegex,
|
|
131
|
+
details: isRegex ? 'Passed' : getErrorDetails(keyName, requirements.type, value)
|
|
132
|
+
});
|
|
133
|
+
break;
|
|
134
|
+
case null:
|
|
135
|
+
const isNull = _validations.isNull(value);
|
|
136
|
+
result.push({
|
|
137
|
+
key: keyName,
|
|
138
|
+
passed: isNull,
|
|
139
|
+
details: isNull ? 'Passed' : getErrorDetails(keyName, requirements.type, value)
|
|
140
|
+
});
|
|
141
|
+
break;
|
|
142
|
+
default:
|
|
143
|
+
result.push({
|
|
144
|
+
key: keyName,
|
|
145
|
+
passed: false,
|
|
146
|
+
details: `No type specified for key: '${keyName}'`
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return result;
|
|
150
|
+
};
|
|
151
|
+
export default checkType;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const _validations = {};
|
|
2
|
+
_validations.isString = (value) => {
|
|
3
|
+
return typeof value === 'string';
|
|
4
|
+
};
|
|
5
|
+
_validations.isDate = (value) => {
|
|
6
|
+
return value instanceof Date && String(value) !== 'Invalid Date';
|
|
7
|
+
};
|
|
8
|
+
_validations.isNumber = (value) => {
|
|
9
|
+
return typeof value === 'number';
|
|
10
|
+
};
|
|
11
|
+
_validations.isNumberGte = (value, gte) => {
|
|
12
|
+
return typeof value === 'number' && value >= gte;
|
|
13
|
+
};
|
|
14
|
+
_validations.isNumberLte = (value, lte) => {
|
|
15
|
+
return typeof value === 'number' && value <= lte;
|
|
16
|
+
};
|
|
17
|
+
_validations.isArray = (value) => {
|
|
18
|
+
return Array.isArray(value);
|
|
19
|
+
};
|
|
20
|
+
_validations.isObject = (value) => {
|
|
21
|
+
return typeof value === 'object' && !Array.isArray(value) && value !== null;
|
|
22
|
+
};
|
|
23
|
+
_validations.lengthIs = (value, length) => {
|
|
24
|
+
return value.length === length;
|
|
25
|
+
};
|
|
26
|
+
_validations.lengthNot = (value, length) => {
|
|
27
|
+
return value.length !== length;
|
|
28
|
+
};
|
|
29
|
+
_validations.lengthMin = (value, min) => {
|
|
30
|
+
return value.length >= min;
|
|
31
|
+
};
|
|
32
|
+
_validations.lengthMax = (value, max) => {
|
|
33
|
+
return value.length <= max;
|
|
34
|
+
};
|
|
35
|
+
_validations.isEmail = (value) => {
|
|
36
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
37
|
+
return emailRegex.test(value);
|
|
38
|
+
};
|
|
39
|
+
_validations.isRegex = (value) => {
|
|
40
|
+
return value instanceof RegExp;
|
|
41
|
+
};
|
|
42
|
+
_validations.hasKey = (obj, key) => {
|
|
43
|
+
return key in obj;
|
|
44
|
+
};
|
|
45
|
+
_validations.isNot = (value, not) => {
|
|
46
|
+
if (typeof not === 'object' && Array.isArray(not)) {
|
|
47
|
+
for (let i = 0; i < not.length; i++) {
|
|
48
|
+
if (value === not[i])
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
return value !== not;
|
|
54
|
+
};
|
|
55
|
+
_validations.is = (value, compareTo) => {
|
|
56
|
+
if (typeof compareTo === 'object' && Array.isArray(compareTo)) {
|
|
57
|
+
for (let i = 0; i < compareTo.length; i++) {
|
|
58
|
+
if (value === compareTo[i])
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
return value === compareTo;
|
|
64
|
+
};
|
|
65
|
+
_validations.isDateYYYYMMDD = (value) => {
|
|
66
|
+
const regex = /^\d{4}-\d{2}-\d{2}$/;
|
|
67
|
+
return regex.test(value);
|
|
68
|
+
};
|
|
69
|
+
_validations.regexTested = (value, regex) => {
|
|
70
|
+
if (!regex)
|
|
71
|
+
throw new Error('regex argument is not defined');
|
|
72
|
+
return regex.test(value);
|
|
73
|
+
};
|
|
74
|
+
_validations.isHex = (value) => {
|
|
75
|
+
const regex = /^#(?:[0-9a-fA-F]{3}){1,2}$/;
|
|
76
|
+
return regex.test(value);
|
|
77
|
+
};
|
|
78
|
+
_validations.isBoolean = (value) => {
|
|
79
|
+
return typeof value === 'boolean';
|
|
80
|
+
};
|
|
81
|
+
_validations.isNull = (value) => {
|
|
82
|
+
return value === null;
|
|
83
|
+
};
|
|
84
|
+
_validations.isUndefined = (value) => {
|
|
85
|
+
return value === undefined;
|
|
86
|
+
};
|
|
87
|
+
export default _validations;
|
package/dist/validate.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import checkRules from "./checkRules.js";
|
|
2
|
+
import checkType from "./checkType.js";
|
|
3
|
+
import { defaultSchemaKeys } from "./Schema.js";
|
|
4
|
+
import _validations from "./utils/validations.js";
|
|
5
|
+
const getResultDefaults = () => {
|
|
6
|
+
return {
|
|
7
|
+
ok: null,
|
|
8
|
+
missed: [],
|
|
9
|
+
failed: [],
|
|
10
|
+
passed: [],
|
|
11
|
+
errors: [],
|
|
12
|
+
byKeys: {},
|
|
13
|
+
errorsByKeys: {}
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
const checkIsNested = (obj) => {
|
|
17
|
+
if (!_validations.isObject(obj))
|
|
18
|
+
return false;
|
|
19
|
+
const objKeys = Object.keys(obj);
|
|
20
|
+
if (objKeys.every((k) => defaultSchemaKeys.includes(k))) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const mergeResults = (resultsOld, resultsNew) => {
|
|
28
|
+
const output = getResultDefaults();
|
|
29
|
+
output.failed = [...resultsOld.failed, ...resultsNew.failed];
|
|
30
|
+
output.errors = [...resultsOld.errors, ...resultsNew.errors];
|
|
31
|
+
output.missed = [...resultsOld.missed, ...resultsNew.missed];
|
|
32
|
+
output.passed = [...resultsOld.passed, ...resultsNew.passed];
|
|
33
|
+
output.byKeys = Object.assign(Object.assign({}, resultsOld.byKeys), resultsNew.byKeys);
|
|
34
|
+
output.errorsByKeys = Object.assign(Object.assign({}, resultsOld.errorsByKeys), resultsNew.errorsByKeys);
|
|
35
|
+
return output;
|
|
36
|
+
};
|
|
37
|
+
const handleReqKey = (key, data, reqs, deepKey = key) => {
|
|
38
|
+
let results = getResultDefaults();
|
|
39
|
+
const hasNested = checkIsNested(reqs);
|
|
40
|
+
const missedCheck = [];
|
|
41
|
+
const typeChecked = [];
|
|
42
|
+
const rulesChecked = [];
|
|
43
|
+
if (reqs.required && (data === undefined ||
|
|
44
|
+
(_validations.isObject(data) && !Object.keys(data).length))) {
|
|
45
|
+
results.missed.push(deepKey);
|
|
46
|
+
results.failed.push(deepKey);
|
|
47
|
+
results.byKeys[deepKey] = false;
|
|
48
|
+
return results;
|
|
49
|
+
}
|
|
50
|
+
if (hasNested) {
|
|
51
|
+
const nestedReqKeys = Object.keys(reqs);
|
|
52
|
+
results.byKeys[deepKey] = true;
|
|
53
|
+
let i = 0;
|
|
54
|
+
while (i < nestedReqKeys.length) {
|
|
55
|
+
const reqKeyI = nestedReqKeys[i];
|
|
56
|
+
const deepResults = handleReqKey(reqKeyI, data[key], reqs[reqKeyI], deepKey + '.' + reqKeyI);
|
|
57
|
+
results = mergeResults(results, deepResults);
|
|
58
|
+
i++;
|
|
59
|
+
}
|
|
60
|
+
return results;
|
|
61
|
+
}
|
|
62
|
+
if (reqs.required === true && key in data === false || data === undefined) {
|
|
63
|
+
missedCheck.push(false);
|
|
64
|
+
results.errors.push(`Missing key '${deepKey}'`);
|
|
65
|
+
return results;
|
|
66
|
+
}
|
|
67
|
+
const typeCheck = checkType(key, data[key], reqs, deepKey);
|
|
68
|
+
typeCheck.forEach(res => {
|
|
69
|
+
if (res.passed === false) {
|
|
70
|
+
typeChecked.push(res.passed);
|
|
71
|
+
results.errors.push(res.details);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
const ruleCheck = checkRules(deepKey, data[key], reqs);
|
|
75
|
+
if (!ruleCheck.ok) {
|
|
76
|
+
rulesChecked.push(false);
|
|
77
|
+
ruleCheck.details.forEach((el) => {
|
|
78
|
+
if (deepKey in results.errorsByKeys)
|
|
79
|
+
results.errorsByKeys[deepKey] = [];
|
|
80
|
+
results.errors.push(el);
|
|
81
|
+
results.errorsByKeys[deepKey] = ['1'];
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
if (missedCheck.length)
|
|
85
|
+
results.missed.push(deepKey);
|
|
86
|
+
if (typeChecked.length || rulesChecked.length) {
|
|
87
|
+
results.failed.push(deepKey);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
results.passed.push(deepKey);
|
|
91
|
+
}
|
|
92
|
+
results.errorsByKeys[deepKey] = [
|
|
93
|
+
...results.errors
|
|
94
|
+
];
|
|
95
|
+
results.byKeys[deepKey] = (missedCheck.length + typeChecked.length + rulesChecked.length) === 0;
|
|
96
|
+
return results;
|
|
97
|
+
};
|
|
98
|
+
const validate = (schema, data) => {
|
|
99
|
+
let results = getResultDefaults();
|
|
100
|
+
for (const [key, reqs] of Object.entries(schema.schema)) {
|
|
101
|
+
const keyResult = handleReqKey(key, data, reqs);
|
|
102
|
+
results = mergeResults(results, keyResult);
|
|
103
|
+
}
|
|
104
|
+
if (results.failed.length)
|
|
105
|
+
results.ok = false;
|
|
106
|
+
else
|
|
107
|
+
results.ok = true;
|
|
108
|
+
return results;
|
|
109
|
+
};
|
|
110
|
+
export default validate;
|