Skip to content

Commit 06fe820

Browse files
committed
Fix WASI LSP shutdown
Return io.EOF when WASI stdin closes instead of triggering repeated empty reads. Cover the command lifecycle in the unified module test.
1 parent 58694de commit 06fe820

3 files changed

Lines changed: 38 additions & 1 deletion

File tree

‎packages/typescript/test/browser/suite.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const fileExclusions = [
5050
{
5151
mode: "sync",
5252
file: "sync/wasm.test.ts",
53-
tests: 2,
53+
tests: 3,
5454
reason: "These Node.js integration tests use node:fs and node:wasi; wasm.test.ts covers browser API loading.",
5555
},
5656
] as const;

‎packages/typescript/test/sync/wasm.test.ts‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,39 @@ describe("API over WebAssembly", () => {
5656
}
5757
});
5858

59+
test("exits successfully when LSP stdin closes", async () => {
60+
const WebAssembly = (globalThis as any).WebAssembly;
61+
const directory = await mkdtemp(path.join(tmpdir(), "typescript-wasip1-"));
62+
try {
63+
const stdin = await open(path.join(directory, "stdin"), "w+");
64+
const stdout = await open(path.join(directory, "stdout"), "w+");
65+
const stderr = await open(path.join(directory, "stderr"), "w+");
66+
try {
67+
const wasi = new WASI({
68+
version: "preview1",
69+
args: ["tsc.wasm", "--lsp", "--stdio"],
70+
env: { PWD: "/" },
71+
preopens: { "/": process.cwd() },
72+
stdin: stdin.fd,
73+
stdout: stdout.fd,
74+
stderr: stderr.fd,
75+
returnOnExit: true,
76+
});
77+
const module = await WebAssembly.compile(await readFile(wasmURL));
78+
const instance = await WebAssembly.instantiate(module, {
79+
wasi_snapshot_preview1: wasi.wasiImport,
80+
});
81+
assert.strictEqual(wasi.start(instance), 0);
82+
}
83+
finally {
84+
await Promise.all([stdin.close(), stdout.close(), stderr.close()]);
85+
}
86+
}
87+
finally {
88+
await rm(directory, { recursive: true });
89+
}
90+
});
91+
5992
test("runs the compiler and checker through the reactor", async () => {
6093
const WebAssembly = (globalThis as any).WebAssembly;
6194
const module = await WebAssembly.compile(

‎tsc/cmd/tsc/lsp_stdin_wasip1.go‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package main
44

55
import (
6+
"io"
67
"runtime"
78
"syscall"
89
)
@@ -12,6 +13,9 @@ type wasiStdin struct{}
1213
func (wasiStdin) Read(buffer []byte) (int, error) {
1314
for {
1415
n, err := syscall.Read(syscall.Stdin, buffer)
16+
if n == 0 && err == nil {
17+
return 0, io.EOF
18+
}
1519
if err != syscall.EAGAIN {
1620
return n, err
1721
}

0 commit comments

Comments
 (0)