-
-
Notifications
You must be signed in to change notification settings - Fork 864
/
ajv.js
172 lines (136 loc) · 5.5 KB
/
ajv.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
'use strict';
var compileSchema = require('./compile')
, resolve = require('./compile/resolve')
, stableStringify = require('json-stable-stringify')
, formats = require('./compile/formats')
, util = require('./compile/util');
module.exports = Ajv;
var META_SCHEMA_ID = 'http://json-schema.org/draft-04/schema';
/**
* Creates validator instance.
* Usage: `jv(opts)`
* @param {Object} opts optional options
* @return {Object} jv instance
*/
function Ajv(opts) {
if (!(this instanceof Ajv)) return new Ajv(opts);
var self = this;
this.opts = opts || {};
this._schemas = {};
this._refs = {};
this._missing = {};
this._byJson = {};
this._formats = formats(this.opts.format);
// this is done on purpose, so that methods are bound to the instance
// (without using bind) so that they can be used without the instance
this.validate = validate;
this.compile = compile;
this.addSchema = addSchema;
this.getSchema = getSchema;
this.addFormat = addFormat;
addInitialSchemas();
addInitialFormats();
/**
* Validate data using schema
* Schema will be compiled and cached (using serialized JSON as key. [json-stable-stringify](https://github.com/substack/json-stable-stringify) is used to serialize.
* @param {String|Object} schemaKeyRef key, ref or schema object
* @param {Any} data to be validated
* @return {Boolean} validation result. Errors from the last validation will be available in `jv.errors` (and also in compiled schema: `schema.errors`).
*/
function validate(schemaKeyRef, data) {
if (typeof schemaKeyRef == 'string') {
var v = getSchema(schemaKeyRef);
if (!v) {
v = getRef(schemaKeyRef);
if (!v) throw new Error('no schema with key or ref "' + schemaKeyRef + '"');
}
} else v = _addSchema(schemaKeyRef);
var valid = v(data);
self.errors = v.errors;
return valid;
}
/**
* Create validator for passed schema.
* @param {String|Object} schema
* @return {Object} validation result { valid: true/false, errors: [...] }
*/
function compile(schema) {
return _addSchema(schema);
}
/**
* Adds schema to the instance.
* @param {Object|Array} schema schema or array of schemas. If array is passed, `key` will be ignored.
* @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`.
* @return {Function} compiled schema with method `validate` that accepts `data`.
*/
function addSchema(schema, key, _skipValidation) {
if (Array.isArray(schema))
return schema.map(function(sch) { return addSchema(sch); });
// can key/id have # inside?
var key = resolve.normalizeId(key || schema.id);
checkUnique(key);
var validate = self._schemas[key] = _addSchema(schema, _skipValidation);
return validate;
}
function validateSchema(schema) {
var $schema = schema.$schema || META_SCHEMA_ID;
return validate($schema, schema);
}
/**
* Get compiled schema from the instance by `key`.
* @param {String} key `key` that was passed to `addSchema` (or `schema.id`).
* @return {Function} schema validating function (with property `schema`).
*/
function getSchema(key) {
key = resolve.normalizeId(key);
return self._schemas[key];
}
/**
* Get compiled schema from the instance by `id`.
* @param {String} id `schema.id` or any reference in any of previously passed schemas.
* @return {Function} schema validating function (with property `schema`).
*/
function getRef(ref) {
ref = resolve.normalizeId(ref);
// TODO
return self._refs[ref];
}
function _addSchema(schema, skipValidation) {
if (typeof schema != 'object') throw new Error('schema should be object');
var str = stableStringify(schema);
if (self._byJson[str]) return self._byJson[str];
var id = resolve.normalizeId(schema.id);
if (id) checkUnique(id);
// var ok = skipValidation || self.opts.validateSchema === false
// || validateSchema(schema);
// if (!ok) throw new Error('schema is invalid');
resolve.ids.call(self, schema);
var validate = self._refs[id] = self._byJson[str] = compileSchema.call(self, schema);
return validate;
}
function addFormat(name, format) {
if (typeof format == 'string') format = new RegExp(format);
self._formats[name] = format;
}
function addInitialSchemas() {
if (self.opts.meta !== false)
addSchema(require('./refs/json-schema-draft-04.json'), META_SCHEMA_ID, true);
var optsSchemas = self.opts.schemas;
if (!optsSchemas) return;
if (Array.isArray(optsSchemas)) addSchema(optsSchemas);
else for (var key in optsSchemas) addSchema(optsSchemas[key], key);
}
function addInitialFormats() {
var optsFormats = self.opts.formats;
if (!optsFormats) return;
for (var name in optsFormats) {
var format = optsFormats[name];
addFormat(name, format);
}
}
function checkUnique(id) {
var schemaRef = self._refs[id];
if (self._schemas[id] || (schemaRef && !schemaRef.missing))
throw new Error('schema with key or id "' + id + '" already exists');
}
}