implementation.js 3.0 KB

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