From 75c8645dfe3b14d33f6d77ae9553de3e68f15911 Mon Sep 17 00:00:00 2001 From: louiellan Date: Wed, 20 May 2026 08:32:27 +0800 Subject: [PATCH] fs: fix glob case mismatch on Windows and MacOS where the `exclude` option is case sensitive but the `pattern` is a case insensitive operation (on Windows and MacOS), thus results to any casing difference in matched list not to be filtered out and does not return the true casing of a matched directory / file Refs: https://github.com/nodejs/node/issues/58991 Signed-off-by: louiellan --- lib/internal/fs/glob.js | 2 +- test/parallel/test-fs-glob.mjs | 53 ++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/lib/internal/fs/glob.js b/lib/internal/fs/glob.js index c5bbdb9813c0d1..64c1fb596f7522 100644 --- a/lib/internal/fs/glob.js +++ b/lib/internal/fs/glob.js @@ -118,7 +118,7 @@ function createMatcher(pattern, options = kEmptyObject) { nocomment: true, optimizationLevel: 2, platform: process.platform, - nocaseMagicOnly: true, + nocaseMagicOnly: (!isWindows && !isMacOS), ...options, }; return new (lazyMinimatch().Minimatch)(pattern, opts); diff --git a/test/parallel/test-fs-glob.mjs b/test/parallel/test-fs-glob.mjs index 560b4e72e4adec..2056414a191613 100644 --- a/test/parallel/test-fs-glob.mjs +++ b/test/parallel/test-fs-glob.mjs @@ -484,6 +484,59 @@ const patterns2 = [ [ 'a/**', [ '*' ], [] ], [ 'a/**', [ '**' ], [] ], [ 'a/**', [ 'a/**' ], [] ], + ...((common.isWindows || common.isMacOS) ? + // on Windows or MacOS + [ + ['a/b', ['A/B'], []], + ['a/b*', ['A/B'], ['a/bc']], + ['A*/B', ['A/B'], []], + ['a*/B', ['A/B'], []], + ['a*/b', ['A/B'], []], + + ['A/B', ['a/b'], []], + ['A/B*', ['a/b'], ['a/bc']], + ['A*/B', ['a/b'], []], + ['a*/B', ['a/b'], []], + ['A*/b', ['a/b'], []], + + ['a/b', ['A/B*'], []], + ['a/b*', ['A/B*'], []], + ['A*/B', ['A/B*'], []], + ['a*/B', ['A/B*'], []], + ['a*/b', ['A/B*'], []], + + ['A/B', ['a/b*'], []], + ['A/B*', ['a/b*'], []], + ['A*/B', ['a/b*'], []], + ['a*/B', ['a/b*'], []], + ['A*/b', ['a/b*'], []], + + ['a/b', ['A*/B'], []], + ['a/b*', ['A*/B'], ['a/bc']], + ['A*/B', ['A*/B'], []], + ['a*/B', ['A*/B'], []], + ['a*/b', ['A*/B'], []], + + ['A/B', ['a*/b'], []], + ['A/B*', ['a*/b'], ['a/bc']], + ['A*/B', ['a*/b'], []], + ['a*/B', ['a*/b'], []], + ['A*/b', ['a*/b'], []], + + ['a/b', ['A/{B,C}'], []], + ['a/b*', ['A/{B,C}'], ['a/bc']], + ['A*/B', ['A/{B,C}'], []], + ['a*/B', ['A/{B,C}'], []], + ['a*/b', ['A/{B,C}'], []], + + ['A/B', ['a/{b,c}'], []], + ['A/B*', ['a/{b,c}'], ['a/bc']], + ['A*/B', ['a/{b,c}'], []], + ['a*/B', ['a/{b,c}'], []], + ['A*/b', ['a/{b,c}'], []], + + ] : [] + ) ]; describe('globSync - exclude', function() {