From e4e0add0de2d3961ac5bac2adab8b3712e21cbf3 Mon Sep 17 00:00:00 2001 From: Moshe Atlow Date: Sun, 26 Nov 2023 09:31:58 +0200 Subject: [PATCH] fs: fix glob returning duplicates PR-URL: https://github.com/nodejs/node/pull/50881 Fixes: https://github.com/nodejs/node/issues/50875 Reviewed-By: Antoine du Hamel Reviewed-By: Yagiz Nizipli Reviewed-By: Benjamin Gruenbaum --- lib/internal/fs/glob.js | 20 ++++++++++---------- test/parallel/test-fs-glob.mjs | 1 + 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/internal/fs/glob.js b/lib/internal/fs/glob.js index 323ef2a25d434c..4c62369048ce74 100644 --- a/lib/internal/fs/glob.js +++ b/lib/internal/fs/glob.js @@ -148,7 +148,7 @@ class Glob { #root; #exclude; #cache = new Cache(); - #results = []; + #results = new SafeSet(); #queue = []; #subpatterns = new SafeMap(); constructor(patterns, options = kEmptyObject) { @@ -193,7 +193,7 @@ class Glob { .forEach((patterns, path) => ArrayPrototypePush(this.#queue, { __proto__: null, path, patterns })); this.#subpatterns.clear(); } - return this.#results; + return ArrayFrom(this.#results); } #addSubpattern(path, pattern) { if (!this.#subpatterns.has(path)) { @@ -240,7 +240,7 @@ class Glob { const p = pattern.at(-1); const stat = this.#cache.statSync(join(fullpath, p)); if (stat && (p || isDirectory)) { - ArrayPrototypePush(this.#results, join(path, p)); + this.#results.add(join(path, p)); } if (pattern.indexes.size === 1 && pattern.indexes.has(last)) { return; @@ -249,7 +249,7 @@ class Glob { (path !== '.' || pattern.at(0) === '.' || (last === 0 && stat))) { // If pattern ends with **, add to results // if path is ".", add it only if pattern starts with "." or pattern is exactly "**" - ArrayPrototypePush(this.#results, path); + this.#results.add(path); } if (!isDirectory) { @@ -296,7 +296,7 @@ class Glob { subPatterns.add(index); } else if (!fromSymlink && index === last) { // If ** is last, add to results - ArrayPrototypePush(this.#results, entryPath); + this.#results.add(entryPath); } // Any pattern after ** is also a potential pattern @@ -304,7 +304,7 @@ class Glob { const nextMatches = pattern.test(nextIndex, entry.name); if (nextMatches && nextIndex === last && !isLast) { // If next pattern is the last one, add to results - ArrayPrototypePush(this.#results, entryPath); + this.#results.add(entryPath); } else if (nextMatches && entry.isDirectory()) { // Pattern mached, meaning two patterns forward // are also potential patterns @@ -337,11 +337,11 @@ class Glob { } else { if (!this.#cache.seen(path, pattern, nextIndex)) { this.#cache.add(path, pattern.child(new SafeSet([nextIndex]))); - ArrayPrototypePush(this.#results, path); + this.#results.add(path); } if (!this.#cache.seen(path, pattern, nextIndex) || !this.#cache.seen(parent, pattern, nextIndex)) { this.#cache.add(parent, pattern.child(new SafeSet([nextIndex]))); - ArrayPrototypePush(this.#results, parent); + this.#results.add(parent); } } } @@ -354,7 +354,7 @@ class Glob { } else if (current === '.' && pattern.test(nextIndex, entry.name)) { // If current pattern is ".", proceed to test next pattern if (nextIndex === last) { - ArrayPrototypePush(this.#results, entryPath); + this.#results.add(entryPath); } else { subPatterns.add(nextIndex + 1); } @@ -364,7 +364,7 @@ class Glob { // If current pattern is a regex that matches entry name (e.g *.js) // add next pattern to potential patterns, or to results if it's the last pattern if (index === last) { - ArrayPrototypePush(this.#results, entryPath); + this.#results.add(entryPath); } else if (entry.isDirectory()) { subPatterns.add(nextIndex); } diff --git a/test/parallel/test-fs-glob.mjs b/test/parallel/test-fs-glob.mjs index 0936f6575cb6d7..a789ed1167098a 100644 --- a/test/parallel/test-fs-glob.mjs +++ b/test/parallel/test-fs-glob.mjs @@ -65,6 +65,7 @@ const patterns = { ], 'a/{b,c,d,e,f}/**/g': [], 'a/b/**': ['a/b', 'a/b/c', 'a/b/c/d'], + 'a/{b/**,b/c}': ['a/b', 'a/b/c', 'a/b/c/d'], './**/g': ['a/abcdef/g', 'a/abcfed/g'], 'a/abc{fed,def}/g/h': ['a/abcdef/g/h', 'a/abcfed/g/h'], 'a/abc{fed/g,def}/**/': ['a/abcdef', 'a/abcdef/g', 'a/abcfed/g'],