arkts-lsp-proxy 0.1.0 → 0.1.2
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/README.md +36 -10
- package/dist/ace-server.d.ts +2 -1
- package/dist/ace-server.d.ts.map +1 -1
- package/dist/ace-server.js +60 -3
- package/dist/ace-server.js.map +1 -1
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +12 -2
- package/dist/env.js.map +1 -1
- package/dist/hvigor.d.ts +25 -0
- package/dist/hvigor.d.ts.map +1 -1
- package/dist/hvigor.js +125 -17
- package/dist/hvigor.js.map +1 -1
- package/dist/index.js +15 -41
- package/dist/index.js.map +1 -1
- package/dist/project.d.ts +23 -4
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +331 -63
- package/dist/project.js.map +1 -1
- package/dist/proxy.d.ts +22 -5
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +652 -36
- package/dist/proxy.js.map +1 -1
- package/package.json +1 -1
package/dist/proxy.js
CHANGED
|
@@ -1,64 +1,680 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.injectInitializationOptions = injectInitializationOptions;
|
|
4
37
|
exports.createProxy = createProxy;
|
|
5
38
|
const node_1 = require("vscode-jsonrpc/node");
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
39
|
+
const vscode_jsonrpc_1 = require("vscode-jsonrpc");
|
|
40
|
+
const path = __importStar(require("node:path"));
|
|
41
|
+
const node_url_1 = require("node:url");
|
|
42
|
+
const project_1 = require("./project");
|
|
43
|
+
const ace_server_1 = require("./ace-server");
|
|
44
|
+
const hvigor_1 = require("./hvigor");
|
|
45
|
+
const ACE_NOTIFICATION_METHODS = {
|
|
46
|
+
'textDocument/didOpen': 'aceProject/onAsyncDidOpen',
|
|
47
|
+
'textDocument/didChange': 'aceProject/onAsyncDidChange',
|
|
48
|
+
'textDocument/didClose': 'aceProject/onAsyncDidClose',
|
|
49
|
+
};
|
|
50
|
+
const ACE_FIND_USAGES_METHOD = 'aceProject/onAsyncFindUsages';
|
|
51
|
+
const ACE_REQUEST_METHODS = {
|
|
52
|
+
'textDocument/hover': 'aceProject/onAsyncHover',
|
|
53
|
+
'textDocument/completion': 'aceProject/onAsyncCompletion',
|
|
54
|
+
'completionItem/resolve': 'aceProject/onAsyncCompletionResolve',
|
|
55
|
+
'textDocument/definition': 'aceProject/onAsyncDefinition',
|
|
56
|
+
'textDocument/references': ACE_FIND_USAGES_METHOD,
|
|
57
|
+
'textDocument/signatureHelp': 'aceProject/onAsyncSignatureHelp',
|
|
58
|
+
};
|
|
59
|
+
const ACE_RESPONSE_METHODS = new Set(Object.values(ACE_REQUEST_METHODS));
|
|
60
|
+
const ACE_MODULE_INIT_METHOD = 'aceProject/onModuleInitFinish';
|
|
61
|
+
function isPlainObject(value) {
|
|
62
|
+
return typeof value === 'object' && value !== null;
|
|
63
|
+
}
|
|
64
|
+
function createQueueToken() {
|
|
65
|
+
return `arkts-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
66
|
+
}
|
|
67
|
+
function uriToFilePath(uri) {
|
|
68
|
+
if (typeof uri !== 'string' || !uri.length) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
if (uri.startsWith('file://')) {
|
|
72
|
+
try {
|
|
73
|
+
return (0, node_url_1.fileURLToPath)(uri);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return path.resolve(uri);
|
|
80
|
+
}
|
|
81
|
+
function detectLanguageId(uri) {
|
|
82
|
+
const ext = path.extname(uri).toLowerCase();
|
|
83
|
+
if (ext === '.ets' || ext === '.d.ets') {
|
|
84
|
+
return 'deveco.apptool.ets';
|
|
85
|
+
}
|
|
86
|
+
if (ext === '.ts') {
|
|
87
|
+
return 'deveco.apptool.ts';
|
|
88
|
+
}
|
|
89
|
+
if (ext === '.js') {
|
|
90
|
+
return 'deveco.apptool.js';
|
|
91
|
+
}
|
|
92
|
+
return 'deveco.apptool.ts';
|
|
93
|
+
}
|
|
94
|
+
function normalizeAceLanguageId(uri, languageId) {
|
|
95
|
+
if (typeof languageId === 'string' && languageId.startsWith('deveco.apptool.')) {
|
|
96
|
+
return languageId;
|
|
97
|
+
}
|
|
98
|
+
return detectLanguageId(uri);
|
|
99
|
+
}
|
|
100
|
+
function inferProjectRootFromInitializeParams(params) {
|
|
101
|
+
if (!isPlainObject(params)) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
const candidate = (Array.isArray(params.workspaceFolders)
|
|
105
|
+
? params.workspaceFolders[0]?.uri
|
|
106
|
+
: undefined) ??
|
|
107
|
+
params.rootUri ??
|
|
108
|
+
params.rootPath;
|
|
109
|
+
return uriToFilePath(candidate ?? null);
|
|
110
|
+
}
|
|
111
|
+
function getEditorFiles(openFiles) {
|
|
112
|
+
return Array.from(openFiles)
|
|
113
|
+
.map((uri) => uriToFilePath(uri))
|
|
114
|
+
.filter((filePath) => Boolean(filePath));
|
|
115
|
+
}
|
|
116
|
+
function getOpenFileUris(openFiles) {
|
|
117
|
+
return Array.from(openFiles);
|
|
118
|
+
}
|
|
119
|
+
function createRequestPayload(params) {
|
|
120
|
+
return {
|
|
121
|
+
requestId: createQueueToken(),
|
|
122
|
+
params: params || {},
|
|
123
|
+
editorFiles: [],
|
|
124
|
+
traceId: createQueueToken(),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function isModuleInitSuccess(payload) {
|
|
128
|
+
if (Array.isArray(payload)) {
|
|
129
|
+
return payload.length > 0 && payload.every(isModuleInitSuccess);
|
|
130
|
+
}
|
|
131
|
+
if (typeof payload === 'boolean') {
|
|
132
|
+
return payload;
|
|
133
|
+
}
|
|
134
|
+
if (!isPlainObject(payload)) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
if ('success' in payload && typeof payload.success === 'boolean') {
|
|
138
|
+
return payload.success;
|
|
139
|
+
}
|
|
140
|
+
if ('code' in payload && typeof payload.code === 'number') {
|
|
141
|
+
return payload.code === 0;
|
|
142
|
+
}
|
|
143
|
+
if ('status' in payload && typeof payload.status === 'string') {
|
|
144
|
+
return payload.status.toLowerCase() === 'success';
|
|
145
|
+
}
|
|
146
|
+
if ('result' in payload && typeof payload.result === 'boolean') {
|
|
147
|
+
return payload.result;
|
|
148
|
+
}
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
function extractTextDocument(params) {
|
|
152
|
+
if (!isPlainObject(params)) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
const textDocument = params.textDocument ?? null;
|
|
156
|
+
return isPlainObject(textDocument) ? textDocument : null;
|
|
157
|
+
}
|
|
158
|
+
function mapNotification(method, params, openFiles) {
|
|
159
|
+
if (!ACE_NOTIFICATION_METHODS[method]) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
if (method === 'textDocument/didOpen') {
|
|
163
|
+
const textDocument = extractTextDocument(params);
|
|
164
|
+
if (!textDocument) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
const uri = typeof textDocument.uri === 'string' ? textDocument.uri : null;
|
|
168
|
+
if (!uri) {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
method: ACE_NOTIFICATION_METHODS[method],
|
|
173
|
+
params: {
|
|
174
|
+
requestId: createQueueToken(),
|
|
175
|
+
params: {
|
|
176
|
+
textDocument: {
|
|
177
|
+
uri,
|
|
178
|
+
languageId: normalizeAceLanguageId(uri, textDocument.languageId),
|
|
179
|
+
version: textDocument.version,
|
|
180
|
+
text: typeof textDocument.text === 'string' ? textDocument.text : '',
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
editorFiles: getEditorFiles(openFiles),
|
|
184
|
+
traceId: createQueueToken(),
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
if (method === 'textDocument/didClose') {
|
|
189
|
+
const textDocument = extractTextDocument(params);
|
|
190
|
+
if (!textDocument) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
const uri = typeof textDocument.uri === 'string' ? textDocument.uri : null;
|
|
194
|
+
if (!uri) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
method: ACE_NOTIFICATION_METHODS[method],
|
|
199
|
+
params: {
|
|
200
|
+
requestId: createQueueToken(),
|
|
201
|
+
params: {
|
|
202
|
+
textDocument,
|
|
203
|
+
},
|
|
204
|
+
editorFiles: getEditorFiles(openFiles),
|
|
205
|
+
traceId: createQueueToken(),
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
if (method === 'textDocument/didChange') {
|
|
210
|
+
const textDocument = extractTextDocument(params);
|
|
211
|
+
if (!textDocument) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
const uri = typeof textDocument.uri === 'string' ? textDocument.uri : null;
|
|
215
|
+
if (!uri) {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
method: ACE_NOTIFICATION_METHODS[method],
|
|
220
|
+
params: {
|
|
221
|
+
requestId: createQueueToken(),
|
|
222
|
+
params: {
|
|
223
|
+
textDocument: {
|
|
224
|
+
uri,
|
|
225
|
+
languageId: detectLanguageId(uri),
|
|
226
|
+
version: textDocument.version,
|
|
227
|
+
text: typeof textDocument.text === 'string' ? textDocument.text : '',
|
|
228
|
+
},
|
|
229
|
+
contentChanges: Array.isArray(params?.contentChanges) ? params.contentChanges : [],
|
|
230
|
+
},
|
|
231
|
+
editorFiles: getEditorFiles(openFiles),
|
|
232
|
+
traceId: createQueueToken(),
|
|
233
|
+
},
|
|
14
234
|
};
|
|
15
|
-
return { ...message, params };
|
|
16
235
|
}
|
|
17
|
-
return
|
|
236
|
+
return {
|
|
237
|
+
method: ACE_NOTIFICATION_METHODS[method],
|
|
238
|
+
params: {
|
|
239
|
+
...createRequestPayload(params),
|
|
240
|
+
editorFiles: getEditorFiles(openFiles),
|
|
241
|
+
},
|
|
242
|
+
};
|
|
18
243
|
}
|
|
19
|
-
function
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
244
|
+
function mapRequest(method, params, openFiles) {
|
|
245
|
+
const mappedMethod = ACE_REQUEST_METHODS[method];
|
|
246
|
+
if (!mappedMethod) {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
const payload = {
|
|
250
|
+
...createRequestPayload(params),
|
|
251
|
+
editorFiles: getEditorFiles(openFiles),
|
|
252
|
+
};
|
|
253
|
+
if (method === 'textDocument/definition') {
|
|
254
|
+
payload.params = {
|
|
255
|
+
...(isPlainObject(payload.params) ? payload.params : {}),
|
|
256
|
+
isGotoDefinition: true,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
method: mappedMethod,
|
|
261
|
+
params: payload,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function isDevEcoEnv(value) {
|
|
265
|
+
return (isPlainObject(value) &&
|
|
266
|
+
typeof value.devecoHome === 'string' &&
|
|
267
|
+
typeof value.sdkPath === 'string' &&
|
|
268
|
+
typeof value.aceServerPath === 'string' &&
|
|
269
|
+
typeof value.nodeBin === 'string' &&
|
|
270
|
+
typeof value.hvigorPath === 'string');
|
|
271
|
+
}
|
|
272
|
+
function isLegacyPayload(value) {
|
|
273
|
+
return (isPlainObject(value) &&
|
|
274
|
+
typeof value.rootUri === 'string' &&
|
|
275
|
+
typeof value.lspServerWorkspacePath === 'string' &&
|
|
276
|
+
Array.isArray(value.modules));
|
|
277
|
+
}
|
|
278
|
+
function isModernMode(value) {
|
|
279
|
+
return isPlainObject(value) && isDevEcoEnv(value.env);
|
|
280
|
+
}
|
|
281
|
+
function injectInitializationOptions(message, payload) {
|
|
282
|
+
if (message.method !== 'initialize' || !message.params) {
|
|
283
|
+
return message;
|
|
284
|
+
}
|
|
285
|
+
const params = { ...message.params };
|
|
286
|
+
const existing = typeof params.initializationOptions === 'object' &&
|
|
287
|
+
params.initializationOptions !== null
|
|
288
|
+
? params.initializationOptions
|
|
289
|
+
: {};
|
|
290
|
+
params.initializationOptions = {
|
|
291
|
+
...existing,
|
|
292
|
+
...payload,
|
|
293
|
+
};
|
|
294
|
+
return { ...message, params };
|
|
295
|
+
}
|
|
296
|
+
function createLegacyProxy(clientConn, proc, payload) {
|
|
297
|
+
if (!proc.stdout || !proc.stdin) {
|
|
23
298
|
throw new Error('aceProcess must have both stdout and stdin streams');
|
|
24
299
|
}
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
clientConn.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return aceConn.sendRequest(method,
|
|
300
|
+
const aceConn = (0, node_1.createMessageConnection)(new node_1.StreamMessageReader(proc.stdout), new node_1.StreamMessageWriter(proc.stdin));
|
|
301
|
+
let disposed = false;
|
|
302
|
+
clientConn.onRequest((method, params) => {
|
|
303
|
+
if (method === 'initialize' && payload) {
|
|
304
|
+
const msg = injectInitializationOptions({
|
|
305
|
+
id: 0,
|
|
306
|
+
method,
|
|
307
|
+
params: isPlainObject(params) ? params : {},
|
|
308
|
+
}, payload);
|
|
309
|
+
return aceConn.sendRequest(method, msg.params);
|
|
35
310
|
}
|
|
36
|
-
return aceConn.sendRequest(method, params
|
|
311
|
+
return aceConn.sendRequest(method, params);
|
|
37
312
|
});
|
|
38
313
|
aceConn.onNotification((method, params) => {
|
|
39
314
|
clientConn.sendNotification(method, params);
|
|
40
315
|
});
|
|
41
|
-
aceConn.
|
|
42
|
-
|
|
43
|
-
});
|
|
44
|
-
aceConn.onError(([err]) => {
|
|
45
|
-
process.stderr.write(`[arkts-lsp] ace connection error: ${err.message}\n`);
|
|
46
|
-
clientConn.dispose();
|
|
316
|
+
aceConn.onError((error) => {
|
|
317
|
+
process.stderr.write(`[arkts-lsp] legacy ace connection error: ${String(error)}\n`);
|
|
47
318
|
});
|
|
48
|
-
clientConn.
|
|
49
|
-
|
|
50
|
-
aceConn.dispose();
|
|
319
|
+
clientConn.onNotification((method, params) => {
|
|
320
|
+
aceConn.sendNotification(method, params);
|
|
51
321
|
});
|
|
52
|
-
|
|
53
|
-
|
|
322
|
+
clientConn.onError((error) => {
|
|
323
|
+
process.stderr.write(`[arkts-lsp] client connection error: ${String(error)}\n`);
|
|
54
324
|
});
|
|
55
325
|
clientConn.listen();
|
|
56
326
|
aceConn.listen();
|
|
57
327
|
return {
|
|
58
328
|
dispose: () => {
|
|
329
|
+
if (disposed) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
disposed = true;
|
|
59
333
|
clientConn.dispose();
|
|
60
334
|
aceConn.dispose();
|
|
61
335
|
},
|
|
62
336
|
};
|
|
63
337
|
}
|
|
338
|
+
function createProxy(clientIn, clientOut, envOrLegacy, maybeOptions) {
|
|
339
|
+
const clientConn = (0, node_1.createMessageConnection)(new node_1.StreamMessageReader(clientIn), new node_1.StreamMessageWriter(clientOut));
|
|
340
|
+
if (!isDevEcoEnv(envOrLegacy)) {
|
|
341
|
+
const legacyProc = envOrLegacy.process ?? envOrLegacy;
|
|
342
|
+
if (!legacyProc) {
|
|
343
|
+
throw new Error('legacy mode requires ChildProcess-like object with stdin/stdout streams');
|
|
344
|
+
}
|
|
345
|
+
return createLegacyProxy(clientConn, legacyProc, isLegacyPayload(maybeOptions) ? maybeOptions : undefined);
|
|
346
|
+
}
|
|
347
|
+
const env = envOrLegacy;
|
|
348
|
+
const options = isModernMode(maybeOptions) ? maybeOptions : { env, projectRootHint: undefined };
|
|
349
|
+
const explicitProjectRoot = options.projectRootHint || process.env.ARKTS_PROJECT_ROOT || process.env.ARKTS_PROJECT_PATH;
|
|
350
|
+
const openFiles = new Set();
|
|
351
|
+
const requestQueue = [];
|
|
352
|
+
const notificationQueue = [];
|
|
353
|
+
const pendingAceRequests = new Map();
|
|
354
|
+
let isInitialized = false;
|
|
355
|
+
let isServerReady = false;
|
|
356
|
+
let isBootstrapping = false;
|
|
357
|
+
let bootstrapPromise = null;
|
|
358
|
+
let initializePromise = null;
|
|
359
|
+
let syncPromise = null;
|
|
360
|
+
let aceConn = null;
|
|
361
|
+
let aceHandle = null;
|
|
362
|
+
let project = null;
|
|
363
|
+
let disposed = false;
|
|
364
|
+
function queueRequest(run) {
|
|
365
|
+
return new Promise((resolve, reject) => {
|
|
366
|
+
requestQueue.push({ run, resolve, reject });
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
function queueNotification(method, params) {
|
|
370
|
+
notificationQueue.push({ method, params });
|
|
371
|
+
}
|
|
372
|
+
function clearQueues(error) {
|
|
373
|
+
const finalError = error ?? new Error('proxy disposed');
|
|
374
|
+
while (requestQueue.length > 0) {
|
|
375
|
+
const p = requestQueue.shift();
|
|
376
|
+
if (p) {
|
|
377
|
+
p.reject(finalError);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
notificationQueue.length = 0;
|
|
381
|
+
for (const pending of pendingAceRequests.values()) {
|
|
382
|
+
pending.reject(finalError);
|
|
383
|
+
}
|
|
384
|
+
pendingAceRequests.clear();
|
|
385
|
+
}
|
|
386
|
+
function flushQueues() {
|
|
387
|
+
if (!isServerReady || !aceConn) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
while (notificationQueue.length > 0) {
|
|
391
|
+
const n = notificationQueue.shift();
|
|
392
|
+
if (!n) {
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
try {
|
|
396
|
+
aceConn.sendNotification(n.method, n.params);
|
|
397
|
+
}
|
|
398
|
+
catch {
|
|
399
|
+
// ignore flush notification errors
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
while (requestQueue.length > 0) {
|
|
403
|
+
const p = requestQueue.shift();
|
|
404
|
+
if (!p) {
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
p.run().then(p.resolve, p.reject);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
function completePendingAceRequest(method, params) {
|
|
411
|
+
if (!ACE_RESPONSE_METHODS.has(method) || !isPlainObject(params)) {
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
const requestId = typeof params.requestId === 'string' ? params.requestId : null;
|
|
415
|
+
if (!requestId) {
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
const pending = pendingAceRequests.get(requestId);
|
|
419
|
+
if (!pending) {
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
pendingAceRequests.delete(requestId);
|
|
423
|
+
pending.resolve('result' in params ? params.result : params);
|
|
424
|
+
return true;
|
|
425
|
+
}
|
|
426
|
+
function sendAceRequestAsNotification(conn, method, params) {
|
|
427
|
+
const requestId = typeof params.requestId === 'string' ? params.requestId : createQueueToken();
|
|
428
|
+
const payload = { ...params, requestId };
|
|
429
|
+
return new Promise((resolve, reject) => {
|
|
430
|
+
pendingAceRequests.set(requestId, { resolve, reject });
|
|
431
|
+
try {
|
|
432
|
+
conn.sendNotification(method, payload);
|
|
433
|
+
}
|
|
434
|
+
catch (err) {
|
|
435
|
+
pendingAceRequests.delete(requestId);
|
|
436
|
+
reject(err);
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
function sendAceRequest(conn, method, params, useNotificationResponse) {
|
|
441
|
+
return useNotificationResponse
|
|
442
|
+
? sendAceRequestAsNotification(conn, method, params)
|
|
443
|
+
: conn.sendRequest(method, params);
|
|
444
|
+
}
|
|
445
|
+
function createAceConnection(proc) {
|
|
446
|
+
if (!proc.stdout || !proc.stdin) {
|
|
447
|
+
throw new Error('aceProcess must have both stdout and stdin streams');
|
|
448
|
+
}
|
|
449
|
+
const conn = (0, node_1.createMessageConnection)(new node_1.StreamMessageReader(proc.stdout), new node_1.StreamMessageWriter(proc.stdin));
|
|
450
|
+
conn.onNotification((method, params) => {
|
|
451
|
+
if (completePendingAceRequest(method, params)) {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
if (method === ACE_MODULE_INIT_METHOD) {
|
|
455
|
+
if (isModuleInitSuccess(params)) {
|
|
456
|
+
isServerReady = true;
|
|
457
|
+
flushQueues();
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
process.stderr.write('[arkts-lsp] ace server module init reported failure, continue serving requests\n');
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
clientConn.sendNotification(method, params);
|
|
464
|
+
});
|
|
465
|
+
conn.onRequest((method, params) => {
|
|
466
|
+
if (method === 'client/registerCapability') {
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
return clientConn.sendRequest(method, params).catch((error) => {
|
|
470
|
+
process.stderr.write(`[arkts-lsp] client request ${method} failed: ${String(error)}\n`);
|
|
471
|
+
return null;
|
|
472
|
+
});
|
|
473
|
+
});
|
|
474
|
+
conn.onError((error) => {
|
|
475
|
+
process.stderr.write(`[arkts-lsp] ace connection error: ${String(error)}\n`);
|
|
476
|
+
clearQueues(error);
|
|
477
|
+
});
|
|
478
|
+
return conn;
|
|
479
|
+
}
|
|
480
|
+
function scheduleHvigorSync(projectRoot) {
|
|
481
|
+
if (syncPromise) {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
const config = (0, hvigor_1.parseHvigorSyncConfig)();
|
|
485
|
+
process.stderr.write(`[arkts-lsp] hvigor metadata sync mode=${config.mode}, timeout=${config.timeoutMs}ms\n`);
|
|
486
|
+
syncPromise = (0, hvigor_1.runHvigorSyncAsync)(env, projectRoot, config)
|
|
487
|
+
.then((result) => {
|
|
488
|
+
const before = result.metadataBefore.state;
|
|
489
|
+
const after = result.metadataAfter?.state ?? before;
|
|
490
|
+
process.stderr.write(`[arkts-lsp] hvigor sync ${result.status}; metadata ${before} -> ${after}; elapsed=${result.elapsedMs}ms\n`);
|
|
491
|
+
if (result.errorMessage) {
|
|
492
|
+
process.stderr.write(`[arkts-lsp] hvigor sync detail: ${result.errorMessage}\n`);
|
|
493
|
+
}
|
|
494
|
+
})
|
|
495
|
+
.catch((error) => {
|
|
496
|
+
process.stderr.write(`[arkts-lsp] hvigor sync unexpected error: ${String(error)}\n`);
|
|
497
|
+
})
|
|
498
|
+
.finally(() => {
|
|
499
|
+
syncPromise = null;
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
function ensureServer(rootHint) {
|
|
503
|
+
if (bootstrapPromise) {
|
|
504
|
+
return bootstrapPromise;
|
|
505
|
+
}
|
|
506
|
+
bootstrapPromise = (async () => {
|
|
507
|
+
isBootstrapping = true;
|
|
508
|
+
const candidate = explicitProjectRoot
|
|
509
|
+
? path.resolve(explicitProjectRoot)
|
|
510
|
+
: rootHint
|
|
511
|
+
? path.resolve(rootHint)
|
|
512
|
+
: process.cwd();
|
|
513
|
+
const resolvedRoot = (0, project_1.findProjectRoot)(candidate);
|
|
514
|
+
if (!resolvedRoot) {
|
|
515
|
+
throw new vscode_jsonrpc_1.ResponseError(vscode_jsonrpc_1.ErrorCodes.InvalidParams, 'No ArkTS project root found in workspace.');
|
|
516
|
+
}
|
|
517
|
+
const parsed = (0, project_1.parseProject)(resolvedRoot, env.sdkPath);
|
|
518
|
+
if (!parsed) {
|
|
519
|
+
throw new vscode_jsonrpc_1.ResponseError(vscode_jsonrpc_1.ErrorCodes.InvalidParams, `Unable to parse build-profile.json5 at ${resolvedRoot}`);
|
|
520
|
+
}
|
|
521
|
+
project = parsed;
|
|
522
|
+
scheduleHvigorSync(parsed.projectRoot);
|
|
523
|
+
const handle = (0, ace_server_1.startAceServer)(env);
|
|
524
|
+
aceHandle = handle;
|
|
525
|
+
const conn = createAceConnection(handle.process);
|
|
526
|
+
aceConn = conn;
|
|
527
|
+
conn.listen();
|
|
528
|
+
handle.onExit((code, signal) => {
|
|
529
|
+
if (disposed) {
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
process.stderr.write(`[arkts-lsp] ace-server exited (code=${code}, signal=${signal})\n`);
|
|
533
|
+
clearQueues(new vscode_jsonrpc_1.ResponseError(vscode_jsonrpc_1.ErrorCodes.InternalError, 'ace-server exited unexpectedly'));
|
|
534
|
+
});
|
|
535
|
+
return conn;
|
|
536
|
+
})();
|
|
537
|
+
const runningPromise = bootstrapPromise;
|
|
538
|
+
runningPromise.finally(() => {
|
|
539
|
+
isBootstrapping = false;
|
|
540
|
+
if (bootstrapPromise === runningPromise) {
|
|
541
|
+
bootstrapPromise = null;
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
return runningPromise;
|
|
545
|
+
}
|
|
546
|
+
function resolveInitializeRequest(params) {
|
|
547
|
+
if (initializePromise) {
|
|
548
|
+
return initializePromise;
|
|
549
|
+
}
|
|
550
|
+
const initRootHint = inferProjectRootFromInitializeParams(params);
|
|
551
|
+
initializePromise = (async () => {
|
|
552
|
+
const connection = await ensureServer(initRootHint);
|
|
553
|
+
if (!project) {
|
|
554
|
+
throw new vscode_jsonrpc_1.ResponseError(vscode_jsonrpc_1.ErrorCodes.InvalidParams, 'Project not available');
|
|
555
|
+
}
|
|
556
|
+
const payload = (0, project_1.buildInitializationOptions)(project);
|
|
557
|
+
const initMessage = injectInitializationOptions({
|
|
558
|
+
id: 0,
|
|
559
|
+
method: 'initialize',
|
|
560
|
+
params: isPlainObject(params) ? params : {},
|
|
561
|
+
}, payload);
|
|
562
|
+
const initParams = (initMessage.params || {});
|
|
563
|
+
if (getEditorFiles(openFiles).length > 0) {
|
|
564
|
+
initParams.editorFiles = getEditorFiles(openFiles);
|
|
565
|
+
}
|
|
566
|
+
const result = await connection.sendRequest('initialize', initParams);
|
|
567
|
+
isInitialized = true;
|
|
568
|
+
isServerReady = true;
|
|
569
|
+
flushQueues();
|
|
570
|
+
return result;
|
|
571
|
+
})().catch((err) => {
|
|
572
|
+
isInitialized = false;
|
|
573
|
+
clearQueues(err);
|
|
574
|
+
throw err;
|
|
575
|
+
}).finally(() => {
|
|
576
|
+
initializePromise = null;
|
|
577
|
+
});
|
|
578
|
+
return initializePromise;
|
|
579
|
+
}
|
|
580
|
+
function onRequest(method, params) {
|
|
581
|
+
if (method === 'initialize') {
|
|
582
|
+
return resolveInitializeRequest(params);
|
|
583
|
+
}
|
|
584
|
+
if (!isInitialized && !initializePromise) {
|
|
585
|
+
return Promise.reject(new vscode_jsonrpc_1.ResponseError(vscode_jsonrpc_1.ErrorCodes.ServerNotInitialized, 'Initialize first.'));
|
|
586
|
+
}
|
|
587
|
+
const mapped = mapRequest(method, params, openFiles);
|
|
588
|
+
const targetMethod = mapped?.method ?? method;
|
|
589
|
+
const targetParams = mapped?.params ?? createRequestPayload(params);
|
|
590
|
+
const useNotificationResponse = Boolean(mapped);
|
|
591
|
+
if (!aceConn) {
|
|
592
|
+
if (!initializePromise) {
|
|
593
|
+
return Promise.reject(new vscode_jsonrpc_1.ResponseError(vscode_jsonrpc_1.ErrorCodes.InternalError, 'ace connection is not ready'));
|
|
594
|
+
}
|
|
595
|
+
return queueRequest(() => {
|
|
596
|
+
if (!aceConn) {
|
|
597
|
+
return Promise.reject(new vscode_jsonrpc_1.ResponseError(vscode_jsonrpc_1.ErrorCodes.InternalError, 'ace connection is not ready'));
|
|
598
|
+
}
|
|
599
|
+
return sendAceRequest(aceConn, targetMethod, targetParams, useNotificationResponse);
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
if (!isServerReady) {
|
|
603
|
+
const activeConn = aceConn;
|
|
604
|
+
if (!activeConn) {
|
|
605
|
+
return Promise.reject(new vscode_jsonrpc_1.ResponseError(vscode_jsonrpc_1.ErrorCodes.InternalError, 'ace connection is not ready'));
|
|
606
|
+
}
|
|
607
|
+
return queueRequest(() => sendAceRequest(activeConn, targetMethod, targetParams, useNotificationResponse));
|
|
608
|
+
}
|
|
609
|
+
return sendAceRequest(aceConn, targetMethod, targetParams, useNotificationResponse);
|
|
610
|
+
}
|
|
611
|
+
function onNotification(method, params) {
|
|
612
|
+
if (method === 'textDocument/didOpen') {
|
|
613
|
+
const textDocument = isPlainObject(params) ? params.textDocument : undefined;
|
|
614
|
+
const uri = isPlainObject(textDocument) ? textDocument.uri : undefined;
|
|
615
|
+
if (uri && typeof uri === 'string') {
|
|
616
|
+
openFiles.add(uri);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
if (method === 'textDocument/didClose') {
|
|
620
|
+
const textDocument = isPlainObject(params) ? params.textDocument : undefined;
|
|
621
|
+
const uri = isPlainObject(textDocument) ? textDocument.uri : undefined;
|
|
622
|
+
if (uri && typeof uri === 'string') {
|
|
623
|
+
openFiles.delete(uri);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
if (method === 'initialized') {
|
|
627
|
+
const editors = getOpenFileUris(openFiles).map((uri) => ({ uri, selected: true, receivedOpened: false }));
|
|
628
|
+
const payload = {
|
|
629
|
+
...(isPlainObject(params) ? params : {}),
|
|
630
|
+
editors,
|
|
631
|
+
};
|
|
632
|
+
if (!aceConn) {
|
|
633
|
+
queueNotification('initialized', payload);
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
aceConn.sendNotification('initialized', payload);
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
const mapped = mapNotification(method, params, openFiles);
|
|
640
|
+
const finalMethod = mapped ? mapped.method : method;
|
|
641
|
+
const finalParams = mapped ? mapped.params : createRequestPayload(params);
|
|
642
|
+
if (!isServerReady || !aceConn) {
|
|
643
|
+
queueNotification(finalMethod, finalParams);
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
try {
|
|
647
|
+
aceConn.sendNotification(finalMethod, finalParams);
|
|
648
|
+
}
|
|
649
|
+
catch {
|
|
650
|
+
queueNotification(finalMethod, finalParams);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
clientConn.onRequest((method, params) => {
|
|
654
|
+
return onRequest(method, params);
|
|
655
|
+
});
|
|
656
|
+
clientConn.onNotification((method, params) => {
|
|
657
|
+
onNotification(method, params);
|
|
658
|
+
});
|
|
659
|
+
clientConn.onError((error) => {
|
|
660
|
+
process.stderr.write(`[arkts-lsp] client connection error: ${String(error)}\n`);
|
|
661
|
+
});
|
|
662
|
+
clientConn.listen();
|
|
663
|
+
return {
|
|
664
|
+
dispose: () => {
|
|
665
|
+
if (disposed) {
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
disposed = true;
|
|
669
|
+
clearQueues(new Error('disposed'));
|
|
670
|
+
if (aceHandle) {
|
|
671
|
+
aceHandle.dispose();
|
|
672
|
+
}
|
|
673
|
+
if (bootstrapPromise && isBootstrapping) {
|
|
674
|
+
bootstrapPromise = null;
|
|
675
|
+
}
|
|
676
|
+
clientConn.dispose();
|
|
677
|
+
},
|
|
678
|
+
};
|
|
679
|
+
}
|
|
64
680
|
//# sourceMappingURL=proxy.js.map
|