From 5bfd2ea9f63e59efaef3f1a659b55bbb9778fce2 Mon Sep 17 00:00:00 2001 From: Martti Laine Date: Thu, 1 Mar 2018 23:53:38 +0200 Subject: [PATCH 01/10] Fixing #385 - Keep defaults local to instance --- lib/axios.js | 2 +- lib/core/Axios.js | 14 +++++++---- lib/utils.js | 48 ++++++++++++++++++++++++++++++++++++- test/specs/defaults.spec.js | 4 ++-- test/specs/options.spec.js | 28 ++++++++++++++++++++++ 5 files changed, 87 insertions(+), 9 deletions(-) diff --git a/lib/axios.js b/lib/axios.js index ed1f519..68621dd 100644 --- a/lib/axios.js +++ b/lib/axios.js @@ -32,7 +32,7 @@ axios.Axios = Axios; // Factory for creating new instances axios.create = function create(instanceConfig) { - return createInstance(utils.merge(defaults, instanceConfig)); + return createInstance(utils.mergeConfig(axios.defaults, instanceConfig || {})); }; // Expose Cancel & CancelToken diff --git a/lib/core/Axios.js b/lib/core/Axios.js index f1af3e7..766a897 100644 --- a/lib/core/Axios.js +++ b/lib/core/Axios.js @@ -1,6 +1,5 @@ 'use strict'; -var defaults = require('./../defaults'); var utils = require('./../utils'); var InterceptorManager = require('./InterceptorManager'); var dispatchRequest = require('./dispatchRequest'); @@ -24,15 +23,20 @@ function Axios(instanceConfig) { * @param {Object} config The config specific for this request (merged with this.defaults) */ Axios.prototype.request = function request(config) { + config = 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 = arguments[1] || {}; + config.url = arguments[0]; } - config = utils.merge(defaults, this.defaults, { method: 'get' }, config); + if (!config.method) { + config.method = 'get'; + } + + config = utils.mergeConfig(this.defaults, config); config.method = config.method.toLowerCase(); // Hook up interceptors middleware diff --git a/lib/utils.js b/lib/utils.js index b3fd865..342fa1f 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -279,6 +279,51 @@ function extend(a, b, thisArg) { return a; } +function mergeConfig(defaults, instanceConfig) { + var config = {}; + forEach(['url', 'method', 'params', 'data'], function(prop) { + config[prop] = instanceConfig[prop]; + }); + forEach(['headers', 'auth', 'proxy'], function(prop) { + if (!isUndefined(instanceConfig[prop])) { + if (!isObject(instanceConfig[prop])) { + config[prop] = instanceConfig[prop]; + } else { + config[prop] = merge( + defaults[prop], + instanceConfig[prop] + ); + } + } else if (!isUndefined(defaults[prop])) { + config[prop] = JSON.parse(JSON.stringify(defaults[prop])); + } + }); + var remainingProperties = [ + 'baseURL', + 'transformRequest', + 'transformResponse', + 'paramsSerializer', + 'timeout', + 'withCredentials', + 'adapter', + 'responseType', + 'xsrfCookieName', + 'xsrfHeaderName', + 'onUploadProgress', + 'onDownloadProgress', + 'maxContentLength', + 'validateStatus', + 'maxRedirects', + 'httpAgent', + 'httpsAgent', + 'cancelToken' + ]; + forEach(remainingProperties, function(prop) { + config[prop] = !isUndefined(instanceConfig[prop]) ? instanceConfig[prop] : defaults[prop]; + }); + return config; +} + module.exports = { isArray: isArray, isArrayBuffer: isArrayBuffer, @@ -299,5 +344,6 @@ module.exports = { forEach: forEach, merge: merge, extend: extend, - trim: trim + trim: trim, + mergeConfig: mergeConfig }; diff --git a/test/specs/defaults.spec.js b/test/specs/defaults.spec.js index de19b6a..c8ee72e 100644 --- a/test/specs/defaults.spec.js +++ b/test/specs/defaults.spec.js @@ -148,14 +148,14 @@ describe('defaults', function () { }); }); - it('should be used by custom instance if set after instance created', function (done) { + it('should not be used by custom instance if set after instance created', function (done) { var instance = axios.create(); axios.defaults.baseURL = 'http://example.org/'; instance.get('/foo'); getAjaxRequest().then(function (request) { - expect(request.url).toBe('http://example.org/foo'); + expect(request.url).toBe('/foo'); done(); }); }); diff --git a/test/specs/options.spec.js b/test/specs/options.spec.js index 6520b8a..762b851 100644 --- a/test/specs/options.spec.js +++ b/test/specs/options.spec.js @@ -81,4 +81,32 @@ describe('options', function () { done(); }); }); + + it('should change only the baseURL of the specified instance', function() { + var instance1 = axios.create(); + var instance2 = axios.create(); + + instance1.defaults.baseURL = 'http://instance1.example.com/'; + + expect(instance2.defaults.baseURL).not.toBe('http://instance1.example.com/'); + }); + + it('should change only the headers of the specified instance', function() { + var instance1 = axios.create(); + var instance2 = axios.create(); + + instance1.defaults.headers.common.Authorization = 'faketoken'; + instance2.defaults.headers.common.Authorization = 'differentfaketoken'; + + instance1.defaults.headers.common['Content-Type'] = 'application/xml'; + instance2.defaults.headers.common['Content-Type'] = 'application/x-www-form-urlencoded'; + + expect(axios.defaults.headers.common.Authorization).toBe(undefined); + expect(instance1.defaults.headers.common.Authorization).toBe('faketoken'); + expect(instance2.defaults.headers.common.Authorization).toBe('differentfaketoken'); + + expect(axios.defaults.headers.common['Content-Type']).toBe(undefined); + expect(instance1.defaults.headers.common['Content-Type']).toBe('application/xml'); + expect(instance2.defaults.headers.common['Content-Type']).toBe('application/x-www-form-urlencoded'); + }); }); From d78204712a88f9e7c8ebad728143dee56ca995f3 Mon Sep 17 00:00:00 2001 From: Martti Laine Date: Fri, 9 Mar 2018 13:58:08 +0200 Subject: [PATCH 02/10] Clean up PR --- lib/axios.js | 2 +- lib/core/Axios.js | 10 +++------ lib/utils.js | 52 ++++++++++++++++++++--------------------------- 3 files changed, 26 insertions(+), 38 deletions(-) diff --git a/lib/axios.js b/lib/axios.js index 68621dd..11e274c 100644 --- a/lib/axios.js +++ b/lib/axios.js @@ -32,7 +32,7 @@ axios.Axios = Axios; // Factory for creating new instances axios.create = function create(instanceConfig) { - return createInstance(utils.mergeConfig(axios.defaults, instanceConfig || {})); + return createInstance(utils.mergeConfig(axios.defaults, instanceConfig)); }; // Expose Cancel & CancelToken diff --git a/lib/core/Axios.js b/lib/core/Axios.js index 766a897..92865d3 100644 --- a/lib/core/Axios.js +++ b/lib/core/Axios.js @@ -23,21 +23,17 @@ function Axios(instanceConfig) { * @param {Object} config The config specific for this request (merged with this.defaults) */ Axios.prototype.request = function request(config) { - config = config || {}; - /*eslint no-param-reassign:0*/ // Allow for axios('example/url'[, config]) a la fetch API if (typeof config === 'string') { config = arguments[1] || {}; config.url = arguments[0]; - } - - if (!config.method) { - config.method = 'get'; + } else { + config = config || {}; } config = utils.mergeConfig(this.defaults, config); - config.method = config.method.toLowerCase(); + config.method = config.method ? config.method.toLowerCase() : 'get'; // Hook up interceptors middleware var chain = [dispatchRequest, undefined]; diff --git a/lib/utils.js b/lib/utils.js index 342fa1f..14225bd 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -279,47 +279,39 @@ function extend(a, b, thisArg) { return a; } + +/** + * Config-specific merge-function which creates a new config-object + * based on given defaults and instance config. + * + * @param {Object} defaults Defaults + * @param {Object} instanceConfig Instance-specific config + * @returns {Object} New object resulting from merging instanceConfig to defaults + */ function mergeConfig(defaults, instanceConfig) { + instanceConfig = instanceConfig || {}; var config = {}; - forEach(['url', 'method', 'params', 'data'], function(prop) { + forEach(['url', 'method', 'params', 'data'], function valueFromInstanceConfig(prop) { config[prop] = instanceConfig[prop]; }); - forEach(['headers', 'auth', 'proxy'], function(prop) { + forEach(['headers', 'auth', 'proxy'], function mergeInstanceConfigWithDefaults(prop) { if (!isUndefined(instanceConfig[prop])) { - if (!isObject(instanceConfig[prop])) { - config[prop] = instanceConfig[prop]; + if (isObject(instanceConfig[prop])) { + config[prop] = merge(defaults[prop], instanceConfig[prop]); } else { - config[prop] = merge( - defaults[prop], - instanceConfig[prop] - ); + config[prop] = instanceConfig[prop]; } } else if (!isUndefined(defaults[prop])) { config[prop] = JSON.parse(JSON.stringify(defaults[prop])); } }); - var remainingProperties = [ - 'baseURL', - 'transformRequest', - 'transformResponse', - 'paramsSerializer', - 'timeout', - 'withCredentials', - 'adapter', - 'responseType', - 'xsrfCookieName', - 'xsrfHeaderName', - 'onUploadProgress', - 'onDownloadProgress', - 'maxContentLength', - 'validateStatus', - 'maxRedirects', - 'httpAgent', - 'httpsAgent', - 'cancelToken' - ]; - forEach(remainingProperties, function(prop) { - config[prop] = !isUndefined(instanceConfig[prop]) ? instanceConfig[prop] : defaults[prop]; + forEach([ + 'baseURL', 'transformRequest', 'transformResponse', 'paramsSerializer', + 'timeout', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName', + 'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress', 'maxContentLength', + 'validateStatus', 'maxRedirects', 'httpAgent', 'httpsAgent', 'cancelToken' + ], function defaultToInstanceConfig(prop) { + config[prop] = isUndefined(instanceConfig[prop]) ? defaults[prop] : instanceConfig[prop]; }); return config; } From 72c66dfdecbcc165c52fcd19d1f8444ad8c011c6 Mon Sep 17 00:00:00 2001 From: Martti Laine Date: Fri, 23 Mar 2018 20:21:02 +0100 Subject: [PATCH 03/10] Refactor and introduce deepMerge --- lib/axios.js | 3 +- lib/core/Axios.js | 3 +- lib/core/mergeConfig.js | 44 +++++++++++++++++++++++++++ lib/utils.js | 67 +++++++++++++++++------------------------ 4 files changed, 76 insertions(+), 41 deletions(-) create mode 100644 lib/core/mergeConfig.js diff --git a/lib/axios.js b/lib/axios.js index 11e274c..8142437 100644 --- a/lib/axios.js +++ b/lib/axios.js @@ -3,6 +3,7 @@ var utils = require('./utils'); var bind = require('./helpers/bind'); var Axios = require('./core/Axios'); +var mergeConfig = require('./core/mergeConfig'); var defaults = require('./defaults'); /** @@ -32,7 +33,7 @@ axios.Axios = Axios; // Factory for creating new instances axios.create = function create(instanceConfig) { - return createInstance(utils.mergeConfig(axios.defaults, instanceConfig)); + return createInstance(mergeConfig(axios.defaults, instanceConfig)); }; // Expose Cancel & CancelToken diff --git a/lib/core/Axios.js b/lib/core/Axios.js index 92865d3..8407a96 100644 --- a/lib/core/Axios.js +++ b/lib/core/Axios.js @@ -3,6 +3,7 @@ var utils = require('./../utils'); var InterceptorManager = require('./InterceptorManager'); var dispatchRequest = require('./dispatchRequest'); +var mergeConfig = require('./mergeConfig'); /** * Create a new instance of Axios @@ -32,7 +33,7 @@ Axios.prototype.request = function request(config) { config = config || {}; } - config = utils.mergeConfig(this.defaults, config); + config = mergeConfig(this.defaults, config); config.method = config.method ? config.method.toLowerCase() : 'get'; // Hook up interceptors middleware diff --git a/lib/core/mergeConfig.js b/lib/core/mergeConfig.js new file mode 100644 index 0000000..fea1238 --- /dev/null +++ b/lib/core/mergeConfig.js @@ -0,0 +1,44 @@ +'use strict'; + +var utils = require('../utils'); + +/** + * Config-specific merge-function which creates a new config-object + * based on given defaults and instance config. + * + * @param {Object} defaults Defaults + * @param {Object} instanceConfig Instance-specific config + * @returns {Object} New object resulting from merging instanceConfig to defaults + */ +module.exports = function mergeConfig(defaults, instanceConfig) { + // eslint-disable-next-line no-param-reassign + instanceConfig = instanceConfig || {}; + var config = {}; + + utils.forEach(['url', 'method', 'params', 'data'], function valueFromInstanceConfig(prop) { + config[prop] = instanceConfig[prop]; + }); + + utils.forEach(['headers', 'auth', 'proxy'], function mergeInstanceConfigWithDefaults(prop) { + if (typeof instanceConfig[prop] !== 'undefined') { + if (typeof instanceConfig[prop] === 'object') { + config[prop] = utils.deepMerge(defaults[prop], instanceConfig[prop]); + } else { + config[prop] = instanceConfig[prop]; + } + } else if (typeof defaults[prop] !== 'undefined') { + config[prop] = utils.deepMerge(defaults[prop]); + } + }); + + utils.forEach([ + 'baseURL', 'transformRequest', 'transformResponse', 'paramsSerializer', + 'timeout', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName', + 'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress', 'maxContentLength', + 'validateStatus', 'maxRedirects', 'httpAgent', 'httpsAgent', 'cancelToken' + ], function defaultToInstanceConfig(prop) { + config[prop] = typeof instanceConfig[prop] === 'undefined' ? defaults[prop] : instanceConfig[prop]; + }); + + return config; +}; diff --git a/lib/utils.js b/lib/utils.js index 14225bd..856aba3 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -260,6 +260,32 @@ function merge(/* obj1, obj2, obj3, ... */) { return result; } +/** + * Function equal to merge with the difference being that no reference + * to original objects is kept. + * + * @see merge + * @param {Object} obj1 Object to merge + * @returns {Object} Result of all merge properties + */ +function deepMerge(/* obj1, obj2, obj3, ... */) { + var result = {}; + function assignValue(val, key) { + if (typeof result[key] === 'object' && typeof val === 'object') { + result[key] = merge(result[key], val); + } else if (typeof val === 'object') { + result[key] = merge({}, val); + } else { + result[key] = val; + } + } + + for (var i = 0, l = arguments.length; i < l; i++) { + forEach(arguments[i], assignValue); + } + return result; +} + /** * Extends object a by mutably adding to it the properties of object b. * @@ -279,43 +305,6 @@ function extend(a, b, thisArg) { return a; } - -/** - * Config-specific merge-function which creates a new config-object - * based on given defaults and instance config. - * - * @param {Object} defaults Defaults - * @param {Object} instanceConfig Instance-specific config - * @returns {Object} New object resulting from merging instanceConfig to defaults - */ -function mergeConfig(defaults, instanceConfig) { - instanceConfig = instanceConfig || {}; - var config = {}; - forEach(['url', 'method', 'params', 'data'], function valueFromInstanceConfig(prop) { - config[prop] = instanceConfig[prop]; - }); - forEach(['headers', 'auth', 'proxy'], function mergeInstanceConfigWithDefaults(prop) { - if (!isUndefined(instanceConfig[prop])) { - if (isObject(instanceConfig[prop])) { - config[prop] = merge(defaults[prop], instanceConfig[prop]); - } else { - config[prop] = instanceConfig[prop]; - } - } else if (!isUndefined(defaults[prop])) { - config[prop] = JSON.parse(JSON.stringify(defaults[prop])); - } - }); - forEach([ - 'baseURL', 'transformRequest', 'transformResponse', 'paramsSerializer', - 'timeout', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName', - 'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress', 'maxContentLength', - 'validateStatus', 'maxRedirects', 'httpAgent', 'httpsAgent', 'cancelToken' - ], function defaultToInstanceConfig(prop) { - config[prop] = isUndefined(instanceConfig[prop]) ? defaults[prop] : instanceConfig[prop]; - }); - return config; -} - module.exports = { isArray: isArray, isArrayBuffer: isArrayBuffer, @@ -335,7 +324,7 @@ module.exports = { isStandardBrowserEnv: isStandardBrowserEnv, forEach: forEach, merge: merge, + deepMerge: deepMerge, extend: extend, - trim: trim, - mergeConfig: mergeConfig + trim: trim }; From 82030ae054ba10bbd25ef00b304990632780f11d Mon Sep 17 00:00:00 2001 From: Martti Laine Date: Tue, 3 Apr 2018 21:53:17 +0200 Subject: [PATCH 04/10] Use deepMerge in deepMerge --- lib/utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/utils.js b/lib/utils.js index 856aba3..aca5f4e 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -272,9 +272,9 @@ function deepMerge(/* obj1, obj2, obj3, ... */) { var result = {}; function assignValue(val, key) { if (typeof result[key] === 'object' && typeof val === 'object') { - result[key] = merge(result[key], val); + result[key] = deepMerge(result[key], val); } else if (typeof val === 'object') { - result[key] = merge({}, val); + result[key] = deepMerge({}, val); } else { result[key] = val; } From 6083d639c54cb093862bfee3f55d45e6456aa217 Mon Sep 17 00:00:00 2001 From: Martti Laine Date: Tue, 3 Apr 2018 21:53:45 +0200 Subject: [PATCH 05/10] Rename mergeConfig arguments --- lib/core/mergeConfig.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/core/mergeConfig.js b/lib/core/mergeConfig.js index fea1238..3b3d610 100644 --- a/lib/core/mergeConfig.js +++ b/lib/core/mergeConfig.js @@ -6,28 +6,28 @@ var utils = require('../utils'); * Config-specific merge-function which creates a new config-object * based on given defaults and instance config. * - * @param {Object} defaults Defaults - * @param {Object} instanceConfig Instance-specific config - * @returns {Object} New object resulting from merging instanceConfig to defaults + * @param {Object} config1 + * @param {Object} config2 + * @returns {Object} New object resulting from merging config2 to config1 */ -module.exports = function mergeConfig(defaults, instanceConfig) { +module.exports = function mergeConfig(config1, config2) { // eslint-disable-next-line no-param-reassign - instanceConfig = instanceConfig || {}; + config2 = config2 || {}; var config = {}; utils.forEach(['url', 'method', 'params', 'data'], function valueFromInstanceConfig(prop) { - config[prop] = instanceConfig[prop]; + config[prop] = config2[prop]; }); utils.forEach(['headers', 'auth', 'proxy'], function mergeInstanceConfigWithDefaults(prop) { - if (typeof instanceConfig[prop] !== 'undefined') { - if (typeof instanceConfig[prop] === 'object') { - config[prop] = utils.deepMerge(defaults[prop], instanceConfig[prop]); + if (typeof config2[prop] !== 'undefined') { + if (typeof config2[prop] === 'object') { + config[prop] = utils.deepMerge(config1[prop], config2[prop]); } else { - config[prop] = instanceConfig[prop]; + config[prop] = config2[prop]; } - } else if (typeof defaults[prop] !== 'undefined') { - config[prop] = utils.deepMerge(defaults[prop]); + } else if (typeof config1[prop] !== 'undefined') { + config[prop] = utils.deepMerge(config1[prop]); } }); @@ -37,7 +37,7 @@ module.exports = function mergeConfig(defaults, instanceConfig) { 'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress', 'maxContentLength', 'validateStatus', 'maxRedirects', 'httpAgent', 'httpsAgent', 'cancelToken' ], function defaultToInstanceConfig(prop) { - config[prop] = typeof instanceConfig[prop] === 'undefined' ? defaults[prop] : instanceConfig[prop]; + config[prop] = typeof config2[prop] === 'undefined' ? config1[prop] : config2[prop]; }); return config; From 506d4e894157cd5b94432c4d7904d832cf0b951f Mon Sep 17 00:00:00 2001 From: Martti Laine Date: Tue, 3 Apr 2018 22:19:38 +0200 Subject: [PATCH 06/10] Unit tests for deepMerge --- test/specs/utils/deepMerge.spec.js | 66 ++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 test/specs/utils/deepMerge.spec.js diff --git a/test/specs/utils/deepMerge.spec.js b/test/specs/utils/deepMerge.spec.js new file mode 100644 index 0000000..d879593 --- /dev/null +++ b/test/specs/utils/deepMerge.spec.js @@ -0,0 +1,66 @@ +var deepMerge = require('../../../lib/utils').deepMerge; + +describe('utils::deepMerge', function () { + it('should be immutable', function () { + var a = {}; + var b = {foo: 123}; + var c = {bar: 456}; + + deepMerge(a, b, c); + + expect(typeof a.foo).toEqual('undefined'); + expect(typeof a.bar).toEqual('undefined'); + expect(typeof b.bar).toEqual('undefined'); + expect(typeof c.foo).toEqual('undefined'); + }); + + it('should deepMerge properties', function () { + var a = {foo: 123}; + var b = {bar: 456}; + var c = {foo: 789}; + var d = deepMerge(a, b, c); + + expect(d.foo).toEqual(789); + expect(d.bar).toEqual(456); + }); + + it('should deepMerge recursively', function () { + var a = {foo: {bar: 123}}; + var b = {foo: {baz: 456}, bar: {qux: 789}}; + + expect(deepMerge(a, b)).toEqual({ + foo: { + bar: 123, + baz: 456 + }, + bar: { + qux: 789 + } + }); + }); + + it('should remove all references from nested objects', function () { + var a = {foo: {bar: 123}}; + var b = {}; + var d = deepMerge(a, b); + + expect(d).toEqual({ + foo: { + bar: 123 + } + }); + + expect(d.foo).not.toBe(a.foo); + }); + + it('handles null and undefined arguments', function () { + expect(deepMerge(undefined, undefined)).toEqual({}); + expect(deepMerge(undefined, {foo: 123})).toEqual({foo: 123}); + expect(deepMerge({foo: 123}, undefined)).toEqual({foo: 123}); + + expect(deepMerge(null, null)).toEqual({}); + expect(deepMerge(null, {foo: 123})).toEqual({foo: 123}); + expect(deepMerge({foo: 123}, null)).toEqual({foo: 123}); + }); +}); + From b1c378606f09a38d7e6713595add07676882b8f2 Mon Sep 17 00:00:00 2001 From: Martti Laine Date: Tue, 3 Apr 2018 22:29:15 +0200 Subject: [PATCH 07/10] Prevent undefined values in mergeConfig --- lib/core/mergeConfig.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/core/mergeConfig.js b/lib/core/mergeConfig.js index 3b3d610..e8782ab 100644 --- a/lib/core/mergeConfig.js +++ b/lib/core/mergeConfig.js @@ -16,7 +16,9 @@ module.exports = function mergeConfig(config1, config2) { var config = {}; utils.forEach(['url', 'method', 'params', 'data'], function valueFromInstanceConfig(prop) { - config[prop] = config2[prop]; + if (typeof config2[prop] !== 'undefined') { + config[prop] = config2[prop]; + } }); utils.forEach(['headers', 'auth', 'proxy'], function mergeInstanceConfigWithDefaults(prop) { From ff61caacb78da139b3a1b199df2c4b40cd55a3cc Mon Sep 17 00:00:00 2001 From: Martti Laine Date: Sat, 7 Apr 2018 13:40:21 +0200 Subject: [PATCH 08/10] Slight refactor/namings/comment on mergeConfig --- lib/core/mergeConfig.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/core/mergeConfig.js b/lib/core/mergeConfig.js index e8782ab..ad7d0f8 100644 --- a/lib/core/mergeConfig.js +++ b/lib/core/mergeConfig.js @@ -4,7 +4,7 @@ var utils = require('../utils'); /** * Config-specific merge-function which creates a new config-object - * based on given defaults and instance config. + * by merging two configuration objects together. * * @param {Object} config1 * @param {Object} config2 @@ -15,13 +15,11 @@ module.exports = function mergeConfig(config1, config2) { config2 = config2 || {}; var config = {}; - utils.forEach(['url', 'method', 'params', 'data'], function valueFromInstanceConfig(prop) { - if (typeof config2[prop] !== 'undefined') { - config[prop] = config2[prop]; - } + utils.forEach(['url', 'method', 'params', 'data'], function valueFromConfig2(prop) { + config[prop] = config2[prop]; }); - utils.forEach(['headers', 'auth', 'proxy'], function mergeInstanceConfigWithDefaults(prop) { + utils.forEach(['headers', 'auth', 'proxy'], function mergeValues(prop) { if (typeof config2[prop] !== 'undefined') { if (typeof config2[prop] === 'object') { config[prop] = utils.deepMerge(config1[prop], config2[prop]); @@ -38,7 +36,7 @@ module.exports = function mergeConfig(config1, config2) { 'timeout', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName', 'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress', 'maxContentLength', 'validateStatus', 'maxRedirects', 'httpAgent', 'httpsAgent', 'cancelToken' - ], function defaultToInstanceConfig(prop) { + ], function defaultToConfig2(prop) { config[prop] = typeof config2[prop] === 'undefined' ? config1[prop] : config2[prop]; }); From 143bbbe1b96f7819d6df5f1c249ba0964cf84819 Mon Sep 17 00:00:00 2001 From: Martti Laine Date: Sat, 7 Apr 2018 15:54:56 +0200 Subject: [PATCH 09/10] Spec for mergeConfig, finalize logic --- lib/core/mergeConfig.js | 26 ++++++----- lib/defaults.js | 1 - test/specs/core/mergeConfig.spec.js | 69 +++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 11 deletions(-) create mode 100644 test/specs/core/mergeConfig.spec.js diff --git a/lib/core/mergeConfig.js b/lib/core/mergeConfig.js index ad7d0f8..1da9040 100644 --- a/lib/core/mergeConfig.js +++ b/lib/core/mergeConfig.js @@ -16,18 +16,20 @@ module.exports = function mergeConfig(config1, config2) { var config = {}; utils.forEach(['url', 'method', 'params', 'data'], function valueFromConfig2(prop) { - config[prop] = config2[prop]; + if (typeof config2[prop] !== 'undefined') { + config[prop] = config2[prop]; + } }); - utils.forEach(['headers', 'auth', 'proxy'], function mergeValues(prop) { - if (typeof config2[prop] !== 'undefined') { - if (typeof config2[prop] === 'object') { - config[prop] = utils.deepMerge(config1[prop], config2[prop]); - } else { - config[prop] = config2[prop]; - } - } else if (typeof config1[prop] !== 'undefined') { + utils.forEach(['headers', 'auth', 'proxy'], function mergeDeepProperties(prop) { + if (utils.isObject(config2[prop])) { + config[prop] = utils.deepMerge(config1[prop], config2[prop]); + } else if (typeof config2[prop] !== 'undefined') { + config[prop] = config2[prop]; + } else if (utils.isObject(config1[prop])) { config[prop] = utils.deepMerge(config1[prop]); + } else if (typeof config1[prop] !== 'undefined') { + config[prop] = config1[prop]; } }); @@ -37,7 +39,11 @@ module.exports = function mergeConfig(config1, config2) { 'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress', 'maxContentLength', 'validateStatus', 'maxRedirects', 'httpAgent', 'httpsAgent', 'cancelToken' ], function defaultToConfig2(prop) { - config[prop] = typeof config2[prop] === 'undefined' ? config1[prop] : config2[prop]; + if (typeof config2[prop] !== 'undefined') { + config[prop] = config2[prop]; + } else if (typeof config1[prop] !== 'undefined') { + config[prop] = config1[prop]; + } }); return config; diff --git a/lib/defaults.js b/lib/defaults.js index e1bc1ca..65a25d5 100644 --- a/lib/defaults.js +++ b/lib/defaults.js @@ -26,7 +26,6 @@ function getDefaultAdapter() { } var defaults = { - method: 'get', adapter: getDefaultAdapter(), transformRequest: [function transformRequest(data, headers) { diff --git a/test/specs/core/mergeConfig.spec.js b/test/specs/core/mergeConfig.spec.js new file mode 100644 index 0000000..bf6d209 --- /dev/null +++ b/test/specs/core/mergeConfig.spec.js @@ -0,0 +1,69 @@ +var defaults = require('../../../lib/defaults'); +var mergeConfig = require('../../../lib/core/mergeConfig'); + +describe('core::mergeConfig', function() { + it('should accept undefined for second argument', function() { + expect(mergeConfig(defaults, undefined)).toEqual(defaults); + }); + + it('should accept an object for second argument', function() { + expect(mergeConfig(defaults, {})).toEqual(defaults); + }); + + it('should not leave references', function() { + var merged = mergeConfig(defaults, {}); + expect(merged).not.toBe(defaults); + expect(merged.headers).not.toBe(defaults.headers); + }); + + it('should allow setting request options', function() { + var config = { + url: '__sample url__', + method: '__sample method__', + params: '__sample params__', + data: { foo: true } + }; + var merged = mergeConfig(defaults, config); + expect(merged.url).toEqual(config.url); + expect(merged.method).toEqual(config.method); + expect(merged.params).toEqual(config.params); + expect(merged.data).toEqual(config.data); + }); + + it('should not inherit request options', function() { + var localDefaults = { + url: '__sample url__', + method: '__sample method__', + params: '__sample params__', + data: { foo: true } + }; + var merged = mergeConfig(localDefaults, {}); + expect(merged.url).toEqual(undefined); + expect(merged.method).toEqual(undefined); + expect(merged.params).toEqual(undefined); + expect(merged.data).toEqual(undefined); + }); + + it('should merge auth, headers, proxy with defaults', function() { + expect(mergeConfig({ auth: undefined }, { auth: { user: 'foo', pass: 'test' } })).toEqual({ + auth: { user: 'foo', pass: 'test' } + }); + expect(mergeConfig({ auth: { user: 'foo', pass: 'test' } }, { auth: { pass: 'foobar' } })).toEqual({ + auth: { user: 'foo', pass: 'foobar' } + }); + }); + + it('should overwrite auth, headers, proxy with a non-object value', function() { + expect(mergeConfig({ auth: { user: 'foo', pass: 'test' } }, { auth: false })).toEqual({ + auth: false + }); + expect(mergeConfig({ auth: { user: 'foo', pass: 'test' } }, { auth: null })).toEqual({ + auth: null + }); + }); + + it('should allow setting other options', function() { + var merged = mergeConfig(defaults, { timeout: 123 }); + expect(merged.timeout).toEqual(123); + }); +}); From 4e8039ef65d3daa35b1c5a1cd13beaf4c283249a Mon Sep 17 00:00:00 2001 From: Martti Laine Date: Tue, 10 Apr 2018 22:29:02 +0200 Subject: [PATCH 10/10] Remember socketPath in mergeConfig --- lib/core/mergeConfig.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/core/mergeConfig.js b/lib/core/mergeConfig.js index 1da9040..6097a3e 100644 --- a/lib/core/mergeConfig.js +++ b/lib/core/mergeConfig.js @@ -37,7 +37,8 @@ module.exports = function mergeConfig(config1, config2) { 'baseURL', 'transformRequest', 'transformResponse', 'paramsSerializer', 'timeout', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName', 'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress', 'maxContentLength', - 'validateStatus', 'maxRedirects', 'httpAgent', 'httpsAgent', 'cancelToken' + 'validateStatus', 'maxRedirects', 'httpAgent', 'httpsAgent', 'cancelToken', + 'socketPath' ], function defaultToConfig2(prop) { if (typeof config2[prop] !== 'undefined') { config[prop] = config2[prop];