@@ -5,12 +5,14 @@ import isBinaryPath from 'is-binary-path';
55import micromatch from 'micromatch' ;
66import readdir , { type Dirent } from 'tiny-readdir' ;
77
8- const alwaysIgnoredNames = new Set ( [ '.git' , '.sl' , '.svn' , '.hg' , '.jj' , 'node_modules' ] ) ;
8+ const defaultIgnoredDirNames = new Set ( [ '.git' , '.sl' , '.svn' , '.hg' , '.jj' , 'node_modules' ] ) ;
99
1010interface DiscoverFmtPathsOptions {
1111 /** Absolute directory used to resolve input paths. */
1212 cwd : string ;
1313 patterns ?: string [ ] ;
14+ /** Whether files inside node_modules may be discovered. */
15+ withNodeModules ?: boolean ;
1416 /** Returns whether a scanned directory can be pruned before traversal. */
1517 isDirectoryIgnored ?: ( directoryPath : string ) => boolean ;
1618}
@@ -47,11 +49,15 @@ const getDirentParentPath = (dirent: Dirent): string =>
4749const getDirentPath = ( dirent : Dirent , parentPath : string ) : string =>
4850 `${ parentPath } ${ parentPath === path . sep ? '' : path . sep } ${ dirent . name } ` ;
4951
50- const hasAlwaysIgnoredSegment = ( cwd : string , filePath : string ) : boolean =>
52+ const hasBuiltInIgnoredSegment = (
53+ cwd : string ,
54+ filePath : string ,
55+ ignoredDirNames : ReadonlySet < string > ,
56+ ) : boolean =>
5157 path
5258 . relative ( cwd , filePath )
5359 . split ( path . sep )
54- . some ( ( segment ) => alwaysIgnoredNames . has ( segment ) ) ;
60+ . some ( ( segment ) => ignoredDirNames . has ( segment ) ) ;
5561
5662const findGitRoot = async ( cwd : string ) : Promise < string > => {
5763 let directoryPath = cwd ;
@@ -202,6 +208,7 @@ class GitIgnoreMatcher {
202208
203209const createTraversalOptions = (
204210 gitIgnore : GitIgnoreMatcher ,
211+ ignoredDirNames : ReadonlySet < string > ,
205212 isIncluded ?: ( filePath : string ) => boolean ,
206213 isDirectoryIgnored ?: ( directoryPath : string ) => boolean ,
207214) => {
@@ -212,7 +219,7 @@ const createTraversalOptions = (
212219 followSymlinks : false ,
213220 ignore : ( targetPath : string ) => {
214221 const isDirectory = directories . delete ( targetPath ) ;
215- if ( alwaysIgnoredNames . has ( path . basename ( targetPath ) ) ) {
222+ if ( ignoredDirNames . has ( path . basename ( targetPath ) ) ) {
216223 return true ;
217224 }
218225
@@ -265,15 +272,19 @@ type ClassifiedPatterns = {
265272 negativeGlobs : string [ ] ;
266273} ;
267274
268- const classifyPatterns = async ( cwd : string , patterns : string [ ] ) : Promise < ClassifiedPatterns > => {
275+ const classifyPatterns = async (
276+ cwd : string ,
277+ patterns : string [ ] ,
278+ ignoredDirNames : ReadonlySet < string > ,
279+ ) : Promise < ClassifiedPatterns > => {
269280 const entries = await Promise . all (
270281 patterns . map ( async ( pattern ) : Promise < PatternEntry | undefined > => {
271282 if ( pattern . startsWith ( '!' ) ) {
272283 return { kind : 'negative-glob' , value : normalizeGlob ( cwd , pattern . slice ( 1 ) ) } ;
273284 }
274285
275286 const filePath = path . resolve ( cwd , pattern ) ;
276- if ( hasAlwaysIgnoredSegment ( cwd , filePath ) ) {
287+ if ( hasBuiltInIgnoredSegment ( cwd , filePath , ignoredDirNames ) ) {
277288 return ;
278289 }
279290
@@ -346,15 +357,24 @@ const getTraversalRoots = (cwd: string, directories: string[], globs: string[]):
346357const discoverFmtPaths = async ( {
347358 cwd,
348359 patterns : inputPatterns ,
360+ withNodeModules = false ,
349361 isDirectoryIgnored,
350362} : DiscoverFmtPathsOptions ) : Promise < string [ ] > => {
351363 const patterns = inputPatterns ?. length ? inputPatterns : [ '.' ] ;
364+ const ignoredDirNames = withNodeModules
365+ ? new Set ( defaultIgnoredDirNames )
366+ : defaultIgnoredDirNames ;
367+
368+ if ( withNodeModules ) {
369+ ignoredDirNames . delete ( 'node_modules' ) ;
370+ }
371+
352372 const {
353373 files : explicitFiles ,
354374 directories,
355375 globs,
356376 negativeGlobs,
357- } = await classifyPatterns ( cwd , patterns ) ;
377+ } = await classifyPatterns ( cwd , patterns , ignoredDirNames ) ;
358378 const directoryRoots = getOutermostPaths ( directories ) ;
359379 const globMatchers = globs . map ( ( pattern ) => micromatch . matcher ( pattern , { dot : true } ) ) ;
360380 const candidates = new Set ( explicitFiles ) ;
@@ -389,7 +409,10 @@ const discoverFmtPaths = async ({
389409 } ;
390410
391411 return (
392- await readdir ( rootPath , createTraversalOptions ( gitIgnore , isIncluded , isDirectoryIgnored ) )
412+ await readdir (
413+ rootPath ,
414+ createTraversalOptions ( gitIgnore , ignoredDirNames , isIncluded , isDirectoryIgnored ) ,
415+ )
393416 ) . files ;
394417 } ) ,
395418 ) ;
0 commit comments