'use strict'; var isES5 = typeof Object.defineProperty === 'function' && typeof Object.defineProperties === 'function'; var hasProto = [].__proto__ === Array.prototype; // eslint-disable-line no-proto if (!isES5 || !hasProto) { throw new TypeError('util.promisify requires a true ES5 environment, that also supports `__proto__`'); } var getOwnPropertyDescriptors = require('object.getownpropertydescriptors'); if (typeof Promise !== 'function') { throw new TypeError('`Promise` must be globally available for util.promisify to work.'); } var callBound = require('es-abstract/helpers/callBound'); var $slice = callBound('Array.prototype.slice'); var $concat = callBound('Array.prototype.concat'); var $forEach = callBound('Array.prototype.forEach'); var hasSymbols = require('has-symbols')(); var kCustomPromisifiedSymbol = hasSymbols ? Symbol('util.promisify.custom') : null; var kCustomPromisifyArgsSymbol = hasSymbols ? Symbol('customPromisifyArgs') : null; module.exports = function promisify(orig) { if (typeof orig !== 'function') { var error = new TypeError('The "original" argument must be of type function'); error.name = 'TypeError [ERR_INVALID_ARG_TYPE]'; error.code = 'ERR_INVALID_ARG_TYPE'; throw error; } if (hasSymbols && orig[kCustomPromisifiedSymbol]) { var customFunction = orig[kCustomPromisifiedSymbol]; if (typeof customFunction !== 'function') { throw new TypeError('The [util.promisify.custom] property must be a function'); } Object.defineProperty(customFunction, kCustomPromisifiedSymbol, { configurable: true, enumerable: false, value: customFunction, writable: false }); return customFunction; } // Names to create an object from in case the callback receives multiple // arguments, e.g. ['stdout', 'stderr'] for child_process.exec. var argumentNames = orig[kCustomPromisifyArgsSymbol]; var promisified = function fn() { var args = $slice(arguments); var self = this; // eslint-disable-line no-invalid-this return new Promise(function (resolve, reject) { orig.apply(self, $concat(args, function (err) { var values = arguments.length > 1 ? $slice(arguments, 1) : []; if (err) { reject(err); } else if (typeof argumentNames !== 'undefined' && values.length > 1) { var obj = {}; $forEach(argumentNames, function (name, index) { obj[name] = values[index]; }); resolve(obj); } else { resolve(values[0]); } })); }); }; promisified.__proto__ = orig.__proto__; // eslint-disable-line no-proto Object.defineProperty(promisified, kCustomPromisifiedSymbol, { configurable: true, enumerable: false, value: promisified, writable: false }); return Object.defineProperties(promisified, getOwnPropertyDescriptors(orig)); }; module.exports.custom = kCustomPromisifiedSymbol; module.exports.customPromisifyArgs = kCustomPromisifyArgsSymbol;