@@ -702,7 +702,8 @@ namespace ts.server {
702
702
}
703
703
704
704
handleProjectFileListChanges ( project : Project ) {
705
- const { projectOptions } = this . configFileToProjectOptions ( project . projectFilename ) ;
705
+ const { projectOptions, errors } = this . configFileToProjectOptions ( project . projectFilename ) ;
706
+ this . reportConfigFileDiagnostics ( project . projectFilename , errors ) ;
706
707
707
708
const newRootFiles = projectOptions . files . map ( ( f => this . getCanonicalFileName ( f ) ) ) ;
708
709
const currentRootFiles = project . getRootFiles ( ) . map ( ( f => this . getCanonicalFileName ( f ) ) ) ;
@@ -720,18 +721,32 @@ namespace ts.server {
720
721
}
721
722
}
722
723
724
+ reportConfigFileDiagnostics ( configFileName : string , diagnostics : Diagnostic [ ] , triggerFile ?: string ) {
725
+ if ( diagnostics && diagnostics . length > 0 ) {
726
+ this . eventHandler ( {
727
+ eventName : "configFileDiag" ,
728
+ data : { configFileName, diagnostics, triggerFile }
729
+ } ) ;
730
+ }
731
+ }
732
+
723
733
/**
724
734
* This is the callback function when a watched directory has an added tsconfig file.
725
735
*/
726
736
directoryWatchedForTsconfigChanged ( fileName : string ) {
727
- if ( ts . getBaseFileName ( fileName ) != "tsconfig.json" ) {
737
+ if ( ts . getBaseFileName ( fileName ) !== "tsconfig.json" ) {
728
738
this . log ( fileName + " is not tsconfig.json" ) ;
729
739
return ;
730
740
}
731
741
732
742
this . log ( "Detected newly added tsconfig file: " + fileName ) ;
733
743
734
- const { projectOptions } = this . configFileToProjectOptions ( fileName ) ;
744
+ const { projectOptions, errors } = this . configFileToProjectOptions ( fileName ) ;
745
+ this . reportConfigFileDiagnostics ( fileName , errors ) ;
746
+
747
+ if ( ! projectOptions ) {
748
+ return ;
749
+ }
735
750
736
751
const rootFilesInTsconfig = projectOptions . files . map ( f => this . getCanonicalFileName ( f ) ) ;
737
752
const openFileRoots = this . openFileRoots . map ( s => this . getCanonicalFileName ( s . fileName ) ) ;
@@ -1224,7 +1239,7 @@ namespace ts.server {
1224
1239
const project = this . findConfiguredProjectByConfigFile ( configFileName ) ;
1225
1240
if ( ! project ) {
1226
1241
const configResult = this . openConfigFile ( configFileName , fileName ) ;
1227
- if ( ! configResult . success ) {
1242
+ if ( ! configResult . project ) {
1228
1243
return { configFileName, configFileErrors : configResult . errors } ;
1229
1244
}
1230
1245
else {
@@ -1335,33 +1350,31 @@ namespace ts.server {
1335
1350
return undefined ;
1336
1351
}
1337
1352
1338
- configFileToProjectOptions ( configFilename : string ) : { succeeded : boolean , projectOptions ?: ProjectOptions , errors : Diagnostic [ ] } {
1353
+ configFileToProjectOptions ( configFilename : string ) : { projectOptions ?: ProjectOptions , errors : Diagnostic [ ] } {
1339
1354
configFilename = ts . normalizePath ( configFilename ) ;
1355
+ let errors : Diagnostic [ ] = [ ] ;
1340
1356
// file references will be relative to dirPath (or absolute)
1341
1357
const dirPath = ts . getDirectoryPath ( configFilename ) ;
1342
1358
const contents = this . host . readFile ( configFilename ) ;
1343
- const rawConfig : { config ?: ProjectOptions ; error ?: Diagnostic ; } = ts . parseConfigFileTextToJson ( configFilename , contents ) ;
1344
- if ( rawConfig . error ) {
1345
- return { succeeded : false , errors : [ rawConfig . error ] } ;
1359
+ const { configJsonObject, diagnostics } = ts . parseAndReEmitConfigJSONFile ( contents ) ;
1360
+ errors = concatenate ( errors , diagnostics ) ;
1361
+ const parsedCommandLine = ts . parseJsonConfigFileContent ( configJsonObject , this . host , dirPath , /*existingOptions*/ { } , configFilename ) ;
1362
+ errors = concatenate ( errors , parsedCommandLine . errors ) ;
1363
+ Debug . assert ( ! ! parsedCommandLine . fileNames ) ;
1364
+
1365
+ if ( parsedCommandLine . fileNames . length === 0 ) {
1366
+ errors . push ( createCompilerDiagnostic ( Diagnostics . The_config_file_0_found_doesn_t_contain_any_source_files , configFilename ) ) ;
1367
+ return { errors } ;
1346
1368
}
1347
1369
else {
1348
- const parsedCommandLine = ts . parseJsonConfigFileContent ( rawConfig . config , this . host , dirPath , /*existingOptions*/ { } , configFilename ) ;
1349
- Debug . assert ( ! ! parsedCommandLine . fileNames ) ;
1350
-
1351
- if ( parsedCommandLine . fileNames . length === 0 ) {
1352
- const error = createCompilerDiagnostic ( Diagnostics . The_config_file_0_found_doesn_t_contain_any_source_files , configFilename ) ;
1353
- return { succeeded : false , errors : concatenate ( parsedCommandLine . errors , [ error ] ) } ;
1354
- }
1355
- else {
1356
- // if the project has some files, we can continue with the parsed options and tolerate
1357
- // errors in the parsedCommandLine
1358
- const projectOptions : ProjectOptions = {
1359
- files : parsedCommandLine . fileNames ,
1360
- wildcardDirectories : parsedCommandLine . wildcardDirectories ,
1361
- compilerOptions : parsedCommandLine . options ,
1362
- } ;
1363
- return { succeeded : true , projectOptions, errors : parsedCommandLine . errors } ;
1364
- }
1370
+ // if the project has some files, we can continue with the parsed options and tolerate
1371
+ // errors in the parsedCommandLine
1372
+ const projectOptions : ProjectOptions = {
1373
+ files : parsedCommandLine . fileNames ,
1374
+ wildcardDirectories : parsedCommandLine . wildcardDirectories ,
1375
+ compilerOptions : parsedCommandLine . options ,
1376
+ } ;
1377
+ return { projectOptions, errors } ;
1365
1378
}
1366
1379
}
1367
1380
@@ -1383,65 +1396,63 @@ namespace ts.server {
1383
1396
return false ;
1384
1397
}
1385
1398
1386
- openConfigFile ( configFilename : string , clientFileName ?: string ) : { success : boolean , project ?: Project , errors : Diagnostic [ ] } {
1387
- const { succeeded , projectOptions , errors : errorsFromConfigFile } = this . configFileToProjectOptions ( configFilename ) ;
1388
- // Note: even if "succeeded"" is true, " errors" may still exist, as they are just tolerated
1389
- if ( ! succeeded ) {
1390
- return { success : false , errors : errorsFromConfigFile } ;
1399
+ openConfigFile ( configFilename : string , clientFileName ?: string ) : { project ?: Project , errors : Diagnostic [ ] } {
1400
+ const parseConfigFileResult = this . configFileToProjectOptions ( configFilename ) ;
1401
+ let errors = parseConfigFileResult . errors ;
1402
+ if ( ! parseConfigFileResult . projectOptions ) {
1403
+ return { errors } ;
1391
1404
}
1392
- else {
1393
- if ( ! projectOptions . compilerOptions . disableSizeLimit && projectOptions . compilerOptions . allowJs ) {
1394
- if ( this . exceedTotalNonTsFileSizeLimit ( projectOptions . files ) ) {
1395
- const project = this . createProject ( configFilename , projectOptions , /*languageServiceDisabled*/ true ) ;
1396
-
1397
- // for configured projects with languageService disabled, we only watch its config file,
1398
- // do not care about the directory changes in the folder.
1399
- project . projectFileWatcher = this . host . watchFile (
1400
- toPath ( configFilename , configFilename , createGetCanonicalFileName ( sys . useCaseSensitiveFileNames ) ) ,
1401
- _ => this . watchedProjectConfigFileChanged ( project ) ) ;
1402
- return { success : true , project, errors : errorsFromConfigFile } ;
1403
- }
1405
+ const projectOptions = parseConfigFileResult . projectOptions ;
1406
+ if ( ! projectOptions . compilerOptions . disableSizeLimit && projectOptions . compilerOptions . allowJs ) {
1407
+ if ( this . exceedTotalNonTsFileSizeLimit ( projectOptions . files ) ) {
1408
+ const project = this . createProject ( configFilename , projectOptions , /*languageServiceDisabled*/ true ) ;
1409
+
1410
+ // for configured projects with languageService disabled, we only watch its config file,
1411
+ // do not care about the directory changes in the folder.
1412
+ project . projectFileWatcher = this . host . watchFile (
1413
+ toPath ( configFilename , configFilename , createGetCanonicalFileName ( sys . useCaseSensitiveFileNames ) ) ,
1414
+ _ => this . watchedProjectConfigFileChanged ( project ) ) ;
1415
+ return { project, errors } ;
1404
1416
}
1417
+ }
1405
1418
1406
- const project = this . createProject ( configFilename , projectOptions ) ;
1407
- let errors : Diagnostic [ ] ;
1408
- for ( const rootFilename of projectOptions . files ) {
1409
- if ( this . host . fileExists ( rootFilename ) ) {
1410
- const info = this . openFile ( rootFilename , /*openedByClient*/ clientFileName == rootFilename ) ;
1411
- project . addRoot ( info ) ;
1412
- }
1413
- else {
1414
- ( errors || ( errors = [ ] ) ) . push ( createCompilerDiagnostic ( Diagnostics . File_0_not_found , rootFilename ) ) ;
1415
- }
1419
+ const project = this . createProject ( configFilename , projectOptions ) ;
1420
+ for ( const rootFilename of projectOptions . files ) {
1421
+ if ( this . host . fileExists ( rootFilename ) ) {
1422
+ const info = this . openFile ( rootFilename , /*openedByClient*/ clientFileName == rootFilename ) ;
1423
+ project . addRoot ( info ) ;
1424
+ }
1425
+ else {
1426
+ ( errors || ( errors = [ ] ) ) . push ( createCompilerDiagnostic ( Diagnostics . File_0_not_found , rootFilename ) ) ;
1416
1427
}
1417
- project . finishGraph ( ) ;
1418
- project . projectFileWatcher = this . host . watchFile ( configFilename , _ => this . watchedProjectConfigFileChanged ( project ) ) ;
1428
+ }
1429
+ project . finishGraph ( ) ;
1430
+ project . projectFileWatcher = this . host . watchFile ( configFilename , _ => this . watchedProjectConfigFileChanged ( project ) ) ;
1419
1431
1420
- const configDirectoryPath = ts . getDirectoryPath ( configFilename ) ;
1432
+ const configDirectoryPath = ts . getDirectoryPath ( configFilename ) ;
1421
1433
1422
- this . log ( "Add recursive watcher for: " + configDirectoryPath ) ;
1423
- project . directoryWatcher = this . host . watchDirectory (
1424
- configDirectoryPath ,
1425
- path => this . directoryWatchedForSourceFilesChanged ( project , path ) ,
1426
- /*recursive*/ true
1427
- ) ;
1434
+ this . log ( "Add recursive watcher for: " + configDirectoryPath ) ;
1435
+ project . directoryWatcher = this . host . watchDirectory (
1436
+ configDirectoryPath ,
1437
+ path => this . directoryWatchedForSourceFilesChanged ( project , path ) ,
1438
+ /*recursive*/ true
1439
+ ) ;
1428
1440
1429
- project . directoriesWatchedForWildcards = reduceProperties ( createMap ( projectOptions . wildcardDirectories ) , ( watchers , flag , directory ) => {
1430
- if ( comparePaths ( configDirectoryPath , directory , "." , ! this . host . useCaseSensitiveFileNames ) !== Comparison . EqualTo ) {
1431
- const recursive = ( flag & WatchDirectoryFlags . Recursive ) !== 0 ;
1432
- this . log ( `Add ${ recursive ? "recursive " : "" } watcher for: ${ directory } ` ) ;
1433
- watchers [ directory ] = this . host . watchDirectory (
1434
- directory ,
1435
- path => this . directoryWatchedForSourceFilesChanged ( project , path ) ,
1436
- recursive
1437
- ) ;
1438
- }
1441
+ project . directoriesWatchedForWildcards = reduceProperties ( createMap ( projectOptions . wildcardDirectories ) , ( watchers , flag , directory ) => {
1442
+ if ( comparePaths ( configDirectoryPath , directory , "." , ! this . host . useCaseSensitiveFileNames ) !== Comparison . EqualTo ) {
1443
+ const recursive = ( flag & WatchDirectoryFlags . Recursive ) !== 0 ;
1444
+ this . log ( `Add ${ recursive ? "recursive " : "" } watcher for: ${ directory } ` ) ;
1445
+ watchers [ directory ] = this . host . watchDirectory (
1446
+ directory ,
1447
+ path => this . directoryWatchedForSourceFilesChanged ( project , path ) ,
1448
+ recursive
1449
+ ) ;
1450
+ }
1439
1451
1440
- return watchers ;
1441
- } , < Map < FileWatcher > > { } ) ;
1452
+ return watchers ;
1453
+ } , < Map < FileWatcher > > { } ) ;
1442
1454
1443
- return { success : true , project : project , errors : concatenate ( errors , errorsFromConfigFile ) } ;
1444
- }
1455
+ return { project : project , errors } ;
1445
1456
}
1446
1457
1447
1458
updateConfiguredProject ( project : Project ) : Diagnostic [ ] {
@@ -1450,8 +1461,8 @@ namespace ts.server {
1450
1461
this . removeProject ( project ) ;
1451
1462
}
1452
1463
else {
1453
- const { succeeded , projectOptions, errors } = this . configFileToProjectOptions ( project . projectFilename ) ;
1454
- if ( ! succeeded ) {
1464
+ const { projectOptions, errors } = this . configFileToProjectOptions ( project . projectFilename ) ;
1465
+ if ( ! projectOptions ) {
1455
1466
return errors ;
1456
1467
}
1457
1468
else {
0 commit comments