From 79a729abf1e50147d16b2d96738b29d677394f8d Mon Sep 17 00:00:00 2001 From: JBYoshi <12983479+JBYoshi@users.noreply.github.com> Date: Mon, 26 Dec 2022 19:49:08 -0600 Subject: [PATCH 1/2] Implement support for evaluating computed properties. This allows expressions like "hello world"[6] to be evaluated. --- .../babel-traverse/src/path/evaluation.ts | 20 +++++++++++++++---- packages/babel-traverse/test/evaluation.js | 5 +++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/babel-traverse/src/path/evaluation.ts b/packages/babel-traverse/src/path/evaluation.ts index 6c7c16163c21..87e93655034b 100644 --- a/packages/babel-traverse/src/path/evaluation.ts +++ b/packages/babel-traverse/src/path/evaluation.ts @@ -158,7 +158,7 @@ function _evaluate(path: NodePath, state: State): any { return evaluateCached(path.get("expression"), state); } - // "foo".length + // "foo".length, "foo"[0] if ( path.isMemberExpression() && !path.parentPath.isCallExpression({ callee: path.node }) @@ -166,12 +166,24 @@ function _evaluate(path: NodePath, state: State): any { const property = path.get("property"); const object = path.get("object"); - if (object.isLiteral() && property.isIdentifier()) { + if (object.isLiteral()) { // @ts-expect-error todo(flow->ts): instead of typeof - would it be better to check type of ast node? const value = object.node.value; const type = typeof value; - if (type === "number" || type === "string") { - return value[property.node.name]; + + let key = null; + if (property.isIdentifier()) { + key = property.node.name; + } else if (path.node.computed) { + key = evaluateCached(property, state); + if (!state.confident) return; + } + if ( + (type === "number" || type === "string") && + key != null && + (typeof key === "number" || typeof key === "string") + ) { + return value[key]; } } } diff --git a/packages/babel-traverse/test/evaluation.js b/packages/babel-traverse/test/evaluation.js index 29a8372f7f69..bd21be347521 100644 --- a/packages/babel-traverse/test/evaluation.js +++ b/packages/babel-traverse/test/evaluation.js @@ -114,6 +114,11 @@ describe("evaluation", function () { .get("body.0.declarations.0.init") .evaluate().value, ).toBe(3); + expect( + getPath("var x = 'hello world'[6]") + .get("body.0.declarations.0.init") + .evaluate().value, + ).toBe("w"); const member_expr = getPath( "var x = Math.min(2,Math.max(3,4));var y = Math.random();", ); From f84faaad87ae3950e9aef845ca62de853f5a9f54 Mon Sep 17 00:00:00 2001 From: JBYoshi <12983479+JBYoshi@users.noreply.github.com> Date: Sun, 1 Jan 2023 22:03:45 -0500 Subject: [PATCH 2/2] Fix cases where the brackets contain a variable. --- packages/babel-traverse/src/path/evaluation.ts | 6 +++--- packages/babel-traverse/test/evaluation.js | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/babel-traverse/src/path/evaluation.ts b/packages/babel-traverse/src/path/evaluation.ts index 87e93655034b..6b35af8e6903 100644 --- a/packages/babel-traverse/src/path/evaluation.ts +++ b/packages/babel-traverse/src/path/evaluation.ts @@ -172,11 +172,11 @@ function _evaluate(path: NodePath, state: State): any { const type = typeof value; let key = null; - if (property.isIdentifier()) { - key = property.node.name; - } else if (path.node.computed) { + if (path.node.computed) { key = evaluateCached(property, state); if (!state.confident) return; + } else if (property.isIdentifier()) { + key = property.node.name; } if ( (type === "number" || type === "string") && diff --git a/packages/babel-traverse/test/evaluation.js b/packages/babel-traverse/test/evaluation.js index bd21be347521..07897748e71c 100644 --- a/packages/babel-traverse/test/evaluation.js +++ b/packages/babel-traverse/test/evaluation.js @@ -119,6 +119,11 @@ describe("evaluation", function () { .get("body.0.declarations.0.init") .evaluate().value, ).toBe("w"); + expect( + getPath("var length = 1; var x = 'abc'[length];") + .get("body.1.declarations.0.init") + .evaluate().value, + ).toBe("b"); const member_expr = getPath( "var x = Math.min(2,Math.max(3,4));var y = Math.random();", );