OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-booking / node_modules / bare-abort-controller / index.js

160 lines · javascript ref:
const { Event, EventTarget } = require('bare-events/web')

// https://webidl.spec.whatwg.org/#aborterror
class AbortError extends Error {
  get name() {
    return 'AbortError'
  }
}

// https://webidl.spec.whatwg.org/#timeouterror
class TimeoutError extends Error {
  get name() {
    return 'TimeoutError'
  }
}

// https://dom.spec.whatwg.org/#abortsignal
class AbortSignal extends EventTarget {
  constructor() {
    super()

    this._reason = undefined
    this._dependent = false
    this._sources = []
    this._dependents = []
  }

  // https://dom.spec.whatwg.org/#dom-abortsignal-aborted
  get aborted() {
    return this._reason !== undefined
  }

  // https://dom.spec.whatwg.org/#dom-abortsignal-reason
  get reason() {
    return this._reason
  }

  // https://dom.spec.whatwg.org/#abortsignal-signal-abort
  _abort(reason = new AbortError('The operation was aborted')) {
    if (this.aborted) return

    this._reason = reason

    this.dispatchEvent(new Event('abort'))

    for (const signal of this._dependents) {
      signal._abort(reason)
    }
  }

  // https://dom.spec.whatwg.org/#dom-abortsignal-throwifaborted
  throwIfAborted() {
    if (this._reason !== undefined) throw this._reason
  }

  toJSON() {
    return {
      aborted: this.aborted,
      reason: this.reason
    }
  }

  [Symbol.for('bare.inspect')]() {
    return {
      __proto__: { constructor: AbortSignal },

      aborted: this.aborted,
      reason: this.reason
    }
  }

  // https://dom.spec.whatwg.org/#dom-abortsignal-abort
  static abort(reason) {
    const signal = new AbortSignal()

    signal._reason = reason

    return signal
  }

  // https://dom.spec.whatwg.org/#dom-abortsignal-timeout
  static timeout(ms) {
    const signal = new AbortSignal()

    const timer = setTimeout(
      () => signal._abort(new TimeoutError('The operation timed out')),
      ms
    )

    timer.unref()

    return signal
  }

  // https://dom.spec.whatwg.org/#dom-abortsignal-any
  static any(signals) {
    const result = new AbortSignal()

    for (const signal of signals) {
      if (signal.aborted) {
        result._reason = signal.reason
        return result
      }
    }

    result._dependent = true

    for (const signal of signals) {
      if (signal._dependent === false) {
        result._sources.push(signal)
        signal._dependents.push(result)
      } else {
        for (const source of signal._sources) {
          result._sources.push(source)
          source._dependents.push(result)
        }
      }
    }

    return result
  }
}

// https://dom.spec.whatwg.org/#abortcontroller
class AbortController {
  constructor() {
    this._signal = new AbortSignal()
  }

  // https://dom.spec.whatwg.org/#dom-abortcontroller-signal
  get signal() {
    return this._signal
  }

  // https://dom.spec.whatwg.org/#dom-abortcontroller-abort
  abort(reason) {
    this._signal._abort(reason)
  }

  toJSON() {
    return {
      signal: this.signal
    }
  }

  [Symbol.for('bare.inspect')]() {
    return {
      __proto__: { constructor: AbortController },

      signal: this.signal
    }
  }
}

module.exports = exports = AbortController

exports.AbortController = exports

exports.AbortSignal = AbortSignal