Skip to content

Commit 9f2adcb

Browse files
Make (*WatchedFiles[T]).Clone propagate nil
1 parent f16a4b7 commit 9f2adcb

File tree

3 files changed

+56
-0
lines changed

3 files changed

+56
-0
lines changed

internal/project/ata/ata_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"github.com/microsoft/typescript-go/internal/bundled"
99
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
10+
"github.com/microsoft/typescript-go/internal/project"
1011
"github.com/microsoft/typescript-go/internal/testutil/projecttestutil"
1112
"gotest.tools/v3/assert"
1213
)
@@ -618,4 +619,48 @@ func TestATA(t *testing.T) {
618619
emberComponentTypesFile := program.GetSourceFile(projecttestutil.TestTypingsLocation + "/node_modules/@types/ember__component/index.d.ts")
619620
assert.Assert(t, emberComponentTypesFile != nil, "ember__component types should be installed")
620621
})
622+
623+
// Test that ATA works correctly when `WatchEnabled` is false but `TypingsLocation` is set.
624+
// Previously if `WatchEnabled` was false but `TypingsLocation` was set, ATA would run but
625+
// crash when cloning file-watcher data for a new snapshot.
626+
t.Run("ATA with WatchEnabled false should not panic", func(t *testing.T) {
627+
t.Parallel()
628+
629+
files := map[string]any{
630+
"/user/username/projects/project/app.js": ``,
631+
"/user/username/projects/project/package.json": `{
632+
"name": "test",
633+
"dependencies": {
634+
"jquery": "^3.1.0"
635+
}
636+
}`,
637+
}
638+
639+
session, utils := projecttestutil.SetupWithOptionsAndTypingsInstaller(files, &project.SessionOptions{
640+
CurrentDirectory: "/",
641+
DefaultLibraryPath: bundled.LibPath(),
642+
TypingsLocation: projecttestutil.TestTypingsLocation,
643+
PositionEncoding: lsproto.PositionEncodingKindUTF8,
644+
WatchEnabled: false,
645+
LoggingEnabled: true,
646+
}, &projecttestutil.TypingsInstallerOptions{
647+
PackageToFile: map[string]string{
648+
"jquery": `declare const $: { x: number }`,
649+
},
650+
})
651+
652+
// Open a file to trigger project creation and ATA.
653+
session.DidOpenFile(context.Background(), lsproto.DocumentUri("file:///user/username/projects/project/app.js"), 1, files["/user/username/projects/project/app.js"].(string), lsproto.LanguageKindJavaScript)
654+
session.WaitForBackgroundTasks()
655+
656+
// ATA should have run
657+
calls := utils.NpmExecutor().NpmInstallCalls()
658+
assert.Equal(t, 2, len(calls), "Expected exactly 2 npm install calls")
659+
660+
// Getting the language service should not panic after
661+
// applying ATA changes and grabbing the latest snapshot.
662+
ls, err := session.GetLanguageService(context.Background(), lsproto.DocumentUri("file:///user/username/projects/project/app.js"))
663+
assert.NilError(t, err)
664+
assert.Assert(t, ls != nil)
665+
})
621666
}

internal/project/watch.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ func (w *WatchedFiles[T]) WatchKind() lsproto.WatchKind {
118118
}
119119

120120
func (w *WatchedFiles[T]) Clone(input T) *WatchedFiles[T] {
121+
if w == nil {
122+
return nil
123+
}
121124
w.mu.RLock()
122125
defer w.mu.RUnlock()
123126
return &WatchedFiles[T]{

internal/project/watch_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,11 @@ func TestGetPathComponentsForWatching(t *testing.T) {
1818
assert.DeepEqual(t, getPathComponentsForWatching("/home", ""), []string{"/home"})
1919
assert.DeepEqual(t, getPathComponentsForWatching("/home/andrew/project", ""), []string{"/home/andrew", "project"})
2020
}
21+
22+
func TestNilWatchedFilesClone(t *testing.T) {
23+
t.Parallel()
24+
25+
var w *WatchedFiles[int]
26+
result := w.Clone(42)
27+
assert.Equal(t, result, nil, "clone on a nil `WatchedFiles` should return nil")
28+
}

0 commit comments

Comments
 (0)