Merge pull request #5588 from Microsoft/reexport-default-export

Reexport default export
This commit is contained in:
Nathan Shively-Sanders 2015-11-11 11:29:31 -08:00
commit c1ea85fa72
5 changed files with 113 additions and 22 deletions

View file

@ -486,9 +486,19 @@ namespace ts {
if (location.kind === SyntaxKind.SourceFile ||
(location.kind === SyntaxKind.ModuleDeclaration && (<ModuleDeclaration>location).name.kind === SyntaxKind.StringLiteral)) {
// It's an external module. Because of module/namespace merging, a module's exports are in scope,
// yet we never want to treat an export specifier as putting a member in scope. Therefore,
// if the name we find is purely an export specifier, it is not actually considered in scope.
// It's an external module. First see if the module has an export default and if the local
// name of that export default matches.
if (result = moduleExports["default"]) {
const localSymbol = getLocalSymbolForExportDefault(result);
if (localSymbol && (result.flags & meaning) && localSymbol.name === name) {
break loop;
}
result = undefined;
}
// Because of module/namespace merging, a module's exports are in scope,
// yet we never want to treat an export specifier as putting a member in scope.
// Therefore, if the name we find is purely an export specifier, it is not actually considered in scope.
// Two things to note about this:
// 1. We have to check this without calling getSymbol. The problem with calling getSymbol
// on an export specifier is that it might find the export specifier itself, and try to
@ -502,13 +512,6 @@ namespace ts {
getDeclarationOfKind(moduleExports[name], SyntaxKind.ExportSpecifier)) {
break;
}
result = moduleExports["default"];
const localSymbol = getLocalSymbolForExportDefault(result);
if (result && localSymbol && (result.flags & meaning) && localSymbol.name === name) {
break loop;
}
result = undefined;
}
if (result = getSymbol(moduleExports, name, meaning & SymbolFlags.ModuleMember)) {
@ -4201,12 +4204,12 @@ namespace ts {
// We only support expressions that are simple qualified names. For other expressions this produces undefined.
const typeNameOrExpression = node.kind === SyntaxKind.TypeReference ? (<TypeReferenceNode>node).typeName :
isSupportedExpressionWithTypeArguments(<ExpressionWithTypeArguments>node) ? (<ExpressionWithTypeArguments>node).expression :
undefined;
undefined;
const symbol = typeNameOrExpression && resolveEntityName(typeNameOrExpression, SymbolFlags.Type) || unknownSymbol;
const type = symbol === unknownSymbol ? unknownType :
symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? getTypeFromClassOrInterfaceReference(node, symbol) :
symbol.flags & SymbolFlags.TypeAlias ? getTypeFromTypeAliasReference(node, symbol) :
getTypeFromNonGenericTypeReference(node, symbol);
symbol.flags & SymbolFlags.TypeAlias ? getTypeFromTypeAliasReference(node, symbol) :
getTypeFromNonGenericTypeReference(node, symbol);
// Cache both the resolved symbol and the resolved type. The resolved symbol is needed in when we check the
// type reference in checkTypeReferenceOrExpressionWithTypeArguments.
links.resolvedSymbol = symbol;
@ -11446,7 +11449,7 @@ namespace ts {
// Abstract methods can't have an implementation -- in particular, they don't need one.
if (!isExportSymbolInsideModule && lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body &&
!(lastSeenNonAmbientDeclaration.flags & NodeFlags.Abstract) ) {
!(lastSeenNonAmbientDeclaration.flags & NodeFlags.Abstract)) {
reportImplementationExpectedError(lastSeenNonAmbientDeclaration);
}
@ -14380,8 +14383,8 @@ namespace ts {
if (className) {
copySymbol(location.symbol, meaning);
}
// fall through; this fall-through is necessary because we would like to handle
// type parameter inside class expression similar to how we handle it in classDeclaration and interface Declaration
// fall through; this fall-through is necessary because we would like to handle
// type parameter inside class expression similar to how we handle it in classDeclaration and interface Declaration
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
// If we didn't come from static member of class or interface,
@ -14537,8 +14540,8 @@ namespace ts {
return resolveEntityName(<EntityName>entityName, meaning);
}
else if ((entityName.parent.kind === SyntaxKind.JsxOpeningElement) ||
(entityName.parent.kind === SyntaxKind.JsxSelfClosingElement) ||
(entityName.parent.kind === SyntaxKind.JsxClosingElement)) {
(entityName.parent.kind === SyntaxKind.JsxSelfClosingElement) ||
(entityName.parent.kind === SyntaxKind.JsxClosingElement)) {
return getJsxElementTagSymbol(<JsxOpeningLikeElement>entityName.parent);
}
else if (isExpression(entityName)) {
@ -14605,8 +14608,8 @@ namespace ts {
: getSymbolOfPartOfRightHandSideOfImportEquals(<Identifier>node);
}
else if (node.parent.kind === SyntaxKind.BindingElement &&
node.parent.parent.kind === SyntaxKind.ObjectBindingPattern &&
node === (<BindingElement>node.parent).propertyName) {
node.parent.parent.kind === SyntaxKind.ObjectBindingPattern &&
node === (<BindingElement>node.parent).propertyName) {
const typeOfPattern = getTypeOfNode(node.parent.parent);
const propertyDeclaration = typeOfPattern && getPropertyOfType(typeOfPattern, (<Identifier>node).text);
@ -14643,7 +14646,7 @@ namespace ts {
(<ImportDeclaration>node.parent).moduleSpecifier === node)) {
return resolveExternalModuleName(node, <LiteralExpression>node);
}
// Fall through
// Fall through
case SyntaxKind.NumericLiteral:
// index access
@ -14839,7 +14842,7 @@ namespace ts {
if (links.isNestedRedeclaration === undefined) {
const container = getEnclosingBlockScopeContainer(symbol.valueDeclaration);
links.isNestedRedeclaration = isStatementWithLocals(container) &&
!!resolveName(container.parent, symbol.name, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined);
!!resolveName(container.parent, symbol.name, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined);
}
return links.isNestedRedeclaration;
}

View file

@ -0,0 +1,27 @@
//// [tests/cases/conformance/es6/modules/reExportDefaultExport.ts] ////
//// [m1.ts]
export default function f() {
}
export {f};
//// [m2.ts]
import foo from "./m1";
import {f} from "./m1";
f();
foo();
//// [m1.js]
function f() {
}
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = f;
exports.f = f;
//// [m2.js]
var m1_1 = require("./m1");
var m1_2 = require("./m1");
m1_2.f();
m1_1.default();

View file

@ -0,0 +1,22 @@
=== tests/cases/conformance/es6/modules/m1.ts ===
export default function f() {
>f : Symbol(f, Decl(m1.ts, 0, 0))
}
export {f};
>f : Symbol(f, Decl(m1.ts, 3, 8))
=== tests/cases/conformance/es6/modules/m2.ts ===
import foo from "./m1";
>foo : Symbol(foo, Decl(m2.ts, 0, 6))
import {f} from "./m1";
>f : Symbol(f, Decl(m2.ts, 1, 8))
f();
>f : Symbol(f, Decl(m2.ts, 1, 8))
foo();
>foo : Symbol(foo, Decl(m2.ts, 0, 6))

View file

@ -0,0 +1,24 @@
=== tests/cases/conformance/es6/modules/m1.ts ===
export default function f() {
>f : () => void
}
export {f};
>f : () => void
=== tests/cases/conformance/es6/modules/m2.ts ===
import foo from "./m1";
>foo : () => void
import {f} from "./m1";
>f : () => void
f();
>f() : void
>f : () => void
foo();
>foo() : void
>foo : () => void

View file

@ -0,0 +1,15 @@
// @module: commonjs
// @target: ES5
// @filename: m1.ts
export default function f() {
}
export {f};
// @filename: m2.ts
import foo from "./m1";
import {f} from "./m1";
f();
foo();