diff --git a/node/_fs/_fs_exists.ts b/node/_fs/_fs_exists.ts index cb4a94922b9e..998ce2585e7a 100644 --- a/node/_fs/_fs_exists.ts +++ b/node/_fs/_fs_exists.ts @@ -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 diff --git a/node/_fs/_fs_exists_test.ts b/node/_fs/_fs_exists_test.ts index 1c360b86335f..94a70bfbc565 100644 --- a/node/_fs/_fs_exists_test.ts +++ b/node/_fs/_fs_exists_test.ts @@ -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) => { @@ -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();