source: frontend/node_modules/ajv/lib/compile/index.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 10.6 KB
Line 
1'use strict';
2
3var resolve = require('./resolve')
4 , util = require('./util')
5 , errorClasses = require('./error_classes')
6 , stableStringify = require('fast-json-stable-stringify');
7
8var validateGenerator = require('../dotjs/validate');
9
10/**
11 * Functions below are used inside compiled validations function
12 */
13
14var ucs2length = util.ucs2length;
15var equal = require('fast-deep-equal');
16
17// this error is thrown by async schemas to return validation errors via exception
18var ValidationError = errorClasses.Validation;
19
20module.exports = compile;
21
22
23/**
24 * Compiles schema to validation function
25 * @this Ajv
26 * @param {Object} schema schema object
27 * @param {Object} root object with information about the root schema for this schema
28 * @param {Object} localRefs the hash of local references inside the schema (created by resolve.id), used for inline resolution
29 * @param {String} baseId base ID for IDs in the schema
30 * @return {Function} validation function
31 */
32function compile(schema, root, localRefs, baseId) {
33 /* jshint validthis: true, evil: true */
34 /* eslint no-shadow: 0 */
35 var self = this
36 , opts = this._opts
37 , refVal = [ undefined ]
38 , refs = {}
39 , patterns = []
40 , patternsHash = {}
41 , defaults = []
42 , defaultsHash = {}
43 , customRules = [];
44
45 function patternCode(i, patterns) {
46 var regExpCode = opts.regExp ? 'regExp' : 'new RegExp';
47 return 'var pattern' + i + ' = ' + regExpCode + '(' + util.toQuotedString(patterns[i]) + ');';
48 }
49
50 root = root || { schema: schema, refVal: refVal, refs: refs };
51
52 var c = checkCompiling.call(this, schema, root, baseId);
53 var compilation = this._compilations[c.index];
54 if (c.compiling) return (compilation.callValidate = callValidate);
55
56 var formats = this._formats;
57 var RULES = this.RULES;
58
59 try {
60 var v = localCompile(schema, root, localRefs, baseId);
61 compilation.validate = v;
62 var cv = compilation.callValidate;
63 if (cv) {
64 cv.schema = v.schema;
65 cv.errors = null;
66 cv.refs = v.refs;
67 cv.refVal = v.refVal;
68 cv.root = v.root;
69 cv.$async = v.$async;
70 if (opts.sourceCode) cv.source = v.source;
71 }
72 return v;
73 } finally {
74 endCompiling.call(this, schema, root, baseId);
75 }
76
77 /* @this {*} - custom context, see passContext option */
78 function callValidate() {
79 /* jshint validthis: true */
80 var validate = compilation.validate;
81 var result = validate.apply(this, arguments);
82 callValidate.errors = validate.errors;
83 return result;
84 }
85
86 function localCompile(_schema, _root, localRefs, baseId) {
87 var isRoot = !_root || (_root && _root.schema == _schema);
88 if (_root.schema != root.schema)
89 return compile.call(self, _schema, _root, localRefs, baseId);
90
91 var $async = _schema.$async === true;
92
93 var sourceCode = validateGenerator({
94 isTop: true,
95 schema: _schema,
96 isRoot: isRoot,
97 baseId: baseId,
98 root: _root,
99 schemaPath: '',
100 errSchemaPath: '#',
101 errorPath: '""',
102 MissingRefError: errorClasses.MissingRef,
103 RULES: RULES,
104 validate: validateGenerator,
105 util: util,
106 resolve: resolve,
107 resolveRef: resolveRef,
108 usePattern: usePattern,
109 useDefault: useDefault,
110 useCustomRule: useCustomRule,
111 opts: opts,
112 formats: formats,
113 logger: self.logger,
114 self: self
115 });
116
117 sourceCode = vars(refVal, refValCode) + vars(patterns, patternCode)
118 + vars(defaults, defaultCode) + vars(customRules, customRuleCode)
119 + sourceCode;
120
121 if (opts.processCode) sourceCode = opts.processCode(sourceCode, _schema);
122 // console.log('\n\n\n *** \n', JSON.stringify(sourceCode));
123 var validate;
124 try {
125 var makeValidate = new Function(
126 'self',
127 'RULES',
128 'formats',
129 'root',
130 'refVal',
131 'defaults',
132 'customRules',
133 'equal',
134 'ucs2length',
135 'ValidationError',
136 'regExp',
137 sourceCode
138 );
139
140 validate = makeValidate(
141 self,
142 RULES,
143 formats,
144 root,
145 refVal,
146 defaults,
147 customRules,
148 equal,
149 ucs2length,
150 ValidationError,
151 opts.regExp
152 );
153
154 refVal[0] = validate;
155 } catch(e) {
156 self.logger.error('Error compiling schema, function code:', sourceCode);
157 throw e;
158 }
159
160 validate.schema = _schema;
161 validate.errors = null;
162 validate.refs = refs;
163 validate.refVal = refVal;
164 validate.root = isRoot ? validate : _root;
165 if ($async) validate.$async = true;
166 if (opts.sourceCode === true) {
167 validate.source = {
168 code: sourceCode,
169 patterns: patterns,
170 defaults: defaults
171 };
172 }
173
174 return validate;
175 }
176
177 function resolveRef(baseId, ref, isRoot) {
178 ref = resolve.url(baseId, ref);
179 var refIndex = refs[ref];
180 var _refVal, refCode;
181 if (refIndex !== undefined) {
182 _refVal = refVal[refIndex];
183 refCode = 'refVal[' + refIndex + ']';
184 return resolvedRef(_refVal, refCode);
185 }
186 if (!isRoot && root.refs) {
187 var rootRefId = root.refs[ref];
188 if (rootRefId !== undefined) {
189 _refVal = root.refVal[rootRefId];
190 refCode = addLocalRef(ref, _refVal);
191 return resolvedRef(_refVal, refCode);
192 }
193 }
194
195 refCode = addLocalRef(ref);
196 var v = resolve.call(self, localCompile, root, ref);
197 if (v === undefined) {
198 var localSchema = localRefs && localRefs[ref];
199 if (localSchema) {
200 v = resolve.inlineRef(localSchema, opts.inlineRefs)
201 ? localSchema
202 : compile.call(self, localSchema, root, localRefs, baseId);
203 }
204 }
205
206 if (v === undefined) {
207 removeLocalRef(ref);
208 } else {
209 replaceLocalRef(ref, v);
210 return resolvedRef(v, refCode);
211 }
212 }
213
214 function addLocalRef(ref, v) {
215 var refId = refVal.length;
216 refVal[refId] = v;
217 refs[ref] = refId;
218 return 'refVal' + refId;
219 }
220
221 function removeLocalRef(ref) {
222 delete refs[ref];
223 }
224
225 function replaceLocalRef(ref, v) {
226 var refId = refs[ref];
227 refVal[refId] = v;
228 }
229
230 function resolvedRef(refVal, code) {
231 return typeof refVal == 'object' || typeof refVal == 'boolean'
232 ? { code: code, schema: refVal, inline: true }
233 : { code: code, $async: refVal && !!refVal.$async };
234 }
235
236 function usePattern(regexStr) {
237 var index = patternsHash[regexStr];
238 if (index === undefined) {
239 index = patternsHash[regexStr] = patterns.length;
240 patterns[index] = regexStr;
241 }
242 return 'pattern' + index;
243 }
244
245 function useDefault(value) {
246 switch (typeof value) {
247 case 'boolean':
248 case 'number':
249 return '' + value;
250 case 'string':
251 return util.toQuotedString(value);
252 case 'object':
253 if (value === null) return 'null';
254 var valueStr = stableStringify(value);
255 var index = defaultsHash[valueStr];
256 if (index === undefined) {
257 index = defaultsHash[valueStr] = defaults.length;
258 defaults[index] = value;
259 }
260 return 'default' + index;
261 }
262 }
263
264 function useCustomRule(rule, schema, parentSchema, it) {
265 if (self._opts.validateSchema !== false) {
266 var deps = rule.definition.dependencies;
267 if (deps && !deps.every(function(keyword) {
268 return Object.prototype.hasOwnProperty.call(parentSchema, keyword);
269 }))
270 throw new Error('parent schema must have all required keywords: ' + deps.join(','));
271
272 var validateSchema = rule.definition.validateSchema;
273 if (validateSchema) {
274 var valid = validateSchema(schema);
275 if (!valid) {
276 var message = 'keyword schema is invalid: ' + self.errorsText(validateSchema.errors);
277 if (self._opts.validateSchema == 'log') self.logger.error(message);
278 else throw new Error(message);
279 }
280 }
281 }
282
283 var compile = rule.definition.compile
284 , inline = rule.definition.inline
285 , macro = rule.definition.macro;
286
287 var validate;
288 if (compile) {
289 validate = compile.call(self, schema, parentSchema, it);
290 } else if (macro) {
291 validate = macro.call(self, schema, parentSchema, it);
292 if (opts.validateSchema !== false) self.validateSchema(validate, true);
293 } else if (inline) {
294 validate = inline.call(self, it, rule.keyword, schema, parentSchema);
295 } else {
296 validate = rule.definition.validate;
297 if (!validate) return;
298 }
299
300 if (validate === undefined)
301 throw new Error('custom keyword "' + rule.keyword + '"failed to compile');
302
303 var index = customRules.length;
304 customRules[index] = validate;
305
306 return {
307 code: 'customRule' + index,
308 validate: validate
309 };
310 }
311}
312
313
314/**
315 * Checks if the schema is currently compiled
316 * @this Ajv
317 * @param {Object} schema schema to compile
318 * @param {Object} root root object
319 * @param {String} baseId base schema ID
320 * @return {Object} object with properties "index" (compilation index) and "compiling" (boolean)
321 */
322function checkCompiling(schema, root, baseId) {
323 /* jshint validthis: true */
324 var index = compIndex.call(this, schema, root, baseId);
325 if (index >= 0) return { index: index, compiling: true };
326 index = this._compilations.length;
327 this._compilations[index] = {
328 schema: schema,
329 root: root,
330 baseId: baseId
331 };
332 return { index: index, compiling: false };
333}
334
335
336/**
337 * Removes the schema from the currently compiled list
338 * @this Ajv
339 * @param {Object} schema schema to compile
340 * @param {Object} root root object
341 * @param {String} baseId base schema ID
342 */
343function endCompiling(schema, root, baseId) {
344 /* jshint validthis: true */
345 var i = compIndex.call(this, schema, root, baseId);
346 if (i >= 0) this._compilations.splice(i, 1);
347}
348
349
350/**
351 * Index of schema compilation in the currently compiled list
352 * @this Ajv
353 * @param {Object} schema schema to compile
354 * @param {Object} root root object
355 * @param {String} baseId base schema ID
356 * @return {Integer} compilation index
357 */
358function compIndex(schema, root, baseId) {
359 /* jshint validthis: true */
360 for (var i=0; i<this._compilations.length; i++) {
361 var c = this._compilations[i];
362 if (c.schema == schema && c.root == root && c.baseId == baseId) return i;
363 }
364 return -1;
365}
366
367
368function defaultCode(i) {
369 return 'var default' + i + ' = defaults[' + i + '];';
370}
371
372
373function refValCode(i, refVal) {
374 return refVal[i] === undefined ? '' : 'var refVal' + i + ' = refVal[' + i + '];';
375}
376
377
378function customRuleCode(i) {
379 return 'var customRule' + i + ' = customRules[' + i + '];';
380}
381
382
383function vars(arr, statement) {
384 if (!arr.length) return '';
385 var code = '';
386 for (var i=0; i<arr.length; i++)
387 code += statement(i, arr);
388 return code;
389}
Note: See TracBrowser for help on using the repository browser.