Spaces:
Paused
Paused
| ; | |
| module.exports = function(Promise, INTERNAL) { | |
| var THIS = {}; | |
| var util = require("./util"); | |
| var nodebackForPromise = require("./nodeback"); | |
| var withAppended = util.withAppended; | |
| var maybeWrapAsError = util.maybeWrapAsError; | |
| var canEvaluate = util.canEvaluate; | |
| var TypeError = require("./errors").TypeError; | |
| var defaultSuffix = "Async"; | |
| var defaultPromisified = {__isPromisified__: true}; | |
| var noCopyProps = [ | |
| "arity", "length", | |
| "name", | |
| "arguments", | |
| "caller", | |
| "callee", | |
| "prototype", | |
| "__isPromisified__" | |
| ]; | |
| var noCopyPropsPattern = new RegExp("^(?:" + noCopyProps.join("|") + ")$"); | |
| var defaultFilter = function(name) { | |
| return util.isIdentifier(name) && | |
| name.charAt(0) !== "_" && | |
| name !== "constructor"; | |
| }; | |
| function propsFilter(key) { | |
| return !noCopyPropsPattern.test(key); | |
| } | |
| function isPromisified(fn) { | |
| try { | |
| return fn.__isPromisified__ === true; | |
| } | |
| catch (e) { | |
| return false; | |
| } | |
| } | |
| function hasPromisified(obj, key, suffix) { | |
| var val = util.getDataPropertyOrDefault(obj, key + suffix, | |
| defaultPromisified); | |
| return val ? isPromisified(val) : false; | |
| } | |
| function checkValid(ret, suffix, suffixRegexp) { | |
| for (var i = 0; i < ret.length; i += 2) { | |
| var key = ret[i]; | |
| if (suffixRegexp.test(key)) { | |
| var keyWithoutAsyncSuffix = key.replace(suffixRegexp, ""); | |
| for (var j = 0; j < ret.length; j += 2) { | |
| if (ret[j] === keyWithoutAsyncSuffix) { | |
| throw new TypeError("Cannot promisify an API that has normal methods with '%s'-suffix\u000a\u000a See http://goo.gl/MqrFmX\u000a" | |
| .replace("%s", suffix)); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| function promisifiableMethods(obj, suffix, suffixRegexp, filter) { | |
| var keys = util.inheritedDataKeys(obj); | |
| var ret = []; | |
| for (var i = 0; i < keys.length; ++i) { | |
| var key = keys[i]; | |
| var value = obj[key]; | |
| var passesDefaultFilter = filter === defaultFilter | |
| ? true : defaultFilter(key, value, obj); | |
| if (typeof value === "function" && | |
| !isPromisified(value) && | |
| !hasPromisified(obj, key, suffix) && | |
| filter(key, value, obj, passesDefaultFilter)) { | |
| ret.push(key, value); | |
| } | |
| } | |
| checkValid(ret, suffix, suffixRegexp); | |
| return ret; | |
| } | |
| var escapeIdentRegex = function(str) { | |
| return str.replace(/([$])/, "\\$"); | |
| }; | |
| var makeNodePromisifiedEval; | |
| if (!false) { | |
| var switchCaseArgumentOrder = function(likelyArgumentCount) { | |
| var ret = [likelyArgumentCount]; | |
| var min = Math.max(0, likelyArgumentCount - 1 - 3); | |
| for(var i = likelyArgumentCount - 1; i >= min; --i) { | |
| ret.push(i); | |
| } | |
| for(var i = likelyArgumentCount + 1; i <= 3; ++i) { | |
| ret.push(i); | |
| } | |
| return ret; | |
| }; | |
| var argumentSequence = function(argumentCount) { | |
| return util.filledRange(argumentCount, "_arg", ""); | |
| }; | |
| var parameterDeclaration = function(parameterCount) { | |
| return util.filledRange( | |
| Math.max(parameterCount, 3), "_arg", ""); | |
| }; | |
| var parameterCount = function(fn) { | |
| if (typeof fn.length === "number") { | |
| return Math.max(Math.min(fn.length, 1023 + 1), 0); | |
| } | |
| return 0; | |
| }; | |
| makeNodePromisifiedEval = | |
| function(callback, receiver, originalName, fn, _, multiArgs) { | |
| var newParameterCount = Math.max(0, parameterCount(fn) - 1); | |
| var argumentOrder = switchCaseArgumentOrder(newParameterCount); | |
| var shouldProxyThis = typeof callback === "string" || receiver === THIS; | |
| function generateCallForArgumentCount(count) { | |
| var args = argumentSequence(count).join(", "); | |
| var comma = count > 0 ? ", " : ""; | |
| var ret; | |
| if (shouldProxyThis) { | |
| ret = "ret = callback.call(this, {{args}}, nodeback); break;\n"; | |
| } else { | |
| ret = receiver === undefined | |
| ? "ret = callback({{args}}, nodeback); break;\n" | |
| : "ret = callback.call(receiver, {{args}}, nodeback); break;\n"; | |
| } | |
| return ret.replace("{{args}}", args).replace(", ", comma); | |
| } | |
| function generateArgumentSwitchCase() { | |
| var ret = ""; | |
| for (var i = 0; i < argumentOrder.length; ++i) { | |
| ret += "case " + argumentOrder[i] +":" + | |
| generateCallForArgumentCount(argumentOrder[i]); | |
| } | |
| ret += " \n\ | |
| default: \n\ | |
| var args = new Array(len + 1); \n\ | |
| var i = 0; \n\ | |
| for (var i = 0; i < len; ++i) { \n\ | |
| args[i] = arguments[i]; \n\ | |
| } \n\ | |
| args[i] = nodeback; \n\ | |
| [CodeForCall] \n\ | |
| break; \n\ | |
| ".replace("[CodeForCall]", (shouldProxyThis | |
| ? "ret = callback.apply(this, args);\n" | |
| : "ret = callback.apply(receiver, args);\n")); | |
| return ret; | |
| } | |
| var getFunctionCode = typeof callback === "string" | |
| ? ("this != null ? this['"+callback+"'] : fn") | |
| : "fn"; | |
| var body = "'use strict'; \n\ | |
| var ret = function (Parameters) { \n\ | |
| 'use strict'; \n\ | |
| var len = arguments.length; \n\ | |
| var promise = new Promise(INTERNAL); \n\ | |
| promise._captureStackTrace(); \n\ | |
| var nodeback = nodebackForPromise(promise, " + multiArgs + "); \n\ | |
| var ret; \n\ | |
| var callback = tryCatch([GetFunctionCode]); \n\ | |
| switch(len) { \n\ | |
| [CodeForSwitchCase] \n\ | |
| } \n\ | |
| if (ret === errorObj) { \n\ | |
| promise._rejectCallback(maybeWrapAsError(ret.e), true, true);\n\ | |
| } \n\ | |
| if (!promise._isFateSealed()) promise._setAsyncGuaranteed(); \n\ | |
| return promise; \n\ | |
| }; \n\ | |
| notEnumerableProp(ret, '__isPromisified__', true); \n\ | |
| return ret; \n\ | |
| ".replace("[CodeForSwitchCase]", generateArgumentSwitchCase()) | |
| .replace("[GetFunctionCode]", getFunctionCode); | |
| body = body.replace("Parameters", parameterDeclaration(newParameterCount)); | |
| return new Function("Promise", | |
| "fn", | |
| "receiver", | |
| "withAppended", | |
| "maybeWrapAsError", | |
| "nodebackForPromise", | |
| "tryCatch", | |
| "errorObj", | |
| "notEnumerableProp", | |
| "INTERNAL", | |
| body)( | |
| Promise, | |
| fn, | |
| receiver, | |
| withAppended, | |
| maybeWrapAsError, | |
| nodebackForPromise, | |
| util.tryCatch, | |
| util.errorObj, | |
| util.notEnumerableProp, | |
| INTERNAL); | |
| }; | |
| } | |
| function makeNodePromisifiedClosure(callback, receiver, _, fn, __, multiArgs) { | |
| var defaultThis = (function() {return this;})(); | |
| var method = callback; | |
| if (typeof method === "string") { | |
| callback = fn; | |
| } | |
| function promisified() { | |
| var _receiver = receiver; | |
| if (receiver === THIS) _receiver = this; | |
| var promise = new Promise(INTERNAL); | |
| promise._captureStackTrace(); | |
| var cb = typeof method === "string" && this !== defaultThis | |
| ? this[method] : callback; | |
| var fn = nodebackForPromise(promise, multiArgs); | |
| try { | |
| cb.apply(_receiver, withAppended(arguments, fn)); | |
| } catch(e) { | |
| promise._rejectCallback(maybeWrapAsError(e), true, true); | |
| } | |
| if (!promise._isFateSealed()) promise._setAsyncGuaranteed(); | |
| return promise; | |
| } | |
| util.notEnumerableProp(promisified, "__isPromisified__", true); | |
| return promisified; | |
| } | |
| var makeNodePromisified = canEvaluate | |
| ? makeNodePromisifiedEval | |
| : makeNodePromisifiedClosure; | |
| function promisifyAll(obj, suffix, filter, promisifier, multiArgs) { | |
| var suffixRegexp = new RegExp(escapeIdentRegex(suffix) + "$"); | |
| var methods = | |
| promisifiableMethods(obj, suffix, suffixRegexp, filter); | |
| for (var i = 0, len = methods.length; i < len; i+= 2) { | |
| var key = methods[i]; | |
| var fn = methods[i+1]; | |
| var promisifiedKey = key + suffix; | |
| if (promisifier === makeNodePromisified) { | |
| obj[promisifiedKey] = | |
| makeNodePromisified(key, THIS, key, fn, suffix, multiArgs); | |
| } else { | |
| var promisified = promisifier(fn, function() { | |
| return makeNodePromisified(key, THIS, key, | |
| fn, suffix, multiArgs); | |
| }); | |
| util.notEnumerableProp(promisified, "__isPromisified__", true); | |
| obj[promisifiedKey] = promisified; | |
| } | |
| } | |
| util.toFastProperties(obj); | |
| return obj; | |
| } | |
| function promisify(callback, receiver, multiArgs) { | |
| return makeNodePromisified(callback, receiver, undefined, | |
| callback, null, multiArgs); | |
| } | |
| Promise.promisify = function (fn, options) { | |
| if (typeof fn !== "function") { | |
| throw new TypeError("expecting a function but got " + util.classString(fn)); | |
| } | |
| if (isPromisified(fn)) { | |
| return fn; | |
| } | |
| options = Object(options); | |
| var receiver = options.context === undefined ? THIS : options.context; | |
| var multiArgs = !!options.multiArgs; | |
| var ret = promisify(fn, receiver, multiArgs); | |
| util.copyDescriptors(fn, ret, propsFilter); | |
| return ret; | |
| }; | |
| Promise.promisifyAll = function (target, options) { | |
| if (typeof target !== "function" && typeof target !== "object") { | |
| throw new TypeError("the target of promisifyAll must be an object or a function\u000a\u000a See http://goo.gl/MqrFmX\u000a"); | |
| } | |
| options = Object(options); | |
| var multiArgs = !!options.multiArgs; | |
| var suffix = options.suffix; | |
| if (typeof suffix !== "string") suffix = defaultSuffix; | |
| var filter = options.filter; | |
| if (typeof filter !== "function") filter = defaultFilter; | |
| var promisifier = options.promisifier; | |
| if (typeof promisifier !== "function") promisifier = makeNodePromisified; | |
| if (!util.isIdentifier(suffix)) { | |
| throw new RangeError("suffix must be a valid identifier\u000a\u000a See http://goo.gl/MqrFmX\u000a"); | |
| } | |
| var keys = util.inheritedDataKeys(target); | |
| for (var i = 0; i < keys.length; ++i) { | |
| var value = target[keys[i]]; | |
| if (keys[i] !== "constructor" && | |
| util.isClass(value)) { | |
| promisifyAll(value.prototype, suffix, filter, promisifier, | |
| multiArgs); | |
| promisifyAll(value, suffix, filter, promisifier, multiArgs); | |
| } | |
| } | |
| return promisifyAll(target, suffix, filter, promisifier, multiArgs); | |
| }; | |
| }; | |