repo_description: Promise based HTTP client for the browser and node.js
repo_topics: hacktoberfest http-client javascript nodejs promise
code: 'use strict';
  
  import CanceledError from './CanceledError.js';
  
  /**
   * A `CancelToken` is an object that can be used to request cancellation of an operation.
   *
   * @param {Function} executor The executor function.
   *
   * @returns {CancelToken}
   */
  class CancelToken {
    constructor(executor) {
      if (typeof executor !== 'function') {
        throw new TypeError('executor must be a function.');
      }
  
      let resolvePromise;
  
      this.promise = new Promise(function promiseExecutor(resolve) {
        resolvePromise = resolve;
      });
  
      const token = this;
  
      // eslint-disable-next-line func-names
      this.promise.then((cancel) => {
        if (!token._listeners) return;
  
        let i = token._listeners.length;
  
        while (i-- > 0) {
          token._listeners[i](cancel);
        }
        token._listeners = null;
      });
  
      // eslint-disable-next-line func-names
      this.promise.then = (onfulfilled) => {
        let _resolve;
        // eslint-disable-next-line func-names
        const promise = new Promise((resolve) => {
          token.subscribe(resolve);
          _resolve = resolve;
        }).then(onfulfilled);
  
        promise.cancel = function reject() {
          token.unsubscribe(_resolve);
        };
  
        return promise;
      };
  
      executor(function cancel(message, config, request) {
        if (token.reason) {
          // Cancellation has already been requested
          return;
        }
  
        token.reason = new CanceledError(message, config, request);
        resolvePromise(token.reason);
      });
    }
  
    /**
     * Throws a `CanceledError` if cancellation has been requested.
     */
    throwIfRequested() {
      if (this.reason) {
        throw this.reason;
      }
    }
  
    /**
     * Subscribe to the cancel signal
     */
  
    subscribe(listener) {
      if (this.reason) {
        listener(this.reason);
        return;
      }
  
      if (this._listeners) {
        this._listeners.push(listener);
      } else {
        this._listeners = [listener];
      }
    }
  
    /**
     * Unsubscribe from the cancel signal
     */
  
    unsubscribe(listener) {
      if (!this._listeners) {
        return;
      }
      const index = this._listeners.indexOf(listener);
      if (index !== -1) {
        this._listeners.splice(index, 1);
      }
    }
  
    toAbortSignal() {
      const controller = new AbortController();
  
      const abort = (err) => {
        controller.abort(err);
      };
  
      this.subscribe(abort);
  
      controller.signal.unsubscribe = () => this.unsubscribe(abort);
  
      return controller.signal;
    }
  
    /**
     * Returns an object that contains a new `CancelToken` and a function that, when called,
     * cancels the `CancelToken`.
     */
    static source() {
      let cancel;
      const token = new CancelToken(function executor(c) {
        cancel = c;
      });
      return {
        token,
        cancel,
      };
    }
  }
  
  export default CancelToken;
  