mergeConfig.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. 'use strict';
  2. import utils from '../utils.js';
  3. import AxiosHeaders from './AxiosHeaders.js';
  4. const headersToObject = (thing) => (thing instanceof AxiosHeaders ? { ...thing } : thing);
  5. /**
  6. * Config-specific merge-function which creates a new config-object
  7. * by merging two configuration objects together.
  8. *
  9. * @param {Object} config1
  10. * @param {Object} config2
  11. *
  12. * @returns {Object} New object resulting from merging config2 to config1
  13. */
  14. export default function mergeConfig(config1, config2) {
  15. // eslint-disable-next-line no-param-reassign
  16. config2 = config2 || {};
  17. // Use a null-prototype object so that downstream reads such as `config.auth`
  18. // or `config.baseURL` cannot inherit polluted values from Object.prototype.
  19. // `hasOwnProperty` is restored as a non-enumerable own slot to preserve
  20. // ergonomics for user code that relies on it.
  21. const config = Object.create(null);
  22. Object.defineProperty(config, 'hasOwnProperty', {
  23. // Null-proto descriptor so a polluted Object.prototype.get cannot turn
  24. // this data descriptor into an accessor descriptor on the way in.
  25. __proto__: null,
  26. value: Object.prototype.hasOwnProperty,
  27. enumerable: false,
  28. writable: true,
  29. configurable: true,
  30. });
  31. function getMergedValue(target, source, prop, caseless) {
  32. if (utils.isPlainObject(target) && utils.isPlainObject(source)) {
  33. return utils.merge.call({ caseless }, target, source);
  34. } else if (utils.isPlainObject(source)) {
  35. return utils.merge({}, source);
  36. } else if (utils.isArray(source)) {
  37. return source.slice();
  38. }
  39. return source;
  40. }
  41. function mergeDeepProperties(a, b, prop, caseless) {
  42. if (!utils.isUndefined(b)) {
  43. return getMergedValue(a, b, prop, caseless);
  44. } else if (!utils.isUndefined(a)) {
  45. return getMergedValue(undefined, a, prop, caseless);
  46. }
  47. }
  48. // eslint-disable-next-line consistent-return
  49. function valueFromConfig2(a, b) {
  50. if (!utils.isUndefined(b)) {
  51. return getMergedValue(undefined, b);
  52. }
  53. }
  54. // eslint-disable-next-line consistent-return
  55. function defaultToConfig2(a, b) {
  56. if (!utils.isUndefined(b)) {
  57. return getMergedValue(undefined, b);
  58. } else if (!utils.isUndefined(a)) {
  59. return getMergedValue(undefined, a);
  60. }
  61. }
  62. // eslint-disable-next-line consistent-return
  63. function mergeDirectKeys(a, b, prop) {
  64. if (utils.hasOwnProp(config2, prop)) {
  65. return getMergedValue(a, b);
  66. } else if (utils.hasOwnProp(config1, prop)) {
  67. return getMergedValue(undefined, a);
  68. }
  69. }
  70. const mergeMap = {
  71. url: valueFromConfig2,
  72. method: valueFromConfig2,
  73. data: valueFromConfig2,
  74. baseURL: defaultToConfig2,
  75. transformRequest: defaultToConfig2,
  76. transformResponse: defaultToConfig2,
  77. paramsSerializer: defaultToConfig2,
  78. timeout: defaultToConfig2,
  79. timeoutMessage: defaultToConfig2,
  80. withCredentials: defaultToConfig2,
  81. withXSRFToken: defaultToConfig2,
  82. adapter: defaultToConfig2,
  83. responseType: defaultToConfig2,
  84. xsrfCookieName: defaultToConfig2,
  85. xsrfHeaderName: defaultToConfig2,
  86. onUploadProgress: defaultToConfig2,
  87. onDownloadProgress: defaultToConfig2,
  88. decompress: defaultToConfig2,
  89. maxContentLength: defaultToConfig2,
  90. maxBodyLength: defaultToConfig2,
  91. beforeRedirect: defaultToConfig2,
  92. transport: defaultToConfig2,
  93. httpAgent: defaultToConfig2,
  94. httpsAgent: defaultToConfig2,
  95. cancelToken: defaultToConfig2,
  96. socketPath: defaultToConfig2,
  97. allowedSocketPaths: defaultToConfig2,
  98. responseEncoding: defaultToConfig2,
  99. validateStatus: mergeDirectKeys,
  100. headers: (a, b, prop) =>
  101. mergeDeepProperties(headersToObject(a), headersToObject(b), prop, true),
  102. };
  103. utils.forEach(Object.keys({ ...config1, ...config2 }), function computeConfigValue(prop) {
  104. if (prop === '__proto__' || prop === 'constructor' || prop === 'prototype') return;
  105. const merge = utils.hasOwnProp(mergeMap, prop) ? mergeMap[prop] : mergeDeepProperties;
  106. const a = utils.hasOwnProp(config1, prop) ? config1[prop] : undefined;
  107. const b = utils.hasOwnProp(config2, prop) ? config2[prop] : undefined;
  108. const configValue = merge(a, b, prop);
  109. (utils.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue);
  110. });
  111. return config;
  112. }