promise-useful-utils
Version:
useful functions for working with promises
385 lines (325 loc) • 9.74 kB
JavaScript
;
var _toConsumableArray = require('babel-runtime/helpers/to-consumable-array')['default'];
var _Symbol = require('babel-runtime/core-js/symbol')['default'];
var _getIterator = require('babel-runtime/core-js/get-iterator')['default'];
var _Object$getOwnPropertyNames = require('babel-runtime/core-js/object/get-own-property-names')['default'];
var _Object$getOwnPropertyDescriptor = require('babel-runtime/core-js/object/get-own-property-descriptor')['default'];
var _Object$keys = require('babel-runtime/core-js/object/keys')['default'];
var _Promise = require('babel-runtime/core-js/promise')['default'];
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.promisify = promisify;
exports.promisifyAll = promisifyAll;
exports.fromNode = fromNode;
exports.asCallback = asCallback;
var THIS = _Symbol();
var rident = /^[a-z$_][a-z$_0-9]*$/i;
var excludedPrototypes = [Array.prototype, Object.prototype, Function.prototype];
var defaultSuffix = 'Async';
var defaultFilter = function defaultFilter(name) {
return isIdentifier(name) && name.charAt(0) !== '_' && name !== 'constructor';
};
/**
* @param {string} str
* @return {boolean}
*/
function isIdentifier(str) {
return rident.test(str);
}
/**
* @param {*} obj
* @return {boolean}
*/
function isExcludedProto(obj) {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = _getIterator(excludedPrototypes), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var excludedProto = _step.value;
if (obj === excludedProto) {
return true;
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator['return']) {
_iterator['return']();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return false;
}
/**
* @param {Object} obj
* @return {string[]}
*/
function inheritedDataKeys(obj) {
var keys = {};
while (obj !== null && !isExcludedProto(obj)) {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = _getIterator(_Object$getOwnPropertyNames(obj)), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var key = _step2.value;
if (keys[key] === undefined) {
var desc = _Object$getOwnPropertyDescriptor(obj, key);
if (desc !== null && desc.get === undefined && desc.set === undefined) {
keys[key] = true;
}
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2['return']) {
_iterator2['return']();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
obj = Object.getPrototypeOf(obj);
}
return _Object$keys(keys);
}
/**
* @param {*} obj
* @return {boolean}
*/
function isPromisified(obj) {
try {
return obj.__isPromisified__ === true;
} catch (err) {
return false;
}
}
/**
* @param {Object} object
* @param {string} key
* @param {string} suffix
* @return {boolean}
*/
function hasPromisified(object, key, suffix) {
var desc = _Object$getOwnPropertyNames(object, key + suffix);
if (desc === null) {
return false;
}
if (desc.get === undefined && desc.set === undefined) {
return isPromisified(desc.value);
}
return true;
}
/**
* @param {*}
* @return {boolean}
*/
function isClass(fn) {
try {
if (typeof fn !== 'function') {
return false;
}
var names = _Object$getOwnPropertyNames(fn.prototype);
return names.length > 1 || names.length > 0 && !(names.length === 1 && names[0] === 'constructor') || /this\s*\.\s*\S+\s*=/.test(fn + '') && _Object$getOwnPropertyNames(fn).length > 0;
} catch (err) {
return false;
}
}
/**
* @param {(function|string)} method
* @param {Object} [receiver]
* @return {function}
*/
function makeNodePromisifier(method, receiver) {
function promisified() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
var _receiver = receiver === THIS ? this : receiver;
var _method = typeof method === 'string' ? _receiver[method] : method;
return fromNode(function (cb) {
_method.apply(_receiver, args.concat(cb));
});
}
Object.defineProperty(promisified, '__isPromisified__', {
value: true,
configurable: true,
enumerable: false,
writable: true
});
return promisified;
}
/**
* @param {Object} target
* @param {string} suffix
* @param {function} filter
* @param {function} promisifier
* @return {Object}
*/
function plainPromisifyAll(target, suffix, filter, promisifier) {
var suffixRegexp = new RegExp(suffix.replace(/([$])/, '\\$') + '$');
var methods = {};
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = _getIterator(inheritedDataKeys(target)), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var key = _step3.value;
var value = target[key];
if (key === 'constructor' || typeof value !== 'function' || isPromisified(value) || hasPromisified(target, key, suffix) || !filter(key, value, target, defaultFilter(key, value, target))) {
continue;
}
if (isClass(value) && value !== target) {
plainPromisifyAll(value, suffix, filter, promisifier);
plainPromisifyAll(value.prototype, suffix, filter, promisifier);
continue;
}
if (suffixRegexp.test(key)) {
var keyWithoutSuffix = key.replace(suffixRegexp, '');
if (methods[keyWithoutSuffix] !== undefined) {
throw new TypeError('Cannot promisify an API that has normal methods with ' + suffix + '-suffix');
}
}
methods[key] = value;
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3['return']) {
_iterator3['return']();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = _getIterator(_Object$keys(methods)), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var key = _step4.value;
if (promisifier === makeNodePromisifier) {
target[key + suffix] = makeNodePromisifier(methods[key], THIS);
} else {
target[key + suffix] = promisifier(methods[key], function (fn) {
return makeNodePromisifier(fn, THIS);
});
}
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4['return']) {
_iterator4['return']();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
return target;
}
/**
* @param {function} nodeFunction
* @param {*} [receiver]
* @return {Promise}
*/
function promisify(nodeFunction) {
var receiver = arguments.length <= 1 || arguments[1] === undefined ? THIS : arguments[1];
if (isPromisified(nodeFunction)) {
return nodeFunction;
}
return makeNodePromisifier(nodeFunction, receiver);
}
/**
* @param {Object} target
* @param {Object} [opts]
* @param {string} [opts.suffix='Async']
* @param {function} [opts.filter]
* @param {function} [opts.promisifier]
*/
function promisifyAll(target, opts) {
opts = Object(opts);
var suffix = opts.suffix;
if (typeof suffix !== 'string') {
suffix = defaultSuffix;
}
var filter = opts.filter;
if (typeof filter !== 'function') {
filter = defaultFilter;
}
var promisifier = opts.promisifier;
if (typeof promisifier !== 'function') {
promisifier = makeNodePromisifier;
}
if (!isIdentifier(suffix)) {
throw new RangeError('suffix must be a valid identifier');
}
if (isClass(target)) {
plainPromisifyAll(target.prototype, suffix, filter, promisifier);
}
return plainPromisifyAll(target, suffix, filter, promisifier);
}
/**
* @param {function} resolver
* @return {Promise}
*/
function fromNode(resolver) {
return new _Promise(function (resolve, reject) {
resolver(function (err) {
for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
args[_key2 - 1] = arguments[_key2];
}
if (err) {
reject(err);
return;
}
if (args.length === 1) {
args = args[0];
}
resolve(args);
});
});
}
/**
* @param {Promise} promise
* @param {function} nodeback
* @param {Object} [opts]
* @param {boolean} [opts.spread=false]
* @return {Promise}
*/
function asCallback(promise, nodeback, options) {
if (typeof nodeback === 'function') {
promise.then(function (value) {
if (Object(options).spread) {
var args = [null].concat(value);
nodeback.apply(undefined, _toConsumableArray(args));
return;
}
nodeback(null, value);
}, function (err) {
nodeback(err);
});
}
return promise;
}