import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; export function createTrackedTempDirs() { const prefixRoots = new Map(); const pendingPrefixRoots = new Map>(); const cleanupRoots = new Set(); let globalDirIndex = 0; const ensurePrefixRoot = async (prefix: string) => { const cached = prefixRoots.get(prefix); if (cached) { return cached; } const pending = pendingPrefixRoots.get(prefix); if (pending) { return await pending; } const create = (async () => { const root = await fs.mkdtemp(path.join(os.tmpdir(), prefix)); const state = { root, nextIndex: 0 }; prefixRoots.set(prefix, state); cleanupRoots.add(root); return state; })(); pendingPrefixRoots.set(prefix, create); try { return await create; } finally { pendingPrefixRoots.delete(prefix); } }; return { async make(prefix: string): Promise { const state = await ensurePrefixRoot(prefix); const dir = path.join(state.root, `dir-${String(globalDirIndex)}`); state.nextIndex += 1; globalDirIndex += 1; await fs.mkdir(dir, { recursive: true }); return dir; }, async cleanup(): Promise { const roots = [...cleanupRoots]; pendingPrefixRoots.clear(); await Promise.all( roots.map(async (dir) => { const entries = await fs.readdir(dir).catch((err: unknown) => { if ((err as NodeJS.ErrnoException).code === "ENOENT") { return []; } throw err; }); await Promise.all( entries.map(async (entry) => { await fs.rm(path.join(dir, entry), { recursive: true, force: true }); }), ); for (const state of prefixRoots.values()) { if (state.root === dir) { state.nextIndex = 0; } } }), ); }, }; }