Skip to content

Commit f2b38cf

Browse files
committed
refactor: organize vue.worker.ts
1 parent 6ddcdc7 commit f2b38cf

File tree

1 file changed

+188
-179
lines changed

1 file changed

+188
-179
lines changed

src/monaco/vue.worker.ts

Lines changed: 188 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import {
1919
import type * as monaco from 'monaco-editor-core'
2020
// @ts-expect-error
2121
import * as worker from 'monaco-editor-core/esm/vs/editor/editor.worker'
22-
import { create as createTypeScriptPlugins } from 'volar-service-typescript'
22+
import { create as createTypeScriptDirectiveCommentPlugin } from 'volar-service-typescript/lib/plugins/directiveComment'
23+
import { create as createTypeScriptSemanticPlugin } from 'volar-service-typescript/lib/plugins/semantic'
2324
import { URI } from 'vscode-uri'
2425
import type { WorkerHost, WorkerMessage } from './env'
2526

@@ -91,165 +92,7 @@ self.onmessage = async (msg: MessageEvent<WorkerMessage>) => {
9192
...getDefaultCompilerOptions(),
9293
...tsconfig.vueCompilerOptions,
9394
}
94-
const globalTypes = generateGlobalTypes(vueCompilerOptions)
95-
const globalTypesPath =
96-
'/node_modules/' + getGlobalTypesFileName(vueCompilerOptions)
97-
vueCompilerOptions.globalTypesPath = () => globalTypesPath
98-
const { stat, readFile } = env.fs!
99-
const ctime = Date.now()
100-
env.fs!.stat = async (uri) => {
101-
if (uri.path === globalTypesPath) {
102-
return {
103-
type: 1,
104-
ctime: ctime,
105-
mtime: ctime,
106-
size: globalTypes.length,
107-
}
108-
}
109-
return stat(uri)
110-
}
111-
env.fs!.readFile = async (uri) => {
112-
if (uri.path === globalTypesPath) {
113-
return globalTypes
114-
}
115-
return readFile(uri)
116-
}
117-
118-
const vueLanguagePlugin = createVueLanguagePlugin(
119-
ts,
120-
compilerOptions,
121-
vueCompilerOptions,
122-
asFileName,
123-
)
124-
const ignoreVueServicePlugins = new Set([
125-
'vue-extract-file',
126-
'vue-document-drop',
127-
'vue-document-highlights',
128-
'typescript-semantic-tokens',
129-
// dedupe
130-
'typescript-doc-comment-template',
131-
'typescript-syntactic',
132-
])
133-
const vueServicePlugins = createVueLanguageServicePlugins(ts, {
134-
getComponentDirectives(fileName) {
135-
return getComponentDirectives(ts, getProgram(), fileName)
136-
},
137-
getComponentEvents(fileName, tag) {
138-
return getComponentEvents(ts, getProgram(), fileName, tag)
139-
},
140-
getComponentNames(fileName) {
141-
return getComponentNames(ts, getProgram(), fileName)
142-
},
143-
getComponentProps(fileName, tag) {
144-
return getComponentProps(ts, getProgram(), fileName, tag)
145-
},
146-
getComponentSlots(fileName) {
147-
const { virtualCode } = getVirtualCode(fileName)
148-
return getComponentSlots(ts, getProgram(), virtualCode)
149-
},
150-
getElementAttrs(fileName, tag) {
151-
return getElementAttrs(ts, getProgram(), fileName, tag)
152-
},
153-
getElementNames(fileName) {
154-
return getElementNames(ts, getProgram(), fileName)
155-
},
156-
getPropertiesAtLocation(fileName, position) {
157-
const { sourceScript, virtualCode } = getVirtualCode(fileName)
158-
return getPropertiesAtLocation(
159-
ts,
160-
languageService.context.language,
161-
getProgram(),
162-
sourceScript,
163-
virtualCode,
164-
position,
165-
false,
166-
)
167-
},
168-
async getQuickInfoAtPosition(fileName, position) {
169-
const uri = asUri(fileName)
170-
const sourceScript = languageService.context.language.scripts.get(uri)
171-
if (!sourceScript) {
172-
return
173-
}
174-
const hover = await languageService.getHover(uri, position)
175-
let text = ''
176-
if (typeof hover?.contents === 'string') {
177-
text = hover.contents
178-
} else if (Array.isArray(hover?.contents)) {
179-
text = hover.contents
180-
.map((c) => (typeof c === 'string' ? c : c.value))
181-
.join('\n')
182-
} else if (hover) {
183-
text = hover.contents.value
184-
}
185-
text = text.replace(/```typescript/g, '')
186-
text = text.replace(/```/g, '')
187-
text = text.replace(/---/g, '')
188-
text = text.trim()
189-
while (true) {
190-
const newText = text.replace(/\n\n/g, '\n')
191-
if (newText === text) {
192-
break
193-
}
194-
text = newText
195-
}
196-
text = text.replace(/\n/g, ' | ')
197-
return text
198-
},
199-
collectExtractProps() {
200-
throw new Error('Not implemented')
201-
},
202-
getImportPathForFile() {
203-
throw new Error('Not implemented')
204-
},
205-
getDocumentHighlights() {
206-
throw new Error('Not implemented')
207-
},
208-
getEncodedSemanticClassifications() {
209-
throw new Error('Not implemented')
210-
},
211-
}).filter((plugin) => !ignoreVueServicePlugins.has(plugin.name!))
212-
213-
const tsServicePlugins = createTypeScriptPlugins(ts)
214-
for (let i = 0; i < tsServicePlugins.length; i++) {
215-
const plugin = tsServicePlugins[i]
216-
if (plugin.name === 'typescript-semantic') {
217-
tsServicePlugins[i] = {
218-
...plugin,
219-
create(context) {
220-
const created = plugin.create(context)
221-
const tsLs = created.provide[
222-
'typescript/languageService'
223-
]() as import('typescript').LanguageService
224-
const proxy = createVueLanguageServiceProxy(
225-
ts,
226-
new Proxy(
227-
{},
228-
{
229-
get(_target, prop, receiver) {
230-
return Reflect.get(
231-
languageService.context.language,
232-
prop,
233-
receiver,
234-
)
235-
},
236-
},
237-
) as unknown as Language,
238-
tsLs,
239-
vueCompilerOptions,
240-
asUri,
241-
)
242-
tsLs.getCompletionsAtPosition = proxy.getCompletionsAtPosition
243-
tsLs.getCompletionEntryDetails = proxy.getCompletionEntryDetails
244-
tsLs.getCodeFixesAtPosition = proxy.getCodeFixesAtPosition
245-
tsLs.getDefinitionAndBoundSpan = proxy.getDefinitionAndBoundSpan
246-
tsLs.getQuickInfoAtPosition = proxy.getQuickInfoAtPosition
247-
return created
248-
},
249-
}
250-
break
251-
}
252-
}
95+
setupGlobalTypes(vueCompilerOptions, env)
25396

25497
const workerService = createTypeScriptWorkerLanguageService({
25598
typescript: ts,
@@ -260,33 +103,199 @@ self.onmessage = async (msg: MessageEvent<WorkerMessage>) => {
260103
asFileName,
261104
asUri,
262105
},
263-
languagePlugins: [vueLanguagePlugin],
264-
languageServicePlugins: [...tsServicePlugins, ...vueServicePlugins],
106+
languagePlugins: [
107+
createVueLanguagePlugin(
108+
ts,
109+
compilerOptions,
110+
vueCompilerOptions,
111+
asFileName,
112+
),
113+
],
114+
languageServicePlugins: [
115+
...getTsLanguageServicePlugins(),
116+
...getVueLanguageServicePlugins(),
117+
],
265118
})
266-
const languageService = (workerService as any)
267-
.languageService as LanguageService
268119

269120
return workerService
270121

271-
function getProgram() {
272-
const tsService: import('typescript').LanguageService =
273-
languageService.context.inject('typescript/languageService')
274-
return tsService.getProgram()!
122+
function setupGlobalTypes(
123+
options: VueCompilerOptions,
124+
env: LanguageServiceEnvironment,
125+
) {
126+
const globalTypes = generateGlobalTypes(options)
127+
const globalTypesPath =
128+
'/node_modules/' + getGlobalTypesFileName(options)
129+
options.globalTypesPath = () => globalTypesPath
130+
const { stat, readFile } = env.fs!
131+
const ctime = Date.now()
132+
env.fs!.stat = async (uri) => {
133+
if (uri.path === globalTypesPath) {
134+
return {
135+
type: 1,
136+
ctime: ctime,
137+
mtime: ctime,
138+
size: globalTypes.length,
139+
}
140+
}
141+
return stat(uri)
142+
}
143+
env.fs!.readFile = async (uri) => {
144+
if (uri.path === globalTypesPath) {
145+
return globalTypes
146+
}
147+
return readFile(uri)
148+
}
149+
}
150+
151+
function getTsLanguageServicePlugins() {
152+
const semanticPlugin = createTypeScriptSemanticPlugin(ts)
153+
const { create } = semanticPlugin
154+
semanticPlugin.create = (context) => {
155+
const created = create(context)
156+
const ls = created.provide[
157+
'typescript/languageService'
158+
]() as import('typescript').LanguageService
159+
const proxy = createVueLanguageServiceProxy(
160+
ts,
161+
new Proxy(
162+
{},
163+
{
164+
get(_target, prop, receiver) {
165+
return Reflect.get(context.language, prop, receiver)
166+
},
167+
},
168+
) as unknown as Language,
169+
ls,
170+
vueCompilerOptions,
171+
asUri,
172+
)
173+
ls.getCompletionsAtPosition = proxy.getCompletionsAtPosition
174+
ls.getCompletionEntryDetails = proxy.getCompletionEntryDetails
175+
ls.getCodeFixesAtPosition = proxy.getCodeFixesAtPosition
176+
ls.getDefinitionAndBoundSpan = proxy.getDefinitionAndBoundSpan
177+
ls.getQuickInfoAtPosition = proxy.getQuickInfoAtPosition
178+
return created
179+
}
180+
return [semanticPlugin, createTypeScriptDirectiveCommentPlugin()]
275181
}
276182

277-
function getVirtualCode(fileName: string) {
278-
const uri = asUri(fileName)
279-
const sourceScript = languageService.context.language.scripts.get(uri)
280-
if (!sourceScript) {
281-
throw new Error('No source script found for file: ' + fileName)
183+
function getVueLanguageServicePlugins() {
184+
const plugins = createVueLanguageServicePlugins(ts, {
185+
getComponentDirectives(fileName) {
186+
return getComponentDirectives(ts, getProgram(), fileName)
187+
},
188+
getComponentEvents(fileName, tag) {
189+
return getComponentEvents(ts, getProgram(), fileName, tag)
190+
},
191+
getComponentNames(fileName) {
192+
return getComponentNames(ts, getProgram(), fileName)
193+
},
194+
getComponentProps(fileName, tag) {
195+
return getComponentProps(ts, getProgram(), fileName, tag)
196+
},
197+
getComponentSlots(fileName) {
198+
const { virtualCode } = getVirtualCode(fileName)
199+
return getComponentSlots(ts, getProgram(), virtualCode)
200+
},
201+
getElementAttrs(fileName, tag) {
202+
return getElementAttrs(ts, getProgram(), fileName, tag)
203+
},
204+
getElementNames(fileName) {
205+
return getElementNames(ts, getProgram(), fileName)
206+
},
207+
getPropertiesAtLocation(fileName, position) {
208+
const { sourceScript, virtualCode } = getVirtualCode(fileName)
209+
return getPropertiesAtLocation(
210+
ts,
211+
getLanguageService().context.language,
212+
getProgram(),
213+
sourceScript,
214+
virtualCode,
215+
position,
216+
false,
217+
)
218+
},
219+
async getQuickInfoAtPosition(fileName, position) {
220+
const uri = asUri(fileName)
221+
const sourceScript =
222+
getLanguageService().context.language.scripts.get(uri)
223+
if (!sourceScript) {
224+
return
225+
}
226+
const hover = await getLanguageService().getHover(uri, position)
227+
let text = ''
228+
if (typeof hover?.contents === 'string') {
229+
text = hover.contents
230+
} else if (Array.isArray(hover?.contents)) {
231+
text = hover.contents
232+
.map((c) => (typeof c === 'string' ? c : c.value))
233+
.join('\n')
234+
} else if (hover) {
235+
text = hover.contents.value
236+
}
237+
text = text.replace(/```typescript/g, '')
238+
text = text.replace(/```/g, '')
239+
text = text.replace(/---/g, '')
240+
text = text.trim()
241+
while (true) {
242+
const newText = text.replace(/\n\n/g, '\n')
243+
if (newText === text) {
244+
break
245+
}
246+
text = newText
247+
}
248+
text = text.replace(/\n/g, ' | ')
249+
return text
250+
},
251+
collectExtractProps() {
252+
throw new Error('Not implemented')
253+
},
254+
getImportPathForFile() {
255+
throw new Error('Not implemented')
256+
},
257+
getDocumentHighlights() {
258+
throw new Error('Not implemented')
259+
},
260+
getEncodedSemanticClassifications() {
261+
throw new Error('Not implemented')
262+
},
263+
})
264+
const ignoreVueServicePlugins = new Set([
265+
'vue-extract-file',
266+
'vue-document-drop',
267+
'vue-document-highlights',
268+
'typescript-semantic-tokens',
269+
])
270+
return plugins.filter(
271+
(plugin) => !ignoreVueServicePlugins.has(plugin.name!),
272+
)
273+
274+
function getVirtualCode(fileName: string) {
275+
const uri = asUri(fileName)
276+
const sourceScript =
277+
getLanguageService().context.language.scripts.get(uri)
278+
if (!sourceScript) {
279+
throw new Error('No source script found for file: ' + fileName)
280+
}
281+
const virtualCode = sourceScript.generated?.root
282+
if (!(virtualCode instanceof VueVirtualCode)) {
283+
throw new Error('No virtual code found for file: ' + fileName)
284+
}
285+
return {
286+
sourceScript,
287+
virtualCode,
288+
}
282289
}
283-
const virtualCode = sourceScript.generated?.root
284-
if (!(virtualCode instanceof VueVirtualCode)) {
285-
throw new Error('No virtual code found for file: ' + fileName)
290+
291+
function getProgram() {
292+
const tsService: import('typescript').LanguageService =
293+
getLanguageService().context.inject('typescript/languageService')
294+
return tsService.getProgram()!
286295
}
287-
return {
288-
sourceScript,
289-
virtualCode,
296+
297+
function getLanguageService() {
298+
return (workerService as any).languageService as LanguageService
290299
}
291300
}
292301
},

0 commit comments

Comments
 (0)