diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index eae769fd562..ef908c40a9b 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -213,7 +213,7 @@ namespace ts { return name; } - export function createGeneratedNameForNode(node: Node, location?: TextRange): Identifier { + export function getGeneratedNameForNode(node: Node, location?: TextRange): Identifier { const name = createNode(SyntaxKind.Identifier, location); name.autoGenerateKind = GeneratedIdentifierKind.Node; name.original = node; diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index d791dd1eb4c..e672a0a79cd 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -8,8 +8,6 @@ namespace ts { export function transformTypeScript(context: TransformationContext) { const { - getGeneratedNameForNode, - makeUniqueName, setNodeEmitFlags, startLexicalEnvironment, endLexicalEnvironment, @@ -496,7 +494,7 @@ namespace ts { // Record an alias to avoid class double-binding. if (resolver.getNodeCheckFlags(getOriginalNode(node)) & NodeCheckFlags.ClassWithBodyScopedClassBinding) { enableExpressionSubstitutionForDecoratedClasses(); - decoratedClassAlias = makeUniqueName(node.name ? node.name.text : "default"); + decoratedClassAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? node.name.text : "default"); decoratedClassAliases[getOriginalNodeId(node)] = decoratedClassAlias; // We emit the class alias as a `let` declaration here so that it has the same @@ -691,7 +689,7 @@ namespace ts { function transformConstructorParameters(constructor: ConstructorDeclaration, hasExtendsClause: boolean) { return constructor ? visitNodes(constructor.parameters, visitor, isParameter) - : hasExtendsClause ? [createRestParameter(makeUniqueName("args"))] : []; + : hasExtendsClause ? [createRestParameter(createUniqueName("args"))] : []; } /** @@ -2103,14 +2101,15 @@ namespace ts { } const savedCurrentNamespaceLocalName = currentNamespaceLocalName; - const modifiers = visitNodes(node.modifiers, visitor, isModifier); const statements: Statement[] = []; let location: TextRange = node; - if (!isNamespaceExport(node)) { + if (!isExported(node) || (isExternalModuleExport(node) && isFirstDeclarationOfKind(node, SyntaxKind.EnumDeclaration))) { + // Emit a VariableStatement if the enum is not exported, or is the first enum + // with the same name exported from an external module. addNode(statements, createVariableStatement( - modifiers, + visitNodes(node.modifiers, visitor, isModifier), createVariableDeclarationList([ createVariableDeclaration(node.name) ]), @@ -2179,7 +2178,7 @@ namespace ts { * * @param member The enum member node. */ - function transformEnumMember(member: EnumMember) { + function transformEnumMember(member: EnumMember): Statement { const name = getExpressionForPropertyName(member); return createStatement( createAssignment( @@ -2443,14 +2442,31 @@ namespace ts { && (isExternalModule(currentSourceFile) || !resolver.isTopLevelValueImportEqualsWithEntityName(node)); } + /** + * Gets a value indicating whether the node is exported. + * + * @param node The node to test. + */ + function isExported(node: Node) { + return (node.flags & NodeFlags.Export) !== 0; + } + + /** + * Gets a value indicating whether the node is exported from a namespace. + * + * @param node The node to test. + */ + function isNamespaceExport(node: Node) { + return currentNamespace !== undefined && isExported(node); + } + /** * Gets a value indicating whether the node is exported from an external module. * * @param node The node to test. */ function isExternalModuleExport(node: Node) { - return currentNamespace === undefined - && (node.flags & NodeFlags.Export) !== 0; + return currentNamespace === undefined && isExported(node); } /** @@ -2473,14 +2489,9 @@ namespace ts { && (node.flags & NodeFlags.Default) !== 0; } - /** - * Gets a value indicating whether the node is exported from a namespace. - * - * @param node The node to test. - */ - function isNamespaceExport(node: Node) { - return currentNamespace !== undefined - && (node.flags & NodeFlags.Export) !== 0; + function isFirstDeclarationOfKind(node: Declaration, kind: SyntaxKind) { + const original = getOriginalNode(node); + return !forEach(original.symbol && original.symbol.declarations, declaration => declaration.kind === kind && declaration.pos < original.pos); } /** diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b700498cd4d..1b707cedc48 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2865,6 +2865,10 @@ namespace ts { return node.kind === SyntaxKind.Identifier; } + export function isGeneratedIdentifier(node: Node): node is Identifier { + return isIdentifier(node) && node.autoGenerateKind > GeneratedIdentifierKind.Node; + } + // Keywords export function isModifier(node: Node): node is Modifier {