|
1 |
| -import type { LanguageServer } from '@volar/language-server'; |
2 |
| -import { createLanguageServiceEnvironment } from '@volar/language-server/lib/project/simpleProject'; |
3 |
| -import { createConnection, createServer } from '@volar/language-server/node'; |
4 |
| -import { |
5 |
| - createLanguage, |
6 |
| - createParsedCommandLine, |
7 |
| - createParsedCommandLineByJson, |
8 |
| - createVueLanguagePlugin, |
9 |
| -} from '@vue/language-core'; |
10 |
| -import { |
11 |
| - createLanguageService, |
12 |
| - createUriMap, |
13 |
| - createVueLanguageServicePlugins, |
14 |
| - type LanguageService, |
15 |
| -} from '@vue/language-service'; |
16 |
| -import * as ts from 'typescript'; |
17 |
| -import { URI } from 'vscode-uri'; |
18 |
| - |
19 |
| -const connection = createConnection(); |
20 |
| -const server = createServer(connection); |
21 |
| -const tsserverRequestHandlers = new Map<number, (res: any) => void>(); |
22 |
| - |
23 |
| -let tsserverRequestId = 0; |
24 |
| - |
25 |
| -connection.listen(); |
26 |
| - |
27 |
| -connection.onNotification('tsserver/response', ([id, res]) => { |
28 |
| - tsserverRequestHandlers.get(id)?.(res); |
29 |
| - tsserverRequestHandlers.delete(id); |
30 |
| -}); |
31 |
| - |
32 |
| -connection.onInitialize(params => { |
33 |
| - const tsconfigProjects = createUriMap<LanguageService>(); |
34 |
| - const file2ProjectInfo = new Map<string, Promise<ts.server.protocol.ProjectInfo | null>>(); |
35 |
| - |
36 |
| - server.fileWatcher.onDidChangeWatchedFiles(({ changes }) => { |
37 |
| - for (const change of changes) { |
38 |
| - const changeUri = URI.parse(change.uri); |
39 |
| - if (tsconfigProjects.has(changeUri)) { |
40 |
| - tsconfigProjects.get(changeUri)!.dispose(); |
41 |
| - tsconfigProjects.delete(changeUri); |
42 |
| - file2ProjectInfo.clear(); |
43 |
| - } |
| 1 | +import { startServer } from './lib/server'; |
| 2 | + |
| 3 | +if (process.argv.includes('--version')) { |
| 4 | + console.log(require('./package.json').version); |
| 5 | +} |
| 6 | +else { |
| 7 | + let ts; |
| 8 | + for (const arg of process.argv) { |
| 9 | + if (arg.startsWith('--tsdk=')) { |
| 10 | + const tsdk = arg.substring('--tsdk='.length); |
| 11 | + const tsPath = require.resolve('./typescript.js', { paths: [tsdk] }); |
| 12 | + ts = require(tsPath); |
| 13 | + break; |
44 | 14 | }
|
45 |
| - }); |
46 |
| - |
47 |
| - let simpleLanguageService: LanguageService | undefined; |
48 |
| - |
49 |
| - return server.initialize( |
50 |
| - params, |
51 |
| - { |
52 |
| - setup() {}, |
53 |
| - async getLanguageService(uri) { |
54 |
| - if (uri.scheme === 'file') { |
55 |
| - const fileName = uri.fsPath.replace(/\\/g, '/'); |
56 |
| - let projectInfoPromise = file2ProjectInfo.get(fileName); |
57 |
| - if (!projectInfoPromise) { |
58 |
| - projectInfoPromise = sendTsServerRequest<ts.server.protocol.ProjectInfo>( |
59 |
| - '_vue:' + ts.server.protocol.CommandTypes.ProjectInfo, |
60 |
| - { |
61 |
| - file: fileName, |
62 |
| - needFileNameList: false, |
63 |
| - } satisfies ts.server.protocol.ProjectInfoRequestArgs, |
64 |
| - ); |
65 |
| - file2ProjectInfo.set(fileName, projectInfoPromise); |
66 |
| - } |
67 |
| - const projectInfo = await projectInfoPromise; |
68 |
| - if (projectInfo) { |
69 |
| - const { configFileName } = projectInfo; |
70 |
| - let languageService = tsconfigProjects.get(URI.file(configFileName)); |
71 |
| - if (!languageService) { |
72 |
| - languageService = createProjectLanguageService(server, configFileName); |
73 |
| - tsconfigProjects.set(URI.file(configFileName), languageService); |
74 |
| - } |
75 |
| - return languageService; |
76 |
| - } |
77 |
| - } |
78 |
| - return simpleLanguageService ??= createProjectLanguageService(server, undefined); |
79 |
| - }, |
80 |
| - getExistingLanguageServices() { |
81 |
| - return Promise.all([ |
82 |
| - ...tsconfigProjects.values(), |
83 |
| - simpleLanguageService, |
84 |
| - ].filter(promise => !!promise)); |
85 |
| - }, |
86 |
| - reload() { |
87 |
| - for (const languageService of tsconfigProjects.values()) { |
88 |
| - languageService.dispose(); |
89 |
| - } |
90 |
| - tsconfigProjects.clear(); |
91 |
| - if (simpleLanguageService) { |
92 |
| - simpleLanguageService.dispose(); |
93 |
| - simpleLanguageService = undefined; |
94 |
| - } |
95 |
| - }, |
96 |
| - }, |
97 |
| - createVueLanguageServicePlugins(ts, { |
98 |
| - collectExtractProps(...args) { |
99 |
| - return sendTsServerRequest('_vue:collectExtractProps', args); |
100 |
| - }, |
101 |
| - getComponentDirectives(...args) { |
102 |
| - return sendTsServerRequest('_vue:getComponentDirectives', args); |
103 |
| - }, |
104 |
| - getComponentEvents(...args) { |
105 |
| - return sendTsServerRequest('_vue:getComponentEvents', args); |
106 |
| - }, |
107 |
| - getComponentNames(...args) { |
108 |
| - return sendTsServerRequest('_vue:getComponentNames', args); |
109 |
| - }, |
110 |
| - getComponentProps(...args) { |
111 |
| - return sendTsServerRequest('_vue:getComponentProps', args); |
112 |
| - }, |
113 |
| - getComponentSlots(...args) { |
114 |
| - return sendTsServerRequest('_vue:getComponentSlots', args); |
115 |
| - }, |
116 |
| - getElementAttrs(...args) { |
117 |
| - return sendTsServerRequest('_vue:getElementAttrs', args); |
118 |
| - }, |
119 |
| - getElementNames(...args) { |
120 |
| - return sendTsServerRequest('_vue:getElementNames', args); |
121 |
| - }, |
122 |
| - getImportPathForFile(...args) { |
123 |
| - return sendTsServerRequest('_vue:getImportPathForFile', args); |
124 |
| - }, |
125 |
| - isRefAtPosition(...args) { |
126 |
| - return sendTsServerRequest('_vue:isRefAtPosition', args); |
127 |
| - }, |
128 |
| - getDocumentHighlights(fileName, position) { |
129 |
| - return sendTsServerRequest( |
130 |
| - '_vue:documentHighlights-full', |
131 |
| - { |
132 |
| - file: fileName, |
133 |
| - ...{ position } as unknown as { line: number; offset: number }, |
134 |
| - filesToSearch: [fileName], |
135 |
| - } satisfies ts.server.protocol.DocumentHighlightsRequestArgs, |
136 |
| - ); |
137 |
| - }, |
138 |
| - getEncodedSemanticClassifications(fileName, span) { |
139 |
| - return sendTsServerRequest( |
140 |
| - '_vue:encodedSemanticClassifications-full', |
141 |
| - { |
142 |
| - file: fileName, |
143 |
| - ...span, |
144 |
| - format: ts.SemanticClassificationFormat.TwentyTwenty, |
145 |
| - } satisfies ts.server.protocol.EncodedSemanticClassificationsRequestArgs, |
146 |
| - ); |
147 |
| - }, |
148 |
| - async getQuickInfoAtPosition(fileName, { line, character }) { |
149 |
| - const result = await sendTsServerRequest<ts.server.protocol.QuickInfoResponseBody>( |
150 |
| - '_vue:' + ts.server.protocol.CommandTypes.Quickinfo, |
151 |
| - { |
152 |
| - file: fileName, |
153 |
| - line: line + 1, |
154 |
| - offset: character + 1, |
155 |
| - } satisfies ts.server.protocol.FileLocationRequestArgs, |
156 |
| - ); |
157 |
| - return result?.displayString; |
158 |
| - }, |
159 |
| - }), |
160 |
| - ); |
161 |
| - |
162 |
| - async function sendTsServerRequest<T>(command: string, args: any): Promise<T | null> { |
163 |
| - return await new Promise<T | null>(resolve => { |
164 |
| - const requestId = ++tsserverRequestId; |
165 |
| - tsserverRequestHandlers.set(requestId, resolve); |
166 |
| - connection.sendNotification('tsserver/request', [requestId, command, args]); |
167 |
| - }); |
168 |
| - } |
169 |
| - |
170 |
| - function createProjectLanguageService(server: LanguageServer, tsconfig: string | undefined) { |
171 |
| - const commonLine = tsconfig && !ts.server.isInferredProjectName(tsconfig) |
172 |
| - ? createParsedCommandLine(ts, ts.sys, tsconfig) |
173 |
| - : createParsedCommandLineByJson(ts, ts.sys, ts.sys.getCurrentDirectory(), {}); |
174 |
| - const language = createLanguage<URI>( |
175 |
| - [ |
176 |
| - { |
177 |
| - getLanguageId: uri => server.documents.get(uri)?.languageId, |
178 |
| - }, |
179 |
| - createVueLanguagePlugin( |
180 |
| - ts, |
181 |
| - commonLine.options, |
182 |
| - commonLine.vueOptions, |
183 |
| - uri => uri.fsPath.replace(/\\/g, '/'), |
184 |
| - ), |
185 |
| - ], |
186 |
| - createUriMap(), |
187 |
| - uri => { |
188 |
| - const document = server.documents.get(uri); |
189 |
| - if (document) { |
190 |
| - language.scripts.set(uri, document.getSnapshot(), document.languageId); |
191 |
| - } |
192 |
| - else { |
193 |
| - language.scripts.delete(uri); |
194 |
| - } |
195 |
| - }, |
196 |
| - ); |
197 |
| - return createLanguageService( |
198 |
| - language, |
199 |
| - server.languageServicePlugins, |
200 |
| - createLanguageServiceEnvironment(server, [...server.workspaceFolders.all]), |
201 |
| - {}, |
202 |
| - ); |
203 | 15 | }
|
204 |
| -}); |
205 |
| - |
206 |
| -connection.onInitialized(server.initialized); |
207 |
| - |
208 |
| -connection.onShutdown(server.shutdown); |
| 16 | + ts ??= require('typescript'); |
| 17 | + startServer(ts); |
| 18 | +} |
0 commit comments