@@ -2,6 +2,7 @@ package ata_test
22
33import (
44 "context"
5+ "fmt"
56 "slices"
67 "strings"
78 "sync"
@@ -441,14 +442,314 @@ func TestATA(t *testing.T) {
441442
442443 release ()
443444 session .WaitForBackgroundTasks ()
445+ snapshot , err = session .APIUpdate (ctx , project.FileChangeSummary {}, nil )
446+ assert .NilError (t , err )
447+ assert .Assert (t , snapshot .ProjectCollection .InferredProject () == nil , "the ATA result should be delivered while no inferred project exists" )
448+ snapshot .Deref ()
449+ session .DidOpenFile (ctx , uri , 1 , files ["/user/username/projects/project/app.js" ].(string ), lsproto .LanguageKindJavaScript )
450+
451+ inferred := session .Snapshot ().ProjectCollection .InferredProject ()
452+ assert .Assert (t , inferred != nil && inferred .GetProgram () != nil )
453+ typingsFile := inferred .GetProgram ().GetSourceFile (projecttestutil .TestTypingsLocation + "/node_modules/@types/jquery/index.d.ts" )
454+ assert .Assert (t , typingsFile != nil , "jquery types should be available immediately after reopening" )
455+ })
456+
457+ t .Run ("ATA install writes delivered with the result do not discard it" , func (t * testing.T ) {
458+ t .Parallel ()
459+
460+ files := map [string ]any {
461+ "/user/username/projects/a/app.js" : `` ,
462+ "/user/username/projects/a/tsconfig.json" : `{"compilerOptions":{"allowJs":true},"typeAcquisition":{"enable":true}}` ,
463+ "/user/username/projects/a/package.json" : `{"name":"a","dependencies":{"jquery":"^3.1.0"}}` ,
464+ "/user/username/projects/b/app.js" : `` ,
465+ "/user/username/projects/b/tsconfig.json" : `{"compilerOptions":{"allowJs":true},"typeAcquisition":{"enable":true}}` ,
466+ "/user/username/projects/b/package.json" : `{"name":"b","dependencies":{"commander":"^14.0.0"}}` ,
467+ }
468+ session , utils := projecttestutil .SetupWithTypingsInstaller (files , & projecttestutil.TypingsInstallerOptions {
469+ PackageToFile : map [string ]string {
470+ "commander" : `declare const commander: { x: number }` ,
471+ "jquery" : `declare const $: { x: number }` ,
472+ },
473+ })
474+ ctx := context .Background ()
475+ aURI := lsproto .DocumentUri ("file:///user/username/projects/a/app.js" )
476+ bURI := lsproto .DocumentUri ("file:///user/username/projects/b/app.js" )
477+ commanderTypings := projecttestutil .TestTypingsLocation + "/node_modules/@types/commander/index.d.ts"
478+ session .DidOpenFile (ctx , aURI , 1 , "" , lsproto .LanguageKindJavaScript )
479+ session .WaitForBackgroundTasks ()
480+ _ , err := session .GetLanguageService (ctx , aURI )
481+ assert .NilError (t , err )
482+ session .WaitForBackgroundTasks ()
483+ assert .Assert (t , utils .WatchesFile (strings .ToLower (commanderTypings )), "the typings location should be watched" )
484+
485+ session .DidOpenFile (ctx , bURI , 1 , "" , lsproto .LanguageKindJavaScript )
486+ session .WaitForBackgroundTasks ()
487+ session .DidChangeWatchedFiles (ctx , []* lsproto.FileEvent {{
488+ Uri : lsproto .DocumentUri ("file://" + commanderTypings ),
489+ Type : lsproto .FileChangeTypeCreated ,
490+ }})
491+ ls , err := session .GetLanguageService (ctx , bURI )
492+ assert .NilError (t , err )
493+ assert .Assert (t , ls .GetProgram ().GetSourceFile (tspath .RootedFilePathFromNormalized (commanderTypings )) != nil , "the install's own writes should not discard its result" )
494+ })
495+
496+ t .Run ("source edit delivered with an ATA result rejects obsolete typings" , func (t * testing.T ) {
497+ t .Parallel ()
498+
499+ files := map [string ]any {
500+ "/user/username/projects/project/app.js" : `import "jquery";` ,
501+ }
502+ session , utils := projecttestutil .SetupWithTypingsInstaller (files , & projecttestutil.TypingsInstallerOptions {
503+ PackageToFile : map [string ]string {
504+ "commander" : `declare const commander: { x: number }` ,
505+ "jquery" : `declare const $: { x: number }` ,
506+ },
507+ })
508+ originalNpmInstall := utils .NpmExecutor ().NpmInstallFunc
509+ jqueryInstallStarted := make (chan struct {}, 1 )
510+ releaseJqueryInstall := make (chan struct {})
511+ releaseCommanderInstall := make (chan struct {})
512+ var releaseOnce sync.Once
513+ releaseCommander := func () { releaseOnce .Do (func () { close (releaseCommanderInstall ) }) }
514+ defer releaseCommander ()
515+ utils .NpmExecutor ().NpmInstallFunc = func (ctx context.Context , cwd tspath.RootedDirectoryPath , args []string ) ([]byte , error ) {
516+ switch {
517+ case slices .Contains (args , "@types/jquery@latest" ):
518+ jqueryInstallStarted <- struct {}{}
519+ <- releaseJqueryInstall
520+ case slices .Contains (args , "@types/commander@latest" ):
521+ <- releaseCommanderInstall
522+ }
523+ return originalNpmInstall (ctx , cwd , args )
524+ }
525+ ctx := context .Background ()
526+ uri := lsproto .DocumentUri ("file:///user/username/projects/project/app.js" )
444527 session .DidOpenFile (ctx , uri , 1 , files ["/user/username/projects/project/app.js" ].(string ), lsproto .LanguageKindJavaScript )
528+ waitForInstall (t , jqueryInstallStarted )
529+ close (releaseJqueryInstall )
530+ session .WaitForBackgroundTasks ()
445531
532+ session .DidChangeFile (ctx , uri , 2 , []lsproto.TextDocumentContentChangePartialOrWholeDocument {{
533+ WholeDocument : & lsproto.TextDocumentContentChangeWholeDocument {Text : `import "commander";` },
534+ }})
446535 ls , err := session .GetLanguageService (ctx , uri )
447536 assert .NilError (t , err )
448- typingsFile := ls .GetProgram ().GetSourceFile (projecttestutil .TestTypingsLocation + "/node_modules/@types/jquery/index.d.ts" )
449- assert .Assert (t , typingsFile != nil , "jquery types should be available immediately after reopening" )
537+ assert .Assert (t , ls .GetProgram ().GetSourceFile (projecttestutil .TestTypingsLocation + "/node_modules/@types/jquery/index.d.ts" ) == nil )
538+ })
539+
540+ t .Run ("package-owned typings deleted with the result invalidate discovery" , func (t * testing.T ) {
541+ t .Parallel ()
542+
543+ const bundledTypes = "/user/username/projects/typings/foo.d.ts"
544+ files := map [string ]any {
545+ "/user/username/projects/project/app.js" : `import "foo";` ,
546+ "/user/username/projects/project/package.json" : `{"name":"test","dependencies":{"foo":"^1.0.0"}}` ,
547+ "/user/username/projects/project/node_modules/foo/package.json" : `{"name":"foo","types":"../../../typings/foo.d.ts"}` ,
548+ bundledTypes : `declare const bundledFoo: { x: number }` ,
549+ }
550+ session , utils := projecttestutil .SetupWithTypingsInstaller (files , & projecttestutil.TypingsInstallerOptions {
551+ PackageToFile : map [string ]string {"foo" : `declare const foo: { x: number }` },
552+ })
553+ ctx := context .Background ()
554+ uri := lsproto .DocumentUri ("file:///user/username/projects/project/app.js" )
555+ session .DidOpenFile (ctx , uri , 1 , files ["/user/username/projects/project/app.js" ].(string ), lsproto .LanguageKindJavaScript )
556+ session .WaitForBackgroundTasks ()
557+
558+ assert .NilError (t , utils .FS ().Remove (bundledTypes ))
559+ session .DidChangeWatchedFiles (ctx , []* lsproto.FileEvent {{
560+ Uri : lsproto .DocumentUri ("file://" + bundledTypes ),
561+ Type : lsproto .FileChangeTypeDeleted ,
562+ }})
563+ ls , err := session .GetLanguageService (ctx , uri )
564+ assert .NilError (t , err )
565+ assert .Assert (t , ! slices .Contains (ls .GetProgram ().CommandLine ().FileNames (), bundledTypes ))
566+ session .WaitForBackgroundTasks ()
567+ ls , err = session .GetLanguageService (ctx , uri )
568+ assert .NilError (t , err )
569+ assert .Assert (t , ls .GetProgram ().GetSourceFile (projecttestutil .TestTypingsLocation + "/node_modules/@types/foo/index.d.ts" ) != nil )
570+ })
571+
572+ t .Run ("ATA install for another project does not discard cached inferred typings" , func (t * testing.T ) {
573+ t .Parallel ()
574+
575+ files := map [string ]any {
576+ "/user/username/projects/project/app.js" : `` ,
577+ "/user/username/projects/project/package.json" : `{"name":"test","dependencies":{"jquery":"^3.1.0"}}` ,
578+ "/user/username/projects/c/app.js" : `` ,
579+ "/user/username/projects/c/tsconfig.json" : `{"compilerOptions":{"allowJs":true},"typeAcquisition":{"enable":true}}` ,
580+ "/user/username/projects/c/package.json" : `{"name":"c","dependencies":{"commander":"^14.0.0"}}` ,
581+ }
582+ session , _ := projecttestutil .SetupWithTypingsInstaller (files , & projecttestutil.TypingsInstallerOptions {
583+ PackageToFile : map [string ]string {
584+ "commander" : `declare const commander: { x: number }` ,
585+ "jquery" : `declare const $: { x: number }` ,
586+ },
587+ })
588+ ctx := context .Background ()
589+ uri := lsproto .DocumentUri ("file:///user/username/projects/project/app.js" )
590+ cURI := lsproto .DocumentUri ("file:///user/username/projects/c/app.js" )
591+ session .DidOpenFile (ctx , uri , 1 , "" , lsproto .LanguageKindJavaScript )
592+ session .WaitForBackgroundTasks ()
593+ _ , err := session .GetLanguageService (ctx , uri )
594+ assert .NilError (t , err )
595+ session .WaitForBackgroundTasks ()
596+ session .DidCloseFile (ctx , uri )
597+ snapshot , err := session .APIUpdate (ctx , project.FileChangeSummary {}, nil )
598+ assert .NilError (t , err )
599+ assert .Assert (t , snapshot .ProjectCollection .InferredProject () == nil )
600+ snapshot .Deref ()
601+ session .WaitForBackgroundTasks ()
602+
603+ session .DidOpenFile (ctx , cURI , 1 , "" , lsproto .LanguageKindJavaScript )
604+ session .WaitForBackgroundTasks ()
605+ session .DidChangeWatchedFiles (ctx , []* lsproto.FileEvent {{
606+ Uri : lsproto .DocumentUri ("file://" + projecttestutil .TestTypingsLocation + "/node_modules/@types/commander/index.d.ts" ),
607+ Type : lsproto .FileChangeTypeCreated ,
608+ }})
609+ _ , err = session .GetLanguageService (ctx , cURI )
610+ assert .NilError (t , err )
611+ session .WaitForBackgroundTasks ()
612+
613+ session .DidOpenFile (ctx , uri , 1 , "" , lsproto .LanguageKindJavaScript )
614+ inferred := session .Snapshot ().ProjectCollection .InferredProject ()
615+ assert .Assert (t , inferred != nil && inferred .GetProgram () != nil )
616+ assert .Assert (t , inferred .GetProgram ().GetSourceFile (projecttestutil .TestTypingsLocation + "/node_modules/@types/jquery/index.d.ts" ) != nil )
617+ })
618+
619+ t .Run ("excessive typings cache writes do not discard cached inferred typings" , func (t * testing.T ) {
620+ t .Parallel ()
621+
622+ files := map [string ]any {
623+ "/user/username/projects/project/app.js" : `` ,
624+ "/user/username/projects/project/package.json" : `{"name":"test","dependencies":{"jquery":"^3.1.0"}}` ,
625+ }
626+ session , _ := projecttestutil .SetupWithTypingsInstaller (files , & projecttestutil.TypingsInstallerOptions {
627+ PackageToFile : map [string ]string {"jquery" : `declare const $: { x: number }` },
628+ })
629+ ctx := context .Background ()
630+ uri := lsproto .DocumentUri ("file:///user/username/projects/project/app.js" )
631+ session .DidOpenFile (ctx , uri , 1 , "" , lsproto .LanguageKindJavaScript )
632+ session .WaitForBackgroundTasks ()
633+ _ , err := session .GetLanguageService (ctx , uri )
634+ assert .NilError (t , err )
635+ session .WaitForBackgroundTasks ()
636+ session .DidCloseFile (ctx , uri )
637+ snapshot , err := session .APIUpdate (ctx , project.FileChangeSummary {}, nil )
638+ assert .NilError (t , err )
639+ assert .Assert (t , snapshot .ProjectCollection .InferredProject () == nil )
640+ snapshot .Deref ()
641+
642+ events := make ([]* lsproto.FileEvent , 1001 )
643+ for i := range events {
644+ events [i ] = & lsproto.FileEvent {
645+ Uri : lsproto .DocumentUri (fmt .Sprintf ("file://%s/node_modules/@types/generated/%d.d.ts" , projecttestutil .TestTypingsLocation , i )),
646+ Type : lsproto .FileChangeTypeCreated ,
647+ }
648+ }
649+ session .DidChangeWatchedFiles (ctx , events )
650+ session .WaitForBackgroundTasks ()
651+
652+ session .DidOpenFile (ctx , uri , 1 , "" , lsproto .LanguageKindJavaScript )
653+ inferred := session .Snapshot ().ProjectCollection .InferredProject ()
654+ assert .Assert (t , inferred != nil && inferred .GetProgram () != nil )
655+ assert .Assert (t , inferred .GetProgram ().GetSourceFile (projecttestutil .TestTypingsLocation + "/node_modules/@types/jquery/index.d.ts" ) != nil )
450656 })
451657
658+ t .Run ("excessive cache writes do not hide filesystem replacement invalidation" , func (t * testing.T ) {
659+ t .Parallel ()
660+
661+ files := map [string ]any {
662+ "/user/username/projects/project/app.js" : `` ,
663+ "/user/username/projects/project/package.json" : `{"name":"test","dependencies":{"jquery":"^3.1.0"}}` ,
664+ }
665+ session , utils := projecttestutil .SetupWithTypingsInstaller (files , & projecttestutil.TypingsInstallerOptions {
666+ PackageToFile : map [string ]string {"jquery" : `declare const $: { x: number }` },
667+ })
668+ ctx := context .Background ()
669+ uri := lsproto .DocumentUri ("file:///user/username/projects/project/app.js" )
670+ session .DidOpenFile (ctx , uri , 1 , "" , lsproto .LanguageKindJavaScript )
671+ session .WaitForBackgroundTasks ()
672+ _ , err := session .GetLanguageService (ctx , uri )
673+ assert .NilError (t , err )
674+ session .WaitForBackgroundTasks ()
675+ session .DidCloseFile (ctx , uri )
676+ snapshot , err := session .APIUpdate (ctx , project.FileChangeSummary {}, nil )
677+ assert .NilError (t , err )
678+ assert .Assert (t , snapshot .ProjectCollection .InferredProject () == nil )
679+ snapshot .Deref ()
680+
681+ summary := project.FileChangeSummary {}
682+ for i := range 1001 {
683+ summary .Created .Add (lsproto .DocumentUri (fmt .Sprintf ("file://%s/node_modules/@types/generated/%d.d.ts" , projecttestutil .TestTypingsLocation , i )))
684+ }
685+ replacement := bundled .WrapFS (vfstest .FromMap (map [string ]string {
686+ "/user/username/projects/project/app.js" : "" ,
687+ "/user/username/projects/project/package.json" : `{"name":"test"}` ,
688+ projecttestutil .TestTypingsLocation + "/node_modules/@types/jquery/index.d.ts" : `declare const $: { x: number }` ,
689+ }, tspath .CaseInsensitive ))
690+ snapshot , err = session .APIUpdate (ctx , summary , & project.APISnapshotRequest {
691+ FileSystem : replacement ,
692+ ReplaceFileSystem : true ,
693+ })
694+ assert .NilError (t , err )
695+ snapshot .Deref ()
696+
697+ snapshot , err = session .APIUpdate (ctx , project.FileChangeSummary {}, & project.APISnapshotRequest {
698+ FileSystem : replacement ,
699+ OpenFiles : map [tspath.PathKey ]tspath.RootedFilePath {
700+ utils .FS ().CaseSensitivity ().PathKey (uri .FileName ().AsPath ()): uri .FileName (),
701+ },
702+ })
703+ assert .NilError (t , err )
704+ defer snapshot .Deref ()
705+ inferred := snapshot .ProjectCollection .InferredProject ()
706+ assert .Assert (t , inferred != nil && inferred .GetProgram () != nil )
707+ assert .Assert (t , inferred .GetProgram ().GetSourceFile (projecttestutil .TestTypingsLocation + "/node_modules/@types/jquery/index.d.ts" ) == nil )
708+ })
709+
710+ for _ , configured := range []bool {false , true } {
711+ name := "inferred"
712+ if configured {
713+ name = "configured"
714+ }
715+ t .Run ("typings added by a manifest change reach the " + name + " program" , func (t * testing.T ) {
716+ t .Parallel ()
717+
718+ files := map [string ]any {
719+ "/user/username/projects/project/app.js" : `` ,
720+ "/user/username/projects/project/package.json" : `{"name":"test","dependencies":{"jquery":"^3.1.0"}}` ,
721+ }
722+ if configured {
723+ files ["/user/username/projects/project/tsconfig.json" ] = `{"compilerOptions":{"allowJs":true},"typeAcquisition":{"enable":true}}`
724+ }
725+ session , utils := projecttestutil .SetupWithTypingsInstaller (files , & projecttestutil.TypingsInstallerOptions {
726+ PackageToFile : map [string ]string {
727+ "commander" : `declare const commander: { x: number }` ,
728+ "jquery" : `declare const $: { x: number }` ,
729+ },
730+ })
731+ ctx := context .Background ()
732+ uri := lsproto .DocumentUri ("file:///user/username/projects/project/app.js" )
733+ packageJSONURI := lsproto .DocumentUri ("file:///user/username/projects/project/package.json" )
734+ session .DidOpenFile (ctx , uri , 1 , "" , lsproto .LanguageKindJavaScript )
735+ session .WaitForBackgroundTasks ()
736+ _ , err := session .GetLanguageService (ctx , uri )
737+ assert .NilError (t , err )
738+ session .WaitForBackgroundTasks ()
739+
740+ assert .NilError (t , utils .FS ().WriteFile (packageJSONURI .FileName (), `{"name":"test","dependencies":{"commander":"^14.0.0","jquery":"^3.1.0"}}` ))
741+ session .DidChangeWatchedFiles (ctx , []* lsproto.FileEvent {{Uri : packageJSONURI , Type : lsproto .FileChangeTypeChanged }})
742+ _ , err = session .GetLanguageService (ctx , uri )
743+ assert .NilError (t , err )
744+ session .WaitForBackgroundTasks ()
745+ ls , err := session .GetLanguageService (ctx , uri )
746+ assert .NilError (t , err )
747+ program := ls .GetProgram ()
748+ assert .Assert (t , program .GetSourceFile (projecttestutil .TestTypingsLocation + "/node_modules/@types/jquery/index.d.ts" ) != nil )
749+ assert .Assert (t , program .GetSourceFile (projecttestutil .TestTypingsLocation + "/node_modules/@types/commander/index.d.ts" ) != nil )
750+ })
751+ }
752+
452753 t .Run ("inferred project rejects ATA result invalidated after closing last file" , func (t * testing.T ) {
453754 t .Parallel ()
454755
0 commit comments