|
|
'use strict';
var errors = require('./errors.js'), isFunction = require('lodash/isFunction'), isObjectLike = require('lodash/isObjectLike'), isString = require('lodash/isString'), isUndefined = require('lodash/isUndefined');
module.exports = function (options) {
var errorText = 'Please verify options'; // For better minification because this string is repeating
if (!isObjectLike(options)) { throw new TypeError(errorText); }
if (!isFunction(options.PromiseImpl)) { throw new TypeError(errorText + '.PromiseImpl'); }
if (!isUndefined(options.constructorMixin) && !isFunction(options.constructorMixin)) { throw new TypeError(errorText + '.PromiseImpl'); }
var PromiseImpl = options.PromiseImpl; var constructorMixin = options.constructorMixin;
var plumbing = {};
plumbing.init = function (requestOptions) {
var self = this;
self._rp_promise = new PromiseImpl(function (resolve, reject) { self._rp_resolve = resolve; self._rp_reject = reject; if (constructorMixin) { constructorMixin.apply(self, arguments); // Using arguments since specific Promise libraries may pass additional parameters
} });
self._rp_callbackOrig = requestOptions.callback; requestOptions.callback = self.callback = function RP$callback(err, response, body) { plumbing.callback.call(self, err, response, body); };
if (isString(requestOptions.method)) { requestOptions.method = requestOptions.method.toUpperCase(); }
requestOptions.transform = requestOptions.transform || plumbing.defaultTransformations[requestOptions.method];
self._rp_options = requestOptions; self._rp_options.simple = requestOptions.simple !== false; self._rp_options.resolveWithFullResponse = requestOptions.resolveWithFullResponse === true; self._rp_options.transform2xxOnly = requestOptions.transform2xxOnly === true;
};
plumbing.defaultTransformations = { HEAD: function (body, response, resolveWithFullResponse) { return resolveWithFullResponse ? response : response.headers; } };
plumbing.callback = function (err, response, body) {
var self = this;
var origCallbackThrewException = false, thrownException = null;
if (isFunction(self._rp_callbackOrig)) { try { self._rp_callbackOrig.apply(self, arguments); // TODO: Apply to self mimics behavior of request@2. Is that also right for request@next?
} catch (e) { origCallbackThrewException = true; thrownException = e; } }
var is2xx = !err && /^2/.test('' + response.statusCode);
if (err) {
self._rp_reject(new errors.RequestError(err, self._rp_options, response));
} else if (self._rp_options.simple && !is2xx) {
if (isFunction(self._rp_options.transform) && self._rp_options.transform2xxOnly === false) {
(new PromiseImpl(function (resolve) { resolve(self._rp_options.transform(body, response, self._rp_options.resolveWithFullResponse)); // transform may return a Promise
})) .then(function (transformedResponse) { self._rp_reject(new errors.StatusCodeError(response.statusCode, body, self._rp_options, transformedResponse)); }) .catch(function (transformErr) { self._rp_reject(new errors.TransformError(transformErr, self._rp_options, response)); });
} else { self._rp_reject(new errors.StatusCodeError(response.statusCode, body, self._rp_options, response)); }
} else {
if (isFunction(self._rp_options.transform) && (is2xx || self._rp_options.transform2xxOnly === false)) {
(new PromiseImpl(function (resolve) { resolve(self._rp_options.transform(body, response, self._rp_options.resolveWithFullResponse)); // transform may return a Promise
})) .then(function (transformedResponse) { self._rp_resolve(transformedResponse); }) .catch(function (transformErr) { self._rp_reject(new errors.TransformError(transformErr, self._rp_options, response)); });
} else if (self._rp_options.resolveWithFullResponse) { self._rp_resolve(response); } else { self._rp_resolve(body); }
}
if (origCallbackThrewException) { throw thrownException; }
};
plumbing.exposePromiseMethod = function (exposeTo, bindTo, promisePropertyKey, methodToExpose, exposeAs) {
exposeAs = exposeAs || methodToExpose;
if (exposeAs in exposeTo) { throw new Error('Unable to expose method "' + exposeAs + '"'); }
exposeTo[exposeAs] = function RP$exposed() { var self = bindTo || this; return self[promisePropertyKey][methodToExpose].apply(self[promisePropertyKey], arguments); };
};
plumbing.exposePromise = function (exposeTo, bindTo, promisePropertyKey, exposeAs) {
exposeAs = exposeAs || 'promise';
if (exposeAs in exposeTo) { throw new Error('Unable to expose method "' + exposeAs + '"'); }
exposeTo[exposeAs] = function RP$promise() { var self = bindTo || this; return self[promisePropertyKey]; };
};
return plumbing;
};
|