Skip to content
This repository was archived by the owner on Oct 16, 2020. It is now read-only.

Commit d107424

Browse files
teasp00nfelixfbecker
authored andcommitted
feat: Add goto type definition. (#475)
Adds support to go directly to the type definition for the symbol under the cursor.
1 parent fcc0ccb commit d107424

File tree

3 files changed

+87
-5
lines changed

3 files changed

+87
-5
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ This is a language server for JavaScript and TypeScript that adheres to the [Lan
2828

2929
- Hovers
3030
- Goto definition
31+
- Goto type definition
3132
- Find all references
3233
- Document symbols
3334
- Workspace symbol search

src/test/typescript-service-helpers.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ export function describeTypeScriptService(
143143
'let target = i.target;',
144144
].join('\n'),
145145
],
146+
[rootUri + 'foo/f.ts', ['import {Foo} from "./b";', '', 'let foo: Foo = Object({});'].join('\n')],
147+
[rootUri + 'foo/g.ts', ['class Foo = {}', '', 'let foo: Foo = Object({});'].join('\n')],
146148
])
147149
)
148150
)
@@ -224,6 +226,68 @@ export function describeTypeScriptService(
224226
])
225227
})
226228
})
229+
230+
describe('textDocumentTypeDefinition()', function(this: TestContext & ISuiteCallbackContext): void {
231+
specify('in other file', async function(this: TestContext & ITestCallbackContext): Promise<void> {
232+
const result: Location[] = await this.service
233+
.textDocumentTypeDefinition({
234+
textDocument: {
235+
uri: rootUri + 'foo/f.ts',
236+
},
237+
position: {
238+
line: 2,
239+
character: 5,
240+
},
241+
})
242+
.reduce<Operation, Location[]>(applyReducer, null as any)
243+
.toPromise()
244+
assert.deepEqual(result, [
245+
{
246+
uri: rootUri + 'foo/b.ts',
247+
range: {
248+
start: {
249+
line: 1,
250+
character: 13,
251+
},
252+
end: {
253+
line: 1,
254+
character: 16,
255+
},
256+
},
257+
},
258+
])
259+
})
260+
specify('in same file', async function(this: TestContext & ITestCallbackContext): Promise<void> {
261+
const result: Location[] = await this.service
262+
.textDocumentTypeDefinition({
263+
textDocument: {
264+
uri: rootUri + 'foo/g.ts',
265+
},
266+
position: {
267+
line: 2,
268+
character: 5,
269+
},
270+
})
271+
.reduce<Operation, Location[]>(applyReducer, null as any)
272+
.toPromise()
273+
assert.deepEqual(result, [
274+
{
275+
uri: rootUri + 'foo/g.ts',
276+
range: {
277+
start: {
278+
line: 0,
279+
character: 6,
280+
},
281+
end: {
282+
line: 0,
283+
character: 9,
284+
},
285+
},
286+
},
287+
])
288+
})
289+
})
290+
227291
describe('textDocumentXdefinition()', function(this: TestContext & ISuiteCallbackContext): void {
228292
specify('on interface field reference', async function(
229293
this: TestContext & ITestCallbackContext

src/typescript-service.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ export class TypeScriptService {
297297
triggerCharacters: ['(', ','],
298298
},
299299
definitionProvider: true,
300+
typeDefinitionProvider: true,
300301
referencesProvider: true,
301302
documentSymbolProvider: true,
302303
workspaceSymbolProvider: true,
@@ -362,15 +363,31 @@ export class TypeScriptService {
362363
*/
363364

364365
public textDocumentDefinition(params: TextDocumentPositionParams, span = new Span()): Observable<Operation> {
365-
return this._getDefinitionLocations(params, span)
366+
return this._getDefinitionLocations(params, span, false)
367+
.map((location: Location): Operation => ({ op: 'add', path: '/-', value: location }))
368+
.startWith({ op: 'add', path: '', value: [] })
369+
}
370+
371+
/**
372+
* The goto type definition request is sent from the client to the server to resolve the type
373+
* location of a symbol at a given text document position.
374+
*
375+
* @return Observable of JSON Patches that build a `Location[]` result
376+
*/
377+
public textDocumentTypeDefinition(params: TextDocumentPositionParams, span = new Span()): Observable<Operation> {
378+
return this._getDefinitionLocations(params, span, true)
366379
.map((location: Location): Operation => ({ op: 'add', path: '/-', value: location }))
367380
.startWith({ op: 'add', path: '', value: [] })
368381
}
369382

370383
/**
371384
* Returns an Observable of all definition locations found for a symbol.
372385
*/
373-
protected _getDefinitionLocations(params: TextDocumentPositionParams, span = new Span()): Observable<Location> {
386+
protected _getDefinitionLocations(
387+
params: TextDocumentPositionParams,
388+
span = new Span(),
389+
goToType = false
390+
): Observable<Location> {
374391
const uri = normalizeUri(params.textDocument.uri)
375392

376393
// Fetch files needed to resolve definition
@@ -392,9 +409,9 @@ export class TypeScriptService {
392409
params.position.line,
393410
params.position.character
394411
)
395-
const definitions: ts.DefinitionInfo[] | undefined = configuration
396-
.getService()
397-
.getDefinitionAtPosition(fileName, offset)
412+
const definitions: ts.DefinitionInfo[] | undefined = goToType
413+
? configuration.getService().getTypeDefinitionAtPosition(fileName, offset)
414+
: configuration.getService().getDefinitionAtPosition(fileName, offset)
398415

399416
return Observable.from(definitions || []).map((definition): Location => {
400417
const sourceFile = this._getSourceFile(configuration, definition.fileName, span)

0 commit comments

Comments
 (0)