|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"use strict"; |
|
module.exports = function(Promise, INTERNAL) { |
|
var THIS = {}; |
|
var util = require("./util.js"); |
|
var es5 = require("./es5.js"); |
|
var nodebackForPromise = require("./promise_resolver.js") |
|
._nodebackForPromise; |
|
var withAppended = util.withAppended; |
|
var maybeWrapAsError = util.maybeWrapAsError; |
|
var canEvaluate = util.canEvaluate; |
|
var notEnumerableProp = util.notEnumerableProp; |
|
var deprecated = util.deprecated; |
|
var ASSERT = require("./assert.js"); |
|
|
|
|
|
var roriginal = new RegExp("__beforePromisified__" + "$"); |
|
var hasProp = {}.hasOwnProperty; |
|
function isPromisified(fn) { |
|
return fn.__isPromisified__ === true; |
|
} |
|
var inheritedMethods = (function() { |
|
if (es5.isES5) { |
|
var create = Object.create; |
|
var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; |
|
return function(cur) { |
|
var original = cur; |
|
var ret = []; |
|
var visitedKeys = create(null); |
|
while (cur !== null) { |
|
var keys = es5.keys(cur); |
|
for (var i = 0, len = keys.length; i < len; ++i) { |
|
var key = keys[i]; |
|
if (visitedKeys[key] || |
|
roriginal.test(key) || |
|
hasProp.call(original, key + "__beforePromisified__") |
|
) { |
|
continue; |
|
} |
|
visitedKeys[key] = true; |
|
var desc = getOwnPropertyDescriptor(cur, key); |
|
if (desc != null && |
|
typeof desc.value === "function" && |
|
!isPromisified(desc.value)) { |
|
ret.push(key, desc.value); |
|
} |
|
} |
|
cur = es5.getPrototypeOf(cur); |
|
} |
|
return ret; |
|
}; |
|
} |
|
else { |
|
return function(obj) { |
|
var ret = []; |
|
|
|
for (var key in obj) { |
|
if (roriginal.test(key) || |
|
hasProp.call(obj, key + "__beforePromisified__")) { |
|
continue; |
|
} |
|
var fn = obj[key]; |
|
if (typeof fn === "function" && |
|
!isPromisified(fn)) { |
|
ret.push(key, fn); |
|
} |
|
} |
|
return ret; |
|
}; |
|
} |
|
})(); |
|
|
|
function switchCaseArgumentOrder(likelyArgumentCount) { |
|
var ret = [likelyArgumentCount]; |
|
var min = Math.max(0, likelyArgumentCount - 1 - 5); |
|
for(var i = likelyArgumentCount - 1; i >= min; --i) { |
|
if (i === likelyArgumentCount) continue; |
|
ret.push(i); |
|
} |
|
for(var i = likelyArgumentCount + 1; i <= 5; ++i) { |
|
ret.push(i); |
|
} |
|
return ret; |
|
} |
|
|
|
function parameterDeclaration(parameterCount) { |
|
var ret = new Array(parameterCount); |
|
for(var i = 0; i < ret.length; ++i) { |
|
ret[i] = "_arg" + i; |
|
} |
|
return ret.join(", "); |
|
} |
|
|
|
function parameterCount(fn) { |
|
if (typeof fn.length === "number") { |
|
return Math.max(Math.min(fn.length, 1023 + 1), 0); |
|
} |
|
return 0; |
|
} |
|
|
|
function propertyAccess(id) { |
|
var rident = /^[a-z$_][a-z$_0-9]*$/i; |
|
|
|
if (rident.test(id)) { |
|
return "." + id; |
|
} |
|
else return "['" + id.replace(/(['\\])/g, "\\$1") + "']"; |
|
} |
|
|
|
function makeNodePromisifiedEval(callback, receiver, originalName, fn) { |
|
var newParameterCount = Math.max(0, parameterCount(fn) - 1); |
|
var argumentOrder = switchCaseArgumentOrder(newParameterCount); |
|
|
|
var callbackName = (typeof originalName === "string" ? |
|
originalName + "Async" : |
|
"promisified"); |
|
|
|
function generateCallForArgumentCount(count) { |
|
var args = new Array(count); |
|
for (var i = 0, len = args.length; i < len; ++i) { |
|
args[i] = "arguments[" + i + "]"; |
|
} |
|
var comma = count > 0 ? "," : ""; |
|
|
|
if (typeof callback === "string" && |
|
receiver === THIS) { |
|
return "this" + propertyAccess(callback) + "("+args.join(",") + |
|
comma +" fn);"+ |
|
"break;"; |
|
} |
|
return (receiver === void 0 |
|
? "callback("+args.join(",")+ comma +" fn);" |
|
: "callback.call("+(receiver === THIS |
|
? "this" |
|
: "receiver")+", "+args.join(",") + comma + " fn);") + |
|
"break;"; |
|
} |
|
|
|
function generateArgumentSwitchCase() { |
|
var ret = ""; |
|
for(var i = 0; i < argumentOrder.length; ++i) { |
|
ret += "case " + argumentOrder[i] +":" + |
|
generateCallForArgumentCount(argumentOrder[i]); |
|
} |
|
ret += "default: var args = new Array(len + 1);" + |
|
"var i = 0;" + |
|
"for (var i = 0; i < len; ++i) { " + |
|
" args[i] = arguments[i];" + |
|
"}" + |
|
"args[i] = fn;" + |
|
|
|
(typeof callback === "string" |
|
? "this" + propertyAccess(callback) + ".apply(" |
|
: "callback.apply(") + |
|
|
|
(receiver === THIS ? "this" : "receiver") + |
|
", args); break;"; |
|
return ret; |
|
} |
|
|
|
return new Function("Promise", "callback", "receiver", |
|
"withAppended", "maybeWrapAsError", "nodebackForPromise", |
|
"INTERNAL", |
|
"var ret = function " + callbackName + |
|
"(" + parameterDeclaration(newParameterCount) + ") {\"use strict\";" + |
|
"var len = arguments.length;" + |
|
"var promise = new Promise(INTERNAL);"+ |
|
"promise._setTrace(" + callbackName + ", void 0);" + |
|
"var fn = nodebackForPromise(promise);"+ |
|
"try {" + |
|
"switch(len) {" + |
|
generateArgumentSwitchCase() + |
|
"}" + |
|
"}" + |
|
"catch(e){ " + |
|
"var wrapped = maybeWrapAsError(e);" + |
|
"promise._attachExtraTrace(wrapped);" + |
|
"promise._reject(wrapped);" + |
|
"}" + |
|
"return promise;" + |
|
"" + |
|
"}; ret.__isPromisified__ = true; return ret;" |
|
)(Promise, callback, receiver, withAppended, |
|
maybeWrapAsError, nodebackForPromise, INTERNAL); |
|
} |
|
|
|
function makeNodePromisifiedClosure(callback, receiver) { |
|
function promisified() { |
|
var _receiver = receiver; |
|
if (receiver === THIS) _receiver = this; |
|
if (typeof callback === "string") { |
|
callback = _receiver[callback]; |
|
} |
|
var promise = new Promise(INTERNAL); |
|
promise._setTrace(promisified, void 0); |
|
var fn = nodebackForPromise(promise); |
|
try { |
|
callback.apply(_receiver, withAppended(arguments, fn)); |
|
} |
|
catch(e) { |
|
var wrapped = maybeWrapAsError(e); |
|
promise._attachExtraTrace(wrapped); |
|
promise._reject(wrapped); |
|
} |
|
return promise; |
|
} |
|
promisified.__isPromisified__ = true; |
|
return promisified; |
|
} |
|
|
|
var makeNodePromisified = canEvaluate |
|
? makeNodePromisifiedEval |
|
: makeNodePromisifiedClosure; |
|
|
|
function f(){} |
|
function _promisify(callback, receiver, isAll) { |
|
if (isAll) { |
|
var methods = inheritedMethods(callback); |
|
for (var i = 0, len = methods.length; i < len; i+= 2) { |
|
var key = methods[i]; |
|
var fn = methods[i+1]; |
|
var originalKey = key + "__beforePromisified__"; |
|
var promisifiedKey = key + "Async"; |
|
notEnumerableProp(callback, originalKey, fn); |
|
callback[promisifiedKey] = |
|
makeNodePromisified(originalKey, THIS, |
|
key, fn); |
|
} |
|
if (methods.length > 16) f.prototype = callback; |
|
return callback; |
|
} |
|
else { |
|
return makeNodePromisified(callback, receiver, void 0, callback); |
|
} |
|
} |
|
|
|
Promise.promisify = function Promise$Promisify(fn, receiver) { |
|
if (typeof fn === "object" && fn !== null) { |
|
deprecated("Promise.promisify for promisifying entire objects is deprecated. Use Promise.promisifyAll instead."); |
|
return _promisify(fn, receiver, true); |
|
} |
|
if (typeof fn !== "function") { |
|
throw new TypeError("fn must be a function"); |
|
} |
|
if (isPromisified(fn)) { |
|
return fn; |
|
} |
|
return _promisify( |
|
fn, |
|
arguments.length < 2 ? THIS : receiver, |
|
false); |
|
}; |
|
|
|
Promise.promisifyAll = function Promise$PromisifyAll(target) { |
|
if (typeof target !== "function" && typeof target !== "object") { |
|
throw new TypeError("the target of promisifyAll must be an object or a function"); |
|
} |
|
return _promisify(target, void 0, true); |
|
}; |
|
}; |
|
|
|
|