From bbb8a144b0a43c9b009758ea5a8045b4887fa77d Mon Sep 17 00:00:00 2001 From: Thiago Arrais Date: Wed, 27 Feb 2019 13:49:30 -0300 Subject: [PATCH 1/7] Transform for F#-style await Inludes support for optimizing single-parameter arrow functions --- .../src/fsharpVisitor.js | 55 +++++++++++++++++++ .../src/index.js | 2 + .../fsharp/arrow-functions-parenless/exec.js | 34 ++++++++++++ .../fixtures/fsharp/arrow-functions/exec.js | 14 +++++ .../fixtures/fsharp/arrow-functions/input.js | 14 +++++ .../fixtures/fsharp/arrow-functions/output.js | 15 +++++ .../test/fixtures/fsharp/await/exec.js | 13 +++++ .../test/fixtures/fsharp/await/input.js | 6 ++ .../test/fixtures/fsharp/await/options.json | 9 +++ .../test/fixtures/fsharp/await/output.js | 5 ++ .../test/fixtures/fsharp/basic/exec.js | 3 + .../test/fixtures/fsharp/basic/input.js | 3 + .../test/fixtures/fsharp/basic/output.js | 5 ++ .../fixtures/fsharp/indirect-eval/exec.js | 7 +++ .../fixtures/fsharp/indirect-eval/input.js | 7 +++ .../fixtures/fsharp/indirect-eval/output.js | 8 +++ .../fsharp/optimize-0-param-arrow/exec.js | 8 +++ .../fsharp/optimize-0-param-arrow/input.js | 8 +++ .../fsharp/optimize-0-param-arrow/output.js | 5 ++ .../test/fixtures/fsharp/options.json | 8 +++ .../minimal/arrow-functions-parenless/exec.js | 20 +++++++ .../arrow-functions-parenless/input.js | 20 +++++++ .../arrow-functions-parenless/output.js | 23 ++++++++ .../src/index.js | 2 +- 24 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions-parenless/exec.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/exec.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/input.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/output.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/await/exec.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/await/input.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/await/options.json create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/await/output.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/basic/exec.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/basic/input.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/basic/output.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/indirect-eval/exec.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/indirect-eval/input.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/indirect-eval/output.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/optimize-0-param-arrow/exec.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/optimize-0-param-arrow/input.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/optimize-0-param-arrow/output.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/options.json create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions-parenless/exec.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions-parenless/input.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions-parenless/output.js diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js b/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js new file mode 100644 index 000000000000..88f94412073a --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js @@ -0,0 +1,55 @@ +import { types as t } from "@babel/core"; + +const fsharpVisitor = { + BinaryExpression(path) { + const { scope } = path; + const { node } = path; + const { operator, left } = node; + let { right } = node; + if (operator !== "|>") return; + + let optimizeArrow = + t.isArrowFunctionExpression(right) && + t.isExpression(right.body) && + !right.async && + !right.generator; + let param; + + if (optimizeArrow) { + const { params } = right; + if (params.length === 1 && t.isIdentifier(params[0])) { + param = params[0]; + } else if (params.length > 0) { + optimizeArrow = false; + } + } else if (t.isIdentifier(right, { name: "eval" })) { + right = t.sequenceExpression([t.numericLiteral(0), right]); + } + + if (optimizeArrow && !param) { + // Arrow function with 0 arguments + path.replaceWith(t.sequenceExpression([left, right.body])); + return; + } + + const placeholder = scope.generateUidIdentifierBasedOnNode(param || left); + scope.push({ id: placeholder }); + if (param) { + path.get("right").scope.rename(param.name, placeholder.name); + } + + const applied = + right.type === "AwaitExpression" + ? t.awaitExpression(t.cloneNode(placeholder)) + : t.callExpression(right, [t.cloneNode(placeholder)]); + const call = optimizeArrow ? right.body : applied; + path.replaceWith( + t.sequenceExpression([ + t.assignmentExpression("=", t.cloneNode(placeholder), left), + call, + ]), + ); + }, +}; + +export default fsharpVisitor; diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/index.js b/packages/babel-plugin-proposal-pipeline-operator/src/index.js index 488cd02da9e0..241a99b87828 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/src/index.js +++ b/packages/babel-plugin-proposal-pipeline-operator/src/index.js @@ -2,10 +2,12 @@ import { declare } from "@babel/helper-plugin-utils"; import syntaxPipelineOperator from "@babel/plugin-syntax-pipeline-operator"; import minimalVisitor from "./minimalVisitor"; import smartVisitor from "./smartVisitor"; +import fsharpVisitor from "./fsharpVisitor"; const visitorsPerProposal = { minimal: minimalVisitor, smart: smartVisitor, + fsharp: fsharpVisitor, }; export default declare((api, options) => { diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions-parenless/exec.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions-parenless/exec.js new file mode 100644 index 000000000000..0e23684373b2 --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions-parenless/exec.js @@ -0,0 +1,34 @@ +const y = 2; + +const f = (x) => (x + |> (y) => y + 1) + |> (z) => z * y + +const _f = (x) => x + |> (y) => y + 1 + |> (z) => z * y + +const g = (x) => x + |> (y) => ( + y + 1 + |> (z) => z * y + ) + +const _g = (x) => x + |> (y => ( + y + 1 + |> (z) => z * y) + ) + +const __g = (x) => x + |> (y => { return ( + y + 1 + |> (z) => z * y); + } + ) + +expect( f(1)).toBe(4); +expect( _f(1)).toBe(4); +expect( g(1)).toBe(2); +expect( _g(1)).toBe(2); +expect(__g(1)).toBe(2); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/exec.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/exec.js new file mode 100644 index 000000000000..2411e82738ee --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/exec.js @@ -0,0 +1,14 @@ +var result = [5,10] + |> (_ => _.map(x => x * 2)) + |> (_ => _.reduce( (a,b) => a + b )) + |> (sum => sum + 1) + +expect(result).toBe(31); + + +var inc = (x) => x + 1; +var double = (x) => x * 2; + +var result2 = [4, 9].map( x => x |> inc |> double ) + +expect(result2).toEqual([10, 20]); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/input.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/input.js new file mode 100644 index 000000000000..2411e82738ee --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/input.js @@ -0,0 +1,14 @@ +var result = [5,10] + |> (_ => _.map(x => x * 2)) + |> (_ => _.reduce( (a,b) => a + b )) + |> (sum => sum + 1) + +expect(result).toBe(31); + + +var inc = (x) => x + 1; +var double = (x) => x * 2; + +var result2 = [4, 9].map( x => x |> inc |> double ) + +expect(result2).toEqual([10, 20]); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/output.js new file mode 100644 index 000000000000..f9e5075a4800 --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/output.js @@ -0,0 +1,15 @@ +var _sum, _ref, _ref2; + +var result = (_sum = (_ref = (_ref2 = [5, 10], _ref2.map(x => x * 2)), _ref.reduce((a, b) => a + b)), _sum + 1); +expect(result).toBe(31); + +var inc = x => x + 1; + +var double = x => x * 2; + +var result2 = [4, 9].map(x => { + var _ref3, _x; + + return _ref3 = (_x = x, inc(_x)), double(_ref3); +}); +expect(result2).toEqual([10, 20]); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/await/exec.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/await/exec.js new file mode 100644 index 000000000000..38503c1d0d23 --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/await/exec.js @@ -0,0 +1,13 @@ +const triple = (x) => x * 3; + +async function myFunction(n) { + return n + |> Math.abs + |> Promise.resolve + |> await + |> triple; +} + +return myFunction(-7).then(result => { + expect(result).toBe(21); +}); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/await/input.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/await/input.js new file mode 100644 index 000000000000..ad69aa432bbf --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/await/input.js @@ -0,0 +1,6 @@ +async function myFunction(n) { + return n + |> Math.abs + |> Promise.resolve + |> await; +} diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/await/options.json b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/await/options.json new file mode 100644 index 000000000000..c5a39e971027 --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/await/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + ["proposal-pipeline-operator", { "proposal": "fsharp" }] + ], + "parserOpts": { + "allowReturnOutsideFunction": true + }, + "minNodeVersion": "8.0.0" +} diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/await/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/await/output.js new file mode 100644 index 000000000000..bf7848696774 --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/await/output.js @@ -0,0 +1,5 @@ +async function myFunction(n) { + var _ref, _ref2, _n; + + return _ref = (_ref2 = (_n = n, Math.abs(_n)), Promise.resolve(_ref2)), await _ref; +} diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/basic/exec.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/basic/exec.js new file mode 100644 index 000000000000..a11e8073bb3f --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/basic/exec.js @@ -0,0 +1,3 @@ +var inc = (x) => x + 1 + +expect(10 |> inc).toBe(11); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/basic/input.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/basic/input.js new file mode 100644 index 000000000000..a11e8073bb3f --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/basic/input.js @@ -0,0 +1,3 @@ +var inc = (x) => x + 1 + +expect(10 |> inc).toBe(11); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/basic/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/basic/output.js new file mode 100644 index 000000000000..6ac05ce0fbc9 --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/basic/output.js @@ -0,0 +1,5 @@ +var _; + +var inc = x => x + 1; + +expect((_ = 10, inc(_))).toBe(11); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/indirect-eval/exec.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/indirect-eval/exec.js new file mode 100644 index 000000000000..30efd15ea92a --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/indirect-eval/exec.js @@ -0,0 +1,7 @@ +(function() { + 'use strict'; + var result = '(function() { return this; })()' + |> eval; + + expect(result).not.toBeUndefined(); +})(); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/indirect-eval/input.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/indirect-eval/input.js new file mode 100644 index 000000000000..30efd15ea92a --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/indirect-eval/input.js @@ -0,0 +1,7 @@ +(function() { + 'use strict'; + var result = '(function() { return this; })()' + |> eval; + + expect(result).not.toBeUndefined(); +})(); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/indirect-eval/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/indirect-eval/output.js new file mode 100644 index 000000000000..3c53e6d4f3bf --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/indirect-eval/output.js @@ -0,0 +1,8 @@ +(function () { + 'use strict'; + + var _functionReturn; + + var result = (_functionReturn = '(function() { return this; })()', (0, eval)(_functionReturn)); + expect(result).not.toBeUndefined(); +})(); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/optimize-0-param-arrow/exec.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/optimize-0-param-arrow/exec.js new file mode 100644 index 000000000000..d8ab9b2ebcf2 --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/optimize-0-param-arrow/exec.js @@ -0,0 +1,8 @@ +var a = 1, + b = 2, + c = 3; +var result = a + |> (() => b) + |> (() => c); + +expect(result).toBe(c); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/optimize-0-param-arrow/input.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/optimize-0-param-arrow/input.js new file mode 100644 index 000000000000..d8ab9b2ebcf2 --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/optimize-0-param-arrow/input.js @@ -0,0 +1,8 @@ +var a = 1, + b = 2, + c = 3; +var result = a + |> (() => b) + |> (() => c); + +expect(result).toBe(c); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/optimize-0-param-arrow/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/optimize-0-param-arrow/output.js new file mode 100644 index 000000000000..4fcc70527ca8 --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/optimize-0-param-arrow/output.js @@ -0,0 +1,5 @@ +var a = 1, + b = 2, + c = 3; +var result = ((a, b), c); +expect(result).toBe(c); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/options.json b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/options.json new file mode 100644 index 000000000000..4e41244cc302 --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/options.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + ["proposal-pipeline-operator", { "proposal": "fsharp" }] + ], + "parserOpts": { + "allowReturnOutsideFunction": true + } +} diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions-parenless/exec.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions-parenless/exec.js new file mode 100644 index 000000000000..88762f8e568f --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions-parenless/exec.js @@ -0,0 +1,20 @@ +const y = 2; +const f = (x) => x + |> (y => y + 1) + |> (z => z * y) + +const g = (x) => x + |> (y => + y + 1 + |> (z => z * y) + ) + +const h = (x) => x + |> (y => ( + y + 1 + |> (z => z * y) + )) + +expect(f(1)).toBe(4); +expect(g(1)).toBe(2); +expect(h(1)).toBe(2); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions-parenless/input.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions-parenless/input.js new file mode 100644 index 000000000000..88762f8e568f --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions-parenless/input.js @@ -0,0 +1,20 @@ +const y = 2; +const f = (x) => x + |> (y => y + 1) + |> (z => z * y) + +const g = (x) => x + |> (y => + y + 1 + |> (z => z * y) + ) + +const h = (x) => x + |> (y => ( + y + 1 + |> (z => z * y) + )) + +expect(f(1)).toBe(4); +expect(g(1)).toBe(2); +expect(h(1)).toBe(2); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions-parenless/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions-parenless/output.js new file mode 100644 index 000000000000..cdc3d1270687 --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions-parenless/output.js @@ -0,0 +1,23 @@ +const y = 2; + +const f = x => { + var _z, _y; + + return _z = (_y = x, _y + 1), _z * y; +}; + +const g = x => { + var _y2, _z2; + + return _y2 = x, (_z2 = _y2 + 1, _z2 * _y2); +}; + +const h = x => { + var _y3, _z3; + + return _y3 = x, (_z3 = _y3 + 1, _z3 * _y3); +}; + +expect(f(1)).toBe(4); +expect(g(1)).toBe(2); +expect(h(1)).toBe(2); diff --git a/packages/babel-plugin-syntax-pipeline-operator/src/index.js b/packages/babel-plugin-syntax-pipeline-operator/src/index.js index 4cb84850ebac..df904e77644c 100644 --- a/packages/babel-plugin-syntax-pipeline-operator/src/index.js +++ b/packages/babel-plugin-syntax-pipeline-operator/src/index.js @@ -1,6 +1,6 @@ import { declare } from "@babel/helper-plugin-utils"; -export const proposals = ["minimal", "smart"]; +export const proposals = ["minimal", "smart", "fsharp"]; export default declare((api, { proposal }) => { api.assertVersion(7); From 573fe40b228d09be7bfd579a0e3aa959f3da25b3 Mon Sep 17 00:00:00 2001 From: Thiago Arrais Date: Mon, 22 Apr 2019 21:34:05 -0300 Subject: [PATCH 2/7] Extracts arrow function optimization to its own function --- .../src/fsharpVisitor.js | 94 +++++++++++-------- .../fixtures/fsharp/arrow-functions/output.js | 8 +- .../fsharp/multiple-argument-use/input.js | 5 + .../fsharp/multiple-argument-use/output.js | 5 + .../fsharp/optimize-0-param-arrow/output.js | 2 + 5 files changed, 73 insertions(+), 41 deletions(-) create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/multiple-argument-use/input.js create mode 100644 packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/multiple-argument-use/output.js diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js b/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js index 88f94412073a..323b29cdd68c 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js +++ b/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js @@ -1,54 +1,74 @@ import { types as t } from "@babel/core"; +// tries to optimize sequence expressions in the format +// (a = b, ((c) => d + e)(a)) +// to +// (a = b, a + e) +const maybeOptimizePipelineSequence = path => { + const [assignNode, callNode] = path.node.expressions; + const { left: placeholderNode, right: pipelineLeft } = assignNode; + const { callee: calledExpression } = callNode; + + let optimizeArrow = + t.isArrowFunctionExpression(calledExpression) && + t.isExpression(calledExpression.body) && + !calledExpression.async && + !calledExpression.generator; + let param; + + if (optimizeArrow) { + const { params } = calledExpression; + if (params.length === 1 && t.isIdentifier(params[0])) { + param = params[0]; + } else if (params.length > 0) { + optimizeArrow = false; + } + } else if (t.isIdentifier(calledExpression, { name: "eval" })) { + const evalSequence = t.sequenceExpression([ + t.numericLiteral(0), + calledExpression, + ]); + + path.get("expressions.1.callee").replaceWith(evalSequence); + } + + if (optimizeArrow && !param) { + // Arrow function with 0 arguments + path.replaceWith( + t.sequenceExpression([pipelineLeft, calledExpression.body]), + ); + return; + } + + if (param) { + path + .get("expressions.1.callee.body") + .scope.rename(param.name, placeholderNode.name); + path.get("expressions.1").replaceWith(calledExpression.body); + } +}; + const fsharpVisitor = { BinaryExpression(path) { const { scope } = path; const { node } = path; - const { operator, left } = node; - let { right } = node; + const { operator, left, right } = node; if (operator !== "|>") return; - let optimizeArrow = - t.isArrowFunctionExpression(right) && - t.isExpression(right.body) && - !right.async && - !right.generator; - let param; - - if (optimizeArrow) { - const { params } = right; - if (params.length === 1 && t.isIdentifier(params[0])) { - param = params[0]; - } else if (params.length > 0) { - optimizeArrow = false; - } - } else if (t.isIdentifier(right, { name: "eval" })) { - right = t.sequenceExpression([t.numericLiteral(0), right]); - } - - if (optimizeArrow && !param) { - // Arrow function with 0 arguments - path.replaceWith(t.sequenceExpression([left, right.body])); - return; - } - - const placeholder = scope.generateUidIdentifierBasedOnNode(param || left); + const placeholder = scope.generateUidIdentifierBasedOnNode(left); scope.push({ id: placeholder }); - if (param) { - path.get("right").scope.rename(param.name, placeholder.name); - } const applied = right.type === "AwaitExpression" ? t.awaitExpression(t.cloneNode(placeholder)) : t.callExpression(right, [t.cloneNode(placeholder)]); - const call = optimizeArrow ? right.body : applied; - path.replaceWith( - t.sequenceExpression([ - t.assignmentExpression("=", t.cloneNode(placeholder), left), - call, - ]), - ); + const call = applied; + const sequence = t.sequenceExpression([ + t.assignmentExpression("=", t.cloneNode(placeholder), left), + call, + ]); + path.replaceWith(sequence); + maybeOptimizePipelineSequence(path); }, }; diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/output.js index f9e5075a4800..cd2b80132c22 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/output.js +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/output.js @@ -1,6 +1,6 @@ -var _sum, _ref, _ref2; +var _ref, _ref2, _ref3; -var result = (_sum = (_ref = (_ref2 = [5, 10], _ref2.map(x => x * 2)), _ref.reduce((a, b) => a + b)), _sum + 1); +var result = (_ref = (_ref2 = (_ref3 = [5, 10], _ref3.map(x => x * 2)), _ref2.reduce((a, b) => a + b)), _ref + 1); expect(result).toBe(31); var inc = x => x + 1; @@ -8,8 +8,8 @@ var inc = x => x + 1; var double = x => x * 2; var result2 = [4, 9].map(x => { - var _ref3, _x; + var _ref4, _x; - return _ref3 = (_x = x, inc(_x)), double(_ref3); + return _ref4 = (_x = x, inc(_x)), double(_ref4); }); expect(result2).toEqual([10, 20]); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/multiple-argument-use/input.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/multiple-argument-use/input.js new file mode 100644 index 000000000000..f29037ed294e --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/multiple-argument-use/input.js @@ -0,0 +1,5 @@ +var array = [10,20,30]; + +var last = array |> (a => a[a.length-1]); + +expect(last).toBe(30); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/multiple-argument-use/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/multiple-argument-use/output.js new file mode 100644 index 000000000000..121f15e8a584 --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/multiple-argument-use/output.js @@ -0,0 +1,5 @@ +var _array; + +var array = [10, 20, 30]; +var last = (_array = array, _array[_array.length - 1]); +expect(last).toBe(30); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/optimize-0-param-arrow/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/optimize-0-param-arrow/output.js index 4fcc70527ca8..1b3ba04d0f8a 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/optimize-0-param-arrow/output.js +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/optimize-0-param-arrow/output.js @@ -1,3 +1,5 @@ +var _ref, _a; + var a = 1, b = 2, c = 3; From 34c4d709cbcae8c4f62f999d4f351334b1a0f542 Mon Sep 17 00:00:00 2001 From: Thiago Arrais Date: Wed, 24 Apr 2019 13:21:44 -0300 Subject: [PATCH 3/7] Share optimizing code between fsharp and minimal --- .../src/fsharpVisitor.js | 52 +------------------ .../src/maybeOptimizePipelineSequence.js | 51 ++++++++++++++++++ .../src/minimalVisitor.js | 38 ++------------ .../arrow-functions-parenless/output.js | 12 ++--- .../minimal/arrow-functions/output.js | 8 +-- .../minimal/multiple-argument-use/output.js | 4 +- .../minimal/optimize-0-param-arrow/output.js | 2 + 7 files changed, 72 insertions(+), 95 deletions(-) create mode 100644 packages/babel-plugin-proposal-pipeline-operator/src/maybeOptimizePipelineSequence.js diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js b/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js index 323b29cdd68c..35634ca60602 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js +++ b/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js @@ -1,52 +1,5 @@ import { types as t } from "@babel/core"; - -// tries to optimize sequence expressions in the format -// (a = b, ((c) => d + e)(a)) -// to -// (a = b, a + e) -const maybeOptimizePipelineSequence = path => { - const [assignNode, callNode] = path.node.expressions; - const { left: placeholderNode, right: pipelineLeft } = assignNode; - const { callee: calledExpression } = callNode; - - let optimizeArrow = - t.isArrowFunctionExpression(calledExpression) && - t.isExpression(calledExpression.body) && - !calledExpression.async && - !calledExpression.generator; - let param; - - if (optimizeArrow) { - const { params } = calledExpression; - if (params.length === 1 && t.isIdentifier(params[0])) { - param = params[0]; - } else if (params.length > 0) { - optimizeArrow = false; - } - } else if (t.isIdentifier(calledExpression, { name: "eval" })) { - const evalSequence = t.sequenceExpression([ - t.numericLiteral(0), - calledExpression, - ]); - - path.get("expressions.1.callee").replaceWith(evalSequence); - } - - if (optimizeArrow && !param) { - // Arrow function with 0 arguments - path.replaceWith( - t.sequenceExpression([pipelineLeft, calledExpression.body]), - ); - return; - } - - if (param) { - path - .get("expressions.1.callee.body") - .scope.rename(param.name, placeholderNode.name); - path.get("expressions.1").replaceWith(calledExpression.body); - } -}; +import maybeOptimizePipelineSequence from "./maybeOptimizePipelineSequence"; const fsharpVisitor = { BinaryExpression(path) { @@ -58,11 +11,10 @@ const fsharpVisitor = { const placeholder = scope.generateUidIdentifierBasedOnNode(left); scope.push({ id: placeholder }); - const applied = + const call = right.type === "AwaitExpression" ? t.awaitExpression(t.cloneNode(placeholder)) : t.callExpression(right, [t.cloneNode(placeholder)]); - const call = applied; const sequence = t.sequenceExpression([ t.assignmentExpression("=", t.cloneNode(placeholder), left), call, diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/maybeOptimizePipelineSequence.js b/packages/babel-plugin-proposal-pipeline-operator/src/maybeOptimizePipelineSequence.js new file mode 100644 index 000000000000..76fa08a18801 --- /dev/null +++ b/packages/babel-plugin-proposal-pipeline-operator/src/maybeOptimizePipelineSequence.js @@ -0,0 +1,51 @@ +import { types as t } from "@babel/core"; + +// tries to optimize sequence expressions in the format +// (a = b, ((c) => d + e)(a)) +// to +// (a = b, a + e) +const maybeOptimizePipelineSequence = path => { + const [assignNode, callNode] = path.node.expressions; + const { left: placeholderNode, right: pipelineLeft } = assignNode; + const { callee: calledExpression } = callNode; + + let optimizeArrow = + t.isArrowFunctionExpression(calledExpression) && + t.isExpression(calledExpression.body) && + !calledExpression.async && + !calledExpression.generator; + let param; + + if (optimizeArrow) { + const { params } = calledExpression; + if (params.length === 1 && t.isIdentifier(params[0])) { + param = params[0]; + } else if (params.length > 0) { + optimizeArrow = false; + } + } else if (t.isIdentifier(calledExpression, { name: "eval" })) { + const evalSequence = t.sequenceExpression([ + t.numericLiteral(0), + calledExpression, + ]); + + path.get("expressions.1.callee").replaceWith(evalSequence); + } + + if (optimizeArrow && !param) { + // Arrow function with 0 arguments + path.replaceWith( + t.sequenceExpression([pipelineLeft, calledExpression.body]), + ); + return; + } + + if (param) { + path + .get("expressions.1.callee.body") + .scope.rename(param.name, placeholderNode.name); + path.get("expressions.1").replaceWith(calledExpression.body); + } +}; + +export default maybeOptimizePipelineSequence; diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.js b/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.js index 960082a09591..4a0c3bfccdfd 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.js +++ b/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.js @@ -1,52 +1,24 @@ import { types as t } from "@babel/core"; +import maybeOptimizePipelineSequence from "./maybeOptimizePipelineSequence"; const minimalVisitor = { BinaryExpression(path) { const { scope } = path; const { node } = path; - const { operator, left } = node; - let { right } = node; + const { operator, left, right } = node; if (operator !== "|>") return; - let optimizeArrow = - t.isArrowFunctionExpression(right) && - t.isExpression(right.body) && - !right.async && - !right.generator; - let param; - - if (optimizeArrow) { - const { params } = right; - if (params.length === 1 && t.isIdentifier(params[0])) { - param = params[0]; - } else if (params.length > 0) { - optimizeArrow = false; - } - } else if (t.isIdentifier(right, { name: "eval" })) { - right = t.sequenceExpression([t.numericLiteral(0), right]); - } - - if (optimizeArrow && !param) { - // Arrow function with 0 arguments - path.replaceWith(t.sequenceExpression([left, right.body])); - return; - } - - const placeholder = scope.generateUidIdentifierBasedOnNode(param || left); + const placeholder = scope.generateUidIdentifierBasedOnNode(left); scope.push({ id: placeholder }); - if (param) { - path.get("right").scope.rename(param.name, placeholder.name); - } - const call = optimizeArrow - ? right.body - : t.callExpression(right, [t.cloneNode(placeholder)]); + const call = t.callExpression(right, [t.cloneNode(placeholder)]); path.replaceWith( t.sequenceExpression([ t.assignmentExpression("=", t.cloneNode(placeholder), left), call, ]), ); + maybeOptimizePipelineSequence(path); }, }; diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions-parenless/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions-parenless/output.js index cdc3d1270687..926086963984 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions-parenless/output.js +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions-parenless/output.js @@ -1,21 +1,21 @@ const y = 2; const f = x => { - var _z, _y; + var _ref, _x; - return _z = (_y = x, _y + 1), _z * y; + return _ref = (_x = x, _x + 1), _ref * y; }; const g = x => { - var _y2, _z2; + var _x2, _ref2; - return _y2 = x, (_z2 = _y2 + 1, _z2 * _y2); + return _x2 = x, (_ref2 = _x2 + 1, _ref2 * _x2); }; const h = x => { - var _y3, _z3; + var _x3, _ref3; - return _y3 = x, (_z3 = _y3 + 1, _z3 * _y3); + return _x3 = x, (_ref3 = _x3 + 1, _ref3 * _x3); }; expect(f(1)).toBe(4); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions/output.js index f9e5075a4800..cd2b80132c22 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions/output.js +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions/output.js @@ -1,6 +1,6 @@ -var _sum, _ref, _ref2; +var _ref, _ref2, _ref3; -var result = (_sum = (_ref = (_ref2 = [5, 10], _ref2.map(x => x * 2)), _ref.reduce((a, b) => a + b)), _sum + 1); +var result = (_ref = (_ref2 = (_ref3 = [5, 10], _ref3.map(x => x * 2)), _ref2.reduce((a, b) => a + b)), _ref + 1); expect(result).toBe(31); var inc = x => x + 1; @@ -8,8 +8,8 @@ var inc = x => x + 1; var double = x => x * 2; var result2 = [4, 9].map(x => { - var _ref3, _x; + var _ref4, _x; - return _ref3 = (_x = x, inc(_x)), double(_ref3); + return _ref4 = (_x = x, inc(_x)), double(_ref4); }); expect(result2).toEqual([10, 20]); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/multiple-argument-use/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/multiple-argument-use/output.js index b26deb11cd97..121f15e8a584 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/multiple-argument-use/output.js +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/multiple-argument-use/output.js @@ -1,5 +1,5 @@ -var _a; +var _array; var array = [10, 20, 30]; -var last = (_a = array, _a[_a.length - 1]); +var last = (_array = array, _array[_array.length - 1]); expect(last).toBe(30); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/optimize-0-param-arrow/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/optimize-0-param-arrow/output.js index 4fcc70527ca8..1b3ba04d0f8a 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/optimize-0-param-arrow/output.js +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/optimize-0-param-arrow/output.js @@ -1,3 +1,5 @@ +var _ref, _a; + var a = 1, b = 2, c = 3; From 4811f0861b860cde86de5c3c42fcdf6b8341b611 Mon Sep 17 00:00:00 2001 From: Thiago Arrais Date: Mon, 29 Apr 2019 13:35:12 -0300 Subject: [PATCH 4/7] Better indentation --- .../fsharp/arrow-functions-parenless/exec.js | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions-parenless/exec.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions-parenless/exec.js index 0e23684373b2..03ffe5328721 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions-parenless/exec.js +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions-parenless/exec.js @@ -1,7 +1,6 @@ const y = 2; -const f = (x) => (x - |> (y) => y + 1) +const f = (x) => (x |> (y) => y + 1) |> (z) => z * y const _f = (x) => x @@ -9,21 +8,15 @@ const _f = (x) => x |> (z) => z * y const g = (x) => x - |> (y) => ( - y + 1 - |> (z) => z * y - ) + |> (y) => (y + 1 |> (z) => z * y) const _g = (x) => x - |> (y => ( - y + 1 - |> (z) => z * y) - ) + |> (y => (y + 1 |> (z) => z * y)) const __g = (x) => x - |> (y => { return ( - y + 1 - |> (z) => z * y); + |> ( + y => { + return (y + 1 |> (z) => z * y); } ) From ecbb465e2dc779ee632bf1d1664ed1b3d49e5565 Mon Sep 17 00:00:00 2001 From: Thiago Arrais Date: Mon, 29 Apr 2019 13:44:53 -0300 Subject: [PATCH 5/7] merge object patterns --- .../src/fsharpVisitor.js | 3 +-- .../src/minimalVisitor.js | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js b/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js index 35634ca60602..e207a1714e9d 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js +++ b/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js @@ -3,8 +3,7 @@ import maybeOptimizePipelineSequence from "./maybeOptimizePipelineSequence"; const fsharpVisitor = { BinaryExpression(path) { - const { scope } = path; - const { node } = path; + const { scope, node } = path; const { operator, left, right } = node; if (operator !== "|>") return; diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.js b/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.js index 4a0c3bfccdfd..b5bd628d3b9f 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.js +++ b/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.js @@ -3,8 +3,7 @@ import maybeOptimizePipelineSequence from "./maybeOptimizePipelineSequence"; const minimalVisitor = { BinaryExpression(path) { - const { scope } = path; - const { node } = path; + const { scope, node } = path; const { operator, left, right } = node; if (operator !== "|>") return; From f50bd7ae934e294ac53723b1386ef949c32fa4df Mon Sep 17 00:00:00 2001 From: Thiago Arrais Date: Mon, 29 Apr 2019 19:16:49 -0300 Subject: [PATCH 6/7] simpler optimization function as per nicolo's suggestion --- ...js => buildOptimizedSequenceExpression.js} | 27 +++++++++---------- .../src/fsharpVisitor.js | 10 +++---- .../src/minimalVisitor.js | 10 +++---- 3 files changed, 23 insertions(+), 24 deletions(-) rename packages/babel-plugin-proposal-pipeline-operator/src/{maybeOptimizePipelineSequence.js => buildOptimizedSequenceExpression.js} (58%) diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/maybeOptimizePipelineSequence.js b/packages/babel-plugin-proposal-pipeline-operator/src/buildOptimizedSequenceExpression.js similarity index 58% rename from packages/babel-plugin-proposal-pipeline-operator/src/maybeOptimizePipelineSequence.js rename to packages/babel-plugin-proposal-pipeline-operator/src/buildOptimizedSequenceExpression.js index 76fa08a18801..05757d4a5a6b 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/src/maybeOptimizePipelineSequence.js +++ b/packages/babel-plugin-proposal-pipeline-operator/src/buildOptimizedSequenceExpression.js @@ -4,10 +4,9 @@ import { types as t } from "@babel/core"; // (a = b, ((c) => d + e)(a)) // to // (a = b, a + e) -const maybeOptimizePipelineSequence = path => { - const [assignNode, callNode] = path.node.expressions; - const { left: placeholderNode, right: pipelineLeft } = assignNode; - const { callee: calledExpression } = callNode; +const buildOptimizedSequenceExpression = ({ assign, call, path }) => { + const { left: placeholderNode, right: pipelineLeft } = assign; + const { callee: calledExpression } = call; let optimizeArrow = t.isArrowFunctionExpression(calledExpression) && @@ -29,23 +28,23 @@ const maybeOptimizePipelineSequence = path => { calledExpression, ]); - path.get("expressions.1.callee").replaceWith(evalSequence); + call.callee = evalSequence; + + return t.sequenceExpression([assign, call]); } if (optimizeArrow && !param) { // Arrow function with 0 arguments - path.replaceWith( - t.sequenceExpression([pipelineLeft, calledExpression.body]), - ); - return; + return t.sequenceExpression([pipelineLeft, calledExpression.body]); } if (param) { - path - .get("expressions.1.callee.body") - .scope.rename(param.name, placeholderNode.name); - path.get("expressions.1").replaceWith(calledExpression.body); + path.get("right").scope.rename(param.name, placeholderNode.name); + + return t.sequenceExpression([assign, calledExpression.body]); } + + return t.sequenceExpression([assign, call]); }; -export default maybeOptimizePipelineSequence; +export default buildOptimizedSequenceExpression; diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js b/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js index e207a1714e9d..0cf2254ea44d 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js +++ b/packages/babel-plugin-proposal-pipeline-operator/src/fsharpVisitor.js @@ -1,5 +1,5 @@ import { types as t } from "@babel/core"; -import maybeOptimizePipelineSequence from "./maybeOptimizePipelineSequence"; +import buildOptimizedSequenceExpression from "./buildOptimizedSequenceExpression"; const fsharpVisitor = { BinaryExpression(path) { @@ -14,12 +14,12 @@ const fsharpVisitor = { right.type === "AwaitExpression" ? t.awaitExpression(t.cloneNode(placeholder)) : t.callExpression(right, [t.cloneNode(placeholder)]); - const sequence = t.sequenceExpression([ - t.assignmentExpression("=", t.cloneNode(placeholder), left), + const sequence = buildOptimizedSequenceExpression({ + assign: t.assignmentExpression("=", t.cloneNode(placeholder), left), call, - ]); + path, + }); path.replaceWith(sequence); - maybeOptimizePipelineSequence(path); }, }; diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.js b/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.js index b5bd628d3b9f..7fa2bfd4152e 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.js +++ b/packages/babel-plugin-proposal-pipeline-operator/src/minimalVisitor.js @@ -1,5 +1,5 @@ import { types as t } from "@babel/core"; -import maybeOptimizePipelineSequence from "./maybeOptimizePipelineSequence"; +import buildOptimizedSequenceExpression from "./buildOptimizedSequenceExpression"; const minimalVisitor = { BinaryExpression(path) { @@ -12,12 +12,12 @@ const minimalVisitor = { const call = t.callExpression(right, [t.cloneNode(placeholder)]); path.replaceWith( - t.sequenceExpression([ - t.assignmentExpression("=", t.cloneNode(placeholder), left), + buildOptimizedSequenceExpression({ + assign: t.assignmentExpression("=", t.cloneNode(placeholder), left), call, - ]), + path, + }), ); - maybeOptimizePipelineSequence(path); }, }; From 63b7c0437097da97aa2572792d1d18dea1ec8ed0 Mon Sep 17 00:00:00 2001 From: Thiago Arrais Date: Thu, 9 May 2019 04:02:16 +0000 Subject: [PATCH 7/7] Optimize simple function calls --- .../src/buildOptimizedSequenceExpression.js | 26 ++++++++++++------- .../fixtures/fsharp/arrow-functions/output.js | 2 +- .../test/fixtures/fsharp/basic/output.js | 2 +- .../minimal/arrow-functions/output.js | 2 +- .../fixtures/minimal/async-arrow/output.js | 2 +- .../test/fixtures/minimal/basic/output.js | 2 +- .../test/fixtures/minimal/chaining/output.js | 2 +- .../fixtures/minimal/precedence/output.js | 4 +-- 8 files changed, 24 insertions(+), 18 deletions(-) diff --git a/packages/babel-plugin-proposal-pipeline-operator/src/buildOptimizedSequenceExpression.js b/packages/babel-plugin-proposal-pipeline-operator/src/buildOptimizedSequenceExpression.js index 05757d4a5a6b..c7e8e4d1d76e 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/src/buildOptimizedSequenceExpression.js +++ b/packages/babel-plugin-proposal-pipeline-operator/src/buildOptimizedSequenceExpression.js @@ -6,42 +6,48 @@ import { types as t } from "@babel/core"; // (a = b, a + e) const buildOptimizedSequenceExpression = ({ assign, call, path }) => { const { left: placeholderNode, right: pipelineLeft } = assign; - const { callee: calledExpression } = call; + const { callee: pipelineRight } = call; let optimizeArrow = - t.isArrowFunctionExpression(calledExpression) && - t.isExpression(calledExpression.body) && - !calledExpression.async && - !calledExpression.generator; + t.isArrowFunctionExpression(pipelineRight) && + t.isExpression(pipelineRight.body) && + !pipelineRight.async && + !pipelineRight.generator; let param; if (optimizeArrow) { - const { params } = calledExpression; + const { params } = pipelineRight; if (params.length === 1 && t.isIdentifier(params[0])) { param = params[0]; } else if (params.length > 0) { optimizeArrow = false; } - } else if (t.isIdentifier(calledExpression, { name: "eval" })) { + } else if (t.isIdentifier(pipelineRight, { name: "eval" })) { const evalSequence = t.sequenceExpression([ t.numericLiteral(0), - calledExpression, + pipelineRight, ]); call.callee = evalSequence; return t.sequenceExpression([assign, call]); + } else if ( + (t.isIdentifier(pipelineRight) && + path.scope.hasBinding(pipelineRight.name)) || + t.isImmutable(pipelineLeft) + ) { + return t.callExpression(pipelineRight, [pipelineLeft]); } if (optimizeArrow && !param) { // Arrow function with 0 arguments - return t.sequenceExpression([pipelineLeft, calledExpression.body]); + return t.sequenceExpression([pipelineLeft, pipelineRight.body]); } if (param) { path.get("right").scope.rename(param.name, placeholderNode.name); - return t.sequenceExpression([assign, calledExpression.body]); + return t.sequenceExpression([assign, pipelineRight.body]); } return t.sequenceExpression([assign, call]); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/output.js index cd2b80132c22..e99168f17307 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/output.js +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/arrow-functions/output.js @@ -10,6 +10,6 @@ var double = x => x * 2; var result2 = [4, 9].map(x => { var _ref4, _x; - return _ref4 = (_x = x, inc(_x)), double(_ref4); + return double(inc(x)); }); expect(result2).toEqual([10, 20]); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/basic/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/basic/output.js index 6ac05ce0fbc9..4dafeb05912f 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/basic/output.js +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/fsharp/basic/output.js @@ -2,4 +2,4 @@ var _; var inc = x => x + 1; -expect((_ = 10, inc(_))).toBe(11); +expect(inc(10)).toBe(11); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions/output.js index cd2b80132c22..e99168f17307 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions/output.js +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/arrow-functions/output.js @@ -10,6 +10,6 @@ var double = x => x * 2; var result2 = [4, 9].map(x => { var _ref4, _x; - return _ref4 = (_x = x, inc(_x)), double(_ref4); + return double(inc(x)); }); expect(result2).toEqual([10, 20]); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/async-arrow/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/async-arrow/output.js index ca8e5ed0c54d..52f8aa3bd5a3 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/async-arrow/output.js +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/async-arrow/output.js @@ -6,7 +6,7 @@ function then(fn) { }; } -var result = (_ref = (_ = 1, (async x => (await x) + 1)(_)), then(x => x + 1)(_ref)); +var result = (_ref = (async x => (await x) + 1)(1), then(x => x + 1)(_ref)); result.then(val => { expect(val).toBe(3); }); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/basic/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/basic/output.js index 6ac05ce0fbc9..4dafeb05912f 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/basic/output.js +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/basic/output.js @@ -2,4 +2,4 @@ var _; var inc = x => x + 1; -expect((_ = 10, inc(_))).toBe(11); +expect(inc(10)).toBe(11); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/chaining/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/chaining/output.js index 84ba2c139dbf..2bf9bf9db584 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/chaining/output.js +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/chaining/output.js @@ -4,4 +4,4 @@ var inc = x => x + 1; var double = x => x * 2; -expect((_ref = (_ = 10, inc(_)), double(_ref))).toBe(22); +expect(double(inc(10))).toBe(22); diff --git a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/precedence/output.js b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/precedence/output.js index e2e39368bb25..10ba20560e0f 100644 --- a/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/precedence/output.js +++ b/packages/babel-plugin-proposal-pipeline-operator/test/fixtures/minimal/precedence/output.js @@ -2,12 +2,12 @@ var _ref, _ref2, _; var inc = x => x + 1; -var result = (_ref = 4 || 9, inc(_ref)); +var result = inc(4 || 9); expect(result).toBe(5); var f = x => x + 10; var h = x => x + 20; -var result2 = (_ref2 = (_ = 10, (f || h)(_)), inc(_ref2)); +var result2 = inc((f || h)(10)); expect(result2).toBe(21);