UNPKG

mktemp

Version:

create temporary files and directories

145 lines (144 loc) 3.86 kB
import { generateUniqueName, getOutcomeCount } from "./unique_name.mjs"; import fs from "node:fs"; //#region src/creation.ts /** permission of 0600 -r-------- */ const _r________ = 384; /** permission of 0700 -rw------- */ const _rw_______ = 448; /** * getOutcomeCount("X") * 1 → 1 - (35/36)^(36*1) = 0.63728996689 * ≈ 63% * 63% chance of success, 37% chance of failure * * getOutcomeCount("X") * 3 → 1 - (35/36)^(36*3) = 0.9522823874 * ≈ 95% * 95% chance of success, 5% chance of failure */ const RETRY_MULTIPLIER = 3; /** * check mode is fs.Mode * * @param mode - target value * @returns true if mode is fs.Mode */ function isMode(mode) { return typeof mode === "number" || typeof mode === "string"; } /** * check error is NodeJS.ErrnoException * * @param error - target value * @returns true if error is NodeJS.ErrnoException */ function isErrnoException(error) { if (typeof error === "object" && error !== null) return "code" in error; return false; } /** * try create unique name file or directory */ function tryCreate({ callback, isDir, mode, retryCount, template }) { const path = generateUniqueName(template); const fn = (err, fd) => { if (err) { if (err.code === "EEXIST") if (retryCount > 0) setImmediate(tryCreate, { callback, isDir, mode, retryCount: retryCount - 1, template }); else callback(/* @__PURE__ */ new RangeError("over max retry count"), null); else callback(err, null); return; } if (fd) fs.close(fd, (err) => { callback(err, path); }); else callback(null, path); }; if (isDir) fs.mkdir(path, mode, fn); else fs.open(path, "ax+", mode, fn); } function createFile(template, mode = _r________, callback) { if (typeof mode === "function") { callback = mode; mode = _r________; } if (typeof callback !== "function") return new Promise((resolve, reject) => { if (isMode(mode)) createFile(template, mode, (err, path) => { if (err) reject(err); else resolve(path); }); else reject(/* @__PURE__ */ new TypeError(`mode must be a fs.Mode: ${mode}`)); }); tryCreate({ callback, isDir: false, mode, retryCount: getOutcomeCount(template) * RETRY_MULTIPLIER, template }); } function createFileSync(template, mode = _r________) { let path; let isExist; let retryCount = getOutcomeCount(template); do { isExist = false; path = generateUniqueName(template); let fd = null; try { fd = fs.openSync(path, "ax+", mode); } catch (err) { if (isErrnoException(err) && err.code === "EEXIST") if (retryCount > 0) isExist = true; else throw new RangeError("over max retry count"); else throw err; } finally { if (fd !== null) fs.closeSync(fd); } retryCount -= 1; } while (isExist); return path; } function createDir(template, mode = _rw_______, callback) { if (typeof mode === "function") { callback = mode; mode = _rw_______; } if (typeof callback !== "function") return new Promise((resolve, reject) => { if (isMode(mode)) createDir(template, mode, (err, path) => { if (err) reject(err); else resolve(path); }); else reject(/* @__PURE__ */ new TypeError(`mode must be a fs.Mode: ${mode}`)); }); tryCreate({ callback, isDir: true, mode, retryCount: getOutcomeCount(template) * RETRY_MULTIPLIER, template }); } function createDirSync(template, mode = _rw_______) { let path; let isExist; let retryCount = getOutcomeCount(template); do { isExist = false; path = generateUniqueName(template); try { fs.mkdirSync(path, mode); } catch (err) { if (isErrnoException(err) && err.code === "EEXIST") if (retryCount > 0) isExist = true; else throw new RangeError("over max retry count"); else throw err; } retryCount -= 1; } while (isExist); return path; } //#endregion export { createDir, createDirSync, createFile, createFileSync }; //# sourceMappingURL=creation.mjs.map