-
Notifications
You must be signed in to change notification settings - Fork 638
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(fs/unstable): add makeTempDir and makeTempDirSync (#6391)
- Loading branch information
Showing
6 changed files
with
273 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
// Copyright 2018-2025 the Deno authors. MIT license. | ||
|
||
import { getNodeFs, getNodeOs, getNodePath, isDeno } from "./_utils.ts"; | ||
import type { MakeTempOptions } from "./unstable_types.ts"; | ||
import { mapError } from "./_map_error.ts"; | ||
|
||
/** | ||
* Creates a new temporary directory in the default directory for temporary | ||
* files, unless `dir` is specified. Other optional options include | ||
* prefixing and suffixing the directory name with `prefix` and `suffix` | ||
* respectively. | ||
* | ||
* This call resolves to the full path to the newly created directory. | ||
* | ||
* Multiple programs calling this function simultaneously will create different | ||
* directories. It is the caller's responsibility to remove the directory when | ||
* no longer needed. | ||
* | ||
* Requires `allow-write` permission. | ||
* | ||
* @example Usage | ||
* ```ts ignore | ||
* import { makeTempDir } from "@std/unstable-make-temp-dir"; | ||
* const tempDirName0 = await makeTempDir(); // e.g. /tmp/2894ea76 | ||
* const tempDirName1 = await makeTempDir({ prefix: 'my_temp' }); // e.g. /tmp/my_temp339c944d | ||
* ``` | ||
* | ||
* @tags allow-write | ||
* | ||
* @param options The options specified when creating a temporary directory. | ||
* @returns A promise that resolves to a path to the temporary directory. | ||
*/ | ||
export async function makeTempDir(options?: MakeTempOptions): Promise<string> { | ||
if (isDeno) { | ||
return Deno.makeTempDir({ ...options }); | ||
} else { | ||
const { | ||
dir = undefined, | ||
prefix = undefined, | ||
suffix = undefined, | ||
} = options ?? {}; | ||
|
||
try { | ||
const { mkdtemp, rename } = getNodeFs().promises; | ||
const { tmpdir } = getNodeOs(); | ||
const { join, sep } = getNodePath(); | ||
|
||
if (!options) { | ||
return await mkdtemp(join(tmpdir(), sep)); | ||
} | ||
|
||
let prependPath = tmpdir(); | ||
if (dir != null) { | ||
prependPath = typeof dir === "string" ? dir : "."; | ||
if (prependPath === "") { | ||
prependPath = "."; | ||
} | ||
} | ||
|
||
if (prefix != null && typeof prefix === "string") { | ||
prependPath = join(prependPath, prefix || sep); | ||
} else { | ||
prependPath = join(prependPath, sep); | ||
} | ||
|
||
if (suffix != null && typeof suffix === "string") { | ||
const tempPath = await mkdtemp(prependPath); | ||
const combinedTempPath = "".concat(tempPath, suffix); | ||
await rename(tempPath, combinedTempPath); | ||
return combinedTempPath; | ||
} | ||
|
||
return await mkdtemp(prependPath); | ||
} catch (error) { | ||
throw mapError(error); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Synchronously creates a new temporary directory in the default directory | ||
* for temporary files, unless `dir` is specified. Other optional options | ||
* include prefixing and suffixing the directory name with `prefix` and | ||
* `suffix` respectively. | ||
* | ||
* The full path to the newly created directory is returned. | ||
* | ||
* Multiple programs calling this function simultaneously will create different | ||
* directories. It is the caller's responsibility to remove the directory when | ||
* no longer needed. | ||
* | ||
* Requires `allow-write` permission. | ||
* | ||
* @example Usage | ||
* ```ts ignore | ||
* import { makeTempDirSync } from "@std/fs/unstable-make-temp-dir"; | ||
* const tempDirName0 = makeTempDirSync(); // e.g. /tmp/2894ea76 | ||
* const tempDirName1 = makeTempDirSync({ prefix: 'my_temp' }); // e.g. /tmp/my_temp339c944d | ||
* ``` | ||
* | ||
* @tags allow-write | ||
* | ||
* @param options The options specified when creating a temporary directory. | ||
* @returns The path of the temporary directory. | ||
*/ | ||
export function makeTempDirSync(options?: MakeTempOptions): string { | ||
if (isDeno) { | ||
return Deno.makeTempDirSync({ ...options }); | ||
} else { | ||
const { | ||
dir = undefined, | ||
prefix = undefined, | ||
suffix = undefined, | ||
} = options ?? {}; | ||
|
||
try { | ||
const { mkdtempSync, renameSync } = getNodeFs(); | ||
const { tmpdir } = getNodeOs(); | ||
const { join, sep } = getNodePath(); | ||
|
||
if (!options) { | ||
return mkdtempSync(join(tmpdir(), sep)); | ||
} | ||
|
||
let prependPath = tmpdir(); | ||
if (dir != null) { | ||
prependPath = typeof dir === "string" ? dir : "."; | ||
if (prependPath === "") { | ||
prependPath = "."; | ||
} | ||
} | ||
|
||
if (prefix != null && typeof prefix === "string") { | ||
prependPath = join(prependPath, prefix || sep); | ||
} else { | ||
prependPath = join(prependPath, sep); | ||
} | ||
|
||
if (suffix != null && typeof prefix === "string") { | ||
const tempPath = mkdtempSync(prependPath); | ||
const combinedTempPath = "".concat(tempPath, suffix); | ||
renameSync(tempPath, combinedTempPath); | ||
return combinedTempPath; | ||
} | ||
|
||
return mkdtempSync(prependPath); | ||
} catch (error) { | ||
throw mapError(error); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// Copyright 2018-2025 the Deno authors. MIT license. | ||
|
||
import { assert, assertRejects, assertThrows } from "@std/assert"; | ||
import { makeTempDir, makeTempDirSync } from "./unstable_make_temp_dir.ts"; | ||
import { NotFound } from "./unstable_errors.js"; | ||
import { rmSync } from "node:fs"; | ||
import { rm } from "node:fs/promises"; | ||
|
||
Deno.test("makeTempDir() creates temporary directories in the default temp directory path", async () => { | ||
const dir1 = await makeTempDir({ prefix: "standard", suffix: "library" }); | ||
const dir2 = await makeTempDir({ prefix: "standard", suffix: "library" }); | ||
|
||
try { | ||
assert(dir1 !== dir2); | ||
|
||
for (const dir of [dir1, dir2]) { | ||
const tempDirName = dir.replace(/^.*[\\\/]/, ""); | ||
assert(tempDirName.startsWith("standard")); | ||
assert(tempDirName.endsWith("library")); | ||
} | ||
} finally { | ||
await rm(dir1, { recursive: true, force: true }); | ||
await rm(dir2, { recursive: true, force: true }); | ||
} | ||
}); | ||
|
||
Deno.test("makeTempDir() creates temporary directories with the 'dir' option", async () => { | ||
const tempParent = await makeTempDir({ prefix: "first", suffix: "last" }); | ||
const dir = await makeTempDir({ dir: tempParent }); | ||
|
||
try { | ||
assert(dir.startsWith(tempParent)); | ||
assert(/^[\\\/]/.test(dir.slice(tempParent.length))); | ||
} finally { | ||
await rm(tempParent, { recursive: true, force: true }); | ||
} | ||
}); | ||
|
||
Deno.test("makeTempDir() rejects with NotFound when passing a 'dir' path that does not exist", async () => { | ||
await assertRejects(async () => { | ||
await makeTempDir({ dir: "/non-existent-dir" }); | ||
}, NotFound); | ||
}); | ||
|
||
Deno.test("makeTempDirSync() creates temporary directories in the default temp directory path", () => { | ||
const dir1 = makeTempDirSync({ prefix: "standard", suffix: "library" }); | ||
const dir2 = makeTempDirSync({ prefix: "standard", suffix: "library" }); | ||
|
||
try { | ||
assert(dir1 !== dir2); | ||
|
||
for (const dir of [dir1, dir2]) { | ||
const tempDirName = dir.replace(/^.*[\\\/]/, ""); | ||
assert(tempDirName.startsWith("standard")); | ||
assert(tempDirName.endsWith("library")); | ||
} | ||
} finally { | ||
rmSync(dir1, { recursive: true, force: true }); | ||
rmSync(dir2, { recursive: true, force: true }); | ||
} | ||
}); | ||
|
||
Deno.test("makeTempDirSync() creates temporary directories with the 'dir' option", () => { | ||
const tempParent = makeTempDirSync({ prefix: "first", suffix: "last" }); | ||
const dir = makeTempDirSync({ dir: tempParent }); | ||
|
||
try { | ||
assert(dir.startsWith(tempParent)); | ||
assert(/^[\\\/]/.test(dir.slice(tempParent.length))); | ||
} finally { | ||
rmSync(tempParent, { recursive: true, force: true }); | ||
} | ||
}); | ||
|
||
Deno.test("makeTempDirSync() throws with NotFound when passing a 'dir' path that does not exist", () => { | ||
assertThrows(() => { | ||
makeTempDirSync({ dir: "/non-existent-dir" }); | ||
}, NotFound); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters