From 66496e7d7f5f18d3f35a10307080162fd1df7497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Fri, 27 May 2022 15:58:45 -0400 Subject: [PATCH 1/3] refactor: simplify buildOptimizedSequenceExpression --- .../src/buildOptimizedSequenceExpression.ts | 64 +++++++++++-------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/buildOptimizedSequenceExpression.ts b/packages/babel-plugin-proposal-pipeline-operator/src/buildOptimizedSequenceExpression.ts index 44909eac757a..50028f935e11 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/src/buildOptimizedSequenceExpression.ts +++ b/packages/babel-plugin-proposal-pipeline-operator/src/buildOptimizedSequenceExpression.ts @@ -1,32 +1,62 @@ import { types as t } from "@babel/core"; +import type { NodePath } from "@babel/traverse"; // tries to optimize sequence expressions in the format // (a = b, (c => c + e)(a)) // to // (a = b, a + e) -const buildOptimizedSequenceExpression = ({ call, path, placeholder }) => { + +type Options = { + call: t.CallExpression; + path: NodePath" }>; + placeholder: t.Identifier; +}; + +function isConciseArrowExpression( + node: t.Node, +): node is t.ArrowFunctionExpression & { body: t.Expression } { + return ( + t.isArrowFunctionExpression(node) && + t.isExpression(node.body) && + !node.async + ); +} + +const buildOptimizedSequenceExpression = ({ + call, + path, + placeholder, +}: Options) => { const { callee: calledExpression } = call; - const pipelineLeft = path.node.left; + // pipelineLeft must not be a PrivateName + const pipelineLeft = path.node.left as t.Expression; const assign = t.assignmentExpression( "=", t.cloneNode(placeholder), pipelineLeft, ); - let optimizeArrow = - t.isArrowFunctionExpression(calledExpression) && - t.isExpression(calledExpression.body) && - !calledExpression.async && - !calledExpression.generator; - let param; + const expressionIsArrow = isConciseArrowExpression(calledExpression); - if (optimizeArrow) { + if (expressionIsArrow) { + let param; + let optimizeArrow = true; const { params } = calledExpression; if (params.length === 1 && t.isIdentifier(params[0])) { param = params[0]; } else if (params.length > 0) { optimizeArrow = false; } + if (optimizeArrow && !param) { + // fixme: arrow function with 1 pattern argument will also go into this branch + // Arrow function with 0 arguments + return t.sequenceExpression([pipelineLeft, calledExpression.body]); + } else if (param) { + path.scope.push({ id: t.cloneNode(placeholder) }); + path.get("right").scope.rename(param.name, placeholder.name); + + return t.sequenceExpression([assign, calledExpression.body]); + } } else if (t.isIdentifier(calledExpression, { name: "eval" })) { const evalSequence = t.sequenceExpression([ t.numericLiteral(0), @@ -34,25 +64,9 @@ const buildOptimizedSequenceExpression = ({ call, path, placeholder }) => { ]); call.callee = evalSequence; - - path.scope.push({ id: t.cloneNode(placeholder) }); - - return t.sequenceExpression([assign, call]); - } - - if (optimizeArrow && !param) { - // Arrow function with 0 arguments - return t.sequenceExpression([pipelineLeft, calledExpression.body]); } - path.scope.push({ id: t.cloneNode(placeholder) }); - if (param) { - path.get("right").scope.rename(param.name, placeholder.name); - - return t.sequenceExpression([assign, calledExpression.body]); - } - return t.sequenceExpression([assign, call]); }; From 3642086fe575158b54a80ff777622e3e200128e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Fri, 27 May 2022 16:05:09 -0400 Subject: [PATCH 2/3] proposal-pipeline-operator --- .../src/buildOptimizedSequenceExpression.ts | 5 +++-- .../src/fsharpVisitor.ts | 7 ++++--- .../src/hackVisitor.ts | 2 +- .../src/minimalVisitor.ts | 7 ++++--- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/buildOptimizedSequenceExpression.ts b/packages/babel-plugin-proposal-pipeline-operator/src/buildOptimizedSequenceExpression.ts index 50028f935e11..e15e7eb3801b 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/src/buildOptimizedSequenceExpression.ts +++ b/packages/babel-plugin-proposal-pipeline-operator/src/buildOptimizedSequenceExpression.ts @@ -7,7 +7,7 @@ import type { NodePath } from "@babel/traverse"; // (a = b, a + e) type Options = { - call: t.CallExpression; + call: t.CallExpression | t.AwaitExpression; path: NodePath" }>; placeholder: t.Identifier; }; @@ -27,6 +27,7 @@ const buildOptimizedSequenceExpression = ({ path, placeholder, }: Options) => { + // @ts-expect-error AwaitExpression does not have callee property const { callee: calledExpression } = call; // pipelineLeft must not be a PrivateName const pipelineLeft = path.node.left as t.Expression; @@ -63,7 +64,7 @@ const buildOptimizedSequenceExpression = ({ calledExpression, ]); - call.callee = evalSequence; + (call as t.CallExpression).callee = evalSequence; } path.scope.push({ id: t.cloneNode(placeholder) }); diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.ts b/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.ts index d285588f37df..5b1b5cac24cd 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.ts +++ b/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.ts @@ -1,7 +1,8 @@ -import { types as t } from "@babel/core"; +import { types as t, type PluginObject } from "@babel/core"; +import type { NodePath } from "@babel/traverse"; import buildOptimizedSequenceExpression from "./buildOptimizedSequenceExpression"; -const fsharpVisitor = { +const fsharpVisitor: PluginObject["visitor"] = { BinaryExpression(path) { const { scope, node } = path; const { operator, left, right } = node; @@ -16,7 +17,7 @@ const fsharpVisitor = { const sequence = buildOptimizedSequenceExpression({ placeholder, call, - path, + path: path as NodePath" }>, }); path.replaceWith(sequence); }, diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/hackVisitor.ts b/packages/babel-plugin-proposal-pipeline-operator/src/hackVisitor.ts index 36af34d537d5..28f6adc7d760 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/src/hackVisitor.ts +++ b/packages/babel-plugin-proposal-pipeline-operator/src/hackVisitor.ts @@ -52,7 +52,7 @@ export default { return; } - const visitorState = { + const visitorState: State = { topicReferences: [], // pipeBodyPath might be a function, and it won't be visited by // topicReferenceVisitor because traverse() skips the top-level diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.ts b/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.ts index 66d3bff98af0..5668ec21f2e4 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.ts +++ b/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.ts @@ -1,7 +1,8 @@ -import { types as t } from "@babel/core"; +import { types as t, type PluginObject } from "@babel/core"; +import type { NodePath } from "@babel/traverse"; import buildOptimizedSequenceExpression from "./buildOptimizedSequenceExpression"; -const minimalVisitor = { +const minimalVisitor: PluginObject["visitor"] = { BinaryExpression(path) { const { scope, node } = path; const { operator, left, right } = node; @@ -14,7 +15,7 @@ const minimalVisitor = { buildOptimizedSequenceExpression({ placeholder, call, - path, + path: path as NodePath" }>, }), ); }, From c4df5bf5ad1bc2d26b26ac0e3c58ccf04af22527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Wed, 1 Jun 2022 12:55:46 -0400 Subject: [PATCH 3/3] address review comments --- .../src/hackVisitor.ts | 6 ++++-- .../src/minimalVisitor.ts | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/hackVisitor.ts b/packages/babel-plugin-proposal-pipeline-operator/src/hackVisitor.ts index 28f6adc7d760..c7e9d8d865c4 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/src/hackVisitor.ts +++ b/packages/babel-plugin-proposal-pipeline-operator/src/hackVisitor.ts @@ -33,7 +33,7 @@ const topicReferenceVisitor: Visitor = { // with sequence expressions containing assignment expressions // with automatically generated variables, // from inside to outside, from left to right. -export default { +const visitor: Visitor = { BinaryExpression: { exit(path) { const { scope, node } = path; @@ -93,4 +93,6 @@ export default { ); }, }, -} as Visitor; +}; + +export default visitor; diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.ts b/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.ts index 5668ec21f2e4..a7a0e3e72464 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.ts +++ b/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.ts @@ -1,8 +1,8 @@ -import { types as t, type PluginObject } from "@babel/core"; -import type { NodePath } from "@babel/traverse"; +import { types as t, type PluginPass } from "@babel/core"; +import type { NodePath, Visitor } from "@babel/traverse"; import buildOptimizedSequenceExpression from "./buildOptimizedSequenceExpression"; -const minimalVisitor: PluginObject["visitor"] = { +const minimalVisitor: Visitor = { BinaryExpression(path) { const { scope, node } = path; const { operator, left, right } = node;