@@ -123,7 +123,66 @@ namespace ts.server {
123123 }
124124 }
125125
126- export class LSHost implements ts . LanguageServiceHost , ModuleResolutionHost {
126+
127+ function throwLanguageServiceIsDisabledError ( ) { ;
128+ throw new Error ( "LanguageService is disabled" ) ;
129+ }
130+
131+ const nullLanguageService : ts . LanguageService = {
132+ cleanupSemanticCache : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
133+ getSyntacticDiagnostics : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
134+ getSemanticDiagnostics : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
135+ getCompilerOptionsDiagnostics : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
136+ getSyntacticClassifications : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
137+ getEncodedSyntacticClassifications : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
138+ getSemanticClassifications : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
139+ getEncodedSemanticClassifications : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
140+ getCompletionsAtPosition : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
141+ findReferences : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
142+ getCompletionEntryDetails : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
143+ getQuickInfoAtPosition : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
144+ findRenameLocations : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
145+ getNameOrDottedNameSpan : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
146+ getBreakpointStatementAtPosition : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
147+ getBraceMatchingAtPosition : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
148+ getSignatureHelpItems : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
149+ getDefinitionAtPosition : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
150+ getRenameInfo : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
151+ getTypeDefinitionAtPosition : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
152+ getReferencesAtPosition : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
153+ getDocumentHighlights : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
154+ getOccurrencesAtPosition : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
155+ getNavigateToItems : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
156+ getNavigationBarItems : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
157+ getOutliningSpans : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
158+ getTodoComments : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
159+ getIndentationAtPosition : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
160+ getFormattingEditsForRange : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
161+ getFormattingEditsForDocument : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
162+ getFormattingEditsAfterKeystroke : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
163+ getDocCommentTemplateAtPosition : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
164+ isValidBraceCompletionAtPostion : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
165+ getEmitOutput : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
166+ getProgram : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
167+ getNonBoundSourceFile : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
168+ dispose : ( ) : any => throwLanguageServiceIsDisabledError ( ) ,
169+ } ;
170+
171+ interface ServerLanguageServiceHost {
172+ getCompilationSettings ( ) : CompilerOptions ;
173+ setCompilationSettings ( options : CompilerOptions ) : void ;
174+ removeRoot ( info : ScriptInfo ) : void ;
175+ removeReferencedFile ( info : ScriptInfo ) : void ;
176+ }
177+
178+ const nullLanguageServiceHost : ServerLanguageServiceHost = {
179+ getCompilationSettings : ( ) => undefined ,
180+ setCompilationSettings : ( ) => undefined ,
181+ removeRoot : ( ) => undefined ,
182+ removeReferencedFile : ( ) => undefined
183+ } ;
184+
185+ export class LSHost implements ts . LanguageServiceHost , ModuleResolutionHost , ServerLanguageServiceHost {
127186 private compilationSettings : ts . CompilerOptions ;
128187 private resolvedModuleNames : ts . FileMap < Map < ResolvedModuleWithFailedLookupLocations > > ;
129188 private resolvedTypeReferenceDirectives : ts . FileMap < Map < ResolvedTypeReferenceDirectiveWithFailedLookupLocations > > ;
@@ -302,31 +361,62 @@ namespace ts.server {
302361 export abstract class Project {
303362 private rootFiles : ScriptInfo [ ] = [ ] ;
304363 private rootFilesMap : FileMap < ScriptInfo > = createFileMap < ScriptInfo > ( ) ;
305- private readonly lsHost : LSHost ;
364+ private lsHost : ServerLanguageServiceHost ;
306365
307- readonly languageService : LanguageService ;
366+ languageService : LanguageService ;
308367 protected program : ts . Program ;
309368
310369 constructor (
311370 readonly projectKind : ProjectKind ,
312371 readonly projectService : ProjectService ,
313- documentRegistry : ts . DocumentRegistry ,
372+ private documentRegistry : ts . DocumentRegistry ,
314373 hasExplicitListOfFiles : boolean ,
315- compilerOptions : CompilerOptions ) {
374+ public languageServiceEnabled : boolean ,
375+ private compilerOptions : CompilerOptions ) {
316376
317- if ( ! compilerOptions ) {
318- compilerOptions = ts . getDefaultCompilerOptions ( ) ;
319- compilerOptions . allowNonTsExtensions = true ;
320- compilerOptions . allowJs = true ;
377+ if ( ! this . compilerOptions ) {
378+ this . compilerOptions = ts . getDefaultCompilerOptions ( ) ;
379+ this . compilerOptions . allowNonTsExtensions = true ;
380+ this . compilerOptions . allowJs = true ;
321381 }
322382 else if ( hasExplicitListOfFiles ) {
323383 // If files are listed explicitly, allow all extensions
324- compilerOptions . allowNonTsExtensions = true ;
384+ this . compilerOptions . allowNonTsExtensions = true ;
385+ }
386+
387+ if ( languageServiceEnabled ) {
388+ this . enableLanguageServiceWorker ( ) ;
389+ }
390+ else {
391+ this . disableLanguageServiceWorker ( ) ;
392+ }
393+ }
394+
395+ enableLanguageService ( ) {
396+ if ( ! this . languageServiceEnabled ) {
397+ this . enableLanguageServiceWorker ( ) ;
398+ }
399+ }
400+
401+ private enableLanguageServiceWorker ( ) {
402+ const lsHost = new LSHost ( this . projectService . host , this , this . projectService . cancellationToken ) ;
403+ lsHost . setCompilationSettings ( this . compilerOptions ) ;
404+ this . languageService = ts . createLanguageService ( lsHost , this . documentRegistry ) ;
405+
406+ this . lsHost = lsHost ;
407+ this . languageServiceEnabled = true ;
408+ }
409+
410+ disableLanguageService ( ) {
411+ if ( this . languageServiceEnabled ) {
412+ this . disableLanguageServiceWorker ( ) ;
325413 }
414+ }
326415
327- this . lsHost = new LSHost ( this . projectService . host , this , this . projectService . cancellationToken ) ;
328- this . lsHost . setCompilationSettings ( compilerOptions ) ;
329- this . languageService = ts . createLanguageService ( this . lsHost , documentRegistry ) ;
416+ private disableLanguageServiceWorker ( ) {
417+ this . languageService = nullLanguageService ;
418+ this . lsHost = nullLanguageServiceHost ;
419+ this . languageServiceEnabled = false ;
330420 }
331421
332422 getProjectFileName ( ) : string {
@@ -343,29 +433,29 @@ namespace ts.server {
343433 }
344434
345435 getRootFiles ( ) {
436+ if ( ! this . languageServiceEnabled && this . projectKind === ProjectKind . Inferred ) {
437+ return undefined ;
438+ }
346439 return this . rootFiles . map ( info => info . fileName ) ;
347440 }
348441
349442 getFileNames ( ) {
350- if ( this . languageServiceDiabled ) {
351- if ( ! this . projectOptions ) {
352- return undefined ;
353- }
354-
355- const fileNames : string [ ] = [ ] ;
356- if ( this . projectOptions && this . projectOptions . compilerOptions ) {
357- fileNames . push ( getDefaultLibFilePath ( this . projectOptions . compilerOptions ) ) ;
443+ if ( ! this . languageServiceEnabled ) {
444+ let rootFiles = this . getRootFiles ( ) ;
445+ if ( this . compilerOptions ) {
446+ const defaultLibrary = getDefaultLibFilePath ( this . compilerOptions ) ;
447+ if ( defaultLibrary ) {
448+ ( rootFiles || ( rootFiles = [ ] ) ) . push ( defaultLibrary ) ;
449+ }
358450 }
359- ts . addRange ( fileNames , this . projectOptions . files ) ;
360- return fileNames ;
451+ return rootFiles ;
361452 }
362-
363453 const sourceFiles = this . program . getSourceFiles ( ) ;
364454 return sourceFiles . map ( sourceFile => sourceFile . fileName ) ;
365455 }
366456
367457 containsScriptInfo ( info : ScriptInfo ) : boolean {
368- return this . program . getSourceFileByPath ( info . path ) !== undefined ;
458+ return this . program && this . program . getSourceFileByPath ( info . path ) !== undefined ;
369459 }
370460
371461 containsFile ( filename : string , requireOpen ?: boolean ) {
@@ -455,8 +545,13 @@ namespace ts.server {
455545 // Used to keep track of what directories are watched for this project
456546 directoriesWatchedForTsconfig : string [ ] = [ ] ;
457547
458- constructor ( projectService : ProjectService , documentRegistry : ts . DocumentRegistry ) {
459- super ( ProjectKind . Inferred , projectService , documentRegistry , /*files*/ undefined , /*compilerOptions*/ undefined ) ;
548+ constructor ( projectService : ProjectService , documentRegistry : ts . DocumentRegistry , languageServiceEnabled : boolean ) {
549+ super ( ProjectKind . Inferred ,
550+ projectService ,
551+ documentRegistry ,
552+ /*files*/ undefined ,
553+ languageServiceEnabled ,
554+ /*compilerOptions*/ undefined ) ;
460555 }
461556
462557 close ( ) {
@@ -483,6 +578,9 @@ namespace ts.server {
483578 currentVersion : number = 1 ;
484579
485580 updateGraph ( ) {
581+ if ( ! this . languageServiceEnabled ) {
582+ return ;
583+ }
486584 const oldProgram = this . program ;
487585
488586 super . updateGraph ( ) ;
@@ -538,8 +636,13 @@ namespace ts.server {
538636 /** Used for configured projects which may have multiple open roots */
539637 openRefCount = 0 ;
540638
541- constructor ( readonly configFileName : string , projectService : ProjectService , documentRegistry : ts . DocumentRegistry , hasExplicitListOfFiles : boolean , compilerOptions : CompilerOptions ) {
542- super ( ProjectKind . Configured , projectService , documentRegistry , hasExplicitListOfFiles , compilerOptions ) ;
639+ constructor ( readonly configFileName : string ,
640+ projectService : ProjectService ,
641+ documentRegistry : ts . DocumentRegistry ,
642+ hasExplicitListOfFiles : boolean ,
643+ compilerOptions : CompilerOptions ,
644+ languageServiceEnabled : boolean ) {
645+ super ( ProjectKind . Configured , projectService , documentRegistry , hasExplicitListOfFiles , languageServiceEnabled , compilerOptions ) ;
543646 }
544647
545648 getProjectFileName ( ) {
@@ -551,20 +654,29 @@ namespace ts.server {
551654 }
552655
553656 watchConfigDirectory ( callback : ( project : ConfiguredProject , path : string ) => void ) {
657+ if ( this . directoryWatcher ) {
658+ return ;
659+ }
660+
554661 const directoryToWatch = ts . getDirectoryPath ( this . configFileName ) ;
555662 this . projectService . log ( `Add recursive watcher for: ${ directoryToWatch } ` ) ;
556663 this . directoryWatcher = this . projectService . host . watchDirectory ( directoryToWatch , path => callback ( this , path ) , /*recursive*/ true ) ;
557664 }
558665
666+ stopWatchingDirectory ( ) {
667+ if ( this . directoryWatcher ) {
668+ this . directoryWatcher . close ( ) ;
669+ this . directoryWatcher = undefined ;
670+ }
671+ }
672+
559673 close ( ) {
560674 super . close ( ) ;
561675
562676 if ( this . projectFileWatcher ) {
563677 this . projectFileWatcher . close ( ) ;
564678 }
565- if ( this . directoryWatcher ) {
566- this . directoryWatcher . close ( ) ;
567- }
679+ this . stopWatchingDirectory ( ) ;
568680 }
569681
570682 addOpenRef ( ) {
@@ -578,8 +690,12 @@ namespace ts.server {
578690 }
579691
580692 class ExternalProject extends VersionedProject {
581- constructor ( readonly projectFileName : string , projectService : ProjectService , documentRegistry : ts . DocumentRegistry , compilerOptions : CompilerOptions ) {
582- super ( ProjectKind . External , projectService , documentRegistry , /*hasExplicitListOfFiles*/ true , compilerOptions ) ;
693+ constructor ( readonly projectFileName : string ,
694+ projectService : ProjectService ,
695+ documentRegistry : ts . DocumentRegistry ,
696+ compilerOptions : CompilerOptions ,
697+ languageServiceEnabled : boolean ) {
698+ super ( ProjectKind . External , projectService , documentRegistry , /*hasExplicitListOfFiles*/ true , languageServiceEnabled , compilerOptions ) ;
583699 }
584700
585701 getProjectFileName ( ) {
@@ -1149,7 +1265,10 @@ namespace ts.server {
11491265 }
11501266 }
11511267
1152- private exceedTotalNonTsFileSizeLimit ( fileNames : string [ ] ) {
1268+ private exceedTotalNonTsFileSizeLimit ( options : CompilerOptions , fileNames : string [ ] ) {
1269+ if ( options && options . disableSizeLimit ) {
1270+ return false ;
1271+ }
11531272 let totalNonTsFileSize = 0 ;
11541273 if ( ! this . host . getFileSize ) {
11551274 return false ;
@@ -1168,23 +1287,38 @@ namespace ts.server {
11681287 }
11691288
11701289 private createAndAddExternalProject ( projectFileName : string , files : string [ ] , compilerOptions : CompilerOptions , clientFileName ?: string ) {
1171- const project = new ExternalProject ( projectFileName , this , this . documentRegistry , compilerOptions ) ;
1290+ const sizeLimitExceeded = this . exceedTotalNonTsFileSizeLimit ( compilerOptions , files ) ;
1291+ const project = new ExternalProject ( projectFileName , this , this . documentRegistry , compilerOptions , ! sizeLimitExceeded ) ;
11721292 const errors = this . addFilesToProject ( project , files , clientFileName ) ;
11731293 this . externalProjects . push ( project ) ;
11741294 return { project, errors } ;
11751295 }
11761296
11771297 private createAndAddConfiguredProject ( configFileName : string , projectOptions : ProjectOptions , clientFileName ?: string ) {
1178- const project = new ConfiguredProject ( configFileName , this , this . documentRegistry , projectOptions . configHasFilesProperty , projectOptions . compilerOptions ) ;
1298+ const sizeLimitExceeded = this . exceedTotalNonTsFileSizeLimit ( projectOptions . compilerOptions , projectOptions . files ) ;
1299+ const project = new ConfiguredProject (
1300+ configFileName ,
1301+ this ,
1302+ this . documentRegistry ,
1303+ projectOptions . configHasFilesProperty ,
1304+ projectOptions . compilerOptions ,
1305+ ! sizeLimitExceeded ) ;
1306+
11791307 const errors = this . addFilesToProject ( project , projectOptions . files , clientFileName ) ;
11801308 project . watchConfigFile ( project => this . onConfigChangedForConfiguredProject ( project ) ) ;
1181- if ( ! projectOptions . configHasFilesProperty ) {
1182- project . watchConfigDirectory ( ( project , path ) => this . onSourceFileInDirectoryChangedForConfiguredProject ( project , path ) ) ;
1309+ if ( ! sizeLimitExceeded ) {
1310+ this . watchConfigDirectoryForProject ( project , projectOptions ) ;
11831311 }
11841312 this . configuredProjects . push ( project ) ;
11851313 return { project, errors } ;
11861314 }
11871315
1316+ private watchConfigDirectoryForProject ( project : ConfiguredProject , options : ProjectOptions ) {
1317+ if ( ! options . configHasFilesProperty ) {
1318+ project . watchConfigDirectory ( ( project , path ) => this . onSourceFileInDirectoryChangedForConfiguredProject ( project , path ) ) ;
1319+ }
1320+ }
1321+
11881322 private addFilesToProject ( project : ConfiguredProject | ExternalProject , files : string [ ] , clientFileName : string ) : Diagnostic [ ] {
11891323 let errors : Diagnostic [ ] ;
11901324 for ( const rootFilename of files ) {
@@ -1266,13 +1400,28 @@ namespace ts.server {
12661400 return errors ;
12671401 }
12681402 else {
1269- this . updateVersionedProjectWorker ( project , projectOptions . files , projectOptions . compilerOptions ) ;
1403+ if ( this . exceedTotalNonTsFileSizeLimit ( projectOptions . compilerOptions , projectOptions . files ) ) {
1404+ project . setCompilerOptions ( projectOptions . compilerOptions ) ;
1405+ if ( ! project . languageServiceEnabled ) {
1406+ // language service is already disabled
1407+ return ;
1408+ }
1409+ project . disableLanguageService ( ) ;
1410+ project . stopWatchingDirectory ( ) ;
1411+ }
1412+ else {
1413+ if ( ! project . languageServiceEnabled ) {
1414+ project . enableLanguageService ( ) ;
1415+ }
1416+ this . watchConfigDirectoryForProject ( project , projectOptions ) ;
1417+ this . updateVersionedProjectWorker ( project , projectOptions . files , projectOptions . compilerOptions ) ;
1418+ }
12701419 }
12711420 }
12721421 }
12731422
12741423 createAndAddInferredProject ( root : ScriptInfo ) {
1275- const project = new InferredProject ( this , this . documentRegistry ) ;
1424+ const project = new InferredProject ( this , this . documentRegistry , /*languageServiceEnabled*/ true ) ;
12761425 project . addRoot ( root ) ;
12771426
12781427 let currentPath = ts . getDirectoryPath ( root . fileName ) ;
0 commit comments