internal/lsp/jb_server.go (146 lines of code) (raw):

// MODIFIED IN THIS FORK: 2025-09-12 Konstantin Ulitin e3893948a2061ee66b3bc9e3df22590aba344872 support ideGetTypeProperty command // MODIFIED IN THIS FORK: 2025-08-25 Aleksei Berezkin 8aa1bd88535b085be08c607ccbecbe4e6fbfeeea Fixed fork after refactoring in upstream // MODIFIED IN THIS FORK: 2025-08-14 Aleksei Berezkin 57b2402e912f23f4a1345039460fac83895ce6c8 WEB-74070 Migrated away from private defaultProjectFinder.findOrCreateProject // MODIFIED IN THIS FORK: 2025-08-05 Aleksei Berezkin a9368494725330485924ed5ff3db447110dab0b3 WEB-74070 Projects cache cleanup // MODIFIED IN THIS FORK: 2025-07-25 Aleksei Berezkin 1b4d405531446e2f049414861843068ad508d68d WEB-74070 Do not reopen a file if it's already opened // MODIFIED IN THIS FORK: 2025-07-24 Aleksei Berezkin 5567c01219bf93fad344a80691da5df021923d10 WEB-74070 Supported the method IdeGetResolvedSignature // MODIFIED IN THIS FORK: 2025-05-21 Piotr Tomiak dfd337df3e64d6fb2bc18c46bf4de05bcbea5a64 Support WebStorm types in LSP mode package lsp import ( "context" "errors" "runtime/debug" "github.com/microsoft/typescript-go/internal/collections" "github.com/microsoft/typescript-go/internal/lsp/lsproto" "github.com/microsoft/typescript-go/internal/project" ) var ProjectNotFoundError = errors.New("ProjectNotFoundError") func (s *Server) jbHandleCustomTsServerCommand(ctx context.Context, req *lsproto.RequestMessage) error { // !!! most likely not needed once support is fully implemented defer func() { if r := recover(); r != nil { stack := debug.Stack() s.Log("panic running jbHandleCustomTsServerCommand:", r, string(stack)) s.sendResult(req.ID, &map[string]string{}) } }() params := req.Params.(*lsproto.JbHandleCustomTsServerCommandParams) switch params.IdeCommand { case lsproto.IdeCommandGetElementType: { args := params.Arguments.(*lsproto.GetElementTypeArguments) project, file, err := s.GetProjectAndFileName(args.ProjectFileName, args.File, ctx) if err != nil { s.jbSendResult(req.ID, nil, err) return nil } element, err := IdeGetTypeOfElement(ctx, project, file, &args.Range, args.ForceReturnType, args.TypeRequestKind) s.jbSendResult(req.ID, element, err) } case lsproto.IdeCommandGetSymbolType: { args := params.Arguments.(*lsproto.GetSymbolTypeArguments) symbolType, err := IdeGetSymbolType(ctx, args.IdeProjectId, uint64(args.IdeTypeCheckerId), args.SymbolId) s.jbSendResult(req.ID, symbolType, err) } case lsproto.IdeCommandGetTypeProperties: { args := params.Arguments.(*lsproto.GetTypePropertiesArguments) typeProperties, err := IdeGetTypeProperties(ctx, args.IdeProjectId, uint64(args.IdeTypeCheckerId), args.TypeId) s.jbSendResult(req.ID, typeProperties, err) } case lsproto.IdeCommandGetTypeProperty: { args := params.Arguments.(*lsproto.GetTypePropertyArguments) symbol, err := IdeGetTypeProperty(ctx, args.IdeProjectId, uint64(args.IdeTypeCheckerId), args.TypeId, args.PropertyName) s.jbSendResult(req.ID, symbol, err) } case lsproto.IdeCommandGetTypeText: { args := params.Arguments.(*lsproto.GetTypeTextArguments) typeText, err := IdeGetTypeText(ctx, args.IdeProjectId, uint64(args.IdeTypeCheckerId), args.TypeId, args.SymbolId, args.Flags) s.jbSendResult(req.ID, typeText, err) } case lsproto.IdeAreTypesMutuallyAssignable: { args := params.Arguments.(*lsproto.AreTypesMutuallyAssignableArguments) result, err := AreTypesMutuallyAssignable(ctx, args.IdeProjectId, uint64(args.IdeTypeCheckerId), args.Type1Id, args.Type2Id) s.jbSendResult(req.ID, result, err) } case lsproto.IdeGetResolvedSignature: { args := params.Arguments.(*lsproto.GetResolvedSignatureArguments) project, file, err := s.GetProjectAndFileName(args.ProjectFileName, args.File, ctx) if err != nil { s.jbSendResult(req.ID, nil, err) return nil } result, err := GetResolvedSignature(ctx, project, file, args.Range) s.jbSendResult(req.ID, result, err) } case lsproto.IdeCommandGetCompletionSymbols: { args := params.Arguments.(*lsproto.GetCompletionSymbolsArguments) proj, file, err := s.GetProjectAndFileName(args.ProjectFileName, args.File, ctx) if err != nil { s.jbSendResult(req.ID, nil, err) return nil } snapshot, release := s.session.Snapshot() defer release() result, err := IdeGetCompletionSymbols(ctx, proj, snapshot, file, args.Position) s.jbSendResult(req.ID, result, err) } } snapshot, release := s.session.Snapshot() defer release() CleanupProjectsCache(append(snapshot.ProjectCollection.Projects(), GetAllSelfManagedProjects(s, ctx)...), s.logger) return nil } func (s *Server) GetProjectAndFileName( projectFileNameUri *lsproto.DocumentUri, fileUri lsproto.DocumentUri, ctx context.Context, ) (*project.Project, string, error) { file := fileUri.FileName() snapshot, release := s.session.Snapshot() released := false releaseOnce := func() { if !released { release() released = true } } defer releaseOnce() if projectFileNameUri != nil { projectFileName := projectFileNameUri.FileName() if IsSelfManagedProject(projectFileName) { if p := GetOrCreateSelfManagedProjectForFile(s, projectFileName, file, ctx); p != nil { return p, file, nil } } for _, p := range snapshot.ProjectCollection.Projects() { if p.Name() == projectFileName && p.GetProgram().GetSourceFile(file) != nil { return p, file, nil } } if p := GetOrCreateSelfManagedProjectForFile(s, projectFileName, file, ctx); p != nil { return p, file, nil } } if p := snapshot.GetDefaultProject(fileUri); p != nil { return p, file, nil } releaseOnce() if _, err := s.session.GetLanguageService(ctx, fileUri); err == nil { // Get a fresh snapshot since GetLanguageService may have updated it newSnapshot, release := s.session.Snapshot() defer release() if p := newSnapshot.GetDefaultProject(fileUri); p != nil { return p, file, nil } } // No project found return nil, file, ProjectNotFoundError /* // Unstable API, skip so far canonicalFileName := tspath.GetCanonicalFileName(file, s.projectService.FS().UseCaseSensitiveFileNames()) scriptInfo := s.projectService.DocumentStore().GetScriptInfoByPath(tspath.Path(canonicalFileName)) if scriptInfo != nil { return scriptInfo.ContainingProjects()[0], file } // Default project - may be inferred // TODO - handle list of automatically opened files and close them automatically as well fileContents, ok := s.projectService.FS().ReadFile(file) if !ok { panic("Failed to read " + file) } scriptKind := core.GetScriptKindFromFileName(file) s.projectService.OpenFile(file, fileContents, scriptKind, file) _, proj = s.projectService.EnsureDefaultProjectForFile(file) return proj, file */ } func (s *Server) jbSendResult(id *lsproto.ID, result *collections.OrderedMap[string, interface{}], err error) { response := make(map[string]interface{}) if err == nil { response["response"] = result } else { errorResponse := make(map[string]interface{}) errorResponse["error"] = err.Error() response["response"] = errorResponse } s.sendResult(id, response) }