Initial commit
[yaffs-website] / node_modules / ajv / lib / async.js
1 'use strict';
2
3 module.exports = {
4   setup: setupAsync,
5   compile: compileAsync
6 };
7
8
9 var util = require('./compile/util');
10
11 var ASYNC = {
12   '*': checkGenerators,
13   'co*': checkGenerators,
14   'es7': checkAsyncFunction
15 };
16
17 var TRANSPILE = {
18   'nodent': getNodent,
19   'regenerator': getRegenerator
20 };
21
22 var MODES = [
23   { async: 'co*' },
24   { async: 'es7', transpile: 'nodent' },
25   { async: 'co*', transpile: 'regenerator' }
26 ];
27
28
29 var regenerator, nodent;
30
31
32 function setupAsync(opts, required) {
33   if (required !== false) required = true;
34   var async = opts.async
35     , transpile = opts.transpile
36     , check;
37
38   switch (typeof transpile) {
39     case 'string':
40       var get = TRANSPILE[transpile];
41       if (!get) throw new Error('bad transpiler: ' + transpile);
42       return (opts._transpileFunc = get(opts, required));
43     case 'undefined':
44     case 'boolean':
45       if (typeof async == 'string') {
46         check = ASYNC[async];
47         if (!check) throw new Error('bad async mode: ' + async);
48         return (opts.transpile = check(opts, required));
49       }
50
51       for (var i=0; i<MODES.length; i++) {
52         var _opts = MODES[i];
53         if (setupAsync(_opts, false)) {
54           util.copy(_opts, opts);
55           return opts.transpile;
56         }
57       }
58       /* istanbul ignore next */
59       throw new Error('generators, nodent and regenerator are not available');
60     case 'function':
61       return (opts._transpileFunc = opts.transpile);
62     default:
63       throw new Error('bad transpiler: ' + transpile);
64   }
65 }
66
67
68 function checkGenerators(opts, required) {
69   /* jshint evil: true */
70   try {
71     (new Function('(function*(){})()'))();
72     return true;
73   } catch(e) {
74     /* istanbul ignore next */
75     if (required) throw new Error('generators not supported');
76   }
77 }
78
79
80 function checkAsyncFunction(opts, required) {
81   /* jshint evil: true */
82   try {
83     (new Function('(async function(){})()'))();
84     /* istanbul ignore next */
85     return true;
86   } catch(e) {
87     if (required) throw new Error('es7 async functions not supported');
88   }
89 }
90
91
92 function getRegenerator(opts, required) {
93   try {
94     if (!regenerator) {
95       var name = 'regenerator';
96       regenerator = require(name);
97       regenerator.runtime();
98     }
99     if (!opts.async || opts.async === true)
100       opts.async = 'es7';
101     return regeneratorTranspile;
102   } catch(e) {
103     /* istanbul ignore next */
104     if (required) throw new Error('regenerator not available');
105   }
106 }
107
108
109 function regeneratorTranspile(code) {
110   return regenerator.compile(code).code;
111 }
112
113
114 function getNodent(opts, required) {
115   /* jshint evil: true */
116   try {
117     if (!nodent) {
118       var name = 'nodent';
119       nodent = require(name)({ log: false, dontInstallRequireHook: true });
120     }
121     if (opts.async != 'es7') {
122       if (opts.async && opts.async !== true) console.warn('nodent transpiles only es7 async functions');
123       opts.async = 'es7';
124     }
125     return nodentTranspile;
126   } catch(e) {
127     /* istanbul ignore next */
128     if (required) throw new Error('nodent not available');
129   }
130 }
131
132
133 function nodentTranspile(code) {
134   return nodent.compile(code, '', { promises: true, sourcemap: false }).code;
135 }
136
137
138 /**
139  * Creates validating function for passed schema with asynchronous loading of missing schemas.
140  * `loadSchema` option should be a function that accepts schema uri and node-style callback.
141  * @this  Ajv
142  * @param {Object}   schema schema object
143  * @param {Function} callback node-style callback, it is always called with 2 parameters: error (or null) and validating function.
144  */
145 function compileAsync(schema, callback) {
146   /* eslint no-shadow: 0 */
147   /* jshint validthis: true */
148   var schemaObj;
149   var self = this;
150   try {
151     schemaObj = this._addSchema(schema);
152   } catch(e) {
153     setTimeout(function() { callback(e); });
154     return;
155   }
156   if (schemaObj.validate) {
157     setTimeout(function() { callback(null, schemaObj.validate); });
158   } else {
159     if (typeof this._opts.loadSchema != 'function')
160       throw new Error('options.loadSchema should be a function');
161     _compileAsync(schema, callback, true);
162   }
163
164
165   function _compileAsync(schema, callback, firstCall) {
166     var validate;
167     try { validate = self.compile(schema); }
168     catch(e) {
169       if (e.missingSchema) loadMissingSchema(e);
170       else deferCallback(e);
171       return;
172     }
173     deferCallback(null, validate);
174
175     function loadMissingSchema(e) {
176       var ref = e.missingSchema;
177       if (self._refs[ref] || self._schemas[ref])
178         return callback(new Error('Schema ' + ref + ' is loaded but ' + e.missingRef + ' cannot be resolved'));
179       var _callbacks = self._loadingSchemas[ref];
180       if (_callbacks) {
181         if (typeof _callbacks == 'function')
182           self._loadingSchemas[ref] = [_callbacks, schemaLoaded];
183         else
184           _callbacks[_callbacks.length] = schemaLoaded;
185       } else {
186         self._loadingSchemas[ref] = schemaLoaded;
187         self._opts.loadSchema(ref, function (err, sch) {
188           var _callbacks = self._loadingSchemas[ref];
189           delete self._loadingSchemas[ref];
190           if (typeof _callbacks == 'function') {
191             _callbacks(err, sch);
192           } else {
193             for (var i=0; i<_callbacks.length; i++)
194               _callbacks[i](err, sch);
195           }
196         });
197       }
198
199       function schemaLoaded(err, sch) {
200         if (err) return callback(err);
201         if (!(self._refs[ref] || self._schemas[ref])) {
202           try {
203             self.addSchema(sch, ref);
204           } catch(e) {
205             callback(e);
206             return;
207           }
208         }
209         _compileAsync(schema, callback);
210       }
211     }
212
213     function deferCallback(err, validate) {
214       if (firstCall) setTimeout(function() { callback(err, validate); });
215       else return callback(err, validate);
216     }
217   }
218 }