|
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