From 1efd019dc1d0bdd0420ba5f713b715c81092d26a Mon Sep 17 00:00:00 2001 From: Mickey Rose Date: Wed, 20 Oct 2021 17:29:43 +0200 Subject: [PATCH 1/2] fix: allow enum member without initializer after non-literal member --- .../src/enum.ts | 30 +++++++++++-------- .../enum/non-foldable-constant/options.json | 3 -- .../enum/non-foldable-constant/output.js | 6 ++++ .../fixtures/enum/outer-references/input.ts | 13 ++++++++ .../fixtures/enum/outer-references/output.js | 17 +++++++++++ 5 files changed, 54 insertions(+), 15 deletions(-) delete mode 100644 packages/babel-plugin-transform-typescript/test/fixtures/enum/non-foldable-constant/options.json create mode 100644 packages/babel-plugin-transform-typescript/test/fixtures/enum/non-foldable-constant/output.js create mode 100644 packages/babel-plugin-transform-typescript/test/fixtures/enum/outer-references/input.ts create mode 100644 packages/babel-plugin-transform-typescript/test/fixtures/enum/outer-references/output.js diff --git a/packages/babel-plugin-transform-typescript/src/enum.ts b/packages/babel-plugin-transform-typescript/src/enum.ts index 3cc49ba12776..bee7ef9537f1 100644 --- a/packages/babel-plugin-transform-typescript/src/enum.ts +++ b/packages/babel-plugin-transform-typescript/src/enum.ts @@ -108,37 +108,43 @@ export function translateEnumValues( ): Array<[name: string, value: t.Expression]> { const seen: PreviousEnumMembers = Object.create(null); // 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; 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 (typeof constValue === "number") { + constValue += 1; + value = t.numericLiteral(constValue); + seen[name] = constValue; + } else if (typeof constValue === "string") { + throw path.buildCodeFrameError("Enum member must have initializer."); } else { - if (prev !== undefined) { - prev++; - value = t.numericLiteral(prev); - seen[name] = prev; - } else { - throw path.buildCodeFrameError("Enum member must have initializer."); - } + // 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]; }); } diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-foldable-constant/options.json b/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-foldable-constant/options.json deleted file mode 100644 index f0cc17142b58..000000000000 --- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-foldable-constant/options.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "throws": "Enum member must have initializer." -} diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-foldable-constant/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-foldable-constant/output.js new file mode 100644 index 000000000000..90d6e1087ef8 --- /dev/null +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-foldable-constant/output.js @@ -0,0 +1,6 @@ +var E; + +(function (E) { + E[E["a"] = Math.sin(1)] = "a"; + E[E["b"] = 1 + E["a"]] = "b"; +})(E || (E = {})); diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/outer-references/input.ts b/packages/babel-plugin-transform-typescript/test/fixtures/enum/outer-references/input.ts new file mode 100644 index 000000000000..25fb6d7b0769 --- /dev/null +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/outer-references/input.ts @@ -0,0 +1,13 @@ +enum socketType { + SOCKET, + SERVER, + IPC, +} + +enum constants { + SOCKET = socketType.SOCKET, + SERVER = socketType.SERVER, + IPC = socketType.IPC, + UV_READABLE, + UV_WRITABLE, +} diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/outer-references/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/outer-references/output.js new file mode 100644 index 000000000000..8e6616d8e88d --- /dev/null +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/outer-references/output.js @@ -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 = {})); From 7669065ba2104bf54c420665c6bfd25c2c144589 Mon Sep 17 00:00:00 2001 From: Mickey Rose Date: Fri, 22 Oct 2021 14:30:29 +0200 Subject: [PATCH 2/2] refactor: seen enum members Object -> Map --- .../babel-plugin-transform-typescript/src/enum.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/babel-plugin-transform-typescript/src/enum.ts b/packages/babel-plugin-transform-typescript/src/enum.ts index bee7ef9537f1..dc13399a80d7 100644 --- a/packages/babel-plugin-transform-typescript/src/enum.ts +++ b/packages/babel-plugin-transform-typescript/src/enum.ts @@ -98,15 +98,13 @@ function enumFill(path, t, id) { * Z = X | Y, * } */ -type PreviousEnumMembers = { - [name: string]: number | string; -}; +type PreviousEnumMembers = Map; export function translateEnumValues( path: NodePath, 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 constValue: number | string | undefined = -1; let lastName: string; @@ -118,7 +116,7 @@ export function translateEnumValues( if (initializer) { constValue = evaluate(initializer, seen); if (constValue !== undefined) { - seen[name] = constValue; + seen.set(name, constValue); if (typeof constValue === "number") { value = t.numericLiteral(constValue); } else { @@ -131,7 +129,7 @@ export function translateEnumValues( } else if (typeof constValue === "number") { constValue += 1; value = t.numericLiteral(constValue); - seen[name] = constValue; + seen.set(name, constValue); } else if (typeof constValue === "string") { throw path.buildCodeFrameError("Enum member must have initializer."); } else { @@ -169,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;