Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(node/fs/exists): fix promisified exists #2409

Merged
merged 1 commit into from
Jul 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions node/_fs/_fs_exists.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
import { fromFileUrl } from "../path.ts";

type ExitsCallback = (exists: boolean) => void;
type ExistsCallback = (exists: boolean) => void;

/**
* TODO: Also accept 'path' parameter as a Node polyfill Buffer type once these
* are implemented. See https://github.com/denoland/deno/issues/3403
* Deprecated in node api
*/
export function exists(path: string | URL, callback: ExitsCallback): void {
export function exists(path: string | URL, callback: ExistsCallback): void {
path = path instanceof URL ? fromFileUrl(path) : path;
Deno.lstat(path).then(() => callback(true), () => callback(false));
}

// The callback of fs.exists doesn't have standard callback signature.
// We need to provide special implementation for promisify.
// See https://github.com/nodejs/node/pull/13316
const kCustomPromisifiedSymbol = Symbol.for("nodejs.util.promisify.custom");
Object.defineProperty(exists, kCustomPromisifiedSymbol, {
value: (path: string | URL) => {
return new Promise((resolve) => {
exists(path, (exists) => resolve(exists));
});
},
});

/**
* TODO: Also accept 'path' parameter as a Node polyfill Buffer or URL type once these
* are implemented. See https://github.com/denoland/deno/issues/3403
Expand Down
16 changes: 14 additions & 2 deletions node/_fs/_fs_exists_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import {
assertStringIncludes,
} from "../../testing/asserts.ts";
import { exists, existsSync } from "./_fs_exists.ts";
import { promisify } from "../util.ts";

Deno.test("existsFile", async function () {
Deno.test("[std/node/fs] exists", async function () {
const availableFile = await new Promise((resolve) => {
const tmpFilePath = Deno.makeTempFileSync();
exists(tmpFilePath, (exists: boolean) => {
Expand All @@ -21,13 +22,24 @@ Deno.test("existsFile", async function () {
assertEquals(notAvailableFile, false);
});

Deno.test("existsSyncFile", function () {
Deno.test("[std/node/fs] existsSync", function () {
const tmpFilePath = Deno.makeTempFileSync();
assertEquals(existsSync(tmpFilePath), true);
Deno.removeSync(tmpFilePath);
assertEquals(existsSync("./notAvailable.txt"), false);
});

Deno.test("[std/node/fs] promisify(exists)", async () => {
const tmpFilePath = await Deno.makeTempFile();
try {
const existsPromisified = promisify(exists);
assert(await existsPromisified(tmpFilePath));
assert(!await existsPromisified("./notAvailable.txt"));
} finally {
await Deno.remove(tmpFilePath);
}
});

Deno.test("[std/node/fs] exists callback isn't called twice if error is thrown", async () => {
// This doesn't use `assertCallbackErrorUncaught()` because `exists()` doesn't return a standard node callback, which is what it expects.
const tempFile = await Deno.makeTempFile();
Expand Down