Skip to content

Commit 5679991

Browse files
committed
Port microsoft#7486 to release-1.8
1 parent 4927091 commit 5679991

File tree

7 files changed

+107
-18
lines changed

7 files changed

+107
-18
lines changed

src/compiler/commandLineParser.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,11 @@ namespace ts {
305305
name: "noCustomAsyncPromise",
306306
type: "boolean",
307307
experimental: true
308+
},
309+
{
310+
name: "disableSizeLimit",
311+
type: "boolean",
312+
description: Diagnostics.Disable_the_upper_limit_for_the_total_file_size_of_a_project
308313
}
309314
];
310315

@@ -534,7 +539,7 @@ namespace ts {
534539
}
535540
else {
536541
// by default exclude node_modules, and any specificied output directory
537-
exclude = ["node_modules"];
542+
exclude = ["node_modules", "bower_components"];
538543
const outDir = json["compilerOptions"] && json["compilerOptions"]["outDir"];
539544
if (outDir) {
540545
exclude.push(outDir);

src/compiler/diagnosticMessages.json

+8
Original file line numberDiff line numberDiff line change
@@ -2458,6 +2458,10 @@
24582458
"category": "Message",
24592459
"code": 6112
24602460
},
2461+
"Disable the upper limit for the total file size of a project.": {
2462+
"category": "Message",
2463+
"code": 6113
2464+
},
24612465
"Variable '{0}' implicitly has an '{1}' type.": {
24622466
"category": "Error",
24632467
"code": 7005
@@ -2661,5 +2665,9 @@
26612665
"Unknown typing option '{0}'.": {
26622666
"category": "Error",
26632667
"code": 17010
2668+
},
2669+
"Too many JavaScript files in the project. Use an exact 'files' list, or use 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'": {
2670+
"category": "Error",
2671+
"code": 17012
26642672
}
26652673
}

src/compiler/program.ts

+30-2
Original file line numberDiff line numberDiff line change
@@ -394,13 +394,41 @@ namespace ts {
394394
(oldOptions.target !== options.target) ||
395395
(oldOptions.noLib !== options.noLib) ||
396396
(oldOptions.jsx !== options.jsx) ||
397-
(oldOptions.allowJs !== options.allowJs)) {
397+
(oldOptions.allowJs !== options.allowJs) ||
398+
(oldOptions.disableSizeLimit !== options.disableSizeLimit)) {
398399
oldProgram = undefined;
399400
}
400401
}
401402

402403
if (!tryReuseStructureFromOldProgram()) {
403-
forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false));
404+
if (options.disableSizeLimit === true) {
405+
forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false));
406+
}
407+
else {
408+
let programSize = 0;
409+
for (const name of rootNames) {
410+
const path = toPath(name, currentDirectory, getCanonicalFileName);
411+
if (programSize <= maxProgramSize) {
412+
processRootFile(name, /*isDefaultLib*/ false);
413+
const file = filesByName.get(path);
414+
if (!hasTypeScriptFileExtension(name) && file && file.text) {
415+
programSize += file.text.length;
416+
}
417+
}
418+
else {
419+
// If the program size limit was reached when processing a file, this file is
420+
// likely in the problematic folder than contains too many files
421+
const commonSourceDirectory = getCommonSourceDirectory();
422+
let rootLevelDirectory = path.substring(0, Math.max(commonSourceDirectory.length, path.indexOf(directorySeparator, commonSourceDirectory.length)));
423+
if (rootLevelDirectory[rootLevelDirectory.length - 1] !== directorySeparator) {
424+
rootLevelDirectory += directorySeparator;
425+
}
426+
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Too_many_JavaScript_files_in_the_project_Use_an_exact_files_list_or_use_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));
427+
break;
428+
}
429+
}
430+
}
431+
404432
// Do not process the default library if:
405433
// - The '--noLib' flag is used.
406434
// - A 'no-default-lib' reference comment is encountered in

src/compiler/sys.ts

+17-12
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ namespace ts {
7474
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
7575
};
7676

