Allow getting import completion details with misspelled name (#23624)

This commit is contained in:
Andy 2018-04-23 11:24:51 -07:00 committed by GitHub
parent 2e78d1ef21
commit 645258cc7d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 13 deletions

View file

@ -2419,14 +2419,7 @@ Actual: ${stringify(fullActual)}`);
public applyCodeActionFromCompletion(markerName: string, options: FourSlashInterface.VerifyCompletionActionOptions) {
this.goToMarker(markerName);
const actualCompletion = this.getCompletionListAtCaret({ ...ts.defaultPreferences, includeCompletionsForModuleExports: true }).entries.find(e =>
e.name === options.name && e.source === options.source);
if (!actualCompletion.hasAction) {
this.raiseError(`Completion for ${options.name} does not have an associated action.`);
}
const details = this.getCompletionEntryDetails(options.name, actualCompletion.source, options.preferences);
const details = this.getCompletionEntryDetails(options.name, options.source, options.preferences);
if (details.codeActions.length !== 1) {
this.raiseError(`Expected one code action, got ${details.codeActions.length}`);
}

View file

@ -47,7 +47,7 @@ namespace ts.Completions {
return getLabelCompletionAtPosition(contextToken.parent);
}
const completionData = getCompletionData(program, log, sourceFile, position, preferences);
const completionData = getCompletionData(program, log, sourceFile, position, preferences, /*detailsEntryId*/ undefined);
if (!completionData) {
return undefined;
}
@ -486,9 +486,9 @@ namespace ts.Completions {
previousToken: Node;
readonly isJsxInitializer: IsJsxInitializer;
}
function getSymbolCompletionFromEntryId(program: Program, log: Log, sourceFile: SourceFile, position: number, { name, source }: CompletionEntryIdentifier,
function getSymbolCompletionFromEntryId(program: Program, log: Log, sourceFile: SourceFile, position: number, entryId: CompletionEntryIdentifier,
): SymbolCompletion | { type: "request", request: Request } | { type: "none" } {
const completionData = getCompletionData(program, log, sourceFile, position, { includeCompletionsForModuleExports: true, includeCompletionsWithInsertText: true });
const completionData = getCompletionData(program, log, sourceFile, position, { includeCompletionsForModuleExports: true, includeCompletionsWithInsertText: true }, entryId);
if (!completionData) {
return { type: "none" };
}
@ -505,7 +505,9 @@ namespace ts.Completions {
return firstDefined<Symbol, SymbolCompletion>(symbols, (symbol): SymbolCompletion => { // TODO: Shouldn't need return type annotation (GH#12632)
const origin = symbolToOriginInfoMap[getSymbolId(symbol)];
const info = getCompletionEntryDisplayNameForSymbol(symbol, program.getCompilerOptions().target, origin, completionKind);
return info && info.name === name && getSourceFromOrigin(origin) === source ? { type: "symbol" as "symbol", symbol, location, symbolToOriginInfoMap, previousToken, isJsxInitializer } : undefined;
return info && info.name === entryId.name && getSourceFromOrigin(origin) === entryId.source
? { type: "symbol" as "symbol", symbol, location, symbolToOriginInfoMap, previousToken, isJsxInitializer }
: undefined;
}) || { type: "none" };
}
@ -755,6 +757,7 @@ namespace ts.Completions {
sourceFile: SourceFile,
position: number,
preferences: Pick<UserPreferences, "includeCompletionsForModuleExports" | "includeCompletionsWithInsertText">,
detailsEntryId: CompletionEntryIdentifier | undefined,
): CompletionData | Request | undefined {
const typeChecker = program.getTypeChecker();
@ -1302,6 +1305,11 @@ namespace ts.Completions {
const tokenTextLowerCase = tokenText.toLowerCase();
codefix.forEachExternalModuleToImportFrom(typeChecker, sourceFile, program.getSourceFiles(), moduleSymbol => {
// Perf -- ignore other modules if this is a request for details
if (detailsEntryId && detailsEntryId.source && stripQuotes(moduleSymbol.name) !== detailsEntryId.source) {
return;
}
for (let symbol of typeChecker.getExportsOfModule(moduleSymbol)) {
// Don't add a completion for a re-export, only for the original.
// The actual import fix might end up coming from a re-export -- we don't compute that until getting completion details.
@ -1320,7 +1328,7 @@ namespace ts.Completions {
}
const origin: SymbolOriginInfo = { type: "export", moduleSymbol, isDefaultExport };
if (stringContainsCharactersInOrder(getSymbolName(symbol, origin, target).toLowerCase(), tokenTextLowerCase)) {
if (detailsEntryId || stringContainsCharactersInOrder(getSymbolName(symbol, origin, target).toLowerCase(), tokenTextLowerCase)) {
symbols.push(symbol);
symbolToOriginInfoMap[getSymbolId(symbol)] = origin;
}

View file

@ -0,0 +1,17 @@
/// <reference path="fourslash.ts" />
// @Filename: /a.ts
////export const abc = 0;
// @Filename: /b.ts
////acb/**/;
goTo.marker("");
verify.applyCodeActionFromCompletion("", {
name: "abc",
source: "/a",
description: `Import 'abc' from module "./a"`,
newFileContent: `import { abc } from "./a";
acb;`,
});