@@ -6,17 +6,18 @@ export default (proxy: ts.LanguageService, info: ts.server.PluginCreateInfo, c:
66 proxy . getDefinitionAndBoundSpan = ( fileName , position ) => {
77 const prior = info . languageService . getDefinitionAndBoundSpan ( fileName , position )
88 if ( ! prior ) {
9- if ( c ( 'enableFileDefinitions' ) ) {
10- const sourceFile = info . languageService . getProgram ( ) ! . getSourceFile ( fileName ) !
11- const node = findChildContainingExactPosition ( sourceFile , position )
12- if ( node && ts . isStringLiteral ( node ) && [ './' , '../' ] . some ( str => node . text . startsWith ( str ) ) ) {
9+ const program = info . languageService . getProgram ( ) !
10+ const sourceFile = program . getSourceFile ( fileName ) !
11+ const node = findChildContainingExactPosition ( sourceFile , position )
12+ if ( node && ts . isStringLiteral ( node ) ) {
13+ const textSpanStart = node . pos + node . getLeadingTriviaWidth ( ) + 1 // + 1 for quote
14+ const textSpan = {
15+ start : textSpanStart ,
16+ length : node . end - textSpanStart - 1 ,
17+ }
18+ if ( c ( 'enableFileDefinitions' ) && [ './' , '../' ] . some ( str => node . text . startsWith ( str ) ) ) {
1319 const file = join ( fileName , '..' , node . text )
1420 if ( info . languageServiceHost . fileExists ?.( file ) ) {
15- const start = node . pos + node . getLeadingTriviaWidth ( ) + 1 // + 1 for quote
16- const textSpan = {
17- start,
18- length : node . end - start - 1 ,
19- }
2021 return {
2122 textSpan,
2223 definitions : [
@@ -33,9 +34,66 @@ export default (proxy: ts.LanguageService, info: ts.server.PluginCreateInfo, c:
3334 }
3435 }
3536 }
37+
38+ // thoughts about type definition: no impl here, will be simpler to do this in core
39+ if ( ts . isCallExpression ( node . parent ) ) {
40+ const parameterIndex = node . parent . arguments . indexOf ( node )
41+ const typeChecker = program . getTypeChecker ( )
42+ const type = typeChecker . getContextualType ( node . parent . expression ) ?? typeChecker . getTypeAtLocation ( node . parent . expression )
43+ // todo handle union
44+ if ( type ) {
45+ const getDefinitionsFromKeyofType = ( object : ts . Type ) => {
46+ const origin = object [ 'origin' ] as ts . Type | undefined
47+ // handle union of type?
48+ if ( ! origin ?. isIndexType ( ) || ! ( origin . type . flags & ts . TypeFlags . Object ) ) return
49+ const properties = origin . type . getProperties ( )
50+ const interestedMember = properties ?. find ( property => property . name === node . text )
51+ if ( interestedMember ) {
52+ const definitions = ( interestedMember . getDeclarations ( ) ?? [ ] ) . map ( ( declaration : ts . Node ) => {
53+ const fileName = declaration . getSourceFile ( ) . fileName
54+ if ( ts . isPropertySignature ( declaration ) ) declaration = declaration . name
55+ const start = declaration . pos + declaration . getLeadingTriviaWidth ( )
56+ return {
57+ containerKind : undefined as any ,
58+ containerName : '' ,
59+ name : '' ,
60+ fileName,
61+ textSpan : { start : start , length : declaration . end - start } ,
62+ kind : ts . ScriptElementKind . memberVariableElement ,
63+ contextSpan : { start : 0 , length : 0 } ,
64+ }
65+ } )
66+ return {
67+ textSpan,
68+ definitions,
69+ }
70+ }
71+ return
72+ }
73+ // todo handle unions and string literal
74+ const sig = type . getCallSignatures ( ) [ 0 ]
75+ const param = sig ?. getParameters ( ) [ parameterIndex ]
76+ const argType = param && typeChecker . getTypeOfSymbolAtLocation ( param , node )
77+ if ( argType ) {
78+ const definitions = getDefinitionsFromKeyofType ( argType )
79+ if ( definitions ) {
80+ return definitions
81+ }
82+
83+ if ( argType . flags & ts . TypeFlags . TypeParameter ) {
84+ const param = argType as ts . TypeParameter
85+ const constraint = param . getConstraint ( )
86+ if ( constraint ) {
87+ return getDefinitionsFromKeyofType ( constraint )
88+ }
89+ }
90+ }
91+ }
92+ }
3693 }
3794 return
3895 }
96+
3997 if ( __WEB__ ) {
4098 // let extension handle it
4199 // TODO failedAliasResolution
0 commit comments