Skip to content

Commit

Permalink
review and improve
Browse files Browse the repository at this point in the history
  • Loading branch information
liuxingbaoyu committed Jan 31, 2023
1 parent 6a8817f commit 9d45aba
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 49 deletions.
Expand Up @@ -27,7 +27,7 @@ export default function transpileConstEnum(
);
}

const { nodes: entries } = translateEnumValues(path, t);
const { enumValues: entries } = translateEnumValues(path, t);

if (isExported) {
const obj = t.objectExpression(
Expand Down
93 changes: 48 additions & 45 deletions packages/babel-plugin-transform-typescript/src/enum.ts
@@ -1,6 +1,5 @@
import { template, types } from "@babel/core";
import { template, types as t } from "@babel/core";
import type { NodePath } from "@babel/traverse";
import type * as t from "@babel/types";
import assert from "assert";

type t = typeof t;
Expand Down Expand Up @@ -84,7 +83,7 @@ const buildEnumMember = (isString: boolean, options: Record<string, unknown>) =>
* `(function (E) { ... assignments ... })(E || (E = {}));`
*/
function enumFill(path: NodePath<t.TSEnumDeclaration>, t: t, id: t.Identifier) {
const { nodes: x, data } = translateEnumValues(path, t);
const { enumValues: x, data } = translateEnumValues(path, t);
const assignments = x.map(([memberName, memberValue]) =>
buildEnumMember(t.isStringLiteral(memberValue), {
ENUM: t.cloneNode(id),
Expand Down Expand Up @@ -145,7 +144,7 @@ export function translateEnumValues(path: NodePath<t.TSEnumDeclaration>, t: t) {

return {
data: seen,
nodes: path.get("members").map(memberPath => {
enumValues: 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");
Expand Down Expand Up @@ -205,31 +204,16 @@ export function translateEnumValues(path: NodePath<t.TSEnumDeclaration>, t: t) {
// Based on the TypeScript repository's `evalConstant` in `checker.ts`.
function evaluate(
path: NodePath,
seen: PreviousEnumMembers,
prevMembers?: PreviousEnumMembers,
seen: Set<t.Identifier> = new Set(),
): number | string | undefined {
return evalConstant(path);

function evalConstant(path: NodePath): number | string | undefined {
const expr = path.node;
switch (expr.type) {
case "MemberExpression": {
const obj = expr.object;
const prop = expr.property;
if (
!types.isIdentifier(obj) ||
(expr.computed
? !types.isStringLiteral(prop)
: !types.isIdentifier(prop))
) {
return;
}
const bindingIdentifier = path.scope.getBindingIdentifier(obj.name);
const data = ENUMS.get(bindingIdentifier);
if (!data) return;
// @ts-expect-error checked above
return data.get(prop.computed ? prop.value : prop.name);
}

case "MemberExpression":
return evaluateRef(path, prevMembers, seen);
case "StringLiteral":
return expr.value;
case "UnaryExpression":
Expand All @@ -240,16 +224,8 @@ function evaluate(
return expr.value;
case "ParenthesizedExpression":
return evalConstant(path.get("expression"));
case "Identifier": {
let value = seen.get(expr.name);
if (value === undefined) {
value = evaluateIdentifier(path);
if (value !== undefined) {
seen.set(expr.name, value);
}
}
return value;
}
case "Identifier":
return evaluateRef(path, prevMembers, seen);
case "TemplateLiteral": {
if (expr.quasis.length === 1) {
return expr.quasis[0].value.cooked;
Expand All @@ -263,7 +239,7 @@ function evaluate(
str += quasis[i].value.cooked;

if (i + 1 < quasis.length) {
const value = evaluateIdentifier(paths[i]);
const value = evaluateRef(paths[i], prevMembers, seen);
if (value === undefined) return undefined;
str += value;
}
Expand All @@ -275,17 +251,44 @@ function evaluate(
}
}

function evaluateIdentifier(path: NodePath) {
if (path.isIdentifier()) {
const binding = path.scope.getBinding(path.node.name);
if (binding?.kind === "const") {
const result = path.evaluate();
if (
result.confident &&
(typeof result.value === "number" || typeof result.value === "string")
) {
return result.value;
}
function evaluateRef(
path: NodePath,
prevMembers: PreviousEnumMembers,
seen: Set<t.Identifier>,
): number | string | undefined {
if (path.isMemberExpression()) {
const expr = path.node;

const obj = expr.object;
const prop = expr.property;
if (
!t.isIdentifier(obj) ||
(expr.computed ? !t.isStringLiteral(prop) : !t.isIdentifier(prop))
) {
return;
}
const bindingIdentifier = path.scope.getBindingIdentifier(obj.name);
const data = ENUMS.get(bindingIdentifier);
if (!data) return;
// @ts-expect-error checked above
return data.get(prop.computed ? prop.value : prop.name);
} else if (path.isIdentifier()) {
const name = path.node.name;

let value = prevMembers?.get(name);
if (value !== undefined) {
return value;
}

if (seen.has(path.node)) return;

const bindingInitPath = path.resolve(); //It only resolves constant bindings
if (bindingInitPath) {
seen.add(path.node);

value = evaluate(bindingInitPath, undefined, seen);
prevMembers?.set(name, value);
return value;
}
}
}
Expand Down
Expand Up @@ -3,14 +3,14 @@ var Foo;
(function (Foo) {
Foo[Foo["a"] = 10] = "a";
Foo[Foo["b"] = 10] = "b";
Foo[Foo["c"] = Foo.b + x] = "c";
Foo[Foo["c"] = 20] = "c";
})(Foo || (Foo = {}));
var Bar;
(function (Bar) {
Bar[Bar["D"] = 10] = "D";
Bar[Bar["E"] = 10] = "E";
Bar[Bar["F"] = Math.E] = "F";
Bar[Bar["G"] = Bar.E + Foo.c] = "G";
Bar[Bar["G"] = 30] = "G";
})(Bar || (Bar = {}));
var Baz;
(function (Baz) {
Expand Down
Expand Up @@ -7,7 +7,13 @@ const enum Values {
Second, // 11
Third, // 12
}

const xxx = 100 + Values.First;
const yyy = xxx;

const enum Routes {
Parts = `${Prefix}/parts`, // "/data/parts"
Invoices = `${Prefix}/invoices`, // "/data/invoices"
x = `${Values.First}/x`,
y = `${yyy}/y`,
}
Expand Up @@ -8,8 +8,12 @@ var Values; // 12
Values[Values["Second"] = 11] = "Second";
Values[Values["Third"] = 12] = "Third";
})(Values || (Values = {}));
var Routes; // "/data/invoices"
const xxx = 100 + Values.First;
const yyy = xxx;
var Routes;
(function (Routes) {
Routes["Parts"] = "/data/parts";
Routes["Invoices"] = "/data/invoices";
Routes["x"] = "10/x";
Routes["y"] = "110/y";
})(Routes || (Routes = {}));

0 comments on commit 9d45aba

Please sign in to comment.