@@ -27,6 +27,8 @@ namespace ts.server {
2727 } ) ;
2828 }
2929
30+ export const maxProgramSizeForNonTsFiles = 20 * 1024 * 1024 ;
31+
3032 export class ScriptInfo {
3133 svc : ScriptVersionCache ;
3234 children : ScriptInfo [ ] = [ ] ; // files referenced by this file
@@ -385,12 +387,29 @@ namespace ts.server {
385387 /** Used for configured projects which may have multiple open roots */
386388 openRefCount = 0 ;
387389
388- constructor ( public projectService : ProjectService , public projectOptions ?: ProjectOptions ) {
390+ constructor (
391+ public projectService : ProjectService ,
392+ public projectOptions ?: ProjectOptions ,
393+ public languageServiceDiabled = false ) {
389394 if ( projectOptions && projectOptions . files ) {
390395 // If files are listed explicitly, allow all extensions
391396 projectOptions . compilerOptions . allowNonTsExtensions = true ;
392397 }
393- this . compilerService = new CompilerService ( this , projectOptions && projectOptions . compilerOptions ) ;
398+ if ( ! languageServiceDiabled ) {
399+ this . compilerService = new CompilerService ( this , projectOptions && projectOptions . compilerOptions ) ;
400+ }
401+ }
402+
403+ enableLanguageService ( ) {
404+ // if the language service was disabled, we should re-initiate the compiler service
405+ if ( this . languageServiceDiabled ) {
406+ this . compilerService = new CompilerService ( this , this . projectOptions && this . projectOptions . compilerOptions ) ;
407+ }
408+ this . languageServiceDiabled = false ;
409+ }
410+
411+ disableLanguageService ( ) {
412+ this . languageServiceDiabled = true ;
394413 }
395414
396415 addOpenRef ( ) {
@@ -407,19 +426,45 @@ namespace ts.server {
407426 }
408427
409428 getRootFiles ( ) {
429+ if ( this . languageServiceDiabled ) {
430+ // When the languageService was disabled, only return file list if it is a configured project
431+ return this . projectOptions ? this . projectOptions . files : undefined ;
432+ }
433+
410434 return this . compilerService . host . roots . map ( info => info . fileName ) ;
411435 }
412436
413437 getFileNames ( ) {
438+ if ( this . languageServiceDiabled ) {
439+ if ( ! this . projectOptions ) {
440+ return undefined ;
441+ }
442+
443+ const fileNames : string [ ] = [ ] ;
444+ if ( this . projectOptions && this . projectOptions . compilerOptions ) {
445+ fileNames . push ( getDefaultLibFilePath ( this . projectOptions . compilerOptions ) ) ;
446+ }
447+ ts . addRange ( fileNames , this . projectOptions . files ) ;
448+ return fileNames ;
449+ }
450+
414451 const sourceFiles = this . program . getSourceFiles ( ) ;
415452 return sourceFiles . map ( sourceFile => sourceFile . fileName ) ;
416453 }
417454
418455 getSourceFile ( info : ScriptInfo ) {
456+ if ( this . languageServiceDiabled ) {
457+ return undefined ;
458+ }
459+
419460 return this . filenameToSourceFile [ info . fileName ] ;
420461 }
421462
422463 getSourceFileFromName ( filename : string , requireOpen ?: boolean ) {
464+ if ( this . languageServiceDiabled ) {
465+ return undefined ;
466+ }
467+
423468 const info = this . projectService . getScriptInfo ( filename ) ;
424469 if ( info ) {
425470 if ( ( ! requireOpen ) || info . isOpen ) {
@@ -429,15 +474,27 @@ namespace ts.server {
429474 }
430475
431476 isRoot ( info : ScriptInfo ) {
477+ if ( this . languageServiceDiabled ) {
478+ return undefined ;
479+ }
480+
432481 return this . compilerService . host . roots . some ( root => root === info ) ;
433482 }
434483
435484 removeReferencedFile ( info : ScriptInfo ) {
485+ if ( this . languageServiceDiabled ) {
486+ return ;
487+ }
488+
436489 this . compilerService . host . removeReferencedFile ( info ) ;
437490 this . updateGraph ( ) ;
438491 }
439492
440493 updateFileMap ( ) {
494+ if ( this . languageServiceDiabled ) {
495+ return ;
496+ }
497+
441498 this . filenameToSourceFile = { } ;
442499 const sourceFiles = this . program . getSourceFiles ( ) ;
443500 for ( let i = 0 , len = sourceFiles . length ; i < len ; i ++ ) {
@@ -447,11 +504,19 @@ namespace ts.server {
447504 }
448505
449506 finishGraph ( ) {
507+ if ( this . languageServiceDiabled ) {
508+ return ;
509+ }
510+
450511 this . updateGraph ( ) ;
451512 this . compilerService . languageService . getNavigateToItems ( ".*" ) ;
452513 }
453514
454515 updateGraph ( ) {
516+ if ( this . languageServiceDiabled ) {
517+ return ;
518+ }
519+
455520 this . program = this . compilerService . languageService . getProgram ( ) ;
456521 this . updateFileMap ( ) ;
457522 }
@@ -462,15 +527,32 @@ namespace ts.server {
462527
463528 // add a root file to project
464529 addRoot ( info : ScriptInfo ) {
530+ if ( this . languageServiceDiabled ) {
531+ return ;
532+ }
533+
465534 this . compilerService . host . addRoot ( info ) ;
466535 }
467536
468537 // remove a root file from project
469538 removeRoot ( info : ScriptInfo ) {
539+ if ( this . languageServiceDiabled ) {
540+ return ;
541+ }
542+
470543 this . compilerService . host . removeRoot ( info ) ;
471544 }
472545
473546 filesToString ( ) {
547+ if ( this . languageServiceDiabled ) {
548+ if ( this . projectOptions ) {
549+ let strBuilder = "" ;
550+ ts . forEach ( this . projectOptions . files ,
551+ file => { strBuilder += file + "\n" ; } ) ;
552+ return strBuilder ;
553+ }
554+ }
555+
474556 let strBuilder = "" ;
475557 ts . forEachValue ( this . filenameToSourceFile ,
476558 sourceFile => { strBuilder += sourceFile . fileName + "\n" ; } ) ;
@@ -481,7 +563,9 @@ namespace ts.server {
481563 this . projectOptions = projectOptions ;
482564 if ( projectOptions . compilerOptions ) {
483565 projectOptions . compilerOptions . allowNonTsExtensions = true ;
484- this . compilerService . setCompilerOptions ( projectOptions . compilerOptions ) ;
566+ if ( ! this . languageServiceDiabled ) {
567+ this . compilerService . setCompilerOptions ( projectOptions . compilerOptions ) ;
568+ }
485569 }
486570 }
487571 }
@@ -1261,7 +1345,24 @@ namespace ts.server {
12611345 return { succeeded : true , projectOptions } ;
12621346 }
12631347 }
1348+ }
1349+
1350+ private exceedTotalNonTsFileSizeLimit ( fileNames : string [ ] ) {
1351+ let totalNonTsFileSize = 0 ;
1352+ if ( ! this . host . getFileSize ) {
1353+ return false ;
1354+ }
12641355
1356+ for ( const fileName of fileNames ) {
1357+ if ( hasTypeScriptFileExtension ( fileName ) ) {
1358+ continue ;
1359+ }
1360+ totalNonTsFileSize += this . host . getFileSize ( fileName ) ;
1361+ if ( totalNonTsFileSize > maxProgramSizeForNonTsFiles ) {
1362+ return true ;
1363+ }
1364+ }
1365+ return false ;
12651366 }
12661367
12671368 openConfigFile ( configFilename : string , clientFileName ?: string ) : { success : boolean , project ?: Project , errors ?: Diagnostic [ ] } {
@@ -1270,6 +1371,19 @@ namespace ts.server {
12701371 return { success : false , errors } ;
12711372 }
12721373 else {
1374+ if ( ! projectOptions . compilerOptions . disableSizeLimit && projectOptions . compilerOptions . allowJs ) {
1375+ if ( this . exceedTotalNonTsFileSizeLimit ( projectOptions . files ) ) {
1376+ const project = this . createProject ( configFilename , projectOptions , /*languageServiceDisabled*/ true ) ;
1377+
1378+ // for configured projects with languageService disabled, we only watch its config file,
1379+ // do not care about the directory changes in the folder.
1380+ project . projectFileWatcher = this . host . watchFile (
1381+ toPath ( configFilename , configFilename , createGetCanonicalFileName ( sys . useCaseSensitiveFileNames ) ) ,
1382+ _ => this . watchedProjectConfigFileChanged ( project ) ) ;
1383+ return { success : true , project } ;
1384+ }
1385+ }
1386+
12731387 const project = this . createProject ( configFilename , projectOptions ) ;
12741388 let errors : Diagnostic [ ] ;
12751389 for ( const rootFilename of projectOptions . files ) {
@@ -1293,7 +1407,7 @@ namespace ts.server {
12931407 }
12941408 }
12951409
1296- updateConfiguredProject ( project : Project ) {
1410+ updateConfiguredProject ( project : Project ) : Diagnostic [ ] {
12971411 if ( ! this . host . fileExists ( project . projectFilename ) ) {
12981412 this . log ( "Config file deleted" ) ;
12991413 this . removeProject ( project ) ;
@@ -1304,7 +1418,43 @@ namespace ts.server {
13041418 return errors ;
13051419 }
13061420 else {
1307- const oldFileNames = project . compilerService . host . roots . map ( info => info . fileName ) ;
1421+ if ( projectOptions . compilerOptions && ! projectOptions . compilerOptions . disableSizeLimit && this . exceedTotalNonTsFileSizeLimit ( projectOptions . files ) ) {
1422+ project . setProjectOptions ( projectOptions ) ;
1423+ if ( project . languageServiceDiabled ) {
1424+ return ;
1425+ }
1426+
1427+ project . disableLanguageService ( ) ;
1428+ if ( project . directoryWatcher ) {
1429+ project . directoryWatcher . close ( ) ;
1430+ project . directoryWatcher = undefined ;
1431+ }
1432+ return ;
1433+ }
1434+
1435+ if ( project . languageServiceDiabled ) {
1436+ project . setProjectOptions ( projectOptions ) ;
1437+ project . enableLanguageService ( ) ;
1438+ project . directoryWatcher = this . host . watchDirectory (
1439+ ts . getDirectoryPath ( project . projectFilename ) ,
1440+ path => this . directoryWatchedForSourceFilesChanged ( project , path ) ,
1441+ /*recursive*/ true
1442+ ) ;
1443+
1444+ for ( const rootFilename of projectOptions . files ) {
1445+ if ( this . host . fileExists ( rootFilename ) ) {
1446+ const info = this . openFile ( rootFilename , /*openedByClient*/ false ) ;
1447+ project . addRoot ( info ) ;
1448+ }
1449+ }
1450+ project . finishGraph ( ) ;
1451+ return ;
1452+ }
1453+
1454+ // if the project is too large, the root files might not have been all loaded if the total
1455+ // program size reached the upper limit. In that case project.projectOptions.files should
1456+ // be more precise. However this would only happen for configured project.
1457+ const oldFileNames = project . projectOptions ? project . projectOptions . files : project . compilerService . host . roots . map ( info => info . fileName ) ;
13081458 const newFileNames = ts . filter ( projectOptions . files , f => this . host . fileExists ( f ) ) ;
13091459 const fileNamesToRemove = oldFileNames . filter ( f => newFileNames . indexOf ( f ) < 0 ) ;
13101460 const fileNamesToAdd = newFileNames . filter ( f => oldFileNames . indexOf ( f ) < 0 ) ;
@@ -1347,8 +1497,8 @@ namespace ts.server {
13471497 }
13481498 }
13491499
1350- createProject ( projectFilename : string , projectOptions ?: ProjectOptions ) {
1351- const project = new Project ( this , projectOptions ) ;
1500+ createProject ( projectFilename : string , projectOptions ?: ProjectOptions , languageServiceDisabled ?: boolean ) {
1501+ const project = new Project ( this , projectOptions , languageServiceDisabled ) ;
13521502 project . projectFilename = projectFilename ;
13531503 return project ;
13541504 }
0 commit comments