| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 | 
							- 'use strict';
 
- var resolve = require('./resolve')
 
-   , util = require('./util')
 
-   , errorClasses = require('./error_classes')
 
-   , stableStringify = require('fast-json-stable-stringify');
 
- var validateGenerator = require('../dotjs/validate');
 
- /**
 
-  * Functions below are used inside compiled validations function
 
-  */
 
- var ucs2length = util.ucs2length;
 
- var equal = require('fast-deep-equal');
 
- // this error is thrown by async schemas to return validation errors via exception
 
- var ValidationError = errorClasses.Validation;
 
- module.exports = compile;
 
- /**
 
-  * Compiles schema to validation function
 
-  * @this   Ajv
 
-  * @param  {Object} schema schema object
 
-  * @param  {Object} root object with information about the root schema for this schema
 
-  * @param  {Object} localRefs the hash of local references inside the schema (created by resolve.id), used for inline resolution
 
-  * @param  {String} baseId base ID for IDs in the schema
 
-  * @return {Function} validation function
 
-  */
 
- function compile(schema, root, localRefs, baseId) {
 
-   /* jshint validthis: true, evil: true */
 
-   /* eslint no-shadow: 0 */
 
-   var self = this
 
-     , opts = this._opts
 
-     , refVal = [ undefined ]
 
-     , refs = {}
 
-     , patterns = []
 
-     , patternsHash = {}
 
-     , defaults = []
 
-     , defaultsHash = {}
 
-     , customRules = [];
 
-   root = root || { schema: schema, refVal: refVal, refs: refs };
 
-   var c = checkCompiling.call(this, schema, root, baseId);
 
-   var compilation = this._compilations[c.index];
 
-   if (c.compiling) return (compilation.callValidate = callValidate);
 
-   var formats = this._formats;
 
-   var RULES = this.RULES;
 
-   try {
 
-     var v = localCompile(schema, root, localRefs, baseId);
 
-     compilation.validate = v;
 
-     var cv = compilation.callValidate;
 
-     if (cv) {
 
-       cv.schema = v.schema;
 
-       cv.errors = null;
 
-       cv.refs = v.refs;
 
-       cv.refVal = v.refVal;
 
-       cv.root = v.root;
 
-       cv.$async = v.$async;
 
-       if (opts.sourceCode) cv.source = v.source;
 
-     }
 
-     return v;
 
-   } finally {
 
-     endCompiling.call(this, schema, root, baseId);
 
-   }
 
-   /* @this   {*} - custom context, see passContext option */
 
-   function callValidate() {
 
-     /* jshint validthis: true */
 
-     var validate = compilation.validate;
 
-     var result = validate.apply(this, arguments);
 
-     callValidate.errors = validate.errors;
 
-     return result;
 
-   }
 
-   function localCompile(_schema, _root, localRefs, baseId) {
 
-     var isRoot = !_root || (_root && _root.schema == _schema);
 
-     if (_root.schema != root.schema)
 
-       return compile.call(self, _schema, _root, localRefs, baseId);
 
-     var $async = _schema.$async === true;
 
-     var sourceCode = validateGenerator({
 
-       isTop: true,
 
-       schema: _schema,
 
-       isRoot: isRoot,
 
-       baseId: baseId,
 
-       root: _root,
 
-       schemaPath: '',
 
-       errSchemaPath: '#',
 
-       errorPath: '""',
 
-       MissingRefError: errorClasses.MissingRef,
 
-       RULES: RULES,
 
-       validate: validateGenerator,
 
-       util: util,
 
-       resolve: resolve,
 
-       resolveRef: resolveRef,
 
-       usePattern: usePattern,
 
-       useDefault: useDefault,
 
-       useCustomRule: useCustomRule,
 
-       opts: opts,
 
-       formats: formats,
 
-       logger: self.logger,
 
-       self: self
 
-     });
 
-     sourceCode = vars(refVal, refValCode) + vars(patterns, patternCode)
 
-                    + vars(defaults, defaultCode) + vars(customRules, customRuleCode)
 
-                    + sourceCode;
 
-     if (opts.processCode) sourceCode = opts.processCode(sourceCode, _schema);
 
-     // console.log('\n\n\n *** \n', JSON.stringify(sourceCode));
 
-     var validate;
 
-     try {
 
-       var makeValidate = new Function(
 
-         'self',
 
-         'RULES',
 
-         'formats',
 
-         'root',
 
-         'refVal',
 
-         'defaults',
 
-         'customRules',
 
-         'equal',
 
-         'ucs2length',
 
-         'ValidationError',
 
-         sourceCode
 
-       );
 
-       validate = makeValidate(
 
-         self,
 
-         RULES,
 
-         formats,
 
-         root,
 
-         refVal,
 
-         defaults,
 
-         customRules,
 
-         equal,
 
-         ucs2length,
 
-         ValidationError
 
-       );
 
-       refVal[0] = validate;
 
-     } catch(e) {
 
-       self.logger.error('Error compiling schema, function code:', sourceCode);
 
-       throw e;
 
-     }
 
-     validate.schema = _schema;
 
-     validate.errors = null;
 
-     validate.refs = refs;
 
-     validate.refVal = refVal;
 
-     validate.root = isRoot ? validate : _root;
 
-     if ($async) validate.$async = true;
 
-     if (opts.sourceCode === true) {
 
-       validate.source = {
 
-         code: sourceCode,
 
-         patterns: patterns,
 
-         defaults: defaults
 
-       };
 
-     }
 
-     return validate;
 
-   }
 
-   function resolveRef(baseId, ref, isRoot) {
 
-     ref = resolve.url(baseId, ref);
 
-     var refIndex = refs[ref];
 
-     var _refVal, refCode;
 
-     if (refIndex !== undefined) {
 
-       _refVal = refVal[refIndex];
 
-       refCode = 'refVal[' + refIndex + ']';
 
-       return resolvedRef(_refVal, refCode);
 
-     }
 
-     if (!isRoot && root.refs) {
 
-       var rootRefId = root.refs[ref];
 
-       if (rootRefId !== undefined) {
 
-         _refVal = root.refVal[rootRefId];
 
-         refCode = addLocalRef(ref, _refVal);
 
-         return resolvedRef(_refVal, refCode);
 
-       }
 
-     }
 
-     refCode = addLocalRef(ref);
 
-     var v = resolve.call(self, localCompile, root, ref);
 
-     if (v === undefined) {
 
-       var localSchema = localRefs && localRefs[ref];
 
-       if (localSchema) {
 
-         v = resolve.inlineRef(localSchema, opts.inlineRefs)
 
-             ? localSchema
 
-             : compile.call(self, localSchema, root, localRefs, baseId);
 
-       }
 
-     }
 
-     if (v === undefined) {
 
-       removeLocalRef(ref);
 
-     } else {
 
-       replaceLocalRef(ref, v);
 
-       return resolvedRef(v, refCode);
 
-     }
 
-   }
 
-   function addLocalRef(ref, v) {
 
-     var refId = refVal.length;
 
-     refVal[refId] = v;
 
-     refs[ref] = refId;
 
-     return 'refVal' + refId;
 
-   }
 
-   function removeLocalRef(ref) {
 
-     delete refs[ref];
 
-   }
 
-   function replaceLocalRef(ref, v) {
 
-     var refId = refs[ref];
 
-     refVal[refId] = v;
 
-   }
 
-   function resolvedRef(refVal, code) {
 
-     return typeof refVal == 'object' || typeof refVal == 'boolean'
 
-             ? { code: code, schema: refVal, inline: true }
 
-             : { code: code, $async: refVal && !!refVal.$async };
 
-   }
 
-   function usePattern(regexStr) {
 
-     var index = patternsHash[regexStr];
 
-     if (index === undefined) {
 
-       index = patternsHash[regexStr] = patterns.length;
 
-       patterns[index] = regexStr;
 
-     }
 
-     return 'pattern' + index;
 
-   }
 
-   function useDefault(value) {
 
-     switch (typeof value) {
 
-       case 'boolean':
 
-       case 'number':
 
-         return '' + value;
 
-       case 'string':
 
-         return util.toQuotedString(value);
 
-       case 'object':
 
-         if (value === null) return 'null';
 
-         var valueStr = stableStringify(value);
 
-         var index = defaultsHash[valueStr];
 
-         if (index === undefined) {
 
-           index = defaultsHash[valueStr] = defaults.length;
 
-           defaults[index] = value;
 
-         }
 
-         return 'default' + index;
 
-     }
 
-   }
 
-   function useCustomRule(rule, schema, parentSchema, it) {
 
-     if (self._opts.validateSchema !== false) {
 
-       var deps = rule.definition.dependencies;
 
-       if (deps && !deps.every(function(keyword) {
 
-         return Object.prototype.hasOwnProperty.call(parentSchema, keyword);
 
-       }))
 
-         throw new Error('parent schema must have all required keywords: ' + deps.join(','));
 
-       var validateSchema = rule.definition.validateSchema;
 
-       if (validateSchema) {
 
-         var valid = validateSchema(schema);
 
-         if (!valid) {
 
-           var message = 'keyword schema is invalid: ' + self.errorsText(validateSchema.errors);
 
-           if (self._opts.validateSchema == 'log') self.logger.error(message);
 
-           else throw new Error(message);
 
-         }
 
-       }
 
-     }
 
-     var compile = rule.definition.compile
 
-       , inline = rule.definition.inline
 
-       , macro = rule.definition.macro;
 
-     var validate;
 
-     if (compile) {
 
-       validate = compile.call(self, schema, parentSchema, it);
 
-     } else if (macro) {
 
-       validate = macro.call(self, schema, parentSchema, it);
 
-       if (opts.validateSchema !== false) self.validateSchema(validate, true);
 
-     } else if (inline) {
 
-       validate = inline.call(self, it, rule.keyword, schema, parentSchema);
 
-     } else {
 
-       validate = rule.definition.validate;
 
-       if (!validate) return;
 
-     }
 
-     if (validate === undefined)
 
-       throw new Error('custom keyword "' + rule.keyword + '"failed to compile');
 
-     var index = customRules.length;
 
-     customRules[index] = validate;
 
-     return {
 
-       code: 'customRule' + index,
 
-       validate: validate
 
-     };
 
-   }
 
- }
 
