@@ -15,7 +15,6 @@ const fsp = fs.promises;
1515const isGlob = require ( "is-glob" ) ;
1616const hash = require ( "../cli-engine/hash" ) ;
1717const minimatch = require ( "minimatch" ) ;
18- const util = require ( "util" ) ;
1918const fswalk = require ( "@nodelib/fs.walk" ) ;
2019const globParent = require ( "glob-parent" ) ;
2120const isPathInside = require ( "is-path-inside" ) ;
@@ -24,7 +23,6 @@ const isPathInside = require("is-path-inside");
2423// Fixup references
2524//-----------------------------------------------------------------------------
2625
27- const doFsWalk = util . promisify ( fswalk . walk ) ;
2826const Minimatch = minimatch . Minimatch ;
2927const MINIMATCH_OPTIONS = { dot :true } ;
3028
@@ -280,56 +278,92 @@ async function globSearch({
280278 */
281279const unmatchedPatterns = new Set ( [ ...relativeToPatterns . keys ( ) ] ) ;
282280
283- const filePaths = ( await doFsWalk ( basePath , {
281+ const filePaths = ( await new Promise ( ( resolve , reject ) => {
284282
285- deepFilter ( entry ) {
286- const relativePath = normalizeToPosix ( path . relative ( basePath , entry . path ) ) ;
287- const matchesPattern = matchers . some ( matcher => matcher . match ( relativePath , true ) ) ;
288-
289- return matchesPattern && ! configs . isDirectoryIgnored ( entry . path ) ;
290- } ,
291- entryFilter ( entry ) {
292- const relativePath = normalizeToPosix ( path . relative ( basePath , entry . path ) ) ;
283+ let promiseRejected = false ;
293284
294- // entries may be directories or files so filter out directories
295- if ( entry . dirent . isDirectory ( ) ) {
285+ /**
286+ * Wraps a boolean-returning filter function. The wrapped function will reject the promise if an error occurs.
287+ *@param {Function } filter A filter function to wrap.
288+ *@returns {Function } A function similar to the wrapped filter that rejects the promise if an error occurs.
289+ */
290+ function wrapFilter ( filter ) {
291+ return ( ...args ) => {
292+
293+ // No need to run the filter if an error has been thrown.
294+ if ( ! promiseRejected ) {
295+ try {
296+ return filter ( ...args ) ;
297+ } catch ( error ) {
298+ promiseRejected = true ;
299+ reject ( error ) ;
300+ }
301+ }
296302return false ;
297- }
303+ } ;
304+ }
298305
299- /*
300- * Optimization: We need to track when patterns are left unmatched
301- * and so we use `unmatchedPatterns` to do that. There is a bit of
302- * complexity here because the same file can be matched by more than
303- * one pattern. So, when we start, we actually need to test every
304- * pattern against every file. Once we know there are no remaining
305- * unmatched patterns, then we can switch to just looking for the
306- * first matching pattern for improved speed.
307- */
308- const matchesPattern = unmatchedPatterns . size > 0
309- ?matchers . reduce ( ( previousValue , matcher ) => {
310- const pathMatches = matcher . match ( relativePath ) ;
306+ fswalk . walk (
307+ basePath ,
308+ {
309+ deepFilter :wrapFilter ( entry => {
310+ const relativePath = normalizeToPosix ( path . relative ( basePath , entry . path ) ) ;
311+ const matchesPattern = matchers . some ( matcher => matcher . match ( relativePath , true ) ) ;
312+
313+ return matchesPattern && ! configs . isDirectoryIgnored ( entry . path ) ;
314+ } ) ,
315+ entryFilter :wrapFilter ( entry => {
316+ const relativePath = normalizeToPosix ( path . relative ( basePath , entry . path ) ) ;
317+
318+ // entries may be directories or files so filter out directories
319+ if ( entry . dirent . isDirectory ( ) ) {
320+ return false ;
321+ }
311322
312323/*
313- * We updated the unmatched patterns set only if the path
314- * matches and the file isn't ignored. If the file is
315- * ignored, that means there wasn't a match for the
316- * pattern so it should not be removed.
317- *
318- * Performance note: isFileIgnored() aggressively caches
319- * results so there is no performance penalty for calling
320- * it twice with the same argument.
324+ * Optimization: We need to track when patterns are left unmatched
325+ * and so we use `unmatchedPatterns` to do that. There is a bit of
326+ * complexity here because the same file can be matched by more than
327+ * one pattern. So, when we start, we actually need to test every
328+ * pattern against every file. Once we know there are no remaining
329+ * unmatched patterns, then we can switch to just looking for the
330+ * first matching pattern for improved speed.
321331 */
322- if ( pathMatches && ! configs . isFileIgnored ( entry . path ) ) {
323- unmatchedPatterns . delete ( matcher . pattern ) ;
324- }
325-
326- return pathMatches || previousValue ;
327- } , false )
328- :matchers . some ( matcher => matcher . match ( relativePath ) ) ;
329-
330- return matchesPattern && ! configs . isFileIgnored ( entry . path ) ;
331- }
332-
332+ const matchesPattern = unmatchedPatterns . size > 0
333+ ?matchers . reduce ( ( previousValue , matcher ) => {
334+ const pathMatches = matcher . match ( relativePath ) ;
335+
336+ /*
337+ * We updated the unmatched patterns set only if the path
338+ * matches and the file isn't ignored. If the file is
339+ * ignored, that means there wasn't a match for the
340+ * pattern so it should not be removed.
341+ *
342+ * Performance note: isFileIgnored() aggressively caches
343+ * results so there is no performance penalty for calling
344+ * it twice with the same argument.
345+ */
346+ if ( pathMatches && ! configs . isFileIgnored ( entry . path ) ) {
347+ unmatchedPatterns . delete ( matcher . pattern ) ;
348+ }
349+
350+ return pathMatches || previousValue ;
351+ } , false )
352+ :matchers . some ( matcher => matcher . match ( relativePath ) ) ;
353+
354+ return matchesPattern && ! configs . isFileIgnored ( entry . path ) ;
355+ } )
356+ } ,
357+ ( error , entries ) => {
358+
359+ // If the promise is already rejected, calling `resolve` or `reject` will do nothing.
360+ if ( error ) {
361+ reject ( error ) ;
362+ } else {
363+ resolve ( entries ) ;
364+ }
365+ }
366+ ) ;
333367} ) ) . map ( entry => entry . path ) ;
334368
335369// now check to see if we have any unmatched patterns