@@ -702,7 +702,8 @@ namespace ts.server {
702702 }
703703
704704 handleProjectFileListChanges ( project : Project ) {
705- const { projectOptions } = this . configFileToProjectOptions ( project . projectFilename ) ;
705+ const { projectOptions, errors } = this . configFileToProjectOptions ( project . projectFilename ) ;
706+ this . reportConfigFileDiagnostics ( project . projectFilename , errors ) ;
706707
707708 const newRootFiles = projectOptions . files . map ( ( f => this . getCanonicalFileName ( f ) ) ) ;
708709 const currentRootFiles = project . getRootFiles ( ) . map ( ( f => this . getCanonicalFileName ( f ) ) ) ;
@@ -720,18 +721,32 @@ namespace ts.server {
720721 }
721722 }
722723
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+
723733 /**
724734 * This is the callback function when a watched directory has an added tsconfig file.
725735 */
726736 directoryWatchedForTsconfigChanged ( fileName : string ) {
727- if ( ts . getBaseFileName ( fileName ) != "tsconfig.json" ) {
737+ if ( ts . getBaseFileName ( fileName ) !== "tsconfig.json" ) {
728738 this . log ( fileName + " is not tsconfig.json" ) ;
729739 return ;
730740 }
731741
732742 this . log ( "Detected newly added tsconfig file: " + fileName ) ;
733743
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+ }
735750
736751 const rootFilesInTsconfig = projectOptions . files . map ( f => this . getCanonicalFileName ( f ) ) ;
737752 const openFileRoots = this . openFileRoots . map ( s => this . getCanonicalFileName ( s . fileName ) ) ;
@@ -1224,7 +1239,7 @@ namespace ts.server {
12241239 const project = this . findConfiguredProjectByConfigFile ( configFileName ) ;
12251240 if ( ! project ) {
12261241 const configResult = this . openConfigFile ( configFileName , fileName ) ;
1227- if ( ! configResult . success ) {
1242+ if ( ! configResult . project ) {
12281243 return { configFileName, configFileErrors : configResult . errors } ;
12291244 }
12301245 else {
@@ -1335,33 +1350,31 @@ namespace ts.server {
13351350 return undefined ;
13361351 }
13371352
1338- configFileToProjectOptions ( configFilename : string ) : { succeeded : boolean , projectOptions ?: ProjectOptions , errors : Diagnostic [ ] } {
1353+ configFileToProjectOptions ( configFilename : string ) : { projectOptions ?: ProjectOptions , errors : Diagnostic [ ] } {
13391354 configFilename = ts . normalizePath ( configFilename ) ;
1355+ let errors : Diagnostic [ ] = [ ] ;
13401356 // file references will be relative to dirPath (or absolute)
13411357 const dirPath = ts . getDirectoryPath ( configFilename ) ;
13421358 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 } ;
13461368 }
13471369 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 } ;
13651378 }
13661379 }
13671380
@@ -1383,65 +1396,63 @@ namespace ts.server {
13831396 return false ;
13841397 }
13851398
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 } ;
13911404 }
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 } ;
14041416 }
1417+ }
14051418
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 ) ) ;
14161427 }
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 ) ) ;
14191431
1420- const configDirectoryPath = ts . getDirectoryPath ( configFilename ) ;
1432+ const configDirectoryPath = ts . getDirectoryPath ( configFilename ) ;
14211433
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+ ) ;
14281440
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+ }
14391451
1440- return watchers ;
1441- } , < Map < FileWatcher > > { } ) ;
1452+ return watchers ;
1453+ } , < Map < FileWatcher > > { } ) ;
14421454
1443- return { success : true , project : project , errors : concatenate ( errors , errorsFromConfigFile ) } ;
1444- }
1455+ return { project : project , errors } ;
14451456 }
14461457
14471458 updateConfiguredProject ( project : Project ) : Diagnostic [ ] {
@@ -1450,8 +1461,8 @@ namespace ts.server {
14501461 this . removeProject ( project ) ;
14511462 }
14521463 else {
1453- const { succeeded , projectOptions, errors } = this . configFileToProjectOptions ( project . projectFilename ) ;
1454- if ( ! succeeded ) {
1464+ const { projectOptions, errors } = this . configFileToProjectOptions ( project . projectFilename ) ;
1465+ if ( ! projectOptions ) {
14551466 return errors ;
14561467 }
14571468 else {
0 commit comments