From 84654b9221416477430444d03a8c474601a44f83 Mon Sep 17 00:00:00 2001 From: Shaurya Saria Date: Sat, 8 Aug 2026 10:28:01 +0530 Subject: [PATCH 1/2] benchmark: cover UTF-8 encoding variants Signed-off-by: Shaurya Saria --- benchmark/fs/bench-writeFileSync.js | 5 ++++- benchmark/fs/readFileSync.js | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/benchmark/fs/bench-writeFileSync.js b/benchmark/fs/bench-writeFileSync.js index 29c16f4aa2a1..987ac7e56e83 100644 --- a/benchmark/fs/bench-writeFileSync.js +++ b/benchmark/fs/bench-writeFileSync.js @@ -7,7 +7,10 @@ tmpdir.refresh(); // Some variants are commented out as they do not show a change and just slow const bench = common.createBenchmark(main, { - encoding: ['utf8'], + // Include valid case variants to measure the fast-path trade-off. + encoding: [ + 'utf8', 'utf-8', 'UTF8', 'UTF-8', 'Utf8', 'Utf-8', + ], useFd: ['true', 'false'], length: [1024, 102400, 1024 * 1024], diff --git a/benchmark/fs/readFileSync.js b/benchmark/fs/readFileSync.js index bfa00070b157..0904a346e3c6 100644 --- a/benchmark/fs/readFileSync.js +++ b/benchmark/fs/readFileSync.js @@ -4,7 +4,10 @@ const common = require('../common.js'); const fs = require('fs'); const bench = common.createBenchmark(main, { - encoding: ['undefined', 'utf8', 'ascii'], + // Include valid case variants to measure the fast-path trade-off. + encoding: [ + 'undefined', 'utf8', 'utf-8', 'UTF8', 'UTF-8', 'Utf8', 'Utf-8', 'ascii', + ], path: ['existing', 'non-existing'], hasFileDescriptor: ['true', 'false'], n: [1e4], From 7fe0fa87d033ac73ca5ba01ca34b91e5d13cf41b Mon Sep 17 00:00:00 2001 From: Shaurya Saria Date: Sat, 8 Aug 2026 10:33:32 +0530 Subject: [PATCH 2/2] fs: use fast paths for UTF-8 aliases Signed-off-by: Shaurya Saria --- lib/fs.js | 14 ++++++++++---- test/parallel/test-fs-readfile-utf8-fast-path.js | 8 ++++++++ test/parallel/test-fs-realpath-buffer-encoding.js | 2 +- test/parallel/test-fs-write-file-sync.js | 10 ++++++++++ 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index 4fbdaf813018..5422e0ba1dd2 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -531,8 +531,7 @@ function readFileSync(path, options) { validateReadFileBufferOptions(options); const hasUserBuffer = options.buffer !== undefined; - if ((options.encoding === 'utf8' || options.encoding === 'utf-8') && - !hasUserBuffer) { + if (isUtf8Encoding(options.encoding) && !hasUserBuffer) { if (!isInt32(path)) { path = getValidatedPath(path); } @@ -2906,7 +2905,7 @@ function writeFileSync(path, data, options) { const flag = options.flag || 'w'; // C++ fast path for string data and UTF8 encoding - if (typeof data === 'string' && (options.encoding === 'utf8' || options.encoding === 'utf-8')) { + if (typeof data === 'string' && isUtf8Encoding(options.encoding)) { if (!isInt32(path)) { path = getValidatedPath(path); } @@ -3196,8 +3195,15 @@ if (isWindows) { }; } +function isUtf8Encoding(encoding) { + return encoding === 'utf8' || + encoding === 'utf-8' || + encoding === 'UTF8' || + encoding === 'UTF-8'; +} + function encodeRealpathResult(result, options) { - if (!options || !options.encoding || options.encoding === 'utf8') + if (!options || !options.encoding || isUtf8Encoding(options.encoding)) return result; const asBuffer = Buffer.from(result); if (options.encoding === 'buffer') { diff --git a/test/parallel/test-fs-readfile-utf8-fast-path.js b/test/parallel/test-fs-readfile-utf8-fast-path.js index 18d0d884dfa4..11cd785a229e 100644 --- a/test/parallel/test-fs-readfile-utf8-fast-path.js +++ b/test/parallel/test-fs-readfile-utf8-fast-path.js @@ -28,6 +28,14 @@ describe('fs.readFileSync utf8 simdutf dispatch', () => { assert.strictEqual(fs.readFileSync(p, 'utf8'), ''); }); + it('UTF-8 encoding aliases', () => { + const buf = Buffer.from('hello 中文 — 🚀', 'utf8'); + const p = writeFile('encoding-aliases.txt', buf); + for (const encoding of ['utf8', 'utf-8', 'UTF8', 'UTF-8']) { + assert.strictEqual(fs.readFileSync(p, encoding), buf.toString('utf8')); + } + }); + it('ascii small', () => { const buf = Buffer.from('hello'); expectMatches(writeFile('tiny-ascii.txt', buf), buf); diff --git a/test/parallel/test-fs-realpath-buffer-encoding.js b/test/parallel/test-fs-realpath-buffer-encoding.js index dbf2bda2c77d..189e9355738e 100644 --- a/test/parallel/test-fs-realpath-buffer-encoding.js +++ b/test/parallel/test-fs-realpath-buffer-encoding.js @@ -8,7 +8,7 @@ const string_dir = fs.realpathSync(fixtures.fixturesDir); const buffer_dir = Buffer.from(string_dir); const encodings = ['ascii', 'utf8', 'utf16le', 'ucs2', - 'base64', 'binary', 'hex']; + 'base64', 'binary', 'hex', 'UTF8', 'UTF-8']; const expected = {}; for (const encoding of encodings) { expected[encoding] = buffer_dir.toString(encoding); diff --git a/test/parallel/test-fs-write-file-sync.js b/test/parallel/test-fs-write-file-sync.js index e5fbe32eab6d..13b79087fed6 100644 --- a/test/parallel/test-fs-write-file-sync.js +++ b/test/parallel/test-fs-write-file-sync.js @@ -119,6 +119,16 @@ tmpdir.refresh(); } } +// Test writeFileSync with UTF-8 encoding aliases +{ + const utf8Data = 'hello world! 中文 — 🚀'; + for (const encoding of ['utf8', 'utf-8', 'UTF8', 'UTF-8']) { + const file = tmpdir.resolve(`testWriteFileSyncEncoding_${encoding}.txt`); + fs.writeFileSync(file, utf8Data, { encoding }); + assert.strictEqual(fs.readFileSync(file, 'utf8'), utf8Data); + } +} + // Test writeFileSync with an invalid input { const file = tmpdir.resolve('testWriteFileSyncInvalid.txt');