Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MR414N-ID
GitHub Repository: MR414N-ID/botku2
Path: blob/master/node_modules/ajv/lib/ajv.js
1126 views
1
'use strict';
2
3
var compileSchema = require('./compile')
4
, resolve = require('./compile/resolve')
5
, Cache = require('./cache')
6
, SchemaObject = require('./compile/schema_obj')
7
, stableStringify = require('fast-json-stable-stringify')
8
, formats = require('./compile/formats')
9
, rules = require('./compile/rules')
10
, $dataMetaSchema = require('./data')
11
, util = require('./compile/util');
12
13
module.exports = Ajv;
14
15
Ajv.prototype.validate = validate;
16
Ajv.prototype.compile = compile;
17
Ajv.prototype.addSchema = addSchema;
18
Ajv.prototype.addMetaSchema = addMetaSchema;
19
Ajv.prototype.validateSchema = validateSchema;
20
Ajv.prototype.getSchema = getSchema;
21
Ajv.prototype.removeSchema = removeSchema;
22
Ajv.prototype.addFormat = addFormat;
23
Ajv.prototype.errorsText = errorsText;
24
25
Ajv.prototype._addSchema = _addSchema;
26
Ajv.prototype._compile = _compile;
27
28
Ajv.prototype.compileAsync = require('./compile/async');
29
var customKeyword = require('./keyword');
30
Ajv.prototype.addKeyword = customKeyword.add;
31
Ajv.prototype.getKeyword = customKeyword.get;
32
Ajv.prototype.removeKeyword = customKeyword.remove;
33
Ajv.prototype.validateKeyword = customKeyword.validate;
34
35
var errorClasses = require('./compile/error_classes');
36
Ajv.ValidationError = errorClasses.Validation;
37
Ajv.MissingRefError = errorClasses.MissingRef;
38
Ajv.$dataMetaSchema = $dataMetaSchema;
39
40
var META_SCHEMA_ID = 'http://json-schema.org/draft-07/schema';
41
42
var META_IGNORE_OPTIONS = [ 'removeAdditional', 'useDefaults', 'coerceTypes', 'strictDefaults' ];
43
var META_SUPPORT_DATA = ['/properties'];
44
45
/**
46
* Creates validator instance.
47
* Usage: `Ajv(opts)`
48
* @param {Object} opts optional options
49
* @return {Object} ajv instance
50
*/
51
function Ajv(opts) {
52
if (!(this instanceof Ajv)) return new Ajv(opts);
53
opts = this._opts = util.copy(opts) || {};
54
setLogger(this);
55
this._schemas = {};
56
this._refs = {};
57
this._fragments = {};
58
this._formats = formats(opts.format);
59
60
this._cache = opts.cache || new Cache;
61
this._loadingSchemas = {};
62
this._compilations = [];
63
this.RULES = rules();
64
this._getId = chooseGetId(opts);
65
66
opts.loopRequired = opts.loopRequired || Infinity;
67
if (opts.errorDataPath == 'property') opts._errorDataPathProperty = true;
68
if (opts.serialize === undefined) opts.serialize = stableStringify;
69
this._metaOpts = getMetaSchemaOptions(this);
70
71
if (opts.formats) addInitialFormats(this);
72
if (opts.keywords) addInitialKeywords(this);
73
addDefaultMetaSchema(this);
74
if (typeof opts.meta == 'object') this.addMetaSchema(opts.meta);
75
if (opts.nullable) this.addKeyword('nullable', {metaSchema: {type: 'boolean'}});
76
addInitialSchemas(this);
77
}
78
79
80
81
/**
82
* Validate data using schema
83
* Schema will be compiled and cached (using serialized JSON as key. [fast-json-stable-stringify](https://github.com/epoberezkin/fast-json-stable-stringify) is used to serialize.
84
* @this Ajv
85
* @param {String|Object} schemaKeyRef key, ref or schema object
86
* @param {Any} data to be validated
87
* @return {Boolean} validation result. Errors from the last validation will be available in `ajv.errors` (and also in compiled schema: `schema.errors`).
88
*/
89
function validate(schemaKeyRef, data) {
90
var v;
91
if (typeof schemaKeyRef == 'string') {
92
v = this.getSchema(schemaKeyRef);
93
if (!v) throw new Error('no schema with key or ref "' + schemaKeyRef + '"');
94
} else {
95
var schemaObj = this._addSchema(schemaKeyRef);
96
v = schemaObj.validate || this._compile(schemaObj);
97
}
98
99
var valid = v(data);
100
if (v.$async !== true) this.errors = v.errors;
101
return valid;
102
}
103
104
105
/**
106
* Create validating function for passed schema.
107
* @this Ajv
108
* @param {Object} schema schema object
109
* @param {Boolean} _meta true if schema is a meta-schema. Used internally to compile meta schemas of custom keywords.
110
* @return {Function} validating function
111
*/
112
function compile(schema, _meta) {
113
var schemaObj = this._addSchema(schema, undefined, _meta);
114
return schemaObj.validate || this._compile(schemaObj);
115
}
116
117
118
/**
119
* Adds schema to the instance.
120
* @this Ajv
121
* @param {Object|Array} schema schema or array of schemas. If array is passed, `key` and other parameters will be ignored.
122
* @param {String} key Optional schema key. Can be passed to `validate` method instead of schema object or id/ref. One schema per instance can have empty `id` and `key`.
123
* @param {Boolean} _skipValidation true to skip schema validation. Used internally, option validateSchema should be used instead.
124
* @param {Boolean} _meta true if schema is a meta-schema. Used internally, addMetaSchema should be used instead.
125
* @return {Ajv} this for method chaining
126
*/
127
function addSchema(schema, key, _skipValidation, _meta) {
128
if (Array.isArray(schema)){
129
for (var i=0; i<schema.length; i++) this.addSchema(schema[i], undefined, _skipValidation, _meta);
130
return this;
131
}
132
var id = this._getId(schema);
133
if (id !== undefined && typeof id != 'string')
134
throw new Error('schema id must be string');
135
key = resolve.normalizeId(key || id);
136
checkUnique(this, key);
137
this._schemas[key] = this._addSchema(schema, _skipValidation, _meta, true);
138
return this;
139
}
140
141
142
/**
143
* Add schema that will be used to validate other schemas
144
* options in META_IGNORE_OPTIONS are alway set to false
145
* @this Ajv
146
* @param {Object} schema schema object
147
* @param {String} key optional schema key
148
* @param {Boolean} skipValidation true to skip schema validation, can be used to override validateSchema option for meta-schema
149
* @return {Ajv} this for method chaining
150
*/
151
function addMetaSchema(schema, key, skipValidation) {
152
this.addSchema(schema, key, skipValidation, true);
153
return this;
154
}
155
156
157
/**
158
* Validate schema
159
* @this Ajv
160
* @param {Object} schema schema to validate
161
* @param {Boolean} throwOrLogError pass true to throw (or log) an error if invalid
162
* @return {Boolean} true if schema is valid
163
*/
164
function validateSchema(schema, throwOrLogError) {
165
var $schema = schema.$schema;
166
if ($schema !== undefined && typeof $schema != 'string')
167
throw new Error('$schema must be a string');
168
$schema = $schema || this._opts.defaultMeta || defaultMeta(this);
169
if (!$schema) {
170
this.logger.warn('meta-schema not available');
171
this.errors = null;
172
return true;
173
}
174
var valid = this.validate($schema, schema);
175
if (!valid && throwOrLogError) {
176
var message = 'schema is invalid: ' + this.errorsText();
177
if (this._opts.validateSchema == 'log') this.logger.error(message);
178
else throw new Error(message);
179
}
180
return valid;
181
}
182
183
184
function defaultMeta(self) {
185
var meta = self._opts.meta;
186
self._opts.defaultMeta = typeof meta == 'object'
187
? self._getId(meta) || meta
188
: self.getSchema(META_SCHEMA_ID)
189
? META_SCHEMA_ID
190
: undefined;
191
return self._opts.defaultMeta;
192
}
193
194
195
/**
196
* Get compiled schema from the instance by `key` or `ref`.
197
* @this Ajv
198
* @param {String} keyRef `key` that was passed to `addSchema` or full schema reference (`schema.id` or resolved id).
199
* @return {Function} schema validating function (with property `schema`).
200
*/
201
function getSchema(keyRef) {
202
var schemaObj = _getSchemaObj(this, keyRef);
203
switch (typeof schemaObj) {
204
case 'object': return schemaObj.validate || this._compile(schemaObj);
205
case 'string': return this.getSchema(schemaObj);
206
case 'undefined': return _getSchemaFragment(this, keyRef);
207
}
208
}
209
210
211
function _getSchemaFragment(self, ref) {
212
var res = resolve.schema.call(self, { schema: {} }, ref);
213
if (res) {
214
var schema = res.schema
215
, root = res.root
216
, baseId = res.baseId;
217
var v = compileSchema.call(self, schema, root, undefined, baseId);
218
self._fragments[ref] = new SchemaObject({
219
ref: ref,
220
fragment: true,
221
schema: schema,
222
root: root,
223
baseId: baseId,
224
validate: v
225
});
226
return v;
227
}
228
}
229
230
231
function _getSchemaObj(self, keyRef) {
232
keyRef = resolve.normalizeId(keyRef);
233
return self._schemas[keyRef] || self._refs[keyRef] || self._fragments[keyRef];
234
}
235
236
237
/**
238
* Remove cached schema(s).
239
* If no parameter is passed all schemas but meta-schemas are removed.
240
* If RegExp is passed all schemas with key/id matching pattern but meta-schemas are removed.
241
* Even if schema is referenced by other schemas it still can be removed as other schemas have local references.
242
* @this Ajv
243
* @param {String|Object|RegExp} schemaKeyRef key, ref, pattern to match key/ref or schema object
244
* @return {Ajv} this for method chaining
245
*/
246
function removeSchema(schemaKeyRef) {
247
if (schemaKeyRef instanceof RegExp) {
248
_removeAllSchemas(this, this._schemas, schemaKeyRef);
249
_removeAllSchemas(this, this._refs, schemaKeyRef);
250
return this;
251
}
252
switch (typeof schemaKeyRef) {
253
case 'undefined':
254
_removeAllSchemas(this, this._schemas);
255
_removeAllSchemas(this, this._refs);
256
this._cache.clear();
257
return this;
258
case 'string':
259
var schemaObj = _getSchemaObj(this, schemaKeyRef);
260
if (schemaObj) this._cache.del(schemaObj.cacheKey);
261
delete this._schemas[schemaKeyRef];
262
delete this._refs[schemaKeyRef];
263
return this;
264
case 'object':
265
var serialize = this._opts.serialize;
266
var cacheKey = serialize ? serialize(schemaKeyRef) : schemaKeyRef;
267
this._cache.del(cacheKey);
268
var id = this._getId(schemaKeyRef);
269
if (id) {
270
id = resolve.normalizeId(id);
271
delete this._schemas[id];
272
delete this._refs[id];
273
}
274
}
275
return this;
276
}
277
278
279
function _removeAllSchemas(self, schemas, regex) {
280
for (var keyRef in schemas) {
281
var schemaObj = schemas[keyRef];
282
if (!schemaObj.meta && (!regex || regex.test(keyRef))) {
283
self._cache.del(schemaObj.cacheKey);
284
delete schemas[keyRef];
285
}
286
}
287
}
288
289
290
/* @this Ajv */
291
function _addSchema(schema, skipValidation, meta, shouldAddSchema) {
292
if (typeof schema != 'object' && typeof schema != 'boolean')
293
throw new Error('schema should be object or boolean');
294
var serialize = this._opts.serialize;
295
var cacheKey = serialize ? serialize(schema) : schema;
296
var cached = this._cache.get(cacheKey);
297
if (cached) return cached;
298
299
shouldAddSchema = shouldAddSchema || this._opts.addUsedSchema !== false;
300
301
var id = resolve.normalizeId(this._getId(schema));
302
if (id && shouldAddSchema) checkUnique(this, id);
303
304
var willValidate = this._opts.validateSchema !== false && !skipValidation;
305
var recursiveMeta;
306
if (willValidate && !(recursiveMeta = id && id == resolve.normalizeId(schema.$schema)))
307
this.validateSchema(schema, true);
308
309
var localRefs = resolve.ids.call(this, schema);
310
311
var schemaObj = new SchemaObject({
312
id: id,
313
schema: schema,
314
localRefs: localRefs,
315
cacheKey: cacheKey,
316
meta: meta
317
});
318
319
if (id[0] != '#' && shouldAddSchema) this._refs[id] = schemaObj;
320
this._cache.put(cacheKey, schemaObj);
321
322
if (willValidate && recursiveMeta) this.validateSchema(schema, true);
323
324
return schemaObj;
325
}
326
327
328
/* @this Ajv */
329
function _compile(schemaObj, root) {
330
if (schemaObj.compiling) {
331
schemaObj.validate = callValidate;
332
callValidate.schema = schemaObj.schema;
333
callValidate.errors = null;
334
callValidate.root = root ? root : callValidate;
335
if (schemaObj.schema.$async === true)
336
callValidate.$async = true;
337
return callValidate;
338
}
339
schemaObj.compiling = true;
340
341
var currentOpts;
342
if (schemaObj.meta) {
343
currentOpts = this._opts;
344
this._opts = this._metaOpts;
345
}
346
347
var v;
348
try { v = compileSchema.call(this, schemaObj.schema, root, schemaObj.localRefs); }
349
catch(e) {
350
delete schemaObj.validate;
351
throw e;
352
}
353
finally {
354
schemaObj.compiling = false;
355
if (schemaObj.meta) this._opts = currentOpts;
356
}
357
358
schemaObj.validate = v;
359
schemaObj.refs = v.refs;
360
schemaObj.refVal = v.refVal;
361
schemaObj.root = v.root;
362
return v;
363
364
365
/* @this {*} - custom context, see passContext option */
366
function callValidate() {
367
/* jshint validthis: true */
368
var _validate = schemaObj.validate;
369
var result = _validate.apply(this, arguments);
370
callValidate.errors = _validate.errors;
371
return result;
372
}
373
}
374
375
376
function chooseGetId(opts) {
377
switch (opts.schemaId) {
378
case 'auto': return _get$IdOrId;
379
case 'id': return _getId;
380
default: return _get$Id;
381
}
382
}
383
384
/* @this Ajv */
385
function _getId(schema) {
386
if (schema.$id) this.logger.warn('schema $id ignored', schema.$id);
387
return schema.id;
388
}
389
390
/* @this Ajv */
391
function _get$Id(schema) {
392
if (schema.id) this.logger.warn('schema id ignored', schema.id);
393
return schema.$id;
394
}
395
396
397
function _get$IdOrId(schema) {
398
if (schema.$id && schema.id && schema.$id != schema.id)
399
throw new Error('schema $id is different from id');
400
return schema.$id || schema.id;
401
}
402
403
404
/**
405
* Convert array of error message objects to string
406
* @this Ajv
407
* @param {Array<Object>} errors optional array of validation errors, if not passed errors from the instance are used.
408
* @param {Object} options optional options with properties `separator` and `dataVar`.
409
* @return {String} human readable string with all errors descriptions
410
*/
411
function errorsText(errors, options) {
412
errors = errors || this.errors;
413
if (!errors) return 'No errors';
414
options = options || {};
415
var separator = options.separator === undefined ? ', ' : options.separator;
416
var dataVar = options.dataVar === undefined ? 'data' : options.dataVar;
417
418
var text = '';
419
for (var i=0; i<errors.length; i++) {
420
var e = errors[i];
421
if (e) text += dataVar + e.dataPath + ' ' + e.message + separator;
422
}
423
return text.slice(0, -separator.length);
424
}
425
426
427
/**
428
* Add custom format
429
* @this Ajv
430
* @param {String} name format name
431
* @param {String|RegExp|Function} format string is converted to RegExp; function should return boolean (true when valid)
432
* @return {Ajv} this for method chaining
433
*/
434
function addFormat(name, format) {
435
if (typeof format == 'string') format = new RegExp(format);
436
this._formats[name] = format;
437
return this;
438
}
439
440
441
function addDefaultMetaSchema(self) {
442
var $dataSchema;
443
if (self._opts.$data) {
444
$dataSchema = require('./refs/data.json');
445
self.addMetaSchema($dataSchema, $dataSchema.$id, true);
446
}
447
if (self._opts.meta === false) return;
448
var metaSchema = require('./refs/json-schema-draft-07.json');
449
if (self._opts.$data) metaSchema = $dataMetaSchema(metaSchema, META_SUPPORT_DATA);
450
self.addMetaSchema(metaSchema, META_SCHEMA_ID, true);
451
self._refs['http://json-schema.org/schema'] = META_SCHEMA_ID;
452
}
453
454
455
function addInitialSchemas(self) {
456
var optsSchemas = self._opts.schemas;
457
if (!optsSchemas) return;
458
if (Array.isArray(optsSchemas)) self.addSchema(optsSchemas);
459
else for (var key in optsSchemas) self.addSchema(optsSchemas[key], key);
460
}
461
462
463
function addInitialFormats(self) {
464
for (var name in self._opts.formats) {
465
var format = self._opts.formats[name];
466
self.addFormat(name, format);
467
}
468
}
469
470
471
function addInitialKeywords(self) {
472
for (var name in self._opts.keywords) {
473
var keyword = self._opts.keywords[name];
474
self.addKeyword(name, keyword);
475
}
476
}
477
478
479
function checkUnique(self, id) {
480
if (self._schemas[id] || self._refs[id])
481
throw new Error('schema with key or id "' + id + '" already exists');
482
}
483
484
485
function getMetaSchemaOptions(self) {
486
var metaOpts = util.copy(self._opts);
487
for (var i=0; i<META_IGNORE_OPTIONS.length; i++)
488
delete metaOpts[META_IGNORE_OPTIONS[i]];
489
return metaOpts;
490
}
491
492
493
function setLogger(self) {
494
var logger = self._opts.logger;
495
if (logger === false) {
496
self.logger = {log: noop, warn: noop, error: noop};
497
} else {
498
if (logger === undefined) logger = console;
499
if (!(typeof logger == 'object' && logger.log && logger.warn && logger.error))
500
throw new Error('logger must implement log, warn and error methods');
501
self.logger = logger;
502
}
503
}
504
505
506
function noop() {}
507
508