@@ -20,16 +20,16 @@ final class FileFilter
2020 private static array $ pathFilterCache = [];
2121
2222 /**
23- * Pre-compiled include regex patterns and match lengths.
23+ * Pre-compiled include regex patterns, raw patterns, and match lengths.
2424 *
25- * @var array<int, array{len: int, regex: string}>|null
25+ * @var array<int, array{pattern: string, len: int, regex: string}>|null
2626 */
2727 private static ?array $ compiledIncludes = null ;
2828
2929 /**
30- * Pre-compiled exclude regex patterns and match lengths.
30+ * Pre-compiled exclude regex patterns, raw patterns, and match lengths.
3131 *
32- * @var array<int, array{len: int, regex: string}>|null
32+ * @var array<int, array{pattern: string, len: int, regex: string}>|null
3333 */
3434 private static ?array $ compiledExcludes = null ;
3535
@@ -83,16 +83,26 @@ public static function isFileExcluded(string|false|null $fileName): bool
8383 }
8484
8585 $ longestIncludeMatch = 0 ;
86- /** @var array<int, array{len: int, regex: string}> $includes */
86+ $ isVendorPath = str_contains ($ normalizedPath , '/vendor/ ' );
87+
88+ /** @var array<int, array{pattern: string, len: int, regex: string}> $includes */
8789 $ includes = self ::$ compiledIncludes ;
8890 foreach ($ includes as $ compiled ) {
91+ $ isExplicitVendorInclude = str_starts_with ($ compiled ['pattern ' ], 'vendor/ ' );
92+ $ isWildcard = ($ compiled ['pattern ' ] === '* ' || $ compiled ['pattern ' ] === '** ' );
93+
94+ // Application include rules (like src/**, src/Core/**) never match inside vendor directories
95+ if ($ isVendorPath && ! $ isExplicitVendorInclude && ! $ isWildcard ) {
96+ continue ;
97+ }
98+
8999 if (preg_match ($ compiled ['regex ' ], $ normalizedPath ) === 1 ) {
90100 $ longestIncludeMatch = max ($ longestIncludeMatch , $ compiled ['len ' ]);
91101 }
92102 }
93103
94104 $ longestExcludeMatch = 0 ;
95- /** @var array<int, array{len: int, regex: string}> $excludes */
105+ /** @var array<int, array{pattern: string, len: int, regex: string}> $excludes */
96106 $ excludes = self ::$ compiledExcludes ;
97107 foreach ($ excludes as $ compiled ) {
98108 if (preg_match ($ compiled ['regex ' ], $ normalizedPath ) === 1 ) {
@@ -122,6 +132,7 @@ private static function compilePatterns(): void
122132 if (\is_string ($ pattern )) {
123133 $ trimmed = trim ($ pattern );
124134 self ::$ compiledIncludes [] = [
135+ 'pattern ' => $ trimmed ,
125136 'len ' => \strlen ($ trimmed ),
126137 'regex ' => self ::compileGlobToRegex ($ trimmed , $ baseDir ),
127138 ];
@@ -133,6 +144,7 @@ private static function compilePatterns(): void
133144 if (\is_string ($ pattern )) {
134145 $ trimmed = trim ($ pattern );
135146 self ::$ compiledExcludes [] = [
147+ 'pattern ' => $ trimmed ,
136148 'len ' => \strlen ($ trimmed ),
137149 'regex ' => self ::compileGlobToRegex ($ trimmed , $ baseDir ),
138150 ];
@@ -153,10 +165,10 @@ private static function compileGlobToRegex(string $glob, string $baseDir): strin
153165
154166 if ($ isAbsolute ) {
155167 $ pattern = '^ ' . $ regex . '$ ' ;
156- } elseif (str_starts_with ($ glob , '** ' )) {
157- $ pattern = '.* ' . substr ($ regex , 4 ) . '$ ' ;
168+ } elseif ($ glob === ' * ' || $ glob === ' ** ' || str_starts_with ($ glob , '** ' )) {
169+ $ pattern = '.* ' . ( $ glob === ' * ' || $ glob === ' ** ' ? '' : substr ($ regex , 4 ) ) . '$ ' ;
158170 } else {
159- $ pattern = '^ ' . preg_quote ($ baseDir . '/ ' , '# ' ) . $ regex . '$ ' ;
171+ $ pattern = '( ^ ' . preg_quote ($ baseDir . '/ ' , '# ' ) . ' |^.*\/) ' . $ regex . '$ ' ;
160172 }
161173
162174 return '# ' . $ pattern . '#i ' ;
0 commit comments