schema-shield 0.0.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/README.md +11 -0
- package/dist/formats.d.ts +3 -0
- package/dist/formats.d.ts.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1289 -0
- package/dist/index.min.js +1 -0
- package/dist/index.min.js.map +1 -0
- package/dist/index.mjs +1267 -0
- package/dist/keywords/array-keywords.d.ts +3 -0
- package/dist/keywords/array-keywords.d.ts.map +1 -0
- package/dist/keywords/number-keywords.d.ts +3 -0
- package/dist/keywords/number-keywords.d.ts.map +1 -0
- package/dist/keywords/object-keywords.d.ts +3 -0
- package/dist/keywords/object-keywords.d.ts.map +1 -0
- package/dist/keywords/other-keywords.d.ts +3 -0
- package/dist/keywords/other-keywords.d.ts.map +1 -0
- package/dist/keywords/string-keywords.d.ts +3 -0
- package/dist/keywords/string-keywords.d.ts.map +1 -0
- package/dist/keywords.d.ts +3 -0
- package/dist/keywords.d.ts.map +1 -0
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils.d.ts +13 -0
- package/dist/utils.d.ts.map +1 -0
- package/lib/formats.ts +56 -0
- package/lib/index.ts +308 -0
- package/lib/keywords/array-keywords.ts +204 -0
- package/lib/keywords/number-keywords.ts +79 -0
- package/lib/keywords/object-keywords.ts +230 -0
- package/lib/keywords/other-keywords.ts +248 -0
- package/lib/keywords/string-keywords.ts +165 -0
- package/lib/keywords.ts +14 -0
- package/lib/types.ts +176 -0
- package/lib/utils.ts +79 -0
- package/package.json +189 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ValidationError } from "../utils";
|
|
2
|
+
import { ValidatorFunction } from "../index";
|
|
3
|
+
|
|
4
|
+
export const NumberKeywords: Record<string, ValidatorFunction> = {
|
|
5
|
+
minimum(schema, data, pointer) {
|
|
6
|
+
if (typeof data !== "number") {
|
|
7
|
+
return { valid: true, errors: [], data };
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const min = schema.exclusiveMinimum
|
|
11
|
+
? schema.minimum + 1e-15
|
|
12
|
+
: schema.minimum;
|
|
13
|
+
|
|
14
|
+
const valid = data >= min;
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
valid,
|
|
18
|
+
errors: valid
|
|
19
|
+
? []
|
|
20
|
+
: [
|
|
21
|
+
new ValidationError("Number is too small", {
|
|
22
|
+
pointer,
|
|
23
|
+
value: data,
|
|
24
|
+
code: "NUMBER_TOO_SMALL"
|
|
25
|
+
})
|
|
26
|
+
],
|
|
27
|
+
data
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
maximum(schema, data, pointer) {
|
|
32
|
+
if (typeof data !== "number") {
|
|
33
|
+
return { valid: true, errors: [], data };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const max = schema.exclusiveMaximum
|
|
37
|
+
? schema.maximum - 1e-15
|
|
38
|
+
: schema.maximum;
|
|
39
|
+
|
|
40
|
+
const valid = data <= max;
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
valid,
|
|
44
|
+
errors: valid
|
|
45
|
+
? []
|
|
46
|
+
: [
|
|
47
|
+
new ValidationError("Number is too large", {
|
|
48
|
+
pointer,
|
|
49
|
+
value: data,
|
|
50
|
+
code: "NUMBER_TOO_LARGE"
|
|
51
|
+
})
|
|
52
|
+
],
|
|
53
|
+
data
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
multipleOf(schema, data, pointer) {
|
|
58
|
+
if (typeof data !== "number") {
|
|
59
|
+
return { valid: true, errors: [], data };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const quotient = data / schema.multipleOf;
|
|
63
|
+
const areMultiples = Math.abs(quotient - Math.round(quotient)) < 1e-15;
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
valid: areMultiples,
|
|
67
|
+
errors: areMultiples
|
|
68
|
+
? []
|
|
69
|
+
: [
|
|
70
|
+
new ValidationError("Number is not a multiple of", {
|
|
71
|
+
pointer,
|
|
72
|
+
value: data,
|
|
73
|
+
code: "NUMBER_NOT_MULTIPLE_OF"
|
|
74
|
+
})
|
|
75
|
+
],
|
|
76
|
+
data
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
};
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { CompiledSchema, ValidatorFunction } from "../index";
|
|
2
|
+
import { ValidationError, isObject } from "../utils";
|
|
3
|
+
|
|
4
|
+
export const ObjectKeywords: Record<string, ValidatorFunction> = {
|
|
5
|
+
// Object
|
|
6
|
+
required(schema, data, pointer) {
|
|
7
|
+
if (!isObject(data)) {
|
|
8
|
+
return {
|
|
9
|
+
valid: true,
|
|
10
|
+
errors: [],
|
|
11
|
+
data
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const errors = [];
|
|
16
|
+
for (let i = 0; i < schema.required.length; i++) {
|
|
17
|
+
const key = schema.required[i];
|
|
18
|
+
if (!data.hasOwnProperty(key)) {
|
|
19
|
+
errors.push(
|
|
20
|
+
new ValidationError("Missing required property", {
|
|
21
|
+
pointer: `${pointer}/${key}`,
|
|
22
|
+
value: data,
|
|
23
|
+
code: "MISSING_REQUIRED_PROPERTY"
|
|
24
|
+
})
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return { valid: errors.length === 0, errors, data };
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
properties(schema, data, pointer, schemaShieldInstance) {
|
|
33
|
+
if (!isObject(data)) {
|
|
34
|
+
return { valid: true, errors: [], data };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const errors = [];
|
|
38
|
+
let finalData = { ...data };
|
|
39
|
+
for (let key in schema.properties) {
|
|
40
|
+
if (!data.hasOwnProperty(key) || typeof data[key] === "undefined") {
|
|
41
|
+
if (
|
|
42
|
+
isObject(schema.properties[key]) &&
|
|
43
|
+
"default" in schema.properties[key]
|
|
44
|
+
) {
|
|
45
|
+
finalData[key] = schema.properties[key].default;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (typeof schema.properties[key] === "boolean") {
|
|
52
|
+
if (schema.properties[key] === false) {
|
|
53
|
+
errors.push(
|
|
54
|
+
new ValidationError("Property is not allowed", {
|
|
55
|
+
pointer: `${pointer}/${key}`,
|
|
56
|
+
value: data[key],
|
|
57
|
+
code: "PROPERTY_NOT_ALLOWED"
|
|
58
|
+
})
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const { validator } = schema.properties[key] as CompiledSchema;
|
|
65
|
+
if (!validator) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const validatorResult = validator(
|
|
70
|
+
schema.properties[key],
|
|
71
|
+
finalData[key],
|
|
72
|
+
`${pointer}/${key}`,
|
|
73
|
+
schemaShieldInstance
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
finalData[key] = validatorResult.data;
|
|
77
|
+
|
|
78
|
+
if (!validatorResult.valid) {
|
|
79
|
+
errors.push(...validatorResult.errors);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return { valid: errors.length === 0, errors, data: finalData };
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
maxProperties(schema, data, pointer) {
|
|
87
|
+
if (!isObject(data) || Object.keys(data).length <= schema.maxProperties) {
|
|
88
|
+
return { valid: true, errors: [], data };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
valid: false,
|
|
93
|
+
errors: [
|
|
94
|
+
new ValidationError("Object has too many properties", {
|
|
95
|
+
pointer,
|
|
96
|
+
value: data,
|
|
97
|
+
code: "OBJECT_TOO_MANY_PROPERTIES"
|
|
98
|
+
})
|
|
99
|
+
],
|
|
100
|
+
data
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
minProperties(schema, data, pointer) {
|
|
105
|
+
if (!isObject(data) || Object.keys(data).length >= schema.minProperties) {
|
|
106
|
+
return { valid: true, errors: [], data };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
valid: false,
|
|
111
|
+
errors: [
|
|
112
|
+
new ValidationError("Object has too few properties", {
|
|
113
|
+
pointer,
|
|
114
|
+
value: data,
|
|
115
|
+
code: "OBJECT_TOO_FEW_PROPERTIES"
|
|
116
|
+
})
|
|
117
|
+
],
|
|
118
|
+
data
|
|
119
|
+
};
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
additionalProperties(schema, data, pointer, schemaShieldInstance) {
|
|
123
|
+
if (!isObject(data)) {
|
|
124
|
+
return { valid: true, errors: [], data };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const errors = [];
|
|
128
|
+
let finalData = { ...data };
|
|
129
|
+
for (let key in data) {
|
|
130
|
+
if (schema.properties && schema.properties.hasOwnProperty(key)) {
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (schema.patternProperties) {
|
|
135
|
+
let match = false;
|
|
136
|
+
for (let pattern in schema.patternProperties) {
|
|
137
|
+
if (new RegExp(pattern).test(key)) {
|
|
138
|
+
match = true;
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (match) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (schema.additionalProperties === false) {
|
|
148
|
+
errors.push(
|
|
149
|
+
new ValidationError("Additional property not allowed", {
|
|
150
|
+
pointer: `${pointer}/${key}`,
|
|
151
|
+
value: data,
|
|
152
|
+
code: "ADDITIONAL_PROPERTY_NOT_ALLOWED"
|
|
153
|
+
})
|
|
154
|
+
);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const { validator } = schema.additionalProperties as CompiledSchema;
|
|
159
|
+
if (!validator) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const validatorResult = validator(
|
|
164
|
+
schema.additionalProperties,
|
|
165
|
+
finalData[key],
|
|
166
|
+
`${pointer}/${key}`,
|
|
167
|
+
schemaShieldInstance
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
finalData[key] = validatorResult.data;
|
|
171
|
+
|
|
172
|
+
if (!validatorResult.valid) {
|
|
173
|
+
errors.push(...validatorResult.errors);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return { valid: errors.length === 0, errors, data: finalData };
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
patternProperties(schema, data, pointer, schemaShieldInstance) {
|
|
181
|
+
if (!isObject(data)) {
|
|
182
|
+
return { valid: true, errors: [], data };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const errors = [];
|
|
186
|
+
let finalData = { ...data };
|
|
187
|
+
for (let pattern in schema.patternProperties) {
|
|
188
|
+
if (typeof schema.patternProperties[pattern] === "boolean") {
|
|
189
|
+
if (schema.patternProperties[pattern] === false) {
|
|
190
|
+
for (let key in finalData) {
|
|
191
|
+
if (new RegExp(pattern).test(key)) {
|
|
192
|
+
errors.push(
|
|
193
|
+
new ValidationError("Property is not allowed", {
|
|
194
|
+
pointer: `${pointer}/${key}`,
|
|
195
|
+
value: data[key],
|
|
196
|
+
code: "PROPERTY_NOT_ALLOWED"
|
|
197
|
+
})
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const { validator } = schema.patternProperties[pattern] as CompiledSchema;
|
|
206
|
+
if (!validator) {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
for (let key in finalData) {
|
|
211
|
+
if (new RegExp(pattern).test(key)) {
|
|
212
|
+
const validatorResult = validator(
|
|
213
|
+
schema.patternProperties[pattern],
|
|
214
|
+
finalData[key],
|
|
215
|
+
`${pointer}/${key}`,
|
|
216
|
+
schemaShieldInstance
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
finalData[key] = validatorResult.data;
|
|
220
|
+
|
|
221
|
+
if (!validatorResult.valid) {
|
|
222
|
+
errors.push(...validatorResult.errors);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return { valid: errors.length === 0, errors, data: finalData };
|
|
229
|
+
}
|
|
230
|
+
};
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { CompiledSchema, ValidatorFunction } from "../index";
|
|
2
|
+
import { ValidationError, isObject } from "../utils";
|
|
3
|
+
|
|
4
|
+
export const OtherKeywords: Record<string, ValidatorFunction> = {
|
|
5
|
+
nullable(schema, data, pointer) {
|
|
6
|
+
if (schema.nullable && data !== null) {
|
|
7
|
+
return {
|
|
8
|
+
valid: false,
|
|
9
|
+
errors: [
|
|
10
|
+
new ValidationError("Value must be null to be empty", {
|
|
11
|
+
pointer,
|
|
12
|
+
value: data,
|
|
13
|
+
code: "VALUE_NOT_NULL"
|
|
14
|
+
})
|
|
15
|
+
],
|
|
16
|
+
data
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return { valid: true, errors: [], data };
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
oneOf(schema, data, pointer, schemaShieldInstance) {
|
|
24
|
+
const errors = [];
|
|
25
|
+
let validCount = 0;
|
|
26
|
+
let finalData = data;
|
|
27
|
+
for (let i = 0; i < schema.oneOf.length; i++) {
|
|
28
|
+
if (isObject(schema.oneOf[i])) {
|
|
29
|
+
const { validator } = schema.oneOf[i] as CompiledSchema;
|
|
30
|
+
if (!validator) {
|
|
31
|
+
validCount++;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const validationResult = validator(
|
|
35
|
+
schema.oneOf[i],
|
|
36
|
+
finalData,
|
|
37
|
+
pointer,
|
|
38
|
+
schemaShieldInstance
|
|
39
|
+
);
|
|
40
|
+
if (validationResult.valid) {
|
|
41
|
+
validCount++;
|
|
42
|
+
} else {
|
|
43
|
+
errors.push(...validationResult.errors);
|
|
44
|
+
}
|
|
45
|
+
finalData = validationResult.data;
|
|
46
|
+
} else {
|
|
47
|
+
if (typeof schema.oneOf[i] === "boolean") {
|
|
48
|
+
if (Boolean(data) === schema.oneOf[i]) {
|
|
49
|
+
validCount++;
|
|
50
|
+
}
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (data === schema.oneOf[i]) {
|
|
55
|
+
validCount++;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (validCount === 1) {
|
|
61
|
+
return { valid: true, errors: [], data: finalData };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
valid: false,
|
|
66
|
+
errors: [
|
|
67
|
+
new ValidationError(`Value must match exactly one schema in oneOf`, {
|
|
68
|
+
pointer,
|
|
69
|
+
value: data,
|
|
70
|
+
code: "VALUE_DOES_NOT_MATCH_ONE_OF"
|
|
71
|
+
})
|
|
72
|
+
],
|
|
73
|
+
data: finalData
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
allOf(schema, data, pointer, schemaShieldInstance) {
|
|
78
|
+
const errors = [];
|
|
79
|
+
let finalData = data;
|
|
80
|
+
for (let i = 0; i < schema.allOf.length; i++) {
|
|
81
|
+
if (isObject(schema.allOf[i])) {
|
|
82
|
+
const { validator } = schema.allOf[i] as CompiledSchema;
|
|
83
|
+
if (!validator) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const validatorResult = validator(
|
|
88
|
+
schema.allOf[i],
|
|
89
|
+
finalData,
|
|
90
|
+
pointer,
|
|
91
|
+
schemaShieldInstance
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
if (!validatorResult.valid) {
|
|
95
|
+
errors.push(...validatorResult.errors);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
finalData = validatorResult.data;
|
|
99
|
+
} else {
|
|
100
|
+
if (typeof schema.allOf[i] === "boolean") {
|
|
101
|
+
if (Boolean(data) !== schema.allOf[i]) {
|
|
102
|
+
errors.push(
|
|
103
|
+
new ValidationError(`Value must match all schemas in allOf`, {
|
|
104
|
+
pointer,
|
|
105
|
+
value: data,
|
|
106
|
+
code: "VALUE_DOES_NOT_MATCH_ALL_OF"
|
|
107
|
+
})
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (data !== schema.allOf[i]) {
|
|
114
|
+
errors.push(
|
|
115
|
+
new ValidationError(`Value must match all schemas in allOf`, {
|
|
116
|
+
pointer,
|
|
117
|
+
value: data,
|
|
118
|
+
code: "VALUE_DOES_NOT_MATCH_ALL_OF"
|
|
119
|
+
})
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return { valid: errors.length === 0, errors, data: finalData };
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
anyOf(schema, data, pointer, schemaShieldInstance) {
|
|
129
|
+
let finalData = data;
|
|
130
|
+
|
|
131
|
+
for (let i = 0; i < schema.anyOf.length; i++) {
|
|
132
|
+
if (isObject(schema.anyOf[i])) {
|
|
133
|
+
const { validator } = schema.anyOf[i] as CompiledSchema;
|
|
134
|
+
if (!validator) {
|
|
135
|
+
return { valid: true, errors: [], data };
|
|
136
|
+
}
|
|
137
|
+
const validationResult = validator(
|
|
138
|
+
schema.anyOf[i],
|
|
139
|
+
finalData,
|
|
140
|
+
pointer,
|
|
141
|
+
schemaShieldInstance
|
|
142
|
+
);
|
|
143
|
+
finalData = validationResult.data;
|
|
144
|
+
if (validationResult.valid) {
|
|
145
|
+
return { valid: true, errors: [], data: finalData };
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
if (typeof schema.anyOf[i] === "boolean") {
|
|
149
|
+
if (Boolean(data) === schema.anyOf[i]) {
|
|
150
|
+
return { valid: true, errors: [], data: finalData };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (data === schema.anyOf[i]) {
|
|
155
|
+
return { valid: true, errors: [], data: finalData };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
valid: false,
|
|
162
|
+
errors: [
|
|
163
|
+
new ValidationError(`Value must match at least one schema in anyOf`, {
|
|
164
|
+
pointer,
|
|
165
|
+
value: data,
|
|
166
|
+
code: "VALUE_DOES_NOT_MATCH_ANY_OF"
|
|
167
|
+
})
|
|
168
|
+
],
|
|
169
|
+
data
|
|
170
|
+
};
|
|
171
|
+
},
|
|
172
|
+
|
|
173
|
+
dependencies(schema, data, pointer, schemaShieldInstance) {
|
|
174
|
+
if (!isObject(data)) {
|
|
175
|
+
return { valid: true, errors: [], data };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const errors = [];
|
|
179
|
+
let finalData = data;
|
|
180
|
+
for (const key in schema.dependencies) {
|
|
181
|
+
if (key in data === false) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const dependency = schema.dependencies[key];
|
|
186
|
+
if (Array.isArray(dependency)) {
|
|
187
|
+
for (let i = 0; i < dependency.length; i++) {
|
|
188
|
+
if (!(dependency[i] in data)) {
|
|
189
|
+
errors.push(
|
|
190
|
+
new ValidationError(`Dependency ${dependency[i]} is missing`, {
|
|
191
|
+
pointer,
|
|
192
|
+
value: data,
|
|
193
|
+
code: "DEPENDENCY_MISSING"
|
|
194
|
+
})
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (typeof dependency === "boolean") {
|
|
202
|
+
if (dependency) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
errors.push(
|
|
206
|
+
new ValidationError(`Dependency ${key} is missing`, {
|
|
207
|
+
pointer,
|
|
208
|
+
value: data,
|
|
209
|
+
code: "DEPENDENCY_MISSING"
|
|
210
|
+
})
|
|
211
|
+
);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (typeof dependency === "string") {
|
|
216
|
+
if (dependency in data) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
errors.push(
|
|
220
|
+
new ValidationError(`Dependency ${dependency} is missing`, {
|
|
221
|
+
pointer,
|
|
222
|
+
value: data,
|
|
223
|
+
code: "DEPENDENCY_MISSING"
|
|
224
|
+
})
|
|
225
|
+
);
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const { validator } = dependency as CompiledSchema;
|
|
230
|
+
if (!validator) {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const validatorResult = validator(
|
|
235
|
+
dependency,
|
|
236
|
+
finalData,
|
|
237
|
+
pointer,
|
|
238
|
+
schemaShieldInstance
|
|
239
|
+
);
|
|
240
|
+
if (!validatorResult.valid) {
|
|
241
|
+
errors.push(...validatorResult.errors);
|
|
242
|
+
}
|
|
243
|
+
finalData = validatorResult.data;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return { valid: errors.length === 0, errors, data: finalData };
|
|
247
|
+
}
|
|
248
|
+
};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { ValidationError, deepEqual } from "../utils";
|
|
2
|
+
|
|
3
|
+
import { ValidatorFunction } from "../index";
|
|
4
|
+
|
|
5
|
+
export const StringKeywords: Record<string, ValidatorFunction> = {
|
|
6
|
+
minLength(schema, data, pointer) {
|
|
7
|
+
if (typeof data !== "string" || data.length >= schema.minLength) {
|
|
8
|
+
return { valid: true, errors: [], data };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
valid: false,
|
|
13
|
+
errors: [
|
|
14
|
+
new ValidationError("String is too short", {
|
|
15
|
+
pointer,
|
|
16
|
+
value: data,
|
|
17
|
+
code: "STRING_TOO_SHORT"
|
|
18
|
+
})
|
|
19
|
+
],
|
|
20
|
+
data
|
|
21
|
+
};
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
maxLength(schema, data, pointer) {
|
|
25
|
+
if (typeof data !== "string" || data.length <= schema.maxLength) {
|
|
26
|
+
return { valid: true, errors: [], data };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
valid: false,
|
|
31
|
+
errors: [
|
|
32
|
+
new ValidationError("String is too long", {
|
|
33
|
+
pointer,
|
|
34
|
+
value: data,
|
|
35
|
+
code: "STRING_TOO_LONG"
|
|
36
|
+
})
|
|
37
|
+
],
|
|
38
|
+
data
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
pattern(schema, data, pointer) {
|
|
43
|
+
if (typeof data !== "string") {
|
|
44
|
+
return { valid: true, errors: [], data };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const patternRegexp =
|
|
48
|
+
typeof schema.pattern === "string"
|
|
49
|
+
? new RegExp(schema.pattern)
|
|
50
|
+
: schema.pattern;
|
|
51
|
+
|
|
52
|
+
if (patternRegexp instanceof RegExp === false) {
|
|
53
|
+
return {
|
|
54
|
+
valid: false,
|
|
55
|
+
errors: [
|
|
56
|
+
new ValidationError("Pattern is not a valid regular expression", {
|
|
57
|
+
pointer,
|
|
58
|
+
value: data,
|
|
59
|
+
code: "PATTERN_IS_NOT_REGEXP"
|
|
60
|
+
})
|
|
61
|
+
],
|
|
62
|
+
data
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const valid = patternRegexp.test(data);
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
valid,
|
|
70
|
+
errors: valid
|
|
71
|
+
? []
|
|
72
|
+
: [
|
|
73
|
+
new ValidationError("String does not match pattern", {
|
|
74
|
+
pointer,
|
|
75
|
+
value: data,
|
|
76
|
+
code: "STRING_DOES_NOT_MATCH_PATTERN"
|
|
77
|
+
})
|
|
78
|
+
],
|
|
79
|
+
data
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
format(schema, data, pointer, formatInstance) {
|
|
84
|
+
if (typeof data !== "string") {
|
|
85
|
+
return { valid: true, errors: [], data };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const formatValidate = formatInstance.formats.get(schema.format);
|
|
89
|
+
if (!formatValidate) {
|
|
90
|
+
return {
|
|
91
|
+
valid: false,
|
|
92
|
+
errors: [
|
|
93
|
+
new ValidationError(`Unknown format ${schema.format}`, {
|
|
94
|
+
pointer,
|
|
95
|
+
value: data,
|
|
96
|
+
code: "UNKNOWN_FORMAT"
|
|
97
|
+
})
|
|
98
|
+
],
|
|
99
|
+
data
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const valid = formatValidate(data);
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
valid,
|
|
107
|
+
errors: valid
|
|
108
|
+
? []
|
|
109
|
+
: [
|
|
110
|
+
new ValidationError(
|
|
111
|
+
`String does not match format ${schema.format}`,
|
|
112
|
+
{
|
|
113
|
+
pointer,
|
|
114
|
+
value: data,
|
|
115
|
+
code: "STRING_DOES_NOT_MATCH_FORMAT"
|
|
116
|
+
}
|
|
117
|
+
)
|
|
118
|
+
],
|
|
119
|
+
data
|
|
120
|
+
};
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
enum(schema, data, pointer) {
|
|
124
|
+
// Simple equality check
|
|
125
|
+
for (let i = 0; i < schema.enum.length; i++) {
|
|
126
|
+
if (schema.enum[i] === data) {
|
|
127
|
+
return { valid: true, errors: [], data };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// If is an array check for a deep equality
|
|
132
|
+
if (Array.isArray(data)) {
|
|
133
|
+
for (let i = 0; i < schema.enum.length; i++) {
|
|
134
|
+
if (Array.isArray(schema.enum[i])) {
|
|
135
|
+
if (deepEqual(schema.enum[i], data)) {
|
|
136
|
+
return { valid: true, errors: [], data };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// If is an object check for a deep equality
|
|
143
|
+
if (typeof data === "object" && data !== null) {
|
|
144
|
+
for (let i = 0; i < schema.enum.length; i++) {
|
|
145
|
+
if (typeof schema.enum[i] === "object" && schema.enum[i] !== null) {
|
|
146
|
+
if (deepEqual(schema.enum[i], data)) {
|
|
147
|
+
return { valid: true, errors: [], data };
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
valid: false,
|
|
155
|
+
errors: [
|
|
156
|
+
new ValidationError(`Value must be one of ${schema.enum.join(", ")}`, {
|
|
157
|
+
pointer,
|
|
158
|
+
value: data,
|
|
159
|
+
code: "VALUE_NOT_IN_ENUM"
|
|
160
|
+
})
|
|
161
|
+
],
|
|
162
|
+
data
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
};
|