source: imaps-frontend/node_modules/ajv/lib/compile/index.js@ d565449

main
Last change on this file since d565449 was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

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