blob: 3cd88f1a057fa18b6e11ab71696661a1704c808a [file] [log] [blame]
Leo Repp58b9f112021-11-22 11:57:47 +01001'use strict';
2
3var isES5 = typeof Object.defineProperty === 'function'
4 && typeof Object.defineProperties === 'function';
5
6var hasProto = [].__proto__ === Array.prototype; // eslint-disable-line no-proto
7
8if (!isES5 || !hasProto) {
9 throw new TypeError('util.promisify requires a true ES5 environment, that also supports `__proto__`');
10}
11
12var getOwnPropertyDescriptors = require('object.getownpropertydescriptors');
13
14if (typeof Promise !== 'function') {
15 throw new TypeError('`Promise` must be globally available for util.promisify to work.');
16}
17
18var callBound = require('es-abstract/helpers/callBound');
19
20var $slice = callBound('Array.prototype.slice');
21var $concat = callBound('Array.prototype.concat');
22var $forEach = callBound('Array.prototype.forEach');
23
24var hasSymbols = require('has-symbols')();
25
26var kCustomPromisifiedSymbol = hasSymbols ? Symbol('util.promisify.custom') : null;
27var kCustomPromisifyArgsSymbol = hasSymbols ? Symbol('customPromisifyArgs') : null;
28
29module.exports = function promisify(orig) {
30 if (typeof orig !== 'function') {
31 var error = new TypeError('The "original" argument must be of type function');
32 error.name = 'TypeError [ERR_INVALID_ARG_TYPE]';
33 error.code = 'ERR_INVALID_ARG_TYPE';
34 throw error;
35 }
36
37 if (hasSymbols && orig[kCustomPromisifiedSymbol]) {
38 var customFunction = orig[kCustomPromisifiedSymbol];
39 if (typeof customFunction !== 'function') {
40 throw new TypeError('The [util.promisify.custom] property must be a function');
41 }
42 Object.defineProperty(customFunction, kCustomPromisifiedSymbol, {
43 configurable: true,
44 enumerable: false,
45 value: customFunction,
46 writable: false
47 });
48 return customFunction;
49 }
50
51 // Names to create an object from in case the callback receives multiple
52 // arguments, e.g. ['stdout', 'stderr'] for child_process.exec.
53 var argumentNames = orig[kCustomPromisifyArgsSymbol];
54
55 var promisified = function fn() {
56 var args = $slice(arguments);
57 var self = this; // eslint-disable-line no-invalid-this
58 return new Promise(function (resolve, reject) {
59 orig.apply(self, $concat(args, function (err) {
60 var values = arguments.length > 1 ? $slice(arguments, 1) : [];
61 if (err) {
62 reject(err);
63 } else if (typeof argumentNames !== 'undefined' && values.length > 1) {
64 var obj = {};
65 $forEach(argumentNames, function (name, index) {
66 obj[name] = values[index];
67 });
68 resolve(obj);
69 } else {
70 resolve(values[0]);
71 }
72 }));
73 });
74 };
75
76 promisified.__proto__ = orig.__proto__; // eslint-disable-line no-proto
77
78 Object.defineProperty(promisified, kCustomPromisifiedSymbol, {
79 configurable: true,
80 enumerable: false,
81 value: promisified,
82 writable: false
83 });
84 return Object.defineProperties(promisified, getOwnPropertyDescriptors(orig));
85};
86
87module.exports.custom = kCustomPromisifiedSymbol;
88module.exports.customPromisifyArgs = kCustomPromisifyArgsSymbol;