From b96fdf878058ba77f05fe4b8cb9e1e05a8b5c6b6 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 23 Jan 2018 13:42:32 -0800 Subject: [PATCH] typescript: Fix enum emit when values are strings (#7160) --- .../src/enum.js | 45 ++++++++++++++----- .../fixtures/enum/boolean-value/actual.js | 4 ++ .../fixtures/enum/boolean-value/expected.js | 6 +++ .../fixtures/enum/inner-references/actual.js | 4 ++ .../enum/inner-references/expected.js | 6 +++ .../enum/string-values-computed/actual.js | 4 ++ .../enum/string-values-computed/expected.js | 6 +++ .../fixtures/enum/string-values/actual.js | 6 +++ .../fixtures/enum/string-values/expected.js | 8 ++++ 9 files changed, 77 insertions(+), 12 deletions(-) create mode 100644 packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/actual.js create mode 100644 packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/expected.js create mode 100644 packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/actual.js create mode 100644 packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/expected.js create mode 100644 packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values-computed/actual.js create mode 100644 packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values-computed/expected.js create mode 100644 packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values/actual.js create mode 100644 packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values/expected.js diff --git a/packages/babel-plugin-transform-typescript/src/enum.js b/packages/babel-plugin-transform-typescript/src/enum.js index 23ae6d0077..8db9a0fa62 100644 --- a/packages/babel-plugin-transform-typescript/src/enum.js +++ b/packages/babel-plugin-transform-typescript/src/enum.js @@ -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; diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/actual.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/actual.js new file mode 100644 index 0000000000..5035e4c506 --- /dev/null +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/actual.js @@ -0,0 +1,4 @@ +// Not type-correct code +enum E { + A = true +} diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/expected.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/expected.js new file mode 100644 index 0000000000..8851c166a8 --- /dev/null +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/expected.js @@ -0,0 +1,6 @@ +// Not type-correct code +var E; + +(function (E) { + E[E["A"] = true] = "A"; +})(E || (E = {})); diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/actual.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/actual.js new file mode 100644 index 0000000000..a1c955ff09 --- /dev/null +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/actual.js @@ -0,0 +1,4 @@ +enum E { + a = 10, + b = a, +} diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/expected.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/expected.js new file mode 100644 index 0000000000..a574edf3f5 --- /dev/null +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/expected.js @@ -0,0 +1,6 @@ +var E; + +(function (E) { + E[E["a"] = 10] = "a"; + E[E["b"] = 10] = "b"; +})(E || (E = {})); diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values-computed/actual.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values-computed/actual.js new file mode 100644 index 0000000000..ac52806fb9 --- /dev/null +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values-computed/actual.js @@ -0,0 +1,4 @@ +// Not type-correct code +enum E { + A = "HALLO" + "WERLD" +} diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values-computed/expected.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values-computed/expected.js new file mode 100644 index 0000000000..e449a1ca23 --- /dev/null +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values-computed/expected.js @@ -0,0 +1,6 @@ +// Not type-correct code +var E; + +(function (E) { + E[E["A"] = "HALLO" + "WERLD"] = "A"; +})(E || (E = {})); diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values/actual.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values/actual.js new file mode 100644 index 0000000000..7846366968 --- /dev/null +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values/actual.js @@ -0,0 +1,6 @@ +enum E { + A = 0, + B = "", + A2 = A, + B2 = B, +} diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values/expected.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values/expected.js new file mode 100644 index 0000000000..338c292664 --- /dev/null +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values/expected.js @@ -0,0 +1,8 @@ +var E; + +(function (E) { + E[E["A"] = 0] = "A"; + E["B"] = ""; + E[E["A2"] = 0] = "A2"; + E["B2"] = ""; +})(E || (E = {}));