@@ -173,6 +173,84 @@ type Project struct {
173173 installedTypingsInfo * ata.TypingsInfo
174174 // typingsFiles are the root files added by the typings installer.
175175 typingsFiles []string
176+ // installedTypingsFileNames are the JavaScript files used during the most
177+ // recently completed typings installation.
178+ installedTypingsFileNames []string
179+ // installedTypingsFilesToWatch are discovery inputs whose changes require
180+ // typings discovery to run again.
181+ installedTypingsFilesToWatch []string
182+ // ataInvalidationSnapshotID is the latest snapshot that invalidated this
183+ // project's ATA discovery inputs.
184+ ataInvalidationSnapshotID uint64
185+ }
186+
187+ type inferredProjectATAState struct {
188+ installedTypingsInfo * ata.TypingsInfo
189+ installedTypingsFileNames []string
190+ installedTypingsFilesToWatch []string
191+ typingsFiles []string
192+ typingsWatch * WatchedFiles [PatternsAndIgnored ]
193+ }
194+
195+ func (p * Project ) inferredProjectATAState () * inferredProjectATAState {
196+ if p .installedTypingsInfo == nil && len (p .installedTypingsFilesToWatch ) == 0 {
197+ return nil
198+ }
199+ return & inferredProjectATAState {
200+ installedTypingsInfo : p .installedTypingsInfo ,
201+ installedTypingsFileNames : slices .Clone (p .installedTypingsFileNames ),
202+ installedTypingsFilesToWatch : slices .Clone (p .installedTypingsFilesToWatch ),
203+ typingsFiles : slices .Clone (p .typingsFiles ),
204+ typingsWatch : p .typingsWatch ,
205+ }
206+ }
207+
208+ func (s * inferredProjectATAState ) canApply (project * Project , fs * snapshotFSBuilder , watchEnabled bool ) bool {
209+ if s == nil || s .installedTypingsInfo == nil {
210+ return false
211+ }
212+ if ! watchEnabled && len (s .installedTypingsFilesToWatch ) > 0 {
213+ return false
214+ }
215+ if ! s .installedTypingsInfo .Equals (project .ComputeTypingsInfo ()) ||
216+ ! slices .Equal (s .installedTypingsFileNames , project .ComputeTypingsFileNames ()) {
217+ return false
218+ }
219+ for _ , fileName := range s .typingsFiles {
220+ if ! fs .FileExists (fileName , fs .toPath (fileName )) {
221+ return false
222+ }
223+ }
224+ return true
225+ }
226+
227+ func (s * inferredProjectATAState ) apply (project * Project ) {
228+ typingsFilesChanged := ! slices .Equal (project .typingsFiles , s .typingsFiles )
229+ project .installedTypingsInfo = s .installedTypingsInfo
230+ project .installedTypingsFileNames = slices .Clone (s .installedTypingsFileNames )
231+ project .installedTypingsFilesToWatch = slices .Clone (s .installedTypingsFilesToWatch )
232+ project .typingsFiles = slices .Clone (s .typingsFiles )
233+ project .typingsWatch = s .typingsWatch
234+ if typingsFilesChanged {
235+ project .dirty = true
236+ project .dirtyFilePath = ""
237+ }
238+ }
239+
240+ func (s * inferredProjectATAState ) canApplyWatchState (project * Project , watchEnabled bool ) bool {
241+ return s != nil &&
242+ s .installedTypingsInfo == nil &&
243+ watchEnabled &&
244+ slices .Equal (s .installedTypingsFileNames , project .ComputeTypingsFileNames ())
245+ }
246+
247+ func (s * inferredProjectATAState ) applyWatchState (project * Project ) {
248+ project .installedTypingsFileNames = slices .Clone (s .installedTypingsFileNames )
249+ project .installedTypingsFilesToWatch = slices .Concat (
250+ slices .Clone (s .installedTypingsFilesToWatch ),
251+ s .typingsFiles ,
252+ )
253+ project .typingsWatch = s .typingsWatch
176254}
177255
178256var _ ls.Project = (* Project )(nil )
@@ -203,6 +281,7 @@ func NewInferredProject(
203281 logger * logging.LogTree ,
204282) * Project {
205283 p := NewProject (inferredProjectID .AsID (), KindInferred , currentDirectory , builder , logger )
284+ p .ataInvalidationSnapshotID = builder .inferredProjectATAInvalidationSnapshotID
206285 if compilerOptions == nil {
207286 compilerOptions = & core.CompilerOptions {
208287 AllowJs : core .TSTrue ,
@@ -278,10 +357,11 @@ func NewProject(
278357 logger .Log (fmt .Sprintf ("Creating %sProject: %s, currentDirectory: %s" , kind .String (), id , currentDirectory ))
279358 }
280359 project := & Project {
281- Kind : kind ,
282- id : id ,
283- currentDirectory : currentDirectory ,
284- dirty : true ,
360+ Kind : kind ,
361+ id : id ,
362+ currentDirectory : currentDirectory ,
363+ dirty : true ,
364+ ataInvalidationSnapshotID : builder .newSnapshotID ,
285365 }
286366
287367 project .programFilesWatch = NewWatchedFiles (
@@ -291,12 +371,7 @@ func NewProject(
291371 createResolutionLookupGlobMapper (builder .sessionOptions .CurrentDirectory , builder .sessionOptions .DefaultLibraryPath , project .currentDirectory , builder .fs .fs .UseCaseSensitiveFileNames ()),
292372 )
293373 if builder .sessionOptions .TypingsLocation != "" {
294- project .typingsWatch = NewWatchedFiles (
295- "typings installer files" ,
296- lsproto .WatchKindCreate | lsproto .WatchKindChange | lsproto .WatchKindDelete ,
297- lsproto .GetClientCapabilities (builder .ctx ).Workspace .DidChangeWatchedFiles .RelativePatternSupport ,
298- core .Identity ,
299- )
374+ project .typingsWatch = newTypingsWatch (builder )
300375 }
301376 project .contentMapperWatch = NewWatchedFilesForPaths (
302377 "content mapper configuration files for " + string (id ),
@@ -309,6 +384,15 @@ func NewProject(
309384 return project
310385}
311386
387+ func newTypingsWatch (builder * ProjectCollectionBuilder ) * WatchedFiles [PatternsAndIgnored ] {
388+ return NewWatchedFiles (
389+ "typings installer files" ,
390+ lsproto .WatchKindCreate | lsproto .WatchKindChange | lsproto .WatchKindDelete ,
391+ lsproto .GetClientCapabilities (builder .ctx ).Workspace .DidChangeWatchedFiles .RelativePatternSupport ,
392+ core .Identity ,
393+ )
394+ }
395+
312396func (p * Project ) CurrentDirectory () string {
313397 return p .currentDirectory
314398}
@@ -418,8 +502,11 @@ func (p *Project) Clone() *Project {
418502 moduleResolverFactory : p .moduleResolverFactory ,
419503 moduleResolverID : p .moduleResolverID ,
420504
421- installedTypingsInfo : p .installedTypingsInfo ,
422- typingsFiles : p .typingsFiles ,
505+ installedTypingsInfo : p .installedTypingsInfo ,
506+ installedTypingsFileNames : p .installedTypingsFileNames ,
507+ installedTypingsFilesToWatch : p .installedTypingsFilesToWatch ,
508+ typingsFiles : p .typingsFiles ,
509+ ataInvalidationSnapshotID : p .ataInvalidationSnapshotID ,
423510 }
424511}
425512
@@ -666,7 +753,8 @@ func (p *Project) ShouldTriggerATA(snapshotID uint64) bool {
666753 return true
667754 }
668755
669- return ! p .installedTypingsInfo .Equals (p .ComputeTypingsInfo ())
756+ return ! p .installedTypingsInfo .Equals (p .ComputeTypingsInfo ()) ||
757+ ! slices .Equal (p .installedTypingsFileNames , p .ComputeTypingsFileNames ())
670758}
671759
672760func (p * Project ) ComputeTypingsInfo () ata.TypingsInfo {
@@ -676,3 +764,17 @@ func (p *Project) ComputeTypingsInfo() ata.TypingsInfo {
676764 UnresolvedImports : p .GetUnresolvedImports (),
677765 }
678766}
767+
768+ func (p * Project ) ComputeTypingsFileNames () []string {
769+ if p .Program == nil {
770+ return nil
771+ }
772+ var fileNames []string
773+ for _ , file := range p .Program .GetSourceFiles () {
774+ if tspath .HasJSFileExtension (file .FileName ()) && ! p .Program .IsSourceFileFromExternalLibrary (file ) {
775+ fileNames = append (fileNames , file .FileName ())
776+ }
777+ }
778+ slices .Sort (fileNames )
779+ return fileNames
780+ }
0 commit comments