From 0e2f4f14171ccd161e85478c7b1aba61c3b431a2 Mon Sep 17 00:00:00 2001 From: Matt Zabriskie Date: Wed, 1 Jun 2016 14:42:14 -0600 Subject: [PATCH] Moving Axios class into core/ --- lib/axios.js | 108 ++----------------------------- lib/core/Axios.js | 110 ++++++++++++++++++++++++++++++++ lib/utils.js | 22 +++++++ test/specs/utils/extend.spec.js | 34 ++++++++++ 4 files changed, 173 insertions(+), 101 deletions(-) create mode 100644 lib/core/Axios.js create mode 100644 test/specs/utils/extend.spec.js diff --git a/lib/axios.js b/lib/axios.js index aba64ec..3f8b416 100644 --- a/lib/axios.js +++ b/lib/axios.js @@ -2,91 +2,21 @@ var defaults = require('./defaults'); var utils = require('./utils'); -var dispatchRequest = require('./core/dispatchRequest'); -var transformData = require('./core/transformData'); -var InterceptorManager = require('./core/InterceptorManager'); -var isAbsoluteURL = require('./helpers/isAbsoluteURL'); -var combineURLs = require('./helpers/combineURLs'); var bind = require('./helpers/bind'); - -function Axios(defaultConfig) { - this.defaults = utils.merge({}, defaultConfig); - this.interceptors = { - request: new InterceptorManager(), - response: new InterceptorManager() - }; -} - -Axios.prototype.request = function request(config) { - /*eslint no-param-reassign:0*/ - // Allow for axios('example/url'[, config]) a la fetch API - if (typeof config === 'string') { - config = utils.merge({ - url: arguments[0] - }, arguments[1]); - } - - config = utils.merge(defaults, this.defaults, { method: 'get' }, config); - - // Support baseURL config - if (config.baseURL && !isAbsoluteURL(config.url)) { - config.url = combineURLs(config.baseURL, config.url); - } - - // Don't allow overriding defaults.withCredentials - config.withCredentials = config.withCredentials || this.defaults.withCredentials; - - // Transform request data - config.data = transformData( - config.data, - config.headers, - config.transformRequest - ); - - // Flatten headers - config.headers = utils.merge( - config.headers.common || {}, - config.headers[config.method] || {}, - config.headers || {} - ); - - utils.forEach( - ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'], - function cleanHeaderConfig(method) { - delete config.headers[method]; - } - ); - - // Hook up interceptors middleware - var chain = [dispatchRequest, undefined]; - var promise = Promise.resolve(config); - - this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) { - chain.unshift(interceptor.fulfilled, interceptor.rejected); - }); - - this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { - chain.push(interceptor.fulfilled, interceptor.rejected); - }); - - while (chain.length) { - promise = promise.then(chain.shift(), chain.shift()); - } - - return promise; -}; +var Axios = require('./core/Axios'); var defaultInstance = new Axios(defaults); var axios = module.exports = bind(Axios.prototype.request, defaultInstance); -axios.request = bind(Axios.prototype.request, defaultInstance); + +// Copy Axios.prototype to axios instance +utils.extend(axios, Axios.prototype, defaultInstance); + +// Copy defaultInstance to axios instance +utils.extend(axios, defaultInstance); // Expose Axios class to allow class inheritance axios.Axios = Axios; -// Expose properties from defaultInstance -axios.defaults = defaultInstance.defaults; -axios.interceptors = defaultInstance.interceptors; - // Factory for creating new instances axios.create = function create(defaultConfig) { return new Axios(defaultConfig); @@ -97,27 +27,3 @@ axios.all = function all(promises) { return Promise.all(promises); }; axios.spread = require('./helpers/spread'); - -// Provide aliases for supported request methods -utils.forEach(['delete', 'get', 'head'], function forEachMethodNoData(method) { - /*eslint func-names:0*/ - Axios.prototype[method] = function(url, config) { - return this.request(utils.merge(config || {}, { - method: method, - url: url - })); - }; - axios[method] = bind(Axios.prototype[method], defaultInstance); -}); - -utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) { - /*eslint func-names:0*/ - Axios.prototype[method] = function(url, data, config) { - return this.request(utils.merge(config || {}, { - method: method, - url: url, - data: data - })); - }; - axios[method] = bind(Axios.prototype[method], defaultInstance); -}); diff --git a/lib/core/Axios.js b/lib/core/Axios.js new file mode 100644 index 0000000..14b51da --- /dev/null +++ b/lib/core/Axios.js @@ -0,0 +1,110 @@ +'use strict'; + +var defaults = require('./../defaults'); +var utils = require('./../utils'); +var InterceptorManager = require('./InterceptorManager'); +var dispatchRequest = require('./dispatchRequest'); +var transformData = require('./transformData'); +var isAbsoluteURL = require('./../helpers/isAbsoluteURL'); +var combineURLs = require('./../helpers/combineURLs'); + +/** + * Create a new instance of Axios + * + * @param {Object} defaultConfig The default config for the instance + */ +function Axios(defaultConfig) { + this.defaults = utils.merge({}, defaultConfig); + this.interceptors = { + request: new InterceptorManager(), + response: new InterceptorManager() + }; +} + +/** + * Dispatch a request + * + * @param {Object} config The config specific for this request (merged with this.defaults) + */ +Axios.prototype.request = function request(config) { + /*eslint no-param-reassign:0*/ + // Allow for axios('example/url'[, config]) a la fetch API + if (typeof config === 'string') { + config = utils.merge({ + url: arguments[0] + }, arguments[1]); + } + + config = utils.merge(defaults, this.defaults, { method: 'get' }, config); + + // Support baseURL config + if (config.baseURL && !isAbsoluteURL(config.url)) { + config.url = combineURLs(config.baseURL, config.url); + } + + // Don't allow overriding defaults.withCredentials + config.withCredentials = config.withCredentials || this.defaults.withCredentials; + + // Transform request data + config.data = transformData( + config.data, + config.headers, + config.transformRequest + ); + + // Flatten headers + config.headers = utils.merge( + config.headers.common || {}, + config.headers[config.method] || {}, + config.headers || {} + ); + + utils.forEach( + ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'], + function cleanHeaderConfig(method) { + delete config.headers[method]; + } + ); + + // Hook up interceptors middleware + var chain = [dispatchRequest, undefined]; + var promise = Promise.resolve(config); + + this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) { + chain.unshift(interceptor.fulfilled, interceptor.rejected); + }); + + this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { + chain.push(interceptor.fulfilled, interceptor.rejected); + }); + + while (chain.length) { + promise = promise.then(chain.shift(), chain.shift()); + } + + return promise; +}; + +// Provide aliases for supported request methods +utils.forEach(['delete', 'get', 'head'], function forEachMethodNoData(method) { + /*eslint func-names:0*/ + Axios.prototype[method] = function(url, config) { + return this.request(utils.merge(config || {}, { + method: method, + url: url + })); + }; +}); + +utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) { + /*eslint func-names:0*/ + Axios.prototype[method] = function(url, data, config) { + return this.request(utils.merge(config || {}, { + method: method, + url: url, + data: data + })); + }; +}); + +module.exports = Axios; diff --git a/lib/utils.js b/lib/utils.js index 74668df..77d84e8 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,5 +1,7 @@ 'use strict'; +var bind = require('./helpers/bind'); + /*global toString:true*/ // utils is a library of generic helper functions non-specific to axios @@ -255,6 +257,25 @@ function merge(/* obj1, obj2, obj3, ... */) { return result; } +/** + * Extends object a by mutably adding to it the properties of object b. + * + * @param {Object} a The object to be extended + * @param {Object} b The object to copy properties from + * @param {Object} thisArg The object to bind function to + * @return {Object} The resulting value of object a + */ +function extend(a, b, thisArg) { + forEach(b, function assignValue(val, key) { + if (thisArg && typeof val === 'function') { + a[key] = bind(val, thisArg); + } else { + a[key] = val; + } + }); + return a; +} + module.exports = { isArray: isArray, isArrayBuffer: isArrayBuffer, @@ -273,5 +294,6 @@ module.exports = { isStandardBrowserEnv: isStandardBrowserEnv, forEach: forEach, merge: merge, + extend: extend, trim: trim }; diff --git a/test/specs/utils/extend.spec.js b/test/specs/utils/extend.spec.js new file mode 100644 index 0000000..3e1bb32 --- /dev/null +++ b/test/specs/utils/extend.spec.js @@ -0,0 +1,34 @@ +var extend = require('../../../lib/utils').extend; + +describe('utils::extend', function () { + it('should be mutable', function () { + var a = {}; + var b = {foo: 123}; + + extend(a, b); + + expect(a.foo).toEqual(b.foo); + }); + + it('should extend properties', function () { + var a = {foo: 123, bar: 456}; + var b = {bar: 789}; + + a = extend(a, b); + + expect(a.foo).toEqual(123); + expect(a.bar).toEqual(789); + }); + + it('should bind to thisArg', function () { + var a = {}; + var b = {getFoo: function getFoo() { return this.foo; }}; + var thisArg = { foo: 'barbaz' }; + + extend(a, b, thisArg); + + expect(typeof a.getFoo).toEqual('function'); + expect(a.getFoo()).toEqual(thisArg.foo); + }); +}); +