@@ -3,16 +3,33 @@ package ata_test
33import (
44 "context"
55 "slices"
6+ "sync"
67 "testing"
8+ "time"
79
810 "github.com/microsoft/TypeScript/tsc/internal/bundled"
11+ "github.com/microsoft/TypeScript/tsc/internal/collections"
12+ "github.com/microsoft/TypeScript/tsc/internal/core"
13+ "github.com/microsoft/TypeScript/tsc/internal/glob"
914 "github.com/microsoft/TypeScript/tsc/internal/ls/lsutil"
1015 "github.com/microsoft/TypeScript/tsc/internal/lsp/lsproto"
1116 "github.com/microsoft/TypeScript/tsc/internal/project"
1217 "github.com/microsoft/TypeScript/tsc/internal/testutil/projecttestutil"
18+ "github.com/microsoft/TypeScript/tsc/internal/tspath"
19+ "github.com/microsoft/TypeScript/tsc/internal/vfs/vfstest"
1320 "gotest.tools/v3/assert"
1421)
1522
23+ func waitForInstall (t * testing.T , installStarted <- chan struct {}) {
24+ t .Helper ()
25+ select {
26+ case <- installStarted :
27+ return
28+ case <- time .After (10 * time .Second ):
29+ t .Fatal ("timed out waiting for typings installation to start" )
30+ }
31+ }
32+
1633func TestATA (t * testing.T ) {
1734 t .Parallel ()
1835 if ! bundled .Embedded {
@@ -89,6 +106,168 @@ func TestATA(t *testing.T) {
89106 assert .Equal (t , len (utils .Client ().RefreshDiagnosticsCalls ()), 1 )
90107 })
91108
109+ t .Run ("configured project ignores ATA results from before manifest invalidation" , func (t * testing.T ) {
110+ t .Parallel ()
111+
112+ files := map [string ]any {
113+ "/user/username/projects/project/app.js" : `` ,
114+ "/user/username/projects/project/tsconfig.json" : `{
115+ "compilerOptions": { "allowJs": true },
116+ "typeAcquisition": { "enable": true },
117+ }` ,
118+ "/user/username/projects/project/package.json" : `{
119+ "name": "test",
120+ "dependencies": {
121+ "jquery": "^3.1.0"
122+ }
123+ }` ,
124+ }
125+
126+ session , utils := projecttestutil .SetupWithTypingsInstaller (files , & projecttestutil.TypingsInstallerOptions {
127+ PackageToFile : map [string ]string {
128+ "commander" : `declare const commander: { x: number }` ,
129+ "jquery" : `declare const $: { x: number }` ,
130+ },
131+ })
132+
133+ ctx := context .Background ()
134+ uri := lsproto .DocumentUri ("file:///user/username/projects/project/app.js" )
135+ packageJSONURI := lsproto .DocumentUri ("file:///user/username/projects/project/package.json" )
136+ session .DidOpenFile (ctx , uri , 1 , files ["/user/username/projects/project/app.js" ].(string ), lsproto .LanguageKindJavaScript )
137+ session .WaitForBackgroundTasks ()
138+ _ , err := session .GetLanguageService (ctx , uri )
139+ assert .NilError (t , err )
140+ session .WaitForBackgroundTasks ()
141+
142+ originalNpmInstall := utils .NpmExecutor ().NpmInstallFunc
143+ installStarted := make (chan struct {}, 1 )
144+ releaseInstall := make (chan struct {})
145+ var releaseInstallOnce sync.Once
146+ release := func () { releaseInstallOnce .Do (func () { close (releaseInstall ) }) }
147+ defer release ()
148+ utils .NpmExecutor ().NpmInstallFunc = func (cwd string , args []string ) ([]byte , error ) {
149+ if slices .Contains (args , "@types/commander@latest" ) {
150+ installStarted <- struct {}{}
151+ <- releaseInstall
152+ }
153+ return originalNpmInstall (cwd , args )
154+ }
155+
156+ err = utils .FS ().WriteFile (packageJSONURI .FileName (), `{
157+ "name": "test",
158+ "dependencies": {
159+ "commander": "^14.0.0",
160+ "jquery": "^3.1.0"
161+ }
162+ }` )
163+ assert .NilError (t , err )
164+ session .DidChangeWatchedFiles (ctx , []* lsproto.FileEvent {{
165+ Uri : packageJSONURI ,
166+ Type : lsproto .FileChangeTypeChanged ,
167+ }})
168+ snapshot , err := session .APIUpdate (ctx , project.FileChangeSummary {}, nil )
169+ assert .NilError (t , err )
170+ snapshot .Deref ()
171+ waitForInstall (t , installStarted )
172+
173+ session .Configure (lsutil .ParseUserPreferences (map [string ]any {
174+ "js/ts" : map [string ]any {
175+ "tsserver" : map [string ]any {
176+ "automaticTypeAcquisition" : map [string ]any {
177+ "enabled" : false ,
178+ },
179+ },
180+ },
181+ }))
182+ err = utils .FS ().WriteFile (packageJSONURI .FileName (), files ["/user/username/projects/project/package.json" ].(string ))
183+ assert .NilError (t , err )
184+ session .DidChangeWatchedFiles (ctx , []* lsproto.FileEvent {{
185+ Uri : packageJSONURI ,
186+ Type : lsproto .FileChangeTypeChanged ,
187+ }})
188+ snapshot , err = session .APIUpdate (ctx , project.FileChangeSummary {}, nil )
189+ assert .NilError (t , err )
190+ snapshot .Deref ()
191+
192+ release ()
193+ session .WaitForBackgroundTasks ()
194+
195+ ls , err := session .GetLanguageService (ctx , uri )
196+ assert .NilError (t , err )
197+ commanderTypesFile := ls .GetProgram ().GetSourceFile (projecttestutil .TestTypingsLocation + "/node_modules/@types/commander/index.d.ts" )
198+ assert .Assert (t , commanderTypesFile == nil , "stale commander typings should not be applied after the manifest changes" )
199+ })
200+
201+ t .Run ("configured project ignores ATA results from a previous project lifetime" , func (t * testing.T ) {
202+ t .Parallel ()
203+
204+ files := map [string ]any {
205+ "/user/username/projects/project/app.js" : `` ,
206+ "/user/username/projects/project/tsconfig.json" : `{
207+ "compilerOptions": { "allowJs": true },
208+ "typeAcquisition": { "enable": true },
209+ }` ,
210+ "/user/username/projects/project/package.json" : `{
211+ "name": "test",
212+ "dependencies": {
213+ "commander": "^14.0.0"
214+ }
215+ }` ,
216+ }
217+
218+ session , utils := projecttestutil .SetupWithTypingsInstaller (files , & projecttestutil.TypingsInstallerOptions {
219+ PackageToFile : map [string ]string {
220+ "commander" : `declare const commander: { x: number }` ,
221+ },
222+ })
223+
224+ originalNpmInstall := utils .NpmExecutor ().NpmInstallFunc
225+ installStarted := make (chan struct {}, 1 )
226+ releaseInstall := make (chan struct {})
227+ var releaseInstallOnce sync.Once
228+ release := func () { releaseInstallOnce .Do (func () { close (releaseInstall ) }) }
229+ defer release ()
230+ utils .NpmExecutor ().NpmInstallFunc = func (cwd string , args []string ) ([]byte , error ) {
231+ if slices .Contains (args , "@types/commander@latest" ) {
232+ installStarted <- struct {}{}
233+ <- releaseInstall
234+ }
235+ return originalNpmInstall (cwd , args )
236+ }
237+
238+ ctx := context .Background ()
239+ uri := lsproto .DocumentUri ("file:///user/username/projects/project/app.js" )
240+ session .DidOpenFile (ctx , uri , 1 , files ["/user/username/projects/project/app.js" ].(string ), lsproto .LanguageKindJavaScript )
241+ waitForInstall (t , installStarted )
242+
243+ session .DidCloseFile (ctx , uri )
244+ snapshot , err := session .APIUpdate (ctx , project.FileChangeSummary {}, & project.APISnapshotRequest {
245+ CloseFiles : & collections.Set [tspath.Path ]{},
246+ })
247+ assert .NilError (t , err )
248+ assert .Equal (t , len (snapshot .ProjectCollection .Projects ()), 0 )
249+ snapshot .Deref ()
250+
251+ session .Configure (lsutil .ParseUserPreferences (map [string ]any {
252+ "js/ts" : map [string ]any {
253+ "tsserver" : map [string ]any {
254+ "automaticTypeAcquisition" : map [string ]any {
255+ "enabled" : false ,
256+ },
257+ },
258+ },
259+ }))
260+ session .DidOpenFile (ctx , uri , 1 , files ["/user/username/projects/project/app.js" ].(string ), lsproto .LanguageKindJavaScript )
261+
262+ release ()
263+ session .WaitForBackgroundTasks ()
264+
265+ ls , err := session .GetLanguageService (ctx , uri )
266+ assert .NilError (t , err )
267+ commanderTypesFile := ls .GetProgram ().GetSourceFile (projecttestutil .TestTypingsLocation + "/node_modules/@types/commander/index.d.ts" )
268+ assert .Assert (t , commanderTypesFile == nil , "stale commander typings should not be applied to a replacement project" )
269+ })
270+
92271 t .Run ("inferred projects" , func (t * testing.T ) {
93272 t .Parallel ()
94273
0 commit comments