zed-ets-language-server 2.3.4 → 3.1.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.
- package/index.js +142 -9
- package/lib/data-parser.js +17 -12
- package/lib/lib-expander.js +11 -3
- package/lib/sdk-discovery.js +182 -0
- package/lib/sdk-discovery.test.js +252 -0
- package/package.json +3 -3
- package/tests/integration/kit-diagnostics.test.js +232 -0
- package/tests/integration/lsp-server.test.js +148 -68
- package/tests/integration/sdk-initialization.test.js +167 -0
- package/tests/mocks/mock-ets-server.js +4 -2
|
@@ -1,18 +1,36 @@
|
|
|
1
1
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
2
2
|
import { spawn } from 'child_process';
|
|
3
|
+
import { mkdtempSync } from 'fs';
|
|
4
|
+
import { tmpdir } from 'os';
|
|
3
5
|
import { fileURLToPath } from 'url';
|
|
4
6
|
import { dirname, join } from 'path';
|
|
5
7
|
|
|
6
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
7
9
|
const __dirname = dirname(__filename);
|
|
8
10
|
|
|
11
|
+
const serverPath = join(__dirname, '../../index.js');
|
|
12
|
+
const mockServerPath = join(__dirname, '../mocks/mock-ets-server.js');
|
|
13
|
+
const bundledTsdk = join(__dirname, '../../node_modules/ohos-typescript/lib');
|
|
14
|
+
|
|
15
|
+
// Hermetic env: never inherit ambient tsdk/sdk settings from the shell.
|
|
16
|
+
function baseEnv(overrides = {}) {
|
|
17
|
+
return {
|
|
18
|
+
...process.env,
|
|
19
|
+
ETS_LANG_SERVER: mockServerPath,
|
|
20
|
+
TSDK: '',
|
|
21
|
+
ZED_ETS_TSDK: '',
|
|
22
|
+
OHOS_SDK_PATH: '',
|
|
23
|
+
ZED_ETS_OHOS_SDK_PATH: '',
|
|
24
|
+
...overrides,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
9
28
|
/**
|
|
10
29
|
* 创建 LSP 消息
|
|
11
30
|
*/
|
|
12
31
|
function createLSPMessage(content) {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
return `Content-Length: ${contentLength}\r\n\r\n${json}`;
|
|
32
|
+
const contentLength = Buffer.byteLength(JSON.stringify(content));
|
|
33
|
+
return `Content-Length: ${contentLength}\r\n\r\n${JSON.stringify(content)}`;
|
|
16
34
|
}
|
|
17
35
|
|
|
18
36
|
/**
|
|
@@ -22,7 +40,7 @@ function parseLSPResponse(data) {
|
|
|
22
40
|
const text = data.toString();
|
|
23
41
|
const match = text.match(/Content-Length: (\d+)\r\n\r\n(.*)/s);
|
|
24
42
|
if (!match) return null;
|
|
25
|
-
|
|
43
|
+
|
|
26
44
|
try {
|
|
27
45
|
return JSON.parse(match[2]);
|
|
28
46
|
} catch (e) {
|
|
@@ -30,28 +48,77 @@ function parseLSPResponse(data) {
|
|
|
30
48
|
}
|
|
31
49
|
}
|
|
32
50
|
|
|
51
|
+
/**
|
|
52
|
+
* 等待特定响应
|
|
53
|
+
*/
|
|
54
|
+
function waitForResponse(responses, predicate, timeout = 2000) {
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
const startTime = Date.now();
|
|
57
|
+
const checkInterval = setInterval(() => {
|
|
58
|
+
const response = responses.find(predicate);
|
|
59
|
+
if (response) {
|
|
60
|
+
clearInterval(checkInterval);
|
|
61
|
+
resolve(response);
|
|
62
|
+
} else if (Date.now() - startTime > timeout) {
|
|
63
|
+
clearInterval(checkInterval);
|
|
64
|
+
reject(new Error('Timeout waiting for response'));
|
|
65
|
+
}
|
|
66
|
+
}, 50);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function startWrapper(env) {
|
|
71
|
+
const serverProcess = spawn('node', [serverPath], {
|
|
72
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
73
|
+
env,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const responses = [];
|
|
77
|
+
let stdoutBuffer = Buffer.alloc(0);
|
|
78
|
+
serverProcess.stdout.on('data', (data) => {
|
|
79
|
+
stdoutBuffer = Buffer.concat([stdoutBuffer, data]);
|
|
80
|
+
// SDK discovery can make initialize responses span multiple pipe chunks.
|
|
81
|
+
while (true) {
|
|
82
|
+
const headerEnd = stdoutBuffer.indexOf('\r\n\r\n');
|
|
83
|
+
if (headerEnd < 0) return;
|
|
84
|
+
const header = stdoutBuffer.subarray(0, headerEnd).toString('ascii');
|
|
85
|
+
const lengthMatch = header.match(/Content-Length:\s*(\d+)/i);
|
|
86
|
+
if (!lengthMatch) throw new Error('Invalid LSP response header');
|
|
87
|
+
const bodyStart = headerEnd + 4;
|
|
88
|
+
const bodyEnd = bodyStart + Number(lengthMatch[1]);
|
|
89
|
+
if (stdoutBuffer.length < bodyEnd) return;
|
|
90
|
+
responses.push(JSON.parse(stdoutBuffer.subarray(bodyStart, bodyEnd).toString('utf8')));
|
|
91
|
+
stdoutBuffer = stdoutBuffer.subarray(bodyEnd);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
serverProcess.stderr.on('data', (data) => {
|
|
96
|
+
console.error(`LSP Server Error: ${data}`);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return { serverProcess, responses };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function initializeMessage(id) {
|
|
103
|
+
return createLSPMessage({
|
|
104
|
+
jsonrpc: '2.0',
|
|
105
|
+
id,
|
|
106
|
+
method: 'initialize',
|
|
107
|
+
params: {
|
|
108
|
+
processId: null,
|
|
109
|
+
rootUri: null,
|
|
110
|
+
capabilities: {},
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
33
115
|
describe('LSP Server Integration Tests', () => {
|
|
34
116
|
let serverProcess;
|
|
35
117
|
let responses = [];
|
|
118
|
+
let messageId = 1;
|
|
36
119
|
|
|
37
120
|
beforeAll(() => {
|
|
38
|
-
|
|
39
|
-
const serverPath = join(__dirname, '../../index.js');
|
|
40
|
-
serverProcess = spawn('node', [serverPath], {
|
|
41
|
-
stdio: ['pipe', 'pipe', 'pipe']
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// 收集响应
|
|
45
|
-
serverProcess.stdout.on('data', (data) => {
|
|
46
|
-
const response = parseLSPResponse(data);
|
|
47
|
-
if (response) {
|
|
48
|
-
responses.push(response);
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
serverProcess.stderr.on('data', (data) => {
|
|
53
|
-
console.error(`LSP Server Error: ${data}`);
|
|
54
|
-
});
|
|
121
|
+
({ serverProcess, responses } = startWrapper(baseEnv()));
|
|
55
122
|
});
|
|
56
123
|
|
|
57
124
|
afterAll(() => {
|
|
@@ -60,65 +127,78 @@ describe('LSP Server Integration Tests', () => {
|
|
|
60
127
|
}
|
|
61
128
|
});
|
|
62
129
|
|
|
63
|
-
it('should respond to initialize request', (
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
capabilities: {}
|
|
72
|
-
}
|
|
73
|
-
};
|
|
130
|
+
it('should respond to initialize request', async () => {
|
|
131
|
+
serverProcess.stdin.write(initializeMessage(messageId));
|
|
132
|
+
const initResponse = await waitForResponse(responses, (r) => r.id === messageId);
|
|
133
|
+
messageId++;
|
|
134
|
+
|
|
135
|
+
expect(initResponse.result).toBeDefined();
|
|
136
|
+
expect(initResponse.result.capabilities).toBeDefined();
|
|
137
|
+
});
|
|
74
138
|
|
|
75
|
-
|
|
76
|
-
serverProcess.stdin.write(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
expect(initResponse).toBeDefined();
|
|
82
|
-
expect(initResponse.result).toBeDefined();
|
|
83
|
-
expect(initResponse.result.capabilities).toBeDefined();
|
|
84
|
-
done();
|
|
85
|
-
}, 1000);
|
|
139
|
+
it('should auto-detect the bundled tsdk when none is configured', async () => {
|
|
140
|
+
serverProcess.stdin.write(initializeMessage(messageId));
|
|
141
|
+
const initResponse = await waitForResponse(responses, (r) => r.id === messageId);
|
|
142
|
+
messageId++;
|
|
143
|
+
|
|
144
|
+
expect(initResponse.result.initializationOptions.typescript.tsdk).toBe(bundledTsdk);
|
|
86
145
|
});
|
|
87
146
|
|
|
88
|
-
it('should accept initialized notification', (
|
|
89
|
-
|
|
147
|
+
it('should accept initialized notification', async () => {
|
|
148
|
+
serverProcess.stdin.write(createLSPMessage({
|
|
90
149
|
jsonrpc: '2.0',
|
|
91
150
|
method: 'initialized',
|
|
92
|
-
params: {}
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
const message = createLSPMessage(initializedNotif);
|
|
96
|
-
serverProcess.stdin.write(message);
|
|
151
|
+
params: {},
|
|
152
|
+
}));
|
|
97
153
|
|
|
98
154
|
// 通知不需要响应,只需确保不崩溃
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
done();
|
|
102
|
-
}, 500);
|
|
155
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
156
|
+
expect(serverProcess.exitCode).toBeNull();
|
|
103
157
|
});
|
|
104
158
|
|
|
105
|
-
it('should handle shutdown request', (
|
|
106
|
-
|
|
159
|
+
it('should handle shutdown request', async () => {
|
|
160
|
+
serverProcess.stdin.write(createLSPMessage({
|
|
107
161
|
jsonrpc: '2.0',
|
|
108
162
|
id: 99,
|
|
109
163
|
method: 'shutdown',
|
|
110
|
-
params: null
|
|
111
|
-
};
|
|
164
|
+
params: null,
|
|
165
|
+
}));
|
|
166
|
+
|
|
167
|
+
const shutdownResponse = await waitForResponse(responses, (r) => r.id === 99);
|
|
168
|
+
// 某些 LSP 服务器可能返回 null result
|
|
169
|
+
expect(shutdownResponse).toBeDefined();
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe('LSP tsdk fallback', () => {
|
|
174
|
+
// A tsdk without lib/typescript.js (e.g. the native TypeScript 7 line)
|
|
175
|
+
// used to hang the real server inside initialize. The wrapper must
|
|
176
|
+
// substitute the bundled ohos-typescript instead of forwarding it.
|
|
177
|
+
it('substitutes a broken TSDK env value with the bundled ohos-typescript', async () => {
|
|
178
|
+
const brokenTsdkDir = mkdtempSync(join(tmpdir(), 'zed-ets-broken-tsdk-'));
|
|
179
|
+
const { serverProcess, responses } = startWrapper(baseEnv({ TSDK: brokenTsdkDir }));
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
serverProcess.stdin.write(initializeMessage(1));
|
|
183
|
+
const initResponse = await waitForResponse(responses, (r) => r.id === 1);
|
|
184
|
+
|
|
185
|
+
expect(initResponse.result.initializationOptions.typescript.tsdk).toBe(bundledTsdk);
|
|
186
|
+
} finally {
|
|
187
|
+
serverProcess.kill();
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('forwards a valid TSDK unchanged', async () => {
|
|
192
|
+
const { serverProcess, responses } = startWrapper(baseEnv({ TSDK: bundledTsdk }));
|
|
112
193
|
|
|
113
|
-
|
|
114
|
-
|
|
194
|
+
try {
|
|
195
|
+
serverProcess.stdin.write(initializeMessage(1));
|
|
196
|
+
const initResponse = await waitForResponse(responses, (r) => r.id === 1);
|
|
115
197
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
done();
|
|
121
|
-
}, 1000);
|
|
198
|
+
expect(initResponse.result.initializationOptions.typescript.tsdk).toBe(bundledTsdk);
|
|
199
|
+
} finally {
|
|
200
|
+
serverProcess.kill();
|
|
201
|
+
}
|
|
122
202
|
});
|
|
123
203
|
});
|
|
124
204
|
|
|
@@ -126,7 +206,7 @@ describe('LSP Message Protocol', () => {
|
|
|
126
206
|
it('should format messages correctly', () => {
|
|
127
207
|
const content = { jsonrpc: '2.0', method: 'test' };
|
|
128
208
|
const message = createLSPMessage(content);
|
|
129
|
-
|
|
209
|
+
|
|
130
210
|
expect(message).toContain('Content-Length:');
|
|
131
211
|
expect(message).toContain('\r\n\r\n');
|
|
132
212
|
expect(message).toContain(JSON.stringify(content));
|
|
@@ -140,7 +220,7 @@ describe('LSP Message Protocol', () => {
|
|
|
140
220
|
};
|
|
141
221
|
const data = createLSPMessage(mockResponse);
|
|
142
222
|
const parsed = parseLSPResponse(Buffer.from(data));
|
|
143
|
-
|
|
223
|
+
|
|
144
224
|
expect(parsed).toEqual(mockResponse);
|
|
145
225
|
});
|
|
146
226
|
});
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
const testDirectory = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
let fixtureDirectory;
|
|
10
|
+
let sdkRoot;
|
|
11
|
+
let hmsSdkRoot;
|
|
12
|
+
let serverProcess;
|
|
13
|
+
let stdoutBuffer = Buffer.alloc(0);
|
|
14
|
+
const responses = [];
|
|
15
|
+
|
|
16
|
+
function encodeLspMessage(message) {
|
|
17
|
+
const body = Buffer.from(JSON.stringify(message));
|
|
18
|
+
return Buffer.concat([
|
|
19
|
+
Buffer.from(`Content-Length: ${body.length}\r\n\r\n`),
|
|
20
|
+
body,
|
|
21
|
+
]);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function collectLspMessages(chunk) {
|
|
25
|
+
stdoutBuffer = Buffer.concat([stdoutBuffer, chunk]);
|
|
26
|
+
|
|
27
|
+
while (true) {
|
|
28
|
+
const headerEnd = stdoutBuffer.indexOf('\r\n\r\n');
|
|
29
|
+
if (headerEnd === -1) return;
|
|
30
|
+
|
|
31
|
+
const header = stdoutBuffer.subarray(0, headerEnd).toString('ascii');
|
|
32
|
+
const lengthMatch = header.match(/Content-Length:\s*(\d+)/i);
|
|
33
|
+
if (!lengthMatch) return;
|
|
34
|
+
|
|
35
|
+
const bodyStart = headerEnd + 4;
|
|
36
|
+
const bodyLength = Number(lengthMatch[1]);
|
|
37
|
+
if (stdoutBuffer.length < bodyStart + bodyLength) return;
|
|
38
|
+
|
|
39
|
+
const body = stdoutBuffer.subarray(bodyStart, bodyStart + bodyLength);
|
|
40
|
+
responses.push(JSON.parse(body.toString('utf8')));
|
|
41
|
+
stdoutBuffer = stdoutBuffer.subarray(bodyStart + bodyLength);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function waitForResponse(predicate, timeout = 3000) {
|
|
46
|
+
const deadline = Date.now() + timeout;
|
|
47
|
+
while (Date.now() < deadline) {
|
|
48
|
+
const response = responses.find(predicate);
|
|
49
|
+
if (response) return response;
|
|
50
|
+
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
51
|
+
}
|
|
52
|
+
throw new Error('Timed out waiting for LSP response');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
beforeAll(async () => {
|
|
56
|
+
fixtureDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'zed-arkts-deveco-'));
|
|
57
|
+
sdkRoot = path.join(fixtureDirectory, 'Contents', 'sdk', 'default', 'openharmony');
|
|
58
|
+
await fs.mkdir(path.join(sdkRoot, 'ets', 'api'), { recursive: true });
|
|
59
|
+
await fs.mkdir(path.join(sdkRoot, 'ets', 'kits'), { recursive: true });
|
|
60
|
+
await fs.mkdir(path.join(sdkRoot, 'ets', 'component'), { recursive: true });
|
|
61
|
+
await fs.mkdir(path.join(sdkRoot, 'ets', 'build-tools', 'ets-loader', 'declarations'), {
|
|
62
|
+
recursive: true,
|
|
63
|
+
});
|
|
64
|
+
await fs.writeFile(
|
|
65
|
+
path.join(sdkRoot, 'ets', 'build-tools', 'ets-loader', 'tsconfig.json'),
|
|
66
|
+
'{}\n',
|
|
67
|
+
);
|
|
68
|
+
await fs.writeFile(
|
|
69
|
+
path.join(sdkRoot, 'ets', 'kits', '@kit.AbilityKit.d.ts'),
|
|
70
|
+
'export declare class UIAbility {}\n',
|
|
71
|
+
);
|
|
72
|
+
hmsSdkRoot = path.join(fixtureDirectory, 'Contents', 'sdk', 'default', 'hms');
|
|
73
|
+
await fs.mkdir(path.join(hmsSdkRoot, 'ets', 'api'), { recursive: true });
|
|
74
|
+
await fs.mkdir(path.join(hmsSdkRoot, 'ets', 'kits'), { recursive: true });
|
|
75
|
+
await fs.writeFile(
|
|
76
|
+
path.join(hmsSdkRoot, 'ets', 'kits', '@kit.TestHmsKit.d.ts'),
|
|
77
|
+
'export declare const hmsApi: string;\n',
|
|
78
|
+
);
|
|
79
|
+
const placeholderSiblingHms = path.join(fixtureDirectory, 'hms');
|
|
80
|
+
await fs.mkdir(path.join(placeholderSiblingHms, 'ets', 'api'), { recursive: true });
|
|
81
|
+
await fs.mkdir(path.join(placeholderSiblingHms, 'ets', 'kits'), { recursive: true });
|
|
82
|
+
|
|
83
|
+
const wrapperPath = path.join(testDirectory, '..', '..', 'index.js');
|
|
84
|
+
const mockServerPath = path.join(testDirectory, '..', 'mocks', 'mock-ets-server.js');
|
|
85
|
+
const tsdk = path.join(testDirectory, '..', '..', 'node_modules', 'ohos-typescript', 'lib');
|
|
86
|
+
const env = { ...process.env };
|
|
87
|
+
delete env.ZED_ETS_OHOS_SDK_PATH;
|
|
88
|
+
delete env.OHOS_SDK_PATH;
|
|
89
|
+
delete env.HARMONYOS_SDK_HOME;
|
|
90
|
+
delete env.OPENHARMONY_SDK_HOME;
|
|
91
|
+
delete env.DEVECO_SDK_HOME;
|
|
92
|
+
delete env.ZED_ETS_HMS_SDK_PATH;
|
|
93
|
+
delete env.HMS_SDK_PATH;
|
|
94
|
+
Object.assign(env, {
|
|
95
|
+
ETS_LANG_SERVER: mockServerPath,
|
|
96
|
+
ZED_ETS_TSDK: tsdk,
|
|
97
|
+
DEVECO_STUDIO_HOME: fixtureDirectory,
|
|
98
|
+
TMPDIR: fixtureDirectory,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
serverProcess = spawn(process.execPath, [wrapperPath], {
|
|
102
|
+
env,
|
|
103
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
104
|
+
});
|
|
105
|
+
serverProcess.stdout.on('data', collectLspMessages);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
afterAll(async () => {
|
|
109
|
+
serverProcess?.kill();
|
|
110
|
+
await fs.rm(fixtureDirectory, { recursive: true, force: true });
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('SDK initialization', () => {
|
|
114
|
+
it('injects the DevEco OpenHarmony SDK into ArkTS initialization', async () => {
|
|
115
|
+
serverProcess.stdin.write(
|
|
116
|
+
encodeLspMessage({
|
|
117
|
+
jsonrpc: '2.0',
|
|
118
|
+
id: 1,
|
|
119
|
+
method: 'initialize',
|
|
120
|
+
params: {
|
|
121
|
+
processId: process.pid,
|
|
122
|
+
rootUri: 'file:///tmp/harmony-project',
|
|
123
|
+
capabilities: {},
|
|
124
|
+
initializationOptions: {},
|
|
125
|
+
},
|
|
126
|
+
}),
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const response = await waitForResponse((message) => message.id === 1);
|
|
130
|
+
const initializationOptions = response.result.initializationOptions;
|
|
131
|
+
|
|
132
|
+
expect(initializationOptions.ohos.sdkPath).toBe(sdkRoot);
|
|
133
|
+
expect(initializationOptions.ets.sdkPath).toBe(sdkRoot);
|
|
134
|
+
expect(initializationOptions.ohos.baseUrl).toBe(path.join(sdkRoot, 'ets'));
|
|
135
|
+
expect(initializationOptions.ets.hmsPath).toBe(hmsSdkRoot);
|
|
136
|
+
expect(initializationOptions.ohos.hmsSdkPath).toBe(hmsSdkRoot);
|
|
137
|
+
expect(initializationOptions.ohos.paths['*']).toContain(
|
|
138
|
+
path.join(hmsSdkRoot, 'ets', 'kits', '*'),
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('does not infer an HMS SDK from the placeholder OpenHarmony SDK', async () => {
|
|
143
|
+
serverProcess.stdin.write(
|
|
144
|
+
encodeLspMessage({
|
|
145
|
+
jsonrpc: '2.0',
|
|
146
|
+
id: 2,
|
|
147
|
+
method: 'initialize',
|
|
148
|
+
params: {
|
|
149
|
+
processId: process.pid,
|
|
150
|
+
rootUri: 'file:///tmp/harmony-project',
|
|
151
|
+
capabilities: {},
|
|
152
|
+
initializationOptions: {
|
|
153
|
+
ohosSdkPath: path.join(fixtureDirectory, 'invalid-openharmony'),
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
}),
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const response = await waitForResponse((message) => message.id === 2);
|
|
160
|
+
const initializationOptions = response.result.initializationOptions;
|
|
161
|
+
|
|
162
|
+
expect(initializationOptions.ets.sdkPath).toBe(
|
|
163
|
+
path.join(fixtureDirectory, 'zed-ets-empty-ohos-sdk'),
|
|
164
|
+
);
|
|
165
|
+
expect(initializationOptions.ets.hmsPath).toBeUndefined();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
@@ -91,10 +91,12 @@ struct Test {
|
|
|
91
91
|
textDocumentSync: 1,
|
|
92
92
|
documentFormattingProvider: true,
|
|
93
93
|
documentRangeFormattingProvider: true
|
|
94
|
-
}
|
|
94
|
+
},
|
|
95
|
+
// Echo what the wrapper forwarded so tests can assert on it.
|
|
96
|
+
initializationOptions: message.params?.initializationOptions ?? {}
|
|
95
97
|
}
|
|
96
98
|
};
|
|
97
|
-
|
|
99
|
+
|
|
98
100
|
process.send(response);
|
|
99
101
|
}
|
|
100
102
|
|