forked from vue-vine/vue-vine
/
language.ts
124 lines (114 loc) · 3.59 KB
/
language.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import type { Language, VirtualFile } from '@volar/language-core'
import { FileCapabilities, FileKind, FileRangeCapabilities } from '@volar/language-core'
import type * as ts from 'typescript/lib/tsserverlibrary'
import type { VineCompilerHooks, VineDiagnostic, VineFileCtx } from '@vue-vine/compiler'
import { compileVineTypeScriptFile } from '@vue-vine/compiler'
import { TextDocument } from 'vscode-languageserver-textdocument'
import { VINE_FILE_SUFFIX_REGEXP } from './constants'
import type { VineVirtualFileExtension } from './types'
function virtualFileName(
sourceFileName: string,
extension: VineVirtualFileExtension,
) {
return `${
sourceFileName.replace(VINE_FILE_SUFFIX_REGEXP, '')
}.vine-virtual.${extension}`
}
export const language: Language<VineFile> = {
createVirtualFile(fileName, snapshot) {
if (VINE_FILE_SUFFIX_REGEXP.test(fileName)) {
return new VineFile(fileName, snapshot)
}
},
updateVirtualFile(vineFile, snapshot) {
vineFile.update(snapshot)
},
}
export class VineFile implements VirtualFile {
kind = FileKind.TextFile
capabilities = FileCapabilities.full
fileName!: string
mappings!: VirtualFile['mappings']
codegenStacks = []
embeddedFiles!: VirtualFile['embeddedFiles']
textDocument!: TextDocument
vineFileCtx!: VineFileCtx
vineCompileErrs: VineDiagnostic[] = []
vineCompileWarns: VineDiagnostic[] = []
compilerHooks: VineCompilerHooks = {
onError: err => this.vineCompileErrs.push(err),
onWarn: warn => this.vineCompileWarns.push(warn),
}
constructor(
public sourceFileName: string,
public snapshot: ts.IScriptSnapshot,
) {
this.fileName = virtualFileName(sourceFileName, 'ts')
this.onSnapshotUpdated()
}
public update(newSnapshot: ts.IScriptSnapshot) {
this.snapshot = newSnapshot
this.onSnapshotUpdated()
}
mustRunOnSnapshotUpdated() {
this.mappings = [{
sourceRange: [0, this.snapshot.getLength()],
generatedRange: [0, this.snapshot.getLength()],
data: FileRangeCapabilities.full,
}]
this.embeddedFiles = []
this.textDocument = TextDocument.create(
this.fileName,
'vine',
0,
this.snapshot.getText(0, this.snapshot.getLength()),
)
this.vineFileCtx = compileVineTypeScriptFile(
this.snapshot.getText(0, this.snapshot.getLength()),
this.sourceFileName,
this.compilerHooks,
)
}
onSnapshotUpdated() {
this.mustRunOnSnapshotUpdated()
this.addEmbeddedStyleFiles()
}
addEmbeddedStyleFiles() {
for (const styleDefine of Object.values(this.vineFileCtx.styleDefine)) {
const { lang, source, range } = styleDefine
const { start, end } = range
const virtualFileExt: VineVirtualFileExtension = (() => {
switch (lang) {
case 'css':
case 'postcss':
return 'css'
case 'stylus':
return 'styl'
default:
return lang
}
})()
this.embeddedFiles.push({
fileName: virtualFileName(this.sourceFileName, virtualFileExt),
kind: FileKind.TextFile,
snapshot: {
getText: (start, end) => source.slice(start, end),
getLength: () => source.length,
getChangeRange: () => undefined,
},
mappings: [{
sourceRange: [
// +1/-1 to skip the first/last quote
start.index + 1,
end.index - 1,
],
generatedRange: [0, source.length],
data: FileRangeCapabilities.full,
}],
codegenStacks: [],
capabilities: FileCapabilities.full,
embeddedFiles: [],
})
}
}
}