-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Add upper limit for the program size to prevent tsserver from crashing #7486
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 10 commits
4d3cff1
b155fa8
a3aa000
a6a466c
d4eb3b8
a839d93
225e3b4
c8e0b00
d7e1d34
cb46f16
74e3d7b
1b76294
5c9ce9e
94d44ad
d387050
4383f1a
e41b10b
3354436
550d912
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -331,6 +331,10 @@ namespace ts { | |
name: "noImplicitUseStrict", | ||
type: "boolean", | ||
description: Diagnostics.Do_not_emit_use_strict_directives_in_module_output | ||
}, | ||
{ | ||
name: "disableSizeLimit", | ||
type: "boolean" | ||
} | ||
]; | ||
|
||
|
@@ -622,7 +626,7 @@ namespace ts { | |
} | ||
else { | ||
// by default exclude node_modules, and any specificied output directory | ||
exclude = ["node_modules"]; | ||
exclude = ["node_modules", "bower_components"]; | ||
const outDir = json["compilerOptions"] && json["compilerOptions"]["outDir"]; | ||
if (outDir) { | ||
exclude.push(outDir); | ||
|
@@ -633,10 +637,22 @@ namespace ts { | |
const supportedExtensions = getSupportedExtensions(options); | ||
Debug.assert(indexOf(supportedExtensions, ".ts") < indexOf(supportedExtensions, ".d.ts"), "Changed priority of extensions to pick"); | ||
|
||
const potentialFiles: string[] = []; | ||
if (host.readDirectoryWithMultipleExtensions) { | ||
addRange(potentialFiles, host.readDirectoryWithMultipleExtensions(basePath, supportedExtensions, exclude)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. possibly split this in a separate PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure. |
||
} | ||
else { | ||
for (const extension of supportedExtensions) { | ||
addRange(potentialFiles, host.readDirectory(basePath, extension, exclude)); | ||
} | ||
} | ||
// Get files of supported extensions in their order of resolution | ||
for (const extension of supportedExtensions) { | ||
const filesInDirWithExtension = host.readDirectory(basePath, extension, exclude); | ||
for (const fileName of filesInDirWithExtension) { | ||
for (const fileName of potentialFiles) { | ||
if (!fileExtensionIs(fileName, extension)) { | ||
continue; | ||
} | ||
|
||
// .ts extension would read the .d.ts extension files too but since .d.ts is lower priority extension, | ||
// lets pick them when its turn comes up | ||
if (extension === ".ts" && fileExtensionIs(fileName, ".d.ts")) { | ||
|
@@ -657,8 +673,10 @@ namespace ts { | |
} | ||
} | ||
|
||
filesSeen[fileName] = true; | ||
fileNames.push(fileName); | ||
if (!filesSeen[fileName]) { | ||
filesSeen[fileName] = true; | ||
fileNames.push(fileName); | ||
} | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ namespace ts { | |
/* @internal */ export let emitTime = 0; | ||
/* @internal */ export let ioReadTime = 0; | ||
/* @internal */ export let ioWriteTime = 0; | ||
/* @internal */ export const maxProgramSizeForNonTsFiles = 20 * 1024 * 1024; | ||
|
||
/** The version of the TypeScript compiler release */ | ||
|
||
|
@@ -696,6 +697,8 @@ namespace ts { | |
let diagnosticsProducingTypeChecker: TypeChecker; | ||
let noDiagnosticsTypeChecker: TypeChecker; | ||
let classifiableNames: Map<string>; | ||
let programSizeLimitExceeded = false; | ||
let programSizeForNonTsFiles = 0; | ||
|
||
let skipDefaultLib = options.noLib; | ||
const supportedExtensions = getSupportedExtensions(options); | ||
|
@@ -742,7 +745,8 @@ namespace ts { | |
(oldOptions.target !== options.target) || | ||
(oldOptions.noLib !== options.noLib) || | ||
(oldOptions.jsx !== options.jsx) || | ||
(oldOptions.allowJs !== options.allowJs)) { | ||
(oldOptions.allowJs !== options.allowJs) || | ||
(oldOptions.disableSizeLimit !== options.disableSizeLimit)) { | ||
oldProgram = undefined; | ||
} | ||
} | ||
|
@@ -790,6 +794,11 @@ namespace ts { | |
|
||
return program; | ||
|
||
function exceedProgramSizeLimit() { | ||
return !options.disableSizeLimit && programSizeLimitExceeded; | ||
} | ||
|
||
|
||
function getCommonSourceDirectory() { | ||
if (typeof commonSourceDirectory === "undefined") { | ||
if (options.rootDir && checkSourceFilesBelongToPath(files, options.rootDir)) { | ||
|
@@ -1415,7 +1424,7 @@ namespace ts { | |
} | ||
} | ||
|
||
if (diagnostic) { | ||
if (diagnostic && !exceedProgramSizeLimit()) { | ||
if (refFile !== undefined && refEnd !== undefined && refPos !== undefined) { | ||
fileProcessingDiagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...diagnosticArgument)); | ||
} | ||
|
@@ -1452,6 +1461,11 @@ namespace ts { | |
return file; | ||
} | ||
|
||
const isNonTsFile = !hasTypeScriptFileExtension(fileName); | ||
if (isNonTsFile && exceedProgramSizeLimit()) { | ||
return undefined; | ||
} | ||
|
||
// We haven't looked for this file, do so now and cache result | ||
const file = host.getSourceFile(fileName, options.target, hostErrorMessage => { | ||
if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) { | ||
|
@@ -1463,6 +1477,25 @@ namespace ts { | |
} | ||
}); | ||
|
||
if (!options.disableSizeLimit && file && file.text && !hasTypeScriptFileExtension(file.fileName)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. looks like we do not need this in the program building, since we are doing it in the server. |
||
programSizeForNonTsFiles += file.text.length; | ||
if (programSizeForNonTsFiles > maxProgramSizeForNonTsFiles) { | ||
// If the program size limit was reached when processing a file, this file is | ||
// likely in the problematic folder than contains too many files. | ||
// Normally the folder is one level down from the commonSourceDirectory, for example, | ||
// if the commonSourceDirectory is "/src/", and the last processed path was "/src/node_modules/a/b.js", | ||
// we should show in the error message "/src/node_modules/". | ||
const commonSourceDirectory = getCommonSourceDirectory(); | ||
let rootLevelDirectory = path.substring(0, Math.max(commonSourceDirectory.length, path.indexOf(directorySeparator, commonSourceDirectory.length))); | ||
if (rootLevelDirectory[rootLevelDirectory.length - 1] !== directorySeparator) { | ||
rootLevelDirectory += directorySeparator; | ||
} | ||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Too_many_JavaScript_files_in_the_project_Consider_specifying_the_exclude_setting_in_project_configuration_to_limit_included_source_folders_The_likely_folder_to_exclude_is_0_To_disable_the_project_size_limit_set_the_disableSizeLimit_compiler_option_to_true, rootLevelDirectory)); | ||
programSizeLimitExceeded = true; | ||
return undefined; | ||
} | ||
} | ||
|
||
filesByName.set(path, file); | ||
if (file) { | ||
file.wasReferenced = file.wasReferenced || isReference; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We were re-reading the directory for every file extension in the list? Crazy!! Good find 😄