Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | 23x 23x 23x 52x 22x 2x 1x 56x 56x 20x 52x 52x 52x 52x 52x 23x 23x 54x 53x | import { randomUUID } from "node:crypto";
import { chmod, mkdir, rename, stat, unlink, writeFile } from "node:fs/promises";
import path from "node:path";
export interface PendingWrite {
content: string;
mode?: number;
target: string;
}
interface StagedWrite extends PendingWrite {
temporaryPath: string;
}
export async function writeBatch(writes: readonly PendingWrite[]): Promise<void> {
assertDistinctTargets(writes);
const staged: StagedWrite[] = [];
try {
for (const write of writes) staged.push(await stageWrite(write));
for (const write of staged) await rename(write.temporaryPath, write.target);
} catch (error) {
await Promise.allSettled(staged.map((write) => unlink(write.temporaryPath)));
throw error;
}
}
export async function readMode(filePath: string): Promise<number | undefined> {
try {
return (await stat(filePath)).mode;
} catch {
return undefined;
}
}
async function stageWrite(write: PendingWrite): Promise<StagedWrite> {
await mkdir(path.dirname(write.target), { recursive: true });
const temporaryPath = path.join(
path.dirname(write.target),
`.${path.basename(write.target)}.${process.pid}.${randomUUID()}.tmp`,
);
await writeFile(temporaryPath, write.content, { flag: "wx", mode: write.mode });
if (write.mode !== undefined) await chmod(temporaryPath, write.mode);
return { ...write, temporaryPath };
}
function assertDistinctTargets(writes: readonly PendingWrite[]): void {
const targets = new Set<string>();
for (const write of writes) {
if (targets.has(write.target)) throw new Error(`Multiple outputs resolve to ${write.target}`);
targets.add(write.target);
}
}
|