diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 4f27187123a9..7fb6ae81a577 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -321,8 +321,16 @@ export default class ExpressionParser extends LValParser { if (op === tt.pipeline) { this.expectPlugin("pipelineOperator"); + const wasInPipeline = this.state.inPipeline; this.state.inPipeline = true; this.checkPipelineAtInfixOperator(left, leftStartPos); + + if ( + this.getPluginOption("pipelineOperator", "proposal") === "fsharp" && + !wasInPipeline + ) { + node.left = this.makePipelineHead(left); + } } else if (op === tt.nullishCoalescing) { this.expectPlugin("nullishCoalescingOperator"); } @@ -376,18 +384,21 @@ export default class ExpressionParser extends LValParser { prec: number, noIn: ?boolean, ): N.Expression { + const startPos = this.state.start; + const startLoc = this.state.startLoc; switch (op) { case tt.pipeline: - if (this.getPluginOption("pipelineOperator", "proposal") === "smart") { - const startPos = this.state.start; - const startLoc = this.state.startLoc; - return this.withTopicPermittingContext(() => { - return this.parseSmartPipelineBody( - this.parseExprOpBaseRightExpr(op, prec, noIn), - startPos, - startLoc, - ); - }); + switch (this.getPluginOption("pipelineOperator", "proposal")) { + case "smart": + return this.withTopicPermittingContext(() => { + return this.parseSmartPipelineBody( + this.parseExprOpBaseRightExpr(op, prec, noIn), + startPos, + startLoc, + ); + }); + case "fsharp": + return this.parseFSharpPipelineBody(op, prec, noIn); } // falls through @@ -2271,4 +2282,31 @@ export default class ExpressionParser extends LValParser { this.state.topicContext.maxTopicIndex >= 0 ); } + + makePipelineHead(left: N.Expression): N.Expression { + const node = this.startNode(); + node.head = left; + + return this.finishNode(node, "PipelineHead"); + } + + parseFSharpPipelineBody( + op: TokenType, + prec: number, + noIn: ?boolean, + ): N.Expression { + const startPos = this.state.start; + const startLoc = this.state.startLoc; + + const node = this.startNodeAt(this.state.start, this.state.startLoc); + node.body = this.parseExprOp( + this.parseMaybeUnary(), + startPos, + startLoc, + op.rightAssociative ? prec - 1 : prec, + noIn, + ); + + return this.finishNode(node, "PipelineBody"); + } } diff --git a/packages/babel-parser/src/types.js b/packages/babel-parser/src/types.js index f00eb1be27ef..6696e36db504 100644 --- a/packages/babel-parser/src/types.js +++ b/packages/babel-parser/src/types.js @@ -568,6 +568,10 @@ export type SequenceExpression = NodeBase & { // Pipelines +export type PipelineHead = NodeBase & { + type: "PipelineHead", +}; + export type PipelineBody = NodeBase & { type: "PipelineBody", }; diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/invalid-proposal/options.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/invalid-proposal/options.json index 382d1ba61cd0..d8fca74323cf 100644 --- a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/invalid-proposal/options.json +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/invalid-proposal/options.json @@ -1,6 +1,4 @@ { - "plugins": [ - ["pipelineOperator", { "proposal": "invalid" }] - ], + "plugins": [["pipelineOperator", { "proposal": "invalid" }]], "throws": "'pipelineOperator' requires 'proposal' option whose value should be one of: 'minimal', 'smart', 'fsharp'" } diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head-indented/input.js b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head-indented/input.js new file mode 100644 index 000000000000..894495272a74 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head-indented/input.js @@ -0,0 +1 @@ +x => x |> inc |> double diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head-indented/options.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head-indented/options.json new file mode 100644 index 000000000000..f95ecc7d6c23 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head-indented/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["pipelineOperator", { "proposal": "fsharp" }]] +} diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head-indented/output.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head-indented/output.json new file mode 100644 index 000000000000..f165d232c382 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head-indented/output.json @@ -0,0 +1,215 @@ +{ + "type": "File", + "start": 0, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "expression": { + "type": "ArrowFunctionExpression", + "start": 0, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "id": null, + "generator": false, + "async": false, + "params": [ + { + "type": "Identifier", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + }, + "identifierName": "x" + }, + "name": "x" + } + ], + "body": { + "type": "BinaryExpression", + "start": 5, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "left": { + "type": "BinaryExpression", + "start": 5, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 13 + } + }, + "left": { + "type": "PipelineHead", + "start": 7, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "head": { + "type": "Identifier", + "start": 5, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 6 + }, + "identifierName": "x" + }, + "name": "x" + } + }, + "operator": "|>", + "right": { + "type": "PipelineBody", + "start": 10, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 13 + } + }, + "body": { + "type": "Identifier", + "start": 10, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 13 + }, + "identifierName": "inc" + }, + "name": "inc" + } + } + }, + "operator": "|>", + "right": { + "type": "PipelineBody", + "start": 17, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 17 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "body": { + "type": "Identifier", + "start": 17, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 17 + }, + "end": { + "line": 1, + "column": 23 + }, + "identifierName": "double" + }, + "name": "double" + } + } + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head/input.js b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head/input.js new file mode 100644 index 000000000000..894495272a74 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head/input.js @@ -0,0 +1 @@ +x => x |> inc |> double diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head/options.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head/options.json new file mode 100644 index 000000000000..f95ecc7d6c23 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["pipelineOperator", { "proposal": "fsharp" }]] +} diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head/output.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head/output.json new file mode 100644 index 000000000000..f165d232c382 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-arrow-at-head/output.json @@ -0,0 +1,215 @@ +{ + "type": "File", + "start": 0, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "expression": { + "type": "ArrowFunctionExpression", + "start": 0, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "id": null, + "generator": false, + "async": false, + "params": [ + { + "type": "Identifier", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + }, + "identifierName": "x" + }, + "name": "x" + } + ], + "body": { + "type": "BinaryExpression", + "start": 5, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "left": { + "type": "BinaryExpression", + "start": 5, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 13 + } + }, + "left": { + "type": "PipelineHead", + "start": 7, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "head": { + "type": "Identifier", + "start": 5, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 6 + }, + "identifierName": "x" + }, + "name": "x" + } + }, + "operator": "|>", + "right": { + "type": "PipelineBody", + "start": 10, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 13 + } + }, + "body": { + "type": "Identifier", + "start": 10, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 13 + }, + "identifierName": "inc" + }, + "name": "inc" + } + } + }, + "operator": "|>", + "right": { + "type": "PipelineBody", + "start": 17, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 17 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "body": { + "type": "Identifier", + "start": 17, + "end": 23, + "loc": { + "start": { + "line": 1, + "column": 17 + }, + "end": { + "line": 1, + "column": 23 + }, + "identifierName": "double" + }, + "name": "double" + } + } + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-base/input.js b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-base/input.js new file mode 100644 index 000000000000..cf3443941ff0 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-base/input.js @@ -0,0 +1 @@ +a |> b diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-base/options.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-base/options.json new file mode 100644 index 000000000000..f95ecc7d6c23 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-base/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["pipelineOperator", { "proposal": "fsharp" }]] +} diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-base/output.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-base/output.json new file mode 100644 index 000000000000..99af7f7ee974 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-base/output.json @@ -0,0 +1,130 @@ +{ + "type": "File", + "start": 0, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "expression": { + "type": "BinaryExpression", + "start": 0, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "left": { + "type": "PipelineHead", + "start": 2, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 2 + }, + "end": { + "line": 1, + "column": 1 + } + }, + "head": { + "type": "Identifier", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + }, + "identifierName": "a" + }, + "name": "a" + } + }, + "operator": "|>", + "right": { + "type": "PipelineBody", + "start": 5, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "body": { + "type": "Identifier", + "start": 5, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 6 + }, + "identifierName": "b" + }, + "name": "b" + } + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-chain/input.js b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-chain/input.js new file mode 100644 index 000000000000..0d1e8411dd06 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-chain/input.js @@ -0,0 +1 @@ +x |> inc |> double diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-chain/options.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-chain/options.json new file mode 100644 index 000000000000..f95ecc7d6c23 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-chain/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["pipelineOperator", { "proposal": "fsharp" }]] +} diff --git a/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-chain/output.json b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-chain/output.json new file mode 100644 index 000000000000..739b13164d56 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/pipeline-operator/proposal-fsharp-chain/output.json @@ -0,0 +1,178 @@ +{ + "type": "File", + "start": 0, + "end": 18, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 18 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 18, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 18 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 18, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 18 + } + }, + "expression": { + "type": "BinaryExpression", + "start": 0, + "end": 18, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 18 + } + }, + "left": { + "type": "BinaryExpression", + "start": 0, + "end": 8, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 8 + } + }, + "left": { + "type": "PipelineHead", + "start": 2, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 2 + }, + "end": { + "line": 1, + "column": 1 + } + }, + "head": { + "type": "Identifier", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + }, + "identifierName": "x" + }, + "name": "x" + } + }, + "operator": "|>", + "right": { + "type": "PipelineBody", + "start": 5, + "end": 8, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 8 + } + }, + "body": { + "type": "Identifier", + "start": 5, + "end": 8, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 8 + }, + "identifierName": "inc" + }, + "name": "inc" + } + } + }, + "operator": "|>", + "right": { + "type": "PipelineBody", + "start": 12, + "end": 18, + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 18 + } + }, + "body": { + "type": "Identifier", + "start": 12, + "end": 18, + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 18 + }, + "identifierName": "double" + }, + "name": "double" + } + } + } + } + ], + "directives": [] + } +} \ No newline at end of file