zed-ets-language-server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +186 -0
  2. package/package.json +17 -0
package/index.js ADDED
@@ -0,0 +1,186 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawn } from 'node:child_process';
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+
11
+ // ETS language server path, passed by Rust extension process through environment variable
12
+ const etsLangServerPath = process.env.ETS_LANG_SERVER;
13
+
14
+ function createSimpleLogger() {
15
+ if (process.env.ZED_ETS_LANG_SERVER_LOG !== 'true') {
16
+ const noop = (_msg) => {};
17
+ return {
18
+ info: noop,
19
+ success: noop,
20
+ error: noop,
21
+ warn: noop,
22
+ section: noop,
23
+ data: noop,
24
+ close: noop,
25
+ };
26
+ }
27
+ // Create log file write stream
28
+ const logFilePath = path.join(__dirname, 'arkts-lsw.log');
29
+ const logStream = fs.createWriteStream(logFilePath, { flags: 'w+' });
30
+
31
+ // Function to get current timestamp
32
+ const getTimestamp = () => {
33
+ const now = new Date();
34
+ return now.toISOString().slice(0, 19).replace('T', ' ');
35
+ };
36
+
37
+ // Logging utility
38
+ const logger = {
39
+ info: (msg) => {
40
+ const timestamp = getTimestamp();
41
+ const logMsg = `[${timestamp}] ℹ ${msg}\n`;
42
+ logStream.write(logMsg);
43
+ },
44
+ success: (msg) => {
45
+ const timestamp = getTimestamp();
46
+ const logMsg = `[${timestamp}] ✓ ${msg}\n`;
47
+ logStream.write(logMsg);
48
+ },
49
+ error: (msg) => {
50
+ const timestamp = getTimestamp();
51
+ const logMsg = `[${timestamp}] ✗ ${msg}\n`;
52
+ logStream.write(logMsg);
53
+ process.stderr.write(logMsg);
54
+ },
55
+ warn: (msg) => {
56
+ const timestamp = getTimestamp();
57
+ const logMsg = `[${timestamp}] ⚠ ${msg}\n`;
58
+ logStream.write(logMsg);
59
+ },
60
+ section: (msg) => {
61
+ const timestamp = getTimestamp();
62
+ const logMsg = `\n[${timestamp}] ${msg}\n\n`;
63
+ logStream.write(logMsg);
64
+ },
65
+ data: (label, data) => {
66
+ const timestamp = getTimestamp();
67
+ const logMsg = `[${timestamp}] ${label}: ${JSON.stringify(data, null, 2)}\n`;
68
+ logStream.write(logMsg);
69
+ },
70
+ // Add method to close log stream
71
+ close: () => {
72
+ logStream.end();
73
+ },
74
+ };
75
+
76
+ return logger;
77
+ }
78
+
79
+ async function main() {
80
+ const logger = createSimpleLogger();
81
+ logger.section('🚀 ETS Language Server Wrapper');
82
+
83
+ // Check if language server exists
84
+ const serverExists = fs.existsSync(etsLangServerPath);
85
+
86
+ if (!serverExists) {
87
+ logger.error(`Language server does not exist, please build the language server first ${etsLangServerPath}`);
88
+ return;
89
+ }
90
+
91
+ logger.success(`Language server path: ${etsLangServerPath}`);
92
+
93
+ // Start language server
94
+ logger.section('🔌 Starting Language Server');
95
+
96
+ const serverProcess = spawn('node', [etsLangServerPath, '--node-ipc', '--server-mode'], {
97
+ stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
98
+ env: { ...process.env },
99
+ });
100
+
101
+ // Listen to server process error and exit events
102
+ serverProcess.on('error', (error) => {
103
+ logger.error(`Language server process error: ${error.message}`);
104
+ });
105
+
106
+ serverProcess.on('exit', (code, signal) => {
107
+ logger.info(`Language server process exited, exit code: ${code}, signal: ${signal}`);
108
+ });
109
+
110
+ // Set up forwarding of serverProcess IPC messages to process.stdout
111
+ serverProcess.on('message', (message) => {
112
+ // Convert IPC message to standard LSP format and send to stdout
113
+ const messageStr = JSON.stringify(message);
114
+ const headers = `Content-Length: ${Buffer.byteLength(messageStr)}\r\n\r\n`;
115
+ process.stdout.write(headers + messageStr);
116
+ });
117
+
118
+ // Set up forwarding of process.stdin to serverProcess IPC
119
+ let stdinBuffer = '';
120
+ process.stdin.on('data', (data) => {
121
+ stdinBuffer += data.toString();
122
+
123
+ while (true) {
124
+ // Find Content-Length header
125
+ const lengthMatch = stdinBuffer.match(/Content-Length: (\d+)\r\n/);
126
+ if (!lengthMatch) break;
127
+
128
+ const contentLength = Number.parseInt(lengthMatch[1]);
129
+ const headerEnd = stdinBuffer.indexOf('\r\n\r\n');
130
+
131
+ if (headerEnd === -1) break;
132
+
133
+ const messageStart = headerEnd + 4;
134
+ const messageEnd = messageStart + contentLength;
135
+
136
+ if (stdinBuffer.length < messageEnd) break;
137
+
138
+ // Extract message
139
+ const messageJson = stdinBuffer.substring(messageStart, messageEnd);
140
+ stdinBuffer = stdinBuffer.substring(messageEnd);
141
+
142
+ try {
143
+ const message = JSON.parse(messageJson);
144
+ // Send message to language server via IPC
145
+ serverProcess.send(message);
146
+ } catch (error) {
147
+ logger.error(`Failed to parse message from stdin: ${error.message}, ${messageJson}`);
148
+ }
149
+ }
150
+ });
151
+
152
+ // Error handling
153
+ process.on('SIGTERM', () => {
154
+ logger.info('Received SIGTERM signal, shutting down language server...');
155
+ serverProcess.kill();
156
+ logger.close();
157
+ process.exit(0);
158
+ });
159
+
160
+ process.on('SIGINT', () => {
161
+ logger.info('Received SIGINT signal, shutting down language server...');
162
+ serverProcess.kill();
163
+ logger.close();
164
+ process.exit(0);
165
+ });
166
+
167
+ logger.success('Language server wrapper started, beginning message forwarding');
168
+ }
169
+
170
+ // Error handling
171
+ process.on('uncaughtException', (error) => {
172
+ logger.error(`Uncaught exception: ${error.message}`);
173
+ console.error(error);
174
+ logger.close(); // Close log stream
175
+ process.exit(1);
176
+ });
177
+
178
+ process.on('unhandledRejection', (reason, _promise) => {
179
+ logger.error(`Unhandled Promise rejection: ${reason}`);
180
+ console.error(reason);
181
+ logger.close(); // Close log stream
182
+ process.exit(1);
183
+ });
184
+
185
+ // Run main function
186
+ main();
package/package.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "zed-ets-language-server",
3
+ "version": "1.0.0",
4
+ "description": "ETS language server wrapper for Zed ArkTS extension.",
5
+ "main": "index.js",
6
+ "engines": {
7
+ "node": ">=22"
8
+ },
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ },
12
+ "author": "liuyanghejerry <liuyanghejerry@126.com>",
13
+ "license": "MIT",
14
+ "dependencies": {
15
+ "@arkts/language-server": "^1.2.2"
16
+ }
17
+ }