@@ -19,6 +19,7 @@ export function proxyLanguageServiceForVue<T>(
19
19
case 'getCompletionsAtPosition' : return getCompletionsAtPosition ( vueOptions , target [ p ] ) ;
20
20
case 'getCompletionEntryDetails' : return getCompletionEntryDetails ( language , asScriptId , target [ p ] ) ;
21
21
case 'getCodeFixesAtPosition' : return getCodeFixesAtPosition ( target [ p ] ) ;
22
+ case 'getDefinitionAndBoundSpan' : return getDefinitionAndBoundSpan ( ts , language , languageService , vueOptions , asScriptId , target [ p ] ) ;
22
23
case 'getQuickInfoAtPosition' : return getQuickInfoAtPosition ( ts , target , target [ p ] ) ;
23
24
// TS plugin only
24
25
case 'getEncodedSemanticClassifications' : return getEncodedSemanticClassifications ( ts , language , target , asScriptId , target [ p ] ) ;
@@ -91,7 +92,11 @@ function getCompletionsAtPosition(vueOptions: VueCompilerOptions, getCompletions
91
92
} ;
92
93
}
93
94
94
- function getCompletionEntryDetails < T > ( language : Language < T > , asScriptId : ( fileName : string ) => T , getCompletionEntryDetails : ts . LanguageService [ 'getCompletionEntryDetails' ] ) : ts . LanguageService [ 'getCompletionEntryDetails' ] {
95
+ function getCompletionEntryDetails < T > (
96
+ language : Language < T > ,
97
+ asScriptId : ( fileName : string ) => T ,
98
+ getCompletionEntryDetails : ts . LanguageService [ 'getCompletionEntryDetails' ]
99
+ ) : ts . LanguageService [ 'getCompletionEntryDetails' ] {
95
100
return ( ...args ) => {
96
101
const details = getCompletionEntryDetails ( ...args ) ;
97
102
// modify import statement
@@ -132,7 +137,9 @@ function getCompletionEntryDetails<T>(language: Language<T>, asScriptId: (fileNa
132
137
} ;
133
138
}
134
139
135
- function getCodeFixesAtPosition ( getCodeFixesAtPosition : ts . LanguageService [ 'getCodeFixesAtPosition' ] ) : ts . LanguageService [ 'getCodeFixesAtPosition' ] {
140
+ function getCodeFixesAtPosition (
141
+ getCodeFixesAtPosition : ts . LanguageService [ 'getCodeFixesAtPosition' ]
142
+ ) : ts . LanguageService [ 'getCodeFixesAtPosition' ] {
136
143
return ( ...args ) => {
137
144
let result = getCodeFixesAtPosition ( ...args ) ;
138
145
// filter __VLS_
@@ -141,7 +148,115 @@ function getCodeFixesAtPosition(getCodeFixesAtPosition: ts.LanguageService['getC
141
148
} ;
142
149
}
143
150
144
- function getQuickInfoAtPosition ( ts : typeof import ( 'typescript' ) , languageService : ts . LanguageService , getQuickInfoAtPosition : ts . LanguageService [ 'getQuickInfoAtPosition' ] ) : ts . LanguageService [ 'getQuickInfoAtPosition' ] {
151
+ function getDefinitionAndBoundSpan < T > (
152
+ ts : typeof import ( 'typescript' ) ,
153
+ language : Language < T > ,
154
+ languageService : ts . LanguageService ,
155
+ vueOptions : VueCompilerOptions ,
156
+ asScriptId : ( fileName : string ) => T ,
157
+ getDefinitionAndBoundSpan : ts . LanguageService [ 'getDefinitionAndBoundSpan' ]
158
+ ) : ts . LanguageService [ 'getDefinitionAndBoundSpan' ] {
159
+ return ( fileName , position ) => {
160
+ const result = getDefinitionAndBoundSpan ( fileName , position ) ;
161
+ if ( ! result ?. definitions ?. length ) {
162
+ return result ;
163
+ }
164
+
165
+ const program = languageService . getProgram ( ) ! ;
166
+ const sourceScript = language . scripts . get ( asScriptId ( fileName ) ) ;
167
+ if ( ! sourceScript ?. generated ) {
168
+ return result ;
169
+ }
170
+
171
+ const root = sourceScript . generated . root ;
172
+ if ( ! ( root instanceof VueVirtualCode ) ) {
173
+ return result ;
174
+ }
175
+
176
+ if (
177
+ ! root . sfc . template
178
+ || position < root . sfc . template . startTagEnd
179
+ || position > root . sfc . template . endTagStart
180
+ ) {
181
+ return result ;
182
+ }
183
+
184
+ const definitions = new Set < ts . DefinitionInfo > ( result . definitions ) ;
185
+ const skippedDefinitions : ts . DefinitionInfo [ ] = [ ] ;
186
+
187
+ for ( const definition of result . definitions ) {
188
+ if ( vueOptions . extensions . some ( ext => definition . fileName . endsWith ( ext ) ) ) {
189
+ continue ;
190
+ }
191
+
192
+ const sourceFile = program . getSourceFile ( definition . fileName ) ;
193
+ if ( ! sourceFile ) {
194
+ continue ;
195
+ }
196
+
197
+ visit ( sourceFile , definition , sourceFile ) ;
198
+ }
199
+
200
+ for ( const definition of skippedDefinitions ) {
201
+ definitions . delete ( definition ) ;
202
+ }
203
+
204
+ return {
205
+ definitions : [ ...definitions ] ,
206
+ textSpan : result . textSpan ,
207
+ } ;
208
+
209
+ function visit (
210
+ node : ts . Node ,
211
+ definition : ts . DefinitionInfo ,
212
+ sourceFile : ts . SourceFile
213
+ ) {
214
+ if ( ts . isPropertySignature ( node ) && node . type ) {
215
+ proxy ( node . name , node . type , definition , sourceFile ) ;
216
+ }
217
+ else if ( ts . isVariableDeclaration ( node ) && ts . isIdentifier ( node . name ) && node . type && ! node . initializer ) {
218
+ proxy ( node . name , node . type , definition , sourceFile ) ;
219
+ }
220
+ else {
221
+ ts . forEachChild ( node , child => visit ( child , definition , sourceFile ) ) ;
222
+ }
223
+ }
224
+
225
+ function proxy (
226
+ name : ts . PropertyName ,
227
+ type : ts . TypeNode ,
228
+ definition : ts . DefinitionInfo ,
229
+ sourceFile : ts . SourceFile
230
+ ) {
231
+ const { textSpan, fileName } = definition ;
232
+ const start = name . getStart ( sourceFile ) ;
233
+ const end = name . getEnd ( ) ;
234
+
235
+ if ( start !== textSpan . start || end - start !== textSpan . length ) {
236
+ return ;
237
+ }
238
+
239
+ if ( ! ts . isIndexedAccessTypeNode ( type ) ) {
240
+ return ;
241
+ }
242
+
243
+ const pos = type . indexType . getStart ( sourceFile ) ;
244
+ const res = getDefinitionAndBoundSpan ( fileName , pos ) ;
245
+ if ( res ?. definitions ?. length ) {
246
+ for ( const definition of res . definitions ) {
247
+ definitions . add ( definition ) ;
248
+ }
249
+ skippedDefinitions . push ( definition ) ;
250
+ }
251
+ }
252
+ }
253
+ }
254
+
255
+ function getQuickInfoAtPosition (
256
+ ts : typeof import ( 'typescript' ) ,
257
+ languageService : ts . LanguageService ,
258
+ getQuickInfoAtPosition : ts . LanguageService [ 'getQuickInfoAtPosition' ]
259
+ ) : ts . LanguageService [ 'getQuickInfoAtPosition' ] {
145
260
return ( ...args ) => {
146
261
const result = getQuickInfoAtPosition ( ...args ) ;
147
262
if ( result && result . documentation ?. length === 1 && result . documentation [ 0 ] . text . startsWith ( '__VLS_emit,' ) ) {
0 commit comments