-
-
Notifications
You must be signed in to change notification settings - Fork 866
/
async.js
165 lines (140 loc) · 4.22 KB
/
async.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
'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,
'es7.nodent': getNodent,
'regenerator': getRegenerator
};
var MODES = ['generators', 'es7.nodent', 'regenerator'];
var MODES_STR = MODES.join('/');
var regenerator, nodent;
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 getNodent() {
/* jshint evil: true */
try {
// nodent declares functions not only on the top level, it won't work in node 0.10-0.12 in strict mode
eval('(function () { "use strict"; if (true) { b(); function b() {} } })()');
if (!nodent) nodent = require('' + 'nodent')({ log: noop });
return nodentTranspile;
} catch(e) {}
}
function noop() {}
function nodentTranspile(code) {
return nodent.compile(code, '', { promises: true, sourcemap: false }).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);
}
}
}