typescript: Fix enum emit when values are strings (#7160)
This commit is contained in:
@@ -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;
|
||||
|
||||
4
packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/actual.js
vendored
Normal file
4
packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/actual.js
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
// Not type-correct code
|
||||
enum E {
|
||||
A = true
|
||||
}
|
||||
6
packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/expected.js
vendored
Normal file
6
packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/expected.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
// Not type-correct code
|
||||
var E;
|
||||
|
||||
(function (E) {
|
||||
E[E["A"] = true] = "A";
|
||||
})(E || (E = {}));
|
||||
4
packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/actual.js
vendored
Normal file
4
packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/actual.js
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
enum E {
|
||||
a = 10,
|
||||
b = a,
|
||||
}
|
||||
6
packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/expected.js
vendored
Normal file
6
packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/expected.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
var E;
|
||||
|
||||
(function (E) {
|
||||
E[E["a"] = 10] = "a";
|
||||
E[E["b"] = 10] = "b";
|
||||
})(E || (E = {}));
|
||||
@@ -0,0 +1,4 @@
|
||||
// Not type-correct code
|
||||
enum E {
|
||||
A = "HALLO" + "WERLD"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// Not type-correct code
|
||||
var E;
|
||||
|
||||
(function (E) {
|
||||
E[E["A"] = "HALLO" + "WERLD"] = "A";
|
||||
})(E || (E = {}));
|
||||
6
packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values/actual.js
vendored
Normal file
6
packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values/actual.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
enum E {
|
||||
A = 0,
|
||||
B = "",
|
||||
A2 = A,
|
||||
B2 = B,
|
||||
}
|
||||
8
packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values/expected.js
vendored
Normal file
8
packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values/expected.js
vendored
Normal 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 = {}));
|
||||
Reference in New Issue
Block a user