@@ -90,6 +90,7 @@ namespace ts.server {
9090 export interface HostConfiguration {
9191 formatCodeOptions : FormatCodeSettings ;
9292 hostInfo : string ;
93+ fileExtensionMap ?: FileExtensionMap ;
9394 }
9495
9596 interface ConfigFileConversionResult {
@@ -114,13 +115,13 @@ namespace ts.server {
114115 interface FilePropertyReader < T > {
115116 getFileName ( f : T ) : string ;
116117 getScriptKind ( f : T ) : ScriptKind ;
117- hasMixedContent ( f : T ) : boolean ;
118+ hasMixedContent ( f : T , mixedContentExtensions : string [ ] ) : boolean ;
118119 }
119120
120121 const fileNamePropertyReader : FilePropertyReader < string > = {
121122 getFileName : x => x ,
122123 getScriptKind : _ => undefined ,
123- hasMixedContent : _ => false
124+ hasMixedContent : ( fileName , mixedContentExtensions ) => forEach ( mixedContentExtensions , extension => fileExtensionIs ( fileName , extension ) )
124125 } ;
125126
126127 const externalFilePropertyReader : FilePropertyReader < protocol . ExternalFile > = {
@@ -235,12 +236,12 @@ namespace ts.server {
235236 private readonly directoryWatchers : DirectoryWatchers ;
236237 private readonly throttledOperations : ThrottledOperations ;
237238
238- private readonly hostConfiguration : HostConfiguration ;
239-
240239 private changedFiles : ScriptInfo [ ] ;
241240
242241 private toCanonicalFileName : ( f : string ) => string ;
243242
243+ public readonly hostConfiguration : HostConfiguration ;
244+
244245 public lastDeletedFile : ScriptInfo ;
245246
246247 constructor ( public readonly host : ServerHost ,
@@ -264,7 +265,8 @@ namespace ts.server {
264265
265266 this . hostConfiguration = {
266267 formatCodeOptions : getDefaultFormatCodeSettings ( this . host ) ,
267- hostInfo : "Unknown host"
268+ hostInfo : "Unknown host" ,
269+ fileExtensionMap : { }
268270 } ;
269271
270272 this . documentRegistry = createDocumentRegistry ( host . useCaseSensitiveFileNames , host . getCurrentDirectory ( ) ) ;
@@ -455,7 +457,7 @@ namespace ts.server {
455457 // If a change was made inside "folder/file", node will trigger the callback twice:
456458 // one with the fileName being "folder/file", and the other one with "folder".
457459 // We don't respond to the second one.
458- if ( fileName && ! ts . isSupportedSourceFileName ( fileName , project . getCompilerOptions ( ) ) ) {
460+ if ( fileName && ! ts . isSupportedSourceFileName ( fileName , project . getCompilerOptions ( ) , this . hostConfiguration . fileExtensionMap ) ) {
459461 return ;
460462 }
461463
@@ -610,6 +612,9 @@ namespace ts.server {
610612 let projectsToRemove : Project [ ] ;
611613 for ( const p of info . containingProjects ) {
612614 if ( p . projectKind === ProjectKind . Configured ) {
615+ if ( info . hasMixedContent ) {
616+ info . hasChanges = true ;
617+ }
613618 // last open file in configured project - close it
614619 if ( ( < ConfiguredProject > p ) . deleteOpenRef ( ) === 0 ) {
615620 ( projectsToRemove || ( projectsToRemove = [ ] ) ) . push ( p ) ;
@@ -772,7 +777,9 @@ namespace ts.server {
772777 this . host ,
773778 getDirectoryPath ( configFilename ) ,
774779 /*existingOptions*/ { } ,
775- configFilename ) ;
780+ configFilename ,
781+ /*resolutionStack*/ [ ] ,
782+ this . hostConfiguration . fileExtensionMap ) ;
776783
777784 if ( parsedCommandLine . errors . length ) {
778785 errors = concatenate ( errors , parsedCommandLine . errors ) ;
@@ -876,7 +883,7 @@ namespace ts.server {
876883 for ( const f of files ) {
877884 const rootFilename = propertyReader . getFileName ( f ) ;
878885 const scriptKind = propertyReader . getScriptKind ( f ) ;
879- const hasMixedContent = propertyReader . hasMixedContent ( f ) ;
886+ const hasMixedContent = propertyReader . hasMixedContent ( f , this . hostConfiguration . fileExtensionMap . mixedContent ) ;
880887 if ( this . host . fileExists ( rootFilename ) ) {
881888 const info = this . getOrCreateScriptInfoForNormalizedPath ( toNormalizedPath ( rootFilename ) , /*openedByClient*/ clientFileName == rootFilename , /*fileContent*/ undefined , scriptKind , hasMixedContent ) ;
882889 project . addRoot ( info ) ;
@@ -922,7 +929,7 @@ namespace ts.server {
922929 rootFilesChanged = true ;
923930 if ( ! scriptInfo ) {
924931 const scriptKind = propertyReader . getScriptKind ( f ) ;
925- const hasMixedContent = propertyReader . hasMixedContent ( f ) ;
932+ const hasMixedContent = propertyReader . hasMixedContent ( f , this . hostConfiguration . fileExtensionMap . mixedContent ) ;
926933 scriptInfo = this . getOrCreateScriptInfoForNormalizedPath ( normalizedPath , /*openedByClient*/ false , /*fileContent*/ undefined , scriptKind , hasMixedContent ) ;
927934 }
928935 }
@@ -1072,6 +1079,9 @@ namespace ts.server {
10721079 }
10731080 if ( openedByClient ) {
10741081 info . isOpen = true ;
1082+ if ( hasMixedContent ) {
1083+ info . hasChanges = true ;
1084+ }
10751085 }
10761086 }
10771087 return info ;
@@ -1103,6 +1113,10 @@ namespace ts.server {
11031113 mergeMaps ( this . hostConfiguration . formatCodeOptions , convertFormatOptions ( args . formatOptions ) ) ;
11041114 this . logger . info ( "Format host information updated" ) ;
11051115 }
1116+ if ( args . fileExtensionMap ) {
1117+ this . hostConfiguration . fileExtensionMap = args . fileExtensionMap ;
1118+ this . logger . info ( "Host file extension mappings updated" ) ;
1119+ }
11061120 }
11071121 }
11081122
@@ -1168,12 +1182,12 @@ namespace ts.server {
11681182 }
11691183
11701184 openClientFileWithNormalizedPath ( fileName : NormalizedPath , fileContent ?: string , scriptKind ?: ScriptKind , hasMixedContent ?: boolean ) : OpenConfiguredProjectResult {
1185+ const info = this . getOrCreateScriptInfoForNormalizedPath ( fileName , /*openedByClient*/ true , fileContent , scriptKind , hasMixedContent ) ;
11711186 const { configFileName = undefined , configFileErrors = undefined } : OpenConfiguredProjectResult = this . findContainingExternalProject ( fileName )
11721187 ? { }
11731188 : this . openOrUpdateConfiguredProjectForFile ( fileName ) ;
11741189
11751190 // at this point if file is the part of some configured/external project then this project should be created
1176- const info = this . getOrCreateScriptInfoForNormalizedPath ( fileName , /*openedByClient*/ true , fileContent , scriptKind , hasMixedContent ) ;
11771191 this . assignScriptInfoToInferredProjectIfNecessary ( info , /*addToListOfOpenFiles*/ true ) ;
11781192 this . printProjects ( ) ;
11791193 return { configFileName, configFileErrors } ;
0 commit comments