Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
81160 views
1
"use strict";
2
module.exports = function(Promise, INTERNAL) {
3
var THIS = {};
4
var util = require("./util.js");
5
var nodebackForPromise = require("./promise_resolver.js")
6
._nodebackForPromise;
7
var withAppended = util.withAppended;
8
var maybeWrapAsError = util.maybeWrapAsError;
9
var canEvaluate = util.canEvaluate;
10
var TypeError = require("./errors").TypeError;
11
var defaultSuffix = "Async";
12
var defaultPromisified = {__isPromisified__: true};
13
var noCopyPropsPattern =
14
/^(?:length|name|arguments|caller|callee|prototype|__isPromisified__)$/;
15
var defaultFilter = function(name, func) {
16
return util.isIdentifier(name) &&
17
name.charAt(0) !== "_" &&
18
!util.isClass(func);
19
};
20
21
function propsFilter(key) {
22
return !noCopyPropsPattern.test(key);
23
}
24
25
function isPromisified(fn) {
26
try {
27
return fn.__isPromisified__ === true;
28
}
29
catch (e) {
30
return false;
31
}
32
}
33
34
function hasPromisified(obj, key, suffix) {
35
var val = util.getDataPropertyOrDefault(obj, key + suffix,
36
defaultPromisified);
37
return val ? isPromisified(val) : false;
38
}
39
function checkValid(ret, suffix, suffixRegexp) {
40
for (var i = 0; i < ret.length; i += 2) {
41
var key = ret[i];
42
if (suffixRegexp.test(key)) {
43
var keyWithoutAsyncSuffix = key.replace(suffixRegexp, "");
44
for (var j = 0; j < ret.length; j += 2) {
45
if (ret[j] === keyWithoutAsyncSuffix) {
46
throw new TypeError("Cannot promisify an API that has normal methods with '%s'-suffix\u000a\u000a See http://goo.gl/iWrZbw\u000a"
47
.replace("%s", suffix));
48
}
49
}
50
}
51
}
52
}
53
54
function promisifiableMethods(obj, suffix, suffixRegexp, filter) {
55
var keys = util.inheritedDataKeys(obj);
56
var ret = [];
57
for (var i = 0; i < keys.length; ++i) {
58
var key = keys[i];
59
var value = obj[key];
60
var passesDefaultFilter = filter === defaultFilter
61
? true : defaultFilter(key, value, obj);
62
if (typeof value === "function" &&
63
!isPromisified(value) &&
64
!hasPromisified(obj, key, suffix) &&
65
filter(key, value, obj, passesDefaultFilter)) {
66
ret.push(key, value);
67
}
68
}
69
checkValid(ret, suffix, suffixRegexp);
70
return ret;
71
}
72
73
var escapeIdentRegex = function(str) {
74
return str.replace(/([$])/, "\\$");
75
};
76
77
var makeNodePromisifiedEval;
78
if (!false) {
79
var switchCaseArgumentOrder = function(likelyArgumentCount) {
80
var ret = [likelyArgumentCount];
81
var min = Math.max(0, likelyArgumentCount - 1 - 3);
82
for(var i = likelyArgumentCount - 1; i >= min; --i) {
83
ret.push(i);
84
}
85
for(var i = likelyArgumentCount + 1; i <= 3; ++i) {
86
ret.push(i);
87
}
88
return ret;
89
};
90
91
var argumentSequence = function(argumentCount) {
92
return util.filledRange(argumentCount, "_arg", "");
93
};
94
95
var parameterDeclaration = function(parameterCount) {
96
return util.filledRange(
97
Math.max(parameterCount, 3), "_arg", "");
98
};
99
100
var parameterCount = function(fn) {
101
if (typeof fn.length === "number") {
102
return Math.max(Math.min(fn.length, 1023 + 1), 0);
103
}
104
return 0;
105
};
106
107
makeNodePromisifiedEval =
108
function(callback, receiver, originalName, fn) {
109
var newParameterCount = Math.max(0, parameterCount(fn) - 1);
110
var argumentOrder = switchCaseArgumentOrder(newParameterCount);
111
var shouldProxyThis = typeof callback === "string" || receiver === THIS;
112
113
function generateCallForArgumentCount(count) {
114
var args = argumentSequence(count).join(", ");
115
var comma = count > 0 ? ", " : "";
116
var ret;
117
if (shouldProxyThis) {
118
ret = "ret = callback.call(this, {{args}}, nodeback); break;\n";
119
} else {
120
ret = receiver === undefined
121
? "ret = callback({{args}}, nodeback); break;\n"
122
: "ret = callback.call(receiver, {{args}}, nodeback); break;\n";
123
}
124
return ret.replace("{{args}}", args).replace(", ", comma);
125
}
126
127
function generateArgumentSwitchCase() {
128
var ret = "";
129
for (var i = 0; i < argumentOrder.length; ++i) {
130
ret += "case " + argumentOrder[i] +":" +
131
generateCallForArgumentCount(argumentOrder[i]);
132
}
133
134
ret += " \n\
135
default: \n\
136
var args = new Array(len + 1); \n\
137
var i = 0; \n\
138
for (var i = 0; i < len; ++i) { \n\
139
args[i] = arguments[i]; \n\
140
} \n\
141
args[i] = nodeback; \n\
142
[CodeForCall] \n\
143
break; \n\
144
".replace("[CodeForCall]", (shouldProxyThis
145
? "ret = callback.apply(this, args);\n"
146
: "ret = callback.apply(receiver, args);\n"));
147
return ret;
148
}
149
150
var getFunctionCode = typeof callback === "string"
151
? ("this != null ? this['"+callback+"'] : fn")
152
: "fn";
153
154
return new Function("Promise",
155
"fn",
156
"receiver",
157
"withAppended",
158
"maybeWrapAsError",
159
"nodebackForPromise",
160
"tryCatch",
161
"errorObj",
162
"INTERNAL","'use strict'; \n\
163
var ret = function (Parameters) { \n\
164
'use strict'; \n\
165
var len = arguments.length; \n\
166
var promise = new Promise(INTERNAL); \n\
167
promise._captureStackTrace(); \n\
168
var nodeback = nodebackForPromise(promise); \n\
169
var ret; \n\
170
var callback = tryCatch([GetFunctionCode]); \n\
171
switch(len) { \n\
172
[CodeForSwitchCase] \n\
173
} \n\
174
if (ret === errorObj) { \n\
175
promise._rejectCallback(maybeWrapAsError(ret.e), true, true);\n\
176
} \n\
177
return promise; \n\
178
}; \n\
179
ret.__isPromisified__ = true; \n\
180
return ret; \n\
181
"
182
.replace("Parameters", parameterDeclaration(newParameterCount))
183
.replace("[CodeForSwitchCase]", generateArgumentSwitchCase())
184
.replace("[GetFunctionCode]", getFunctionCode))(
185
Promise,
186
fn,
187
receiver,
188
withAppended,
189
maybeWrapAsError,
190
nodebackForPromise,
191
util.tryCatch,
192
util.errorObj,
193
INTERNAL
194
);
195
};
196
}
197
198
function makeNodePromisifiedClosure(callback, receiver, _, fn) {
199
var defaultThis = (function() {return this;})();
200
var method = callback;
201
if (typeof method === "string") {
202
callback = fn;
203
}
204
function promisified() {
205
var _receiver = receiver;
206
if (receiver === THIS) _receiver = this;
207
var promise = new Promise(INTERNAL);
208
promise._captureStackTrace();
209
var cb = typeof method === "string" && this !== defaultThis
210
? this[method] : callback;
211
var fn = nodebackForPromise(promise);
212
try {
213
cb.apply(_receiver, withAppended(arguments, fn));
214
} catch(e) {
215
promise._rejectCallback(maybeWrapAsError(e), true, true);
216
}
217
return promise;
218
}
219
promisified.__isPromisified__ = true;
220
return promisified;
221
}
222
223
var makeNodePromisified = canEvaluate
224
? makeNodePromisifiedEval
225
: makeNodePromisifiedClosure;
226
227
function promisifyAll(obj, suffix, filter, promisifier) {
228
var suffixRegexp = new RegExp(escapeIdentRegex(suffix) + "$");
229
var methods =
230
promisifiableMethods(obj, suffix, suffixRegexp, filter);
231
232
for (var i = 0, len = methods.length; i < len; i+= 2) {
233
var key = methods[i];
234
var fn = methods[i+1];
235
var promisifiedKey = key + suffix;
236
obj[promisifiedKey] = promisifier === makeNodePromisified
237
? makeNodePromisified(key, THIS, key, fn, suffix)
238
: promisifier(fn, function() {
239
return makeNodePromisified(key, THIS, key, fn, suffix);
240
});
241
}
242
util.toFastProperties(obj);
243
return obj;
244
}
245
246
function promisify(callback, receiver) {
247
return makeNodePromisified(callback, receiver, undefined, callback);
248
}
249
250
Promise.promisify = function (fn, receiver) {
251
if (typeof fn !== "function") {
252
throw new TypeError("fn must be a function\u000a\u000a See http://goo.gl/916lJJ\u000a");
253
}
254
if (isPromisified(fn)) {
255
return fn;
256
}
257
var ret = promisify(fn, arguments.length < 2 ? THIS : receiver);
258
util.copyDescriptors(fn, ret, propsFilter);
259
return ret;
260
};
261
262
Promise.promisifyAll = function (target, options) {
263
if (typeof target !== "function" && typeof target !== "object") {
264
throw new TypeError("the target of promisifyAll must be an object or a function\u000a\u000a See http://goo.gl/9ITlV0\u000a");
265
}
266
options = Object(options);
267
var suffix = options.suffix;
268
if (typeof suffix !== "string") suffix = defaultSuffix;
269
var filter = options.filter;
270
if (typeof filter !== "function") filter = defaultFilter;
271
var promisifier = options.promisifier;
272
if (typeof promisifier !== "function") promisifier = makeNodePromisified;
273
274
if (!util.isIdentifier(suffix)) {
275
throw new RangeError("suffix must be a valid identifier\u000a\u000a See http://goo.gl/8FZo5V\u000a");
276
}
277
278
var keys = util.inheritedDataKeys(target);
279
for (var i = 0; i < keys.length; ++i) {
280
var value = target[keys[i]];
281
if (keys[i] !== "constructor" &&
282
util.isClass(value)) {
283
promisifyAll(value.prototype, suffix, filter, promisifier);
284
promisifyAll(value, suffix, filter, promisifier);
285
}
286
}
287
288
return promisifyAll(target, suffix, filter, promisifier);
289
};
290
};
291
292
293