fix: allow enum member without initializer after non-literal member (#13865)

This commit is contained in:
Mickey Rose 2021-10-22 14:52:23 +02:00 committed by GitHub
parent c75fa21cb8
commit cfe6739dc0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 58 additions and 21 deletions

View File

@ -98,47 +98,51 @@ function enumFill(path, t, id) {
* Z = X | Y,
* }
*/
type PreviousEnumMembers = {
[name: string]: number | string;
};
type PreviousEnumMembers = Map<string, number | string>;
export function translateEnumValues(
path: NodePath<t.TSEnumDeclaration>,
t: typeof import("@babel/types"),
): Array<[name: string, value: t.Expression]> {
const seen: PreviousEnumMembers = Object.create(null);
const seen: PreviousEnumMembers = new Map();
// Start at -1 so the first enum member is its increment, 0.
let prev: number | typeof undefined = -1;
let constValue: number | string | undefined = -1;
let lastName: string;
return path.node.members.map(member => {
const name = t.isIdentifier(member.id) ? member.id.name : member.id.value;
const initializer = member.initializer;
let value: t.Expression;
if (initializer) {
const constValue = evaluate(initializer, seen);
constValue = evaluate(initializer, seen);
if (constValue !== undefined) {
seen[name] = constValue;
seen.set(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;
}
} else {
if (prev !== undefined) {
prev++;
value = t.numericLiteral(prev);
seen[name] = prev;
} else {
} else if (typeof constValue === "number") {
constValue += 1;
value = t.numericLiteral(constValue);
seen.set(name, constValue);
} else if (typeof constValue === "string") {
throw path.buildCodeFrameError("Enum member must have initializer.");
}
} else {
// create dynamic initializer: 1 + ENUM["PREVIOUS"]
const lastRef = t.memberExpression(
t.cloneNode(path.node.id),
t.stringLiteral(lastName),
true,
);
value = t.binaryExpression("+", t.numericLiteral(1), lastRef);
}
lastName = name;
return [name, value];
});
}
@ -163,7 +167,7 @@ function evaluate(
case "ParenthesizedExpression":
return evalConstant(expr.expression);
case "Identifier":
return seen[expr.name];
return seen.get(expr.name);
case "TemplateLiteral":
if (expr.quasis.length === 1) {
return expr.quasis[0].value.cooked;

View File

@ -1,3 +0,0 @@
{
"throws": "Enum member must have initializer."
}

View File

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

View File

@ -0,0 +1,13 @@
enum socketType {
SOCKET,
SERVER,
IPC,
}
enum constants {
SOCKET = socketType.SOCKET,
SERVER = socketType.SERVER,
IPC = socketType.IPC,
UV_READABLE,
UV_WRITABLE,
}

View File

@ -0,0 +1,17 @@
var socketType;
(function (socketType) {
socketType[socketType["SOCKET"] = 0] = "SOCKET";
socketType[socketType["SERVER"] = 1] = "SERVER";
socketType[socketType["IPC"] = 2] = "IPC";
})(socketType || (socketType = {}));
var constants;
(function (constants) {
constants[constants["SOCKET"] = socketType.SOCKET] = "SOCKET";
constants[constants["SERVER"] = socketType.SERVER] = "SERVER";
constants[constants["IPC"] = socketType.IPC] = "IPC";
constants[constants["UV_READABLE"] = 1 + constants["IPC"]] = "UV_READABLE";
constants[constants["UV_WRITABLE"] = 1 + constants["UV_READABLE"]] = "UV_WRITABLE";
})(constants || (constants = {}));