Skip to content

Commit ecd4ec6

Browse files
committed
fix(lsp): address review and quality gate findings
1 parent 6f9526e commit ecd4ec6

4 files changed

Lines changed: 64 additions & 111 deletions

File tree

packages/lsp/src/client.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,21 +102,22 @@ export async function createLSPClient(input: {
102102
// out-of-order reply can't overwrite fresher diagnostics with stale ones.
103103
const pullDiagnostics = async (filePath: string): Promise<void> => {
104104
if (!supportsPullDiagnostics) { return }
105-
const pullID = (diagnosticPulls[filePath] ?? 0) + 1
106-
diagnosticPulls[filePath] = pullID
105+
const normalizedPath = normalizePath(filePath)
106+
const pullID = (diagnosticPulls[normalizedPath] ?? 0) + 1
107+
diagnosticPulls[normalizedPath] = pullID
107108
try {
108109
const report = (await withTimeout(
109110
connection.sendRequest('textDocument/diagnostic', {
110-
textDocument: { uri: pathToFileURL(filePath).href },
111+
textDocument: { uri: pathToFileURL(normalizedPath).href },
111112
}),
112113
DIAGNOSTICS_WAIT_TIMEOUT_MS,
113114
)) as { kind?: string, items?: Diagnostic[] } | null
114115
// Drop a response superseded by a newer pull or close.
115-
if (diagnosticPulls[filePath] !== pullID) { return }
116+
if (diagnosticPulls[normalizedPath] !== pullID) { return }
116117
// A "full" report carries items; an "unchanged" report means keep the
117118
// previously reported set, so leave the map as-is.
118119
if (report?.kind === 'full' && Array.isArray(report.items)) {
119-
applyDiagnostics(normalizePath(filePath), report.items)
120+
applyDiagnostics(normalizedPath, report.items)
120121
}
121122
}
122123
catch {
@@ -250,8 +251,9 @@ export async function createLSPClient(input: {
250251
},
251252
})
252253
delete files[filePath]
253-
diagnosticPulls[filePath] = (diagnosticPulls[filePath] ?? 0) + 1
254-
diagnostics.delete(normalizePath(filePath))
254+
const normalizedPath = normalizePath(filePath)
255+
diagnosticPulls[normalizedPath] = (diagnosticPulls[normalizedPath] ?? 0) + 1
256+
diagnostics.delete(normalizedPath)
255257
},
256258
},
257259

packages/lsp/test/fixture/fake-lsp-server.js

Lines changed: 3 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,13 @@
11
// Simple JSON-RPC 2.0 LSP-like fake server over stdio
22
// Implements a minimal LSP handshake and publishes diagnostics
33

4-
import { Buffer } from 'node:buffer'
5-
import process from 'node:process'
4+
import { send, start } from './fake-lsp-transport.js'
65

76
let nextId = 1
87
// Tracks how many didOpen notifications were received per uri, so tests can
98
// assert that concurrent opens do not emit a duplicate didOpen.
109
const openCounts = {}
1110

12-
function encode(message) {
13-
const json = JSON.stringify(message)
14-
const header = `Content-Length: ${Buffer.byteLength(json, 'utf8')}\r\n\r\n`
15-
return Buffer.concat([
16-
Buffer.from(header, 'utf8'),
17-
Buffer.from(json, 'utf8'),
18-
])
19-
}
20-
21-
function decodeFrames(buffer) {
22-
const results = []
23-
let idx = buffer.indexOf('\r\n\r\n')
24-
while (idx !== -1) {
25-
const header = buffer.slice(0, idx).toString('utf8')
26-
const m = /Content-Length:\s*(\d+)/i.exec(header)
27-
const len = m ? Number.parseInt(m[1], 10) : 0
28-
const bodyStart = idx + 4
29-
const bodyEnd = bodyStart + len
30-
if (buffer.length < bodyEnd)
31-
break
32-
const body = buffer.slice(bodyStart, bodyEnd).toString('utf8')
33-
results.push(body)
34-
buffer = buffer.slice(bodyEnd)
35-
idx = buffer.indexOf('\r\n\r\n')
36-
}
37-
return { messages: results, rest: buffer }
38-
}
39-
40-
let readBuffer = Buffer.alloc(0)
41-
42-
process.stdin.on('data', (chunk) => {
43-
readBuffer = Buffer.concat([readBuffer, chunk])
44-
const { messages, rest } = decodeFrames(readBuffer)
45-
readBuffer = rest
46-
for (const m of messages) handle(m)
47-
})
48-
49-
function send(msg) {
50-
process.stdout.write(encode(msg))
51-
}
52-
5311
function sendNotification(method, params) {
5412
send({ jsonrpc: '2.0', method, params })
5513
}
@@ -60,14 +18,7 @@ function sendRequest(method, params) {
6018
return id
6119
}
6220

63-
function handle(raw) {
64-
let data
65-
try {
66-
data = JSON.parse(raw)
67-
}
68-
catch {
69-
return
70-
}
21+
start((data) => {
7122

7223
// Initialize request
7324
if (data.method === 'initialize') {
@@ -211,4 +162,4 @@ function handle(raw) {
211162
if (typeof data.id !== 'undefined') {
212163
send({ jsonrpc: '2.0', id: data.id, result: null })
213164
}
214-
}
165+
})
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { Buffer } from 'node:buffer'
2+
import process from 'node:process'
3+
4+
function encode(message) {
5+
const json = JSON.stringify(message)
6+
const header = `Content-Length: ${Buffer.byteLength(json, 'utf8')}\r\n\r\n`
7+
return Buffer.concat([
8+
Buffer.from(header, 'utf8'),
9+
Buffer.from(json, 'utf8'),
10+
])
11+
}
12+
13+
function decodeFrames(buffer) {
14+
const messages = []
15+
let headerEnd = buffer.indexOf('\r\n\r\n')
16+
while (headerEnd !== -1) {
17+
const header = buffer.slice(0, headerEnd).toString('utf8')
18+
const match = /Content-Length:\s*(\d+)/i.exec(header)
19+
const length = match ? Number.parseInt(match[1], 10) : 0
20+
const bodyStart = headerEnd + 4
21+
const bodyEnd = bodyStart + length
22+
if (buffer.length < bodyEnd) { break }
23+
messages.push(buffer.slice(bodyStart, bodyEnd).toString('utf8'))
24+
buffer = buffer.slice(bodyEnd)
25+
headerEnd = buffer.indexOf('\r\n\r\n')
26+
}
27+
return { messages, rest: buffer }
28+
}
29+
30+
export function send(message) {
31+
process.stdout.write(encode(message))
32+
}
33+
34+
export function start(handler) {
35+
let readBuffer = Buffer.alloc(0)
36+
process.stdin.on('data', (chunk) => {
37+
readBuffer = Buffer.concat([readBuffer, chunk])
38+
const { messages, rest } = decodeFrames(readBuffer)
39+
readBuffer = rest
40+
for (const raw of messages) {
41+
try {
42+
handler(JSON.parse(raw))
43+
}
44+
catch {
45+
// Ignore malformed test input.
46+
}
47+
}
48+
})
49+
}

packages/lsp/test/fixture/fake-pull-lsp-server.js

Lines changed: 3 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,58 +3,9 @@
33
// Mirrors how typescript-go (tsgo) behaves, so the client's pull path can be
44
// tested without the real binary.
55

6-
import { Buffer } from 'node:buffer'
7-
import process from 'node:process'
6+
import { send, start } from './fake-lsp-transport.js'
87

9-
function encode(message) {
10-
const json = JSON.stringify(message)
11-
const header = `Content-Length: ${Buffer.byteLength(json, 'utf8')}\r\n\r\n`
12-
return Buffer.concat([
13-
Buffer.from(header, 'utf8'),
14-
Buffer.from(json, 'utf8'),
15-
])
16-
}
17-
18-
function decodeFrames(buffer) {
19-
const results = []
20-
let idx = buffer.indexOf('\r\n\r\n')
21-
while (idx !== -1) {
22-
const header = buffer.slice(0, idx).toString('utf8')
23-
const m = /Content-Length:\s*(\d+)/i.exec(header)
24-
const len = m ? Number.parseInt(m[1], 10) : 0
25-
const bodyStart = idx + 4
26-
const bodyEnd = bodyStart + len
27-
if (buffer.length < bodyEnd)
28-
break
29-
const body = buffer.slice(bodyStart, bodyEnd).toString('utf8')
30-
results.push(body)
31-
buffer = buffer.slice(bodyEnd)
32-
idx = buffer.indexOf('\r\n\r\n')
33-
}
34-
return { messages: results, rest: buffer }
35-
}
36-
37-
let readBuffer = Buffer.alloc(0)
38-
39-
process.stdin.on('data', (chunk) => {
40-
readBuffer = Buffer.concat([readBuffer, chunk])
41-
const { messages, rest } = decodeFrames(readBuffer)
42-
readBuffer = rest
43-
for (const m of messages) handle(m)
44-
})
45-
46-
function send(msg) {
47-
process.stdout.write(encode(msg))
48-
}
49-
50-
function handle(raw) {
51-
let data
52-
try {
53-
data = JSON.parse(raw)
54-
}
55-
catch {
56-
return
57-
}
8+
start((data) => {
589

5910
// Initialize request - advertise a diagnostic provider (pull model).
6011
if (data.method === 'initialize') {
@@ -115,4 +66,4 @@ function handle(raw) {
11566
if (typeof data.id !== 'undefined') {
11667
send({ jsonrpc: '2.0', id: data.id, result: null })
11768
}
118-
}
69+
})

0 commit comments

Comments
 (0)