feat(language-service): Implement definitionAndBoundSpan (#30125)

This PR adds the implementation for `definitionAndBoundSpan` because
it's now preferred over `definition`. vscode would send this new request
for `Go to definition`. As part of this PR the implementation for
`definition` is refactored and simplified. Goldens for both methods are
checked in.

PR Close #30125
This commit is contained in:
Keen Yee Liau
2019-04-25 11:11:33 -07:00
committed by Andrew Kushnir
parent 67012509a8
commit f4916730b5
4 changed files with 117 additions and 39 deletions

View File

@ -10,7 +10,7 @@ import * as ts from 'typescript'; // used as value, passed in by tsserver at run
import * as tss from 'typescript/lib/tsserverlibrary'; // used as type only
import {createLanguageService} from './language_service';
import {Completion, Diagnostic, DiagnosticMessageChain} from './types';
import {Completion, Diagnostic, DiagnosticMessageChain, Location} from './types';
import {TypeScriptServiceHost} from './typescript_host';
const projectHostMap = new WeakMap<tss.server.Project, TypeScriptServiceHost>();
@ -156,36 +156,61 @@ export function create(info: tss.server.PluginCreateInfo): ts.LanguageService {
return base;
};
proxy.getDefinitionAtPosition = function(
fileName: string, position: number): ReadonlyArray<ts.DefinitionInfo> {
let base = oldLS.getDefinitionAtPosition(fileName, position);
if (base && base.length) {
return base;
}
proxy.getDefinitionAtPosition = function(fileName: string, position: number):
ReadonlyArray<ts.DefinitionInfo>|
undefined {
const base = oldLS.getDefinitionAtPosition(fileName, position);
if (base && base.length) {
return base;
}
const ours = ls.getDefinitionAt(fileName, position);
if (ours && ours.length) {
return ours.map((loc: Location) => {
return {
fileName: loc.fileName,
textSpan: {
start: loc.span.start,
length: loc.span.end - loc.span.start,
},
name: '',
kind: ts.ScriptElementKind.unknown,
containerName: loc.fileName,
containerKind: ts.ScriptElementKind.unknown,
};
});
}
};
return tryOperation('get definition', () => {
const ours = ls.getDefinitionAt(fileName, position);
let combined;
if (ours && ours.length) {
combined = base && base.concat([]) || [];
for (const loc of ours) {
combined.push({
fileName: loc.fileName,
textSpan: {start: loc.span.start, length: loc.span.end - loc.span.start},
name: '',
// TODO: remove any and fix type error.
kind: 'definition' as any,
containerName: loc.fileName,
containerKind: 'file' as any,
});
}
} else {
combined = base;
}
return combined;
}) || [];
};
proxy.getDefinitionAndBoundSpan = function(fileName: string, position: number):
ts.DefinitionInfoAndBoundSpan |
undefined {
const base = oldLS.getDefinitionAndBoundSpan(fileName, position);
if (base && base.definitions && base.definitions.length) {
return base;
}
const ours = ls.getDefinitionAt(fileName, position);
if (ours && ours.length) {
return {
definitions: ours.map((loc: Location) => {
return {
fileName: loc.fileName,
textSpan: {
start: loc.span.start,
length: loc.span.end - loc.span.start,
},
name: '',
kind: ts.ScriptElementKind.unknown,
containerName: loc.fileName,
containerKind: ts.ScriptElementKind.unknown,
};
}),
textSpan: {
start: ours[0].span.start,
length: ours[0].span.end - ours[0].span.start,
},
};
}
};
return proxy;
}