.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / ajv / lib / compile / index.js
1 'use strict';
2
3 var resolve = require('./resolve')
4   , util = require('./util')
5   , errorClasses = require('./error_classes')
6   , stableStringify = require('fast-json-stable-stringify');
7
8 var validateGenerator = require('../dotjs/validate');
9
10 /**
11  * Functions below are used inside compiled validations function
12  */
13
14 var ucs2length = util.ucs2length;
15 var equal = require('fast-deep-equal');
16
17 // this error is thrown by async schemas to return validation errors via exception
18 var ValidationError = errorClasses.Validation;
19
20 module.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  */
32 function 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  */
315 function 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  */
336 function 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  */
351 function 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
361 function patternCode(i, patterns) {
362   return 'var pattern' + i + ' = new RegExp(' + util.toQuotedString(patterns[i]) + ');';
363 }
364
365
366 function defaultCode(i) {
367   return 'var default' + i + ' = defaults[' + i + '];';
368 }
369
370
371 function refValCode(i, refVal) {
372   return refVal[i] === undefined ? '' : 'var refVal' + i + ' = refVal[' + i + '];';
373 }
374
375
376 function customRuleCode(i) {
377   return 'var customRule' + i + ' = customRules[' + i + '];';
378 }
379
380
381 function 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 }