Fixes emit for exported namespaces in external modules.

This commit is contained in:
Ron Buckton 2016-04-04 15:52:37 -07:00
parent 0f4a3dbc63
commit a69d13ba0f
2 changed files with 66 additions and 83 deletions

View File

@ -665,14 +665,9 @@ namespace ts {
function visitExpressionStatement(node: ExpressionStatement): VisitResult<Statement> {
const original = getOriginalNode(node);
if (hasModifier(original, ModifierFlags.Export)) {
switch (original.kind) {
case SyntaxKind.EnumDeclaration:
return visitExpressionStatementForEnumDeclaration(node, <EnumDeclaration>original);
case SyntaxKind.ModuleDeclaration:
return visitExpressionStatementForModuleDeclaration(node, <ModuleDeclaration>original);
}
if (original.kind === SyntaxKind.EnumDeclaration
&& hasModifier(original, ModifierFlags.Export)) {
return visitExpressionStatementForEnumDeclaration(node, <EnumDeclaration>original);
}
return node;
@ -681,28 +676,7 @@ namespace ts {
function visitExpressionStatementForEnumDeclaration(node: ExpressionStatement, original: EnumDeclaration): VisitResult<Statement> {
if (isFirstDeclarationOfKind(original, SyntaxKind.EnumDeclaration)) {
const statements: Statement[] = [node];
addVarForExportedEnumOrModule(statements, original);
return statements;
}
return node;
}
function isModuleMergedWithES6Class(node: ModuleDeclaration) {
return languageVersion === ScriptTarget.ES6
&& isMergedWithClass(node);
}
function visitExpressionStatementForModuleDeclaration(node: ExpressionStatement, original: ModuleDeclaration): VisitResult<Statement> {
if (isFirstDeclarationOfKind(original, SyntaxKind.ModuleDeclaration)) {
const statements: Statement[] = [node];
if (isModuleMergedWithES6Class(original)) {
addAssignmentForExportedModule(statements, original);
}
else {
addVarForExportedEnumOrModule(statements, original);
}
addVarForExportedEnumDeclaration(statements, original);
return statements;
}
@ -712,7 +686,7 @@ namespace ts {
/**
* Adds a trailing VariableStatement for an enum or module declaration.
*/
function addVarForExportedEnumOrModule(statements: Statement[], node: EnumDeclaration | ModuleDeclaration) {
function addVarForExportedEnumDeclaration(statements: Statement[], node: EnumDeclaration | ModuleDeclaration) {
statements.push(
createVariableStatement(
/*modifiers*/ undefined,
@ -725,21 +699,6 @@ namespace ts {
);
}
/**
* Adds a trailing assignment for a module declaration.
*/
function addAssignmentForExportedModule(statements: Statement[], node: ModuleDeclaration) {
statements.push(
createStatement(
createAssignment(
getDeclarationName(node),
createPropertyAccess(createIdentifier("exports"), getDeclarationName(node))
),
/*location*/ node
)
);
}
function getDeclarationName(node: DeclarationStatement) {
return node.name ? getSynthesizedClone(node.name) : getGeneratedNameForNode(node);
}

View File

@ -27,6 +27,7 @@ namespace ts {
const resolver = context.getEmitResolver();
const compilerOptions = context.getCompilerOptions();
const languageVersion = getEmitScriptTarget(compilerOptions);
const moduleKind = getEmitModuleKind(compilerOptions);
// Save the previous transformation hooks.
const previousOnEmitNode = context.onEmitNode;
@ -2167,14 +2168,32 @@ namespace ts {
return createPartiallyEmittedExpression(expression, node);
}
/**
* Determines whether to emit an enum declaration.
*
* @param node The enum declaration node.
*/
function shouldEmitEnumDeclaration(node: EnumDeclaration) {
return !isConst(node)
|| compilerOptions.preserveConstEnums
|| compilerOptions.isolatedModules;
}
function shouldEmitVarForEnumDeclaration(node: EnumDeclaration | ModuleDeclaration) {
return !hasModifier(node, ModifierFlags.Export)
|| (isES6ExportedDeclaration(node) && isFirstDeclarationOfKind(node, node.kind));
}
/**
* Adds a leading VariableStatement for an enum or module declaration.
*/
function addVarForEnumOrModuleDeclaration(statements: Statement[], node: EnumDeclaration | ModuleDeclaration) {
function addVarForEnumDeclaration(statements: Statement[], node: EnumDeclaration) {
// Emit a variable statement for the enum.
statements.push(
createVariableStatement(
visitNodes(node.modifiers, visitor, isModifier),
isES6ExportedDeclaration(node)
? visitNodes(node.modifiers, visitor, isModifier)
: undefined,
[createVariableDeclaration(
getDeclarationName(node)
)],
@ -2186,7 +2205,7 @@ namespace ts {
/**
* Adds a trailing VariableStatement for an enum or module declaration.
*/
function addVarForEnumOrModuleExportedFromNamespace(statements: Statement[], node: EnumDeclaration | ModuleDeclaration) {
function addVarForEnumExportedFromNamespace(statements: Statement[], node: EnumDeclaration | ModuleDeclaration) {
statements.push(
createVariableStatement(
/*modifiers*/ undefined,
@ -2199,34 +2218,6 @@ namespace ts {
)
}
function addAssignmentForModuleExportedFromNamespace(statements: Statement[], node: ModuleDeclaration) {
statements.push(
createStatement(
createAssignment(
getDeclarationName(node),
setNodeEmitFlags(getDeclarationName(node), NodeEmitFlags.PrefixExportedLocal)
),
/*location*/ node
)
);
}
/**
* Determines whether to emit an enum declaration.
*
* @param node The enum declaration node.
*/
function shouldEmitEnumDeclaration(node: EnumDeclaration) {
return !isConst(node)
|| compilerOptions.preserveConstEnums
|| compilerOptions.isolatedModules;
}
function shouldEmitVarForEnumOrModuleDeclaration(node: EnumDeclaration | ModuleDeclaration) {
return !hasModifier(node, ModifierFlags.Export)
|| (isExternalModuleExport(node) && isFirstDeclarationOfKind(node, node.kind));
}
/**
* Visits an enum declaration.
*
@ -2240,8 +2231,8 @@ namespace ts {
}
const statements: Statement[] = [];
if (shouldEmitVarForEnumOrModuleDeclaration(node)) {
addVarForEnumOrModuleDeclaration(statements, node);
if (shouldEmitVarForEnumDeclaration(node)) {
addVarForEnumDeclaration(statements, node);
}
const localName = getGeneratedNameForNode(node);
@ -2276,7 +2267,7 @@ namespace ts {
);
if (isNamespaceExport(node)) {
addVarForEnumOrModuleExportedFromNamespace(statements, node);
addVarForEnumExportedFromNamespace(statements, node);
}
return statements;
@ -2357,6 +2348,38 @@ namespace ts {
&& isMergedWithClass(node);
}
function isES6ExportedDeclaration(node: Node) {
return isExternalModuleExport(node)
&& moduleKind >= ModuleKind.ES6;
}
function shouldEmitVarForModuleDeclaration(node: ModuleDeclaration) {
return !isModuleMergedWithES6Class(node)
&& (!isES6ExportedDeclaration(node)
|| isFirstDeclarationOfKind(node, node.kind));
}
/**
* Adds a leading VariableStatement for a module declaration.
*/
function addVarForModuleDeclaration(statements: Statement[], node: ModuleDeclaration) {
// Emit a variable statement for the module.
statements.push(
setOriginalNode(
createVariableStatement(
isES6ExportedDeclaration(node)
? visitNodes(node.modifiers, visitor, isModifier)
: undefined,
[createVariableDeclaration(
getDeclarationName(node)
)],
/*location*/ node
),
node
)
);
}
/**
* Visits a module declaration node.
*
@ -2373,8 +2396,9 @@ namespace ts {
enableExpressionSubstitutionForNamespaceExports();
const statements: Statement[] = [];
if (!isModuleMergedWithES6Class(node) && (isNamespaceExport(node) || shouldEmitVarForEnumOrModuleDeclaration(node))) {
addVarForEnumOrModuleDeclaration(statements, node);
if (shouldEmitVarForModuleDeclaration(node)) {
addVarForModuleDeclaration(statements, node);
}
const localName = getGeneratedNameForNode(node);
@ -2389,7 +2413,7 @@ namespace ts {
)
);
if (isNamespaceExport(node)) {
if (hasModifier(node, ModifierFlags.Export) && !isES6ExportedDeclaration(node)) {
moduleArg = createAssignment(getDeclarationName(node), moduleArg);
}