Skip to content

Commit 4882cfd

Browse files
committed
fs: apply function exclude to glob results
1 parent 4744070 commit 4882cfd

2 files changed

Lines changed: 85 additions & 16 deletions

File tree

lib/internal/fs/glob.js

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,18 @@ class Glob {
491491
ArrayPrototypePush(this.#subpatterns.get(path), pattern);
492492
}
493493
}
494+
#addResult(path, dirent) {
495+
if (this.#exclude) {
496+
if (this.#withFileTypes) {
497+
if (dirent !== null && this.#exclude(dirent)) {
498+
return false;
499+
}
500+
} else if (this.#exclude(path)) {
501+
return false;
502+
}
503+
}
504+
return this.#results.add(path);
505+
}
494506
#addSubpatterns(path, pattern) {
495507
const seen = this.#cache.add(path, pattern);
496508
if (seen) {
@@ -532,7 +544,7 @@ class Glob {
532544
const p = pattern.at(-1);
533545
const stat = this.#cache.statSync(join(fullpath, p));
534546
if (stat && (p || isDirectory)) {
535-
this.#results.add(join(path, p));
547+
this.#addResult(join(path, p), stat);
536548
}
537549
if (pattern.indexes.size === 1 && pattern.indexes.has(last)) {
538550
return;
@@ -541,7 +553,7 @@ class Glob {
541553
(path !== '.' || pattern.at(0) === '.' || (last === 0 && stat))) {
542554
// If pattern ends with **, add to results
543555
// if path is ".", add it only if pattern starts with "." or pattern is exactly "**"
544-
this.#results.add(path);
556+
this.#addResult(path, stat);
545557
}
546558

547559
if (!isDirectory || this.#isCyclicSync(fullpath, isDirectory, pattern)) {
@@ -604,14 +616,14 @@ class Glob {
604616
subPatterns.add(index);
605617
} else if (!fromSymlink && index === last) {
606618
// If ** is last, add to results
607-
this.#results.add(entryPath);
619+
this.#addResult(entryPath, entry);
608620
}
609621

610622
// Any pattern after ** is also a potential pattern
611623
// so we can already test it here
612624
if (nextMatches && nextIndex === last && !isLast) {
613625
// If next pattern is the last one, add to results
614-
this.#results.add(entryPath);
626+
this.#addResult(entryPath, entry);
615627
} else if (nextMatches && entryIsDirectory) {
616628
// Pattern matched, meaning two patterns forward
617629
// are also potential patterns
@@ -644,11 +656,11 @@ class Glob {
644656
} else {
645657
if (!this.#cache.seen(path, pattern, nextIndex)) {
646658
this.#cache.add(path, pattern.child(new SafeSet().add(nextIndex)));
647-
this.#results.add(path);
659+
this.#addResult(path, this.#cache.statSync(fullpath));
648660
}
649661
if (!this.#cache.seen(path, pattern, nextIndex) || !this.#cache.seen(parent, pattern, nextIndex)) {
650662
this.#cache.add(parent, pattern.child(new SafeSet().add(nextIndex)));
651-
this.#results.add(parent);
663+
this.#addResult(parent, this.#cache.statSync(join(this.#root, parent)));
652664
}
653665
}
654666
}
@@ -661,7 +673,7 @@ class Glob {
661673
} else if (current === '.' && pattern.test(nextIndex, entry.name)) {
662674
// If current pattern is ".", proceed to test next pattern
663675
if (nextIndex === last) {
664-
this.#results.add(entryPath);
676+
this.#addResult(entryPath, entry);
665677
} else {
666678
subPatterns.add(nextIndex + 1);
667679
}
@@ -671,7 +683,7 @@ class Glob {
671683
// If current pattern is a regex that matches entry name (e.g *.js)
672684
// add next pattern to potential patterns, or to results if it's the last pattern
673685
if (index === last) {
674-
this.#results.add(entryPath);
686+
this.#addResult(entryPath, entry);
675687
} else if (entryIsDirectory) {
676688
subPatterns.add(nextIndex);
677689
}
@@ -740,7 +752,7 @@ class Glob {
740752
if (stat && (p || isDirectory)) {
741753
const result = join(path, p);
742754
if (!this.#results.has(result)) {
743-
if (this.#results.add(result)) {
755+
if (this.#addResult(result, stat)) {
744756
yield this.#withFileTypes ? stat : result;
745757
}
746758
}
@@ -753,7 +765,7 @@ class Glob {
753765
// If pattern ends with **, add to results
754766
// if path is ".", add it only if pattern starts with "." or pattern is exactly "**"
755767
if (!this.#results.has(path)) {
756-
if (this.#results.add(path)) {
768+
if (this.#addResult(path, stat)) {
757769
yield this.#withFileTypes ? stat : path;
758770
}
759771
}
@@ -821,7 +833,7 @@ class Glob {
821833
subPatterns.add(index);
822834
} else if (!fromSymlink && index === last) {
823835
// If ** is last, add to results
824-
if (!this.#results.has(entryPath) && this.#results.add(entryPath)) {
836+
if (!this.#results.has(entryPath) && this.#addResult(entryPath, entry)) {
825837
yield this.#withFileTypes ? entry : entryPath;
826838
}
827839
}
@@ -830,7 +842,7 @@ class Glob {
830842
// so we can already test it here
831843
if (nextMatches && nextIndex === last && !isLast) {
832844
// If next pattern is the last one, add to results
833-
if (!this.#results.has(entryPath) && this.#results.add(entryPath)) {
845+
if (!this.#results.has(entryPath) && this.#addResult(entryPath, entry)) {
834846
yield this.#withFileTypes ? entry : entryPath;
835847
}
836848
} else if (nextMatches && entryIsDirectory) {
@@ -866,15 +878,15 @@ class Glob {
866878
if (!this.#cache.seen(path, pattern, nextIndex)) {
867879
this.#cache.add(path, pattern.child(new SafeSet().add(nextIndex)));
868880
if (!this.#results.has(path)) {
869-
if (this.#results.add(path)) {
881+
if (this.#addResult(path, this.#cache.statSync(fullpath))) {
870882
yield this.#withFileTypes ? this.#cache.statSync(fullpath) : path;
871883
}
872884
}
873885
}
874886
if (!this.#cache.seen(path, pattern, nextIndex) || !this.#cache.seen(parent, pattern, nextIndex)) {
875887
this.#cache.add(parent, pattern.child(new SafeSet().add(nextIndex)));
876888
if (!this.#results.has(parent)) {
877-
if (this.#results.add(parent)) {
889+
if (this.#addResult(parent, this.#cache.statSync(join(this.#root, parent)))) {
878890
yield this.#withFileTypes ? this.#cache.statSync(join(this.#root, parent)) : parent;
879891
}
880892
}
@@ -891,7 +903,7 @@ class Glob {
891903
// If current pattern is ".", proceed to test next pattern
892904
if (nextIndex === last) {
893905
if (!this.#results.has(entryPath)) {
894-
if (this.#results.add(entryPath)) {
906+
if (this.#addResult(entryPath, entry)) {
895907
yield this.#withFileTypes ? entry : entryPath;
896908
}
897909
}
@@ -905,7 +917,7 @@ class Glob {
905917
// add next pattern to potential patterns, or to results if it's the last pattern
906918
if (index === last) {
907919
if (!this.#results.has(entryPath)) {
908-
if (this.#results.add(entryPath)) {
920+
if (this.#addResult(entryPath, entry)) {
909921
yield this.#withFileTypes ? entry : entryPath;
910922
}
911923
}

test/parallel/test-fs-glob.mjs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,9 @@ const patterns2 = [
486486
[ 'a/**', [ 'a/**' ], [] ],
487487
];
488488

489+
const excludedNestedFile = ['a', 'b', 'c', 'd'].join(sep);
490+
const excludesNestedFile = (path) => path === excludedNestedFile;
491+
489492
describe('globSync - exclude', function() {
490493
for (const [pattern, exclude] of Object.entries(patterns).map(([k, v]) => [k, v.filter(Boolean)])) {
491494
test(`${pattern} - exclude: ${exclude}`, () => {
@@ -500,6 +503,22 @@ describe('globSync - exclude', function() {
500503
assert.deepStrictEqual(actual, normalized);
501504
});
502505
}
506+
507+
test('applies function exclude to terminal globstar results', () => {
508+
const actual = globSync('**', {
509+
cwd: fixtureDir,
510+
exclude: excludesNestedFile,
511+
});
512+
assert.ok(!actual.includes(excludedNestedFile));
513+
});
514+
515+
test('applies function exclude to terminal pattern results', () => {
516+
const actual = globSync('**/d', {
517+
cwd: fixtureDir,
518+
exclude: excludesNestedFile,
519+
});
520+
assert.ok(!actual.includes(excludedNestedFile));
521+
});
503522
});
504523

505524
describe('glob - exclude', function() {
@@ -517,6 +536,22 @@ describe('glob - exclude', function() {
517536
assert.deepStrictEqual(actual, normalized);
518537
});
519538
}
539+
540+
test('applies function exclude to terminal globstar results', async () => {
541+
const actual = await promisified('**', {
542+
cwd: fixtureDir,
543+
exclude: excludesNestedFile,
544+
});
545+
assert.ok(!actual.includes(excludedNestedFile));
546+
});
547+
548+
test('applies function exclude to terminal pattern results', async () => {
549+
const actual = await promisified('**/d', {
550+
cwd: fixtureDir,
551+
exclude: excludesNestedFile,
552+
});
553+
assert.ok(!actual.includes(excludedNestedFile));
554+
});
520555
});
521556

522557
describe('fsPromises glob - exclude', function() {
@@ -536,6 +571,28 @@ describe('fsPromises glob - exclude', function() {
536571
assert.deepStrictEqual(actual.sort(), normalized);
537572
});
538573
}
574+
575+
test('applies function exclude to terminal globstar results', async () => {
576+
const actual = [];
577+
for await (const item of asyncGlob('**', {
578+
cwd: fixtureDir,
579+
exclude: excludesNestedFile,
580+
})) {
581+
actual.push(item);
582+
}
583+
assert.ok(!actual.includes(excludedNestedFile));
584+
});
585+
586+
test('applies function exclude to terminal pattern results', async () => {
587+
const actual = [];
588+
for await (const item of asyncGlob('**/d', {
589+
cwd: fixtureDir,
590+
exclude: excludesNestedFile,
591+
})) {
592+
actual.push(item);
593+
}
594+
assert.ok(!actual.includes(excludedNestedFile));
595+
});
539596
});
540597

541598
const followSymlinkPattern = 'follow/**';

0 commit comments

Comments
 (0)