From 39650923ae446dfa5243301a9136a0cf43a0be82 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Tue, 28 Apr 2026 08:42:13 +0000 Subject: [PATCH] fix(ext/node): support `encoding` option in `fs.watch` `fs.watch(path, { encoding })` previously emitted the filename as a plain utf8 string regardless of the requested encoding. Match Node: - `encoding: 'buffer'` returns a `Buffer`, - any other named encoding (e.g. `'hex'`, `'base64'`) re-encodes the filename via `Buffer.from(filename).toString(encoding)`, - the default (`'utf8'` or absent) leaves the string unchanged. See https://github.com/nodejs/node/blob/main/lib/internal/fs/watchers.js Enables `parallel/test-fs-watch-encoding.js`. --- ext/node/polyfills/fs.ts | 26 ++++++++++++++++++++++++-- tests/node_compat/config.jsonc | 1 + 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/ext/node/polyfills/fs.ts b/ext/node/polyfills/fs.ts index 7d7c490126d04b..b683da164c0443 100644 --- a/ext/node/polyfills/fs.ts +++ b/ext/node/polyfills/fs.ts @@ -3135,7 +3135,28 @@ type watchOptions = { encoding?: string; }; -type watchListener = (eventType: string, filename: string) => void; +type watchListener = ( + eventType: string, + filename: string | Buffer, +) => void; + +// Match Node: `encoding: 'buffer'` returns a Buffer, any other named encoding +// returns the filename re-encoded from utf8. Default ('utf8' or absent) leaves +// the string unchanged. https://github.com/nodejs/node/blob/main/lib/internal/fs/watchers.js +function encodeWatchFilename( + filename: string, + encoding: string | undefined, +): string | Buffer { + if (!encoding || encoding === "utf8" || encoding === "utf-8") { + return filename; + } + const asBuffer = Buffer.from(filename); + if (encoding === "buffer") { + return asBuffer; + } + // deno-lint-ignore prefer-primordials + return asBuffer.toString(encoding as BufferEncoding); +} function watch( filename: string | URL, @@ -3171,6 +3192,7 @@ function watch( const watchPath = getValidatedPath(filename).toString(); const recursive = options?.recursive || false; + const encoding = options?.encoding; const iterator: Deno.FsWatcher = Deno.watchFs(watchPath, { recursive, }); @@ -3190,7 +3212,7 @@ function watch( fsWatcher.emit( "change", convertDenoFsEventToNodeFsEvent(val.kind), - filename, + encodeWatchFilename(filename, encoding), ); }, (e) => { fsWatcher.emit("error", e); diff --git a/tests/node_compat/config.jsonc b/tests/node_compat/config.jsonc index 93a58f911a2cc9..ba670bda5e0030 100644 --- a/tests/node_compat/config.jsonc +++ b/tests/node_compat/config.jsonc @@ -1189,6 +1189,7 @@ "parallel/test-fs-util-validateoffsetlength.js": {}, "parallel/test-fs-utimes-y2K38.js": {}, "parallel/test-fs-utimes.js": {}, + "parallel/test-fs-watch-encoding.js": {}, "parallel/test-fs-watch-file-enoent-after-deletion.js": {}, "parallel/test-fs-watch-recursive-add-file-to-existing-subfolder.js": {}, "parallel/test-fs-watch-recursive-add-folder.js": {},