added completion for exports in named imports section

This commit is contained in:
Vladimir Matveev 2015-02-24 15:37:13 -08:00
parent 6055dea93e
commit caabb7d99b
3 changed files with 68 additions and 0 deletions

View file

@ -56,6 +56,7 @@ module ts {
isImplementationOfOverload,
getAliasedSymbol: resolveImport,
getEmitResolver,
getExportsOfExternalModule,
};
var undefinedSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "undefined");
@ -2754,6 +2755,19 @@ module ts {
return result;
}
function getExportsOfExternalModule(node: ImportDeclaration): Symbol[]{
if (!node.moduleSpecifier) {
return emptyArray;
}
var module = resolveExternalModuleName(node, node.moduleSpecifier);
if (!module || !module.exports) {
return emptyArray;
}
return mapToArray(module.exports)
}
function getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature {
var links = getNodeLinks(declaration);
if (!links.resolvedSignature) {

View file

@ -1100,6 +1100,7 @@ module ts {
getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number;
isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean;
getAliasedSymbol(symbol: Symbol): Symbol;
getExportsOfExternalModule(node: ImportDeclaration): Symbol[];
// Should not be called directly. Should only be accessed through the Program instance.
/* @internal */ getDiagnostics(sourceFile?: SourceFile): Diagnostic[];

View file

@ -2403,6 +2403,19 @@ module ts {
getCompletionEntriesFromSymbols(filteredMembers, activeCompletionSession);
}
}
else if (getAncestor(previousToken, SyntaxKind.ImportClause)) {
// cursor is in import clause
// try to show exported member for imported module
isMemberCompletion = true;
isNewIdentifierLocation = true;
if (canShowCompletionInImportsClause(previousToken)) {
var importDeclaration = <ImportDeclaration>getAncestor(previousToken, SyntaxKind.ImportDeclaration);
Debug.assert(importDeclaration !== undefined);
var exports = typeInfoResolver.getExportsOfExternalModule(importDeclaration);
var filteredExports = filterModuleExports(exports, importDeclaration);
getCompletionEntriesFromSymbols(filteredExports, activeCompletionSession);
}
}
else {
// Get scope members
isMemberCompletion = false;
@ -2453,6 +2466,16 @@ module ts {
return result;
}
function canShowCompletionInImportsClause(node: Node): boolean {
// import {|
// import {a,|
if (node.kind === SyntaxKind.OpenBraceToken || node.kind === SyntaxKind.CommaToken) {
return node.parent.kind === SyntaxKind.NamedImports;
}
return false;
}
function isNewIdentifierDefinitionLocation(previousToken: Node): boolean {
if (previousToken) {
var containingNodeKind = previousToken.parent.kind;
@ -2531,6 +2554,8 @@ module ts {
return false;
}
function getContainingObjectLiteralApplicableForCompletion(previousToken: Node): ObjectLiteralExpression {
// The locations in an object literal expression that are applicable for completion are property name definition locations.
@ -2664,6 +2689,34 @@ module ts {
return false;
}
function filterModuleExports(exports: Symbol[], importDeclaration: ImportDeclaration): Symbol[]{
var exisingImports: Map<boolean> = {};
if (!importDeclaration.importClause) {
return exports;
}
if (importDeclaration.importClause.name) {
exisingImports[importDeclaration.importClause.name.text] = true;
}
if (importDeclaration.importClause.namedBindings &&
importDeclaration.importClause.namedBindings.kind === SyntaxKind.NamedImports) {
forEach((<NamedImports>importDeclaration.importClause.namedBindings).elements, el => {
var name = el.propertyName || el.name;
exisingImports[name.text] = true;
});
}
if (isEmpty(exisingImports)) {
return exports;
}
else {
return filter(exports, e => !lookUp(exisingImports, e.name));
}
}
function filterContextualMembersList(contextualMemberSymbols: Symbol[], existingMembers: Declaration[]): Symbol[] {
if (!existingMembers || existingMembers.length === 0) {
return contextualMemberSymbols;