Skip to content

Commit 5a64556

Browse files
authored
Merge pull request #17604 from Microsoft/implicitlyExcludeNodeModules
exclude node_modules unless explicitly included
2 parents 31230b9 + 813aaf4 commit 5a64556

File tree

8 files changed

+202
-108
lines changed

8 files changed

+202
-108
lines changed

src/compiler/commandLineParser.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,14 +1446,10 @@ namespace ts {
14461446
}
14471447
}
14481448
else {
1449-
// If no includes were specified, exclude common package folders and the outDir
1450-
const specs = includeSpecs ? [] : ["node_modules", "bower_components", "jspm_packages"];
1451-
14521449
const outDir = raw["compilerOptions"] && raw["compilerOptions"]["outDir"];
14531450
if (outDir) {
1454-
specs.push(outDir);
1451+
excludeSpecs = [outDir];
14551452
}
1456-
excludeSpecs = specs;
14571453
}
14581454

14591455
if (fileNames === undefined && includeSpecs === undefined) {

src/compiler/core.ts

Lines changed: 70 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1875,14 +1875,54 @@ namespace ts {
18751875
const reservedCharacterPattern = /[^\w\s\/]/g;
18761876
const wildcardCharCodes = [CharacterCodes.asterisk, CharacterCodes.question];
18771877

1878-
/**
1879-
* Matches any single directory segment unless it is the last segment and a .min.js file
1880-
* Breakdown:
1881-
* [^./] # matches everything up to the first . character (excluding directory seperators)
1882-
* (\\.(?!min\\.js$))? # matches . characters but not if they are part of the .min.js file extension
1883-
*/
1884-
const singleAsteriskRegexFragmentFiles = "([^./]|(\\.(?!min\\.js$))?)*";
1885-
const singleAsteriskRegexFragmentOther = "[^/]*";
1878+
/* @internal */
1879+
export const commonPackageFolders: ReadonlyArray<string> = ["node_modules", "bower_components", "jspm_packages"];
1880+
1881+
const implicitExcludePathRegexPattern = `(?!(${commonPackageFolders.join("|")})(/|$))`;
1882+
1883+
interface WildcardMatcher {
1884+
singleAsteriskRegexFragment: string;
1885+
doubleAsteriskRegexFragment: string;
1886+
replaceWildcardCharacter: (match: string) => string;
1887+
}
1888+
1889+
const filesMatcher: WildcardMatcher = {
1890+
/**
1891+
* Matches any single directory segment unless it is the last segment and a .min.js file
1892+
* Breakdown:
1893+
* [^./] # matches everything up to the first . character (excluding directory seperators)
1894+
* (\\.(?!min\\.js$))? # matches . characters but not if they are part of the .min.js file extension
1895+
*/
1896+
singleAsteriskRegexFragment: "([^./]|(\\.(?!min\\.js$))?)*",
1897+
/**
1898+
* Regex for the ** wildcard. Matches any number of subdirectories. When used for including
1899+
* files or directories, does not match subdirectories that start with a . character
1900+
*/
1901+
doubleAsteriskRegexFragment: `(/${implicitExcludePathRegexPattern}[^/.][^/]*)*?`,
1902+
replaceWildcardCharacter: match => replaceWildcardCharacter(match, filesMatcher.singleAsteriskRegexFragment)
1903+
};
1904+
1905+
const directoriesMatcher: WildcardMatcher = {
1906+
singleAsteriskRegexFragment: "[^/]*",
1907+
/**
1908+
* Regex for the ** wildcard. Matches any number of subdirectories. When used for including
1909+
* files or directories, does not match subdirectories that start with a . character
1910+
*/
1911+
doubleAsteriskRegexFragment: `(/${implicitExcludePathRegexPattern}[^/.][^/]*)*?`,
1912+
replaceWildcardCharacter: match => replaceWildcardCharacter(match, directoriesMatcher.singleAsteriskRegexFragment)
1913+
};
1914+
1915+
const excludeMatcher: WildcardMatcher = {
1916+
singleAsteriskRegexFragment: "[^/]*",
1917+
doubleAsteriskRegexFragment: "(/.+?)?",
1918+
replaceWildcardCharacter: match => replaceWildcardCharacter(match, excludeMatcher.singleAsteriskRegexFragment)
1919+
};
1920+
1921+
const wildcardMatchers = {
1922+
files: filesMatcher,
1923+
directories: directoriesMatcher,
1924+
exclude: excludeMatcher
1925+
};
18861926

18871927
export function getRegularExpressionForWildcard(specs: ReadonlyArray<string>, basePath: string, usage: "files" | "directories" | "exclude"): string | undefined {
18881928
const patterns = getRegularExpressionsForWildcards(specs, basePath, usage);
@@ -1901,17 +1941,8 @@ namespace ts {
19011941
return undefined;
19021942
}
19031943

1904-
const replaceWildcardCharacter = usage === "files" ? replaceWildCardCharacterFiles : replaceWildCardCharacterOther;
1905-
const singleAsteriskRegexFragment = usage === "files" ? singleAsteriskRegexFragmentFiles : singleAsteriskRegexFragmentOther;
1906-
1907-
/**
1908-
* Regex for the ** wildcard. Matches any number of subdirectories. When used for including
1909-
* files or directories, does not match subdirectories that start with a . character
1910-
*/
1911-
const doubleAsteriskRegexFragment = usage === "exclude" ? "(/.+?)?" : "(/[^/.][^/]*)*?";
1912-
19131944
return flatMap(specs, spec =>
1914-
spec && getSubPatternFromSpec(spec, basePath, usage, singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter));
1945+
spec && getSubPatternFromSpec(spec, basePath, usage, wildcardMatchers[usage]));
19151946
}
19161947

19171948
/**
@@ -1922,7 +1953,7 @@ namespace ts {
19221953
return !/[.*?]/.test(lastPathComponent);
19231954
}
19241955

1925-
function getSubPatternFromSpec(spec: string, basePath: string, usage: "files" | "directories" | "exclude", singleAsteriskRegexFragment: string, doubleAsteriskRegexFragment: string, replaceWildcardCharacter: (match: string) => string): string | undefined {
1956+
function getSubPatternFromSpec(spec: string, basePath: string, usage: "files" | "directories" | "exclude", { singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter }: WildcardMatcher): string | undefined {
19261957
let subpattern = "";
19271958
let hasRecursiveDirectoryWildcard = false;
19281959
let hasWrittenComponent = false;
@@ -1961,20 +1992,36 @@ namespace ts {
19611992
}
19621993

19631994
if (usage !== "exclude") {
1995+
let componentPattern = "";
19641996
// The * and ? wildcards should not match directories or files that start with . if they
19651997
// appear first in a component. Dotted directories and files can be included explicitly
19661998
// like so: **/.*/.*
19671999
if (component.charCodeAt(0) === CharacterCodes.asterisk) {
1968-
subpattern += "([^./]" + singleAsteriskRegexFragment + ")?";
2000+
componentPattern += "([^./]" + singleAsteriskRegexFragment + ")?";
19692001
component = component.substr(1);
19702002
}
19712003
else if (component.charCodeAt(0) === CharacterCodes.question) {
1972-
subpattern += "[^./]";
2004+
componentPattern += "[^./]";
19732005
component = component.substr(1);
19742006
}
1975-
}
19762007

