Skip to content

Commit 95ffddf

Browse files
committed
add stat:true option
Fix: #353
1 parent 9d3609e commit 95ffddf

File tree

4 files changed

+58
-2
lines changed

4 files changed

+58
-2
lines changed

README.md

+21
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,21 @@ g3.stream().on('data', path => {
8282
path.readdirSync().map(e => e.name)
8383
)
8484
})
85+
86+
// if you use stat:true and withFileTypes, you can sort results
87+
// by things like modified time, filter by permission mode, etc.
88+
// All Stats fields will be avialable in that case. Slightly
89+
// slower, though.
90+
// For example:
91+
const results = await glob('**', { stat: true, withFileTypes: true })
92+
93+
const timeSortedFiles = results
94+
.sort((a, b) => a.mtimeMS - b.mtimeMS)
95+
.map(path => path.fullpath())
96+
97+
const groupReadableFiles = results
98+
.filter(path => path.mode & 0o040)
99+
.map(path => path.fullpath())
85100
```
86101

87102
**Note** Glob patterns should always use `/` as a path separator,
@@ -321,6 +336,12 @@ share the previously loaded cache.
321336
- `nodir` Do not match directories, only files. (Note: to match
322337
_only_ directories, put a `/` at the end of the pattern.)
323338

339+
- `stat` Call `lstat()` on all entries, whether required or not
340+
to determine whether it's a valid match. When used with
341+
`withFileTypes`, this means that matches will include data such
342+
as modified time, permissions, and so on. Note that this will
343+
incur a performance cost due to the added system calls.
344+
324345
- `ignore` string or string[]. A glob pattern or array of glob
325346
patterns to exclude from matches. To ignore all children within
326347
a directory, as well as the entry itself, append `/**'` to the

src/glob.ts

+11
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,15 @@ export interface GlobOptions {
218218
*/
219219
scurry?: PathScurry
220220

221+
/**
222+
* Call `lstat()` on all entries, whether required or not to determine
223+
* whether it's a valid match. When used with {@link withFileTypes}, this
224+
* means that matches will include data such as modified time, permissions,
225+
* and so on. Note that this will incur a performance cost due to the added
226+
* system calls.
227+
*/
228+
stat?: boolean
229+
221230
/**
222231
* An AbortSignal which will cancel the Glob walk when
223232
* triggered.
@@ -311,6 +320,7 @@ export class Glob<Opts extends GlobOptions> implements GlobOptions {
311320
platform: NodeJS.Platform
312321
realpath: boolean
313322
scurry: PathScurry
323+
stat: boolean
314324
signal?: AbortSignal
315325
windowsPathsNoEscape: boolean
316326
withFileTypes: FileTypes<Opts>
@@ -362,6 +372,7 @@ export class Glob<Opts extends GlobOptions> implements GlobOptions {
362372
this.matchBase = !!opts.matchBase
363373
this.maxDepth =
364374
typeof opts.maxDepth === 'number' ? opts.maxDepth : Infinity
375+
this.stat = !!opts.stat
365376

366377
if (this.withFileTypes && this.absolute !== undefined) {
367378
throw new Error('cannot set absolute and withFileTypes:true')

src/walker.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export interface GlobWalkerOpts {
3737
platform?: NodeJS.Platform
3838
realpath?: boolean
3939
root?: string
40+
stat?: boolean
4041
signal?: AbortSignal
4142
windowsPathsNoEscape?: boolean
4243
withFileTypes?: boolean
@@ -169,7 +170,7 @@ export abstract class GlobUtil<O extends GlobWalkerOpts = GlobWalkerOpts> {
169170
if (!rpc) return undefined
170171
e = rpc
171172
}
172-
const needStat = e.isUnknown()
173+
const needStat = e.isUnknown() || this.opts.stat
173174
return this.matchCheckTest(needStat ? await e.lstat() : e, ifDir)
174175
}
175176

@@ -191,7 +192,7 @@ export abstract class GlobUtil<O extends GlobWalkerOpts = GlobWalkerOpts> {
191192
if (!rpc) return undefined
192193
e = rpc
193194
}
194-
const needStat = e.isUnknown()
195+
const needStat = e.isUnknown() || this.opts.stat
195196
return this.matchCheckTest(needStat ? e.lstatSync() : e, ifDir)
196197
}
197198

test/stat.ts

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { resolve } from 'path'
2+
import t from 'tap'
3+
import { glob, globSync } from '../'
4+
5+
t.test('stat: true', async t => {
6+
const cwd = resolve(__dirname, 'fixtures')
7+
const pattern = '*'
8+
const asyncRes = await glob(pattern, {
9+
cwd,
10+
withFileTypes: true,
11+
stat: true,
12+
})
13+
const syncRes = globSync(pattern, {
14+
cwd,
15+
withFileTypes: true,
16+
stat: true,
17+
})
18+
t.type(asyncRes[0].mode, 'number')
19+
t.type(syncRes[0].mode, 'number')
20+
21+
const noStat = await glob(pattern, { cwd, withFileTypes: true })
22+
t.equal(noStat[0].mode, undefined)
23+
})

0 commit comments

Comments
 (0)