@@ -1889,14 +1889,54 @@ namespace ts {
18891889 const reservedCharacterPattern = / [ ^ \w \s \/ ] / g;
18901890 const wildcardCharCodes = [ CharacterCodes . asterisk , CharacterCodes . question ] ;
18911891
1892- /**
1893- * Matches any single directory segment unless it is the last segment and a .min.js file
1894- * Breakdown:
1895- * [^./] # matches everything up to the first . character (excluding directory seperators)
1896- * (\\.(?!min\\.js$))? # matches . characters but not if they are part of the .min.js file extension
1897- */
1898- const singleAsteriskRegexFragmentFiles = "([^./]|(\\.(?!min\\.js$))?)*" ;
1899- const singleAsteriskRegexFragmentOther = "[^/]*" ;
1892+ /* @internal */
1893+ export const commonPackageFolders : ReadonlyArray < string > = [ "node_modules" , "bower_components" , "jspm_packages" ] ;
1894+
1895+ const implicitExcludePathRegexPattern = `(?!(${ commonPackageFolders . join ( "|" ) } )(/|$))` ;
1896+
1897+ interface WildcardMatcher {
1898+ singleAsteriskRegexFragment : string ;
1899+ doubleAsteriskRegexFragment : string ;
1900+ replaceWildcardCharacter : ( match : string ) => string ;
1901+ }
1902+
1903+ const filesMatcher : WildcardMatcher = {
1904+ /**
1905+ * Matches any single directory segment unless it is the last segment and a .min.js file
1906+ * Breakdown:
1907+ * [^./] # matches everything up to the first . character (excluding directory seperators)
1908+ * (\\.(?!min\\.js$))? # matches . characters but not if they are part of the .min.js file extension
1909+ */
1910+ singleAsteriskRegexFragment : "([^./]|(\\.(?!min\\.js$))?)*" ,
1911+ /**
1912+ * Regex for the ** wildcard. Matches any number of subdirectories. When used for including
1913+ * files or directories, does not match subdirectories that start with a . character
1914+ */
1915+ doubleAsteriskRegexFragment : `(/${ implicitExcludePathRegexPattern } [^/.][^/]*)*?` ,
1916+ replaceWildcardCharacter : match => replaceWildcardCharacter ( match , filesMatcher . singleAsteriskRegexFragment )
1917+ } ;
1918+
1919+ const directoriesMatcher : WildcardMatcher = {
1920+ singleAsteriskRegexFragment : "[^/]*" ,
1921+ /**
1922+ * Regex for the ** wildcard. Matches any number of subdirectories. When used for including
1923+ * files or directories, does not match subdirectories that start with a . character
1924+ */
1925+ doubleAsteriskRegexFragment : `(/${ implicitExcludePathRegexPattern } [^/.][^/]*)*?` ,
1926+ replaceWildcardCharacter : match => replaceWildcardCharacter ( match , directoriesMatcher . singleAsteriskRegexFragment )
1927+ } ;
1928+
1929+ const excludeMatcher : WildcardMatcher = {
1930+ singleAsteriskRegexFragment : "[^/]*" ,
1931+ doubleAsteriskRegexFragment : "(/.+?)?" ,
1932+ replaceWildcardCharacter : match => replaceWildcardCharacter ( match , excludeMatcher . singleAsteriskRegexFragment )
1933+ } ;
1934+
1935+ const wildcardMatchers = {
1936+ files : filesMatcher ,
1937+ directories : directoriesMatcher ,
1938+ exclude : excludeMatcher
1939+ } ;
19001940
19011941 export function getRegularExpressionForWildcard ( specs : ReadonlyArray < string > , basePath : string , usage : "files" | "directories" | "exclude" ) : string | undefined {
19021942 const patterns = getRegularExpressionsForWildcards ( specs , basePath , usage ) ;
@@ -1915,17 +1955,8 @@ namespace ts {
19151955 return undefined ;
19161956 }
19171957
1918- const replaceWildcardCharacter = usage === "files" ? replaceWildCardCharacterFiles : replaceWildCardCharacterOther ;
1919- const singleAsteriskRegexFragment = usage === "files" ? singleAsteriskRegexFragmentFiles : singleAsteriskRegexFragmentOther ;
1920-
1921- /**
1922- * Regex for the ** wildcard. Matches any number of subdirectories. When used for including
1923- * files or directories, does not match subdirectories that start with a . character
1924- */
1925- const doubleAsteriskRegexFragment = usage === "exclude" ? "(/.+?)?" : "(/[^/.][^/]*)*?" ;
1926-
19271958 return flatMap ( specs , spec =>
1928- spec && getSubPatternFromSpec ( spec , basePath , usage , singleAsteriskRegexFragment , doubleAsteriskRegexFragment , replaceWildcardCharacter ) ) ;
1959+ spec && getSubPatternFromSpec ( spec , basePath , usage , wildcardMatchers [ usage ] ) ) ;
19291960 }
19301961
19311962 /**
@@ -1936,7 +1967,7 @@ namespace ts {
19361967 return ! / [ . * ? ] / . test ( lastPathComponent ) ;
19371968 }
19381969
1939- function getSubPatternFromSpec ( spec : string , basePath : string , usage : "files" | "directories" | "exclude" , singleAsteriskRegexFragment : string , doubleAsteriskRegexFragment : string , replaceWildcardCharacter : ( match : string ) => string ) : string | undefined {
1970+ function getSubPatternFromSpec ( spec : string , basePath : string , usage : "files" | "directories" | "exclude" , { singleAsteriskRegexFragment , doubleAsteriskRegexFragment, replaceWildcardCharacter } : WildcardMatcher ) : string | undefined {
19401971 let subpattern = "" ;
19411972 let hasRecursiveDirectoryWildcard = false ;
19421973 let hasWrittenComponent = false ;
@@ -1975,20 +2006,36 @@ namespace ts {
19752006 }
19762007
19772008 if ( usage !== "exclude" ) {
2009+ let componentPattern = "" ;
19782010 // The * and ? wildcards should not match directories or files that start with . if they
19792011 // appear first in a component. Dotted directories and files can be included explicitly
19802012 // like so: **/.*/.*
19812013 if ( component . charCodeAt ( 0 ) === CharacterCodes . asterisk ) {
1982- subpattern += "([^./]" + singleAsteriskRegexFragment + ")?" ;
2014+ componentPattern += "([^./]" + singleAsteriskRegexFragment + ")?" ;
19832015 component = component . substr ( 1 ) ;
19842016 }
19852017 else if ( component . charCodeAt ( 0 ) === CharacterCodes . question ) {
1986- subpattern += "[^./]" ;
2018+ componentPattern += "[^./]" ;
19872019 component = component . substr ( 1 ) ;
19882020 }
1989- }
19902021
1991- subpattern += component . replace ( reservedCharacterPattern , replaceWildcardCharacter ) ;
2022+ componentPattern += component . replace ( reservedCharacterPattern , replaceWildcardCharacter ) ;
2023+
2024+ // Patterns should not include subfolders like node_modules unless they are
2025+ // explicitly included as part of the path.
2026+ //
2027+ // As an optimization, if the component pattern is the same as the component,
2028+ // then there definitely were no wildcard characters and we do not need to
2029+ // add the exclusion pattern.
2030+ if ( componentPattern !== component ) {
2031+ subpattern += implicitExcludePathRegexPattern ;
2032+ }
2033+
2034+ subpattern += componentPattern ;
2035+ }
2036+ else {
2037+ subpattern += component . replace ( reservedCharacterPattern , replaceWildcardCharacter ) ;
2038+ }
19922039 }
19932040
19942041 hasWrittenComponent = true ;
@@ -2002,14 +2049,6 @@ namespace ts {
20022049 return subpattern ;
20032050 }
20042051
2005- function replaceWildCardCharacterFiles ( match : string ) {
2006- return replaceWildcardCharacter ( match , singleAsteriskRegexFragmentFiles ) ;
2007- }
2008-
2009- function replaceWildCardCharacterOther ( match : string ) {
2010- return replaceWildcardCharacter ( match , singleAsteriskRegexFragmentOther ) ;
2011- }
2012-
20132052 function replaceWildcardCharacter ( match : string , singleAsteriskRegexFragment : string ) {
20142053 return match === "*" ? singleAsteriskRegexFragment : match === "?" ? "[^/]" : "\\" + match ;
20152054 }
0 commit comments