1977-
subpattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter);
2008+
componentPattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter);
2009+
2010+
// Patterns should not include subfolders like node_modules unless they are
2011+
// explicitly included as part of the path.
2012+
//
2013+
// As an optimization, if the component pattern is the same as the component,
2014+
// then there definitely were no wildcard characters and we do not need to
2015+
// add the exclusion pattern.
2016+
if (componentPattern !== component) {
2017+
subpattern += implicitExcludePathRegexPattern;
2018+
}
2019+
2020+
subpattern += componentPattern;
2021+
}
2022+
else {
2023+
subpattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter);
2024+
}
19782025
}
19792026

19802027
hasWrittenComponent = true;
@@ -1988,14 +2035,6 @@ namespace ts {
19882035
return subpattern;
19892036
}
19902037

1991-
function replaceWildCardCharacterFiles(match: string) {
1992-
return replaceWildcardCharacter(match, singleAsteriskRegexFragmentFiles);
1993-
}
1994-
1995-
function replaceWildCardCharacterOther(match: string) {
1996-
return replaceWildcardCharacter(match, singleAsteriskRegexFragmentOther);
1997-
}
1998-
19992038
function replaceWildcardCharacter(match: string, singleAsteriskRegexFragment: string) {
20002039
return match === "*" ? singleAsteriskRegexFragment : match === "?" ? "[^/]" : "\\" + match;
20012040
}

src/harness/harness.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ namespace Utils {
420420

421421
const maxHarnessFrames = 1;
422422

423-
export function filterStack(error: Error, stackTraceLimit: number = Infinity) {
423+
export function filterStack(error: Error, stackTraceLimit = Infinity) {
424424
const stack = <string>(<any>error).stack;
425425
if (stack) {
426426
const lines = stack.split(/\r\n?|\n/g);

0 commit comments

Comments
 (0)