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/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
- value;
32
- code;
33
- constructor(message, options = {
34
- pointer: "",
35
- value: null,
36
- code: ""
37
- }) {
38
- super(message);
39
- this.name = "ValidationError";
40
- this.pointer = options.pointer;
41
- this.message = message;
42
- this.value = options.value;
43
- this.code = options.code;
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
- return RegExps["date-time"].test(data);
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 RegExps.uri.test(data);
210
+ return /^[a-zA-Z][a-zA-Z0-9+\-.]*:[^\s]*$/.test(data);
100
211
  },
101
212
  email(data) {
102
- return RegExps.email.test(data);
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 RegExps.ipv4.test(data);
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
- return RegExps.ipv6.test(data);
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 RegExps.hostname.test(data);
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
- array(schema, data, pointer) {
152
- if (Array.isArray(data)) {
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
- if (typeof data === "object" && data !== null && "length" in data) {
160
- const keys = Object.keys(data);
161
- if (keys.length > 0 && (keys[0] !== "0" || keys.length !== data.length)) {
162
- return {
163
- valid: false,
164
- errors: [
165
- new ValidationError("Data is not an array", {
166
- pointer,
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
- string(schema, data, pointer) {
193
- if (typeof data === "string") {
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
- number(schema, data, pointer) {
213
- if (typeof data === "number") {
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
- valid: false,
222
- errors: [
223
- new ValidationError("Data is not a number", {
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
- integer(schema, data, pointer) {
233
- if (typeof data === "number" && Number.isInteger(data)) {
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
- boolean(schema, data, pointer) {
253
- if (typeof data === "boolean") {
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
- null(schema, data, pointer) {
273
- if (data === null) {
274
- return {
275
- valid: true,
276
- errors: [],
277
- data
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
- valid: false,
282
- errors: [
283
- new ValidationError("Data is not null", {
284
- pointer,
285
- value: data,
286
- code: "NOT_NULL"
287
- })
288
- ],
289
- data
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, pointer, schemaShieldInstance) {
361
+ items(schema, data, defineError) {
297
362
  if (!Array.isArray(data)) {
298
- return { valid: true, errors: [], data };
299
- }
300
- const errors = [];
301
- let finalData = [...data];
302
- if (Array.isArray(schema.items)) {
303
- for (let i = 0; i < schema.items.length; i++) {
304
- if (typeof schema.items[i] === "boolean") {
305
- if (schema.items[i] === false && typeof data[i] !== "undefined") {
306
- errors.push(
307
- new ValidationError("Array item is not allowed", {
308
- pointer: `${pointer}/${i}`,
309
- value: data[i],
310
- code: "ARRAY_ITEM_NOT_ALLOWED"
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
- const { validator } = schema.items[i];
317
- if (!validator) {
318
- continue;
319
- }
320
- const validatorResult = validator(
321
- schema.items[i],
322
- finalData[i],
323
- `${pointer}/${i}`,
324
- schemaShieldInstance
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
- } else if (typeof schema.items === "boolean") {
332
- if (schema.items === false && data.length > 0) {
333
- errors.push(
334
- new ValidationError("Array is not allowed", {
335
- pointer,
336
- value: data,
337
- code: "ARRAY_NOT_ALLOWED"
338
- })
339
- );
340
- }
341
- } else {
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 { valid: errors.length === 0, errors, data: finalData };
412
+ return;
360
413
  },
361
- minItems(schema, data, pointer) {
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 { valid: true, errors: [], data };
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, pointer) {
436
+ maxItems(schema, data, defineError) {
378
437
  if (!Array.isArray(data) || data.length <= schema.maxItems) {
379
- return { valid: true, errors: [], data };
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, pointer, schemaShieldInstance) {
394
- if (!Array.isArray(data) || !schema.items || !Array.isArray(schema.items)) {
395
- return { valid: true, errors: [], data };
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 { valid: true, errors: [], data };
412
- }
413
- const errors = [];
414
- let finalData = [...data];
415
- if (typeof schema.additionalItems === "object") {
416
- for (let i = schema.items.length; i < finalData.length; i++) {
417
- const { validator } = schema.additionalItems;
418
- const validatorResult = validator(
419
- schema.additionalItems,
420
- finalData[i],
421
- `${pointer}/${i}`,
422
- schemaShieldInstance
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
- finalData[i] = validatorResult.data;
464
+ return;
428
465
  }
466
+ return;
429
467
  }
430
- return { valid: errors.length === 0, errors, data: finalData };
468
+ return;
431
469
  },
432
- uniqueItems(schema, data, pointer) {
470
+ uniqueItems(schema, data, defineError) {
433
471
  if (!Array.isArray(data) || !schema.uniqueItems) {
434
- return { valid: true, errors: [], data };
472
+ return;
435
473
  }
436
474
  const unique = /* @__PURE__ */ new Set();
437
475
  for (const item of data) {
438
- let itemStr = item;
476
+ let itemStr;
439
477
  if (typeof item === "string") {
440
- itemStr = `"${item}"`;
478
+ itemStr = `s:${item}`;
441
479
  } else if (isObject(item)) {
442
- const keys = Object.keys(item).sort();
443
- const sorted = {};
444
- for (let i = 0; i < keys.length; i++) {
445
- sorted[keys[i]] = item[keys[i]];
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
- return { valid: true, errors: [], data };
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, pointer) {
523
+ minimum(schema, data, defineError, instance) {
474
524
  if (typeof data !== "number") {
475
- return { valid: true, errors: [], data };
476
- }
477
- const min = schema.exclusiveMinimum ? schema.minimum + 1e-15 : schema.minimum;
478
- const valid = data >= min;
479
- return {
480
- valid,
481
- errors: valid ? [] : [
482
- new ValidationError("Number is too small", {
483
- pointer,
484
- value: data,
485
- code: "NUMBER_TOO_SMALL"
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, pointer) {
538
+ maximum(schema, data, defineError, instance) {
492
539
  if (typeof data !== "number") {
493
- return { valid: true, errors: [], data };
494
- }
495
- const max = schema.exclusiveMaximum ? schema.maximum - 1e-15 : schema.maximum;
496
- const valid = data <= max;
497
- return {
498
- valid,
499
- errors: valid ? [] : [
500
- new ValidationError("Number is too large", {
501
- pointer,
502
- value: data,
503
- code: "NUMBER_TOO_LARGE"
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, pointer) {
553
+ multipleOf(schema, data, defineError, instance) {
510
554
  if (typeof data !== "number") {
511
- return { valid: true, errors: [], data };
555
+ return;
512
556
  }
513
557
  const quotient = data / schema.multipleOf;
514
- const areMultiples = Math.abs(quotient - Math.round(quotient)) < 1e-15;
515
- return {
516
- valid: areMultiples,
517
- errors: areMultiples ? [] : [
518
- new ValidationError("Number is not a multiple of", {
519
- pointer,
520
- value: data,
521
- code: "NUMBER_NOT_MULTIPLE_OF"
522
- })
523
- ],
524
- data
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, pointer) {
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
- errors.push(
545
- new ValidationError("Missing required property", {
546
- pointer: `${pointer}/${key}`,
547
- value: data,
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 { valid: errors.length === 0, errors, data };
605
+ return;
554
606
  },
555
- properties(schema, data, pointer, schemaShieldInstance) {
607
+ properties(schema, data, defineError) {
556
608
  if (!isObject(data)) {
557
- return { valid: true, errors: [], data };
558
- }
559
- const errors = [];
560
- let finalData = { ...data };
561
- for (let key in schema.properties) {
562
- if (!data.hasOwnProperty(key) || typeof data[key] === "undefined") {
563
- if (isObject(schema.properties[key]) && "default" in schema.properties[key]) {
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
- errors.push(
571
- new ValidationError("Property is not allowed", {
572
- pointer: `${pointer}/${key}`,
573
- value: data[key],
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
- const { validator } = schema.properties[key];
581
- if (!validator) {
582
- continue;
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
- const validatorResult = validator(
585
- schema.properties[key],
586
- finalData[key],
587
- `${pointer}/${key}`,
588
- schemaShieldInstance
589
- );
590
- finalData[key] = validatorResult.data;
591
- if (!validatorResult.valid) {
592
- errors.push(...validatorResult.errors);
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 { valid: errors.length === 0, errors, data: finalData };
656
+ return;
596
657
  },
597
- maxProperties(schema, data, pointer) {
658
+ maxProperties(schema, data, defineError) {
598
659
  if (!isObject(data) || Object.keys(data).length <= schema.maxProperties) {
599
- return { valid: true, errors: [], data };
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, pointer) {
664
+ minProperties(schema, data, defineError) {
614
665
  if (!isObject(data) || Object.keys(data).length >= schema.minProperties) {
615
- return { valid: true, errors: [], data };
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, pointer, schemaShieldInstance) {
670
+ additionalProperties(schema, data, defineError) {
630
671
  if (!isObject(data)) {
631
- return { valid: true, errors: [], data };
672
+ return;
632
673
  }
633
- const errors = [];
634
- let finalData = { ...data };
635
- for (let key in data) {
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 (let pattern in schema.patternProperties) {
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
- errors.push(
653
- new ValidationError("Additional property not allowed", {
654
- pointer: `${pointer}/${key}`,
655
- value: data,
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
- const { validator } = schema.additionalProperties;
662
- if (!validator) {
663
- continue;
664
- }
665
- const validatorResult = validator(
666
- schema.additionalProperties,
667
- finalData[key],
668
- `${pointer}/${key}`,
669
- schemaShieldInstance
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 { valid: errors.length === 0, errors, data: finalData };
709
+ return;
677
710
  },
678
- patternProperties(schema, data, pointer, schemaShieldInstance) {
711
+ patternProperties(schema, data, defineError) {
679
712
  if (!isObject(data)) {
680
- return { valid: true, errors: [], data };
713
+ return;
681
714
  }
682
- const errors = [];
683
- let finalData = { ...data };
684
- for (let pattern in schema.patternProperties) {
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 (let key in finalData) {
688
- if (new RegExp(pattern).test(key)) {
689
- errors.push(
690
- new ValidationError("Property is not allowed", {
691
- pointer: `${pointer}/${key}`,
692
- value: data[key],
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 { validator } = schema.patternProperties[pattern];
702
- if (!validator) {
703
- continue;
704
- }
705
- for (let key in finalData) {
706
- if (new RegExp(pattern).test(key)) {
707
- const validatorResult = validator(
708
- schema.patternProperties[pattern],
709
- finalData[key],
710
- `${pointer}/${key}`,
711
- schemaShieldInstance
712
- );
713
- finalData[key] = validatorResult.data;
714
- if (!validatorResult.valid) {
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 { valid: errors.length === 0, errors, data: finalData };
721
- }
722
- };
723
-
724
- // lib/keywords/other-keywords.ts
725
- var OtherKeywords = {
726
- nullable(schema, data, pointer) {
727
- if (schema.nullable && data !== null) {
728
- return {
729
- valid: false,
730
- errors: [
731
- new ValidationError("Value must be null to be empty", {
732
- pointer,
733
- value: data,
734
- code: "VALUE_NOT_NULL"
735
- })
736
- ],
737
- data
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 { valid: true, errors: [], data };
772
+ return;
741
773
  },
742
- oneOf(schema, data, pointer, schemaShieldInstance) {
743
- const errors = [];
744
- let validCount = 0;
745
- let finalData = data;
746
- for (let i = 0; i < schema.oneOf.length; i++) {
747
- if (isObject(schema.oneOf[i])) {
748
- const { validator } = schema.oneOf[i];
749
- if (!validator) {
750
- validCount++;
751
- continue;
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
- const validationResult = validator(
754
- schema.oneOf[i],
755
- finalData,
756
- pointer,
757
- schemaShieldInstance
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
- finalData = validationResult.data;
765
- } else {
766
- if (typeof schema.oneOf[i] === "boolean") {
767
- if (Boolean(data) === schema.oneOf[i]) {
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
- if (data === schema.oneOf[i]) {
773
- validCount++;
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
- if (validCount === 1) {
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, pointer, schemaShieldInstance) {
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
- const { validator } = schema.allOf[i];
798
- if (!validator) {
799
- continue;
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
- if (data !== schema.allOf[i]) {
825
- errors.push(
826
- new ValidationError(`Value must match all schemas in allOf`, {
827
- pointer,
828
- value: data,
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 { valid: errors.length === 0, errors, data: finalData };
876
+ return;
836
877
  },
837
- anyOf(schema, data, pointer, schemaShieldInstance) {
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
- const { validator } = schema.anyOf[i];
842
- if (!validator) {
843
- return { valid: true, errors: [], data };
844
- }
845
- const validationResult = validator(
846
- schema.anyOf[i],
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 { valid: true, errors: [], data: finalData };
892
+ return;
859
893
  }
860
894
  }
861
895
  if (data === schema.anyOf[i]) {
862
- return { valid: true, errors: [], data: finalData };
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
- dependencies(schema, data, pointer, schemaShieldInstance) {
879
- if (!isObject(data)) {
880
- return { valid: true, errors: [], data };
881
- }
882
- const errors = [];
883
- let finalData = data;
884
- for (const key in schema.dependencies) {
885
- if (key in data === false) {
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
- if (typeof dependency === "boolean") {
904
- if (dependency) {
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
- errors.push(
908
- new ValidationError(`Dependency ${key} is missing`, {
909
- pointer,
910
- value: data,
911
- code: "DEPENDENCY_MISSING"
912
- })
913
- );
914
- continue;
922
+ if (data === schema.oneOf[i]) {
923
+ validCount++;
924
+ }
915
925
  }
916
- if (typeof dependency === "string") {
917
- if (dependency in data) {
918
- continue;
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
- errors.push(
921
- new ValidationError(`Dependency ${dependency} is missing`, {
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
- const { validator } = dependency;
930
- if (!validator) {
931
- continue;
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
- const validatorResult = validator(
934
- dependency,
935
- finalData,
936
- pointer,
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
- finalData = validatorResult.data;
965
+ return;
943
966
  }
944
- return { valid: errors.length === 0, errors, data: finalData };
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, pointer) {
991
+ minLength(schema, data, defineError) {
951
992
  if (typeof data !== "string" || data.length >= schema.minLength) {
952
- return { valid: true, errors: [], data };
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, pointer) {
997
+ maxLength(schema, data, defineError) {
967
998
  if (typeof data !== "string" || data.length <= schema.maxLength) {
968
- return { valid: true, errors: [], data };
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, pointer) {
1003
+ pattern(schema, data, defineError) {
983
1004
  if (typeof data !== "string") {
984
- return { valid: true, errors: [], data };
1005
+ return;
985
1006
  }
986
- const patternRegexp = typeof schema.pattern === "string" ? new RegExp(schema.pattern) : schema.pattern;
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
- const formatValidate = formatInstance.formats.get(schema.format);
1018
- if (!formatValidate) {
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
- const valid = formatValidate(data);
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
- enum(schema, data, pointer) {
1048
- for (let i = 0; i < schema.enum.length; i++) {
1049
- if (schema.enum[i] === data) {
1050
- return { valid: true, errors: [], data };
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
- if (typeof data === "object" && data !== null) {
1063
- for (let i = 0; i < schema.enum.length; i++) {
1064
- if (typeof schema.enum[i] === "object" && schema.enum[i] !== null) {
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 = /* @__PURE__ */ new Map();
1097
- formats = /* @__PURE__ */ new Map();
1098
- keywords = /* @__PURE__ */ new Map();
1099
- constructor() {
1100
- for (const type in Types) {
1101
- this.addType(type, Types[type]);
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 in keywords) {
1104
- this.addKeyword(keyword, keywords[keyword]);
1054
+ for (const [keyword, validator] of Object.entries(keywords)) {
1055
+ this.addKeyword(keyword, validator);
1105
1056
  }
1106
- for (const format in Formats) {
1107
- this.addFormat(format, Formats[format]);
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
- addType(name, validator) {
1111
- this.types.set(name, validator);
1069
+ getType(type) {
1070
+ return this.types[type];
1112
1071
  }
1113
- addFormat(name, validator) {
1114
- this.formats.set(name, validator);
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
- addKeyword(name, validator) {
1117
- this.keywords.set(name, validator);
1087
+ getKeyword(keyword) {
1088
+ return this.keywords[keyword];
1118
1089
  }
1119
1090
  compile(schema) {
1120
- const compiledSchema = this.compileSchema(schema, "#");
1121
- const schemaShield = this;
1122
- function validate(data) {
1123
- return compiledSchema.validator(compiledSchema, data, "#", schemaShield);
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, pointer) {
1129
- if (typeof schema !== "object" || schema === null) {
1130
- throw new ValidationError("Schema is not an object", {
1131
- pointer,
1132
- value: schema,
1133
- code: "SCHEMA_NOT_OBJECT"
1134
- });
1135
- }
1136
- const compiledSchema = {
1137
- ...schema,
1138
- pointer
1139
- };
1140
- if ("type" in compiledSchema) {
1141
- const types = Array.isArray(compiledSchema.type) ? compiledSchema.type : compiledSchema.type.split(",").map((t) => t.trim());
1142
- compiledSchema.validators = types.filter((type) => this.types.has(type)).map((type) => this.types.get(type));
1143
- }
1144
- const validator = (schema2, data, pointer2) => {
1145
- if (typeof data === "undefined") {
1146
- if (pointer2 === "#") {
1147
- return {
1148
- valid: false,
1149
- errors: [
1150
- new ValidationError("Data is undefined", {
1151
- pointer: pointer2,
1152
- value: data,
1153
- code: "DATA_UNDEFINED"
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
- let finalData = data;
1161
- const typeErrorsResult = this.validateTypes(schema2, finalData, pointer2);
1162
- if (typeErrorsResult.valid === false) {
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
- finalData = typeErrorsResult.data;
1166
- return this.validateKeywords(schema2, finalData, pointer2);
1167
- };
1168
- compiledSchema.validator = validator;
1169
- for (let key in schema) {
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
- if (this.keywords.has(key)) {
1174
- const validator2 = this.keywords.get(key);
1175
- compiledSchema.keywords = compiledSchema.keywords || {};
1176
- compiledSchema.keywords[key] = validator2;
1177
- }
1178
- if (Array.isArray(schema[key])) {
1179
- this.handleArraySchema(key, schema, pointer, compiledSchema);
1180
- continue;
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.handleObjectSchema(key, schema, pointer, compiledSchema);
1211
+ compiledSchema[key] = this.compileSchema(schema[key]);
1184
1212
  continue;
1185
1213
  }
1186
- }
1187
- return compiledSchema;
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
- if (typeof schema[key][subKey] === "object") {
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
- validateTypes(schema, data, pointer) {
1242
- if (typeof data === "undefined" || !Array.isArray(schema.validators) || schema.validators.length === 0) {
1243
- return {
1244
- valid: true,
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
- errors = schemaResult.errors;
1258
- }
1259
- return {
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
  };