Skip to content

Commit bc431c8

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 b7b18fd commit bc431c8

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
@@ -354,7 +354,10 @@ class Glob {
354354
// consistent comparison before instantiating matchers.
355355
const matchers = exclude
356356
.map((pattern) => resolve(this.#root, pattern))
357-
.map((pattern) => createMatcher(pattern));
357+
// Exclude matching is a pure string comparison with no filesystem
358+
// lookups, so unlike include patterns, literal patterns must also
359+
// match case-insensitively on case-insensitive platforms.
360+
.map((pattern) => createMatcher(pattern, { nocaseMagicOnly: false }));
358361
this.#isExcluded = (value) =>
359362
matchers.some((matcher) => matcher.match(value));
360363
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
@@ -730,3 +730,31 @@ describe('glob - seen cache', function() {
730730
assert.strictEqual(child.status, 0, child.stderr || child.stdout);
731731
});
732732
});
733+
734+
// gh-58991: exclude patterns must apply the same case-sensitivity as include
735+
// patterns. On case-insensitive filesystems include patterns match entries
736+
// regardless of case, so literal exclude patterns must match that behavior.
737+
const skipCaseTests = { skip: !common.isWindows && !common.isMacOS };
738+
describe('glob - exclude case-insensitive consistency', skipCaseTests, function() {
739+
test('literal exclude ignores case (sync)', () => {
740+
assert.deepStrictEqual(
741+
globSync('a/b', { cwd: fixtureDir, exclude: ['A/B'] }), []);
742+
});
743+
test('literal exclude matches differently-cased results (sync)', () => {
744+
assert.deepStrictEqual(
745+
globSync('A/b', { cwd: fixtureDir, exclude: ['a/b'] }), []);
746+
});
747+
test('literal exclude ignores case (async)', async () => {
748+
const promisified = promisify(glob);
749+
assert.deepStrictEqual(
750+
await promisified('a/b', { cwd: fixtureDir, exclude: ['A/B'] }), []);
751+
});
752+
test('literal exclude ignores case (promise)', async () => {
753+
const actual = [];
754+
for await (const entry of asyncGlob(
755+
'a/b', { cwd: fixtureDir, exclude: ['A/B'] })) {
756+
actual.push(entry);
757+
}
758+
assert.deepStrictEqual(actual, []);
759+
});
760+
});

0 commit comments

Comments
 (0)