with-local-tmp-dir
Version:
Creates a temporary folder inside cwd, cds inside the folder, runs a function, and removes the folder. Especially useful for testing.
74 lines • 2.07 kB
JavaScript
import crypto from "node:crypto";
import fsPromises from "node:fs/promises";
import pathLib from "node:path";
import chdir from "@dword-design/chdir";
import fs from "fs-extra";
import pRetry from "p-retry";
const TEMPLATE_PATTERN = /XXXXXX/;
const RANDOM_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const _randomChars = howMany => {
const value = [];
let rnd = null;
try {
rnd = crypto.randomBytes(howMany);
} catch {
rnd = crypto.pseudoRandomBytes(howMany);
}
for (let i = 0; i < howMany; i++) {
value.push(RANDOM_CHARS[rnd[i] % RANDOM_CHARS.length]);
}
return value.join("");
};
const _generateTmpName = opts => {
if (opts.name !== void 0) {
return pathLib.join(opts.dir, opts.name);
}
if (opts.template !== void 0) {
return pathLib.join(opts.dir, opts.template).replace(TEMPLATE_PATTERN, _randomChars(6));
}
const name = [opts.prefix, "-", process.pid, "-", _randomChars(12), opts.postfix ? "-" + opts.postfix : ""].join("");
return pathLib.join(opts.dir, name);
};
export default async (...args) => {
let options = args.find(arg => typeof arg === "object");
options = {
dir: ".",
keep: false,
mode: 448,
prefix: "tmp",
tries: 3,
unsafeCleanup: true,
...options
};
const callback = args.find(arg => typeof arg === "function");
const path = _generateTmpName(options);
await pRetry(async () => {
try {
await fs.stat(path);
} catch {
return;
}
throw new Error(`Temporary directory already exists: ${path}`);
}, {
retries: options.tries
});
await fs.ensureDir(path, options.mode);
const removeFunction = options.unsafeCleanup ? fs.remove.bind(fs) : fsPromises.rmdir.bind(fsPromises);
if (callback) {
try {
return await chdir(path, callback);
} finally {
if (!options.keep) {
await removeFunction(path);
}
}
}
const back = chdir(path);
return () => {
back();
if (options.keep) {
return Promise.resolve();
}
return removeFunction(path);
};
};