@@ -10,7 +10,9 @@ import { text as stream2text } from "node:stream/consumers";
1010import url from "node:url" ;
1111import resolveTimeout from "promise-resolve-timeout" ;
1212import { exit } from "specialist" ;
13- import readdir from "tiny-readdir-glob" ;
13+ import readdir from "tiny-readdir" ;
14+ import readdirGlob from "tiny-readdir-glob" ;
15+ import zeptomatch from "zeptomatch" ;
1416import zeptomatchEscape from "zeptomatch-escape" ;
1517import zeptomatchIsStatic from "zeptomatch-is-static" ;
1618import type { ContextOptions , FormatOptions , FunctionMaybe , Key , LogLevel , Options , PrettierConfigWithOverrides , PrettierPlugin } from "./types.js" ;
@@ -54,6 +56,19 @@ function getCachePath(rootPath: string): string {
5456 return cachePath ;
5557}
5658
59+ function getDirectoryPaths ( rootPath : string , withNodeModules : boolean ) {
60+ const ignoreGlob = `**/{.git,.sl,.svn,.hg,.DS_Store,Thumbs.db${ withNodeModules ? "" : ",node_modules" } }` ;
61+ const ignoreRe = zeptomatch . compile ( ignoreGlob ) ;
62+ const ignore = ( targetPath : string ) : boolean => {
63+ return ignoreRe . test ( path . relative ( rootPath , targetPath ) ) ;
64+ } ;
65+
66+ return readdir ( rootPath , {
67+ followSymlinks : false ,
68+ ignore,
69+ } ) ;
70+ }
71+
5772function getExpandedFoldersPaths ( foldersPaths : string [ ] , untilPath : string = "/" ) : [ string [ ] , string [ ] ] {
5873 const knownPaths = new Set ( foldersPaths ) ;
5974 const expandedPaths = new Set < string > ( ) ;
@@ -88,7 +103,7 @@ async function getFoldersChildrenPaths(foldersPaths: string[]): Promise<string[]
88103}
89104
90105function getGlobPaths ( rootPath : string , globs : string [ ] , withNodeModules : boolean ) {
91- return readdir ( globs , {
106+ return readdirGlob ( globs , {
92107 cwd : rootPath ,
93108 followSymlinks : false ,
94109 ignore : `**/{.git,.sl,.svn,.hg,.DS_Store,Thumbs.db${ withNodeModules ? "" : ",node_modules" } }` ,
@@ -179,6 +194,14 @@ function getProjectPath(rootPath: string): string {
179194 }
180195}
181196
197+ function getStats ( targetPath : string ) : fs . Stats | undefined {
198+ try {
199+ return fs . statSync ( targetPath ) ;
200+ } catch {
201+ return ;
202+ }
203+ }
204+
182205const getStdin = once ( async ( ) : Promise < string | undefined > => {
183206 // Without a TTY, the process is likely, but not certainly, being piped
184207 if ( ! process . stdin . isTTY ) {
@@ -196,28 +219,39 @@ async function getTargetsPaths(
196219 const targetFiles : string [ ] = [ ] ;
197220 const targetFilesNames : string [ ] = [ ] ;
198221 const targetFilesNamesToPaths : Record < string , string [ ] > = { } ;
222+ const targetDirectories : string [ ] = [ ] ;
199223 const targetGlobs : string [ ] = [ ] ;
200224
201225 for ( const glob of globs ) {
202226 const filePath = path . resolve ( rootPath , glob ) ;
203- if ( isFile ( filePath ) ) {
227+ const fileStats = getStats ( filePath ) ;
228+ if ( fileStats ?. isFile ( ) ) {
204229 const fileName = path . basename ( filePath ) ;
205230 targetFiles . push ( filePath ) ;
206231 targetFilesNames . push ( fileName ) ;
207232 targetFilesNamesToPaths . propertyIsEnumerable ( fileName ) || ( targetFilesNamesToPaths [ fileName ] = [ ] ) ;
208233 targetFilesNamesToPaths [ fileName ] . push ( filePath ) ;
234+ } else if ( fileStats ?. isDirectory ( ) ) {
235+ targetDirectories . push ( filePath ) ;
209236 } else {
210237 targetGlobs . push ( glob ) ;
211238 }
212239 }
213240
214- const result = await getGlobPaths ( rootPath , targetGlobs , withNodeModules ) ;
215- const resultFiles = result . files ;
216- const resultFilesFoundNames = [ ...result . filesFoundNames ] ;
241+ const globResult = await getGlobPaths ( rootPath , targetGlobs , withNodeModules ) ;
242+ const globResultFiles = globResult . files ;
243+ const globResultFilesFoundNames = [ ...globResult . filesFoundNames ] ;
217244
218- const filesPaths = [ ...without ( targetFiles , resultFiles ) , ...resultFiles ] ;
219- const filesNames = [ ...without ( targetFilesNames , resultFilesFoundNames ) , ...resultFilesFoundNames ] ;
220- const filesNamesToPaths = result . filesFoundNamesToPaths ;
245+ const directoriesResults = await Promise . all ( targetDirectories . map ( ( targetPath ) => getDirectoryPaths ( targetPath , withNodeModules ) ) ) ;
246+ const directoriesResultsFiles = directoriesResults . map ( ( result ) => result . files ) ;
247+ const directoriesResultsFilesFoundNames = directoriesResults . map ( ( result ) => [ ...result . filesNames ] ) ;
248+
249+ const foundFiles = uniqChunks ( globResultFiles , ...directoriesResultsFiles ) ;
250+ const foundFilesNames = uniqChunks ( globResultFilesFoundNames , ...directoriesResultsFilesFoundNames ) ;
251+
252+ const filesPaths = [ ...without ( targetFiles , foundFiles ) , ...foundFiles ] ;
253+ const filesNames = [ ...without ( targetFilesNames , foundFilesNames ) , ...foundFilesNames ] ;
254+ const filesNamesToPaths = globResult . filesFoundNamesToPaths ;
221255
222256 for ( const fileName in targetFilesNamesToPaths ) {
223257 const prev = filesNamesToPaths [ fileName ] ;
@@ -226,8 +260,8 @@ async function getTargetsPaths(
226260 }
227261
228262 const filesExplicitPaths = targetFiles ;
229- const filesFoundPaths = result . filesFound ;
230- const foldersFoundPaths = [ rootPath , ...result . directoriesFound ] ;
263+ const filesFoundPaths = globResult . filesFound ;
264+ const foldersFoundPaths = [ rootPath , ...globResult . directoriesFound ] ;
231265 return [ filesPaths , filesNames , filesNamesToPaths , filesExplicitPaths , filesFoundPaths , foldersFoundPaths ] ;
232266}
233267
@@ -239,15 +273,6 @@ function isBoolean(value: unknown): value is boolean {
239273 return typeof value === "boolean" ;
240274}
241275
242- function isFile ( targetPath : string ) : boolean {
243- try {
244- const stats = fs . statSync ( targetPath ) ;
245- return stats . isFile ( ) ;
246- } catch {
247- return false ;
248- }
249- }
250-
251276function isFunction ( value : unknown ) : value is Function {
252277 return typeof value === "function" ;
253278}
@@ -650,6 +675,17 @@ function uniq<T>(values: T[]): T[] {
650675 return Array . from ( new Set ( values ) ) ;
651676}
652677
678+ function uniqChunks < T > ( ...chunks : T [ ] [ ] ) : T [ ] {
679+ const chunksNonEmpty = chunks . filter ( ( chunk ) => chunk . length ) ;
680+ if ( chunksNonEmpty . length === 0 ) {
681+ return [ ] ;
682+ } else if ( chunksNonEmpty . length === 1 ) {
683+ return chunksNonEmpty [ 0 ] ;
684+ } else {
685+ return uniq ( chunks . flat ( ) ) ;
686+ }
687+ }
688+
653689function without < T > ( values : T [ ] , exclude : T [ ] ) : T [ ] {
654690 if ( ! values . length ) return values ;
655691 if ( ! exclude . length ) return values ;
@@ -691,6 +727,7 @@ export {
691727 getPluginsPaths ,
692728 getPluginsVersions ,
693729 getProjectPath ,
730+ getStats ,
694731 getStdin ,
695732 getTargetsPaths ,
696733 isArray ,
@@ -720,6 +757,7 @@ export {
720757 someOf ,
721758 trimFinalNewline ,
722759 uniq ,
760+ uniqChunks ,
723761 without ,
724762 zipObjectUnless ,
725763} ;
0 commit comments