diff --git a/src/test-helpers/temp-dir.ts b/src/test-helpers/temp-dir.ts index 920c5a217b9..896b2928975 100644 --- a/src/test-helpers/temp-dir.ts +++ b/src/test-helpers/temp-dir.ts @@ -3,6 +3,51 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; +const asyncPrefixRoots = new Map(); +const pendingAsyncPrefixRoots = new Map>(); +const syncPrefixRoots = new Map(); +let nextAsyncDirIndex = 0; +let nextSyncDirIndex = 0; + +function getRootKey(options: { prefix: string; parentDir?: string }): string { + return `${options.parentDir ?? os.tmpdir()}\u0000${options.prefix}`; +} + +async function ensureAsyncPrefixRoot(options: { + prefix: string; + parentDir?: string; +}): Promise { + const key = getRootKey(options); + const cached = asyncPrefixRoots.get(key); + if (cached) { + return cached; + } + const pending = pendingAsyncPrefixRoots.get(key); + if (pending) { + return await pending; + } + const create = fs.mkdtemp(path.join(options.parentDir ?? os.tmpdir(), options.prefix)); + pendingAsyncPrefixRoots.set(key, create); + try { + const root = await create; + asyncPrefixRoots.set(key, root); + return root; + } finally { + pendingAsyncPrefixRoots.delete(key); + } +} + +function ensureSyncPrefixRoot(options: { prefix: string; parentDir?: string }): string { + const key = getRootKey(options); + const cached = syncPrefixRoots.get(key); + if (cached) { + return cached; + } + const root = fsSync.mkdtempSync(path.join(options.parentDir ?? os.tmpdir(), options.prefix)); + syncPrefixRoots.set(key, root); + return root; +} + export async function withTempDir( options: { prefix: string; @@ -11,7 +56,10 @@ export async function withTempDir( }, run: (dir: string) => Promise, ): Promise { - const base = await fs.mkdtemp(path.join(options.parentDir ?? os.tmpdir(), options.prefix)); + const root = await ensureAsyncPrefixRoot(options); + const base = path.join(root, `dir-${String(nextAsyncDirIndex)}`); + nextAsyncDirIndex += 1; + await fs.mkdir(base, { recursive: true }); const dir = options.subdir ? path.join(base, options.subdir) : base; if (options.subdir) { await fs.mkdir(dir, { recursive: true }); @@ -68,7 +116,10 @@ export function withTempDirSync( }, run: (dir: string) => T, ): T { - const base = fsSync.mkdtempSync(path.join(options.parentDir ?? os.tmpdir(), options.prefix)); + const root = ensureSyncPrefixRoot(options); + const base = path.join(root, `dir-${String(nextSyncDirIndex)}`); + nextSyncDirIndex += 1; + fsSync.mkdirSync(base, { recursive: true }); const dir = options.subdir ? path.join(base, options.subdir) : base; if (options.subdir) { fsSync.mkdirSync(dir, { recursive: true });