-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Port #7486 to release 1.8 #7513
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 9 commits
3b55558
708fb97
35b972e
4aba58c
6ed14c2
cfa83e9
5e74ebd
4d0f488
f13a9c7
7547f2f
23184f5
760c163
b0fc9e0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -348,6 +348,7 @@ namespace ts { | |
| let diagnosticsProducingTypeChecker: TypeChecker; | ||
| let noDiagnosticsTypeChecker: TypeChecker; | ||
| let classifiableNames: Map<string>; | ||
| let programSizeForNonTsFiles = 0; | ||
|
|
||
| let skipDefaultLib = options.noLib; | ||
| const supportedExtensions = getSupportedExtensions(options); | ||
|
|
@@ -394,7 +395,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; | ||
| } | ||
| } | ||
|
|
@@ -1031,8 +1033,10 @@ namespace ts { | |
| diagnosticArgument = [fileName, "'" + supportedExtensions.join("', '") + "'"]; | ||
| } | ||
| else if (!findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd)) { | ||
| diagnostic = Diagnostics.File_0_not_found; | ||
| diagnosticArgument = [fileName]; | ||
| if (hasTypeScriptFileExtension(fileName) || options.disableSizeLimit || programSizeForNonTsFiles !== -1) { | ||
| diagnostic = Diagnostics.File_0_not_found; | ||
| diagnosticArgument = [fileName]; | ||
| } | ||
| } | ||
| else if (refFile && host.getCanonicalFileName(fileName) === host.getCanonicalFileName(refFile.fileName)) { | ||
| diagnostic = Diagnostics.A_file_cannot_have_a_reference_to_itself; | ||
|
|
@@ -1043,13 +1047,17 @@ namespace ts { | |
| const nonTsFile: SourceFile = options.allowNonTsExtensions && findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd); | ||
| if (!nonTsFile) { | ||
| if (options.allowNonTsExtensions) { | ||
| diagnostic = Diagnostics.File_0_not_found; | ||
| diagnosticArgument = [fileName]; | ||
| if (options.disableSizeLimit || programSizeForNonTsFiles !== -1) { | ||
| diagnostic = Diagnostics.File_0_not_found; | ||
| diagnosticArgument = [fileName]; | ||
| } | ||
| } | ||
| else if (!forEach(supportedExtensions, extension => findSourceFile(fileName + extension, toPath(fileName + extension, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd))) { | ||
| diagnostic = Diagnostics.File_0_not_found; | ||
| fileName += ".ts"; | ||
| diagnosticArgument = [fileName]; | ||
| if (options.disableSizeLimit || programSizeForNonTsFiles !== -1) { | ||
| diagnostic = Diagnostics.File_0_not_found; | ||
| fileName += ".ts"; | ||
| diagnosticArgument = [fileName]; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -1087,6 +1095,11 @@ namespace ts { | |
| return file; | ||
| } | ||
|
|
||
| const isNonTsFile = !hasTypeScriptFileExtension(fileName); | ||
| if (isNonTsFile && !options.disableSizeLimit && programSizeForNonTsFiles === -1) { | ||
| 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) { | ||
|
|
@@ -1098,6 +1111,25 @@ namespace ts { | |
| } | ||
| }); | ||
|
|
||
| if (isNonTsFile && !options.disableSizeLimit && file && file.text) { | ||
| 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)); | ||
|
||
| programSizeForNonTsFiles = -1; | ||
| return undefined; | ||
| } | ||
| } | ||
|
|
||
| filesByName.set(path, file); | ||
| if (file) { | ||
| file.path = path; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2476,6 +2476,10 @@ namespace ts { | |
| return forEach(supportedJavascriptExtensions, extension => fileExtensionIs(fileName, extension)); | ||
| } | ||
|
|
||
| export function hasTypeScriptFileExtension(fileName: string) { | ||
| return forEach(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension)); | ||
| } | ||
|
|
||
| /** | ||
| * Replace each instance of non-ascii characters by one, two, three, or four escape sequences | ||
| * representing the UTF-8 encoding of the character, and return the expanded char code list. | ||
|
|
@@ -2858,4 +2862,6 @@ namespace ts { | |
| export function isParameterPropertyDeclaration(node: ParameterDeclaration): boolean { | ||
| return node.flags & NodeFlags.AccessibilityModifier && node.parent.kind === SyntaxKind.Constructor && isClassLike(node.parent.parent); | ||
| } | ||
|
|
||
| export const maxProgramSizeForNonTsFiles = 20 * 1024 * 1024; | ||
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1217,10 +1217,45 @@ namespace ts.server { | |
| } | ||
| else { | ||
| const project = this.createProject(configFilename, projectOptions); | ||
| let programSizeForNonTsFiles = 0; | ||
|
|
||
| // As the project openning might not be complete if there are too many files, | ||
| // therefore to surface the diagnostics we need to make sure the given client file is opened. | ||
| if (clientFileName) { | ||
| if (this.host.fileExists(clientFileName)) { | ||
| const currentClientFileInfo = this.openFile(clientFileName, /*openedByClient*/ true); | ||
| project.addRoot(currentClientFileInfo); | ||
| if (!hasTypeScriptFileExtension(currentClientFileInfo.fileName) && currentClientFileInfo.content) { | ||
| programSizeForNonTsFiles += currentClientFileInfo.content.length; | ||
| } | ||
| } | ||
| else { | ||
| return { errorMsg: "specified file " + clientFileName + " not found" }; | ||
| } | ||
| } | ||
|
|
||
| for (const rootFilename of projectOptions.files) { | ||
| if (rootFilename === clientFileName) { | ||
| continue; | ||
| } | ||
|
|
||
| if (this.host.fileExists(rootFilename)) { | ||
| const info = this.openFile(rootFilename, /*openedByClient*/ clientFileName == rootFilename); | ||
| project.addRoot(info); | ||
| if (projectOptions.compilerOptions.disableSizeLimit) { | ||
| const info = this.openFile(rootFilename, /*openedByClient*/ false); | ||
| project.addRoot(info); | ||
| } | ||
| else if (programSizeForNonTsFiles <= maxProgramSizeForNonTsFiles) { | ||
| const info = this.openFile(rootFilename, /*openedByClient*/ false); | ||
| project.addRoot(info); | ||
| if (!hasTypeScriptFileExtension(rootFilename)) { | ||
| programSizeForNonTsFiles += info.content.length; | ||
| } | ||
| } | ||
| else { | ||
| // The project size is too large. Stop loading the files on the server, | ||
| // and let the compiler issue an diagnostic via `createProgram`. | ||
| break; | ||
|
Member
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. Is the intent to just stop loading files at this point without issuing an error, and to let
Contributor
Author
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. Exactly, as I can't create a diagnostic within |
||
| } | ||
| } | ||
| else { | ||
| return { errorMsg: "specified file " + rootFilename + " not found" }; | ||
|
|
@@ -1251,7 +1286,10 @@ namespace ts.server { | |
| return error; | ||
| } | ||
| else { | ||
| const oldFileNames = project.compilerService.host.roots.map(info => info.fileName); | ||
| // if the project is too large, the root files might not have been all loaded if the total | ||
| // program size reached the upper limit. In that case project.projectOptions.files should | ||
| // be more precise. However this would only happen for configured project. | ||
| const oldFileNames = project.projectOptions ? project.projectOptions.files : project.compilerService.host.roots.map(info => info.fileName); | ||
|
Member
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. Just because
Contributor
Author
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. This |
||
| const newFileNames = projectOptions.files; | ||
| const fileNamesToRemove = oldFileNames.filter(f => newFileNames.indexOf(f) < 0); | ||
| const fileNamesToAdd = newFileNames.filter(f => oldFileNames.indexOf(f) < 0); | ||
|
|
||
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.
This magic
-1value is being used in a few places now. Can you make this aconstwith a meaningful name and use that to make the code more readable (e.g.const sizeLimitExceeded = -1). It would also help readability if this was a simple helper function (e.g.function sizeLimitExceed() { return !options.disableLimit && programSizeForNonTsFiles === sizeLimitExceeded;}) used in these conditions.