146 lines
3.7 KiB
JavaScript
146 lines
3.7 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* Create validating function for passed schema with asynchronous loading of missing schemas.
|
|
* `loadSchema` option should be a function that accepts schema uri and node-style callback.
|
|
* @param {String|Object} schema
|
|
* @param {Function} callback node-style callback, it is always called with 2 parameters: error (or null) and validating function.
|
|
*/
|
|
module.exports = {
|
|
setTranspile: setTranspile,
|
|
compile: compileAsync
|
|
};
|
|
|
|
|
|
var ASYNC = {
|
|
generators: generatorsSupported,
|
|
regenerator: getRegenerator
|
|
};
|
|
var MODES = ['generators', 'regenerator'];
|
|
var MODES_STR = MODES.join('/');
|
|
var regenerator;
|
|
|
|
|
|
function setTranspile(opts) {
|
|
var mode = opts.async;
|
|
var get = ASYNC[mode];
|
|
var transpile;
|
|
if (get) {
|
|
transpile = opts.transpile = get();
|
|
if (transpile) return transpile;
|
|
} else {
|
|
for (var i=0; i<MODES.length; i++) {
|
|
mode = MODES[i];
|
|
get = ASYNC[mode];
|
|
transpile = get();
|
|
if (transpile) {
|
|
opts.async = mode;
|
|
opts.transpile = transpile;
|
|
return transpile;
|
|
}
|
|
}
|
|
mode = MODES_STR;
|
|
}
|
|
|
|
throw new Error(mode + ' not available');
|
|
}
|
|
|
|
|
|
function generatorsSupported() {
|
|
/* jshint evil: true */
|
|
try { eval("(function*(){})()"); return true; }
|
|
catch(e) {}
|
|
}
|
|
|
|
|
|
function getRegenerator() {
|
|
try {
|
|
if (!regenerator) {
|
|
regenerator = require('' + 'regenerator');
|
|
regenerator.runtime();
|
|
}
|
|
return regeneratorTranspile;
|
|
} catch(e) {}
|
|
}
|
|
|
|
|
|
function regeneratorTranspile(code) {
|
|
return regenerator.compile(code).code;
|
|
}
|
|
|
|
|
|
function compileAsync(schema, callback) {
|
|
/* jshint validthis: true */
|
|
var schemaObj;
|
|
var self = this;
|
|
try {
|
|
schemaObj = this._addSchema(schema);
|
|
} catch(e) {
|
|
setTimeout(function() { callback(e); });
|
|
return;
|
|
}
|
|
if (schemaObj.validate)
|
|
setTimeout(function() { callback(null, schemaObj.validate); });
|
|
else {
|
|
if (typeof this._opts.loadSchema != 'function')
|
|
throw new Error('options.loadSchema should be a function');
|
|
_compileAsync(schema, callback, true);
|
|
}
|
|
|
|
|
|
function _compileAsync(schema, callback, firstCall) {
|
|
var validate;
|
|
try { validate = self.compile(schema); }
|
|
catch(e) {
|
|
if (e.missingSchema) loadMissingSchema(e);
|
|
else deferCallback(e);
|
|
return;
|
|
}
|
|
deferCallback(null, validate);
|
|
|
|
function loadMissingSchema(e) {
|
|
var ref = e.missingSchema;
|
|
if (self._refs[ref] || self._schemas[ref])
|
|
return callback(new Error('Schema ' + ref + ' is loaded but' + e.missingRef + 'cannot be resolved'));
|
|
var _callbacks = self._loadingSchemas[ref];
|
|
if (_callbacks) {
|
|
if (typeof _callbacks == 'function')
|
|
self._loadingSchemas[ref] = [_callbacks, schemaLoaded];
|
|
else
|
|
_callbacks[_callbacks.length] = schemaLoaded;
|
|
} else {
|
|
self._loadingSchemas[ref] = schemaLoaded;
|
|
self._opts.loadSchema(ref, function (err, sch) {
|
|
var _callbacks = self._loadingSchemas[ref];
|
|
delete self._loadingSchemas[ref];
|
|
if (typeof _callbacks == 'function')
|
|
_callbacks(err, sch);
|
|
else
|
|
for (var i=0; i<_callbacks.length; i++)
|
|
_callbacks[i](err, sch);
|
|
});
|
|
}
|
|
|
|
function schemaLoaded(err, sch) {
|
|
if (err) callback(err);
|
|
else {
|
|
if (!(self._refs[ref] || self._schemas[ref])) {
|
|
try {
|
|
self.addSchema(sch, ref);
|
|
} catch(e) {
|
|
callback(e);
|
|
return;
|
|
}
|
|
}
|
|
_compileAsync(schema, callback);
|
|
}
|
|
}
|
|
}
|
|
|
|
function deferCallback(err, validate) {
|
|
if (firstCall) setTimeout(function() { callback(err, validate); });
|
|
else callback(err, validate);
|
|
}
|
|
}
|
|
}
|