mergeConfig.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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. const ownEnumerableKeys = (thing) => {
  6. if (Object.getOwnPropertySymbols && Object.getOwnPropertyDescriptor) {
  7. return Object.keys(thing).concat(
  8. Object.getOwnPropertySymbols(thing).filter(
  9. (symbol) => Object.getOwnPropertyDescriptor(thing, symbol).enumerable
  10. )
  11. );
  12. }
  13. return Object.keys(thing);
  14. };
  15. /**
  16. * Config-specific merge-function which creates a new config-object
  17. * by merging two configuration objects together.
  18. *
  19. * @param {Object} config1
  20. * @param {Object} config2
  21. *
  22. * @returns {Object} New object resulting from merging config2 to config1
  23. */
  24. export default function mergeConfig(config1, config2) {
  25. // eslint-disable-next-line no-param-reassign
  26. config1 = config1 || {};
  27. config2 = config2 || {};
  28. // Use a null-prototype object so that downstream reads such as `config.auth`
  29. // or `config.baseURL` cannot inherit polluted values from Object.prototype.
  30. // `hasOwnProperty` is restored as a non-enumerable own slot to preserve
  31. // ergonomics for user code that relies on it.
  32. const config = Object.create(null);
  33. Object.defineProperty(config, 'hasOwnProperty', {
  34. // Null-proto descriptor so a polluted Object.prototype.get cannot turn
  35. // this data descriptor into an accessor descriptor on the way in.
  36. __proto__: null,
  37. value: Object.prototype.hasOwnProperty,
  38. enumerable: false,
  39. writable: true,
  40. configurable: true,
  41. });
  42. function getMergedValue(target, source, prop, caseless) {
  43. if (utils.isPlainObject(target) && utils.isPlainObject(source)) {
  44. return utils.merge.call({ caseless }, target, source);
  45. } else if (utils.isPlainObject(source)) {
  46. return utils.merge({}, source);
  47. } else if (utils.isArray(source)) {
  48. return source.slice();
  49. }
  50. return source;
  51. }
  52. function mergeDeepProperties(a, b, prop, caseless) {
  53. if (!utils.isUndefined(b)) {
  54. return getMergedValue(a, b, prop, caseless);
  55. } else if (!utils.isUndefined(a)) {
  56. return getMergedValue(undefined, a, prop, caseless);
  57. }
  58. }
  59. // eslint-disable-next-line consistent-return
  60. function valueFromConfig2(a, b) {
  61. if (!utils.isUndefined(b)) {
  62. return getMergedValue(undefined, b);
  63. }
  64. }
  65. // eslint-disable-next-line consistent-return
  66. function defaultToConfig2(a, b) {
  67. if (!utils.isUndefined(b)) {
  68. return getMergedValue(undefined, b);
  69. } else if (!utils.isUndefined(a)) {
  70. return getMergedValue(undefined, a);
  71. }
  72. }
  73. function getMergedTransitionalOption(prop) {
  74. const transitional2 = utils.hasOwnProp(config2, 'transitional')
  75. ? config2.transitional
  76. : undefined;
  77. if (!utils.isUndefined(transitional2)) {
  78. if (utils.isPlainObject(transitional2)) {
  79. if (utils.hasOwnProp(transitional2, prop)) {
  80. return transitional2[prop];
  81. }
  82. } else {
  83. return undefined;
  84. }
  85. }
  86. const transitional1 = utils.hasOwnProp(config1, 'transitional')
  87. ? config1.transitional
  88. : undefined;
  89. if (utils.isPlainObject(transitional1) && utils.hasOwnProp(transitional1, prop)) {
  90. return transitional1[prop];
  91. }
  92. return undefined;
  93. }
  94. // eslint-disable-next-line consistent-return
  95. function mergeDirectKeys(a, b, prop) {
  96. if (utils.hasOwnProp(config2, prop)) {
  97. return getMergedValue(a, b);
  98. } else if (utils.hasOwnProp(config1, prop)) {
  99. return getMergedValue(undefined, a);
  100. }
  101. }
  102. const mergeMap = {
  103. url: valueFromConfig2,
  104. method: valueFromConfig2,
  105. data: valueFromConfig2,
  106. baseURL: defaultToConfig2,
  107. transformRequest: defaultToConfig2,
  108. transformResponse: defaultToConfig2,
  109. paramsSerializer: defaultToConfig2,
  110. timeout: defaultToConfig2,
  111. timeoutMessage: defaultToConfig2,
  112. withCredentials: defaultToConfig2,
  113. withXSRFToken: defaultToConfig2,
  114. adapter: defaultToConfig2,
  115. responseType: defaultToConfig2,
  116. xsrfCookieName: defaultToConfig2,
  117. xsrfHeaderName: defaultToConfig2,
  118. onUploadProgress: defaultToConfig2,
  119. onDownloadProgress: defaultToConfig2,
  120. decompress: defaultToConfig2,
  121. maxContentLength: defaultToConfig2,
  122. maxBodyLength: defaultToConfig2,
  123. beforeRedirect: defaultToConfig2,
  124. transport: defaultToConfig2,
  125. httpAgent: defaultToConfig2,
  126. httpsAgent: defaultToConfig2,
  127. cancelToken: defaultToConfig2,
  128. socketPath: defaultToConfig2,
  129. allowedSocketPaths: defaultToConfig2,
  130. responseEncoding: defaultToConfig2,
  131. validateStatus: mergeDirectKeys,
  132. headers: (a, b, prop) =>
  133. mergeDeepProperties(headersToObject(a), headersToObject(b), prop, true),
  134. };
  135. utils.forEach(ownEnumerableKeys({ ...config1, ...config2 }), function computeConfigValue(prop) {
  136. if (prop === '__proto__' || prop === 'constructor' || prop === 'prototype') return;
  137. const merge = utils.hasOwnProp(mergeMap, prop) ? mergeMap[prop] : mergeDeepProperties;
  138. const a = utils.hasOwnProp(config1, prop) ? config1[prop] : undefined;
  139. const b = utils.hasOwnProp(config2, prop) ? config2[prop] : undefined;
  140. const configValue = merge(a, b, prop);
  141. (utils.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue);
  142. });
  143. if (
  144. utils.hasOwnProp(config2, 'validateStatus') &&
  145. utils.isUndefined(config2.validateStatus) &&
  146. getMergedTransitionalOption('validateStatusUndefinedResolves') === false
  147. ) {
  148. if (utils.hasOwnProp(config1, 'validateStatus')) {
  149. config.validateStatus = getMergedValue(undefined, config1.validateStatus);
  150. } else {
  151. delete config.validateStatus;
  152. }
  153. }
  154. return config;
  155. }