@@ -27,6 +27,8 @@ namespace ts.server {
27
27
} ) ;
28
28
}
29
29
30
+ export const maxProgramSizeForNonTsFiles = 20 * 1024 * 1024 ;
31
+
30
32
export class ScriptInfo {
31
33
svc : ScriptVersionCache ;
32
34
children : ScriptInfo [ ] = [ ] ; // files referenced by this file
@@ -385,12 +387,29 @@ namespace ts.server {
385
387
/** Used for configured projects which may have multiple open roots */
386
388
openRefCount = 0 ;
387
389
388
- constructor ( public projectService : ProjectService , public projectOptions ?: ProjectOptions ) {
390
+ constructor (
391
+ public projectService : ProjectService ,
392
+ public projectOptions ?: ProjectOptions ,
393
+ public languageServiceDiabled = false ) {
389
394
if ( projectOptions && projectOptions . files ) {
390
395
// If files are listed explicitly, allow all extensions
391
396
projectOptions . compilerOptions . allowNonTsExtensions = true ;
392
397
}
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 ;
394
413
}
395
414
396
415
addOpenRef ( ) {
@@ -407,19 +426,45 @@ namespace ts.server {
407
426
}
408
427
409
428
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
+
410
434
return this . compilerService . host . roots . map ( info => info . fileName ) ;
411
435
}
412
436
413
437
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
+
414
451
const sourceFiles = this . program . getSourceFiles ( ) ;
415
452
return sourceFiles . map ( sourceFile => sourceFile . fileName ) ;
416
453
}
417
454
418
455
getSourceFile ( info : ScriptInfo ) {
456
+ if ( this . languageServiceDiabled ) {
457
+ return undefined ;
458
+ }
459
+
419
460
return this . filenameToSourceFile [ info . fileName ] ;
420
461
}
421
462
422
463
getSourceFileFromName ( filename : string , requireOpen ?: boolean ) {
464
+ if ( this . languageServiceDiabled ) {
465
+ return undefined ;
466
+ }
467
+
423
468
const info = this . projectService . getScriptInfo ( filename ) ;
424
469
if ( info ) {
425
470
if ( ( ! requireOpen ) || info . isOpen ) {
@@ -429,15 +474,27 @@ namespace ts.server {
429
474
}
430
475
431
476
isRoot ( info : ScriptInfo ) {
477
+ if ( this . languageServiceDiabled ) {
478
+ return undefined ;
479
+ }
480
+
432
481
return this . compilerService . host . roots . some ( root => root === info ) ;
433
482
}
434
483
435
484
removeReferencedFile ( info : ScriptInfo ) {
485
+ if ( this . languageServiceDiabled ) {
486
+ return ;
487
+ }
488
+
436
489
this . compilerService . host . removeReferencedFile ( info ) ;
437
490
this . updateGraph ( ) ;
438
491
}
439
492
440
493
updateFileMap ( ) {
494
+ if ( this . languageServiceDiabled ) {
495
+ return ;
496
+ }
497
+
441
498
this . filenameToSourceFile = { } ;
442
499
const sourceFiles = this . program . getSourceFiles ( ) ;
443
500
for ( let i = 0 , len = sourceFiles . length ; i < len ; i ++ ) {
@@ -447,11 +504,19 @@ namespace ts.server {
447
504
}
448
505
449
506
finishGraph ( ) {
507
+ if ( this . languageServiceDiabled ) {
508
+ return ;
509
+ }
510
+
450
511
this . updateGraph ( ) ;
451
512
this . compilerService . languageService . getNavigateToItems ( ".*" ) ;
452
513
}
453
514
454
515
updateGraph ( ) {
516
+ if ( this . languageServiceDiabled ) {
517
+ return ;
518
+ }
519
+
455
520
this . program = this . compilerService . languageService . getProgram ( ) ;
456
521
this . updateFileMap ( ) ;
457
522
}
@@ -462,15 +527,32 @@ namespace ts.server {
462
527
463
528
// add a root file to project
464
529
addRoot ( info : ScriptInfo ) {
530
+ if ( this . languageServiceDiabled ) {
531
+ return ;
532
+ }
533
+
465
534
this . compilerService . host . addRoot ( info ) ;
466
535
}
467
536
468
537
// remove a root file from project
469
538
removeRoot ( info : ScriptInfo ) {
539
+ if ( this . languageServiceDiabled ) {
540
+ return ;
541
+ }
542
+
470
543
this . compilerService . host . removeRoot ( info ) ;
471
544
}
472
545
473
546
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
+
474
556
let strBuilder = "" ;
475
557
ts . forEachValue ( this . filenameToSourceFile ,
476
558
sourceFile => { strBuilder += sourceFile . fileName + "\n" ; } ) ;
@@ -481,7 +563,9 @@ namespace ts.server {
481
563
this . projectOptions = projectOptions ;
482
564
if ( projectOptions . compilerOptions ) {
483
565
projectOptions . compilerOptions . allowNonTsExtensions = true ;
484
- this . compilerService . setCompilerOptions ( projectOptions . compilerOptions ) ;
566
+ if ( ! this . languageServiceDiabled ) {
567
+ this . compilerService . setCompilerOptions ( projectOptions . compilerOptions ) ;
568
+ }
485
569
}
486
570
}
487
571
}
@@ -1261,7 +1345,24 @@ namespace ts.server {
1261
1345
return { succeeded : true , projectOptions } ;
1262
1346
}
1263
1347
}
1348
+ }
1349
+
1350
+ private exceedTotalNonTsFileSizeLimit ( fileNames : string [ ] ) {
1351
+ let totalNonTsFileSize = 0 ;
1352
+ if ( ! this . host . getFileSize ) {
1353
+ return false ;
1354
+ }
1264
1355
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 ;
1265
1366
}
1266
1367
1267
1368
openConfigFile ( configFilename : string , clientFileName ?: string ) : { success : boolean , project ?: Project , errors ?: Diagnostic [ ] } {
@@ -1270,6 +1371,19 @@ namespace ts.server {
1270
1371
return { success : false , errors } ;
1271
1372
}
1272
1373
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
+
1273
1387
const project = this . createProject ( configFilename , projectOptions ) ;
1274
1388
let errors : Diagnostic [ ] ;
1275
1389
for ( const rootFilename of projectOptions . files ) {
@@ -1293,7 +1407,7 @@ namespace ts.server {
1293
1407
}
1294
1408
}
1295
1409
1296
- updateConfiguredProject ( project : Project ) {
1410
+ updateConfiguredProject ( project : Project ) : Diagnostic [ ] {
1297
1411
if ( ! this . host . fileExists ( project . projectFilename ) ) {
1298
1412
this . log ( "Config file deleted" ) ;
1299
1413
this . removeProject ( project ) ;
@@ -1304,7 +1418,43 @@ namespace ts.server {
1304
1418
return errors ;
1305
1419
}
1306
1420
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 ) ;
1308
1458
const newFileNames = ts . filter ( projectOptions . files , f => this . host . fileExists ( f ) ) ;
1309
1459
const fileNamesToRemove = oldFileNames . filter ( f => newFileNames . indexOf ( f ) < 0 ) ;
1310
1460
const fileNamesToAdd = newFileNames . filter ( f => oldFileNames . indexOf ( f ) < 0 ) ;
@@ -1347,8 +1497,8 @@ namespace ts.server {
1347
1497
}
1348
1498
}
1349
1499
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 ) ;
1352
1502
project . projectFilename = projectFilename ;
1353
1503
return project ;
1354
1504
}
0 commit comments