worktree.ts 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. const normalize = (directory: string) => directory.replace(/[\\/]+$/, "")
  2. type State =
  3. | {
  4. status: "pending"
  5. }
  6. | {
  7. status: "ready"
  8. }
  9. | {
  10. status: "failed"
  11. message: string
  12. }
  13. const state = new Map<string, State>()
  14. const waiters = new Map<
  15. string,
  16. {
  17. promise: Promise<State>
  18. resolve: (state: State) => void
  19. }
  20. >()
  21. function deferred() {
  22. const box = { resolve: (_: State) => {} }
  23. const promise = new Promise<State>((resolve) => {
  24. box.resolve = resolve
  25. })
  26. return { promise, resolve: box.resolve }
  27. }
  28. export const Worktree = {
  29. get(directory: string) {
  30. return state.get(normalize(directory))
  31. },
  32. pending(directory: string) {
  33. const key = normalize(directory)
  34. const current = state.get(key)
  35. if (current && current.status !== "pending") return
  36. state.set(key, { status: "pending" })
  37. },
  38. ready(directory: string) {
  39. const key = normalize(directory)
  40. const next = { status: "ready" } as const
  41. state.set(key, next)
  42. const waiter = waiters.get(key)
  43. if (!waiter) return
  44. waiters.delete(key)
  45. waiter.resolve(next)
  46. },
  47. failed(directory: string, message: string) {
  48. const key = normalize(directory)
  49. const next = { status: "failed", message } as const
  50. state.set(key, next)
  51. const waiter = waiters.get(key)
  52. if (!waiter) return
  53. waiters.delete(key)
  54. waiter.resolve(next)
  55. },
  56. wait(directory: string) {
  57. const key = normalize(directory)
  58. const current = state.get(key)
  59. if (current && current.status !== "pending") return Promise.resolve(current)
  60. const existing = waiters.get(key)
  61. if (existing) return existing.promise
  62. const waiter = deferred()
  63. waiters.set(key, waiter)
  64. return waiter.promise
  65. },
  66. }