From 2de285c04853a7554e014373c9ce38de452e46cf Mon Sep 17 00:00:00 2001 From: adarsh-priydarshi-5646 Date: Thu, 20 Nov 2025 11:47:19 +0530 Subject: [PATCH 1/2] feat: add isClosed() method to Deno.FsFile Adds a new isClosed() method to check if a file has been closed. This helps developers query the close status of FsFile instances. Fixes #31341 --- cli/tsc/dts/lib.deno.ns.d.ts | 11 +++++++++ ext/fs/30_fs.js | 10 ++++++++- tests/unit/files_test.ts | 43 ++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/cli/tsc/dts/lib.deno.ns.d.ts b/cli/tsc/dts/lib.deno.ns.d.ts index dae1c2cf2e0181..29d5f0668a12fc 100644 --- a/cli/tsc/dts/lib.deno.ns.d.ts +++ b/cli/tsc/dts/lib.deno.ns.d.ts @@ -2239,6 +2239,17 @@ declare namespace Deno { * ``` */ close(): void; + /** + * Check if the file is closed. + * + * ```ts + * const file = await Deno.open("my_file.txt"); + * console.log(file.isClosed()); // false + * file.close(); + * console.log(file.isClosed()); // true + * ``` + */ + isClosed(): boolean; [Symbol.dispose](): void; } diff --git a/ext/fs/30_fs.js b/ext/fs/30_fs.js index 16653592826edd..76d178de6bc1b7 100644 --- a/ext/fs/30_fs.js +++ b/ext/fs/30_fs.js @@ -584,6 +584,7 @@ class FsFile { #readable; #writable; + #closed = false; constructor(rid, symbol) { ObjectDefineProperty(this, internalRidSymbol, { @@ -650,6 +651,11 @@ class FsFile { close() { core.close(this.#rid); + this.#closed = true; + } + + isClosed() { + return this.#closed; } get readable() { @@ -718,7 +724,9 @@ class FsFile { } [SymbolDispose]() { - core.tryClose(this.#rid); + if (core.tryClose(this.#rid)) { + this.#closed = true; + } } } diff --git a/tests/unit/files_test.ts b/tests/unit/files_test.ts index aa211b224d0bf9..7a8a94ca1a9134 100644 --- a/tests/unit/files_test.ts +++ b/tests/unit/files_test.ts @@ -701,6 +701,49 @@ Deno.test( }, ); +Deno.test( + { permissions: { read: true } }, + async function fsFileIsClosed() { + const file = await Deno.open("tests/testdata/assets/hello.txt"); + assertEquals(file.isClosed(), false); + file.close(); + assertEquals(file.isClosed(), true); + }, +); + +Deno.test( + { permissions: { read: true } }, + function fsFileIsClosedSync() { + const file = Deno.openSync("tests/testdata/assets/hello.txt"); + assertEquals(file.isClosed(), false); + file.close(); + assertEquals(file.isClosed(), true); + }, +); + +Deno.test( + { permissions: { read: true } }, + async function fsFileIsClosedWithUsing() { + let file2: Deno.FsFile; + { + using file = await Deno.open("tests/testdata/assets/hello.txt"); + file2 = file; + assertEquals(file.isClosed(), false); + } + assertEquals(file2.isClosed(), true); + }, +); + +Deno.test( + { permissions: { read: true } }, + async function fsFileIsClosedAfterManualCloseInUsing() { + using file = await Deno.open("tests/testdata/assets/hello.txt"); + assertEquals(file.isClosed(), false); + file.close(); + assertEquals(file.isClosed(), true); + }, +); + Deno.test( { permissions: { read: true, write: true } }, function fsFileDatasyncSyncSuccess() { From 9344dc551d8224f354e28cdeb95394f4881f38b2 Mon Sep 17 00:00:00 2001 From: adarsh-priydarshi-5646 Date: Thu, 20 Nov 2025 12:09:14 +0530 Subject: [PATCH 2/2] fix: correct SymbolDispose implementation for isClosed --- ext/fs/30_fs.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ext/fs/30_fs.js b/ext/fs/30_fs.js index 76d178de6bc1b7..a0434b9bcdbc9a 100644 --- a/ext/fs/30_fs.js +++ b/ext/fs/30_fs.js @@ -724,9 +724,8 @@ class FsFile { } [SymbolDispose]() { - if (core.tryClose(this.#rid)) { - this.#closed = true; - } + core.tryClose(this.#rid); + this.#closed = true; } }