implementation.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. 'use strict';
  2. var forEach = require('for-each');
  3. var isES5 = typeof Object.defineProperty === 'function';
  4. var gPO = Object.getPrototypeOf;
  5. var sPO = Object.setPrototypeOf;
  6. var hasProto = require('has-proto')() || (typeof gPO === 'function' && gPO([]) === Array.prototype);
  7. if (!isES5 || !hasProto) {
  8. throw new TypeError('util.promisify requires a true ES5+ environment, that also supports `__proto__` and/or `Object.getPrototypeOf`');
  9. }
  10. var getOwnPropertyDescriptors = require('object.getownpropertydescriptors');
  11. if (typeof Promise !== 'function') {
  12. throw new TypeError('`Promise` must be globally available for util.promisify to work.');
  13. }
  14. var oDP = Object.defineProperty;
  15. var $Promise = Promise;
  16. var $TypeError = TypeError;
  17. var safeConcat = require('safe-array-concat');
  18. var callBound = require('call-bind/callBound');
  19. var $slice = callBound('Array.prototype.slice');
  20. var hasSymbols = require('has-symbols/shams')();
  21. // eslint-disable-next-line no-restricted-properties
  22. var kCustomPromisifiedSymbol = hasSymbols ? Symbol['for']('nodejs.util.promisify.custom') : null;
  23. var kCustomPromisifyArgsSymbol = hasSymbols ? Symbol('customPromisifyArgs') : null;
  24. module.exports = function promisify(orig) {
  25. if (typeof orig !== 'function') {
  26. var error = new $TypeError('The "original" argument must be of type function');
  27. error.code = 'ERR_INVALID_ARG_TYPE';
  28. error.toString = function value() {
  29. return this.name + '[' + this.code + ']: ' + this.message;
  30. };
  31. throw error;
  32. }
  33. if (hasSymbols && orig[kCustomPromisifiedSymbol]) {
  34. var customFunction = orig[kCustomPromisifiedSymbol];
  35. if (typeof customFunction !== 'function') {
  36. var customError = $TypeError('The [util.promisify.custom] property must be of type function.');
  37. customError.code = 'ERR_INVALID_ARG_TYPE';
  38. customError.toString = function value() {
  39. return this.name + '[' + this.code + ']: ' + this.message;
  40. };
  41. throw customError;
  42. }
  43. oDP(customFunction, kCustomPromisifiedSymbol, {
  44. configurable: true,
  45. enumerable: false,
  46. value: customFunction,
  47. writable: false
  48. });
  49. return customFunction;
  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. var promisified = function fn() {
  55. var args = $slice(arguments);
  56. var self = this; // eslint-disable-line no-invalid-this
  57. return new $Promise(function (resolve, reject) {
  58. orig.apply(self, safeConcat(args, function (err) {
  59. var values = arguments.length > 1 ? $slice(arguments, 1) : [];
  60. if (err) {
  61. reject(err);
  62. } else if (typeof argumentNames !== 'undefined' && values.length > 1) {
  63. var obj = {};
  64. forEach(argumentNames, function (name, index) {
  65. obj[name] = values[index];
  66. });
  67. resolve(obj);
  68. } else {
  69. resolve(values[0]);
  70. }
  71. }));
  72. });
  73. };
  74. if (typeof sPO === 'function' && typeof gPO === 'function') {
  75. sPO(promisified, gPO(orig));
  76. } else {
  77. promisified.__proto__ = orig.__proto__; // eslint-disable-line no-proto
  78. }
  79. oDP(promisified, kCustomPromisifiedSymbol, {
  80. configurable: true,
  81. enumerable: false,
  82. value: promisified,
  83. writable: false
  84. });
  85. var descriptors = getOwnPropertyDescriptors(orig);
  86. forEach(descriptors, function (k, v) {
  87. try {
  88. oDP(promisified, k, v);
  89. } catch (e) {
  90. // handle nonconfigurable function properties
  91. }
  92. });
  93. return promisified;
  94. };
  95. module.exports.custom = kCustomPromisifiedSymbol;
  96. module.exports.customPromisifyArgs = kCustomPromisifyArgsSymbol;