mktemp
Version:
create temporary files and directories
1 lines • 11.3 kB
Source Map (JSON)
{"version":3,"file":"creation.cjs","names":["generateUniqueName","getOutcomeCount","fs"],"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 = (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, (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((resolve, reject) => {\n // NOTE: maybe unreachable to else statement, this code is for the tsc\n if (isMode(mode)) {\n createFile(template, mode, (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((resolve, reject) => {\n // NOTE: maybe unreachable to else statement, this code is for the tsc\n if (isMode(mode)) {\n createDir(template, mode, (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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"}