repo_description: Promise based HTTP client for the browser and node.js
repo_topics: hacktoberfest http-client javascript nodejs promise
code: 'use strict';
  
  import utils from '../utils.js';
  import buildURL from '../helpers/buildURL.js';
  import InterceptorManager from './InterceptorManager.js';
  import dispatchRequest from './dispatchRequest.js';
  import mergeConfig from './mergeConfig.js';
  import buildFullPath from './buildFullPath.js';
  import validator from '../helpers/validator.js';
  import AxiosHeaders from './AxiosHeaders.js';
  import transitionalDefaults from '../defaults/transitional.js';
  
  const validators = validator.validators;
  
  /**
   * Create a new instance of Axios
   *
   * @param {Object} instanceConfig The default config for the instance
   *
   * @return {Axios} A new instance of Axios
   */
  class Axios {
    constructor(instanceConfig) {
      this.defaults = instanceConfig || {};
      this.interceptors = {
        request: new InterceptorManager(),
        response: new InterceptorManager(),
      };
    }
  
    /**
     * Dispatch a request
     *
     * @param {String|Object} configOrUrl The config specific for this request (merged with this.defaults)
     * @param {?Object} config
     *
     * @returns {Promise} The Promise to be fulfilled
     */
    async request(configOrUrl, config) {
      try {
        return await this._request(configOrUrl, config);
      } catch (err) {
        if (err instanceof Error) {
          let dummy = {};
  
          Error.captureStackTrace ? Error.captureStackTrace(dummy) : (dummy = new Error());
  
          // slice off the Error: ... line
          const stack = (() => {
            if (!dummy.stack) {
              return '';
            }
  
            const firstNewlineIndex = dummy.stack.indexOf('\n');
  
            return firstNewlineIndex === -1 ? '' : dummy.stack.slice(firstNewlineIndex + 1);
          })();
          try {
            if (!err.stack) {
              err.stack = stack;
              // match without the 2 top stack lines
            } else if (stack) {
              const firstNewlineIndex = stack.indexOf('\n');
              const secondNewlineIndex =
                firstNewlineIndex === -1 ? -1 : stack.indexOf('\n', firstNewlineIndex + 1);
              const stackWithoutTwoTopLines =
                secondNewlineIndex === -1 ? '' : stack.slice(secondNewlineIndex + 1);
  
              if (!String(err.stack).endsWith(stackWithoutTwoTopLines)) {
                err.stack += '\n' + stack;
              }
            }
          } catch (e) {
            // ignore the case where "stack" is an un-writable property
          }
        }
  
        throw err;
      }
    }
  
    _request(configOrUrl, config) {
      /*eslint no-param-reassign:0*/
      // Allow for axios('example/url'[, config]) a la fetch API
      if (typeof configOrUrl === 'string') {
        config = config || {};
        config.url = configOrUrl;
      } else {
        config = configOrUrl || {};
      }
  
      config = mergeConfig(this.defaults, config);
  
      const { transitional, paramsSerializer, headers } = config;
  
      if (transitional !== undefined) {
        validator.assertOptions(
          transitional,
          {
            silentJSONParsing: validators.transitional(validators.boolean),
            forcedJSONParsing: validators.transitional(validators.boolean),
            clarifyTimeoutError: validators.transitional(validators.boolean),
            legacyInterceptorReqResOrdering: validators.transitional(validators.boolean),
          },
          false
        );
      }
  
      if (paramsSerializer != null) {
        if (utils.isFunction(paramsSerializer)) {
          config.paramsSerializer = {
            serialize: paramsSerializer,
          };
        } else {
          validator.assertOptions(
            paramsSerializer,
            {
              encode: validators.function,
              serialize: validators.function,
            },
            true
          );
        }
      }
  
      // Set config.allowAbsoluteUrls
      if (config.allowAbsoluteUrls !== undefined) {
        // do nothing
      } else if (this.defaults.allowAbsoluteUrls !== undefined) {
        config.allowAbsoluteUrls = this.defaults.allowAbsoluteUrls;
      } else {
        config.allowAbsoluteUrls = true;
      }
  
      validator.assertOptions(
        config,
        {
          baseUrl: validators.spelling('baseURL'),
          withXsrfToken: validators.spelling('withXSRFToken'),
        },
        true
      );
  
      // Set config.method
      config.method = (config.method || this.defaults.method || 'get').toLowerCase();
  
      // Flatten headers
      let contextHeaders = headers && utils.merge(headers.common, headers[config.method]);
  
      headers &&
        utils.forEach(['delete', 'get', 'head', 'post', 'put', 'patch', 'common'], (method) => {
          delete headers[method];
        });
  
      config.headers = AxiosHeaders.concat(contextHeaders, headers);
  
      // filter out skipped interceptors
      const requestInterceptorChain = [];
      let synchronousRequestInterceptors = true;
      this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
        if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {
          return;
        }
  
        synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
  
        const transitional = config.transitional || transitionalDefaults;
        const legacyInterceptorReqResOrdering =
          transitional && transitional.legacyInterceptorReqResOrdering;
  
        if (legacyInterceptorReqResOrdering) {
          requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
        } else {
          requestInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
        }
      });
  
      const responseInterceptorChain = [];
      this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
        responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
      });
  
      let promise;
      let i = 0;
      let len;
  
      if (!synchronousRequestInterceptors) {
        const chain = [dispatchRequest.bind(this), undefined];
        chain.unshift(...requestInterceptorChain);
        chain.push(...responseInterceptorChain);
        len = chain.length;
  
        promise = Promise.resolve(config);
  
        while (i < len) {
          promise = promise.then(chain[i++], chain[i++]);
        }
  
        return promise;
      }
  
      len = requestInterceptorChain.length;
  
      let newConfig = config;
  
      while (i < len) {
        const onFulfilled = requestInterceptorChain[i++];
        const onRejected = requestInterceptorChain[i++];
        try {
          newConfig = onFulfilled(newConfig);
        } catch (error) {
          onRejected.call(this, error);
          break;
        }
      }
  
      try {
        promise = dispatchRequest.call(this, newConfig);
      } catch (error) {
        return Promise.reject(error);
      }
  
      i = 0;
      len = responseInterceptorChain.length;
  
      while (i < len) {
        promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++]);
      }
  
      return promise;
    }
  
    getUri(config) {
      config = mergeConfig(this.defaults, config);
      const fullPath = buildFullPath(config.baseURL, config.url, config.allowAbsoluteUrls);
      return buildURL(fullPath, config.params, config.paramsSerializer);
    }
  }
  
  // Provide aliases for supported request methods
  utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
    /*eslint func-names:0*/
    Axios.prototype[method] = function (url, config) {
      return this.request(
        mergeConfig(config || {}, {
          method,
          url,
          data: (config || {}).data,
        })
      );
    };
  });
  
  utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
    function generateHTTPMethod(isForm) {
      return function httpMethod(url, data, config) {
        return this.request(
          mergeConfig(config || {}, {
            method,
            headers: isForm
              ? {
                  'Content-Type': 'multipart/form-data',
                }
              : {},
            url,
            data,
          })
        );
      };
    }
  
    Axios.prototype[method] = generateHTTPMethod();
  
    Axios.prototype[method + 'Form'] = generateHTTPMethod(true);
  });
  
  export default Axios;
  