77-
export var sys: System = (function () {
77+
export var sys: System = (function() {
7878

7979
function getWScriptSystem(): System {
8080

@@ -407,8 +407,8 @@ namespace ts {
407407
const watchedFileSet = createWatchedFileSet();
408408

409409
function isNode4OrLater(): boolean {
410-
return parseInt(process.version.charAt(1)) >= 4;
411-
}
410+
return parseInt(process.version.charAt(1)) >= 4;
411+
}
412412

413413
const platform: string = _os.platform();
414414
// win32\win64 are case insensitive platforms, MacOS (darwin) by default is also case insensitive
@@ -477,15 +477,20 @@ namespace ts {
477477
for (const current of files) {
478478
const name = combinePaths(path, current);
479479
if (!contains(exclude, getCanonicalPath(name))) {
480-
const stat = _fs.statSync(name);
481-
if (stat.isFile()) {
482-
if (!extension || fileExtensionIs(name, extension)) {
483-
result.push(name);
480+
// fs.statSync would throw an exception if the file is a symlink
481+
// whose linked file doesn't exist.
482+
try {
483+
const stat = _fs.statSync(name);
484+
if (stat.isFile()) {
485+
if (!extension || fileExtensionIs(name, extension)) {
486+
result.push(name);
487+
}
488+
}
489+
else if (stat.isDirectory()) {
490+
directories.push(name);
484491
}
485492
}
486-
else if (stat.isDirectory()) {
487-
directories.push(name);
488-
}
493+
catch (e) { }
489494
}
490495
}
491496
for (const current of directories) {
@@ -509,7 +514,7 @@ namespace ts {
509514
// and https://github.com/Microsoft/TypeScript/issues/4643), therefore
510515
// if the current node.js version is newer than 4, use `fs.watch` instead.
511516
const watchSet = isNode4OrLater() ? watchedFileSet : pollingWatchedFileSet;
512-
const watchedFile = watchSet.addFile(filePath, callback);
517+
const watchedFile = watchSet.addFile(filePath, callback);
513518
return {
514519
close: () => watchSet.removeFile(watchedFile)
515520
};
@@ -539,7 +544,7 @@ namespace ts {
539544
}
540545
);
541546
},
542-
resolvePath: function (path: string): string {
547+
resolvePath: function(path: string): string {
543548
return _path.resolve(path);
544549
},
545550
fileExists(path: string): boolean {

src/compiler/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2437,6 +2437,7 @@ namespace ts {
24372437
allowSyntheticDefaultImports?: boolean;
24382438
allowJs?: boolean;
24392439
noImplicitUseStrict?: boolean;
2440+
disableSizeLimit?: boolean;
24402441
/* @internal */ stripInternal?: boolean;
24412442

24422443
// Skip checking lib.d.ts to help speed up tests.

src/compiler/utilities.ts

+6
Original file line numberDiff line numberDiff line change
@@ -2476,6 +2476,10 @@ namespace ts {
24762476
return forEach(supportedJavascriptExtensions, extension => fileExtensionIs(fileName, extension));
24772477
}
24782478

2479+
export function hasTypeScriptFileExtension(fileName: string) {
2480+
return forEach(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension));
2481+
}
2482+
24792483
/**
24802484
* Replace each instance of non-ascii characters by one, two, three, or four escape sequences
24812485
* representing the UTF-8 encoding of the character, and return the expanded char code list.
@@ -2858,4 +2862,6 @@ namespace ts {
28582862
export function isParameterPropertyDeclaration(node: ParameterDeclaration): boolean {
28592863
return node.flags & NodeFlags.AccessibilityModifier && node.parent.kind === SyntaxKind.Constructor && isClassLike(node.parent.parent);
28602864
}
2865+
2866+
export const maxProgramSize = 20 * 1024 * 1024;
28612867
}

src/server/editorServices.ts

+39-3
Original file line numberDiff line numberDiff line change
@@ -1217,10 +1217,43 @@ namespace ts.server {
12171217
}
12181218
else {
12191219
const project = this.createProject(configFilename, projectOptions);
1220+
let programSize = 0;
1221+
1222+
// As the project openning might not be complete if there are too many files,
1223+
// therefore to surface the diagnostics we need to make sure the given client file is opened.
1224+
if (clientFileName) {
1225+
if (this.host.fileExists(clientFileName)) {
1226+
const currentClientFileInfo = this.openFile(clientFileName, /*openedByClient*/ true);
1227+
project.addRoot(currentClientFileInfo);
1228+
if (!hasTypeScriptFileExtension(currentClientFileInfo.fileName) && currentClientFileInfo.content) {
1229+
programSizeForNonTsFiles += currentClientFileInfo.content.length;
1230+
}
1231+
}
1232+
else {
1233+
return { errorMsg: "specified file " + clientFileName + " not found" };
1234+
}
1235+
}
1236+
12201237
for (const rootFilename of projectOptions.files) {
1238+
if (rootFilename === clientFileName) {
1239+
continue;
1240+
}
1241+
12211242
if (this.host.fileExists(rootFilename)) {
1222-
const info = this.openFile(rootFilename, /*openedByClient*/ clientFileName == rootFilename);
1223-
project.addRoot(info);
1243+
if (projectOptions.compilerOptions.disableSizeLimit) {
1244+
const info = this.openFile(rootFilename, /*openedByClient*/ false);
1245+
project.addRoot(info);
1246+
}
1247+
else if (programSizeForNonTsFiles <= maxProgramSizeForNonTsFiles) {
1248+
const info = this.openFile(rootFilename, /*openedByClient*/ false);
1249+
project.addRoot(info);
1250+
if (!hasTypeScriptFileExtension(rootFilename)) {
1251+
programSizeForNonTsFiles += info.content.length;
1252+
}
1253+
}
1254+
else {
1255+
break;
1256+
}
12241257
}
12251258
else {
12261259
return { errorMsg: "specified file " + rootFilename + " not found" };
@@ -1251,7 +1284,10 @@ namespace ts.server {
12511284
return error;
12521285
}
12531286
else {
1254-
const oldFileNames = project.compilerService.host.roots.map(info => info.fileName);
1287+
// if the project is too large, the root files might not have been all loaded if the total
1288+
// program size reached the upper limit. In that case project.projectOptions.files should
1289+
// be more precise. However this would only happen for configured project.
1290+
const oldFileNames = project.projectOptions ? project.projectOptions.files : project.compilerService.host.roots.map(info => info.fileName);
12551291
const newFileNames = projectOptions.files;
12561292
const fileNamesToRemove = oldFileNames.filter(f => newFileNames.indexOf(f) < 0);
12571293
const fileNamesToAdd = newFileNames.filter(f => oldFileNames.indexOf(f) < 0);

0 commit comments

Comments
 (0)