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

feat: Add goto type definition. #475

Merged
merged 1 commit into from
Jun 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ This is a language server for JavaScript and TypeScript that adheres to the [Lan

- Hovers
- Goto definition
- Goto type definition
- Find all references
- Document symbols
- Workspace symbol search
Expand Down
64 changes: 64 additions & 0 deletions src/test/typescript-service-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ export function describeTypeScriptService(
'let target = i.target;',
].join('\n'),
],
[rootUri + 'foo/f.ts', ['import {Foo} from "./b";', '', 'let foo: Foo = Object({});'].join('\n')],
[rootUri + 'foo/g.ts', ['class Foo = {}', '', 'let foo: Foo = Object({});'].join('\n')],
])
)
)
Expand Down Expand Up @@ -224,6 +226,68 @@ export function describeTypeScriptService(
])
})
})

describe('textDocumentTypeDefinition()', function(this: TestContext & ISuiteCallbackContext): void {
specify('in other file', async function(this: TestContext & ITestCallbackContext): Promise<void> {
const result: Location[] = await this.service
.textDocumentTypeDefinition({
textDocument: {
uri: rootUri + 'foo/f.ts',
},
position: {
line: 2,
character: 5,
},
})
.reduce<Operation, Location[]>(applyReducer, null as any)
.toPromise()
assert.deepEqual(result, [
{
uri: rootUri + 'foo/b.ts',
range: {
start: {
line: 1,
character: 13,
},
end: {
line: 1,
character: 16,
},
},
},
])
})
specify('in same file', async function(this: TestContext & ITestCallbackContext): Promise<void> {
const result: Location[] = await this.service
.textDocumentTypeDefinition({
textDocument: {
uri: rootUri + 'foo/g.ts',
},
position: {
line: 2,
character: 5,
},
})
.reduce<Operation, Location[]>(applyReducer, null as any)
.toPromise()
assert.deepEqual(result, [
{
uri: rootUri + 'foo/g.ts',
range: {
start: {
line: 0,
character: 6,
},
end: {
line: 0,
character: 9,
},
},
},
])
})
})

describe('textDocumentXdefinition()', function(this: TestContext & ISuiteCallbackContext): void {
specify('on interface field reference', async function(
this: TestContext & ITestCallbackContext
Expand Down
27 changes: 22 additions & 5 deletions src/typescript-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ export class TypeScriptService {
triggerCharacters: ['(', ','],
},
definitionProvider: true,
typeDefinitionProvider: true,
referencesProvider: true,
documentSymbolProvider: true,
workspaceSymbolProvider: true,
Expand Down Expand Up @@ -362,15 +363,31 @@ export class TypeScriptService {
*/

public textDocumentDefinition(params: TextDocumentPositionParams, span = new Span()): Observable<Operation> {
return this._getDefinitionLocations(params, span)
return this._getDefinitionLocations(params, span, false)
.map((location: Location): Operation => ({ op: 'add', path: '/-', value: location }))
.startWith({ op: 'add', path: '', value: [] })
}

/**
* The goto type definition request is sent from the client to the server to resolve the type
* location of a symbol at a given text document position.
*
* @return Observable of JSON Patches that build a `Location[]` result
*/
public textDocumentTypeDefinition(params: TextDocumentPositionParams, span = new Span()): Observable<Operation> {
return this._getDefinitionLocations(params, span, true)
.map((location: Location): Operation => ({ op: 'add', path: '/-', value: location }))
.startWith({ op: 'add', path: '', value: [] })
}

/**
* Returns an Observable of all definition locations found for a symbol.
*/
protected _getDefinitionLocations(params: TextDocumentPositionParams, span = new Span()): Observable<Location> {
protected _getDefinitionLocations(
params: TextDocumentPositionParams,
span = new Span(),
goToType = false
): Observable<Location> {
const uri = normalizeUri(params.textDocument.uri)

// Fetch files needed to resolve definition
Expand All @@ -392,9 +409,9 @@ export class TypeScriptService {
params.position.line,
params.position.character
)
const definitions: ts.DefinitionInfo[] | undefined = configuration
.getService()
.getDefinitionAtPosition(fileName, offset)
const definitions: ts.DefinitionInfo[] | undefined = goToType
? configuration.getService().getTypeDefinitionAtPosition(fileName, offset)
: configuration.getService().getDefinitionAtPosition(fileName, offset)

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