@@ -19,6 +19,7 @@ export function proxyLanguageServiceForVue<T>(
1919 case 'getCompletionsAtPosition' : return getCompletionsAtPosition ( vueOptions , target [ p ] ) ;
2020 case 'getCompletionEntryDetails' : return getCompletionEntryDetails ( language , asScriptId , target [ p ] ) ;
2121 case 'getCodeFixesAtPosition' : return getCodeFixesAtPosition ( target [ p ] ) ;
22+ case 'getDefinitionAndBoundSpan' : return getDefinitionAndBoundSpan ( ts , language , languageService , vueOptions , asScriptId , target [ p ] ) ;
2223 case 'getQuickInfoAtPosition' : return getQuickInfoAtPosition ( ts , target , target [ p ] ) ;
2324 // TS plugin only
2425 case 'getEncodedSemanticClassifications' : return getEncodedSemanticClassifications ( ts , language , target , asScriptId , target [ p ] ) ;
@@ -91,7 +92,11 @@ function getCompletionsAtPosition(vueOptions: VueCompilerOptions, getCompletions
9192 } ;
9293}
9394
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' ] {
95100 return ( ...args ) => {
96101 const details = getCompletionEntryDetails ( ...args ) ;
97102 // modify import statement
@@ -132,7 +137,9 @@ function getCompletionEntryDetails<T>(language: Language<T>, asScriptId: (fileNa
132137 } ;
133138}
134139
135- function getCodeFixesAtPosition ( getCodeFixesAtPosition : ts . LanguageService [ 'getCodeFixesAtPosition' ] ) : ts . LanguageService [ 'getCodeFixesAtPosition' ] {
140+ function getCodeFixesAtPosition (
141+ getCodeFixesAtPosition : ts . LanguageService [ 'getCodeFixesAtPosition' ]
142+ ) : ts . LanguageService [ 'getCodeFixesAtPosition' ] {
136143 return ( ...args ) => {
137144 let result = getCodeFixesAtPosition ( ...args ) ;
138145 // filter __VLS_
@@ -141,7 +148,115 @@ function getCodeFixesAtPosition(getCodeFixesAtPosition: ts.LanguageService['getC
141148 } ;
142149}
143150
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' ] {
145260 return ( ...args ) => {
146261 const result = getQuickInfoAtPosition ( ...args ) ;
147262 if ( result && result . documentation ?. length === 1 && result . documentation [ 0 ] . text . startsWith ( '__VLS_emit,' ) ) {
0 commit comments