@@ -16,7 +16,7 @@ const { |
16 | 16 |
|
17 | 17 | const { lstatSync, readdirSync } = require('fs'); |
18 | 18 | const { lstat, readdir } = require('fs/promises'); |
19 | | -const { join, resolve } = require('path'); |
| 19 | +const { join, resolve, basename, isAbsolute } = require('path'); |
20 | 20 |
|
21 | 21 | const { |
22 | 22 | kEmptyObject, |
@@ -27,6 +27,7 @@ const { |
27 | 27 | validateString, |
28 | 28 | validateStringArray, |
29 | 29 | } = require('internal/validators'); |
| 30 | +const { DirentFromStats } = require('internal/fs/utils'); |
30 | 31 |
|
31 | 32 | let minimatch; |
32 | 33 | function lazyMinimatch() { |
@@ -37,6 +38,14 @@ function lazyMinimatch() { |
37 | 38 | const isWindows = process.platform === 'win32'; |
38 | 39 | const isOSX = process.platform === 'darwin'; |
39 | 40 |
|
| 41 | +async function getDirent(path) { |
| 42 | + return new DirentFromStats(basename(path), await lstat(path), path); |
| 43 | +} |
| 44 | + |
| 45 | +function getDirentSync(path) { |
| 46 | + return new DirentFromStats(basename(path), lstatSync(path), path); |
| 47 | +} |
| 48 | + |
40 | 49 | class Cache { |
41 | 50 | #cache = new SafeMap(); |
42 | 51 | #statsCache = new SafeMap(); |
@@ -47,7 +56,7 @@ class Cache { |
47 | 56 | if (cached) { |
48 | 57 | return cached; |
49 | 58 | } |
50 | | - const promise = PromisePrototypeThen(lstat(path), null, () => null); |
| 59 | + const promise = PromisePrototypeThen(getDirent(path), null, () => null); |
51 | 60 | this.#statsCache.set(path, promise); |
52 | 61 | return promise; |
53 | 62 | } |
@@ -58,7 +67,7 @@ class Cache { |
58 | 67 | } |
59 | 68 | let val; |
60 | 69 | try { |
61 | | - val = lstatSync(path); |
| 70 | + val = getDirentSync(path); |
62 | 71 | } catch { |
63 | 72 | val = null; |
64 | 73 | } |
@@ -175,14 +184,16 @@ class Glob { |
175 | 184 | #queue = []; |
176 | 185 | #subpatterns = new SafeMap(); |
177 | 186 | #patterns; |
| 187 | + #withFileTypes; |
178 | 188 | constructor(pattern, options = kEmptyObject) { |
179 | 189 | validateObject(options, 'options'); |
180 | | - const { exclude, cwd } = options; |
| 190 | + const { exclude, cwd, withFileTypes } = options; |
181 | 191 | if (exclude != null) { |
182 | 192 | validateFunction(exclude, 'options.exclude'); |
183 | 193 | } |
184 | 194 | this.#root = cwd ?? '.'; |
185 | 195 | this.#exclude = exclude; |
| 196 | + this.#withFileTypes = !!withFileTypes; |
186 | 197 | let patterns; |
187 | 198 | if (typeof pattern === 'object') { |
188 | 199 | validateStringArray(pattern, 'patterns'); |
@@ -222,7 +233,14 @@ class Glob { |
222 | 233 | .forEach((patterns, path) => ArrayPrototypePush(this.#queue, { __proto__: null, path, patterns })); |
223 | 234 | this.#subpatterns.clear(); |
224 | 235 | } |
225 | | - return ArrayFrom(this.#results); |
| 236 | + return ArrayFrom( |
| 237 | + this.#results, |
| 238 | + this.#withFileTypes ? (path) => this.#cache.statSync( |
| 239 | + isAbsolute(path) ? |
| 240 | + path : |
| 241 | + join(this.#root, path), |
| 242 | + ) : undefined, |
| 243 | + ); |
226 | 244 | } |
227 | 245 | #addSubpattern(path, pattern) { |
228 | 246 | if (!this.#subpatterns.has(path)) { |
@@ -317,7 +335,7 @@ class Glob { |
317 | 335 | const fromSymlink = pattern.symlinks.has(index); |
318 | 336 |
|
319 | 337 | if (current === lazyMinimatch().GLOBSTAR) { |
320 | | - if (entry.name[0] === '.' || (this.#exclude && this.#exclude(entry.name))) { |
| 338 | + if (entry.name[0] === '.' || (this.#exclude && this.#exclude(this.#withFileTypes ? entry : entry.name))) { |
321 | 339 | continue; |
322 | 340 | } |
323 | 341 | if (!fromSymlink && entry.isDirectory()) { |
@@ -460,7 +478,7 @@ class Glob { |
460 | 478 | const result = join(path, p); |
461 | 479 | if (!this.#results.has(result)) { |
462 | 480 | this.#results.add(result); |
463 | | - yield result; |
| 481 | + yield this.#withFileTypes ? stat : result; |
464 | 482 | } |
465 | 483 | } |
466 | 484 | if (pattern.indexes.size === 1 && pattern.indexes.has(last)) { |
@@ -472,7 +490,7 @@ class Glob { |
472 | 490 | // if path is ".", add it only if pattern starts with "." or pattern is exactly "**" |
473 | 491 | if (!this.#results.has(path)) { |
474 | 492 | this.#results.add(path); |
475 | | - yield path; |
| 493 | + yield this.#withFileTypes ? stat : path; |
476 | 494 | } |
477 | 495 | } |
478 | 496 |
|
@@ -522,7 +540,7 @@ class Glob { |
522 | 540 | // If ** is last, add to results |
523 | 541 | if (!this.#results.has(entryPath)) { |
524 | 542 | this.#results.add(entryPath); |
525 | | - yield entryPath; |
| 543 | + yield this.#withFileTypes ? entry : entryPath; |
526 | 544 | } |
527 | 545 | } |
528 | 546 |
|
@@ -533,7 +551,7 @@ class Glob { |
533 | 551 | // If next pattern is the last one, add to results |
534 | 552 | if (!this.#results.has(entryPath)) { |
535 | 553 | this.#results.add(entryPath); |
536 | | - yield entryPath; |
| 554 | + yield this.#withFileTypes ? entry : entryPath; |
537 | 555 | } |
538 | 556 | } else if (nextMatches && entry.isDirectory()) { |
539 | 557 | // Pattern mached, meaning two patterns forward |
@@ -569,14 +587,14 @@ class Glob { |
569 | 587 | this.#cache.add(path, pattern.child(new SafeSet().add(nextIndex))); |
570 | 588 | if (!this.#results.has(path)) { |
571 | 589 | this.#results.add(path); |
572 | | - yield path; |
| 590 | + yield this.#withFileTypes ? this.#cache.statSync(fullpath) : path; |
573 | 591 | } |
574 | 592 | } |
575 | 593 | if (!this.#cache.seen(path, pattern, nextIndex) || !this.#cache.seen(parent, pattern, nextIndex)) { |
576 | 594 | this.#cache.add(parent, pattern.child(new SafeSet().add(nextIndex))); |
577 | 595 | if (!this.#results.has(parent)) { |
578 | 596 | this.#results.add(parent); |
579 | | - yield parent; |
| 597 | + yield this.#withFileTypes ? this.#cache.statSync(join(this.#root, parent)) : parent; |
580 | 598 | } |
581 | 599 | } |
582 | 600 | } |
@@ -592,7 +610,7 @@ class Glob { |
592 | 610 | if (nextIndex === last) { |
593 | 611 | if (!this.#results.has(entryPath)) { |
594 | 612 | this.#results.add(entryPath); |
595 | | - yield entryPath; |
| 613 | + yield this.#withFileTypes ? entry : entryPath; |
596 | 614 | } |
597 | 615 | } else { |
598 | 616 | subPatterns.add(nextIndex + 1); |
@@ -605,7 +623,7 @@ class Glob { |
605 | 623 | if (index === last) { |
606 | 624 | if (!this.#results.has(entryPath)) { |
607 | 625 | this.#results.add(entryPath); |
608 | | - yield entryPath; |
| 626 | + yield this.#withFileTypes ? entry : entryPath; |
609 | 627 | } |
610 | 628 | } else if (entry.isDirectory()) { |
611 | 629 | subPatterns.add(nextIndex); |
|