1
1
import type { LanguagePlugin } from '@volar/language-core' ;
2
2
import * as path from 'path-browserify' ;
3
- import { getDefaultVueLanguagePlugins } from './plugins' ;
3
+ import { getDefaultVueLanguagePlugins , createPluginContext } from './plugins' ;
4
4
import { VueFile } from './virtualFile/vueFile' ;
5
5
import { VueCompilerOptions , VueLanguagePlugin } from './types' ;
6
6
import type * as ts from 'typescript/lib/tsserverlibrary' ;
@@ -32,32 +32,43 @@ function getVueFileRegistry(key: string, plugins: VueLanguagePlugin[]) {
32
32
return fileRegistry ;
33
33
}
34
34
35
+ function getFileRegistryKey (
36
+ compilerOptions : ts . CompilerOptions ,
37
+ vueCompilerOptions : VueCompilerOptions ,
38
+ plugins : ReturnType < VueLanguagePlugin > [ ] ,
39
+ globalTypesHolder : string | undefined ,
40
+ ) {
41
+ const values = [
42
+ globalTypesHolder ,
43
+ ...Object . keys ( vueCompilerOptions )
44
+ . sort ( )
45
+ . filter ( key => key !== 'plugins' )
46
+ . map ( key => [ key , vueCompilerOptions [ key as keyof VueCompilerOptions ] ] ) ,
47
+ [ ...new Set ( plugins . map ( plugin => plugin . requiredCompilerOptions ?? [ ] ) . flat ( ) ) ]
48
+ . sort ( )
49
+ . map ( key => [ key , compilerOptions [ key as keyof ts . CompilerOptions ] ] ) ,
50
+ ] ;
51
+ return JSON . stringify ( values ) ;
52
+ }
53
+
35
54
export function createVueLanguage (
36
55
ts : typeof import ( 'typescript/lib/tsserverlibrary' ) ,
37
56
compilerOptions : ts . CompilerOptions = { } ,
38
57
_vueCompilerOptions : Partial < VueCompilerOptions > = { } ,
39
58
codegenStack : boolean = false ,
59
+ globalTypesHolder ?: string
40
60
) : LanguagePlugin < VueFile > {
41
61
42
62
const vueCompilerOptions = resolveVueCompilerOptions ( _vueCompilerOptions ) ;
43
- const plugins = getDefaultVueLanguagePlugins (
63
+ const allowLanguageIds = new Set ( [ 'vue' ] ) ;
64
+ const pluginContext = createPluginContext (
44
65
ts ,
45
66
compilerOptions ,
46
67
vueCompilerOptions ,
47
68
codegenStack ,
69
+ globalTypesHolder ,
48
70
) ;
49
- const keys = [
50
- ...Object . keys ( vueCompilerOptions )
51
- . sort ( )
52
- . filter ( key => key !== 'plugins' )
53
- . map ( key => [ key , vueCompilerOptions [ key as keyof VueCompilerOptions ] ] ) ,
54
- [ ...new Set ( plugins . map ( plugin => plugin . requiredCompilerOptions ?? [ ] ) . flat ( ) ) ]
55
- . sort ( )
56
- . map ( key => [ key , compilerOptions [ key as keyof ts . CompilerOptions ] ] ) ,
57
- ] ;
58
- const fileRegistry = getVueFileRegistry ( JSON . stringify ( keys ) , _vueCompilerOptions . plugins ?? [ ] ) ;
59
-
60
- const allowLanguageIds = new Set ( [ 'vue' ] ) ;
71
+ const plugins = getDefaultVueLanguagePlugins ( pluginContext ) ;
61
72
62
73
if ( vueCompilerOptions . extensions . includes ( '.md' ) ) {
63
74
allowLanguageIds . add ( 'markdown' ) ;
@@ -66,21 +77,61 @@ export function createVueLanguage(
66
77
allowLanguageIds . add ( 'html' ) ;
67
78
}
68
79
80
+ let fileRegistry : Map < string , VueFile > | undefined ;
81
+
69
82
return {
70
- createVirtualFile ( id , languageId , snapshot ) {
83
+ createVirtualFile ( fileName , languageId , snapshot ) {
71
84
if ( allowLanguageIds . has ( languageId ) ) {
72
- if ( fileRegistry . has ( id ) ) {
73
- const reusedVueFile = fileRegistry . get ( id ) ! ;
85
+
86
+ if ( ! fileRegistry ) {
87
+
88
+ pluginContext . globalTypesHolder ??= fileName ;
89
+
90
+ fileRegistry = getVueFileRegistry (
91
+ getFileRegistryKey ( compilerOptions , vueCompilerOptions , plugins , pluginContext . globalTypesHolder ) ,
92
+ vueCompilerOptions . plugins ,
93
+ ) ;
94
+ }
95
+
96
+ if ( fileRegistry . has ( fileName ) ) {
97
+ const reusedVueFile = fileRegistry . get ( fileName ) ! ;
74
98
reusedVueFile . update ( snapshot ) ;
75
99
return reusedVueFile ;
76
100
}
77
- const vueFile = new VueFile ( id , languageId , snapshot , vueCompilerOptions , plugins , ts , codegenStack ) ;
78
- fileRegistry . set ( id , vueFile ) ;
101
+ const vueFile = new VueFile ( fileName , languageId , snapshot , vueCompilerOptions , plugins , ts , codegenStack ) ;
102
+ fileRegistry . set ( fileName , vueFile ) ;
79
103
return vueFile ;
80
104
}
81
105
} ,
82
- updateVirtualFile ( sourceFile , snapshot ) {
83
- sourceFile . update ( snapshot ) ;
106
+ updateVirtualFile ( vueFile , snapshot ) {
107
+ vueFile . update ( snapshot ) ;
108
+ } ,
109
+ disposeVirtualFile ( vueFile , files ) {
110
+ fileRegistry ?. delete ( vueFile . fileName ) ;
111
+ if ( vueFile . fileName === pluginContext . globalTypesHolder ) {
112
+ if ( fileRegistry ?. size ) {
113
+ for ( const [ fileName , file ] of fileRegistry ! ) {
114
+ pluginContext . globalTypesHolder = fileName ;
115
+
116
+ fileRegistry = getVueFileRegistry (
117
+ getFileRegistryKey ( compilerOptions , vueCompilerOptions , plugins , pluginContext . globalTypesHolder ) ,
118
+ vueCompilerOptions . plugins ,
119
+ ) ;
120
+
121
+ files . updateSourceFile (
122
+ file . fileName ,
123
+ file . languageId ,
124
+ // force dirty
125
+ { ...file . snapshot } ,
126
+ ) ;
127
+ break ;
128
+ }
129
+ }
130
+ else {
131
+ fileRegistry = undefined ;
132
+ pluginContext . globalTypesHolder = undefined ;
133
+ }
134
+ }
84
135
} ,
85
136
typescript : {
86
137
resolveSourceFileName ( tsFileName ) {
@@ -106,9 +157,10 @@ export function createLanguages(
106
157
compilerOptions : ts . CompilerOptions = { } ,
107
158
vueCompilerOptions : Partial < VueCompilerOptions > = { } ,
108
159
codegenStack : boolean = false ,
160
+ globalTypesHolder ?: string
109
161
) : LanguagePlugin [ ] {
110
162
return [
111
- createVueLanguage ( ts , compilerOptions , vueCompilerOptions , codegenStack ) ,
163
+ createVueLanguage ( ts , compilerOptions , vueCompilerOptions , codegenStack , globalTypesHolder ) ,
112
164
...vueCompilerOptions . experimentalAdditionalLanguageModules ?. map ( module => require ( module ) ) ?? [ ] ,
113
165
] ;
114
166
}
0 commit comments