util: add util.promisify() · nodejs/node@99da8e8

@@ -4,6 +4,8 @@ const errors = require('internal/errors');

44

const binding = process.binding('util');

55

const signals = process.binding('constants').os.signals;

667+

const { createPromise, promiseResolve, promiseReject } = binding;

8+79

const kArrowMessagePrivateSymbolIndex = binding['arrow_message_private_symbol'];

810

const kDecoratedPrivateSymbolIndex = binding['decorated_private_symbol'];

911

const noCrypto = !process.versions.openssl;

@@ -217,3 +219,62 @@ module.exports = exports = {

217219

// default isEncoding implementation, just in case userland overrides it.

218220

kIsEncodingSymbol: Symbol('node.isEncoding')

219221

};

222+223+

const kCustomPromisifiedSymbol = Symbol('util.promisify.custom');

224+

const kCustomPromisifyArgsSymbol = Symbol('customPromisifyArgs');

225+226+

function promisify(orig) {

227+

if (typeof orig !== 'function') {

228+

const errors = require('internal/errors');

229+

throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'original', 'function');

230+

}

231+232+

if (orig[kCustomPromisifiedSymbol]) {

233+

const fn = orig[kCustomPromisifiedSymbol];

234+

if (typeof fn !== 'function') {

235+

throw new TypeError('The [util.promisify.custom] property must be ' +

236+

'a function');

237+

}

238+

Object.defineProperty(fn, kCustomPromisifiedSymbol, {

239+

value: fn, enumerable: false, writable: false, configurable: true

240+

});

241+

return fn;

242+

}

243+244+

// Names to create an object from in case the callback receives multiple

245+

// arguments, e.g. ['stdout', 'stderr'] for child_process.exec.

246+

const argumentNames = orig[kCustomPromisifyArgsSymbol];

247+248+

function fn(...args) {

249+

const promise = createPromise();

250+

try {

251+

orig.call(this, ...args, (err, ...values) => {

252+

if (err) {

253+

promiseReject(promise, err);

254+

} else if (argumentNames !== undefined && values.length > 1) {

255+

const obj = {};

256+

for (var i = 0; i < argumentNames.length; i++)

257+

obj[argumentNames[i]] = values[i];

258+

promiseResolve(promise, obj);

259+

} else {

260+

promiseResolve(promise, values[0]);

261+

}

262+

});

263+

} catch (err) {

264+

promiseReject(promise, err);

265+

}

266+

return promise;

267+

}

268+269+

Object.setPrototypeOf(fn, Object.getPrototypeOf(orig));

270+271+

Object.defineProperty(fn, kCustomPromisifiedSymbol, {

272+

value: fn, enumerable: false, writable: false, configurable: true

273+

});

274+

return Object.defineProperties(fn, Object.getOwnPropertyDescriptors(orig));

275+

}

276+277+

promisify.custom = kCustomPromisifiedSymbol;

278+279+

exports.promisify = promisify;

280+

exports.customPromisifyArgs = kCustomPromisifyArgsSymbol;