schema-shield 0.0.2 → 0.0.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/LICENSE +201 -0
- package/README.md +761 -6
- package/dist/formats.d.ts +2 -2
- package/dist/formats.d.ts.map +1 -1
- package/dist/index.d.ts +29 -29
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +925 -977
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +925 -977
- package/dist/keywords/array-keywords.d.ts +2 -2
- package/dist/keywords/array-keywords.d.ts.map +1 -1
- package/dist/keywords/number-keywords.d.ts +2 -2
- package/dist/keywords/number-keywords.d.ts.map +1 -1
- package/dist/keywords/object-keywords.d.ts +2 -2
- package/dist/keywords/object-keywords.d.ts.map +1 -1
- package/dist/keywords/other-keywords.d.ts +2 -2
- package/dist/keywords/other-keywords.d.ts.map +1 -1
- package/dist/keywords/string-keywords.d.ts +2 -2
- package/dist/keywords/string-keywords.d.ts.map +1 -1
- package/dist/keywords.d.ts +2 -2
- package/dist/keywords.d.ts.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +23 -7
- package/dist/utils.d.ts.map +1 -1
- package/lib/formats.ts +225 -39
- package/lib/index.ts +199 -225
- package/lib/keywords/array-keywords.ts +138 -146
- package/lib/keywords/number-keywords.ts +78 -62
- package/lib/keywords/object-keywords.ts +199 -144
- package/lib/keywords/other-keywords.ts +137 -195
- package/lib/keywords/string-keywords.ts +24 -137
- package/lib/keywords.ts +2 -2
- package/lib/types.ts +37 -164
- package/lib/utils.ts +106 -28
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -25,24 +25,41 @@ module.exports = __toCommonJS(lib_exports);
|
|
|
25
25
|
|
|
26
26
|
// lib/utils.ts
|
|
27
27
|
var ValidationError = class extends Error {
|
|
28
|
-
name;
|
|
29
|
-
pointer;
|
|
30
28
|
message;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
this.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
this.
|
|
29
|
+
item;
|
|
30
|
+
keyword;
|
|
31
|
+
cause;
|
|
32
|
+
path = "";
|
|
33
|
+
data;
|
|
34
|
+
schema;
|
|
35
|
+
_getCause(pointer = "#") {
|
|
36
|
+
const path = pointer + "/" + this.keyword + (typeof this.item !== "undefined" ? "/" + this.item : "");
|
|
37
|
+
if (!this.cause) {
|
|
38
|
+
this.path = path;
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
return this.cause._getCause(path);
|
|
42
|
+
}
|
|
43
|
+
getCause() {
|
|
44
|
+
return this._getCause();
|
|
44
45
|
}
|
|
45
46
|
};
|
|
47
|
+
function getDefinedErrorFunctionForKey(key, schema) {
|
|
48
|
+
const KeywordError = new ValidationError(`Invalid ${key}`);
|
|
49
|
+
KeywordError.keyword = key;
|
|
50
|
+
KeywordError.schema = schema;
|
|
51
|
+
const defineError = (message, options = {}) => {
|
|
52
|
+
KeywordError.message = message;
|
|
53
|
+
KeywordError.item = options.item;
|
|
54
|
+
KeywordError.cause = options.cause;
|
|
55
|
+
KeywordError.data = options.data;
|
|
56
|
+
return KeywordError;
|
|
57
|
+
};
|
|
58
|
+
return getNamedFunction(
|
|
59
|
+
`defineError_${key}`,
|
|
60
|
+
defineError
|
|
61
|
+
);
|
|
62
|
+
}
|
|
46
63
|
function deepEqual(obj, other) {
|
|
47
64
|
if (Array.isArray(obj) && Array.isArray(other)) {
|
|
48
65
|
if (obj.length !== other.length) {
|
|
@@ -75,571 +92,595 @@ function deepEqual(obj, other) {
|
|
|
75
92
|
function isObject(data) {
|
|
76
93
|
return typeof data === "object" && data !== null && !Array.isArray(data);
|
|
77
94
|
}
|
|
95
|
+
function areCloseEnough(a, b, epsilon = 1e-15) {
|
|
96
|
+
return Math.abs(a - b) <= epsilon * Math.max(Math.abs(a), Math.abs(b));
|
|
97
|
+
}
|
|
98
|
+
function deepClone(obj) {
|
|
99
|
+
if (Array.isArray(obj)) {
|
|
100
|
+
const result = [];
|
|
101
|
+
for (let i = 0; i < obj.length; i++) {
|
|
102
|
+
result[i] = deepClone(obj[i]);
|
|
103
|
+
}
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
if (obj && obj.constructor && obj.constructor.name !== "Object") {
|
|
107
|
+
return obj;
|
|
108
|
+
}
|
|
109
|
+
if (isObject(obj)) {
|
|
110
|
+
const result = {
|
|
111
|
+
...obj
|
|
112
|
+
};
|
|
113
|
+
for (const key in obj) {
|
|
114
|
+
result[key] = deepClone(obj[key]);
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
return obj;
|
|
119
|
+
}
|
|
120
|
+
function isCompiledSchema(subSchema) {
|
|
121
|
+
return isObject(subSchema) && "$validate" in subSchema;
|
|
122
|
+
}
|
|
123
|
+
function getNamedFunction(name, fn) {
|
|
124
|
+
return Object.defineProperty(fn, "name", { value: name });
|
|
125
|
+
}
|
|
78
126
|
|
|
79
127
|
// lib/formats.ts
|
|
80
|
-
var RegExps = {
|
|
81
|
-
"date-time": /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/,
|
|
82
|
-
uri: /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/,
|
|
83
|
-
email: /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
|
|
84
|
-
ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
|
|
85
|
-
ipv6: /^(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(?=(?:[0-9a-fA-F]{0,4}:){0,7}[0-9a-fA-F]{0,4}(?![:.\w]))(([0-9a-fA-F]{1,4}:){1,7}|:)((:[0-9a-fA-F]{1,4}){1,7}|:))$/,
|
|
86
|
-
hostname: /^[a-zA-Z0-9][a-zA-Z0-9-]{0,62}(\.[a-zA-Z0-9][a-zA-Z0-9-]{0,62})*$/
|
|
87
|
-
};
|
|
88
|
-
function notImplementedFormat(data) {
|
|
89
|
-
throw new ValidationError(
|
|
90
|
-
`Format "${data}" is not implemented yet. Please open an issue on GitHub.`
|
|
91
|
-
);
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
128
|
var Formats = {
|
|
95
129
|
["date-time"](data) {
|
|
96
|
-
|
|
130
|
+
const match = data.match(
|
|
131
|
+
/^(\d{4})-(0[0-9]|1[0-2])-(\d{2})T(0[0-9]|1\d|2[0-3]):([0-5]\d):((?:[0-5]\d|60))(?:.\d+)?(?:([+-])(0[0-9]|1\d|2[0-3]):([0-5]\d)|Z)?$/i
|
|
132
|
+
);
|
|
133
|
+
if (!match) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
let day = Number(match[3]);
|
|
137
|
+
if (match[2] === "02" && day > 29) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
const [
|
|
141
|
+
,
|
|
142
|
+
yearStr,
|
|
143
|
+
monthStr,
|
|
144
|
+
,
|
|
145
|
+
hourStr,
|
|
146
|
+
minuteStr,
|
|
147
|
+
secondStr,
|
|
148
|
+
timezoneSign,
|
|
149
|
+
timezoneHourStr,
|
|
150
|
+
timezoneMinuteStr
|
|
151
|
+
] = match;
|
|
152
|
+
let year = Number(yearStr);
|
|
153
|
+
let month = Number(monthStr);
|
|
154
|
+
let hour = Number(hourStr);
|
|
155
|
+
let minute = Number(minuteStr);
|
|
156
|
+
let second = Number(secondStr);
|
|
157
|
+
if (timezoneSign === "-" || timezoneSign === "+") {
|
|
158
|
+
const timezoneHour = Number(timezoneHourStr);
|
|
159
|
+
const timezoneMinute = Number(timezoneMinuteStr);
|
|
160
|
+
if (timezoneSign === "-") {
|
|
161
|
+
hour += timezoneHour;
|
|
162
|
+
minute += timezoneMinute;
|
|
163
|
+
} else if (timezoneSign === "+") {
|
|
164
|
+
hour -= timezoneHour;
|
|
165
|
+
minute -= timezoneMinute;
|
|
166
|
+
}
|
|
167
|
+
if (minute > 59) {
|
|
168
|
+
hour += 1;
|
|
169
|
+
minute -= 60;
|
|
170
|
+
} else if (minute < 0) {
|
|
171
|
+
hour -= 1;
|
|
172
|
+
minute += 60;
|
|
173
|
+
}
|
|
174
|
+
if (hour > 23) {
|
|
175
|
+
day += 1;
|
|
176
|
+
hour -= 24;
|
|
177
|
+
} else if (hour < 0) {
|
|
178
|
+
day -= 1;
|
|
179
|
+
hour += 24;
|
|
180
|
+
}
|
|
181
|
+
if (day > 31) {
|
|
182
|
+
month += 1;
|
|
183
|
+
day -= 31;
|
|
184
|
+
} else if (day < 1) {
|
|
185
|
+
month -= 1;
|
|
186
|
+
day += 31;
|
|
187
|
+
}
|
|
188
|
+
if (month > 12) {
|
|
189
|
+
year += 1;
|
|
190
|
+
month -= 12;
|
|
191
|
+
} else if (month < 1) {
|
|
192
|
+
year -= 1;
|
|
193
|
+
month += 12;
|
|
194
|
+
}
|
|
195
|
+
if (year < 0) {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const daysInMonth = [31, , 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
200
|
+
const maxDays = month === 2 ? year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28 : daysInMonth[month - 1];
|
|
201
|
+
if (day > maxDays) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
if (second === 60 && (minute !== 59 || hour !== 23)) {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
return true;
|
|
97
208
|
},
|
|
98
209
|
uri(data) {
|
|
99
|
-
return
|
|
210
|
+
return /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/.test(data);
|
|
100
211
|
},
|
|
101
212
|
email(data) {
|
|
102
|
-
return
|
|
213
|
+
return /^(?!\.)(?!.*\.$)[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,20}(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]{1,21}){0,2}@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,60}[a-z0-9])?){0,3}$/i.test(
|
|
214
|
+
data
|
|
215
|
+
);
|
|
103
216
|
},
|
|
104
217
|
ipv4(data) {
|
|
105
|
-
return
|
|
218
|
+
return /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])$/.test(
|
|
219
|
+
data
|
|
220
|
+
);
|
|
106
221
|
},
|
|
222
|
+
// ipv6: isMyIpValid({ version: 6 }),
|
|
107
223
|
ipv6(data) {
|
|
108
|
-
|
|
224
|
+
if (data === "::") {
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
if (data.indexOf(":") === -1 || /(?:\s+|:::+|^\w{5,}|\w{5}$|^:{1}\w|\w:{1}$)/.test(data)) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
const hasIpv4 = data.indexOf(".") !== -1;
|
|
231
|
+
let addressParts = data;
|
|
232
|
+
if (hasIpv4) {
|
|
233
|
+
addressParts = data.split(":");
|
|
234
|
+
const ipv4Part = addressParts.pop();
|
|
235
|
+
if (!/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])$/.test(
|
|
236
|
+
ipv4Part
|
|
237
|
+
)) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
const isShortened = data.indexOf("::") !== -1;
|
|
242
|
+
const ipv6Part = hasIpv4 ? addressParts.join(":") : data;
|
|
243
|
+
if (isShortened) {
|
|
244
|
+
if (ipv6Part.split("::").length - 1 > 1) {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
if (!/^[0-9a-fA-F:.]*$/.test(ipv6Part)) {
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
return /^(?:(?:(?:[0-9a-fA-F]{1,4}(?::|$)){1,6}))|(?:::(?:[0-9a-fA-F]{1,4})){0,5}$/.test(
|
|
251
|
+
ipv6Part
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
const isIpv6Valid = /^(?:(?:[0-9a-fA-F]{1,4}:){7}(?:[0-9a-fA-F]{1,4}|:))$/.test(ipv6Part);
|
|
255
|
+
const hasInvalidChar = /(?:[0-9a-fA-F]{5,}|\D[0-9a-fA-F]{3}:)/.test(
|
|
256
|
+
ipv6Part
|
|
257
|
+
);
|
|
258
|
+
if (hasIpv4) {
|
|
259
|
+
return isIpv6Valid || !hasInvalidChar;
|
|
260
|
+
}
|
|
261
|
+
return isIpv6Valid && !hasInvalidChar;
|
|
109
262
|
},
|
|
110
263
|
hostname(data) {
|
|
111
|
-
return
|
|
112
|
-
},
|
|
113
|
-
// Not supported yet
|
|
114
|
-
time: notImplementedFormat,
|
|
115
|
-
date: notImplementedFormat,
|
|
116
|
-
duration: notImplementedFormat,
|
|
117
|
-
"idn-email": notImplementedFormat,
|
|
118
|
-
"idn-hostname": notImplementedFormat,
|
|
119
|
-
uuid: notImplementedFormat,
|
|
120
|
-
"uri-reference": notImplementedFormat,
|
|
121
|
-
iri: notImplementedFormat,
|
|
122
|
-
"iri-reference": notImplementedFormat,
|
|
123
|
-
"uri-template": notImplementedFormat,
|
|
124
|
-
"json-pointer": notImplementedFormat,
|
|
125
|
-
"relative-json-pointer": notImplementedFormat,
|
|
126
|
-
regex: notImplementedFormat
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
// lib/types.ts
|
|
130
|
-
var Types = {
|
|
131
|
-
object(schema, data, pointer) {
|
|
132
|
-
if (typeof data === "object" && data !== null && !Array.isArray(data)) {
|
|
133
|
-
return {
|
|
134
|
-
valid: true,
|
|
135
|
-
errors: [],
|
|
136
|
-
data
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
return {
|
|
140
|
-
valid: false,
|
|
141
|
-
errors: [
|
|
142
|
-
new ValidationError("Data is not an object", {
|
|
143
|
-
pointer,
|
|
144
|
-
value: data,
|
|
145
|
-
code: "NOT_AN_OBJECT"
|
|
146
|
-
})
|
|
147
|
-
],
|
|
264
|
+
return /^[a-z0-9][a-z0-9-]{0,62}(?:\.[a-z0-9][a-z0-9-]{0,62})*[a-z0-9]$/i.test(
|
|
148
265
|
data
|
|
149
|
-
|
|
266
|
+
);
|
|
150
267
|
},
|
|
151
|
-
|
|
152
|
-
if (
|
|
153
|
-
return
|
|
154
|
-
valid: true,
|
|
155
|
-
errors: [],
|
|
156
|
-
data
|
|
157
|
-
};
|
|
268
|
+
date(data) {
|
|
269
|
+
if (/^(\d{4})-(\d{2})-(\d{2})$/.test(data) === false) {
|
|
270
|
+
return false;
|
|
158
271
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
value: data,
|
|
168
|
-
code: "NOT_AN_ARRAY"
|
|
169
|
-
})
|
|
170
|
-
],
|
|
171
|
-
data
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
return {
|
|
175
|
-
valid: true,
|
|
176
|
-
errors: [],
|
|
177
|
-
data
|
|
178
|
-
};
|
|
272
|
+
return !isNaN(new Date(data).getTime());
|
|
273
|
+
},
|
|
274
|
+
regex(data) {
|
|
275
|
+
try {
|
|
276
|
+
new RegExp(data);
|
|
277
|
+
return true;
|
|
278
|
+
} catch (e) {
|
|
279
|
+
return false;
|
|
179
280
|
}
|
|
180
|
-
return {
|
|
181
|
-
valid: false,
|
|
182
|
-
errors: [
|
|
183
|
-
new ValidationError("Data is not an array", {
|
|
184
|
-
pointer,
|
|
185
|
-
value: data,
|
|
186
|
-
code: "NOT_AN_ARRAY"
|
|
187
|
-
})
|
|
188
|
-
],
|
|
189
|
-
data
|
|
190
|
-
};
|
|
191
281
|
},
|
|
192
|
-
|
|
193
|
-
if (
|
|
194
|
-
return
|
|
195
|
-
valid: true,
|
|
196
|
-
errors: [],
|
|
197
|
-
data
|
|
198
|
-
};
|
|
282
|
+
"json-pointer"(data) {
|
|
283
|
+
if (data === "") {
|
|
284
|
+
return true;
|
|
199
285
|
}
|
|
200
|
-
return
|
|
201
|
-
valid: false,
|
|
202
|
-
errors: [
|
|
203
|
-
new ValidationError("Data is not a string", {
|
|
204
|
-
pointer,
|
|
205
|
-
value: data,
|
|
206
|
-
code: "NOT_A_STRING"
|
|
207
|
-
})
|
|
208
|
-
],
|
|
209
|
-
data
|
|
210
|
-
};
|
|
286
|
+
return /^\/(?:[^~]|~0|~1)*$/.test(data);
|
|
211
287
|
},
|
|
212
|
-
|
|
213
|
-
if (
|
|
214
|
-
return
|
|
215
|
-
valid: true,
|
|
216
|
-
errors: [],
|
|
217
|
-
data
|
|
218
|
-
};
|
|
288
|
+
"relative-json-pointer"(data) {
|
|
289
|
+
if (data === "") {
|
|
290
|
+
return true;
|
|
219
291
|
}
|
|
220
|
-
return
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
pointer,
|
|
225
|
-
value: data,
|
|
226
|
-
code: "NOT_A_NUMBER"
|
|
227
|
-
})
|
|
228
|
-
],
|
|
292
|
+
return /^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/.test(data);
|
|
293
|
+
},
|
|
294
|
+
time(data) {
|
|
295
|
+
return /^(\d{2}):(\d{2}):(\d{2})(\.\d+)?(Z|([+-])(\d{2}):(\d{2}))$/.test(
|
|
229
296
|
data
|
|
230
|
-
|
|
297
|
+
);
|
|
231
298
|
},
|
|
232
|
-
|
|
233
|
-
if (
|
|
234
|
-
return
|
|
235
|
-
valid: true,
|
|
236
|
-
errors: [],
|
|
237
|
-
data
|
|
238
|
-
};
|
|
299
|
+
"uri-reference"(data) {
|
|
300
|
+
if (/\\/.test(data)) {
|
|
301
|
+
return false;
|
|
239
302
|
}
|
|
240
|
-
return
|
|
241
|
-
valid: false,
|
|
242
|
-
errors: [
|
|
243
|
-
new ValidationError("Data is not an integer", {
|
|
244
|
-
pointer,
|
|
245
|
-
value: data,
|
|
246
|
-
code: "NOT_AN_INTEGER"
|
|
247
|
-
})
|
|
248
|
-
],
|
|
303
|
+
return /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#((?![^#]*\\)[^#]*))?/i.test(
|
|
249
304
|
data
|
|
250
|
-
|
|
305
|
+
);
|
|
251
306
|
},
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
return {
|
|
255
|
-
valid: true,
|
|
256
|
-
errors: [],
|
|
257
|
-
data
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
return {
|
|
261
|
-
valid: false,
|
|
262
|
-
errors: [
|
|
263
|
-
new ValidationError("Data is not a boolean", {
|
|
264
|
-
pointer,
|
|
265
|
-
value: data,
|
|
266
|
-
code: "NOT_A_BOOLEAN"
|
|
267
|
-
})
|
|
268
|
-
],
|
|
307
|
+
"uri-template"(data) {
|
|
308
|
+
return /^(?:(?:https?:\/\/[\w.-]+)?\/?)?[\w- ;,.\/?%&=]*(?:\{[\w-]+(?::\d+)?\}[\w- ;,.\/?%&=]*)*\/?$/.test(
|
|
269
309
|
data
|
|
270
|
-
|
|
310
|
+
);
|
|
271
311
|
},
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
312
|
+
// Not supported yet
|
|
313
|
+
duration: false,
|
|
314
|
+
uuid: false,
|
|
315
|
+
"idn-email": false,
|
|
316
|
+
"idn-hostname": false,
|
|
317
|
+
iri: false,
|
|
318
|
+
"iri-reference": false
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
// lib/types.ts
|
|
322
|
+
var Types = {
|
|
323
|
+
object(data) {
|
|
324
|
+
return isObject(data);
|
|
325
|
+
},
|
|
326
|
+
array(data) {
|
|
327
|
+
if (Array.isArray(data)) {
|
|
328
|
+
return true;
|
|
279
329
|
}
|
|
280
|
-
return
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
330
|
+
return typeof data === "object" && data !== null && "length" in data && "0" in data && Object.keys(data).length - 1 === data.length;
|
|
331
|
+
},
|
|
332
|
+
string(data) {
|
|
333
|
+
return typeof data === "string";
|
|
334
|
+
},
|
|
335
|
+
number(data) {
|
|
336
|
+
return typeof data === "number";
|
|
337
|
+
},
|
|
338
|
+
integer(data) {
|
|
339
|
+
return typeof data === "number" && data % 1 === 0;
|
|
340
|
+
},
|
|
341
|
+
boolean(data) {
|
|
342
|
+
return typeof data === "boolean";
|
|
343
|
+
},
|
|
344
|
+
null(data) {
|
|
345
|
+
return data === null;
|
|
346
|
+
},
|
|
347
|
+
// Not implemented yet
|
|
348
|
+
timestamp: false,
|
|
349
|
+
int8: false,
|
|
350
|
+
unit8: false,
|
|
351
|
+
int16: false,
|
|
352
|
+
unit16: false,
|
|
353
|
+
int32: false,
|
|
354
|
+
unit32: false,
|
|
355
|
+
float32: false,
|
|
356
|
+
float64: false
|
|
292
357
|
};
|
|
293
358
|
|
|
294
359
|
// lib/keywords/array-keywords.ts
|
|
295
360
|
var ArrayKeywords = {
|
|
296
|
-
items(schema, data,
|
|
361
|
+
items(schema, data, defineError) {
|
|
297
362
|
if (!Array.isArray(data)) {
|
|
298
|
-
return
|
|
299
|
-
}
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
if (
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const schemaItems = schema.items;
|
|
366
|
+
const dataLength = data.length;
|
|
367
|
+
if (typeof schemaItems === "boolean") {
|
|
368
|
+
if (schemaItems === false && dataLength > 0) {
|
|
369
|
+
return defineError("Array items are not allowed", { data });
|
|
370
|
+
}
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
if (Array.isArray(schemaItems)) {
|
|
374
|
+
const schemaItemsLength = schemaItems.length;
|
|
375
|
+
const itemsLength = Math.min(schemaItemsLength, dataLength);
|
|
376
|
+
for (let i = 0; i < itemsLength; i++) {
|
|
377
|
+
const schemaItem = schemaItems[i];
|
|
378
|
+
if (typeof schemaItem === "boolean") {
|
|
379
|
+
if (schemaItem === false && typeof data[i] !== "undefined") {
|
|
380
|
+
return defineError("Array item is not allowed", {
|
|
381
|
+
item: i,
|
|
382
|
+
data: data[i]
|
|
383
|
+
});
|
|
313
384
|
}
|
|
314
385
|
continue;
|
|
315
386
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
);
|
|
326
|
-
finalData[i] = validatorResult.data;
|
|
327
|
-
if (!validatorResult.valid) {
|
|
328
|
-
errors.push(...validatorResult.errors);
|
|
387
|
+
if (isCompiledSchema(schemaItem)) {
|
|
388
|
+
const error = schemaItem.$validate(data[i]);
|
|
389
|
+
if (error) {
|
|
390
|
+
return defineError("Array item is invalid", {
|
|
391
|
+
item: i,
|
|
392
|
+
cause: error,
|
|
393
|
+
data: data[i]
|
|
394
|
+
});
|
|
395
|
+
}
|
|
329
396
|
}
|
|
330
397
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
const { validator } = schema.items;
|
|
343
|
-
if (!validator) {
|
|
344
|
-
return { valid: true, errors: [], data };
|
|
345
|
-
}
|
|
346
|
-
for (let i = 0; i < finalData.length; i++) {
|
|
347
|
-
const validatorErrors = validator(
|
|
348
|
-
schema.items,
|
|
349
|
-
finalData[i],
|
|
350
|
-
`${pointer}/${i}`,
|
|
351
|
-
schemaShieldInstance
|
|
352
|
-
);
|
|
353
|
-
finalData[i] = validatorErrors.data;
|
|
354
|
-
if (!validatorErrors.valid) {
|
|
355
|
-
errors.push(...validatorErrors.errors);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
if (isCompiledSchema(schemaItems)) {
|
|
401
|
+
for (let i = 0; i < dataLength; i++) {
|
|
402
|
+
const error = schemaItems.$validate(data[i]);
|
|
403
|
+
if (error) {
|
|
404
|
+
return defineError("Array item is invalid", {
|
|
405
|
+
item: i,
|
|
406
|
+
cause: error,
|
|
407
|
+
data: data[i]
|
|
408
|
+
});
|
|
356
409
|
}
|
|
357
410
|
}
|
|
358
411
|
}
|
|
359
|
-
return
|
|
412
|
+
return;
|
|
360
413
|
},
|
|
361
|
-
|
|
414
|
+
elements(schema, data, defineError) {
|
|
415
|
+
if (!Array.isArray(data) || !isCompiledSchema(schema.elements)) {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
for (let i = 0; i < data.length; i++) {
|
|
419
|
+
const error = schema.elements.$validate(data[i]);
|
|
420
|
+
if (error) {
|
|
421
|
+
return defineError("Array item is invalid", {
|
|
422
|
+
item: i,
|
|
423
|
+
cause: error,
|
|
424
|
+
data: data[i]
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return;
|
|
429
|
+
},
|
|
430
|
+
minItems(schema, data, defineError) {
|
|
362
431
|
if (!Array.isArray(data) || data.length >= schema.minItems) {
|
|
363
|
-
return
|
|
364
|
-
}
|
|
365
|
-
return {
|
|
366
|
-
valid: false,
|
|
367
|
-
errors: [
|
|
368
|
-
new ValidationError("Array is too short", {
|
|
369
|
-
pointer,
|
|
370
|
-
value: data,
|
|
371
|
-
code: "ARRAY_TOO_SHORT"
|
|
372
|
-
})
|
|
373
|
-
],
|
|
374
|
-
data
|
|
375
|
-
};
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
return defineError("Array is too short", { data });
|
|
376
435
|
},
|
|
377
|
-
maxItems(schema, data,
|
|
436
|
+
maxItems(schema, data, defineError) {
|
|
378
437
|
if (!Array.isArray(data) || data.length <= schema.maxItems) {
|
|
379
|
-
return
|
|
380
|
-
}
|
|
381
|
-
return {
|
|
382
|
-
valid: false,
|
|
383
|
-
errors: [
|
|
384
|
-
new ValidationError("Array is too long", {
|
|
385
|
-
pointer,
|
|
386
|
-
value: data,
|
|
387
|
-
code: "ARRAY_TOO_LONG"
|
|
388
|
-
})
|
|
389
|
-
],
|
|
390
|
-
data
|
|
391
|
-
};
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
return defineError("Array is too long", { data });
|
|
392
441
|
},
|
|
393
|
-
additionalItems(schema, data,
|
|
394
|
-
if (!
|
|
395
|
-
return
|
|
442
|
+
additionalItems(schema, data, defineError) {
|
|
443
|
+
if (!schema.items || isObject(schema.items)) {
|
|
444
|
+
return;
|
|
396
445
|
}
|
|
397
446
|
if (schema.additionalItems === false) {
|
|
398
447
|
if (data.length > schema.items.length) {
|
|
399
|
-
return {
|
|
400
|
-
valid: false,
|
|
401
|
-
errors: [
|
|
402
|
-
new ValidationError("Array has too many items", {
|
|
403
|
-
pointer,
|
|
404
|
-
value: data,
|
|
405
|
-
code: "ARRAY_TOO_MANY_ITEMS"
|
|
406
|
-
})
|
|
407
|
-
],
|
|
408
|
-
data
|
|
409
|
-
};
|
|
448
|
+
return defineError("Array is too long", { data });
|
|
410
449
|
}
|
|
411
|
-
return
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
if (!validatorResult.valid) {
|
|
425
|
-
errors.push(...validatorResult.errors);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
if (isObject(schema.additionalItems)) {
|
|
453
|
+
if (isCompiledSchema(schema.additionalItems)) {
|
|
454
|
+
for (let i = schema.items.length; i < data.length; i++) {
|
|
455
|
+
const error = schema.additionalItems.$validate(data[i]);
|
|
456
|
+
if (error) {
|
|
457
|
+
return defineError("Array item is invalid", {
|
|
458
|
+
item: i,
|
|
459
|
+
cause: error,
|
|
460
|
+
data: data[i]
|
|
461
|
+
});
|
|
462
|
+
}
|
|
426
463
|
}
|
|
427
|
-
|
|
464
|
+
return;
|
|
428
465
|
}
|
|
466
|
+
return;
|
|
429
467
|
}
|
|
430
|
-
return
|
|
468
|
+
return;
|
|
431
469
|
},
|
|
432
|
-
uniqueItems(schema, data,
|
|
470
|
+
uniqueItems(schema, data, defineError) {
|
|
433
471
|
if (!Array.isArray(data) || !schema.uniqueItems) {
|
|
434
|
-
return
|
|
472
|
+
return;
|
|
435
473
|
}
|
|
436
474
|
const unique = /* @__PURE__ */ new Set();
|
|
437
475
|
for (const item of data) {
|
|
438
|
-
let itemStr
|
|
476
|
+
let itemStr;
|
|
439
477
|
if (typeof item === "string") {
|
|
440
|
-
itemStr = `
|
|
478
|
+
itemStr = `s:${item}`;
|
|
441
479
|
} else if (isObject(item)) {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
}
|
|
447
|
-
itemStr = JSON.stringify(sorted);
|
|
480
|
+
itemStr = `o:${JSON.stringify(
|
|
481
|
+
Object.fromEntries(
|
|
482
|
+
Object.entries(item).sort(([a], [b]) => a.localeCompare(b))
|
|
483
|
+
)
|
|
484
|
+
)}`;
|
|
448
485
|
} else if (Array.isArray(item)) {
|
|
449
486
|
itemStr = JSON.stringify(item);
|
|
487
|
+
} else {
|
|
488
|
+
itemStr = String(item);
|
|
450
489
|
}
|
|
451
490
|
if (unique.has(itemStr)) {
|
|
452
|
-
return {
|
|
453
|
-
valid: false,
|
|
454
|
-
errors: [
|
|
455
|
-
new ValidationError("Array items are not unique", {
|
|
456
|
-
pointer,
|
|
457
|
-
value: data,
|
|
458
|
-
code: "ARRAY_ITEMS_NOT_UNIQUE"
|
|
459
|
-
})
|
|
460
|
-
],
|
|
461
|
-
data
|
|
462
|
-
};
|
|
463
|
-
} else {
|
|
464
|
-
unique.add(itemStr);
|
|
491
|
+
return defineError("Array items are not unique", { data: item });
|
|
465
492
|
}
|
|
493
|
+
unique.add(itemStr);
|
|
494
|
+
}
|
|
495
|
+
return;
|
|
496
|
+
},
|
|
497
|
+
contains(schema, data, defineError) {
|
|
498
|
+
if (!Array.isArray(data)) {
|
|
499
|
+
return;
|
|
466
500
|
}
|
|
467
|
-
|
|
501
|
+
if (typeof schema.contains === "boolean") {
|
|
502
|
+
if (schema.contains) {
|
|
503
|
+
if (data.length === 0) {
|
|
504
|
+
return defineError("Array must contain at least one item", { data });
|
|
505
|
+
}
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
return defineError("Array must not contain any items", { data });
|
|
509
|
+
}
|
|
510
|
+
for (let i = 0; i < data.length; i++) {
|
|
511
|
+
const error = schema.contains.$validate(data[i]);
|
|
512
|
+
if (!error) {
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
return defineError("Array must contain at least one item", { data });
|
|
468
518
|
}
|
|
469
519
|
};
|
|
470
520
|
|
|
471
521
|
// lib/keywords/number-keywords.ts
|
|
472
522
|
var NumberKeywords = {
|
|
473
|
-
minimum(schema, data,
|
|
523
|
+
minimum(schema, data, defineError, instance) {
|
|
474
524
|
if (typeof data !== "number") {
|
|
475
|
-
return
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
],
|
|
488
|
-
data
|
|
489
|
-
};
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
let min = schema.minimum;
|
|
528
|
+
if (typeof schema.exclusiveMinimum === "number") {
|
|
529
|
+
min = schema.exclusiveMinimum + 1e-15;
|
|
530
|
+
} else if (schema.exclusiveMinimum === true) {
|
|
531
|
+
min += 1e-15;
|
|
532
|
+
}
|
|
533
|
+
if (data < min) {
|
|
534
|
+
return defineError("Value is less than the minimum", { data });
|
|
535
|
+
}
|
|
536
|
+
return;
|
|
490
537
|
},
|
|
491
|
-
maximum(schema, data,
|
|
538
|
+
maximum(schema, data, defineError, instance) {
|
|
492
539
|
if (typeof data !== "number") {
|
|
493
|
-
return
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
],
|
|
506
|
-
data
|
|
507
|
-
};
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
let max = schema.maximum;
|
|
543
|
+
if (typeof schema.exclusiveMaximum === "number") {
|
|
544
|
+
max = schema.exclusiveMaximum - 1e-15;
|
|
545
|
+
} else if (schema.exclusiveMaximum === true) {
|
|
546
|
+
max -= 1e-15;
|
|
547
|
+
}
|
|
548
|
+
if (data > max) {
|
|
549
|
+
return defineError("Value is greater than the maximum", { data });
|
|
550
|
+
}
|
|
551
|
+
return;
|
|
508
552
|
},
|
|
509
|
-
multipleOf(schema, data,
|
|
553
|
+
multipleOf(schema, data, defineError, instance) {
|
|
510
554
|
if (typeof data !== "number") {
|
|
511
|
-
return
|
|
555
|
+
return;
|
|
512
556
|
}
|
|
513
557
|
const quotient = data / schema.multipleOf;
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
}
|
|
558
|
+
if (!isFinite(quotient)) {
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
if (!areCloseEnough(quotient, Math.round(quotient))) {
|
|
562
|
+
return defineError("Value is not a multiple of the multipleOf", { data });
|
|
563
|
+
}
|
|
564
|
+
return;
|
|
565
|
+
},
|
|
566
|
+
exclusiveMinimum(schema, data, defineError, instance) {
|
|
567
|
+
if (typeof data !== "number" || typeof schema.exclusiveMinimum !== "number" || "minimum" in schema) {
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
if (data <= schema.exclusiveMinimum + 1e-15) {
|
|
571
|
+
return defineError("Value is less than or equal to the exclusiveMinimum");
|
|
572
|
+
}
|
|
573
|
+
return;
|
|
574
|
+
},
|
|
575
|
+
exclusiveMaximum(schema, data, defineError, instance) {
|
|
576
|
+
if (typeof data !== "number" || typeof schema.exclusiveMaximum !== "number" || "maximum" in schema) {
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
if (data >= schema.exclusiveMaximum) {
|
|
580
|
+
return defineError(
|
|
581
|
+
"Value is greater than or equal to the exclusiveMaximum",
|
|
582
|
+
{ data }
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
return;
|
|
526
586
|
}
|
|
527
587
|
};
|
|
528
588
|
|
|
529
589
|
// lib/keywords/object-keywords.ts
|
|
530
590
|
var ObjectKeywords = {
|
|
531
591
|
// Object
|
|
532
|
-
required(schema, data,
|
|
592
|
+
required(schema, data, defineError) {
|
|
533
593
|
if (!isObject(data)) {
|
|
534
|
-
return
|
|
535
|
-
valid: true,
|
|
536
|
-
errors: [],
|
|
537
|
-
data
|
|
538
|
-
};
|
|
594
|
+
return;
|
|
539
595
|
}
|
|
540
|
-
const errors = [];
|
|
541
596
|
for (let i = 0; i < schema.required.length; i++) {
|
|
542
597
|
const key = schema.required[i];
|
|
543
598
|
if (!data.hasOwnProperty(key)) {
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
code: "MISSING_REQUIRED_PROPERTY"
|
|
549
|
-
})
|
|
550
|
-
);
|
|
599
|
+
return defineError("Required property is missing", {
|
|
600
|
+
item: key,
|
|
601
|
+
data: data[key]
|
|
602
|
+
});
|
|
551
603
|
}
|
|
552
604
|
}
|
|
553
|
-
return
|
|
605
|
+
return;
|
|
554
606
|
},
|
|
555
|
-
properties(schema, data,
|
|
607
|
+
properties(schema, data, defineError) {
|
|
556
608
|
if (!isObject(data)) {
|
|
557
|
-
return
|
|
558
|
-
}
|
|
559
|
-
const
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
finalData[key] = schema.properties[key].default;
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
for (const key of Object.keys(schema.properties)) {
|
|
612
|
+
if (!data.hasOwnProperty(key)) {
|
|
613
|
+
const schemaProp = schema.properties[key];
|
|
614
|
+
if (isObject(schemaProp) && "default" in schemaProp) {
|
|
615
|
+
data[key] = schemaProp.default;
|
|
565
616
|
}
|
|
566
617
|
continue;
|
|
567
618
|
}
|
|
568
619
|
if (typeof schema.properties[key] === "boolean") {
|
|
569
620
|
if (schema.properties[key] === false) {
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
code: "PROPERTY_NOT_ALLOWED"
|
|
575
|
-
})
|
|
576
|
-
);
|
|
621
|
+
return defineError("Property is not allowed", {
|
|
622
|
+
item: key,
|
|
623
|
+
data: data[key]
|
|
624
|
+
});
|
|
577
625
|
}
|
|
578
626
|
continue;
|
|
579
627
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
628
|
+
if ("$validate" in schema.properties[key]) {
|
|
629
|
+
const error = schema.properties[key].$validate(data[key]);
|
|
630
|
+
if (error) {
|
|
631
|
+
return defineError("Property is invalid", {
|
|
632
|
+
item: key,
|
|
633
|
+
cause: error,
|
|
634
|
+
data: data[key]
|
|
635
|
+
});
|
|
636
|
+
}
|
|
583
637
|
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
638
|
+
}
|
|
639
|
+
return;
|
|
640
|
+
},
|
|
641
|
+
values(schema, data, defineError) {
|
|
642
|
+
if (!isObject(data) || !isCompiledSchema(schema.values)) {
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
const keys = Object.keys(data);
|
|
646
|
+
for (const key of keys) {
|
|
647
|
+
const error = schema.values.$validate(data[key]);
|
|
648
|
+
if (error) {
|
|
649
|
+
return defineError("Property is invalid", {
|
|
650
|
+
item: key,
|
|
651
|
+
cause: error,
|
|
652
|
+
data: data[key]
|
|
653
|
+
});
|
|
593
654
|
}
|
|
594
655
|
}
|
|
595
|
-
return
|
|
656
|
+
return;
|
|
596
657
|
},
|
|
597
|
-
maxProperties(schema, data,
|
|
658
|
+
maxProperties(schema, data, defineError) {
|
|
598
659
|
if (!isObject(data) || Object.keys(data).length <= schema.maxProperties) {
|
|
599
|
-
return
|
|
600
|
-
}
|
|
601
|
-
return {
|
|
602
|
-
valid: false,
|
|
603
|
-
errors: [
|
|
604
|
-
new ValidationError("Object has too many properties", {
|
|
605
|
-
pointer,
|
|
606
|
-
value: data,
|
|
607
|
-
code: "OBJECT_TOO_MANY_PROPERTIES"
|
|
608
|
-
})
|
|
609
|
-
],
|
|
610
|
-
data
|
|
611
|
-
};
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
return defineError("Too many properties", { data });
|
|
612
663
|
},
|
|
613
|
-
minProperties(schema, data,
|
|
664
|
+
minProperties(schema, data, defineError) {
|
|
614
665
|
if (!isObject(data) || Object.keys(data).length >= schema.minProperties) {
|
|
615
|
-
return
|
|
616
|
-
}
|
|
617
|
-
return {
|
|
618
|
-
valid: false,
|
|
619
|
-
errors: [
|
|
620
|
-
new ValidationError("Object has too few properties", {
|
|
621
|
-
pointer,
|
|
622
|
-
value: data,
|
|
623
|
-
code: "OBJECT_TOO_FEW_PROPERTIES"
|
|
624
|
-
})
|
|
625
|
-
],
|
|
626
|
-
data
|
|
627
|
-
};
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
return defineError("Too few properties", { data });
|
|
628
669
|
},
|
|
629
|
-
additionalProperties(schema, data,
|
|
670
|
+
additionalProperties(schema, data, defineError) {
|
|
630
671
|
if (!isObject(data)) {
|
|
631
|
-
return
|
|
672
|
+
return;
|
|
632
673
|
}
|
|
633
|
-
const
|
|
634
|
-
|
|
635
|
-
for (
|
|
674
|
+
const keys = Object.keys(data);
|
|
675
|
+
const isCompiled = isCompiledSchema(schema.additionalProperties);
|
|
676
|
+
for (const key of keys) {
|
|
636
677
|
if (schema.properties && schema.properties.hasOwnProperty(key)) {
|
|
637
678
|
continue;
|
|
638
679
|
}
|
|
639
680
|
if (schema.patternProperties) {
|
|
640
681
|
let match = false;
|
|
641
|
-
for (
|
|
642
|
-
if (new RegExp(pattern).test(key)) {
|
|
682
|
+
for (const pattern in schema.patternProperties) {
|
|
683
|
+
if (new RegExp(pattern, "u").test(key)) {
|
|
643
684
|
match = true;
|
|
644
685
|
break;
|
|
645
686
|
}
|
|
@@ -649,436 +690,340 @@ var ObjectKeywords = {
|
|
|
649
690
|
}
|
|
650
691
|
}
|
|
651
692
|
if (schema.additionalProperties === false) {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
code: "ADDITIONAL_PROPERTY_NOT_ALLOWED"
|
|
657
|
-
})
|
|
658
|
-
);
|
|
659
|
-
continue;
|
|
693
|
+
return defineError("Additional properties are not allowed", {
|
|
694
|
+
item: key,
|
|
695
|
+
data: data[key]
|
|
696
|
+
});
|
|
660
697
|
}
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
);
|
|
671
|
-
finalData[key] = validatorResult.data;
|
|
672
|
-
if (!validatorResult.valid) {
|
|
673
|
-
errors.push(...validatorResult.errors);
|
|
698
|
+
if (isCompiled) {
|
|
699
|
+
const error = schema.additionalProperties.$validate(data[key]);
|
|
700
|
+
if (error) {
|
|
701
|
+
return defineError("Additional properties are invalid", {
|
|
702
|
+
item: key,
|
|
703
|
+
cause: error,
|
|
704
|
+
data: data[key]
|
|
705
|
+
});
|
|
706
|
+
}
|
|
674
707
|
}
|
|
675
708
|
}
|
|
676
|
-
return
|
|
709
|
+
return;
|
|
677
710
|
},
|
|
678
|
-
patternProperties(schema, data,
|
|
711
|
+
patternProperties(schema, data, defineError) {
|
|
679
712
|
if (!isObject(data)) {
|
|
680
|
-
return
|
|
713
|
+
return;
|
|
681
714
|
}
|
|
682
|
-
const
|
|
683
|
-
|
|
684
|
-
|
|
715
|
+
const patterns = Object.keys(schema.patternProperties);
|
|
716
|
+
for (const pattern of patterns) {
|
|
717
|
+
const regex = new RegExp(pattern, "u");
|
|
685
718
|
if (typeof schema.patternProperties[pattern] === "boolean") {
|
|
686
719
|
if (schema.patternProperties[pattern] === false) {
|
|
687
|
-
for (
|
|
688
|
-
if (
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
code: "PROPERTY_NOT_ALLOWED"
|
|
694
|
-
})
|
|
695
|
-
);
|
|
720
|
+
for (const key in data) {
|
|
721
|
+
if (regex.test(key)) {
|
|
722
|
+
return defineError("Property is not allowed", {
|
|
723
|
+
item: key,
|
|
724
|
+
data: data[key]
|
|
725
|
+
});
|
|
696
726
|
}
|
|
697
727
|
}
|
|
698
728
|
}
|
|
699
729
|
continue;
|
|
700
730
|
}
|
|
701
|
-
const
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
errors.push(...validatorResult.errors);
|
|
731
|
+
const keys = Object.keys(data);
|
|
732
|
+
for (const key of keys) {
|
|
733
|
+
if (regex.test(key)) {
|
|
734
|
+
if ("$validate" in schema.patternProperties[pattern]) {
|
|
735
|
+
const error = schema.patternProperties[pattern].$validate(
|
|
736
|
+
data[key]
|
|
737
|
+
);
|
|
738
|
+
if (error) {
|
|
739
|
+
return defineError("Property is invalid", {
|
|
740
|
+
item: key,
|
|
741
|
+
cause: error,
|
|
742
|
+
data: data[key]
|
|
743
|
+
});
|
|
744
|
+
}
|
|
716
745
|
}
|
|
717
746
|
}
|
|
718
747
|
}
|
|
719
748
|
}
|
|
720
|
-
return
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
749
|
+
return;
|
|
750
|
+
},
|
|
751
|
+
propertyNames(schema, data, defineError) {
|
|
752
|
+
if (!isObject(data)) {
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
if (typeof schema.propertyNames === "boolean") {
|
|
756
|
+
if (schema.propertyNames === false && Object.keys(data).length > 0) {
|
|
757
|
+
return defineError("Properties are not allowed", { data });
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
if (isCompiledSchema(schema.propertyNames)) {
|
|
761
|
+
for (let key in data) {
|
|
762
|
+
const error = schema.propertyNames.$validate(key);
|
|
763
|
+
if (error) {
|
|
764
|
+
return defineError("Property name is invalid", {
|
|
765
|
+
item: key,
|
|
766
|
+
cause: error,
|
|
767
|
+
data: data[key]
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
}
|
|
739
771
|
}
|
|
740
|
-
return
|
|
772
|
+
return;
|
|
741
773
|
},
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
for (
|
|
747
|
-
if (
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
774
|
+
dependencies(schema, data, defineError) {
|
|
775
|
+
if (!isObject(data)) {
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
for (const key in schema.dependencies) {
|
|
779
|
+
if (key in data === false) {
|
|
780
|
+
continue;
|
|
781
|
+
}
|
|
782
|
+
const dependency = schema.dependencies[key];
|
|
783
|
+
if (Array.isArray(dependency)) {
|
|
784
|
+
for (let i = 0; i < dependency.length; i++) {
|
|
785
|
+
if (!(dependency[i] in data)) {
|
|
786
|
+
return defineError("Dependency is not satisfied", {
|
|
787
|
+
item: i,
|
|
788
|
+
data: dependency[i]
|
|
789
|
+
});
|
|
790
|
+
}
|
|
752
791
|
}
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
);
|
|
759
|
-
if (validationResult.valid) {
|
|
760
|
-
validCount++;
|
|
761
|
-
} else {
|
|
762
|
-
errors.push(...validationResult.errors);
|
|
792
|
+
continue;
|
|
793
|
+
}
|
|
794
|
+
if (typeof dependency === "boolean") {
|
|
795
|
+
if (dependency) {
|
|
796
|
+
continue;
|
|
763
797
|
}
|
|
764
|
-
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
validCount++;
|
|
769
|
-
}
|
|
798
|
+
return defineError("Dependency is not satisfied", { data: dependency });
|
|
799
|
+
}
|
|
800
|
+
if (typeof dependency === "string") {
|
|
801
|
+
if (dependency in data) {
|
|
770
802
|
continue;
|
|
771
803
|
}
|
|
772
|
-
|
|
773
|
-
|
|
804
|
+
return defineError("Dependency is not satisfied", { data: dependency });
|
|
805
|
+
}
|
|
806
|
+
const error = dependency.$validate(data);
|
|
807
|
+
if (error) {
|
|
808
|
+
return defineError("Dependency is not satisfied", {
|
|
809
|
+
cause: error,
|
|
810
|
+
data
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
return;
|
|
815
|
+
},
|
|
816
|
+
// Required by other keywords but not used as a function itself
|
|
817
|
+
then: false,
|
|
818
|
+
else: false,
|
|
819
|
+
default: false,
|
|
820
|
+
// Not implemented yet
|
|
821
|
+
$ref: false,
|
|
822
|
+
definitions: false,
|
|
823
|
+
$id: false,
|
|
824
|
+
$schema: false,
|
|
825
|
+
// Metadata keywords (not used as a function)
|
|
826
|
+
title: false,
|
|
827
|
+
description: false,
|
|
828
|
+
$comment: false,
|
|
829
|
+
examples: false,
|
|
830
|
+
contentMediaType: false,
|
|
831
|
+
contentEncoding: false,
|
|
832
|
+
// Not supported Open API keywords
|
|
833
|
+
discriminator: false,
|
|
834
|
+
nullable: false
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
// lib/keywords/other-keywords.ts
|
|
838
|
+
var OtherKeywords = {
|
|
839
|
+
enum(schema, data, defineError) {
|
|
840
|
+
const isArray = Array.isArray(data);
|
|
841
|
+
const isObject2 = typeof data === "object" && data !== null;
|
|
842
|
+
for (let i = 0; i < schema.enum.length; i++) {
|
|
843
|
+
const enumItem = schema.enum[i];
|
|
844
|
+
if (enumItem === data) {
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
if (isArray && Array.isArray(enumItem) || isObject2 && typeof enumItem === "object" && enumItem !== null) {
|
|
848
|
+
if (deepEqual(enumItem, data)) {
|
|
849
|
+
return;
|
|
774
850
|
}
|
|
775
851
|
}
|
|
776
852
|
}
|
|
777
|
-
|
|
778
|
-
return { valid: true, errors: [], data: finalData };
|
|
779
|
-
}
|
|
780
|
-
return {
|
|
781
|
-
valid: false,
|
|
782
|
-
errors: [
|
|
783
|
-
new ValidationError(`Value must match exactly one schema in oneOf`, {
|
|
784
|
-
pointer,
|
|
785
|
-
value: data,
|
|
786
|
-
code: "VALUE_DOES_NOT_MATCH_ONE_OF"
|
|
787
|
-
})
|
|
788
|
-
],
|
|
789
|
-
data: finalData
|
|
790
|
-
};
|
|
853
|
+
return defineError("Value is not one of the allowed values", { data });
|
|
791
854
|
},
|
|
792
|
-
allOf(schema, data,
|
|
793
|
-
const errors = [];
|
|
794
|
-
let finalData = data;
|
|
855
|
+
allOf(schema, data, defineError) {
|
|
795
856
|
for (let i = 0; i < schema.allOf.length; i++) {
|
|
796
857
|
if (isObject(schema.allOf[i])) {
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
const validatorResult = validator(
|
|
802
|
-
schema.allOf[i],
|
|
803
|
-
finalData,
|
|
804
|
-
pointer,
|
|
805
|
-
schemaShieldInstance
|
|
806
|
-
);
|
|
807
|
-
if (!validatorResult.valid) {
|
|
808
|
-
errors.push(...validatorResult.errors);
|
|
809
|
-
}
|
|
810
|
-
finalData = validatorResult.data;
|
|
811
|
-
} else {
|
|
812
|
-
if (typeof schema.allOf[i] === "boolean") {
|
|
813
|
-
if (Boolean(data) !== schema.allOf[i]) {
|
|
814
|
-
errors.push(
|
|
815
|
-
new ValidationError(`Value must match all schemas in allOf`, {
|
|
816
|
-
pointer,
|
|
817
|
-
value: data,
|
|
818
|
-
code: "VALUE_DOES_NOT_MATCH_ALL_OF"
|
|
819
|
-
})
|
|
820
|
-
);
|
|
858
|
+
if ("$validate" in schema.allOf[i]) {
|
|
859
|
+
const error = schema.allOf[i].$validate(data);
|
|
860
|
+
if (error) {
|
|
861
|
+
return defineError("Value is not valid", { cause: error, data });
|
|
821
862
|
}
|
|
822
|
-
continue;
|
|
823
863
|
}
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
code: "VALUE_DOES_NOT_MATCH_ALL_OF"
|
|
830
|
-
})
|
|
831
|
-
);
|
|
864
|
+
continue;
|
|
865
|
+
}
|
|
866
|
+
if (typeof schema.allOf[i] === "boolean") {
|
|
867
|
+
if (Boolean(data) !== schema.allOf[i]) {
|
|
868
|
+
return defineError("Value is not valid", { data });
|
|
832
869
|
}
|
|
870
|
+
continue;
|
|
871
|
+
}
|
|
872
|
+
if (data !== schema.allOf[i]) {
|
|
873
|
+
return defineError("Value is not valid", { data });
|
|
833
874
|
}
|
|
834
875
|
}
|
|
835
|
-
return
|
|
876
|
+
return;
|
|
836
877
|
},
|
|
837
|
-
anyOf(schema, data,
|
|
838
|
-
let finalData = data;
|
|
878
|
+
anyOf(schema, data, defineError) {
|
|
839
879
|
for (let i = 0; i < schema.anyOf.length; i++) {
|
|
840
880
|
if (isObject(schema.anyOf[i])) {
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
finalData,
|
|
848
|
-
pointer,
|
|
849
|
-
schemaShieldInstance
|
|
850
|
-
);
|
|
851
|
-
finalData = validationResult.data;
|
|
852
|
-
if (validationResult.valid) {
|
|
853
|
-
return { valid: true, errors: [], data: finalData };
|
|
881
|
+
if ("$validate" in schema.anyOf[i]) {
|
|
882
|
+
const error = schema.anyOf[i].$validate(data);
|
|
883
|
+
if (!error) {
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
continue;
|
|
854
887
|
}
|
|
888
|
+
return;
|
|
855
889
|
} else {
|
|
856
890
|
if (typeof schema.anyOf[i] === "boolean") {
|
|
857
891
|
if (Boolean(data) === schema.anyOf[i]) {
|
|
858
|
-
return
|
|
892
|
+
return;
|
|
859
893
|
}
|
|
860
894
|
}
|
|
861
895
|
if (data === schema.anyOf[i]) {
|
|
862
|
-
return
|
|
896
|
+
return;
|
|
863
897
|
}
|
|
864
898
|
}
|
|
865
899
|
}
|
|
866
|
-
return {
|
|
867
|
-
valid: false,
|
|
868
|
-
errors: [
|
|
869
|
-
new ValidationError(`Value must match at least one schema in anyOf`, {
|
|
870
|
-
pointer,
|
|
871
|
-
value: data,
|
|
872
|
-
code: "VALUE_DOES_NOT_MATCH_ANY_OF"
|
|
873
|
-
})
|
|
874
|
-
],
|
|
875
|
-
data
|
|
876
|
-
};
|
|
900
|
+
return defineError("Value is not valid", { data });
|
|
877
901
|
},
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
continue;
|
|
887
|
-
}
|
|
888
|
-
const dependency = schema.dependencies[key];
|
|
889
|
-
if (Array.isArray(dependency)) {
|
|
890
|
-
for (let i = 0; i < dependency.length; i++) {
|
|
891
|
-
if (!(dependency[i] in data)) {
|
|
892
|
-
errors.push(
|
|
893
|
-
new ValidationError(`Dependency ${dependency[i]} is missing`, {
|
|
894
|
-
pointer,
|
|
895
|
-
value: data,
|
|
896
|
-
code: "DEPENDENCY_MISSING"
|
|
897
|
-
})
|
|
898
|
-
);
|
|
902
|
+
oneOf(schema, data, defineError) {
|
|
903
|
+
let validCount = 0;
|
|
904
|
+
for (let i = 0; i < schema.oneOf.length; i++) {
|
|
905
|
+
if (isObject(schema.oneOf[i])) {
|
|
906
|
+
if ("$validate" in schema.oneOf[i]) {
|
|
907
|
+
const error = schema.oneOf[i].$validate(data);
|
|
908
|
+
if (!error) {
|
|
909
|
+
validCount++;
|
|
899
910
|
}
|
|
911
|
+
continue;
|
|
900
912
|
}
|
|
913
|
+
validCount++;
|
|
901
914
|
continue;
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
|
|
915
|
+
} else {
|
|
916
|
+
if (typeof schema.oneOf[i] === "boolean") {
|
|
917
|
+
if (Boolean(data) === schema.oneOf[i]) {
|
|
918
|
+
validCount++;
|
|
919
|
+
}
|
|
905
920
|
continue;
|
|
906
921
|
}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
value: data,
|
|
911
|
-
code: "DEPENDENCY_MISSING"
|
|
912
|
-
})
|
|
913
|
-
);
|
|
914
|
-
continue;
|
|
922
|
+
if (data === schema.oneOf[i]) {
|
|
923
|
+
validCount++;
|
|
924
|
+
}
|
|
915
925
|
}
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
926
|
+
}
|
|
927
|
+
if (validCount === 1) {
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
return defineError("Value is not valid", { data });
|
|
931
|
+
},
|
|
932
|
+
const(schema, data, defineError) {
|
|
933
|
+
if (data === schema.const || isObject(data) && isObject(schema.const) && deepEqual(data, schema.const) || Array.isArray(data) && Array.isArray(schema.const) && deepEqual(data, schema.const)) {
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
return defineError("Value is not valid", { data });
|
|
937
|
+
},
|
|
938
|
+
if(schema, data, defineError) {
|
|
939
|
+
if ("then" in schema === false && "else" in schema === false) {
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
if (typeof schema.if === "boolean") {
|
|
943
|
+
if (schema.if) {
|
|
944
|
+
if (isCompiledSchema(schema.then)) {
|
|
945
|
+
return schema.then.$validate(data);
|
|
919
946
|
}
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
pointer,
|
|
923
|
-
value: data,
|
|
924
|
-
code: "DEPENDENCY_MISSING"
|
|
925
|
-
})
|
|
926
|
-
);
|
|
927
|
-
continue;
|
|
947
|
+
} else if (isCompiledSchema(schema.else)) {
|
|
948
|
+
return schema.else.$validate(data);
|
|
928
949
|
}
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
if (!isCompiledSchema(schema.if)) {
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
955
|
+
const error = schema.if.$validate(data);
|
|
956
|
+
if (!error) {
|
|
957
|
+
if (isCompiledSchema(schema.then)) {
|
|
958
|
+
return schema.then.$validate(data);
|
|
932
959
|
}
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
schemaShieldInstance
|
|
938
|
-
);
|
|
939
|
-
if (!validatorResult.valid) {
|
|
940
|
-
errors.push(...validatorResult.errors);
|
|
960
|
+
return;
|
|
961
|
+
} else {
|
|
962
|
+
if (isCompiledSchema(schema.else)) {
|
|
963
|
+
return schema.else.$validate(data);
|
|
941
964
|
}
|
|
942
|
-
|
|
965
|
+
return;
|
|
943
966
|
}
|
|
944
|
-
|
|
967
|
+
},
|
|
968
|
+
not(schema, data, defineError) {
|
|
969
|
+
if (typeof schema.not === "boolean") {
|
|
970
|
+
if (schema.not) {
|
|
971
|
+
return defineError("Value is not valid", { data });
|
|
972
|
+
}
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
if (isObject(schema.not)) {
|
|
976
|
+
if ("$validate" in schema.not) {
|
|
977
|
+
const error = schema.not.$validate(data);
|
|
978
|
+
if (!error) {
|
|
979
|
+
return defineError("Value is not valid", { cause: error, data });
|
|
980
|
+
}
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
return defineError("Value is not valid", { data });
|
|
984
|
+
}
|
|
985
|
+
return defineError("Value is not valid", { data });
|
|
945
986
|
}
|
|
946
987
|
};
|
|
947
988
|
|
|
948
989
|
// lib/keywords/string-keywords.ts
|
|
949
990
|
var StringKeywords = {
|
|
950
|
-
minLength(schema, data,
|
|
991
|
+
minLength(schema, data, defineError) {
|
|
951
992
|
if (typeof data !== "string" || data.length >= schema.minLength) {
|
|
952
|
-
return
|
|
953
|
-
}
|
|
954
|
-
return {
|
|
955
|
-
valid: false,
|
|
956
|
-
errors: [
|
|
957
|
-
new ValidationError("String is too short", {
|
|
958
|
-
pointer,
|
|
959
|
-
value: data,
|
|
960
|
-
code: "STRING_TOO_SHORT"
|
|
961
|
-
})
|
|
962
|
-
],
|
|
963
|
-
data
|
|
964
|
-
};
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
return defineError("Value is shorter than the minimum length", { data });
|
|
965
996
|
},
|
|
966
|
-
maxLength(schema, data,
|
|
997
|
+
maxLength(schema, data, defineError) {
|
|
967
998
|
if (typeof data !== "string" || data.length <= schema.maxLength) {
|
|
968
|
-
return
|
|
969
|
-
}
|
|
970
|
-
return {
|
|
971
|
-
valid: false,
|
|
972
|
-
errors: [
|
|
973
|
-
new ValidationError("String is too long", {
|
|
974
|
-
pointer,
|
|
975
|
-
value: data,
|
|
976
|
-
code: "STRING_TOO_LONG"
|
|
977
|
-
})
|
|
978
|
-
],
|
|
979
|
-
data
|
|
980
|
-
};
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
return defineError("Value is longer than the maximum length", { data });
|
|
981
1002
|
},
|
|
982
|
-
pattern(schema, data,
|
|
1003
|
+
pattern(schema, data, defineError) {
|
|
983
1004
|
if (typeof data !== "string") {
|
|
984
|
-
return
|
|
1005
|
+
return;
|
|
985
1006
|
}
|
|
986
|
-
const patternRegexp =
|
|
1007
|
+
const patternRegexp = new RegExp(schema.pattern, "u");
|
|
987
1008
|
if (patternRegexp instanceof RegExp === false) {
|
|
988
|
-
return {
|
|
989
|
-
valid: false,
|
|
990
|
-
errors: [
|
|
991
|
-
new ValidationError("Pattern is not a valid regular expression", {
|
|
992
|
-
pointer,
|
|
993
|
-
value: data,
|
|
994
|
-
code: "PATTERN_IS_NOT_REGEXP"
|
|
995
|
-
})
|
|
996
|
-
],
|
|
997
|
-
data
|
|
998
|
-
};
|
|
999
|
-
}
|
|
1000
|
-
const valid = patternRegexp.test(data);
|
|
1001
|
-
return {
|
|
1002
|
-
valid,
|
|
1003
|
-
errors: valid ? [] : [
|
|
1004
|
-
new ValidationError("String does not match pattern", {
|
|
1005
|
-
pointer,
|
|
1006
|
-
value: data,
|
|
1007
|
-
code: "STRING_DOES_NOT_MATCH_PATTERN"
|
|
1008
|
-
})
|
|
1009
|
-
],
|
|
1010
|
-
data
|
|
1011
|
-
};
|
|
1012
|
-
},
|
|
1013
|
-
format(schema, data, pointer, formatInstance) {
|
|
1014
|
-
if (typeof data !== "string") {
|
|
1015
|
-
return { valid: true, errors: [], data };
|
|
1009
|
+
return defineError("Invalid regular expression", { data });
|
|
1016
1010
|
}
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
return {
|
|
1020
|
-
valid: false,
|
|
1021
|
-
errors: [
|
|
1022
|
-
new ValidationError(`Unknown format ${schema.format}`, {
|
|
1023
|
-
pointer,
|
|
1024
|
-
value: data,
|
|
1025
|
-
code: "UNKNOWN_FORMAT"
|
|
1026
|
-
})
|
|
1027
|
-
],
|
|
1028
|
-
data
|
|
1029
|
-
};
|
|
1011
|
+
if (patternRegexp.test(data)) {
|
|
1012
|
+
return;
|
|
1030
1013
|
}
|
|
1031
|
-
|
|
1032
|
-
return {
|
|
1033
|
-
valid,
|
|
1034
|
-
errors: valid ? [] : [
|
|
1035
|
-
new ValidationError(
|
|
1036
|
-
`String does not match format ${schema.format}`,
|
|
1037
|
-
{
|
|
1038
|
-
pointer,
|
|
1039
|
-
value: data,
|
|
1040
|
-
code: "STRING_DOES_NOT_MATCH_FORMAT"
|
|
1041
|
-
}
|
|
1042
|
-
)
|
|
1043
|
-
],
|
|
1044
|
-
data
|
|
1045
|
-
};
|
|
1014
|
+
return defineError("Value does not match the pattern", { data });
|
|
1046
1015
|
},
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
}
|
|
1053
|
-
if (Array.isArray(data)) {
|
|
1054
|
-
for (let i = 0; i < schema.enum.length; i++) {
|
|
1055
|
-
if (Array.isArray(schema.enum[i])) {
|
|
1056
|
-
if (deepEqual(schema.enum[i], data)) {
|
|
1057
|
-
return { valid: true, errors: [], data };
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
}
|
|
1016
|
+
// Take into account that if we receive a format that is not defined, we
|
|
1017
|
+
// will not throw an error, we just ignore it.
|
|
1018
|
+
format(schema, data, defineError, instance) {
|
|
1019
|
+
if (typeof data !== "string") {
|
|
1020
|
+
return;
|
|
1061
1021
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
if (deepEqual(schema.enum[i], data)) {
|
|
1066
|
-
return { valid: true, errors: [], data };
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1022
|
+
const formatValidate = instance.getFormat(schema.format);
|
|
1023
|
+
if (!formatValidate || formatValidate(data)) {
|
|
1024
|
+
return;
|
|
1070
1025
|
}
|
|
1071
|
-
return {
|
|
1072
|
-
valid: false,
|
|
1073
|
-
errors: [
|
|
1074
|
-
new ValidationError(`Value must be one of ${schema.enum.join(", ")}`, {
|
|
1075
|
-
pointer,
|
|
1076
|
-
value: data,
|
|
1077
|
-
code: "VALUE_NOT_IN_ENUM"
|
|
1078
|
-
})
|
|
1079
|
-
],
|
|
1080
|
-
data
|
|
1081
|
-
};
|
|
1026
|
+
return defineError("Value does not match the format", { data });
|
|
1082
1027
|
}
|
|
1083
1028
|
};
|
|
1084
1029
|
|
|
@@ -1093,197 +1038,200 @@ var keywords = {
|
|
|
1093
1038
|
|
|
1094
1039
|
// lib/index.ts
|
|
1095
1040
|
var SchemaShield = class {
|
|
1096
|
-
types =
|
|
1097
|
-
formats =
|
|
1098
|
-
keywords =
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1041
|
+
types = {};
|
|
1042
|
+
formats = {};
|
|
1043
|
+
keywords = {};
|
|
1044
|
+
immutable = false;
|
|
1045
|
+
constructor({
|
|
1046
|
+
immutable = false
|
|
1047
|
+
} = {}) {
|
|
1048
|
+
this.immutable = immutable;
|
|
1049
|
+
for (const [type, validator] of Object.entries(Types)) {
|
|
1050
|
+
if (validator) {
|
|
1051
|
+
this.addType(type, validator);
|
|
1052
|
+
}
|
|
1102
1053
|
}
|
|
1103
|
-
for (const keyword
|
|
1104
|
-
this.addKeyword(keyword,
|
|
1054
|
+
for (const [keyword, validator] of Object.entries(keywords)) {
|
|
1055
|
+
this.addKeyword(keyword, validator);
|
|
1105
1056
|
}
|
|
1106
|
-
for (const format
|
|
1107
|
-
|
|
1057
|
+
for (const [format, validator] of Object.entries(Formats)) {
|
|
1058
|
+
if (validator) {
|
|
1059
|
+
this.addFormat(format, validator);
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
addType(name, validator, overwrite = false) {
|
|
1064
|
+
if (this.types[name] && !overwrite) {
|
|
1065
|
+
throw new ValidationError(`Type "${name}" already exists`);
|
|
1108
1066
|
}
|
|
1067
|
+
this.types[name] = validator;
|
|
1109
1068
|
}
|
|
1110
|
-
|
|
1111
|
-
this.types
|
|
1069
|
+
getType(type) {
|
|
1070
|
+
return this.types[type];
|
|
1112
1071
|
}
|
|
1113
|
-
addFormat(name, validator) {
|
|
1114
|
-
this.formats
|
|
1072
|
+
addFormat(name, validator, overwrite = false) {
|
|
1073
|
+
if (this.formats[name] && !overwrite) {
|
|
1074
|
+
throw new ValidationError(`Format "${name}" already exists`);
|
|
1075
|
+
}
|
|
1076
|
+
this.formats[name] = validator;
|
|
1077
|
+
}
|
|
1078
|
+
getFormat(format) {
|
|
1079
|
+
return this.formats[format];
|
|
1080
|
+
}
|
|
1081
|
+
addKeyword(name, validator, overwrite = false) {
|
|
1082
|
+
if (this.keywords[name] && !overwrite) {
|
|
1083
|
+
throw new ValidationError(`Keyword "${name}" already exists`);
|
|
1084
|
+
}
|
|
1085
|
+
this.keywords[name] = validator;
|
|
1115
1086
|
}
|
|
1116
|
-
|
|
1117
|
-
this.keywords
|
|
1087
|
+
getKeyword(keyword) {
|
|
1088
|
+
return this.keywords[keyword];
|
|
1118
1089
|
}
|
|
1119
1090
|
compile(schema) {
|
|
1120
|
-
const compiledSchema = this.compileSchema(schema
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1091
|
+
const compiledSchema = this.compileSchema(schema);
|
|
1092
|
+
if (!compiledSchema.$validate) {
|
|
1093
|
+
if (this.isSchemaLike(schema) === false) {
|
|
1094
|
+
throw new ValidationError("Invalid schema");
|
|
1095
|
+
}
|
|
1096
|
+
compiledSchema.$validate = getNamedFunction(
|
|
1097
|
+
"any",
|
|
1098
|
+
() => {
|
|
1099
|
+
}
|
|
1100
|
+
);
|
|
1124
1101
|
}
|
|
1102
|
+
const validate = (data) => {
|
|
1103
|
+
const clonedData = this.immutable ? deepClone(data) : data;
|
|
1104
|
+
const error = compiledSchema.$validate(clonedData);
|
|
1105
|
+
return {
|
|
1106
|
+
data: clonedData,
|
|
1107
|
+
error: error ? error : null,
|
|
1108
|
+
valid: !error
|
|
1109
|
+
};
|
|
1110
|
+
};
|
|
1125
1111
|
validate.compiledSchema = compiledSchema;
|
|
1126
1112
|
return validate;
|
|
1127
1113
|
}
|
|
1128
|
-
compileSchema(schema
|
|
1129
|
-
if (
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
})
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
}
|
|
1144
|
-
const
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
],
|
|
1156
|
-
data
|
|
1157
|
-
};
|
|
1114
|
+
compileSchema(schema) {
|
|
1115
|
+
if (!isObject(schema)) {
|
|
1116
|
+
if (schema === true) {
|
|
1117
|
+
schema = {
|
|
1118
|
+
anyOf: [{}]
|
|
1119
|
+
};
|
|
1120
|
+
} else if (schema === false) {
|
|
1121
|
+
schema = {
|
|
1122
|
+
oneOf: []
|
|
1123
|
+
};
|
|
1124
|
+
} else {
|
|
1125
|
+
schema = {
|
|
1126
|
+
oneOf: [schema]
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
const compiledSchema = { ...schema };
|
|
1131
|
+
const defineTypeError = getDefinedErrorFunctionForKey("type", schema);
|
|
1132
|
+
const typeValidations = [];
|
|
1133
|
+
let methodName = "";
|
|
1134
|
+
if ("type" in schema) {
|
|
1135
|
+
const types = Array.isArray(schema.type) ? schema.type : schema.type.split(",").map((t) => t.trim());
|
|
1136
|
+
for (const type of types) {
|
|
1137
|
+
const validator = this.getType(type);
|
|
1138
|
+
if (validator) {
|
|
1139
|
+
typeValidations.push(validator);
|
|
1140
|
+
methodName += (methodName ? "_OR_" : "") + validator.name;
|
|
1158
1141
|
}
|
|
1159
1142
|
}
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
return typeErrorsResult;
|
|
1143
|
+
const typeValidationsLength = typeValidations.length;
|
|
1144
|
+
if (typeValidationsLength === 0) {
|
|
1145
|
+
throw defineTypeError("Invalid type for schema", { data: schema.type });
|
|
1164
1146
|
}
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1147
|
+
if (typeValidationsLength === 1) {
|
|
1148
|
+
const typeValidation = typeValidations[0];
|
|
1149
|
+
compiledSchema.$validate = getNamedFunction(
|
|
1150
|
+
methodName,
|
|
1151
|
+
(data) => {
|
|
1152
|
+
if (!typeValidation(data)) {
|
|
1153
|
+
return defineTypeError("Invalid type", { data });
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
);
|
|
1157
|
+
} else if (typeValidationsLength > 1) {
|
|
1158
|
+
compiledSchema.$validate = getNamedFunction(
|
|
1159
|
+
methodName,
|
|
1160
|
+
(data) => {
|
|
1161
|
+
for (let i = 0; i < typeValidationsLength; i++) {
|
|
1162
|
+
if (typeValidations[i](data)) {
|
|
1163
|
+
return;
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
return defineTypeError("Invalid type", { data });
|
|
1167
|
+
}
|
|
1168
|
+
);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
for (const key of Object.keys(schema)) {
|
|
1170
1172
|
if (key === "type") {
|
|
1173
|
+
compiledSchema.type = schema.type;
|
|
1171
1174
|
continue;
|
|
1172
1175
|
}
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
compiledSchema
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1176
|
+
const keywordValidator = this.getKeyword(key);
|
|
1177
|
+
if (keywordValidator) {
|
|
1178
|
+
const defineError = getDefinedErrorFunctionForKey(key, schema[key]);
|
|
1179
|
+
if (compiledSchema.$validate) {
|
|
1180
|
+
const prevValidator = compiledSchema.$validate;
|
|
1181
|
+
methodName += `_AND_${keywordValidator.name}`;
|
|
1182
|
+
compiledSchema.$validate = getNamedFunction(
|
|
1183
|
+
methodName,
|
|
1184
|
+
(data) => {
|
|
1185
|
+
const error = prevValidator(data);
|
|
1186
|
+
if (error) {
|
|
1187
|
+
return error;
|
|
1188
|
+
}
|
|
1189
|
+
return keywordValidator(
|
|
1190
|
+
compiledSchema,
|
|
1191
|
+
data,
|
|
1192
|
+
defineError,
|
|
1193
|
+
this
|
|
1194
|
+
);
|
|
1195
|
+
}
|
|
1196
|
+
);
|
|
1197
|
+
} else {
|
|
1198
|
+
methodName = keywordValidator.name;
|
|
1199
|
+
compiledSchema.$validate = getNamedFunction(
|
|
1200
|
+
methodName,
|
|
1201
|
+
(data) => keywordValidator(
|
|
1202
|
+
compiledSchema,
|
|
1203
|
+
data,
|
|
1204
|
+
defineError,
|
|
1205
|
+
this
|
|
1206
|
+
)
|
|
1207
|
+
);
|
|
1208
|
+
}
|
|
1181
1209
|
}
|
|
1182
1210
|
if (isObject(schema[key])) {
|
|
1183
|
-
this.
|
|
1211
|
+
compiledSchema[key] = this.compileSchema(schema[key]);
|
|
1184
1212
|
continue;
|
|
1185
1213
|
}
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
handleArraySchema(key, schema, pointer, compiledSchema) {
|
|
1190
|
-
compiledSchema[key] = schema[key].map((subSchema, index) => {
|
|
1191
|
-
if (typeof subSchema === "object" && subSchema !== null) {
|
|
1192
|
-
if ("type" in subSchema) {
|
|
1193
|
-
return this.compileSchema(subSchema, `${pointer}/${key}/${index}`);
|
|
1194
|
-
}
|
|
1195
|
-
for (let subKey in subSchema) {
|
|
1196
|
-
if (this.keywords.has(subKey)) {
|
|
1197
|
-
return this.compileSchema(subSchema, `${pointer}/${key}/${index}`);
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
return subSchema;
|
|
1202
|
-
});
|
|
1203
|
-
}
|
|
1204
|
-
handleObjectSchema(key, schema, pointer, compiledSchema) {
|
|
1205
|
-
if ("type" in schema[key]) {
|
|
1206
|
-
compiledSchema[key] = this.compileSchema(
|
|
1207
|
-
schema[key],
|
|
1208
|
-
`${pointer}/${key}`
|
|
1209
|
-
);
|
|
1210
|
-
return;
|
|
1211
|
-
}
|
|
1212
|
-
for (let subKey in schema[key]) {
|
|
1213
|
-
compiledSchema[key] = compiledSchema[key] || {};
|
|
1214
|
-
if (this.keywords.has(subKey)) {
|
|
1215
|
-
compiledSchema[key][subKey] = this.compileSchema(
|
|
1216
|
-
schema[key][subKey],
|
|
1217
|
-
`${pointer}/${subKey}`
|
|
1214
|
+
if (Array.isArray(schema[key])) {
|
|
1215
|
+
compiledSchema[key] = schema[key].map(
|
|
1216
|
+
(subSchema, index) => this.isSchemaLike(subSchema) ? this.compileSchema(subSchema) : subSchema
|
|
1218
1217
|
);
|
|
1219
1218
|
continue;
|
|
1220
1219
|
}
|
|
1221
|
-
|
|
1222
|
-
if ("type" in schema[key][subKey]) {
|
|
1223
|
-
compiledSchema[key][subKey] = this.compileSchema(
|
|
1224
|
-
schema[key][subKey],
|
|
1225
|
-
`${pointer}/${key}/${subKey}`
|
|
1226
|
-
);
|
|
1227
|
-
continue;
|
|
1228
|
-
}
|
|
1229
|
-
for (let subSubKey in schema[key][subKey]) {
|
|
1230
|
-
if (this.keywords.has(subSubKey)) {
|
|
1231
|
-
compiledSchema[key][subKey] = this.compileSchema(
|
|
1232
|
-
schema[key][subKey],
|
|
1233
|
-
`${pointer}/${key}/${subKey}`
|
|
1234
|
-
);
|
|
1235
|
-
continue;
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1220
|
+
compiledSchema[key] = schema[key];
|
|
1239
1221
|
}
|
|
1222
|
+
return compiledSchema;
|
|
1240
1223
|
}
|
|
1241
|
-
|
|
1242
|
-
if (
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
errors: [],
|
|
1246
|
-
data
|
|
1247
|
-
};
|
|
1248
|
-
}
|
|
1249
|
-
let errors = [];
|
|
1250
|
-
let finalData = data;
|
|
1251
|
-
for (let schemaValidator of schema.validators) {
|
|
1252
|
-
const schemaResult = schemaValidator(schema, data, pointer, this);
|
|
1253
|
-
finalData = schemaResult.data;
|
|
1254
|
-
if (schemaResult.valid) {
|
|
1255
|
-
return schemaResult;
|
|
1224
|
+
isSchemaLike(subSchema) {
|
|
1225
|
+
if (isObject(subSchema)) {
|
|
1226
|
+
if ("type" in subSchema) {
|
|
1227
|
+
return true;
|
|
1256
1228
|
}
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
valid: errors.length === 0,
|
|
1261
|
-
errors,
|
|
1262
|
-
data: finalData
|
|
1263
|
-
};
|
|
1264
|
-
}
|
|
1265
|
-
validateKeywords(schema, data, pointer) {
|
|
1266
|
-
const errors = [];
|
|
1267
|
-
let finalData = data;
|
|
1268
|
-
if ("keywords" in schema) {
|
|
1269
|
-
for (let keyword in schema.keywords) {
|
|
1270
|
-
const keywordValidator = schema.keywords[keyword];
|
|
1271
|
-
const keywordResult = keywordValidator(
|
|
1272
|
-
schema,
|
|
1273
|
-
finalData,
|
|
1274
|
-
pointer,
|
|
1275
|
-
this
|
|
1276
|
-
);
|
|
1277
|
-
finalData = keywordResult.data;
|
|
1278
|
-
if (!keywordResult.valid) {
|
|
1279
|
-
errors.push(...keywordResult.errors);
|
|
1229
|
+
for (let subKey in subSchema) {
|
|
1230
|
+
if (subKey in this.keywords) {
|
|
1231
|
+
return true;
|
|
1280
1232
|
}
|
|
1281
1233
|
}
|
|
1282
1234
|
}
|
|
1283
|
-
return
|
|
1284
|
-
valid: errors.length === 0,
|
|
1285
|
-
errors,
|
|
1286
|
-
data: finalData
|
|
1287
|
-
};
|
|
1235
|
+
return false;
|
|
1288
1236
|
}
|
|
1289
1237
|
};
|