1
+ import process from 'node:process' ;
1
2
import fs from 'node:fs' ;
2
3
import nodePath from 'node:path' ;
3
- import merge2 from 'merge2 ' ;
4
+ import mergeStreams from '@sindresorhus/merge-streams ' ;
4
5
import fastGlob from 'fast-glob' ;
5
- import dirGlob from 'dir-glob' ;
6
+ import { isDirectory , isDirectorySync } from 'path-type' ;
7
+ import { toPath } from 'unicorn-magic' ;
6
8
import {
7
9
GITIGNORE_FILES_PATTERN ,
8
10
isIgnoredByIgnoreFiles ,
9
11
isIgnoredByIgnoreFilesSync ,
10
12
} from './ignore.js' ;
11
- import { FilterStream , toPath , isNegativePattern } from './utilities.js' ;
13
+ import { isNegativePattern } from './utilities.js' ;
12
14
13
15
const assertPatternsInput = patterns => {
14
16
if ( patterns . some ( pattern => typeof pattern !== 'string' ) ) {
15
17
throw new TypeError ( 'Patterns must be a string or an array of strings' ) ;
16
18
}
17
19
} ;
18
20
21
+ const normalizePathForDirectoryGlob = ( filePath , cwd ) => {
22
+ const path = isNegativePattern ( filePath ) ? filePath . slice ( 1 ) : filePath ;
23
+ return nodePath . isAbsolute ( path ) ? path : nodePath . join ( cwd , path ) ;
24
+ } ;
25
+
26
+ const getDirectoryGlob = ( { directoryPath, files, extensions} ) => {
27
+ const extensionGlob = extensions ?. length > 0 ? `.${ extensions . length > 1 ? `{${ extensions . join ( ',' ) } }` : extensions [ 0 ] } ` : '' ;
28
+ return files
29
+ ? files . map ( file => nodePath . posix . join ( directoryPath , `**/${ nodePath . extname ( file ) ? file : `${ file } ${ extensionGlob } ` } ` ) )
30
+ : [ nodePath . posix . join ( directoryPath , `**${ extensionGlob ? `/${ extensionGlob } ` : '' } ` ) ] ;
31
+ } ;
32
+
33
+ const directoryToGlob = async ( directoryPaths , {
34
+ cwd = process . cwd ( ) ,
35
+ files,
36
+ extensions,
37
+ } = { } ) => {
38
+ const globs = await Promise . all ( directoryPaths . map ( async directoryPath =>
39
+ ( await isDirectory ( normalizePathForDirectoryGlob ( directoryPath , cwd ) ) ) ? getDirectoryGlob ( { directoryPath, files, extensions} ) : directoryPath ) ,
40
+ ) ;
41
+
42
+ return globs . flat ( ) ;
43
+ } ;
44
+
45
+ const directoryToGlobSync = ( directoryPaths , {
46
+ cwd = process . cwd ( ) ,
47
+ files,
48
+ extensions,
49
+ } = { } ) => directoryPaths . flatMap ( directoryPath => isDirectorySync ( normalizePathForDirectoryGlob ( directoryPath , cwd ) ) ? getDirectoryGlob ( { directoryPath, files, extensions} ) : directoryPath ) ;
50
+
19
51
const toPatternsArray = patterns => {
20
52
patterns = [ ...new Set ( [ patterns ] . flat ( ) ) ] ;
21
53
assertPatternsInput ( patterns ) ;
22
54
return patterns ;
23
55
} ;
24
56
25
- const checkCwdOption = options => {
26
- if ( ! options . cwd ) {
57
+ const checkCwdOption = cwd => {
58
+ if ( ! cwd ) {
27
59
return ;
28
60
}
29
61
30
62
let stat ;
31
63
try {
32
- stat = fs . statSync ( options . cwd ) ;
64
+ stat = fs . statSync ( cwd ) ;
33
65
} catch {
34
66
return ;
35
67
}
@@ -42,20 +74,18 @@ const checkCwdOption = options => {
42
74
const normalizeOptions = ( options = { } ) => {
43
75
options = {
44
76
...options ,
45
- ignore : options . ignore || [ ] ,
46
- expandDirectories : options . expandDirectories === undefined
47
- ? true
48
- : options . expandDirectories ,
77
+ ignore : options . ignore ?? [ ] ,
78
+ expandDirectories : options . expandDirectories ?? true ,
49
79
cwd : toPath ( options . cwd ) ,
50
80
} ;
51
81
52
- checkCwdOption ( options ) ;
82
+ checkCwdOption ( options . cwd ) ;
53
83
54
84
return options ;
55
85
} ;
56
86
57
- const normalizeArguments = fn => async ( patterns , options ) => fn ( toPatternsArray ( patterns ) , normalizeOptions ( options ) ) ;
58
- const normalizeArgumentsSync = fn => ( patterns , options ) => fn ( toPatternsArray ( patterns ) , normalizeOptions ( options ) ) ;
87
+ const normalizeArguments = function_ => async ( patterns , options ) => function_ ( toPatternsArray ( patterns ) , normalizeOptions ( options ) ) ;
88
+ const normalizeArgumentsSync = function_ => ( patterns , options ) => function_ ( toPatternsArray ( patterns ) , normalizeOptions ( options ) ) ;
59
89
60
90
const getIgnoreFilesPatterns = options => {
61
91
const { ignoreFiles, gitignore} = options ;
@@ -86,16 +116,19 @@ const createFilterFunction = isIgnored => {
86
116
const seen = new Set ( ) ;
87
117
88
118
return fastGlobResult => {
89
- const path = fastGlobResult . path || fastGlobResult ;
90
- const pathKey = nodePath . normalize ( path ) ;
91
- const seenOrIgnored = seen . has ( pathKey ) || ( isIgnored && isIgnored ( path ) ) ;
119
+ const pathKey = nodePath . normalize ( fastGlobResult . path ?? fastGlobResult ) ;
120
+
121
+ if ( seen . has ( pathKey ) || ( isIgnored && isIgnored ( pathKey ) ) ) {
122
+ return false ;
123
+ }
124
+
92
125
seen . add ( pathKey ) ;
93
- return ! seenOrIgnored ;
126
+
127
+ return true ;
94
128
} ;
95
129
} ;
96
130
97
131
const unionFastGlobResults = ( results , filter ) => results . flat ( ) . filter ( fastGlobResult => filter ( fastGlobResult ) ) ;
98
- const unionFastGlobStreams = ( streams , filter ) => merge2 ( streams ) . pipe ( new FilterStream ( fastGlobResult => filter ( fastGlobResult ) ) ) ;
99
132
100
133
const convertNegativePatterns = ( patterns , options ) => {
101
134
const tasks = [ ] ;
@@ -133,7 +166,7 @@ const convertNegativePatterns = (patterns, options) => {
133
166
return tasks ;
134
167
} ;
135
168
136
- const getDirGlobOptions = ( options , cwd ) => ( {
169
+ const normalizeExpandDirectoriesOption = ( options , cwd ) => ( {
137
170
...( cwd ? { cwd} : { } ) ,
138
171
...( Array . isArray ( options ) ? { files : options } : options ) ,
139
172
} ) ;
@@ -147,8 +180,7 @@ const generateTasks = async (patterns, options) => {
147
180
return globTasks ;
148
181
}
149
182
150
- const patternExpandOptions = getDirGlobOptions ( expandDirectories , cwd ) ;
151
- const ignoreExpandOptions = cwd ? { cwd} : undefined ;
183
+ const directoryToGlobOptions = normalizeExpandDirectoriesOption ( expandDirectories , cwd ) ;
152
184
153
185
return Promise . all (
154
186
globTasks . map ( async task => {
@@ -158,8 +190,8 @@ const generateTasks = async (patterns, options) => {
158
190
patterns ,
159
191
options . ignore ,
160
192
] = await Promise . all ( [
161
- dirGlob ( patterns , patternExpandOptions ) ,
162
- dirGlob ( options . ignore , ignoreExpandOptions ) ,
193
+ directoryToGlob ( patterns , directoryToGlobOptions ) ,
194
+ directoryToGlob ( options . ignore , { cwd } ) ,
163
195
] ) ;
164
196
165
197
return { patterns, options} ;
@@ -169,20 +201,18 @@ const generateTasks = async (patterns, options) => {
169
201
170
202
const generateTasksSync = ( patterns , options ) => {
171
203
const globTasks = convertNegativePatterns ( patterns , options ) ;
172
-
173
204
const { cwd, expandDirectories} = options ;
174
205
175
206
if ( ! expandDirectories ) {
176
207
return globTasks ;
177
208
}
178
209
179
- const patternExpandOptions = getDirGlobOptions ( expandDirectories , cwd ) ;
180
- const ignoreExpandOptions = cwd ? { cwd} : undefined ;
210
+ const directoryToGlobSyncOptions = normalizeExpandDirectoriesOption ( expandDirectories , cwd ) ;
181
211
182
212
return globTasks . map ( task => {
183
213
let { patterns, options} = task ;
184
- patterns = dirGlob . sync ( patterns , patternExpandOptions ) ;
185
- options . ignore = dirGlob . sync ( options . ignore , ignoreExpandOptions ) ;
214
+ patterns = directoryToGlobSync ( patterns , directoryToGlobSyncOptions ) ;
215
+ options . ignore = directoryToGlobSync ( options . ignore , { cwd } ) ;
186
216
return { patterns, options} ;
187
217
} ) ;
188
218
} ;
@@ -195,25 +225,28 @@ export const globby = normalizeArguments(async (patterns, options) => {
195
225
generateTasks ( patterns , options ) ,
196
226
getFilter ( options ) ,
197
227
] ) ;
198
- const results = await Promise . all ( tasks . map ( task => fastGlob ( task . patterns , task . options ) ) ) ;
199
228
229
+ const results = await Promise . all ( tasks . map ( task => fastGlob ( task . patterns , task . options ) ) ) ;
200
230
return unionFastGlobResults ( results , filter ) ;
201
231
} ) ;
202
232
203
233
export const globbySync = normalizeArgumentsSync ( ( patterns , options ) => {
204
234
const tasks = generateTasksSync ( patterns , options ) ;
205
235
const filter = getFilterSync ( options ) ;
206
236
const results = tasks . map ( task => fastGlob . sync ( task . patterns , task . options ) ) ;
207
-
208
237
return unionFastGlobResults ( results , filter ) ;
209
238
} ) ;
210
239
211
240
export const globbyStream = normalizeArgumentsSync ( ( patterns , options ) => {
212
241
const tasks = generateTasksSync ( patterns , options ) ;
213
242
const filter = getFilterSync ( options ) ;
214
243
const streams = tasks . map ( task => fastGlob . stream ( task . patterns , task . options ) ) ;
244
+ const stream = mergeStreams ( streams ) . filter ( fastGlobResult => filter ( fastGlobResult ) ) ;
245
+
246
+ // TODO: Make it return a web stream at some point.
247
+ // return Readable.toWeb(stream);
215
248
216
- return unionFastGlobStreams ( streams , filter ) ;
249
+ return stream ;
217
250
} ) ;
218
251
219
252
export const isDynamicPattern = normalizeArgumentsSync (
0 commit comments