Skip to content

Commit d647f89

Browse files
committed
Fix emit for modules and enums.
1 parent 36257ec commit d647f89

7 files changed

Lines changed: 401 additions & 277 deletions

File tree

src/compiler/checker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16076,15 +16076,15 @@ namespace ts {
1607616076

1607716077
// When resolved as an expression identifier, if the given node references an exported entity, return the declaration
1607816078
// node of the exported entity's container. Otherwise, return undefined.
16079-
function getReferencedExportContainer(node: Identifier): SourceFile | ModuleDeclaration | EnumDeclaration {
16079+
function getReferencedExportContainer(node: Identifier, prefixLocals?: boolean): SourceFile | ModuleDeclaration | EnumDeclaration {
1608016080
let symbol = getReferencedValueSymbol(node);
1608116081
if (symbol) {
1608216082
if (symbol.flags & SymbolFlags.ExportValue) {
1608316083
// If we reference an exported entity within the same module declaration, then whether
1608416084
// we prefix depends on the kind of entity. SymbolFlags.ExportHasLocal encompasses all the
1608516085
// kinds that we do NOT prefix.
1608616086
const exportSymbol = getMergedSymbol(symbol.exportSymbol);
16087-
if (exportSymbol.flags & SymbolFlags.ExportHasLocal) {
16087+
if (exportSymbol.flags & SymbolFlags.ExportHasLocal && !prefixLocals) {
1608816088
return undefined;
1608916089
}
1609016090
symbol = exportSymbol;

src/compiler/transformers/module/module.ts

Lines changed: 106 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,9 @@ namespace ts {
258258
case SyntaxKind.ClassDeclaration:
259259
return visitClassDeclaration(<ClassDeclaration>node);
260260

261+
case SyntaxKind.ExpressionStatement:
262+
return visitExpressionStatement(<ExpressionStatement>node);
263+
261264
default:
262265
// This visitor does not descend into the tree, as export/import statements
263266
// are only transformed at the top level of a file.
@@ -544,24 +547,33 @@ namespace ts {
544547
}
545548
}
546549

547-
function addExportMemberAssignment(statements: Statement[], node: FunctionDeclaration | ClassDeclaration) {
550+
function addExportMemberAssignment(statements: Statement[], node: DeclarationStatement) {
548551
if (hasModifier(node, ModifierFlags.Default)) {
549-
addExportDefault(statements, node.name ? getSynthesizedClone(node.name) : getGeneratedNameForNode(node), /*location*/ node);
552+
addExportDefault(statements, getDeclarationName(node), /*location*/ node);
550553
}
551554
else {
552555
statements.push(
553-
startOnNewLine(
554-
createStatement(
555-
createExportAssignment(node.name, node.name),
556-
/*location*/ node
557-
)
558-
)
556+
createExportStatement(node.name, node.name, /*location*/ node)
559557
);
560558
}
561559
}
562560

563561
function visitVariableStatement(node: VariableStatement): VisitResult<Statement> {
564562
if (hasModifier(node, ModifierFlags.Export)) {
563+
// If the variable is for a declaration that has a local name,
564+
// do not elide the declaration.
565+
const original = getOriginalNode(node);
566+
if (original.kind === SyntaxKind.EnumDeclaration
567+
|| original.kind === SyntaxKind.ModuleDeclaration) {
568+
return setOriginalNode(
569+
createVariableStatement(
570+
/*modifiers*/ undefined,
571+
node.declarationList
572+
),
573+
node
574+
);
575+
}
576+
565577
const variables = getInitializedVariables(node.declarationList);
566578
if (variables.length === 0) {
567579
// elide statement if there are no initialized variables
@@ -651,6 +663,87 @@ namespace ts {
651663
return singleOrMany(statements);
652664
}
653665

666+
function visitExpressionStatement(node: ExpressionStatement): VisitResult<Statement> {
667+
const original = getOriginalNode(node);
668+
if (hasModifier(original, ModifierFlags.Export)) {
669+
switch (original.kind) {
670+
case SyntaxKind.EnumDeclaration:
671+
return visitExpressionStatementForEnumDeclaration(node, <EnumDeclaration>original);
672+
673+
case SyntaxKind.ModuleDeclaration:
674+
return visitExpressionStatementForModuleDeclaration(node, <ModuleDeclaration>original);
675+
}
676+
}
677+
678+
return node;
679+
}
680+
681+
function visitExpressionStatementForEnumDeclaration(node: ExpressionStatement, original: EnumDeclaration): VisitResult<Statement> {
682+
if (isFirstDeclarationOfKind(original, SyntaxKind.EnumDeclaration)) {
683+
const statements: Statement[] = [node];
684+
addVarForExportedEnumOrModule(statements, original);
685+
return statements;
686+
}
687+
688+
return node;
689+
}
690+
691+
function isModuleMergedWithES6Class(node: ModuleDeclaration) {
692+
return languageVersion === ScriptTarget.ES6
693+
&& isMergedWithClass(node);
694+
}
695+
696+
function visitExpressionStatementForModuleDeclaration(node: ExpressionStatement, original: ModuleDeclaration): VisitResult<Statement> {
697+
if (isFirstDeclarationOfKind(original, SyntaxKind.ModuleDeclaration)) {
698+
const statements: Statement[] = [node];
699+
if (isModuleMergedWithES6Class(original)) {
700+
addAssignmentForExportedModule(statements, original);
701+
}
702+
else {
703+
addVarForExportedEnumOrModule(statements, original);
704+
}
705+
706+
return statements;
707+
}
708+
709+
return node;
710+
}
711+
712+
/**
713+
* Adds a trailing VariableStatement for an enum or module declaration.
714+
*/
715+
function addVarForExportedEnumOrModule(statements: Statement[], node: EnumDeclaration | ModuleDeclaration) {
716+
statements.push(
717+
createVariableStatement(
718+
/*modifiers*/ undefined,
719+
[createVariableDeclaration(
720+
getDeclarationName(node),
721+
createPropertyAccess(createIdentifier("exports"), getDeclarationName(node))
722+
)],
723+
/*location*/ node
724+
)
725+
);
726+
}
727+
728+
/**
729+
* Adds a trailing assignment for a module declaration.
730+
*/
731+
function addAssignmentForExportedModule(statements: Statement[], node: ModuleDeclaration) {
732+
statements.push(
733+
createStatement(
734+
createAssignment(
735+
getDeclarationName(node),
736+
createPropertyAccess(createIdentifier("exports"), getDeclarationName(node))
737+
),
738+
/*location*/ node
739+
)
740+
);
741+
}
742+
743+
function getDeclarationName(node: DeclarationStatement) {
744+
return node.name ? getSynthesizedClone(node.name) : getGeneratedNameForNode(node);
745+
}
746+
654747
function substituteExpression(node: Expression) {
655748
node = previousExpressionSubstitution(node);
656749
if (isIdentifier(node)) {
@@ -663,7 +756,7 @@ namespace ts {
663756
function substituteExpressionIdentifier(node: Identifier): Expression {
664757
const original = getOriginalNode(node);
665758
if (isIdentifier(original)) {
666-
const container = resolver.getReferencedExportContainer(original);
759+
const container = resolver.getReferencedExportContainer(original, (getNodeEmitFlags(node) & NodeEmitFlags.PrefixExportedLocal) !== 0);
667760
if (container) {
668761
if (container.kind === SyntaxKind.SourceFile) {
669762
return createPropertyAccess(
@@ -760,6 +853,10 @@ namespace ts {
760853
return createCall(createIdentifier("require"), args);
761854
}
762855

856+
function createExportStatement(name: Identifier, value: Expression, location?: TextRange) {
857+
return startOnNewLine(createStatement(createExportAssignment(name, value), location));
858+
}
859+
763860
function createExportAssignment(name: Identifier, value: Expression) {
764861
return createAssignment(
765862
name.originalKeywordKind && languageVersion === ScriptTarget.ES3

0 commit comments

Comments
 (0)