@@ -342,6 +342,7 @@ namespace ts.server {
342342 FailedLookupLocation = "Directory of Failed lookup locations in module resolution" ,
343343 TypeRoots = "Type root directory" ,
344344 NodeModulesForClosedScriptInfo = "node_modules for closed script infos in them" ,
345+ MissingSourceMapFile = "Missing source map file"
345346 }
346347
347348 const enum ConfigFileWatcherStatus {
@@ -953,22 +954,25 @@ namespace ts.server {
953954 private handleSourceMapProjects ( info : ScriptInfo ) {
954955 // Change in d.ts, update source projects as well
955956 if ( info . sourceMapFilePath ) {
956- const sourceMapFileInfo = this . getScriptInfoForPath ( info . sourceMapFilePath ) ;
957- if ( sourceMapFileInfo && sourceMapFileInfo . sourceInfos ) {
958- this . delayUpdateSourceInfoProjects ( sourceMapFileInfo . sourceInfos ) ;
957+ if ( isString ( info . sourceMapFilePath ) ) {
958+ const sourceMapFileInfo = this . getScriptInfoForPath ( info . sourceMapFilePath ) ;
959+ this . delayUpdateSourceInfoProjects ( sourceMapFileInfo && sourceMapFileInfo . sourceInfos ) ;
960+ }
961+ else {
962+ this . delayUpdateSourceInfoProjects ( info . sourceMapFilePath . sourceInfos ) ;
959963 }
960964 }
961965 // Change in mapInfo, update declarationProjects and source projects
962- if ( info . sourceInfos ) {
963- this . delayUpdateSourceInfoProjects ( info . sourceInfos ) ;
964- }
966+ this . delayUpdateSourceInfoProjects ( info . sourceInfos ) ;
965967 if ( info . declarationInfoPath ) {
966968 this . delayUpdateProjectsOfScriptInfoPath ( info . declarationInfoPath ) ;
967969 }
968970 }
969971
970- private delayUpdateSourceInfoProjects ( sourceInfos : Map < true > ) {
971- sourceInfos . forEach ( ( _value , path ) => this . delayUpdateProjectsOfScriptInfoPath ( path as Path ) ) ;
972+ private delayUpdateSourceInfoProjects ( sourceInfos : Map < true > | undefined ) {
973+ if ( sourceInfos ) {
974+ sourceInfos . forEach ( ( _value , path ) => this . delayUpdateProjectsOfScriptInfoPath ( path as Path ) ) ;
975+ }
972976 }
973977
974978 private delayUpdateProjectsOfScriptInfoPath ( path : Path ) {
@@ -992,6 +996,14 @@ namespace ts.server {
992996 // update projects to make sure that set of referenced files is correct
993997 this . delayUpdateProjectGraphs ( containingProjects ) ;
994998 this . handleSourceMapProjects ( info ) ;
999+ info . closeSourceMapFileWatcher ( ) ;
1000+ // need to recalculate source map from declaration file
1001+ if ( info . declarationInfoPath ) {
1002+ const declarationInfo = this . getScriptInfoForPath ( info . declarationInfoPath ) ;
1003+ if ( declarationInfo ) {
1004+ declarationInfo . sourceMapFilePath = undefined ;
1005+ }
1006+ }
9951007 }
9961008 }
9971009
@@ -2228,32 +2240,43 @@ namespace ts.server {
22282240
22292241 /*@internal */
22302242 getDocumentPositionMapper ( project : Project , generatedFileName : string , sourceFileName ?: string ) : DocumentPositionMapper | undefined {
2231- const declarationInfo = this . getOrCreateScriptInfoNotOpenedByClient ( generatedFileName , project . currentDirectory , project . directoryStructureHost ) ;
2243+ // Since declaration info and map file watches arent updating project's directory structure host (which can cache file structure) use host
2244+ const declarationInfo = this . getOrCreateScriptInfoNotOpenedByClient ( generatedFileName , project . currentDirectory , this . host ) ;
22322245 if ( ! declarationInfo ) return undefined ;
22332246
22342247 // Try to get from cache
22352248 declarationInfo . getSnapshot ( ) ; // Ensure synchronized
2236- if ( declarationInfo . sourceMapFilePath !== undefined ) {
2237- // Doesnt have sourceMap
2238- if ( ! declarationInfo . sourceMapFilePath ) return undefined ;
2239-
2249+ if ( isString ( declarationInfo . sourceMapFilePath ) ) {
22402250 // Ensure mapper is synchronized
2241- const mapFileInfo = this . getScriptInfoForPath ( declarationInfo . sourceMapFilePath ) ;
2242- if ( mapFileInfo ) {
2243- mapFileInfo . getSnapshot ( ) ;
2244- if ( mapFileInfo . documentPositionMapper !== undefined ) {
2245- return mapFileInfo . documentPositionMapper ? mapFileInfo . documentPositionMapper : undefined ;
2251+ const sourceMapFileInfo = this . getScriptInfoForPath ( declarationInfo . sourceMapFilePath ) ;
2252+ if ( sourceMapFileInfo ) {
2253+ sourceMapFileInfo . getSnapshot ( ) ;
2254+ if ( sourceMapFileInfo . documentPositionMapper !== undefined ) {
2255+ sourceMapFileInfo . sourceInfos = this . addSourceInfoToSourceMap ( sourceFileName , project , sourceMapFileInfo . sourceInfos ) ;
2256+ return sourceMapFileInfo . documentPositionMapper ? sourceMapFileInfo . documentPositionMapper : undefined ;
22462257 }
22472258 }
2259+ declarationInfo . sourceMapFilePath = undefined ;
2260+ }
2261+ else if ( declarationInfo . sourceMapFilePath ) {
2262+ declarationInfo . sourceMapFilePath . sourceInfos = this . addSourceInfoToSourceMap ( sourceFileName , project , declarationInfo . sourceMapFilePath . sourceInfos ) ;
2263+ return undefined ;
2264+ }
2265+ else if ( declarationInfo . sourceMapFilePath !== undefined ) {
2266+ // Doesnt have sourceMap
2267+ return undefined ;
22482268 }
22492269
22502270 // Create the mapper
2251- declarationInfo . sourceMapFilePath = undefined ;
22522271 let sourceMapFileInfo : ScriptInfo | undefined ;
2272+ let mapFileNameFromDeclarationInfo : string | undefined ;
22532273
2254- let readMapFile : ReadMapFile | undefined = mapFileName => {
2255- const mapInfo = this . getOrCreateScriptInfoNotOpenedByClient ( mapFileName , project . currentDirectory , project . directoryStructureHost ) ;
2256- if ( ! mapInfo ) return undefined ;
2274+ let readMapFile : ReadMapFile | undefined = ( mapFileName , mapFileNameFromDts ) => {
2275+ const mapInfo = this . getOrCreateScriptInfoNotOpenedByClient ( mapFileName , project . currentDirectory , this . host ) ;
2276+ if ( ! mapInfo ) {
2277+ mapFileNameFromDeclarationInfo = mapFileNameFromDts ;
2278+ return undefined ;
2279+ }
22572280 sourceMapFileInfo = mapInfo ;
22582281 const snap = mapInfo . getSnapshot ( ) ;
22592282 if ( mapInfo . documentPositionMapper !== undefined ) return mapInfo . documentPositionMapper ;
@@ -2271,18 +2294,54 @@ namespace ts.server {
22712294 declarationInfo . sourceMapFilePath = sourceMapFileInfo . path ;
22722295 sourceMapFileInfo . declarationInfoPath = declarationInfo . path ;
22732296 sourceMapFileInfo . documentPositionMapper = documentPositionMapper || false ;
2274- if ( sourceFileName && documentPositionMapper ) {
2275- // Attach as source
2276- const sourceInfo = this . getOrCreateScriptInfoNotOpenedByClient ( sourceFileName , project . currentDirectory , project . directoryStructureHost ) ! ;
2277- ( sourceMapFileInfo . sourceInfos || ( sourceMapFileInfo . sourceInfos = createMap ( ) ) ) . set ( sourceInfo . path , true ) ;
2278- }
2297+ sourceMapFileInfo . sourceInfos = this . addSourceInfoToSourceMap ( sourceFileName , project , sourceMapFileInfo . sourceInfos ) ;
2298+ }
2299+ else if ( mapFileNameFromDeclarationInfo ) {
2300+ declarationInfo . sourceMapFilePath = {
2301+ declarationInfoPath : declarationInfo . path ,
2302+ watcher : this . addMissingSourceMapFile (
2303+ project . currentDirectory === this . currentDirectory ?
2304+ mapFileNameFromDeclarationInfo :
2305+ getNormalizedAbsolutePath ( mapFileNameFromDeclarationInfo , project . currentDirectory ) ,
2306+ declarationInfo . path
2307+ ) ,
2308+ sourceInfos : this . addSourceInfoToSourceMap ( sourceFileName , project )
2309+ } ;
22792310 }
22802311 else {
22812312 declarationInfo . sourceMapFilePath = false ;
22822313 }
22832314 return documentPositionMapper ;
22842315 }
22852316
2317+ private addSourceInfoToSourceMap ( sourceFileName : string | undefined , project : Project , sourceInfos ?: Map < true > ) {
2318+ if ( sourceFileName ) {
2319+ // Attach as source
2320+ const sourceInfo = this . getOrCreateScriptInfoNotOpenedByClient ( sourceFileName , project . currentDirectory , project . directoryStructureHost ) ! ;
2321+ ( sourceInfos || ( sourceInfos = createMap ( ) ) ) . set ( sourceInfo . path , true ) ;
2322+ }
2323+ return sourceInfos ;
2324+ }
2325+
2326+ private addMissingSourceMapFile ( mapFileName : string , declarationInfoPath : Path ) {
2327+ const fileWatcher = this . watchFactory . watchFile (
2328+ this . host ,
2329+ mapFileName ,
2330+ ( ) => {
2331+ const declarationInfo = this . getScriptInfoForPath ( declarationInfoPath ) ;
2332+ if ( declarationInfo && declarationInfo . sourceMapFilePath && ! isString ( declarationInfo . sourceMapFilePath ) ) {
2333+ // Update declaration and source projects
2334+ this . delayUpdateProjectGraphs ( declarationInfo . containingProjects ) ;
2335+ this . delayUpdateSourceInfoProjects ( declarationInfo . sourceMapFilePath . sourceInfos ) ;
2336+ declarationInfo . closeSourceMapFileWatcher ( ) ;
2337+ }
2338+ } ,
2339+ PollingInterval . High ,
2340+ WatchType . MissingSourceMapFile ,
2341+ ) ;
2342+ return fileWatcher ;
2343+ }
2344+
22862345 /*@internal */
22872346 getSourceFileLike ( fileName : string , projectNameOrProject : string | Project , declarationInfo ?: ScriptInfo ) {
22882347 const project = ( projectNameOrProject as Project ) . projectName ? projectNameOrProject as Project : this . findProject ( projectNameOrProject as string ) ;
@@ -2297,7 +2356,7 @@ namespace ts.server {
22972356 if ( ! info ) return undefined ;
22982357
22992358 // Attach as source
2300- if ( declarationInfo && declarationInfo . sourceMapFilePath && info !== declarationInfo ) {
2359+ if ( declarationInfo && isString ( declarationInfo . sourceMapFilePath ) && info !== declarationInfo ) {
23012360 const sourceMapInfo = this . getScriptInfoForPath ( declarationInfo . sourceMapFilePath ) ;
23022361 if ( sourceMapInfo ) {
23032362 ( sourceMapInfo . sourceInfos || ( sourceMapInfo . sourceInfos = createMap ( ) ) ) . set ( info . path , true ) ;
@@ -2669,11 +2728,18 @@ namespace ts.server {
26692728 if ( ! info . isScriptOpen ( ) && info . isOrphan ( ) ) {
26702729 // Otherwise if there is any source info that is alive, this alive too
26712730 if ( ! info . sourceMapFilePath ) return ;
2672- const sourceMapInfo = this . getScriptInfoForPath ( info . sourceMapFilePath ) ;
2673- if ( ! sourceMapInfo || ! sourceMapInfo . sourceInfos ) return ;
2674- if ( ! forEachKey ( sourceMapInfo . sourceInfos , path => {
2675- const info = this . getScriptInfoForPath ( path as Path ) ! ;
2676- return info . isScriptOpen ( ) || ! info . isOrphan ( ) ;
2731+ let sourceInfos : Map < true > | undefined ;
2732+ if ( isString ( info . sourceMapFilePath ) ) {
2733+ const sourceMapInfo = this . getScriptInfoForPath ( info . sourceMapFilePath ) ;
2734+ sourceInfos = sourceMapInfo && sourceMapInfo . sourceInfos ;
2735+ }
2736+ else {
2737+ sourceInfos = info . sourceMapFilePath . sourceInfos ;
2738+ }
2739+ if ( ! sourceInfos ) return ;
2740+ if ( ! forEachKey ( sourceInfos , path => {
2741+ const info = this . getScriptInfoForPath ( path as Path ) ;
2742+ return ! ! info && ( info . isScriptOpen ( ) || ! info . isOrphan ( ) ) ;
26772743 } ) ) {
26782744 return ;
26792745 }
@@ -2682,11 +2748,18 @@ namespace ts.server {
26822748 // Retain this script info
26832749 toRemoveScriptInfos . delete ( info . path ) ;
26842750 if ( info . sourceMapFilePath ) {
2685- // And map file info and source infos
2686- toRemoveScriptInfos . delete ( info . sourceMapFilePath ) ;
2687- const sourceMapInfo = this . getScriptInfoForPath ( info . sourceMapFilePath ) ;
2688- if ( sourceMapInfo && sourceMapInfo . sourceInfos ) {
2689- sourceMapInfo . sourceInfos . forEach ( ( _value , path ) => toRemoveScriptInfos . delete ( path ) ) ;
2751+ let sourceInfos : Map < true > | undefined ;
2752+ if ( isString ( info . sourceMapFilePath ) ) {
2753+ // And map file info and source infos
2754+ toRemoveScriptInfos . delete ( info . sourceMapFilePath ) ;
2755+ const sourceMapInfo = this . getScriptInfoForPath ( info . sourceMapFilePath ) ;
2756+ sourceInfos = sourceMapInfo && sourceMapInfo . sourceInfos ;
2757+ }
2758+ else {
2759+ sourceInfos = info . sourceMapFilePath . sourceInfos ;
2760+ }
2761+ if ( sourceInfos ) {
2762+ sourceInfos . forEach ( ( _value , path ) => toRemoveScriptInfos . delete ( path ) ) ;
26902763 }
26912764 }
26922765 } ) ;
@@ -2695,6 +2768,7 @@ namespace ts.server {
26952768 // if there are not projects that include this script info - delete it
26962769 this . stopWatchingScriptInfo ( info ) ;
26972770 this . deleteScriptInfo ( info ) ;
2771+ info . closeSourceMapFileWatcher ( ) ;
26982772 } ) ;
26992773 }
27002774
0 commit comments