Skip to content

Commit 187b299

Browse files
yhay81aduh95
authored andcommitted
fs: apply nocase to literal glob exclude patterns
On case-insensitive platforms include patterns match entries regardless of case, but literal (non-magic) exclude patterns were matched case-sensitively because exclude matchers are created with nocaseMagicOnly. Exclusion is a pure string match with no filesystem lookups, so disable nocaseMagicOnly for exclude matchers. Fixes: #58991 Refs: #63446 Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com> PR-URL: #64817 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Stefan Stojanovic <stefan.stojanovic@janeasystems.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
1 parent 3f9236a commit 187b299

2 files changed

Lines changed: 32 additions & 1 deletion

File tree

lib/internal/fs/glob.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,10 @@ class Glob {
664664
// consistent comparison before instantiating matchers.
665665
const matchers = exclude
666666
.map((pattern) => resolve(this.#root, pattern))
667-
.map((pattern) => createMatcher(pattern));
667+
// Exclude matching is a pure string comparison with no filesystem
668+
// lookups, so unlike include patterns, literal patterns must also
669+
// match case-insensitively on case-insensitive platforms.
670+
.map((pattern) => createMatcher(pattern, { nocaseMagicOnly: false }));
668671
this.#isExcluded = (value) =>
669672
matchers.some((matcher) => matcher.match(value));
670673
this.#results.setup(this.#root, this.#isExcluded);

test/parallel/test-fs-glob.mjs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,3 +983,31 @@ describe('glob - seen cache', function() {
983983
);
984984
});
985985
});
986+
987+
// gh-58991: exclude patterns must apply the same case-sensitivity as include
988+
// patterns. On case-insensitive filesystems include patterns match entries
989+
// regardless of case, so literal exclude patterns must match that behavior.
990+
const skipCaseTests = { skip: !common.isWindows && !common.isMacOS };
991+
describe('glob - exclude case-insensitive consistency', skipCaseTests, function() {
992+
test('literal exclude ignores case (sync)', () => {
993+
assert.deepStrictEqual(
994+
globSync('a/b', { cwd: fixtureDir, exclude: ['A/B'] }), []);
995+
});
996+
test('literal exclude matches differently-cased results (sync)', () => {
997+
assert.deepStrictEqual(
998+
globSync('A/b', { cwd: fixtureDir, exclude: ['a/b'] }), []);
999+
});
1000+
test('literal exclude ignores case (async)', async () => {
1001+
const promisified = promisify(glob);
1002+
assert.deepStrictEqual(
1003+
await promisified('a/b', { cwd: fixtureDir, exclude: ['A/B'] }), []);
1004+
});
1005+
test('literal exclude ignores case (promise)', async () => {
1006+
const actual = [];
1007+
for await (const entry of asyncGlob(
1008+
'a/b', { cwd: fixtureDir, exclude: ['A/B'] })) {
1009+
actual.push(entry);
1010+
}
1011+
assert.deepStrictEqual(actual, []);
1012+
});
1013+
});

0 commit comments

Comments
 (0)