Skip to content

Commit

Permalink
fix(fs): improve the docs and error message of ensureSymlink(Sync) (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
kt3k authored Nov 21, 2024
1 parent 7e4aa57 commit 93e0cd6
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 9 deletions.
54 changes: 46 additions & 8 deletions fs/ensure_symlink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,43 @@ function getSymlinkOption(
* @see {@link https://docs.deno.com/runtime/manual/basics/permissions#file-system-access}
* for more information on Deno's permissions system.
*
* @param target The source file path as a string or URL.
* @param target The source file path as a string or URL. If it is a relative path string, it have to be relative to the link path.
* @param linkName The destination link path as a string or URL.
*
* @returns A void promise that resolves once the link exists.
*
* @example Usage
* @example Basic usage
* ```ts ignore
* import { ensureSymlink } from "@std/fs/ensure-symlink";
*
* await ensureSymlink("./folder/targetFile.dat", "./folder/targetFile.link.dat");
* // Ensures the link `./targetFile.link.dat` exists and points to `./targetFile.dat`
* await ensureSymlink("./targetFile.dat", "./targetFile.link.dat");
* ```
*
* @example Ensuring a link in a folder
* ```ts ignore
* import { ensureSymlink } from "@std/fs/ensure-symlink";
*
* // Ensures the link `./folder/targetFile.link.dat` exists and points to `./folder/targetFile.dat`
* await ensureSymlink("./targetFile.dat", "./folder/targetFile.link.dat");
* ```
*/
export async function ensureSymlink(
target: string | URL,
linkName: string | URL,
) {
const targetRealPath = resolveSymlinkTarget(target, linkName);
const srcStatInfo = await Deno.lstat(targetRealPath);
let srcStatInfo;
try {
srcStatInfo = await Deno.lstat(targetRealPath);
} catch (error) {
if (error instanceof Deno.errors.NotFound) {
throw new Deno.errors.NotFound(
`Cannot ensure symlink as the target path does not exist: ${targetRealPath}`,
);
}
throw error;
}
const srcFilePathType = getFileInfoType(srcStatInfo);

await ensureDir(dirname(toPathString(linkName)));
Expand Down Expand Up @@ -96,23 +115,42 @@ export async function ensureSymlink(
* @see {@link https://docs.deno.com/runtime/manual/basics/permissions#file-system-access}
* for more information on Deno's permissions system.
*
* @param target The source file path as a string or URL.
* @param target The source file path as a string or URL. If it is a relative path string, it have to be relative to the link path.
* @param linkName The destination link path as a string or URL.
* @returns A void value that returns once the link exists.
*
* @example Usage
* @example Basic usage
* ```ts ignore
* import { ensureSymlinkSync } from "@std/fs/ensure-symlink";
*
* ensureSymlinkSync("./folder/targetFile.dat", "./folder/targetFile.link.dat");
* // Ensures the link `./targetFile.link.dat` exists and points to `./targetFile.dat`
* ensureSymlinkSync("./targetFile.dat", "./targetFile.link.dat");
* ```
*
* @example Ensuring a link in a folder
* ```ts ignore
* import { ensureSymlinkSync } from "@std/fs/ensure-symlink";
*
* // Ensures the link `./folder/targetFile.link.dat` exists and points to `./folder/targetFile.dat`
* ensureSymlinkSync("./targetFile.dat", "./folder/targetFile.link.dat");
* ```
*/
export function ensureSymlinkSync(
target: string | URL,
linkName: string | URL,
) {
const targetRealPath = resolveSymlinkTarget(target, linkName);
const srcStatInfo = Deno.lstatSync(targetRealPath);
let srcStatInfo;
try {
srcStatInfo = Deno.lstatSync(targetRealPath);
} catch (error) {
if (error instanceof Deno.errors.NotFound) {
throw new Deno.errors.NotFound(
`Cannot ensure symlink as the target path does not exist: ${targetRealPath}`,
);
}
throw error;
}
const srcFilePathType = getFileInfoType(srcStatInfo);

ensureDirSync(dirname(toPathString(linkName)));
Expand Down
31 changes: 30 additions & 1 deletion fs/ensure_symlink_test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// TODO(axetroy): Add test for Windows once symlink is implemented for Windows.
import { assert, assertEquals, assertRejects, assertThrows } from "@std/assert";
import {
assert,
assertEquals,
assertMatch,
assertRejects,
assertThrows,
} from "@std/assert";
import * as path from "@std/path";
import { ensureSymlink, ensureSymlinkSync } from "./ensure_symlink.ts";
import { IS_DENO_2 } from "../internal/_is_deno_2.ts";
Expand Down Expand Up @@ -239,6 +245,29 @@ Deno.test("ensureSymlinkSync() creates symlink with relative target", function (
Deno.removeSync(testDir, { recursive: true });
});

Deno.test("ensureSymlink() rejects when the target path doesn't exist", async () => {
const e = await assertRejects(
async () => {
await ensureSymlink("non-existent-target", "non-existent-link");
},
Deno.errors.NotFound,
);
assertMatch(
e.message,
/^Cannot ensure symlink as the target path does not exist: .*non-existent-target$/,
);
});

Deno.test("ensureSymlinkSync() throws when the target path doesn't exist", () => {
const e = assertThrows(() => {
ensureSymlinkSync("non-existent-target", "non-existent-link");
}, Deno.errors.NotFound);
assertMatch(
e.message,
/^Cannot ensure symlink as the target path does not exist: .*non-existent-target$/,
);
});

Deno.test("ensureSymlink() works with URLs", {
// TODO(kt3k): The 2nd test case doesn't pass on Windows. Fix it.
ignore: Deno.build.os === "windows",
Expand Down

0 comments on commit 93e0cd6

Please sign in to comment.