UNPKG

mktemp

Version:

create temporary files and directories

1 lines 11.9 kB
{"version":3,"sources":["../src/creation.ts"],"sourcesContent":["import fs from 'node:fs';\n\nimport { generateUniqueName, getOutcomeCount } from './unique_name';\n\n/* -----------------------------------------------------------------------------\n * private\n * -------------------------------------------------------------------------- */\n\ntype Callback = (\n err: NodeJS.ErrnoException | null,\n path: string | null\n) => void;\n\ntype TryCreateParams = {\n callback: Callback;\n isDir: boolean;\n mode: fs.Mode;\n retryCount: number;\n template: string;\n};\n\n/** permission of 0600 -r-------- */\nconst _r________ = 384; /* =0o600 */\n/** permission of 0700 -rw------- */\nconst _rw_______ = 448; /* =0o700 */\n\n/**\n * getOutcomeCount(\"X\") * 1 → 1 - (35/36)^(36*1) = 0.63728996689\n * ≈ 63%\n * 63% chance of success, 37% chance of failure\n *\n * getOutcomeCount(\"X\") * 3 → 1 - (35/36)^(36*3) = 0.9522823874\n * ≈ 95%\n * 95% chance of success, 5% chance of failure\n */\nconst RETRY_MULTIPLIER = 3;\n\n/**\n * check mode is fs.Mode\n *\n * @param mode - target value\n * @returns true if mode is fs.Mode\n */\nfunction isMode(mode: unknown): mode is fs.Mode {\n return typeof mode === 'number' || typeof mode === 'string';\n}\n\n/**\n * check error is NodeJS.ErrnoException\n *\n * @param error - target value\n * @returns true if error is NodeJS.ErrnoException\n */\nfunction isErrnoException(error: unknown): error is NodeJS.ErrnoException {\n if (typeof error === 'object' && error !== null) {\n return 'code' in (error as NodeJS.ErrnoException);\n }\n\n return false;\n}\n\n/**\n * try create unique name file or directory\n */\nfunction tryCreate({\n callback,\n isDir,\n mode,\n retryCount,\n template\n}: TryCreateParams) {\n const path = generateUniqueName(template);\n\n const fn = function (err: NodeJS.ErrnoException | null, fd?: number): void {\n if (err) {\n if (err.code === 'EEXIST') {\n // NOTE: EEXIST error\n if (retryCount > 0) {\n setImmediate(tryCreate, {\n callback,\n isDir,\n mode,\n retryCount: retryCount - 1,\n template\n });\n } else {\n callback(new RangeError('over max retry count'), null);\n }\n } else {\n // NOTE: other errors\n callback(err, null);\n }\n\n return;\n }\n\n if (fd) {\n fs.close(fd, function (err) {\n callback(err, path);\n });\n } else {\n callback(null, path);\n }\n };\n\n if (isDir) {\n fs.mkdir(path, mode, fn);\n } else {\n fs.open(path, 'ax+', mode, fn);\n }\n}\n\n/* -----------------------------------------------------------------------------\n * public / createFile\n * -------------------------------------------------------------------------- */\n\n/**\n * create unique name file\n *\n * @param template - template string for filename\n * @returns result with Promise\n */\nexport function createFile(template: string): Promise<string | null>;\n/**\n * create unique name file\n *\n * @param template - template string for filename\n * @param mode - permission\n * @returns result with Promise\n */\nexport function createFile(\n template: string,\n mode: fs.Mode\n): Promise<string | null>;\n/**\n * create unique name file\n *\n * @param template - template string for filename\n * @param callback - callback function\n */\nexport function createFile(template: string, callback: Callback): void;\n/**\n * create unique name file\n *\n * @param template - template string for filename\n * @param mode - permission\n * @param callback - callback function\n */\nexport function createFile(\n template: string,\n mode: fs.Mode,\n callback: Callback\n): void;\n\nexport function createFile(\n template: string,\n mode: fs.Mode | Callback = _r________,\n callback?: Callback\n): void | Promise<string | null> {\n if (typeof mode === 'function') {\n callback = mode;\n mode = _r________;\n }\n\n // NOTE: if don't pass mode argument, mode is initialize to _r________\n\n if (typeof callback !== 'function') {\n return new Promise(function (resolve, reject) {\n // NOTE: maybe unreachable to else statement, this code is for the tsc\n if (isMode(mode)) {\n createFile(template, mode, function (err, path) {\n if (err) {\n reject(err);\n } else {\n resolve(path);\n }\n });\n } else {\n reject(new TypeError(`mode must be a fs.Mode: ${mode}`));\n }\n });\n }\n\n tryCreate({\n callback,\n isDir: false,\n mode,\n retryCount: getOutcomeCount(template) * RETRY_MULTIPLIER,\n template\n });\n}\n\n/**\n * create unique name file, sync version\n *\n * @param template - template string for filename\n * @returns unique filename\n */\nexport function createFileSync(template: string): string;\n/**\n * create unique name file, sync version\n *\n * @param template - template string for filename\n * @param mode - permission\n * @returns unique filename\n */\nexport function createFileSync(template: string, mode: fs.Mode): string;\n\nexport function createFileSync(\n template: string,\n mode: fs.Mode = _r________\n): string {\n let path: string;\n let isExist: boolean;\n\n let retryCount = getOutcomeCount(template);\n\n do {\n isExist = false;\n path = generateUniqueName(template);\n\n let fd: number | null = null;\n\n try {\n fd = fs.openSync(path, 'ax+', mode);\n } catch (err) {\n if (isErrnoException(err) && err.code === 'EEXIST') {\n if (retryCount > 0) {\n isExist = true;\n } else {\n throw new RangeError('over max retry count');\n }\n } else {\n throw err;\n }\n } finally {\n if (fd !== null) {\n fs.closeSync(fd);\n }\n }\n\n retryCount -= 1;\n } while (isExist);\n\n return path;\n}\n\n/* -----------------------------------------------------------------------------\n * public / createDir\n * -------------------------------------------------------------------------- */\n\n/**\n * create unique name directory\n *\n * @param template - template string for dirname\n * @returns result with Promise\n */\nexport function createDir(template: string): Promise<string | null>;\n/**\n * create unique name directory\n *\n * @param template - template string for dirname\n * @param mode - permission\n * @returns result with Promise\n */\nexport function createDir(\n template: string,\n mode: fs.Mode\n): Promise<string | null>;\n/**\n * create unique name directory\n *\n * @param template - template string for dirname\n * @param callback - callback function\n */\nexport function createDir(template: string, callback: Callback): void;\n/**\n * create unique name directory\n *\n * @param template - template string for dirname\n * @param mode - permission\n * @param callback - callback function\n */\nexport function createDir(\n template: string,\n mode: fs.Mode,\n callback: Callback\n): void;\n\nexport function createDir(\n template: string,\n mode: fs.Mode | Callback = _rw_______,\n callback?: Callback\n): void | Promise<string | null> {\n if (typeof mode === 'function') {\n callback = mode;\n mode = _rw_______;\n }\n\n // NOTE: if don't pass mode argument, mode is initialize to _rw_______\n\n if (typeof callback !== 'function') {\n return new Promise(function (resolve, reject) {\n // NOTE: maybe unreachable to else statement, this code is for the tsc\n if (isMode(mode)) {\n createDir(template, mode, function (err, path) {\n if (err) {\n reject(err);\n } else {\n resolve(path);\n }\n });\n } else {\n reject(new TypeError(`mode must be a fs.Mode: ${mode}`));\n }\n });\n }\n\n tryCreate({\n callback,\n isDir: true,\n mode,\n retryCount: getOutcomeCount(template) * RETRY_MULTIPLIER,\n template\n });\n}\n\n/**\n * create unique name directory, sync version\n *\n * @param template - template string for dirname\n * @returns unique filename\n */\nexport function createDirSync(template: string): string;\n/**\n * create unique name directory, sync version\n *\n * @param template - template string for dirname\n * @returns unique filename\n */\nexport function createDirSync(template: string, mode: fs.Mode): string;\n\nexport function createDirSync(\n template: string,\n mode: fs.Mode = _rw_______\n): string {\n let path: string;\n let isExist: boolean;\n\n let retryCount = getOutcomeCount(template);\n\n do {\n isExist = false;\n path = generateUniqueName(template);\n\n try {\n fs.mkdirSync(path, mode);\n } catch (err) {\n if (isErrnoException(err) && err.code === 'EEXIST') {\n if (retryCount > 0) {\n isExist = true;\n } else {\n throw new RangeError('over max retry count');\n }\n } else {\n throw err;\n }\n }\n\n retryCount -= 1;\n } while (isExist);\n\n return path;\n}\n"],"mappings":"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","names":["err"]}