Skip to content

Commit 3d1bb23

Browse files
🐛 fix flaky nodejs queries (#995)
- Set up workspace folders correctly - Set up client capabilities so server enables support for document symbol hierarchy and definition links (required to find stuff in node_modules) - Disable workspace/symbol completely for nodejs (this is unreliable) - Add retries to definition and document symbol queries <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Improved initialization, workspace-folder normalization and deduplication, and open/close lifecycle handling for fewer duplicate events and safer concurrency. * Parallelized symbol caching and lookups with stronger concurrency controls and much more detailed logging. * **New Features** * Expanded client capabilities for richer code intelligence (definition link support, hierarchical document symbols, diagnostics refresh). * Initialization options still loaded from settings. * **Tests** * Added a test incident covering a React reference scenario. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Pranav Gaikwad <[email protected]>
1 parent 1397460 commit 3d1bb23

File tree

5 files changed

+345
-115
lines changed

5 files changed

+345
-115
lines changed

demo-output.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,12 @@
803803
lineNumber: 1
804804
variables:
805805
file: file:///examples/nodejs/Component.tsx
806+
- uri: file:///examples/nodejs/Component.tsx
807+
message: Found React reference using nodejs provider
808+
codeSnip: " 1 import React from 'react';\n 2 \n 3 export const MyComponent: React.FC = () => {\n 4 return <div>Hello from TypeScript React</div>;\n 5 };\n"
809+
lineNumber: 3
810+
variables:
811+
file: file:///examples/nodejs/Component.tsx
806812
- uri: file:///examples/nodejs/LegacyComponent.jsx
807813
message: Found React reference using nodejs provider
808814
codeSnip: " 1 import React from 'react';\n 2 \n 3 export const LegacyComponent = () => {\n 4 return <div>Hello from JavaScript React</div>;\n 5 };\n"

external-providers/generic-external-provider/pkg/server_configurations/nodejs/service_client.go

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"path/filepath"
78
"strings"
89

910
"github.com/go-logr/logr"
@@ -45,7 +46,11 @@ func (n *NodeServiceClientBuilder) Init(ctx context.Context, log logr.Logger, c
4546

4647
params := protocol.InitializeParams{}
4748

49+
// treat location as the only workspace folder
4850
if c.Location != "" {
51+
if !strings.HasPrefix(c.Location, "file://") {
52+
c.Location = "file://" + c.Location
53+
}
4954
sc.Config.WorkspaceFolders = []string{c.Location}
5055
}
5156

@@ -59,16 +64,45 @@ func (n *NodeServiceClientBuilder) Init(ctx context.Context, log logr.Logger, c
5964
} else {
6065
params.RootURI = sc.Config.WorkspaceFolders[0]
6166
}
62-
// var workspaceFolders []protocol.WorkspaceFolder
63-
// for _, f := range sc.Config.WorkspaceFolders {
64-
// workspaceFolders = append(workspaceFolders, protocol.WorkspaceFolder{
65-
// URI: f,
66-
// Name: f,
67-
// })
68-
// }
69-
// params.WorkspaceFolders = workspaceFolders
7067

71-
params.Capabilities = protocol.ClientCapabilities{}
68+
var workspaceFolders []protocol.WorkspaceFolder
69+
seen := make(map[string]bool)
70+
for _, f := range sc.Config.WorkspaceFolders {
71+
if seen[f] {
72+
continue
73+
}
74+
seen[f] = true
75+
workspaceFolders = append(workspaceFolders, protocol.WorkspaceFolder{
76+
URI: f,
77+
Name: filepath.Base(strings.ReplaceAll(f, "file://", "")),
78+
})
79+
}
80+
params.WorkspaceFolders = workspaceFolders
81+
82+
params.Capabilities = protocol.ClientCapabilities{
83+
Workspace: &protocol.WorkspaceClientCapabilities{
84+
WorkspaceFolders: true,
85+
// enables the server to refresh diagnostics on-demand, useful in agent mode
86+
Diagnostics: &protocol.DiagnosticWorkspaceClientCapabilities{
87+
RefreshSupport: true,
88+
},
89+
},
90+
TextDocument: &protocol.TextDocumentClientCapabilities{
91+
// this enables the textDocument/definition responses to be
92+
// LocationLink[] instead of Location[]. LocationLink contains
93+
// source -> target mapping of symbols which gives us more information
94+
Definition: &protocol.DefinitionClientCapabilities{
95+
LinkSupport: true,
96+
},
97+
// this enables the documentSymbol responses to be a tree instead of a flat list
98+
// this allows us to understand enclosed symbols better. Right now, we use this
99+
// information to find a concrete symbol at a location. While a flat list could
100+
// work, but in future, the tree will help us with advanced queries.
101+
DocumentSymbol: &protocol.DocumentSymbolClientCapabilities{
102+
HierarchicalDocumentSymbolSupport: true,
103+
},
104+
},
105+
}
72106

73107
var InitializationOptions map[string]any
74108
err = json.Unmarshal([]byte(sc.Config.LspServerInitializationOptions), &InitializationOptions)
@@ -140,7 +174,7 @@ func (sc *NodeServiceClient) EvaluateReferenced(ctx context.Context, cap string,
140174
}
141175

142176
// Query symbols once after all files are indexed
143-
symbols := sc.GetAllDeclarations(ctx, query)
177+
symbols := sc.GetAllDeclarations(ctx, query, false)
144178
incidentsMap, err := sc.EvaluateSymbols(ctx, symbols)
145179
if err != nil {
146180
return resp{}, err

lsp/base_service_client/base_capabilities.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func EvaluateReferenced[T base](t T, ctx ctx, cap string, info []byte) (resp, er
5454
return resp{}, fmt.Errorf("unable to get query info")
5555
}
5656

57-
symbols := sc.GetAllDeclarations(ctx, query)
57+
symbols := sc.GetAllDeclarations(ctx, query, true)
5858

5959
incidents := []provider.IncidentContext{}
6060
incidentsMap := make(map[string]provider.IncidentContext) // Remove duplicates

0 commit comments

Comments
 (0)