Skip to content

Commit 43a2d38

Browse files
author
Andy
authored
Merge pull request #13446 from Microsoft/export_equals_completion
Include properties of an `export =` value in import completions.
2 parents 1476d7e + 765114f commit 43a2d38

File tree

8 files changed

+76
-12
lines changed

8 files changed

+76
-12
lines changed

src/compiler/checker.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ namespace ts {
108108
getAliasedSymbol: resolveAlias,
109109
getEmitResolver,
110110
getExportsOfModule: getExportsOfModuleAsArray,
111+
getExportsAndPropertiesOfModule,
111112
getAmbientModules,
112113
getJsxElementAttributesType,
113114
getJsxIntrinsicTagNames,
@@ -1527,6 +1528,15 @@ namespace ts {
15271528
return symbolsToArray(getExportsOfModule(moduleSymbol));
15281529
}
15291530

1531+
function getExportsAndPropertiesOfModule(moduleSymbol: Symbol): Symbol[] {
1532+
const exports = getExportsOfModuleAsArray(moduleSymbol);
1533+
const exportEquals = resolveExternalModuleSymbol(moduleSymbol);
1534+
if (exportEquals !== moduleSymbol) {
1535+
addRange(exports, getPropertiesOfType(getTypeOfSymbol(exportEquals)));
1536+
}
1537+
return exports;
1538+
}
1539+
15301540
function tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined {
15311541
const symbolTable = getExportsOfModule(moduleSymbol);
15321542
if (symbolTable) {

src/compiler/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2370,6 +2370,8 @@ namespace ts {
23702370
isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean;
23712371
getAliasedSymbol(symbol: Symbol): Symbol;
23722372
getExportsOfModule(moduleSymbol: Symbol): Symbol[];
2373+
/** Unlike `getExportsOfModule`, this includes properties of an `export =` value. */
2374+
/* @internal */ getExportsAndPropertiesOfModule(moduleSymbol: Symbol): Symbol[];
23732375

23742376
getJsxElementAttributesType(elementNode: JsxOpeningLikeElement): Type;
23752377
getJsxIntrinsicTagNames(): Symbol[];

src/harness/fourslash.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,8 +425,7 @@ namespace FourSlash {
425425
}
426426

427427
private raiseError(message: string) {
428-
message = this.messageAtLastKnownMarker(message);
429-
throw new Error(message);
428+
throw new Error(this.messageAtLastKnownMarker(message));
430429
}
431430

432431
private messageAtLastKnownMarker(message: string) {
@@ -723,6 +722,27 @@ namespace FourSlash {
723722
}
724723
}
725724

725+
public verifyCompletionsAt(markerName: string, expected: string[]) {
726+
this.goToMarker(markerName);
727+
728+
const actualCompletions = this.getCompletionListAtCaret();
729+
if (!actualCompletions) {
730+
this.raiseError(`No completions at position '${this.currentCaretPosition}'.`);
731+
}
732+
733+
const actual = actualCompletions.entries;
734+
735+
if (actual.length !== expected.length) {
736+
this.raiseError(`Expected ${expected.length} completions, got ${actual.map(a => a.name)}.`);
737+
}
738+
739+
ts.zipWith(actual, expected, (completion, expectedCompletion, index) => {
740+
if (completion.name !== expectedCompletion) {
741+
this.raiseError(`Expected completion at index ${index} to be ${expectedCompletion}, got ${completion.name}`);
742+
}
743+
});
744+
}
745+
726746
public verifyCompletionListContains(symbol: string, text?: string, documentation?: string, kind?: string, spanIndex?: number) {
727747
const completions = this.getCompletionListAtCaret();
728748
if (completions) {
@@ -3166,6 +3186,10 @@ namespace FourSlashInterface {
31663186
super(state);
31673187
}
31683188

3189+
public completionsAt(markerName: string, completions: string[]) {
3190+
this.state.verifyCompletionsAt(markerName, completions);
3191+
}
3192+
31693193
public quickInfoIs(expectedText: string, expectedDocumentation?: string) {
31703194
this.state.verifyQuickInfoString(expectedText, expectedDocumentation);
31713195
}

src/services/completions.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,14 +1318,14 @@ namespace ts.Completions {
13181318
isMemberCompletion = true;
13191319
isNewIdentifierLocation = false;
13201320

1321-
let exports: Symbol[];
1322-
const moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(importOrExportDeclaration.moduleSpecifier);
1323-
if (moduleSpecifierSymbol) {
1324-
exports = typeChecker.getExportsOfModule(moduleSpecifierSymbol);
1321+
const moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(moduleSpecifier);
1322+
if (!moduleSpecifierSymbol) {
1323+
symbols = emptyArray;
1324+
return true;
13251325
}
13261326

1327-
symbols = exports ? filterNamedImportOrExportCompletionItems(exports, namedImportsOrExports.elements) : emptyArray;
1328-
1327+
const exports = typeChecker.getExportsAndPropertiesOfModule(moduleSpecifierSymbol);
1328+
symbols = filterNamedImportOrExportCompletionItems(exports, namedImportsOrExports.elements);
13291329
return true;
13301330
}
13311331

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
///<reference path="fourslash.ts"/>
3+
4+
// @Filename: /node_modules/foo/index.d.ts
5+
////export = Foo;
6+
////declare var Foo: Foo.Static;
7+
////declare namespace Foo {
8+
//// interface Static {
9+
//// foo(): void;
10+
//// }
11+
////}
12+
13+
// @Filename: /a.ts
14+
////import { /**/ } from "foo";
15+
16+
verify.completionsAt("", ["Static", "foo"]);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
///<reference path="fourslash.ts"/>
3+
4+
// @Filename: /node_modules/foo/index.d.ts
5+
////export = Foo;
6+
////interface Foo { bar: number; }
7+
////declare namespace Foo {
8+
//// interface Static {}
9+
////}
10+
11+
// @Filename: /a.ts
12+
////import { /**/ } from "foo";
13+
14+
verify.completionsAt("", ["Static"]);

tests/cases/fourslash/completionListInImportClause04.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@
1111
// @Filename: app.ts
1212
////import {/*1*/} from './foo';
1313

14-
goTo.marker('1');
15-
verify.completionListContains('prop1');
16-
verify.completionListContains('prop2');
17-
verify.not.completionListContains('Foo');
14+
verify.completionsAt("1", ["prototype", "prop1", "prop2"]);
1815
verify.numberOfErrorsInCurrentFile(0);
1916
goTo.marker('2');
2017
verify.numberOfErrorsInCurrentFile(0);

tests/cases/fourslash/fourslash.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ declare namespace FourSlashInterface {
138138
class verify extends verifyNegatable {
139139
assertHasRanges(ranges: Range[]): void;
140140
caretAtMarker(markerName?: string): void;
141+
completionsAt(markerName: string, completions: string[]): void;
141142
indentationIs(numberOfSpaces: number): void;
142143
indentationAtPositionIs(fileName: string, position: number, numberOfSpaces: number, indentStyle?: ts.IndentStyle, baseIndentSize?: number): void;
143144
textAtCaretIs(text: string): void;

0 commit comments

Comments
 (0)