async.js (2644B)
1 'use strict'; 2 3 var MissingRefError = require('./error_classes').MissingRef; 4 5 module.exports = compileAsync; 6 7 8 /** 9 * Creates validating function for passed schema with asynchronous loading of missing schemas. 10 * `loadSchema` option should be a function that accepts schema uri and returns promise that resolves with the schema. 11 * @this Ajv 12 * @param {Object} schema schema object 13 * @param {Boolean} meta optional true to compile meta-schema; this parameter can be skipped 14 * @param {Function} callback an optional node-style callback, it is called with 2 parameters: error (or null) and validating function. 15 * @return {Promise} promise that resolves with a validating function. 16 */ 17 function compileAsync(schema, meta, callback) { 18 /* eslint no-shadow: 0 */ 19 /* global Promise */ 20 /* jshint validthis: true */ 21 var self = this; 22 if (typeof this._opts.loadSchema != 'function') 23 throw new Error('options.loadSchema should be a function'); 24 25 if (typeof meta == 'function') { 26 callback = meta; 27 meta = undefined; 28 } 29 30 var p = loadMetaSchemaOf(schema).then(function () { 31 var schemaObj = self._addSchema(schema, undefined, meta); 32 return schemaObj.validate || _compileAsync(schemaObj); 33 }); 34 35 if (callback) { 36 p.then( 37 function(v) { callback(null, v); }, 38 callback 39 ); 40 } 41 42 return p; 43 44 45 function loadMetaSchemaOf(sch) { 46 var $schema = sch.$schema; 47 return $schema && !self.getSchema($schema) 48 ? compileAsync.call(self, { $ref: $schema }, true) 49 : Promise.resolve(); 50 } 51 52 53 function _compileAsync(schemaObj) { 54 try { return self._compile(schemaObj); } 55 catch(e) { 56 if (e instanceof MissingRefError) return loadMissingSchema(e); 57 throw e; 58 } 59 60 61 function loadMissingSchema(e) { 62 var ref = e.missingSchema; 63 if (added(ref)) throw new Error('Schema ' + ref + ' is loaded but ' + e.missingRef + ' cannot be resolved'); 64 65 var schemaPromise = self._loadingSchemas[ref]; 66 if (!schemaPromise) { 67 schemaPromise = self._loadingSchemas[ref] = self._opts.loadSchema(ref); 68 schemaPromise.then(removePromise, removePromise); 69 } 70 71 return schemaPromise.then(function (sch) { 72 if (!added(ref)) { 73 return loadMetaSchemaOf(sch).then(function () { 74 if (!added(ref)) self.addSchema(sch, ref, undefined, meta); 75 }); 76 } 77 }).then(function() { 78 return _compileAsync(schemaObj); 79 }); 80 81 function removePromise() { 82 delete self._loadingSchemas[ref]; 83 } 84 85 function added(ref) { 86 return self._refs[ref] || self._schemas[ref]; 87 } 88 } 89 } 90 }