- /**
 
-  * Checks if the schema is currently compiled
 
-  * @this   Ajv
 
-  * @param  {Object} schema schema to compile
 
-  * @param  {Object} root root object
 
-  * @param  {String} baseId base schema ID
 
-  * @return {Object} object with properties "index" (compilation index) and "compiling" (boolean)
 
-  */
 
- function checkCompiling(schema, root, baseId) {
 
-   /* jshint validthis: true */
 
-   var index = compIndex.call(this, schema, root, baseId);
 
-   if (index >= 0) return { index: index, compiling: true };
 
-   index = this._compilations.length;
 
-   this._compilations[index] = {
 
-     schema: schema,
 
-     root: root,
 
-     baseId: baseId
 
-   };
 
-   return { index: index, compiling: false };
 
- }
 
- /**
 
-  * Removes the schema from the currently compiled list
 
-  * @this   Ajv
 
-  * @param  {Object} schema schema to compile
 
-  * @param  {Object} root root object
 
-  * @param  {String} baseId base schema ID
 
-  */
 
- function endCompiling(schema, root, baseId) {
 
-   /* jshint validthis: true */
 
-   var i = compIndex.call(this, schema, root, baseId);
 
-   if (i >= 0) this._compilations.splice(i, 1);
 
- }
 
- /**
 
-  * Index of schema compilation in the currently compiled list
 
-  * @this   Ajv
 
-  * @param  {Object} schema schema to compile
 
-  * @param  {Object} root root object
 
-  * @param  {String} baseId base schema ID
 
-  * @return {Integer} compilation index
 
-  */
 
- function compIndex(schema, root, baseId) {
 
-   /* jshint validthis: true */
 
-   for (var i=0; i<this._compilations.length; i++) {
 
-     var c = this._compilations[i];
 
-     if (c.schema == schema && c.root == root && c.baseId == baseId) return i;
 
-   }
 
-   return -1;
 
- }
 
- function patternCode(i, patterns) {
 
-   return 'var pattern' + i + ' = new RegExp(' + util.toQuotedString(patterns[i]) + ');';
 
- }
 
- function defaultCode(i) {
 
-   return 'var default' + i + ' = defaults[' + i + '];';
 
- }
 
- function refValCode(i, refVal) {
 
-   return refVal[i] === undefined ? '' : 'var refVal' + i + ' = refVal[' + i + '];';
 
- }
 
- function customRuleCode(i) {
 
-   return 'var customRule' + i + ' = customRules[' + i + '];';
 
- }
 
- function vars(arr, statement) {
 
-   if (!arr.length) return '';
 
-   var code = '';
 
-   for (var i=0; i<arr.length; i++)
 
-     code += statement(i, arr);
 
-   return code;
 
- }
 
 
  |