Skip to content

Commit

Permalink
Initial implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
ljharb committed May 30, 2017
1 parent 54c2ccb commit 05ff048
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 2 deletions.
8 changes: 8 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@

"extends": "@ljharb",

"env": {
"es6": true
},

"rules": {
"id-length": [2, { "max": 30 }],
"max-statements": [2, 16],
"no-magic-numbers": 0,
"operator-linebreak": [2, "before"]
}
}
86 changes: 86 additions & 0 deletions implementation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
'use strict';

var isES5 = typeof Object.defineProperty === 'function'
&& typeof Object.defineProperties === 'function'
&& typeof Object.getPrototypeOf === 'function'
&& typeof Object.setPrototypeOf === 'function';

if (!isES5) {
throw new TypeError('util.promisify requires a true ES5 environment');
}

var getOwnPropertyDescriptors = require('object.getownpropertydescriptors');

if (typeof Promise !== 'function') {
throw new TypeError('`Promise` must be globally available for util.promisify to work.');
}

var slice = Function.call.bind(Array.prototype.slice);
var concat = Function.call.bind(Array.prototype.concat);
var forEach = Function.call.bind(Array.prototype.forEach);

var hasSymbols = typeof Symbol === 'function' && typeof Symbol('') === 'symbol';

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]);
}
}));
});
};

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

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;
24 changes: 24 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use strict';

var define = require('define-properties');
var util = require('util');

var implementation = require('./implementation');
var getPolyfill = require('./polyfill');
var polyfill = getPolyfill();
var shim = require('./shim');

/* eslint-disable no-unused-vars */
var boundPromisify = function promisify(orig) {
/* eslint-enable no-unused-vars */
return polyfill.apply(util, arguments);
};
define(boundPromisify, {
custom: polyfill.custom,
customPromisifyArgs: polyfill.customPromisifyArgs,
getPolyfill: getPolyfill,
implementation: implementation,
shim: shim
});

module.exports = boundPromisify;
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
"version": "0.0.0",
"description": "Polyfill/shim for util.promisify in node versions < v8",
"main": "index.js",
"dependencies": {},
"dependencies": {
"define-properties": "^1.1.2",
"object.getownpropertydescriptors": "^2.0.3"
},
"devDependencies": {
"@es-shims/api": "^1.2.0",
"@ljharb/eslint-config": "^11.0.0",
Expand All @@ -14,7 +17,7 @@
"prepublish": "safe-publish-latest",
"lint": "eslint .",
"pretest": "npm run lint",
"tests-only": "es-shim-api",
"tests-only": "es-shim-api --bound",
"test": "npm run tests-only"
},
"repository": {
Expand Down
11 changes: 11 additions & 0 deletions polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'use strict';

var util = require('util');
var implementation = require('./implementation');

module.exports = function getPolyfill() {
if (typeof util.promisify === 'function') {
return util.promisify;
}
return implementation;
};
13 changes: 13 additions & 0 deletions shim.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use strict';

var util = require('util');
var getPolyfill = require('./polyfill');

module.exports = function shimUtilPromisify() {
var polyfill = getPolyfill();
if (polyfill !== util.promisify) {
util.promisify = polyfill;
Object.defineProperty(util, 'promisify', { value: polyfill });
}
return polyfill;
};

0 comments on commit 05ff048

Please sign in to comment.