source dump of claude code
at main 56 lines 1.6 kB view raw
1type QueueItem<T extends unknown[], R> = { 2 args: T 3 resolve: (value: R) => void 4 reject: (reason?: unknown) => void 5 context: unknown 6} 7 8/** 9 * Creates a sequential execution wrapper for async functions to prevent race conditions. 10 * Ensures that concurrent calls to the wrapped function are executed one at a time 11 * in the order they were received, while preserving the correct return values. 12 * 13 * This is useful for operations that must be performed sequentially, such as 14 * file writes or database updates that could cause conflicts if executed concurrently. 15 * 16 * @param fn - The async function to wrap with sequential execution 17 * @returns A wrapped version of the function that executes calls sequentially 18 */ 19export function sequential<T extends unknown[], R>( 20 fn: (...args: T) => Promise<R>, 21): (...args: T) => Promise<R> { 22 const queue: QueueItem<T, R>[] = [] 23 let processing = false 24 25 async function processQueue(): Promise<void> { 26 if (processing) return 27 if (queue.length === 0) return 28 29 processing = true 30 31 while (queue.length > 0) { 32 const { args, resolve, reject, context } = queue.shift()! 33 34 try { 35 const result = await fn.apply(context, args) 36 resolve(result) 37 } catch (error) { 38 reject(error) 39 } 40 } 41 42 processing = false 43 44 // Check if new items were added while we were processing 45 if (queue.length > 0) { 46 void processQueue() 47 } 48 } 49 50 return function (this: unknown, ...args: T): Promise<R> { 51 return new Promise((resolve, reject) => { 52 queue.push({ args, resolve, reject, context: this }) 53 void processQueue() 54 }) 55 } 56}