Merge pull request #13446 from Microsoft/export_equals_completion

Include properties of an `export =` value in import completions.
This commit is contained in:
Andy 2017-01-13 09:55:43 -08:00 committed by GitHub
commit 43a2d3849b
8 changed files with 76 additions and 12 deletions

View file

@ -108,6 +108,7 @@ namespace ts {
getAliasedSymbol: resolveAlias,
getEmitResolver,
getExportsOfModule: getExportsOfModuleAsArray,
getExportsAndPropertiesOfModule,
getAmbientModules,
getJsxElementAttributesType,
getJsxIntrinsicTagNames,
@ -1527,6 +1528,15 @@ namespace ts {
return symbolsToArray(getExportsOfModule(moduleSymbol));
}
function getExportsAndPropertiesOfModule(moduleSymbol: Symbol): Symbol[] {
const exports = getExportsOfModuleAsArray(moduleSymbol);
const exportEquals = resolveExternalModuleSymbol(moduleSymbol);
if (exportEquals !== moduleSymbol) {
addRange(exports, getPropertiesOfType(getTypeOfSymbol(exportEquals)));
}
return exports;
}
function tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined {
const symbolTable = getExportsOfModule(moduleSymbol);
if (symbolTable) {

View file

@ -2370,6 +2370,8 @@ namespace ts {
isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean;
getAliasedSymbol(symbol: Symbol): Symbol;
getExportsOfModule(moduleSymbol: Symbol): Symbol[];
/** Unlike `getExportsOfModule`, this includes properties of an `export =` value. */
/* @internal */ getExportsAndPropertiesOfModule(moduleSymbol: Symbol): Symbol[];
getJsxElementAttributesType(elementNode: JsxOpeningLikeElement): Type;
getJsxIntrinsicTagNames(): Symbol[];

View file

@ -425,8 +425,7 @@ namespace FourSlash {
}
private raiseError(message: string) {
message = this.messageAtLastKnownMarker(message);
throw new Error(message);
throw new Error(this.messageAtLastKnownMarker(message));
}
private messageAtLastKnownMarker(message: string) {
@ -723,6 +722,27 @@ namespace FourSlash {
}
}
public verifyCompletionsAt(markerName: string, expected: string[]) {
this.goToMarker(markerName);
const actualCompletions = this.getCompletionListAtCaret();
if (!actualCompletions) {
this.raiseError(`No completions at position '${this.currentCaretPosition}'.`);
}
const actual = actualCompletions.entries;
if (actual.length !== expected.length) {
this.raiseError(`Expected ${expected.length} completions, got ${actual.map(a => a.name)}.`);
}
ts.zipWith(actual, expected, (completion, expectedCompletion, index) => {
if (completion.name !== expectedCompletion) {
this.raiseError(`Expected completion at index ${index} to be ${expectedCompletion}, got ${completion.name}`);
}
});
}
public verifyCompletionListContains(symbol: string, text?: string, documentation?: string, kind?: string, spanIndex?: number) {
const completions = this.getCompletionListAtCaret();
if (completions) {
@ -3166,6 +3186,10 @@ namespace FourSlashInterface {
super(state);
}
public completionsAt(markerName: string, completions: string[]) {
this.state.verifyCompletionsAt(markerName, completions);
}
public quickInfoIs(expectedText: string, expectedDocumentation?: string) {
this.state.verifyQuickInfoString(expectedText, expectedDocumentation);
}

View file

@ -1318,14 +1318,14 @@ namespace ts.Completions {
isMemberCompletion = true;
isNewIdentifierLocation = false;
let exports: Symbol[];
const moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(importOrExportDeclaration.moduleSpecifier);
if (moduleSpecifierSymbol) {
exports = typeChecker.getExportsOfModule(moduleSpecifierSymbol);
const moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(moduleSpecifier);
if (!moduleSpecifierSymbol) {
symbols = emptyArray;
return true;
}
symbols = exports ? filterNamedImportOrExportCompletionItems(exports, namedImportsOrExports.elements) : emptyArray;
const exports = typeChecker.getExportsAndPropertiesOfModule(moduleSpecifierSymbol);
symbols = filterNamedImportOrExportCompletionItems(exports, namedImportsOrExports.elements);
return true;
}

View file

@ -0,0 +1,16 @@
///<reference path="fourslash.ts"/>
// @Filename: /node_modules/foo/index.d.ts
////export = Foo;
////declare var Foo: Foo.Static;
////declare namespace Foo {
//// interface Static {
//// foo(): void;
//// }
////}
// @Filename: /a.ts
////import { /**/ } from "foo";
verify.completionsAt("", ["Static", "foo"]);

View file

@ -0,0 +1,14 @@
///<reference path="fourslash.ts"/>
// @Filename: /node_modules/foo/index.d.ts
////export = Foo;
////interface Foo { bar: number; }
////declare namespace Foo {
//// interface Static {}
////}
// @Filename: /a.ts
////import { /**/ } from "foo";
verify.completionsAt("", ["Static"]);

View file

@ -11,10 +11,7 @@
// @Filename: app.ts
////import {/*1*/} from './foo';
goTo.marker('1');
verify.completionListContains('prop1');
verify.completionListContains('prop2');
verify.not.completionListContains('Foo');
verify.completionsAt("1", ["prototype", "prop1", "prop2"]);
verify.numberOfErrorsInCurrentFile(0);
goTo.marker('2');
verify.numberOfErrorsInCurrentFile(0);

View file

@ -138,6 +138,7 @@ declare namespace FourSlashInterface {
class verify extends verifyNegatable {
assertHasRanges(ranges: Range[]): void;
caretAtMarker(markerName?: string): void;
completionsAt(markerName: string, completions: string[]): void;
indentationIs(numberOfSpaces: number): void;
indentationAtPositionIs(fileName: string, position: number, numberOfSpaces: number, indentStyle?: ts.IndentStyle, baseIndentSize?: number): void;
textAtCaretIs(text: string): void;