Skip to content

Commit 645258c

Browse files
author
Andy
authored
Allow getting import completion details with misspelled name (microsoft#23624)
1 parent 2e78d1e commit 645258c

File tree

3 files changed

+31
-13
lines changed

3 files changed

+31
-13
lines changed

src/harness/fourslash.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2419,14 +2419,7 @@ Actual: ${stringify(fullActual)}`);
24192419
public applyCodeActionFromCompletion(markerName: string, options: FourSlashInterface.VerifyCompletionActionOptions) {
24202420
this.goToMarker(markerName);
24212421

2422-
const actualCompletion = this.getCompletionListAtCaret({ ...ts.defaultPreferences, includeCompletionsForModuleExports: true }).entries.find(e =>
2423-
e.name === options.name && e.source === options.source);
2424-
2425-
if (!actualCompletion.hasAction) {
2426-
this.raiseError(`Completion for ${options.name} does not have an associated action.`);
2427-
}
2428-
2429-
const details = this.getCompletionEntryDetails(options.name, actualCompletion.source, options.preferences);
2422+
const details = this.getCompletionEntryDetails(options.name, options.source, options.preferences);
24302423
if (details.codeActions.length !== 1) {
24312424
this.raiseError(`Expected one code action, got ${details.codeActions.length}`);
24322425
}

src/services/completions.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ namespace ts.Completions {
4747
return getLabelCompletionAtPosition(contextToken.parent);
4848
}
4949

50-
const completionData = getCompletionData(program, log, sourceFile, position, preferences);
50+
const completionData = getCompletionData(program, log, sourceFile, position, preferences, /*detailsEntryId*/ undefined);
5151
if (!completionData) {
5252
return undefined;
5353
}
@@ -486,9 +486,9 @@ namespace ts.Completions {
486486
previousToken: Node;
487487
readonly isJsxInitializer: IsJsxInitializer;
488488
}
489-
function getSymbolCompletionFromEntryId(program: Program, log: Log, sourceFile: SourceFile, position: number, { name, source }: CompletionEntryIdentifier,
489+
function getSymbolCompletionFromEntryId(program: Program, log: Log, sourceFile: SourceFile, position: number, entryId: CompletionEntryIdentifier,
490490
): SymbolCompletion | { type: "request", request: Request } | { type: "none" } {
491-
const completionData = getCompletionData(program, log, sourceFile, position, { includeCompletionsForModuleExports: true, includeCompletionsWithInsertText: true });
491+
const completionData = getCompletionData(program, log, sourceFile, position, { includeCompletionsForModuleExports: true, includeCompletionsWithInsertText: true }, entryId);
492492
if (!completionData) {
493493
return { type: "none" };
494494
}
@@ -505,7 +505,9 @@ namespace ts.Completions {
505505
return firstDefined<Symbol, SymbolCompletion>(symbols, (symbol): SymbolCompletion => { // TODO: Shouldn't need return type annotation (GH#12632)
506506
const origin = symbolToOriginInfoMap[getSymbolId(symbol)];
507507
const info = getCompletionEntryDisplayNameForSymbol(symbol, program.getCompilerOptions().target, origin, completionKind);
508-
return info && info.name === name && getSourceFromOrigin(origin) === source ? { type: "symbol" as "symbol", symbol, location, symbolToOriginInfoMap, previousToken, isJsxInitializer } : undefined;
508+
return info && info.name === entryId.name && getSourceFromOrigin(origin) === entryId.source
509+
? { type: "symbol" as "symbol", symbol, location, symbolToOriginInfoMap, previousToken, isJsxInitializer }
510+
: undefined;
509511
}) || { type: "none" };
510512
}
511513

@@ -755,6 +757,7 @@ namespace ts.Completions {
755757
sourceFile: SourceFile,
756758
position: number,
757759
preferences: Pick<UserPreferences, "includeCompletionsForModuleExports" | "includeCompletionsWithInsertText">,
760+
detailsEntryId: CompletionEntryIdentifier | undefined,
758761
): CompletionData | Request | undefined {
759762
const typeChecker = program.getTypeChecker();
760763

@@ -1302,6 +1305,11 @@ namespace ts.Completions {
13021305
const tokenTextLowerCase = tokenText.toLowerCase();
13031306

13041307
codefix.forEachExternalModuleToImportFrom(typeChecker, sourceFile, program.getSourceFiles(), moduleSymbol => {
1308+
// Perf -- ignore other modules if this is a request for details
1309+
if (detailsEntryId && detailsEntryId.source && stripQuotes(moduleSymbol.name) !== detailsEntryId.source) {
1310+
return;
1311+
}
1312+
13051313
for (let symbol of typeChecker.getExportsOfModule(moduleSymbol)) {
13061314
// Don't add a completion for a re-export, only for the original.
13071315
// 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 {
13201328
}
13211329

13221330
const origin: SymbolOriginInfo = { type: "export", moduleSymbol, isDefaultExport };
1323-
if (stringContainsCharactersInOrder(getSymbolName(symbol, origin, target).toLowerCase(), tokenTextLowerCase)) {
1331+
if (detailsEntryId || stringContainsCharactersInOrder(getSymbolName(symbol, origin, target).toLowerCase(), tokenTextLowerCase)) {
13241332
symbols.push(symbol);
13251333
symbolToOriginInfoMap[getSymbolId(symbol)] = origin;
13261334
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @Filename: /a.ts
4+
////export const abc = 0;
5+
6+
// @Filename: /b.ts
7+
////acb/**/;
8+
9+
goTo.marker("");
10+
verify.applyCodeActionFromCompletion("", {
11+
name: "abc",
12+
source: "/a",
13+
description: `Import 'abc' from module "./a"`,
14+
newFileContent: `import { abc } from "./a";
15+
16+
acb;`,
17+
});

0 commit comments

Comments
 (0)