All files ensureUniqueCounter.ts

88.13% Statements 52/59
88.88% Branches 8/9
100% Functions 2/2
88.13% Lines 52/59

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 761x   56x 56x 56x 56x 56x 56x         56x 56x 56x   56x 7x 7x 7x   56x 56x 56x   56x 56x 56x 56x 56x 56x 56x           56x 56x                 56x 56x 56x 56x 56x 56x 56x 56x 56x 56x 56x   56x   56x 56x 56x 56x 56x 56x 56x 56x 56x 56x 55x 55x 56x 56x  
const uniqueCounterScopes = new WeakMap<object, Promise<void>>()
 
async function runEnsureUniqueCounterValue<T>({
  initialValue,
  isTaken,
  reserve,
  nextValue,
}: {
  initialValue: T
  isTaken: (candidate: T) => Promise<boolean> | boolean
  reserve: (candidate: T) => void
  nextValue: (counter: number) => T
}): Promise<T> {
  let candidate = initialValue
  let counter = 1
 
  while (await isTaken(candidate)) {
    candidate = nextValue(counter)
    counter += 1
  }
 
  reserve(candidate)
  return candidate
}
 
export async function ensureUniqueCounterValue<T>({
  initialValue,
  isTaken,
  reserve,
  nextValue,
  scope,
}: {
  initialValue: T
  isTaken: (candidate: T) => Promise<boolean> | boolean
  reserve: (candidate: T) => void
  nextValue: (counter: number) => T
  scope?: object
}): Promise<T> {
  if (scope == null) {
    return await runEnsureUniqueCounterValue({
      initialValue,
      isTaken,
      reserve,
      nextValue,
    })
  }
 
  const previous = uniqueCounterScopes.get(scope) ?? Promise.resolve()
  let releaseScope: (() => void) | undefined
  const pendingScope = new Promise<void>((resolve) => {
    releaseScope = resolve
  })
  const currentScope = previous
    .catch(() => undefined)
    .then(async () => {
      await pendingScope
    })
  uniqueCounterScopes.set(scope, currentScope)
 
  await previous.catch(() => undefined)
 
  try {
    return await runEnsureUniqueCounterValue({
      initialValue,
      isTaken,
      reserve,
      nextValue,
    })
  } finally {
    releaseScope?.()
    if (uniqueCounterScopes.get(scope) === currentScope) {
      uniqueCounterScopes.delete(scope)
    }
  }
}