typescript: Fix enum emit when values are strings (#7160)

This commit is contained in:
Andy
2018-01-23 13:42:32 -08:00
committed by Brian Ng
parent 180eda3211
commit b96fdf8780
9 changed files with 77 additions and 12 deletions

View File

@@ -1,3 +1,5 @@
import assert from "assert";
export default function transpileEnum(path, t) {
const { node } = path;
if (node.declare) {
@@ -60,11 +62,13 @@ function enumFill(path, t, id) {
t.memberExpression(id, t.stringLiteral(memberName), /*computed*/ true),
memberValue,
);
const outer = t.assignmentExpression(
"=",
t.memberExpression(id, inner, /*computed*/ true),
t.stringLiteral(memberName),
);
const outer = t.isStringLiteral(memberValue)
? inner
: t.assignmentExpression(
"=",
t.memberExpression(id, inner, /*computed*/ true),
t.stringLiteral(memberName),
);
return t.expressionStatement(outer);
});
@@ -88,7 +92,7 @@ function enumFill(path, t, id) {
* Z = X | Y,
* }
*/
type PreviousEnumMembers = { [name: string]: number | typeof undefined };
type PreviousEnumMembers = { [name: string]: number | string };
function translateEnumValues(path, t) {
const seen: PreviousEnumMembers = Object.create(null);
@@ -101,8 +105,15 @@ function translateEnumValues(path, t) {
if (initializer) {
const constValue = evaluate(initializer, seen);
if (constValue !== undefined) {
value = t.numericLiteral(constValue);
prev = constValue;
seen[name] = constValue;
if (typeof constValue === "number") {
value = t.numericLiteral(constValue);
prev = constValue;
} else {
assert(typeof constValue === "string");
value = t.stringLiteral(constValue);
prev = undefined;
}
} else {
value = initializer;
prev = undefined;
@@ -111,6 +122,7 @@ function translateEnumValues(path, t) {
if (prev !== undefined) {
prev++;
value = t.numericLiteral(prev);
seen[name] = prev;
} else {
throw path.buildCodeFrameError("Enum member must have initializer.");
}
@@ -121,10 +133,16 @@ function translateEnumValues(path, t) {
}
// Based on the TypeScript repository's `evalConstant` in `checker.ts`.
function evaluate(expr, seen: PreviousEnumMembers) {
function evaluate(
expr,
seen: PreviousEnumMembers,
): number | string | typeof undefined {
if (expr.type === "StringLiteral") {
return expr.value;
}
return evalConstant(expr);
function evalConstant(expr) {
function evalConstant(expr): number | typeof undefined {
switch (expr.type) {
case "UnaryExpression":
return evalUnaryExpression(expr);
@@ -141,7 +159,10 @@ function evaluate(expr, seen: PreviousEnumMembers) {
}
}
function evalUnaryExpression({ argument, operator }) {
function evalUnaryExpression({
argument,
operator,
}): number | typeof undefined {
const value = evalConstant(argument);
if (value === undefined) {
return undefined;
@@ -159,7 +180,7 @@ function evaluate(expr, seen: PreviousEnumMembers) {
}
}
function evalBinaryExpression(expr) {
function evalBinaryExpression(expr): number | typeof undefined {
const left = evalConstant(expr.left);
if (left === undefined) {
return undefined;

View File

@@ -0,0 +1,4 @@
// Not type-correct code
enum E {
A = true
}

View File

@@ -0,0 +1,6 @@
// Not type-correct code
var E;
(function (E) {
E[E["A"] = true] = "A";
})(E || (E = {}));

View File

@@ -0,0 +1,4 @@
enum E {
a = 10,
b = a,
}

View File

@@ -0,0 +1,6 @@
var E;
(function (E) {
E[E["a"] = 10] = "a";
E[E["b"] = 10] = "b";
})(E || (E = {}));

View File

@@ -0,0 +1,4 @@
// Not type-correct code
enum E {
A = "HALLO" + "WERLD"
}

View File

@@ -0,0 +1,6 @@
// Not type-correct code
var E;
(function (E) {
E[E["A"] = "HALLO" + "WERLD"] = "A";
})(E || (E = {}));

View File

@@ -0,0 +1,6 @@
enum E {
A = 0,
B = "",
A2 = A,
B2 = B,
}

View File

@@ -0,0 +1,8 @@
var E;
(function (E) {
E[E["A"] = 0] = "A";
E["B"] = "";
E[E["A2"] = 0] = "A2";
E["B2"] = "";
})(E || (E = {}));