Skip to content

Commit caabb7d

Browse files
committed
added completion for exports in named imports section
1 parent 6055dea commit caabb7d

3 files changed

Lines changed: 68 additions & 0 deletions

File tree

src/compiler/checker.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ module ts {
5656
isImplementationOfOverload,
5757
getAliasedSymbol: resolveImport,
5858
getEmitResolver,
59+
getExportsOfExternalModule,
5960
};
6061

6162
var undefinedSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "undefined");
@@ -2754,6 +2755,19 @@ module ts {
27542755
return result;
27552756
}
27562757

2758+
function getExportsOfExternalModule(node: ImportDeclaration): Symbol[]{
2759+
if (!node.moduleSpecifier) {
2760+
return emptyArray;
2761+
}
2762+
2763+
var module = resolveExternalModuleName(node, node.moduleSpecifier);
2764+
if (!module || !module.exports) {
2765+
return emptyArray;
2766+
}
2767+
2768+
return mapToArray(module.exports)
2769+
}
2770+
27572771
function getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature {
27582772
var links = getNodeLinks(declaration);
27592773
if (!links.resolvedSignature) {

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,6 +1100,7 @@ module ts {
11001100
getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number;
11011101
isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean;
11021102
getAliasedSymbol(symbol: Symbol): Symbol;
1103+
getExportsOfExternalModule(node: ImportDeclaration): Symbol[];
11031104

11041105
// Should not be called directly. Should only be accessed through the Program instance.
11051106
/* @internal */ getDiagnostics(sourceFile?: SourceFile): Diagnostic[];

src/services/services.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2403,6 +2403,19 @@ module ts {
24032403
getCompletionEntriesFromSymbols(filteredMembers, activeCompletionSession);
24042404
}
24052405
}
2406+
else if (getAncestor(previousToken, SyntaxKind.ImportClause)) {
2407+
// cursor is in import clause
2408+
// try to show exported member for imported module
2409+
isMemberCompletion = true;
2410+
isNewIdentifierLocation = true;
2411+
if (canShowCompletionInImportsClause(previousToken)) {
2412+
var importDeclaration = <ImportDeclaration>getAncestor(previousToken, SyntaxKind.ImportDeclaration);
2413+
Debug.assert(importDeclaration !== undefined);
2414+
var exports = typeInfoResolver.getExportsOfExternalModule(importDeclaration);
2415+
var filteredExports = filterModuleExports(exports, importDeclaration);
2416+
getCompletionEntriesFromSymbols(filteredExports, activeCompletionSession);
2417+
}
2418+
}
24062419
else {
24072420
// Get scope members
24082421
isMemberCompletion = false;
@@ -2453,6 +2466,16 @@ module ts {
24532466
return result;
24542467
}
24552468

2469+
function canShowCompletionInImportsClause(node: Node): boolean {
2470+
// import {|
2471+
// import {a,|
2472+
if (node.kind === SyntaxKind.OpenBraceToken || node.kind === SyntaxKind.CommaToken) {
2473+
return node.parent.kind === SyntaxKind.NamedImports;
2474+
}
2475+
2476+
return false;
2477+
}
2478+
24562479
function isNewIdentifierDefinitionLocation(previousToken: Node): boolean {
24572480
if (previousToken) {
24582481
var containingNodeKind = previousToken.parent.kind;
@@ -2531,6 +2554,8 @@ module ts {
25312554
return false;
25322555
}
25332556

2557+
2558+
25342559
function getContainingObjectLiteralApplicableForCompletion(previousToken: Node): ObjectLiteralExpression {
25352560
// The locations in an object literal expression that are applicable for completion are property name definition locations.
25362561

@@ -2664,6 +2689,34 @@ module ts {
26642689
return false;
26652690
}
26662691

2692+
function filterModuleExports(exports: Symbol[], importDeclaration: ImportDeclaration): Symbol[]{
2693+
var exisingImports: Map<boolean> = {};
2694+
2695+
if (!importDeclaration.importClause) {
2696+
return exports;
2697+
}
2698+
2699+
if (importDeclaration.importClause.name) {
2700+
exisingImports[importDeclaration.importClause.name.text] = true;
2701+
}
2702+
2703+
if (importDeclaration.importClause.namedBindings &&
2704+
importDeclaration.importClause.namedBindings.kind === SyntaxKind.NamedImports) {
2705+
2706+
forEach((<NamedImports>importDeclaration.importClause.namedBindings).elements, el => {
2707+
var name = el.propertyName || el.name;
2708+
exisingImports[name.text] = true;
2709+
});
2710+
}
2711+
2712+
if (isEmpty(exisingImports)) {
2713+
return exports;
2714+
}
2715+
else {
2716+
return filter(exports, e => !lookUp(exisingImports, e.name));
2717+
}
2718+
}
2719+
26672720
function filterContextualMembersList(contextualMemberSymbols: Symbol[], existingMembers: Declaration[]): Symbol[] {
26682721
if (!existingMembers || existingMembers.length === 0) {
26692722
return contextualMemberSymbols;

0 commit comments

Comments
 (0)