168 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			168 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | '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; | ||
|  | 
 | ||
|  | }; |