diff --git a/packages/babel-plugin-transform-typescript/src/enum.ts b/packages/babel-plugin-transform-typescript/src/enum.ts index 8cb9351df3f9..419b8724879f 100644 --- a/packages/babel-plugin-transform-typescript/src/enum.ts +++ b/packages/babel-plugin-transform-typescript/src/enum.ts @@ -6,6 +6,21 @@ type t = typeof t; const ENUMS = new WeakMap(); +const buildEnumWrapper = template.statement(` + (function (ID) { + ASSIGNMENTS; + })(ID || (ID = {})); +`); + +const buildPureEnumWrapper = template.expression( + ` + /*#__PURE__*/(function (ID) { + ASSIGNMENTS; + })(ID || {}) +`, + { preserveComments: true }, +); + export default function transpileEnum( path: NodePath, t: t, @@ -18,24 +33,50 @@ export default function transpileEnum( } const name = node.id.name; - const { wrapper: fill, data } = enumFill(path, t, node.id); + const { fill, data, isPure } = enumFill(path, t, node.id); switch (path.parent.type) { case "BlockStatement": case "ExportNamedDeclaration": case "Program": { - path.insertAfter(fill); - if (seen(path.parentPath)) { - path.remove(); + // todo: Consider exclude program with import/export + // && !path.parent.body.some(n => t.isImportDeclaration(n) || t.isExportDeclaration(n)); + const isGlobal = t.isProgram(path.parent); + + if (isPure && isGlobal) { + if (seen(path.parentPath)) { + path.replaceWith( + t.assignmentExpression( + "=", + t.cloneNode(node.id), + buildPureEnumWrapper(fill), + ), + ); + } else { + path.scope.registerDeclaration( + path.replaceWith( + t.variableDeclaration("var", [ + t.variableDeclarator(node.id, buildPureEnumWrapper(fill)), + ]), + )[0], + ); + } } else { - // todo: Consider exclude program with import/export - // && !path.parent.body.some(n => t.isImportDeclaration(n) || t.isExportDeclaration(n)); - const isGlobal = t.isProgram(path.parent); - path.scope.registerDeclaration( - path.replaceWith(makeVar(node.id, t, isGlobal ? "var" : "let"))[0], - ); - ENUMS.set(path.scope.getBindingIdentifier(name), data); + path.insertAfter(buildEnumWrapper(fill)); + + if (seen(path.parentPath)) { + path.remove(); + } else { + path.scope.registerDeclaration( + path.replaceWith( + t.variableDeclaration(isGlobal ? "var" : "let", [ + t.variableDeclarator(node.id), + ]), + )[0], + ); + } } + ENUMS.set(path.scope.getBindingIdentifier(name), data); break; } @@ -57,16 +98,6 @@ export default function transpileEnum( } } -function makeVar(id: t.Identifier, t: t, kind: "var" | "let" | "const") { - return t.variableDeclaration(kind, [t.variableDeclarator(id)]); -} - -const buildEnumWrapper = template(` - (function (ID) { - ASSIGNMENTS; - })(ID || (ID = {})); -`); - const buildStringAssignment = template(` ENUM["NAME"] = VALUE; `); @@ -83,7 +114,7 @@ const buildEnumMember = (isString: boolean, options: Record) => * `(function (E) { ... assignments ... })(E || (E = {}));` */ function enumFill(path: NodePath, t: t, id: t.Identifier) { - const { enumValues: x, data } = translateEnumValues(path, t); + const { enumValues: x, data, isPure } = translateEnumValues(path, t); const assignments = x.map(([memberName, memberValue]) => buildEnumMember(t.isStringLiteral(memberValue), { ENUM: t.cloneNode(id), @@ -93,11 +124,12 @@ function enumFill(path: NodePath, t: t, id: t.Identifier) { ); return { - wrapper: buildEnumWrapper({ + fill: { ID: t.cloneNode(id), ASSIGNMENTS: assignments, - }), - data: data, + }, + data, + isPure, }; } @@ -141,10 +173,11 @@ export function translateEnumValues(path: NodePath, t: t) { // Start at -1 so the first enum member is its increment, 0. let constValue: number | string | undefined = -1; let lastName: string; + let isPure = true; - return { - data: seen, - enumValues: path.get("members").map(memberPath => { + const enumValues: Array<[name: string, value: t.Expression]> = path + .get("members") + .map(memberPath => { const member = memberPath.node; const name = t.isIdentifier(member.id) ? member.id.name : member.id.value; const initializerPath = memberPath.get("initializer"); @@ -161,6 +194,10 @@ export function translateEnumValues(path: NodePath, t: t) { value = t.stringLiteral(constValue); } } else { + if (isPure && !initializerPath.isPure()) { + isPure = false; + } + if (initializerPath.isReferencedIdentifier()) { ReferencedIdentifier(initializerPath, { t, @@ -197,7 +234,12 @@ export function translateEnumValues(path: NodePath, t: t) { lastName = name; return [name, value]; - }) as Array<[name: string, value: t.Expression]>, + }); + + return { + isPure, + data: seen, + enumValues, }; } diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/output.js index c7a36e337c4e..60af8407925f 100644 --- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/output.js +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/boolean-value/output.js @@ -1,5 +1,4 @@ // Not type-correct code -var E; -(function (E) { +var E = /*#__PURE__*/function (E) { E[E["A"] = true] = "A"; -})(E || (E = {})); +}(E || {}); diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/const/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/const/output.js index a4e1cb2fe6a4..0c3fe5fcf1e0 100644 --- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/const/output.js +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/const/output.js @@ -1,3 +1,2 @@ // With --isolatedModules, TSC ignores the "const" modifier when compiling enums -var E; -(function (E) {})(E || (E = {})); +var E = /*#__PURE__*/function (E) {}(E || {}); diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/constant-folding/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/constant-folding/output.js index 4f53c5fd8b6a..b679e8bdb1e2 100644 --- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/constant-folding/output.js +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/constant-folding/output.js @@ -1,5 +1,4 @@ -var E; -(function (E) { +var E = /*#__PURE__*/function (E) { E[E["a"] = 0] = "a"; E[E["b"] = 3] = "b"; E[E["c"] = 1] = "c"; @@ -18,4 +17,4 @@ var E; E[E["p"] = -3] = "p"; E[E["q"] = 5.4] = "q"; E[E["r"] = 6.4] = "r"; -})(E || (E = {})); +}(E || {}); diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/inferred/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/inferred/output.js index 08295f526d48..8a848ea7aae2 100644 --- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/inferred/output.js +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/inferred/output.js @@ -1,5 +1,4 @@ -var E; -(function (E) { +var E = /*#__PURE__*/function (E) { E[E["x"] = 0] = "x"; E[E["y"] = 1] = "y"; -})(E || (E = {})); +}(E || {}); diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/output.js index ba1d6a55e157..5b066c809ef6 100644 --- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/output.js +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/inner-references/output.js @@ -1,5 +1,4 @@ -var E; -(function (E) { +var E = /*#__PURE__*/function (E) { E[E["a"] = 10] = "a"; E[E["b"] = 10] = "b"; -})(E || (E = {})); +}(E || {}); diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/mix-references/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/mix-references/output.js index 7ac74a98f5d4..ba6ba58df2c3 100644 --- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/mix-references/output.js +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/mix-references/output.js @@ -1,10 +1,9 @@ var x = 10; -var Foo; -(function (Foo) { +var Foo = /*#__PURE__*/function (Foo) { Foo[Foo["a"] = 10] = "a"; Foo[Foo["b"] = 10] = "b"; Foo[Foo["c"] = 20] = "c"; -})(Foo || (Foo = {})); +}(Foo || {}); var Bar; (function (Bar) { Bar[Bar["D"] = 10] = "D"; diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-scoped/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-scoped/output.js index 886b2faa2894..42e71045ccd7 100644 --- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-scoped/output.js +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/non-scoped/output.js @@ -1,8 +1,7 @@ -var E; -(function (E) { +var E = /*#__PURE__*/function (E) { E[E["x"] = 1] = "x"; E[E["y"] = 2] = "y"; -})(E || (E = {})); -(function (E) { +}(E || {}); +E = /*#__PURE__*/function (E) { E[E["z"] = 3] = "z"; -})(E || (E = {})); +}(E || {}); 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 index f12f2500f92d..495ecad2be6b 100644 --- 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 @@ -1,14 +1,12 @@ -var socketType; -(function (socketType) { +var socketType = /*#__PURE__*/function (socketType) { socketType[socketType["SOCKET"] = 0] = "SOCKET"; socketType[socketType["SERVER"] = 1] = "SERVER"; socketType[socketType["IPC"] = 2] = "IPC"; -})(socketType || (socketType = {})); -var constants; -(function (constants) { +}(socketType || {}); +var constants = /*#__PURE__*/function (constants) { constants[constants["SOCKET"] = 0] = "SOCKET"; constants[constants["SERVER"] = 1] = "SERVER"; constants[constants["IPC"] = 2] = "IPC"; constants[constants["UV_READABLE"] = 3] = "UV_READABLE"; constants[constants["UV_WRITABLE"] = 4] = "UV_WRITABLE"; -})(constants || (constants = {})); +}(constants || {}); diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value-template/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value-template/output.js index be926edbf829..9ba0c2fb06a2 100644 --- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value-template/output.js +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value-template/output.js @@ -1,4 +1,3 @@ -var E; -(function (E) { +var E = /*#__PURE__*/function (E) { E["A"] = "Hey"; -})(E || (E = {})); +}(E || {}); diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value/output.js index ebb05ab32c8c..c437618b7ddf 100644 --- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value/output.js +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-value/output.js @@ -1,7 +1,6 @@ -var E; -(function (E) { +var E = /*#__PURE__*/function (E) { E[E["A"] = 0] = "A"; E["B"] = ""; E[E["A2"] = 0] = "A2"; E["B2"] = ""; -})(E || (E = {})); +}(E || {}); diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values-computed/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values-computed/output.js index f9a627d43490..be9eddba884c 100644 --- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values-computed/output.js +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/string-values-computed/output.js @@ -1,4 +1,3 @@ -var E; -(function (E) { +var E = /*#__PURE__*/function (E) { E["A"] = "HALLOWERLD"; -})(E || (E = {})); +}(E || {}); diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/enum/ts5.0-const-foldable/output.js b/packages/babel-plugin-transform-typescript/test/fixtures/enum/ts5.0-const-foldable/output.js index e839254369de..66badb633164 100644 --- a/packages/babel-plugin-transform-typescript/test/fixtures/enum/ts5.0-const-foldable/output.js +++ b/packages/babel-plugin-transform-typescript/test/fixtures/enum/ts5.0-const-foldable/output.js @@ -2,18 +2,16 @@ const BaseValue = 10; const Prefix = "/data"; -var Values; // 12 -(function (Values) { +var Values = /*#__PURE__*/function (Values) { Values[Values["First"] = 10] = "First"; Values[Values["Second"] = 11] = "Second"; Values[Values["Third"] = 12] = "Third"; -})(Values || (Values = {})); +}(Values || {}); // 12 const xxx = 100 + Values.First; const yyy = xxx; -var Routes; -(function (Routes) { +var Routes = /*#__PURE__*/function (Routes) { Routes["Parts"] = "/data/parts"; Routes["Invoices"] = "/data/invoices"; Routes["x"] = "10/x"; Routes["y"] = "110/y"; -})(Routes || (Routes = {})); +}(Routes || {}); diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/exports/declared-types/output.mjs b/packages/babel-plugin-transform-typescript/test/fixtures/exports/declared-types/output.mjs index b4b07dbf06dd..065f59d6fc76 100644 --- a/packages/babel-plugin-transform-typescript/test/fixtures/exports/declared-types/output.mjs +++ b/packages/babel-plugin-transform-typescript/test/fixtures/exports/declared-types/output.mjs @@ -1,19 +1,17 @@ export class C2 {} // everything removed export { C2 as C3 }; // only C2->C3 -var BB; -(function (BB) { +var BB = /*#__PURE__*/function (BB) { BB[BB["K"] = 0] = "K"; -})(BB || (BB = {})); -(function (BB) { +}(BB || {}); +BB = /*#__PURE__*/function (BB) { BB["L"] = "LL"; -})(BB || (BB = {})); +}(BB || {}); export { BB }; // only BB // everything removed export { BB as BB1 }; // BB->BB1 -var BB2; -(function (BB2) {})(BB2 || (BB2 = {})); +var BB2 = /*#__PURE__*/function (BB2) {}(BB2 || {}); function foo() {} export { BB2 as BB3, foo }; // only BB2->BB3 and foo diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/exports/export-const-enums/output.mjs b/packages/babel-plugin-transform-typescript/test/fixtures/exports/export-const-enums/output.mjs index 5f968d0b838c..fdf16f230322 100644 --- a/packages/babel-plugin-transform-typescript/test/fixtures/exports/export-const-enums/output.mjs +++ b/packages/babel-plugin-transform-typescript/test/fixtures/exports/export-const-enums/output.mjs @@ -1,4 +1,3 @@ -var None; -(function (None) {})(None || (None = {})); +var None = /*#__PURE__*/function (None) {}(None || {}); ; export {}; diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/imports/enum-id/output.mjs b/packages/babel-plugin-transform-typescript/test/fixtures/imports/enum-id/output.mjs index 7d058acd55eb..9d59225616db 100644 --- a/packages/babel-plugin-transform-typescript/test/fixtures/imports/enum-id/output.mjs +++ b/packages/babel-plugin-transform-typescript/test/fixtures/imports/enum-id/output.mjs @@ -1,6 +1,5 @@ -var Enum; -(function (Enum) { +var Enum = /*#__PURE__*/function (Enum) { Enum[Enum["A"] = 0] = "A"; -})(Enum || (Enum = {})); +}(Enum || {}); ; export {}; diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/imports/enum-value/output.mjs b/packages/babel-plugin-transform-typescript/test/fixtures/imports/enum-value/output.mjs index d79e7bca2b66..92b5d24c92d8 100644 --- a/packages/babel-plugin-transform-typescript/test/fixtures/imports/enum-value/output.mjs +++ b/packages/babel-plugin-transform-typescript/test/fixtures/imports/enum-value/output.mjs @@ -1,6 +1,5 @@ import { A } from 'lib'; -var Enum; -(function (Enum) { +var Enum = /*#__PURE__*/function (Enum) { Enum[Enum["id"] = A] = "id"; -})(Enum || (Enum = {})); +}(Enum || {}); ; diff --git a/packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-enum/output.mjs b/packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-enum/output.mjs index e32e56effd7d..85db0c4629f7 100644 --- a/packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-enum/output.mjs +++ b/packages/babel-plugin-transform-typescript/test/fixtures/namespace/clobber-enum/output.mjs @@ -1,7 +1,6 @@ -var A; -(function (A) { +var A = /*#__PURE__*/function (A) { A[A["C"] = 2] = "C"; -})(A || (A = {})); +}(A || {}); (function (_A) { const B = _A.B = 1; })(A || (A = {})); diff --git a/packages/babel-preset-typescript/test/fixtures/flow-compat/ts-valid/output.js b/packages/babel-preset-typescript/test/fixtures/flow-compat/ts-valid/output.js index 9dcd76542c20..86f23d27d954 100644 --- a/packages/babel-preset-typescript/test/fixtures/flow-compat/ts-valid/output.js +++ b/packages/babel-preset-typescript/test/fixtures/flow-compat/ts-valid/output.js @@ -1,5 +1,4 @@ -var Example; -(function (Example) { +var Example = /*#__PURE__*/function (Example) { Example[Example["Value"] = 0] = "Value"; -})(Example || (Example = {})); +}(Example || {}); foo; diff --git a/packages/babel-preset-typescript/test/fixtures/flow-compat/tsx-valid/output.js b/packages/babel-preset-typescript/test/fixtures/flow-compat/tsx-valid/output.js index 9dcd76542c20..86f23d27d954 100644 --- a/packages/babel-preset-typescript/test/fixtures/flow-compat/tsx-valid/output.js +++ b/packages/babel-preset-typescript/test/fixtures/flow-compat/tsx-valid/output.js @@ -1,5 +1,4 @@ -var Example; -(function (Example) { +var Example = /*#__PURE__*/function (Example) { Example[Example["Value"] = 0] = "Value"; -})(Example || (Example = {})); +}(Example || {}); foo;