{"version":3,"file":"file-mutation-queue.d.ts","sourceRoot":"","sources":["../../../src/harness/tools/file-mutation-queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA2BhD,kFAAkF;AAClF,wBAAsB,qBAAqB,CAAC,CAAC,EAC5C,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,EAAE,OAAO,GACd,OAAO,CAAC,CAAC,CAAC,CA2BZ","sourcesContent":["import type { Context } from \"../context.ts\";\nimport type { ExecutionEnv } from \"../types.ts\";\nimport { getOrThrow } from \"../types.ts\";\n\ntype MutationQueueState = {\n\tqueues: Map<string, Promise<void>>;\n\tregistration: Promise<void>;\n};\n\nconst states = new WeakMap<ExecutionEnv, MutationQueueState>();\n\nfunction getState(env: ExecutionEnv): MutationQueueState {\n\tlet state = states.get(env);\n\tif (!state) {\n\t\tstate = { queues: new Map(), registration: Promise.resolve() };\n\t\tstates.set(env, state);\n\t}\n\treturn state;\n}\n\nasync function getMutationQueueKey(env: ExecutionEnv, path: string, context: Context): Promise<string> {\n\tconst absolutePath = getOrThrow(await env.absolutePath(path, context));\n\tconst canonicalPath = await env.canonicalPath(absolutePath, context);\n\tif (canonicalPath.ok) return canonicalPath.value;\n\tif (canonicalPath.error.code === \"not_found\" || canonicalPath.error.code === \"not_supported\") return absolutePath;\n\tthrow canonicalPath.error;\n}\n\n/** Serialize file mutations targeting the same environment and canonical path. */\nexport async function withFileMutationQueue<T>(\n\tenv: ExecutionEnv,\n\tpath: string,\n\tfn: () => Promise<T>,\n\tcontext: Context,\n): Promise<T> {\n\tconst state = getState(env);\n\tconst registration = state.registration.then(async () => {\n\t\tconst key = await getMutationQueueKey(env, path, context);\n\t\tconst currentQueue = state.queues.get(key) ?? Promise.resolve();\n\n\t\tlet releaseNext = () => {};\n\t\tconst nextQueue = new Promise<void>((resolve) => {\n\t\t\treleaseNext = resolve;\n\t\t});\n\t\tconst chainedQueue = currentQueue.then(() => nextQueue);\n\t\tstate.queues.set(key, chainedQueue);\n\t\treturn { key, currentQueue, chainedQueue, releaseNext };\n\t});\n\tstate.registration = registration.then(\n\t\t() => undefined,\n\t\t() => undefined,\n\t);\n\n\tconst { key, currentQueue, chainedQueue, releaseNext } = await registration;\n\tawait currentQueue;\n\ttry {\n\t\treturn await fn();\n\t} finally {\n\t\treleaseNext();\n\t\tif (state.queues.get(key) === chainedQueue) state.queues.delete(key);\n\t}\n}\n"]}