OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-booking / node_modules / scope-lock / index.js

90 lines · javascript ref:
let tmpResolve = null

module.exports = class ScopeLock {
  constructor ({ debounce = false } = {}) {
    this.debounce = debounce
    this.waiting = []
    this.locked = false
    this.skip = 0
    this.destroyed = false
  }

  flush () {
    if (this.locked === false && this.waiting.length === 0) return Promise.resolve(this.destroyed === false)

    const promise = new Promise(setTmpResolve)
    const resolve = tmpResolve

    tmpResolve = null
    this.waiting.push({ lock: false, resolve })

    return promise
  }

  destroy () {
    this.destroyed = true
  }

  lock () {
    const promise = new Promise(setTmpResolve)
    const resolve = tmpResolve

    tmpResolve = null

    if (this.locked === true) {
      this.waiting.push({ lock: true, resolve })
      return promise
    }

    if (this.destroyed === true) {
      resolve(false)
      return promise
    }

    this.locked = true
    resolve(true)

    return promise
  }

  unlock () {
    if (this.destroyed === true) {
      for (let i = 0; i < this.waiting.length; i++) {
        this.waiting[i].resolve(false)
      }
      this.waiting = []
      this.skip = 0
      this.locked = false
      return
    }

    if (this.skip !== 0) {
      for (let i = 0; i < this.skip; i++) {
        const { lock, resolve } = this.waiting[i]
        resolve(lock === false)
      }

      this.waiting = this.waiting.slice(this.skip)
      this.skip = 0
    }

    while (this.waiting.length > 0 && this.waiting[0].lock === false) {
      this.waiting.shift().resolve(true)
    }

    if (this.waiting.length === 0) {
      this.locked = false
      return
    }

    const { resolve } = this.waiting.shift()
    if (this.debounce === true) this.skip = this.waiting.length

    resolve(true)
  }
}

function setTmpResolve (resolve) {
  tmpResolve = resolve
}