@@ -62,6 +62,7 @@ class Walker extends EventEmitter {
62
62
63
63
emit ( ev : string , data : any ) : boolean {
64
64
let ret = false ;
65
+
65
66
if ( ! ( this . sawError && ev === "error" ) ) {
66
67
if ( ev === "error" ) {
67
68
this . sawError = true ;
@@ -81,73 +82,67 @@ class Walker extends EventEmitter {
81
82
return ret ;
82
83
}
83
84
84
- start ( ) : this {
85
- this . ide
86
- . listDir ( this . path )
87
- . then ( ( entries ) => {
88
- this . onReaddir ( entries ) ;
89
- } )
90
- . catch ( ( err ) => {
91
- this . emit ( "error" , err ) ;
92
- } ) ;
93
- return this ;
85
+ async * start ( ) {
86
+ try {
87
+ const entries = await this . ide . listDir ( this . path ) ;
88
+
89
+ for await ( const result of this . onReadDir ( entries ) ) {
90
+ yield result ;
91
+ }
92
+ } catch ( err ) {
93
+ this . emit ( "error" , err ) ;
94
+ }
94
95
}
95
96
96
97
isIgnoreFile ( e : Entry ) : boolean {
97
98
const p = e [ 0 ] ;
98
99
return p !== "." && p !== ".." && this . ignoreFiles . indexOf ( p ) !== - 1 ;
99
100
}
100
101
101
- onReaddir ( entries : Entry [ ] ) : void {
102
+ async * onReadDir ( entries : Entry [ ] ) {
102
103
this . entries = entries ;
104
+
103
105
if ( entries . length === 0 ) {
104
106
if ( this . includeEmpty ) {
105
107
this . result . add ( this . path . slice ( this . root . length + 1 ) ) ;
106
108
}
107
109
this . emit ( "done" , this . result ) ;
110
+ yield this . result ;
108
111
} else {
109
112
const hasIg = this . entries . some ( ( e ) => this . isIgnoreFile ( e ) ) ;
110
113
111
114
if ( hasIg ) {
112
- this . addIgnoreFiles ( ) ;
113
- } else {
114
- this . filterEntries ( ) ;
115
+ await this . addIgnoreFiles ( ) ;
115
116
}
117
+
118
+ yield * this . filterEntries ( ) ;
116
119
}
117
120
}
118
121
119
- addIgnoreFiles ( ) : void {
122
+ async addIgnoreFiles ( ) {
120
123
const newIg = this . entries ! . filter ( ( e ) => this . isIgnoreFile ( e ) ) ;
121
-
122
- let igCount = newIg . length ;
123
- const then = ( ) => {
124
- if ( -- igCount === 0 ) {
125
- this . filterEntries ( ) ;
126
- }
127
- } ;
128
-
129
- newIg . forEach ( ( e ) => this . addIgnoreFile ( e , then ) ) ;
124
+ await Promise . all ( newIg . map ( ( e ) => this . addIgnoreFile ( e ) ) ) ;
130
125
}
131
126
132
- addIgnoreFile ( file : Entry , then : ( ) => void ) : void {
133
- const ig = path . resolve ( this . path , file [ 0 ] ) ;
134
- this . ide
135
- . readFile ( ig )
136
- . then ( ( data ) => {
137
- this . onReadIgnoreFile ( file , data , then ) ;
138
- } )
139
- . catch ( ( err ) => {
140
- this . emit ( "error" , err ) ;
141
- } ) ;
127
+ async addIgnoreFile ( fileEntry : Entry ) {
128
+ const ig = path . resolve ( this . path , fileEntry [ 0 ] ) ;
129
+
130
+ try {
131
+ const file = await this . ide . readFile ( ig ) ;
132
+ this . onReadIgnoreFile ( fileEntry , file ) ;
133
+ } catch ( err ) {
134
+ this . emit ( "error" , err ) ;
135
+ }
142
136
}
143
137
144
- onReadIgnoreFile ( file : Entry , data : string , then : ( ) => void ) : void {
138
+ onReadIgnoreFile ( file : Entry , data : string ) : void {
145
139
const mmopt = {
146
140
matchBase : true ,
147
141
dot : true ,
148
142
flipNegate : true ,
149
143
nocase : true ,
150
144
} ;
145
+
151
146
const rules = data
152
147
. split ( / \r ? \n / )
153
148
. filter ( ( line ) => ! / ^ # | ^ $ / . test ( line . trim ( ) ) )
@@ -156,8 +151,6 @@ class Walker extends EventEmitter {
156
151
} ) ;
157
152
158
153
this . ignoreRules [ file [ 0 ] ] = rules ;
159
-
160
- then ( ) ;
161
154
}
162
155
163
156
addIgnoreRules ( rules : string [ ] ) {
@@ -167,6 +160,7 @@ class Walker extends EventEmitter {
167
160
flipNegate : true ,
168
161
nocase : true ,
169
162
} ;
163
+
170
164
const minimatchRules = rules
171
165
. filter ( ( line ) => ! / ^ # | ^ $ / . test ( line . trim ( ) ) )
172
166
. map ( ( rule ) => {
@@ -176,15 +170,22 @@ class Walker extends EventEmitter {
176
170
this . ignoreRules [ ".defaultignore" ] = minimatchRules ;
177
171
}
178
172
179
- filterEntries ( ) : void {
180
- const filtered = this . entries ! . map ( ( entry ) => {
181
- const passFile = this . filterEntry ( entry [ 0 ] ) ;
182
- const passDir = this . filterEntry ( entry [ 0 ] , true ) ;
183
- return passFile || passDir ? [ entry , passFile , passDir ] : false ;
184
- } ) . filter ( ( e ) => e ) as [ Entry , boolean , boolean ] [ ] ;
173
+ async * filterEntries ( ) {
174
+ const filtered = ( await Promise . all (
175
+ this . entries ! . map ( async ( entry ) => {
176
+ const passFile = await this . filterEntry ( entry [ 0 ] ) ;
177
+ const passDir = await this . filterEntry ( entry [ 0 ] , true ) ;
178
+ return passFile || passDir ? [ entry , passFile , passDir ] : false ;
179
+ } ) ,
180
+ ) . then ( ( entries ) => entries . filter ( ( e ) => e ) ) ) as [
181
+ Entry ,
182
+ boolean ,
183
+ boolean ,
184
+ ] [ ] ;
185
185
let entryCount = filtered . length ;
186
186
if ( entryCount === 0 ) {
187
187
this . emit ( "done" , this . result ) ;
188
+ yield this . result ;
188
189
} else {
189
190
const then = ( ) => {
190
191
if ( -- entryCount === 0 ) {
@@ -195,10 +196,12 @@ class Walker extends EventEmitter {
195
196
this . emit ( "done" , this . result ) ;
196
197
}
197
198
} ;
198
- filtered . forEach ( ( filt ) => {
199
- const [ entry , file , dir ] = filt ;
200
- this . stat ( entry , file , dir , then ) ;
201
- } ) ;
199
+
200
+ for ( const [ entry , file , dir ] of filtered ) {
201
+ for await ( const statResult of this . stat ( entry , file , dir , then ) ) {
202
+ yield statResult ;
203
+ }
204
+ }
202
205
}
203
206
}
204
207
@@ -212,29 +215,36 @@ class Walker extends EventEmitter {
212
215
return entry [ 1 ] === Directory ;
213
216
}
214
217
215
- onstat ( entry : Entry , file : boolean , dir : boolean , then : ( ) => void ) : void {
218
+ async * onstat ( entry : Entry , file : boolean , dir : boolean , then : ( ) => void ) {
216
219
const abs = this . path + "/" + entry [ 0 ] ;
217
220
const isSymbolicLink = this . entryIsSymlink ( entry ) ;
218
221
if ( ! this . entryIsDirectory ( entry ) ) {
219
222
if ( file && ! this . onlyDirs ) {
220
223
this . result . add ( abs . slice ( this . root . length + 1 ) ) ;
221
224
}
222
225
then ( ) ;
226
+ yield this . result ;
223
227
} else {
224
228
if ( dir ) {
225
- this . walker (
229
+ yield * this . walker (
226
230
entry [ 0 ] ,
227
- { isSymbolicLink, exact : this . filterEntry ( entry [ 0 ] + "/" ) } ,
231
+ { isSymbolicLink, exact : await this . filterEntry ( entry [ 0 ] + "/" ) } ,
228
232
then ,
229
233
) ;
230
234
} else {
231
235
then ( ) ;
236
+ yield this . result ;
232
237
}
233
238
}
234
239
}
235
240
236
- stat ( entry : Entry , file : boolean , dir : boolean , then : ( ) => void ) : void {
237
- this . onstat ( entry , file , dir , then ) ;
241
+ async * stat (
242
+ entry : Entry ,
243
+ file : boolean ,
244
+ dir : boolean ,
245
+ then : ( ) => void ,
246
+ ) : any {
247
+ yield * this . onstat ( entry , file , dir , then ) ;
238
248
}
239
249
240
250
walkerOpt ( entry : string , opts : Partial < WalkerOptions > ) : WalkerOptions {
@@ -249,29 +259,36 @@ class Walker extends EventEmitter {
249
259
} ;
250
260
}
251
261
252
- walker ( entry : string , opts : Partial < WalkerOptions > , then : ( ) => void ) : void {
253
- new Walker ( this . walkerOpt ( entry , opts ) , this . ide ) . on ( "done" , then ) . start ( ) ;
262
+ async * walker ( entry : string , opts : Partial < WalkerOptions > , then : ( ) => void ) {
263
+ const walker = new Walker ( this . walkerOpt ( entry , opts ) , this . ide ) ;
264
+
265
+ walker . on ( "done" , then ) ;
266
+ yield * walker . start ( ) ;
254
267
}
255
268
256
- filterEntry (
269
+ async filterEntry (
257
270
entry : string ,
258
271
partial ?: boolean ,
259
272
entryBasename ?: string ,
260
- ) : boolean {
273
+ ) : Promise < boolean > {
261
274
let included = true ;
262
275
263
276
if ( this . parent && this . parent . filterEntry ) {
264
277
const parentEntry = this . basename + "/" + entry ;
265
278
const parentBasename = entryBasename || entry ;
266
- included = this . parent . filterEntry ( parentEntry , partial , parentBasename ) ;
279
+ included = await this . parent . filterEntry (
280
+ parentEntry ,
281
+ partial ,
282
+ parentBasename ,
283
+ ) ;
267
284
if ( ! included && ! this . exact ) {
268
285
return false ;
269
286
}
270
287
}
271
288
272
- this . ignoreFiles . forEach ( ( f ) => {
289
+ for ( const f of this . ignoreFiles ) {
273
290
if ( this . ignoreRules [ f ] ) {
274
- this . ignoreRules [ f ] . forEach ( ( rule ) => {
291
+ for ( const rule of this . ignoreRules [ f ] ) {
275
292
if ( rule . negate !== included ) {
276
293
const isRelativeRule =
277
294
entryBasename &&
@@ -299,29 +316,14 @@ class Walker extends EventEmitter {
299
316
included = rule . negate ;
300
317
}
301
318
}
302
- } ) ;
319
+ }
303
320
}
304
- } ) ;
321
+ }
305
322
306
323
return included ;
307
324
}
308
325
}
309
326
310
- interface WalkCallback {
311
- ( err : Error | null , result ?: string [ ] ) : void ;
312
- }
313
-
314
- async function walkDirWithCallback (
315
- opts : WalkerOptions ,
316
- ide : IDE ,
317
- callback ?: WalkCallback ,
318
- ) : Promise < string [ ] | void > {
319
- const p = new Promise < string [ ] > ( ( resolve , reject ) => {
320
- new Walker ( opts , ide ) . on ( "done" , resolve ) . on ( "error" , reject ) . start ( ) ;
321
- } ) ;
322
- return callback ? p . then ( ( res ) => callback ( null , res ) , callback ) : p ;
323
- }
324
-
325
327
const defaultOptions : WalkerOptions = {
326
328
ignoreFiles : [ ".gitignore" , ".continueignore" ] ,
327
329
onlyDirs : false ,
@@ -333,40 +335,41 @@ export async function walkDir(
333
335
ide : IDE ,
334
336
_options ?: WalkerOptions ,
335
337
) : Promise < string [ ] > {
338
+ let entries : string [ ] = [ ] ;
336
339
const options = { ...defaultOptions , ..._options } ;
337
- return new Promise ( ( resolve , reject ) => {
338
- walkDirWithCallback (
339
- {
340
- path,
341
- ignoreFiles : options . ignoreFiles ,
342
- onlyDirs : options . onlyDirs ,
343
- follow : true ,
344
- includeEmpty : false ,
345
- additionalIgnoreRules : options . additionalIgnoreRules ,
346
- } ,
347
- ide ,
348
- async ( err , result ) => {
349
- if ( err ) {
350
- reject ( err ) ;
351
- } else {
352
- const relativePaths = result || [ ] ;
353
- if ( options ?. returnRelativePaths ) {
354
- resolve ( relativePaths ) ;
355
- } else {
356
- const pathSep = await ide . pathSep ( ) ;
357
- if ( pathSep === "/" ) {
358
- resolve ( relativePaths . map ( ( p ) => path + pathSep + p ) ) ;
359
- } else {
360
- // Need to replace with windows path sep
361
- resolve (
362
- relativePaths . map (
363
- ( p ) => path + pathSep + p . split ( "/" ) . join ( pathSep ) ,
364
- ) ,
365
- ) ;
366
- }
367
- }
368
- }
369
- } ,
370
- ) ;
371
- } ) ;
340
+
341
+ const walker = new Walker (
342
+ {
343
+ path,
344
+ ignoreFiles : options . ignoreFiles ,
345
+ onlyDirs : options . onlyDirs ,
346
+ follow : true ,
347
+ includeEmpty : false ,
348
+ additionalIgnoreRules : options . additionalIgnoreRules ,
349
+ } ,
350
+ ide ,
351
+ ) ;
352
+
353
+ try {
354
+ for await ( const walkedEntries of walker . start ( ) ) {
355
+ entries = [ ... walkedEntries ] ;
356
+ }
357
+ } catch ( err ) {
358
+ console . error ( `Error walking directories: ${ err } ` ) ;
359
+ throw err ;
360
+ }
361
+
362
+ const relativePaths = entries || [ ] ;
363
+
364
+ if ( options ?. returnRelativePaths ) {
365
+ return relativePaths ;
366
+ }
367
+
368
+ const pathSep = await ide . pathSep ( ) ;
369
+
370
+ if ( pathSep === "/" ) {
371
+ return relativePaths . map ( ( p ) => path + pathSep + p ) ;
372
+ }
373
+
374
+ return relativePaths . map ( ( p ) => path + pathSep + p . split ( "/" ) . join ( pathSep ) ) ;
372
375
}
0 commit comments