emit unqualified enum members as qualified

This commit is contained in:
Vladimir Matveev 2016-04-06 23:49:14 -07:00
parent 1317d23a8a
commit 0e0182c1ea
4 changed files with 85 additions and 27 deletions

View file

@ -13,6 +13,8 @@ namespace ts {
NamespaceExports = 1 << 1, NamespaceExports = 1 << 1,
/** Enables substitutions for async methods with `super` calls. */ /** Enables substitutions for async methods with `super` calls. */
AsyncMethodsWithSuper = 1 << 2, AsyncMethodsWithSuper = 1 << 2,
/* Enables substitutions for unqualified enum members */
NonQualifiedEnumMembers = 1 << 3
} }
export function transformTypeScript(context: TransformationContext) { export function transformTypeScript(context: TransformationContext) {
@ -65,7 +67,7 @@ namespace ts {
* Keeps track of whether we are within any containing namespaces when performing * Keeps track of whether we are within any containing namespaces when performing
* just-in-time substitution while printing an expression identifier. * just-in-time substitution while printing an expression identifier.
*/ */
let isEnclosedInNamespace: boolean; let applicableSubstitutions: TypeScriptSubstitutionFlags;
/** /**
* This keeps track of containers where `super` is valid, for use with * This keeps track of containers where `super` is valid, for use with
@ -2234,6 +2236,7 @@ namespace ts {
// ... // ...
// })(x || (x = {})); // })(x || (x = {}));
statements.push( statements.push(
setNodeEmitFlags(
setOriginalNode( setOriginalNode(
createStatement( createStatement(
createCall( createCall(
@ -2254,6 +2257,8 @@ namespace ts {
/*location*/ node /*location*/ node
), ),
/*original*/ node /*original*/ node
),
NodeEmitFlags.AdviseOnEmitNode
) )
); );
@ -2317,13 +2322,16 @@ namespace ts {
if (value !== undefined) { if (value !== undefined) {
return createLiteral(value); return createLiteral(value);
} }
else if (member.initializer) { else {
enableSubstitutionForNonQualifiedEnumMembers();
if (member.initializer) {
return visitNode(member.initializer, visitor, isExpression); return visitNode(member.initializer, visitor, isExpression);
} }
else { else {
return createVoidZero(); return createVoidZero();
} }
} }
}
/** /**
* Determines whether to elide a module declaration. * Determines whether to elide a module declaration.
@ -2634,8 +2642,12 @@ namespace ts {
return getOriginalNode(node).kind === SyntaxKind.ModuleDeclaration; return getOriginalNode(node).kind === SyntaxKind.ModuleDeclaration;
} }
function isTransformedEnumDeclaration(node: Node): boolean {
return getOriginalNode(node).kind === SyntaxKind.EnumDeclaration;
}
function onEmitNode(node: Node, emit: (node: Node) => void): void { function onEmitNode(node: Node, emit: (node: Node) => void): void {
const savedIsEnclosedInNamespace = isEnclosedInNamespace; const savedApplicableSubstitutions = applicableSubstitutions;
const savedCurrentSuperContainer = currentSuperContainer; const savedCurrentSuperContainer = currentSuperContainer;
// If we need support substitutions for aliases for decorated classes, // If we need support substitutions for aliases for decorated classes,
@ -2651,7 +2663,10 @@ namespace ts {
} }
if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && isTransformedModuleDeclaration(node)) { if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && isTransformedModuleDeclaration(node)) {
isEnclosedInNamespace = true; applicableSubstitutions |= TypeScriptSubstitutionFlags.NamespaceExports;
}
if (enabledSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && isTransformedEnumDeclaration(node)) {
applicableSubstitutions |= TypeScriptSubstitutionFlags.NonQualifiedEnumMembers;
} }
previousOnEmitNode(node, emit); previousOnEmitNode(node, emit);
@ -2660,7 +2675,7 @@ namespace ts {
currentDecoratedClassAliases[getOriginalNodeId(node)] = undefined; currentDecoratedClassAliases[getOriginalNodeId(node)] = undefined;
} }
isEnclosedInNamespace = savedIsEnclosedInNamespace; applicableSubstitutions = savedApplicableSubstitutions;
currentSuperContainer = savedCurrentSuperContainer; currentSuperContainer = savedCurrentSuperContainer;
} }
@ -2705,18 +2720,22 @@ namespace ts {
} }
} }
if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && isEnclosedInNamespace) { if (enabledSubstitutions & applicableSubstitutions) {
// If we are nested within a namespace declaration, we may need to qualifiy // If we are nested within a namespace declaration, we may need to qualifiy
// an identifier that is exported from a merged namespace. // an identifier that is exported from a merged namespace.
const original = getOriginalNode(node); const original = getOriginalNode(node);
if (isIdentifier(original) && original.parent) { if (isIdentifier(original) && original.parent) {
const container = resolver.getReferencedExportContainer(original); const container = resolver.getReferencedExportContainer(original);
if (container && container.kind === SyntaxKind.ModuleDeclaration) { if (container) {
const substitute =
(applicableSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && container.kind === SyntaxKind.ModuleDeclaration) ||
(applicableSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && container.kind === SyntaxKind.EnumDeclaration);
if (substitute) {
return createPropertyAccess(getGeneratedNameForNode(container), node, /*location*/ node); return createPropertyAccess(getGeneratedNameForNode(container), node, /*location*/ node);
} }
} }
} }
}
return node; return node;
} }
@ -2770,6 +2789,13 @@ namespace ts {
return node; return node;
} }
function enableSubstitutionForNonQualifiedEnumMembers() {
if ((enabledSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers) === 0) {
enabledSubstitutions |= TypeScriptSubstitutionFlags.NonQualifiedEnumMembers;
context.enableExpressionSubstitution(SyntaxKind.Identifier);
}
}
function enableExpressionSubstitutionForAsyncMethodsWithSuper() { function enableExpressionSubstitutionForAsyncMethodsWithSuper() {
if ((enabledSubstitutions & TypeScriptSubstitutionFlags.AsyncMethodsWithSuper) === 0) { if ((enabledSubstitutions & TypeScriptSubstitutionFlags.AsyncMethodsWithSuper) === 0) {
enabledSubstitutions |= TypeScriptSubstitutionFlags.AsyncMethodsWithSuper; enabledSubstitutions |= TypeScriptSubstitutionFlags.AsyncMethodsWithSuper;

View file

@ -0,0 +1,12 @@
tests/cases/compiler/enumWithComputedMember.ts(4,5): error TS1061: Enum member must have initializer.
==== tests/cases/compiler/enumWithComputedMember.ts (1 errors) ====
enum A {
X = "".length,
Y = X,
Z
~
!!! error TS1061: Enum member must have initializer.
}

View file

@ -0,0 +1,15 @@
//// [enumWithComputedMember.ts]
enum A {
X = "".length,
Y = X,
Z
}
//// [enumWithComputedMember.js]
var A;
(function (A) {
A[A["X"] = "".length] = "X";
A[A["Y"] = A.X] = "Y";
A[A["Z"] = void 0] = "Z";
})(A || (A = {}));

View file

@ -0,0 +1,5 @@
enum A {
X = "".length,
Y = X,
Z
}