Skip to content

Commit

Permalink
Refactor mergeConfig without utils.deepMerge (#2844)
Browse files Browse the repository at this point in the history
* Adding failing test

* Fixing #2587 default custom config persisting

* Adding Concat keys and filter duplicates

* Fixed value from CPE

* update for review feedbacks

* no deepMerge

* only merge between plain objects

* fix rename

* always merge config by mergeConfig

* extract function mergeDeepProperties

* refactor mergeConfig with all keys, and add special logic for validateStatus

* add test for resetting headers

* add lots of tests and fix a bug

* should not inherit `data`

* use simple toString

* revert #1845

Co-authored-by: David Tanner <david.tanner@lifeomic.com>
Co-authored-by: Justin Beckwith <justin.beckwith@gmail.com>
  • Loading branch information
3 people committed Jun 8, 2020
1 parent 4879416 commit 0d69a79
Show file tree
Hide file tree
Showing 10 changed files with 412 additions and 153 deletions.
4 changes: 2 additions & 2 deletions lib/core/Axios.js
Expand Up @@ -73,7 +73,7 @@ Axios.prototype.getUri = function getUri(config) {
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, config) {
return this.request(utils.merge(config || {}, {
return this.request(mergeConfig(config || {}, {
method: method,
url: url
}));
Expand All @@ -83,7 +83,7 @@ utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData
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 || {}, {
return this.request(mergeConfig(config || {}, {
method: method,
url: url,
data: data
Expand Down
7 changes: 0 additions & 7 deletions lib/core/dispatchRequest.js
Expand Up @@ -47,13 +47,6 @@ module.exports = function dispatchRequest(config) {
}
);

// Remove header where value is null
utils.forEach(config.headers, function deleteNullValueHeaders(value, key) {
if (value === null) {
delete config.headers[key];
}
});

var adapter = config.adapter || defaults.adapter;

return adapter(config).then(function onAdapterResolution(response) {
Expand Down
72 changes: 43 additions & 29 deletions lib/core/mergeConfig.js
Expand Up @@ -18,56 +18,70 @@ module.exports = function mergeConfig(config1, config2) {
var valueFromConfig2Keys = ['url', 'method', 'data'];
var mergeDeepPropertiesKeys = ['headers', 'auth', 'proxy', 'params'];
var defaultToConfig2Keys = [
'baseURL', 'url', 'transformRequest', 'transformResponse', 'paramsSerializer',
'timeout', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName',
'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress',
'maxContentLength', 'maxBodyLength', 'validateStatus', 'maxRedirects', 'httpAgent',
'baseURL', 'transformRequest', 'transformResponse', 'paramsSerializer',
'timeout', 'timeoutMessage', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName',
'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress', 'decompress',
'maxContentLength', 'maxBodyLength', 'maxRedirects', 'transport', 'httpAgent',
'httpsAgent', 'cancelToken', 'socketPath', 'responseEncoding'
];
var directMergeKeys = ['validateStatus'];

function getMergedValue(target, source) {
if (utils.isPlainObject(target) && utils.isPlainObject(source)) {
return utils.merge(target, source);
} else if (utils.isPlainObject(source)) {
return utils.merge({}, source);
} else if (utils.isArray(source)) {
return source.slice();
}
return source;
}

function mergeDeepProperties(prop) {
if (!utils.isUndefined(config2[prop])) {
config[prop] = getMergedValue(config1[prop], config2[prop]);
} else if (!utils.isUndefined(config1[prop])) {
config[prop] = getMergedValue(undefined, config1[prop]);
}
}

utils.forEach(valueFromConfig2Keys, function valueFromConfig2(prop) {
if (typeof config2[prop] !== 'undefined') {
config[prop] = config2[prop];
if (!utils.isUndefined(config2[prop])) {
config[prop] = getMergedValue(undefined, config2[prop]);
}
});

utils.forEach(mergeDeepPropertiesKeys, 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];
utils.forEach(mergeDeepPropertiesKeys, mergeDeepProperties);

utils.forEach(defaultToConfig2Keys, function defaultToConfig2(prop) {
if (!utils.isUndefined(config2[prop])) {
config[prop] = getMergedValue(undefined, config2[prop]);
} else if (!utils.isUndefined(config1[prop])) {
config[prop] = getMergedValue(undefined, config1[prop]);
}
});

utils.forEach(defaultToConfig2Keys, function defaultToConfig2(prop) {
if (typeof config2[prop] !== 'undefined') {
config[prop] = config2[prop];
} else if (typeof config1[prop] !== 'undefined') {
config[prop] = config1[prop];
utils.forEach(directMergeKeys, function merge(prop) {
if (prop in config2) {
config[prop] = getMergedValue(config1[prop], config2[prop]);
} else if (prop in config1) {
config[prop] = getMergedValue(undefined, config1[prop]);
}
});

var axiosKeys = valueFromConfig2Keys
.concat(mergeDeepPropertiesKeys)
.concat(defaultToConfig2Keys);
.concat(defaultToConfig2Keys)
.concat(directMergeKeys);

var otherKeys = Object
.keys(config2)
.keys(config1)
.concat(Object.keys(config2))
.filter(function filterAxiosKeys(key) {
return axiosKeys.indexOf(key) === -1;
});

utils.forEach(otherKeys, function otherKeysDefaultToConfig2(prop) {
if (typeof config2[prop] !== 'undefined') {
config[prop] = config2[prop];
} else if (typeof config1[prop] !== 'undefined') {
config[prop] = config1[prop];
}
});
utils.forEach(otherKeys, mergeDeepProperties);

return config;
};
54 changes: 21 additions & 33 deletions lib/utils.js
Expand Up @@ -105,6 +105,21 @@ function isObject(val) {
return val !== null && typeof val === 'object';
}

/**
* Determine if a value is a plain Object
*
* @param {Object} val The value to test
* @return {boolean} True if value is a plain Object, otherwise false
*/
function isPlainObject(val) {
if (toString.call(val) !== '[object Object]') {
return false;
}

var prototype = Object.getPrototypeOf(val);
return prototype === null || prototype === Object.prototype;
}

/**
* Determine if a value is a Date
*
Expand Down Expand Up @@ -261,8 +276,12 @@ function forEach(obj, fn) {
function merge(/* obj1, obj2, obj3, ... */) {
var result = {};
function assignValue(val, key) {
if (typeof result[key] === 'object' && typeof val === 'object') {
if (isPlainObject(result[key]) && isPlainObject(val)) {
result[key] = merge(result[key], val);
} else if (isPlainObject(val)) {
result[key] = merge({}, val);
} else if (isArray(val)) {
result[key] = val.slice();
} else {
result[key] = val;
}
Expand All @@ -274,37 +293,6 @@ 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] = deepMerge(result[key], val);
} else if (typeof val === 'object') {
result[key] = deepMerge({}, val);
} else {
result[key] = val;
}
}

var lastArgument = arguments[arguments.length - 1];
if (lastArgument === null || typeof lastArgument === 'undefined') {
return lastArgument;
}

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.
*
Expand Down Expand Up @@ -333,6 +321,7 @@ module.exports = {
isString: isString,
isNumber: isNumber,
isObject: isObject,
isPlainObject: isPlainObject,
isUndefined: isUndefined,
isDate: isDate,
isFile: isFile,
Expand All @@ -343,7 +332,6 @@ module.exports = {
isStandardBrowserEnv: isStandardBrowserEnv,
forEach: forEach,
merge: merge,
deepMerge: deepMerge,
extend: extend,
trim: trim
};

0 comments on commit 0d69a79

Please sign in to comment.