diff --git a/.golangci.yml b/.golangci.yml index afb62f07e9..5212cb09a7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -22,6 +22,7 @@ linters: - errname - errorlint - fatcontext + - forbidigo - gocheckcompilerdirectives - goprintffuncname - govet @@ -70,11 +71,30 @@ linters: - pkg: 'encoding/json$' desc: 'Use "github.com/go-json-experiment/json" instead.' + forbidigo: + analyze-types: true + forbid: + - pattern: '.*' + msg: tspath should likely be used instead + pkg: ^(path|path/filepath)$ + - pattern: '.*' + msg: a host implementation should likely be used instead + pkg: ^os/ + - pattern: 'GOOS' + msg: a host implementation should likely be used instead + pkg: ^runtime$ + exclusions: rules: - path: internal/fourslash/tests/gen/ linters: - misspell + - path: 'internal/(repo|testutil|testrunner|vfs|pprof|execute/tsctests|bundled)|cmd/tsgo' + text: should likely be used instead + - path: '(.+)_test\.go$' + text: should likely be used instead + - path: '_tools' + text: should likely be used instead presets: - comments diff --git a/cmd/tsgo/lsp.go b/cmd/tsgo/lsp.go index 35c973a3a0..0dd04c57fb 100644 --- a/cmd/tsgo/lsp.go +++ b/cmd/tsgo/lsp.go @@ -1,10 +1,14 @@ package main import ( + "context" "flag" "fmt" "os" + "os/exec" + "os/signal" "runtime" + "syscall" "github.com/microsoft/typescript-go/internal/bundled" "github.com/microsoft/typescript-go/internal/core" @@ -49,9 +53,17 @@ func runLSP(args []string) int { FS: fs, DefaultLibraryPath: defaultLibraryPath, TypingsLocation: typingsLocation, + NpmInstall: func(cwd string, args []string) ([]byte, error) { + cmd := exec.Command("npm", args...) + cmd.Dir = cwd + return cmd.Output() + }, }) - if err := s.Run(); err != nil { + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + defer stop() + + if err := s.Run(ctx); err != nil { return 1 } return 0 diff --git a/internal/fourslash/fourslash.go b/internal/fourslash/fourslash.go index 8c64ea2f90..ddac550413 100644 --- a/internal/fourslash/fourslash.go +++ b/internal/fourslash/fourslash.go @@ -1,6 +1,7 @@ package fourslash import ( + "context" "fmt" "io" "maps" @@ -164,7 +165,7 @@ func NewFourslash(t *testing.T, capabilities *lsproto.ClientCapabilities, conten defer func() { outputWriter.Close() }() - err := server.Run() + err := server.Run(context.TODO()) if err != nil { t.Error("server error:", err) } diff --git a/internal/lsp/server.go b/internal/lsp/server.go index 54f78f2e16..2265ebb344 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -5,14 +5,10 @@ import ( "errors" "fmt" "io" - "os" - "os/exec" - "os/signal" "runtime/debug" "slices" "sync" "sync/atomic" - "syscall" "time" "github.com/go-json-experiment/json" @@ -39,6 +35,7 @@ type ServerOptions struct { DefaultLibraryPath string TypingsLocation string ParseCache *project.ParseCache + NpmInstall func(cwd string, args []string) ([]byte, error) } func NewServer(opts *ServerOptions) *Server { @@ -59,6 +56,7 @@ func NewServer(opts *ServerOptions) *Server { defaultLibraryPath: opts.DefaultLibraryPath, typingsLocation: opts.TypingsLocation, parseCache: opts.ParseCache, + npmInstall: opts.NpmInstall, } } @@ -157,6 +155,8 @@ type Server struct { compilerOptionsForInferredProjects *core.CompilerOptions // parseCache can be passed in so separate tests can share ASTs parseCache *project.ParseCache + + npmInstall func(cwd string, args []string) ([]byte, error) } // WatchFiles implements project.Client. @@ -218,10 +218,7 @@ func (s *Server) RefreshDiagnostics(ctx context.Context) error { return nil } -func (s *Server) Run() error { - ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) - defer stop() - +func (s *Server) Run(ctx context.Context) error { g, ctx := errgroup.WithContext(ctx) g.Go(func() error { return s.dispatchLoop(ctx) }) g.Go(func() error { return s.writeLoop(ctx) }) @@ -877,9 +874,7 @@ func (s *Server) SetCompilerOptionsForInferredProjects(ctx context.Context, opti // NpmInstall implements ata.NpmExecutor func (s *Server) NpmInstall(cwd string, args []string) ([]byte, error) { - cmd := exec.Command("npm", args...) - cmd.Dir = cwd - return cmd.Output() + return s.npmInstall(cwd, args) } func isBlockingMethod(method lsproto.Method) bool { diff --git a/internal/tspath/extension.go b/internal/tspath/extension.go index cc30d48a66..1b4422e791 100644 --- a/internal/tspath/extension.go +++ b/internal/tspath/extension.go @@ -51,7 +51,7 @@ func RemoveFileExtension(path string) string { } } // Otherwise just remove single dot extension, if any - return path[:len(path)-len(filepath.Ext(path))] + return path[:len(path)-len(filepath.Ext(path))] //nolint:forbidigo } func TryGetExtensionFromPath(p string) string {