123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- '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;
- };
|